#define PCRE2_CODE_UNIT_WIDTH 8 #include #include #include #include #include #include #include size_t min(const size_t lhs, const size_t rhs) { return lhs > rhs ? rhs : lhs; } char* relative_path_in_current_dir(git_repository* repo, const char* filename) { const long maximum = pathconf(".", _PC_PATH_MAX); size_t len = 0 > maximum ? 1024 : maximum; char* buf = NULL; char* cwd = NULL; for (; NULL == cwd && 1024 * 50 > len; len *= 2) { if (NULL == (cwd = realloc(buf, len))) { if (NULL != buf) free(buf); return NULL; } buf = cwd; cwd = getcwd(buf, len); if (NULL == cwd && ERANGE != errno) { free(buf); return NULL; } } const char* workdir = git_repository_workdir(repo); const size_t prefix = min(strlen(cwd), strlen(workdir)); if (0 != strncmp(cwd, workdir, prefix)) { free(cwd); return NULL; } const size_t relative = strlen(cwd + prefix); if (NULL == (buf = malloc(relative + strlen(filename) + 2))) { free(cwd); return NULL; } strcpy(buf, cwd + prefix); if (0 < relative) strcat(buf, "/"); strcat(buf, filename); free(cwd); return buf; } void gerror(void) { const git_error* err = git_error_last(); dprintf(2, "%s\n", err->message); } int main(int argc, char* argv[]) { git_libgit2_init(); git_repository* repo = NULL; int err = git_repository_open_ext(&repo, NULL, GIT_REPOSITORY_OPEN_FROM_ENV, NULL); if (0 > err) { gerror(); return 1; } git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT; diffopts.pathspec.strings = (char*[]){relative_path_in_current_dir(repo, "PKGBUILD")}; diffopts.pathspec.count = 1; git_pathspec* pathspec = NULL; err = git_pathspec_new(&pathspec, &diffopts.pathspec); if (0 > err) { gerror(); return 1; } git_revwalk* walker = NULL; err = git_revwalk_new(&walker, repo); if (0 > err) { gerror(); return 1; } err = git_revwalk_push_head(walker); if (0 > err) { gerror(); return 1; } git_oid oid; git_tree* earlier = NULL; git_tree* later = NULL; while (0 == git_revwalk_next(&oid, walker)) { git_commit* commit; err = git_commit_lookup(&commit, repo, &oid); if (0 > err) { gerror(); return 1; } if (NULL != earlier) git_tree_free(earlier); earlier = later; err = git_commit_tree(&later, commit); if (0 > err) { gerror(); return 1; } const int matched = 0 == git_pathspec_match_tree(NULL, later, GIT_PATHSPEC_NO_MATCH_ERROR, pathspec); if (matched) { char buf[GIT_OID_HEXSZ + 1]; git_oid_tostr(buf, sizeof(buf), git_commit_id(commit)); puts(buf); } git_commit_free(commit); } if (NULL != earlier) git_tree_free(earlier); if (NULL != later) git_tree_free(later); git_revwalk_free(walker); git_pathspec_free(pathspec); free(diffopts.pathspec.strings[0]); git_repository_free(repo); }