]> git.armaanb.net Git - stagit.git/blobdiff - stagit.c
simplify range check
[stagit.git] / stagit.c
index bf027f64dc1c63e8332f01faf08f5d6468e01789..6598ddd2cc0523f918db6c87a01795ced9ee51d9 100644 (file)
--- a/stagit.c
+++ b/stagit.c
@@ -57,6 +57,7 @@ static char *strippedname = "";
 static char description[255];
 static char cloneurl[1024];
 static int haslicense, hasreadme, hassubmodules;
+static long long nlogcommits = -1; /* < 0 indicates not used */
 
 /* cache */
 static git_oid lastoid;
@@ -64,10 +65,6 @@ static char lastoidstr[GIT_OID_HEXSZ + 2]; /* id + newline + nul byte */
 static FILE *rcachefp, *wcachefp;
 static const char *cachefile;
 
-#ifndef USE_PLEDGE
-#define pledge(p1,p2) 0
-#endif
-
 void
 joinpath(char *buf, size_t bufsiz, const char *path, const char *path2)
 {
@@ -86,7 +83,7 @@ deltainfo_free(struct deltainfo *di)
        if (!di)
                return;
        git_patch_free(di->patch);
-       di->patch = NULL;
+       memset(di, 0, sizeof(*di));
        free(di);
 }
 
@@ -94,6 +91,7 @@ int
 commitinfo_getstats(struct commitinfo *ci)
 {
        struct deltainfo *di;
+       git_diff_options opts;
        const git_diff_delta *delta;
        const git_diff_hunk *hunk;
        const git_diff_line *line;
@@ -101,6 +99,20 @@ commitinfo_getstats(struct commitinfo *ci)
        size_t ndeltas, nhunks, nhunklines;
        size_t i, j, k;
 
+       if (git_tree_lookup(&(ci->commit_tree), repo, git_commit_tree_id(ci->commit)))
+               goto err;
+       if (!git_commit_parent(&(ci->parent), ci->commit, 0)) {
+               if (git_tree_lookup(&(ci->parent_tree), repo, git_commit_tree_id(ci->parent))) {
+                       ci->parent = NULL;
+                       ci->parent_tree = NULL;
+               }
+       }
+
+       git_diff_init_options(&opts, GIT_DIFF_OPTIONS_VERSION);
+       opts.flags |= GIT_DIFF_DISABLE_PATHSPEC_MATCH;
+       if (git_diff_tree_to_tree(&(ci->diff), repo, ci->parent_tree, ci->commit_tree, &opts))
+               goto err;
+
        ndeltas = git_diff_num_deltas(ci->diff);
        if (ndeltas && !(ci->deltas = calloc(ndeltas, sizeof(struct deltainfo *))))
                err(1, "calloc");
@@ -142,6 +154,15 @@ commitinfo_getstats(struct commitinfo *ci)
        return 0;
 
 err:
+       git_diff_free(ci->diff);
+       ci->diff = NULL;
+       git_tree_free(ci->commit_tree);
+       ci->commit_tree = NULL;
+       git_tree_free(ci->parent_tree);
+       ci->parent_tree = NULL;
+       git_commit_free(ci->parent);
+       ci->parent = NULL;
+
        if (ci->deltas)
                for (i = 0; i < ci->ndeltas; i++)
                        deltainfo_free(ci->deltas[i]);
@@ -165,13 +186,14 @@ commitinfo_free(struct commitinfo *ci)
        if (ci->deltas)
                for (i = 0; i < ci->ndeltas; i++)
                        deltainfo_free(ci->deltas[i]);
+
        free(ci->deltas);
-       ci->deltas = NULL;
        git_diff_free(ci->diff);
        git_tree_free(ci->commit_tree);
        git_tree_free(ci->parent_tree);
        git_commit_free(ci->commit);
        git_commit_free(ci->parent);
+       memset(ci, 0, sizeof(*ci));
        free(ci);
 }
 
