diff options
Diffstat (limited to 'source/ui-stats.c')
| -rw-r--r-- | source/ui-stats.c | 56 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 file changed, 30 insertions, 26 deletions
diff --git a/source/ui-stats.c b/source/ui-stats.c index a04b189..3960b14 100644 --- a/source/ui-stats.c +++ b/source/ui-stats.c @@ -17,11 +17,9 @@ #define DEFAULT_AUTHOR_ROWS 10 -/* - * One author's share of the window. periods is keyed by the label of a - * period, with the commit count stored in the util field itself rather than - * behind another allocation. - */ +// One author's share of the window. periods is keyed by the label of a period, +// with the commit count stored in the util field itself rather than behind +// another allocation. struct authorstat { long total; struct string_list periods; @@ -144,10 +142,8 @@ static char *pretty_year(struct tm *tm) return cgit_fmt("%d", tm->tm_year + 1900); } -/* - * The order runs from the finest window to the coarsest, because a repository - * caps the page by storing an index into this table as its max-stats. - */ +// The order runs from the finest window to the coarsest, because a repository +// caps the page by storing an index into this table as its max-stats. static const struct cgit_period periods[] = { {'w', "week", 4, trunc_week, dec_week, inc_week, pretty_week}, {'m', "month", 4, trunc_month, dec_month, inc_month, pretty_month}, @@ -157,10 +153,13 @@ static const struct cgit_period periods[] = { static void window_start(const struct cgit_period *period, struct tm *tm) { - time_t now; + // Read once, so the buckets and the column labels agree on the window + // even when the clock crosses a period boundary between them. + static time_t now; int i; - time(&now); + if (!now) + time(&now); gmtime_r(&now, tm); period->trunc(tm); for (i = 1; i < period->count; i++) @@ -175,7 +174,6 @@ static void add_commit(struct string_list *authors, struct commitinfo *info, char *name, *label; struct tm date; time_t when; - uintptr_t *count; // A commit can lack an author header, so fall back rather than // handing xstrdup a NULL. @@ -194,11 +192,11 @@ static void add_commit(struct string_list *authors, struct commitinfo *info, return; period->trunc(&date); label = xstrdup(period->pretty(&date)); + // The pointer field holds the count itself. bucket = string_list_insert(&stats->periods, label); - count = (uintptr_t *)&bucket->util; - if (*count) + if (bucket->util) free(label); - (*count)++; + bucket->util = (void *)((uintptr_t)bucket->util + 1); stats->total++; } @@ -213,10 +211,11 @@ static struct string_list collect_stats(const struct cgit_period *period) struct string_list authors; struct rev_info rev; struct commit *commit; - // setup_revisions reads the entries after the double dash up to a - // NULL, past the count, so the sentinel has to stay even when the - // path fills the slot before it. - const char *argv[] = {NULL, ctx.qry.head, NULL, NULL, NULL}; + // setup_revisions reads these the way main does, skipping the first + // entry, and reads past the count up to a NULL after the double dash, + // so the sentinel has to stay even when the path fills the slot before + // it. + const char *argv[] = { NULL, ctx.qry.head, NULL, NULL, NULL }; int argc = 2; time_t since; struct tm tm; @@ -235,16 +234,19 @@ static struct string_list collect_stats(const struct cgit_period *period) rev.max_parents = 1; rev.verbose_header = 1; rev.show_root_diff = 0; - // setup_revisions reads argv the way main does and ignores the first - // entry, so the head to walk sits at argv[1]. setup_revisions(argc, argv, &rev, NULL); // Prune the walk to the displayed window instead of traversing the // whole history and discarding older commits. The check below still // bounds the period edge exactly. rev.max_age = since; - prepare_revision_walk(&rev); memset(&authors, 0, sizeof(authors)); - while ((commit = get_revision(&rev)) != NULL) { + // A failed setup leaves the walk holding freed commits, so it must + // not be read from. + if (prepare_revision_walk(&rev)) { + cgit_print_error_page(500, "Internal Server Error", "Unable to read the history"); + return authors; + } + while ((commit = get_revision(&rev))) { struct commitinfo *info = cgit_parse_commit(commit); if ((time_t)info->committer_date >= since) @@ -352,7 +354,7 @@ static void print_authors(struct string_list *authors, int max_rows, const struc if (!bucket) html("<td>0</td>"); else { - htmlf("<td>%lu</td>", (uintptr_t)bucket->util); + htmlf("<td>%ju</td>", (uintmax_t)(uintptr_t)bucket->util); total += (uintptr_t)bucket->util; } } @@ -360,7 +362,8 @@ static void print_authors(struct string_list *authors, int max_rows, const struc } if (rows < authors->nr) - print_summary_row(authors, rows, authors->nr - rows, "Others (%ld)", "left", "", "sum", labels); + print_summary_row(authors, rows, authors->nr - rows, "Others (%ld)", "left", "", "sum", + labels); print_summary_row(authors, 0, authors->nr, "Total", "total", "sum", "sum", labels); html("</table>\n"); @@ -380,7 +383,8 @@ static void print_options_form(const struct cgit_period *period, int top) html("<tr><td class='label'>Period:</td>"); html("<td class='ctrl'><select name='period'>"); for (i = 0; i < choices; i++) - html_option(cgit_fmt("%c", periods[i].code), periods[i].name, cgit_fmt("%c", period->code)); + html_option(cgit_fmt("%c", periods[i].code), periods[i].name, + cgit_fmt("%c", period->code)); html("</select></td></tr>\n"); } html("<tr><td class='label'>Authors:</td>"); |
