{"thread":{"id":"12321","subject":"[PATCH 1/2] Add API access to shortlog","startedAt":"2008-02-25T23:24:14Z","lastAt":"2008-02-25T23:24:14Z","messageCount":1,"participants":["Daniel Barkalow"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"69945","messageId":"alpine.LNX.1.00.0802251822120.19024@iabervon.org","threadId":"12321","inReplyTo":null,"subject":"[PATCH 1/2] Add API access to shortlog","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2008-02-25T23:24:14Z","receivedAt":"2008-02-25T23:24:14Z","isPatch":true,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"Shortlog is gives a pretty simple API for cases where you're already\nidentifying all of the individual commits. Make this available to\nother code instead of requiring them to use the revision API and\ncommand line.\n\nSigned-off-by: Daniel Barkalow <barkalow@iabervon.org>\n---\n builtin-shortlog.c |  149 ++++++++++++++++++++++++++++------------------------\n shortlog.h         |   26 +++++++++\n 2 files changed, 106 insertions(+), 69 deletions(-)\n create mode 100644 shortlog.h\n\ndiff --git a/builtin-shortlog.c b/builtin-shortlog.c\nindex 0055a57..af31aba 100644\n--- a/builtin-shortlog.c\n+++ b/builtin-shortlog.c\n@@ -6,13 +6,11 @@\n #include \"revision.h\"\n #include \"utf8.h\"\n #include \"mailmap.h\"\n+#include \"shortlog.h\"\n \n static const char shortlog_usage[] =\n \"git-shortlog [-n] [-s] [-e] [<commit-id>... ]\";\n \n-static char *common_repo_prefix;\n-static int email;\n-\n static int compare_by_number(const void *a1, const void *a2)\n {\n \tconst struct path_list_item *i1 = a1, *i2 = a2;\n@@ -26,13 +24,11 @@ static int compare_by_number(const void *a1, const void *a2)\n \t\treturn -1;\n }\n \n-static struct path_list mailmap = {NULL, 0, 0, 0};\n-\n-static void insert_one_record(struct path_list *list,\n+static void insert_one_record(struct shortlog *log,\n \t\t\t      const char *author,\n \t\t\t      const char *oneline)\n {\n-\tconst char *dot3 = common_repo_prefix;\n+\tconst char *dot3 = log->common_repo_prefix;\n \tchar *buffer, *p;\n \tstruct path_list_item *item;\n \tstruct path_list *onelines;\n@@ -47,7 +43,7 @@ static void insert_one_record(struct path_list *list,\n \teoemail = strchr(boemail, '>');\n \tif (!eoemail)\n \t\treturn;\n-\tif (!map_email(&mailmap, boemail+1, namebuf, sizeof(namebuf))) {\n+\tif (!map_email(&log->mailmap, boemail+1, namebuf, sizeof(namebuf))) {\n \t\twhile (author < boemail && isspace(*author))\n \t\t\tauthor++;\n \t\tfor (len = 0;\n@@ -61,14 +57,14 @@ static void insert_one_record(struct path_list *list,\n \telse\n \t\tlen = strlen(namebuf);\n \n-\tif (email) {\n+\tif (log->email) {\n \t\tsize_t room = sizeof(namebuf) - len - 1;\n \t\tint maillen = eoemail - boemail + 1;\n \t\tsnprintf(namebuf + len, room, \" %.*s\", maillen, boemail);\n \t}\n \n \tbuffer = xstrdup(namebuf);\n-\titem = path_list_insert(buffer, list);\n+\titem = path_list_insert(buffer, &log->list);\n \tif (item->util == NULL)\n \t\titem->util = xcalloc(1, sizeof(struct path_list));\n \telse\n@@ -114,7 +110,7 @@ static void insert_one_record(struct path_list *list,\n \tonelines->items[onelines->nr++].path = buffer;\n }\n \n-static void read_from_stdin(struct path_list *list)\n+static void read_from_stdin(struct shortlog *log)\n {\n \tchar author[1024], oneline[1024];\n \n@@ -128,39 +124,43 @@ static void read_from_stdin(struct path_list *list)\n \t\twhile (fgets(oneline, sizeof(oneline), stdin) &&\n \t\t       oneline[0] == '\\n')\n \t\t\t; /* discard blanks */\n-\t\tinsert_one_record(list, author + 8, oneline);\n+\t\tinsert_one_record(log, author + 8, oneline);\n \t}\n }\n \n-static void get_from_rev(struct rev_info *rev, struct path_list *list)\n+void shortlog_add_commit(struct shortlog *log, struct commit *commit)\n {\n-\tstruct commit *commit;\n-\n-\tif (prepare_revision_walk(rev))\n-\t\tdie(\"revision walk setup failed\");\n-\twhile ((commit = get_revision(rev)) != NULL) {\n-\t\tconst char *author = NULL, *buffer;\n+\tconst char *author = NULL, *buffer;\n \n-\t\tbuffer = commit->buffer;\n-\t\twhile (*buffer && *buffer != '\\n') {\n-\t\t\tconst char *eol = strchr(buffer, '\\n');\n+\tbuffer = commit->buffer;\n+\twhile (*buffer && *buffer != '\\n') {\n+\t\tconst char *eol = strchr(buffer, '\\n');\n \n-\t\t\tif (eol == NULL)\n-\t\t\t\teol = buffer + strlen(buffer);\n-\t\t\telse\n-\t\t\t\teol++;\n+\t\tif (eol == NULL)\n+\t\t\teol = buffer + strlen(buffer);\n+\t\telse\n+\t\t\teol++;\n \n-\t\t\tif (!prefixcmp(buffer, \"author \"))\n-\t\t\t\tauthor = buffer + 7;\n-\t\t\tbuffer = eol;\n-\t\t}\n-\t\tif (!author)\n-\t\t\tdie(\"Missing author: %s\",\n-\t\t\t    sha1_to_hex(commit->object.sha1));\n-\t\tif (*buffer)\n-\t\t\tbuffer++;\n-\t\tinsert_one_record(list, author, !*buffer ? \"<none>\" : buffer);\n+\t\tif (!prefixcmp(buffer, \"author \"))\n+\t\t\tauthor = buffer + 7;\n+\t\tbuffer = eol;\n \t}\n+\tif (!author)\n+\t\tdie(\"Missing author: %s\",\n+\t\t    sha1_to_hex(commit->object.sha1));\n+\tif (*buffer)\n+\t\tbuffer++;\n+\tinsert_one_record(log, author, !*buffer ? \"<none>\" : buffer);\n+}\n+\n+static void get_from_rev(struct rev_info *rev, struct shortlog *log)\n+{\n+\tstruct commit *commit;\n+\n+\tif (prepare_revision_walk(rev))\n+\t\tdie(\"revision walk setup failed\");\n+\twhile ((commit = get_revision(rev)) != NULL)\n+\t\tshortlog_add_commit(log, commit);\n }\n \n static int parse_uint(char const **arg, int comma)\n@@ -212,29 +212,38 @@ static void parse_wrap_args(const char *arg, int *in1, int *in2, int *wrap)\n \t\tdie(wrap_arg_usage);\n }\n \n+void shortlog_init(struct shortlog *log)\n+{\n+\tmemset(log, 0, sizeof(*log));\n+\n+\tread_mailmap(&log->mailmap, \".mailmap\", &log->common_repo_prefix);\n+\n+\tlog->list.strdup_paths = 1;\n+\tlog->wrap = DEFAULT_WRAPLEN;\n+\tlog->in1 = DEFAULT_INDENT1;\n+\tlog->in2 = DEFAULT_INDENT2;\n+}\n+\n int cmd_shortlog(int argc, const char **argv, const char *prefix)\n {\n+\tstruct shortlog log;\n \tstruct rev_info rev;\n-\tstruct path_list list = { NULL, 0, 0, 1 };\n-\tint i, j, sort_by_number = 0, summary = 0;\n-\tint wrap_lines = 0;\n-\tint wrap = DEFAULT_WRAPLEN;\n-\tint in1 = DEFAULT_INDENT1;\n-\tint in2 = DEFAULT_INDENT2;\n+\n+\tshortlog_init(&log);\n \n \t/* since -n is a shadowed rev argument, parse our args first */\n \twhile (argc > 1) {\n \t\tif (!strcmp(argv[1], \"-n\") || !strcmp(argv[1], \"--numbered\"))\n-\t\t\tsort_by_number = 1;\n+\t\t\tlog.sort_by_number = 1;\n \t\telse if (!strcmp(argv[1], \"-s\") ||\n \t\t\t\t!strcmp(argv[1], \"--summary\"))\n-\t\t\tsummary = 1;\n+\t\t\tlog.summary = 1;\n \t\telse if (!strcmp(argv[1], \"-e\") ||\n \t\t\t !strcmp(argv[1], \"--email\"))\n-\t\t\temail = 1;\n+\t\t\tlog.email = 1;\n \t\telse if (!prefixcmp(argv[1], \"-w\")) {\n-\t\t\twrap_lines = 1;\n-\t\t\tparse_wrap_args(argv[1], &in1, &in2, &wrap);\n+\t\t\tlog.wrap_lines = 1;\n+\t\t\tparse_wrap_args(argv[1], &log.in1, &log.in2, &log.wrap);\n \t\t}\n \t\telse if (!strcmp(argv[1], \"-h\") || !strcmp(argv[1], \"--help\"))\n \t\t\tusage(shortlog_usage);\n@@ -248,34 +257,38 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)\n \tif (argc > 1)\n \t\tdie (\"unrecognized argument: %s\", argv[1]);\n \n-\tread_mailmap(&mailmap, \".mailmap\", &common_repo_prefix);\n-\n \t/* assume HEAD if from a tty */\n \tif (!rev.pending.nr && isatty(0))\n \t\tadd_head_to_pending(&rev);\n \tif (rev.pending.nr == 0) {\n-\t\tread_from_stdin(&list);\n+\t\tread_from_stdin(&log);\n \t}\n \telse\n-\t\tget_from_rev(&rev, &list);\n+\t\tget_from_rev(&rev, &log);\n \n-\tif (sort_by_number)\n-\t\tqsort(list.items, list.nr, sizeof(struct path_list_item),\n-\t\t\tcompare_by_number);\n+\tshortlog_output(&log);\n+\treturn 0;\n+}\n \n-\tfor (i = 0; i < list.nr; i++) {\n-\t\tstruct path_list *onelines = list.items[i].util;\n+void shortlog_output(struct shortlog *log)\n+{\n+\tint i, j;\n+\tif (log->sort_by_number)\n+\t\tqsort(log->list.items, log->list.nr, sizeof(struct path_list_item),\n+\t\t\tcompare_by_number);\n+\tfor (i = 0; i < log->list.nr; i++) {\n+\t\tstruct path_list *onelines = log->list.items[i].util;\n \n-\t\tif (summary) {\n-\t\t\tprintf(\"%6d\\t%s\\n\", onelines->nr, list.items[i].path);\n+\t\tif (log->summary) {\n+\t\t\tprintf(\"%6d\\t%s\\n\", onelines->nr, log->list.items[i].path);\n \t\t} else {\n-\t\t\tprintf(\"%s (%d):\\n\", list.items[i].path, onelines->nr);\n+\t\t\tprintf(\"%s (%d):\\n\", log->list.items[i].path, onelines->nr);\n \t\t\tfor (j = onelines->nr - 1; j >= 0; j--) {\n \t\t\t\tconst char *msg = onelines->items[j].path;\n \n-\t\t\t\tif (wrap_lines) {\n-\t\t\t\t\tint col = print_wrapped_text(msg, in1, in2, wrap);\n-\t\t\t\t\tif (col != wrap)\n+\t\t\t\tif (log->wrap_lines) {\n+\t\t\t\t\tint col = print_wrapped_text(msg, log->in1, log->in2, log->wrap);\n+\t\t\t\t\tif (col != log->wrap)\n \t\t\t\t\t\tputchar('\\n');\n \t\t\t\t}\n \t\t\t\telse\n@@ -287,13 +300,11 @@ int cmd_shortlog(int argc, const char **argv, const char *prefix)\n \t\tonelines->strdup_paths = 1;\n \t\tpath_list_clear(onelines, 1);\n \t\tfree(onelines);\n-\t\tlist.items[i].util = NULL;\n+\t\tlog->list.items[i].util = NULL;\n \t}\n \n-\tlist.strdup_paths = 1;\n-\tpath_list_clear(&list, 1);\n-\tmailmap.strdup_paths = 1;\n-\tpath_list_clear(&mailmap, 1);\n-\n-\treturn 0;\n+\tlog->list.strdup_paths = 1;\n+\tpath_list_clear(&log->list, 1);\n+\tlog->mailmap.strdup_paths = 1;\n+\tpath_list_clear(&log->mailmap, 1);\n }\ndiff --git a/shortlog.h b/shortlog.h\nnew file mode 100644\nindex 0000000..31ff491\n--- /dev/null\n+++ b/shortlog.h\n@@ -0,0 +1,26 @@\n+#ifndef SHORTLOG_H\n+#define SHORTLOG_H\n+\n+#include \"path-list.h\"\n+\n+struct shortlog {\n+\tstruct path_list list;\n+\tint summary;\n+\tint wrap_lines;\n+\tint sort_by_number;\n+\tint wrap;\n+\tint in1;\n+\tint in2;\n+\n+\tchar *common_repo_prefix;\n+\tint email;\n+\tstruct path_list mailmap;\n+};\n+\n+void shortlog_init(struct shortlog *log);\n+\n+void shortlog_add_commit(struct shortlog *log, struct commit *commit);\n+\n+void shortlog_output(struct shortlog *log);\n+\n+#endif\n-- \n1.5.4.3.330.g53ab.dirty\n"}]}