#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 line_line(const git_diff_delta* delta, const git_diff_hunk* hunk, const git_diff_line* line, void* payload) { switch (line->origin) { case GIT_DIFF_LINE_ADDITION: printf("+%.*s", line->content_len, line->content); break; case GIT_DIFF_LINE_DELETION: printf("-%.*s", line->content_len, line->content); break; default: } return 0; } 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; } git_diff* diff; if (NULL == earlier) err = git_diff_tree_to_workdir_with_index(&diff, repo, later, &diffopts); else err = git_diff_tree_to_tree(&diff, repo, later, earlier, &diffopts); if (0 > err) { gerror(); return 1; } git_diff_foreach(diff, NULL, NULL, NULL, &line_line, NULL); git_diff_free(diff); 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); }