@@ -179,7 +201,6 @@ struct commitinfo *
 commitinfo_getbyoid(const git_oid *id)
 {
        struct commitinfo *ci;
-       git_diff_options opts;
 
        if (!(ci = calloc(1, sizeof(struct commitinfo))))
                err(1, "calloc");
@@ -196,20 +217,6 @@ commitinfo_getbyoid(const git_oid *id)
        ci->summary = git_commit_summary(ci->commit);
        ci->msg = git_commit_message(ci->commit);
 
-       if (git_tree_lookup(&(ci->commit_tree), repo, git_commit_tree_id(ci->commit)))
-               goto err;
-       if (!git_commit_parent(&(ci->parent), ci->commit, 0)) {
-               if (git_tree_lookup(&(ci->parent_tree), repo, git_commit_tree_id(ci->parent))) {
-                       ci->parent = NULL;
-                       ci->parent_tree = NULL;
-               }
-       }
-
-       git_diff_init_options(&opts, GIT_DIFF_OPTIONS_VERSION);
-       opts.flags |= GIT_DIFF_DISABLE_PATHSPEC_MATCH;
-       if (git_diff_tree_to_tree(&(ci->diff), repo, ci->parent_tree, ci->commit_tree, &opts))
-               goto err;
-
        return ci;
 
 err:
@@ -558,7 +565,7 @@ writelog(FILE *fp, const git_oid *oid)
        struct commitinfo *ci;
        git_revwalk *w = NULL;
        git_oid id;
-       char path[PATH_MAX];
+       char path[PATH_MAX], oidstr[GIT_OID_HEXSZ + 1];
        FILE *fpfile;
        int r;
 
@@ -572,24 +579,41 @@ writelog(FILE *fp, const git_oid *oid)
 
                if (cachefile && !memcmp(&id, &lastoid, sizeof(id)))
                        break;
+
+               git_oid_tostr(oidstr, sizeof(oidstr), &id);
+               r = snprintf(path, sizeof(path), "commit/%s.html", oidstr);
+               if (r == -1 || (size_t)r >= sizeof(path))
+                       errx(1, "path truncated: 'commit/%s.html'", oidstr);
+               r = access(path, F_OK);
+
+               /* optimization: if there are no log lines to write and
+                  the commit file already exists: skip the diffstat */
+               if (!nlogcommits && !r)
+                       continue;
+
                if (!(ci = commitinfo_getbyoid(&id)))
                        break;
-               /* lookup stats: only required here */
+               /* diffstat: for stagit HTML required for the log.html line */
                if (commitinfo_getstats(ci) == -1)
                        goto err;
 
-               writelogline(fp, ci);
+               if (nlogcommits < 0) {
+                       writelogline(fp, ci);
+               } else if (nlogcommits > 0) {
+                       writelogline(fp, ci);
+                       nlogcommits--;
+                       if (!nlogcommits && ci->parentoid[0])
+                               fputs("<tr><td></td><td colspan=\"5\">"
+                                     "More commits remaining [...]</td>"
+                                     "</tr>\n", fp);
+               }
+
                if (cachefile)
                        writelogline(wcachefp, ci);
 
-               relpath = "../";
-
-               r = snprintf(path, sizeof(path), "commit/%s.html", ci->oid);
-               if (r == -1 || (size_t)r >= sizeof(path))
-                       errx(1, "path truncated: 'commit/%s.html'", ci->oid);
-
                /* check if file exists if so skip it */
-               if (access(path, F_OK)) {
+               if (r) {
+                       relpath = "../";
                        fpfile = efopen(path, "w");
                        writeheader(fpfile, ci->summary);
                        fputs("<pre>", fpfile);
@@ -986,7 +1010,7 @@ err:
 void
 usage(char *argv0)
 {
-       fprintf(stderr, "%s [-c cachefile] repodir\n", argv0);
+       fprintf(stderr, "%s [-c cachefile | -l commits] repodir\n", argv0);
        exit(1);
 }
 
@@ -1003,18 +1027,23 @@ main(int argc, char *argv[])
        size_t n;
        int i, fd;
 
-       if (pledge("stdio rpath wpath cpath", NULL) == -1)
-               err(1, "pledge");
-
        for (i = 1; i < argc; i++) {
                if (argv[i][0] != '-') {
                        if (repodir)
                                usage(argv[0]);
                        repodir = argv[i];
                } else if (argv[i][1] == 'c') {
-                       if (i + 1 >= argc)
+                       if (nlogcommits > 0 || i + 1 >= argc)
                                usage(argv[0]);
                        cachefile = argv[++i];
+               } else if (argv[i][1] == 'l') {
+                       if (cachefile || i + 1 >= argc)
+                               usage(argv[0]);
+                       errno = 0;
+                       nlogcommits = strtoll(argv[++i], &p, 10);
+                       if (argv[i][0] == '\0' || *p != '\0' ||
+                           nlogcommits <= 0 || errno)
+                               usage(argv[0]);
                }
        }
        if (!repodir)
@@ -1025,6 +1054,16 @@ main(int argc, char *argv[])
 
        git_libgit2_init();
 
+#ifdef __OpenBSD__
+       if (cachefile) {
+               if (pledge("stdio rpath wpath cpath fattr", NULL) == -1)
+                       err(1, "pledge");
+       } else {
+               if (pledge("stdio rpath wpath cpath", NULL) == -1)
+                       err(1, "pledge");
+       }
+#endif
+
        if (git_repository_open_ext(&repo, repodir,
                GIT_REPOSITORY_OPEN_NO_SEARCH, NULL) < 0) {
                e = giterr_last();
@@ -1037,10 +1076,6 @@ main(int argc, char *argv[])
                head = git_object_id(obj);
        git_object_free(obj);
 
-       /* don't cache if there is no HEAD */
-       if (!head)
-               cachefile = NULL;
-
        /* use directory name as name */
        if ((name = strrchr(repodirabs, '/')))
                name++;
@@ -1104,7 +1139,7 @@ main(int argc, char *argv[])
              "<td class=\"num\" align=\"right\"><b>+</b></td>"
              "<td class=\"num\" align=\"right\"><b>-</b></td></tr>\n</thead><tbody>\n", fp);
 
-       if (cachefile) {
+       if (cachefile && head) {
                /* read from cache file (does not need to exist) */
                if ((rcachefp = fopen(cachefile, "r"))) {
                        if (!fgets(lastoidstr, sizeof(lastoidstr), rcachefp))
@@ -1167,7 +1202,7 @@ main(int argc, char *argv[])
        fclose(fp);
 
        /* rename new cache file on success */
-       if (cachefile) {
+       if (cachefile && head) {
                if (rename(tmppath, cachefile))
                        err(1, "rename: '%s' to '%s'", tmppath, cachefile);
                umask((mask = umask(0)));