{"thread":{"id":"32553","subject":"[PATCH v2 01/10] string-list: allow case-insensitive string list","startedAt":"2013-01-08T00:10:11Z","lastAt":"2013-01-10T21:35:05Z","messageCount":18,"participants":["Junio C Hamano","Antoine Pelisse","René Scharfe"],"isPatch":true,"patchVersion":2,"patchTotal":10},"messages":[{"id":"206252","messageId":"1357603821-8647-1-git-send-email-gitster@pobox.com","threadId":"32553","inReplyTo":null,"subject":"[PATCH v2 00/10] reroll of ap/log-mailmap","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-01-08T00:10:11Z","receivedAt":"2013-01-08T00:10:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This is a reroll of the previous series Antoine posted on Saturday.\n\nA new patch \"string-list: allow case-insensitive string list\"\nteaches the string-list API that some string lists can be sorted\ncase insensitively (actually, you can feed any custom two string\ncomparison functions).\n\nThe string_list_lookup_extended() function introduced by the\nprevious series has been discarded.  Instead, the third patch\n\"mailmap: remove email copy and length limitation\" introduces a\nhelper function that takes a <char *, size_t> key that is not NUL\nterminated to look for a matching item in a string list, and uses\nthat to update map_user() function, together with the fourth\npatch \"mailmap: simplify map_user() interface\".\n\nAll other patches are unmodified from Antoine's series (modulo\nwording tweaks here and there).\n\nAntoine Pelisse (9):\n  Use split_ident_line to parse author and committer\n  mailmap: remove email copy and length limitation\n  mailmap: simplify map_user() interface\n  mailmap: add mailmap structure to rev_info and pp\n  pretty: use mailmap to display username and email\n  log: add --use-mailmap option\n  test: add test for --use-mailmap option\n  log: grep author/committer using mailmap\n  log: add log.mailmap configuration option\n\nJunio C Hamano (1):\n  string-list: allow case-insensitive string list\n\n Documentation/config.txt  |   4 +\n Documentation/git-log.txt |   5 ++\n builtin/blame.c           | 183 ++++++++++++++++++++++------------------------\n builtin/log.c             |  16 +++-\n builtin/shortlog.c        |  54 ++++----------\n commit.h                  |   1 +\n log-tree.c                |   1 +\n mailmap.c                 |  94 +++++++++++++++---------\n mailmap.h                 |   4 +-\n pretty.c                  | 114 ++++++++++++++++-------------\n revision.c                |  54 ++++++++++++++\n revision.h                |   1 +\n string-list.c             |  17 ++++-\n string-list.h             |   4 +\n t/t4203-mailmap.sh        |  56 ++++++++++++++\n 15 files changed, 379 insertions(+), 229 deletions(-)\n\n-- \n1.8.1.304.gf036638\n"},{"id":"206251","messageId":"1357603821-8647-2-git-send-email-gitster@pobox.com","threadId":"32553","inReplyTo":"1357603821-8647-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 01/10] string-list: allow case-insensitive string list","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-01-08T00:10:12Z","receivedAt":"2013-01-08T00:10:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Some string list needs to be searched case insensitively, and for\nthat to work correctly, the string needs to be sorted case\ninsensitively from the beginning.\n\nAllow a custom comparison function to be defined on a string list\ninstance and use it throughout in place of strcmp().\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n string-list.c | 17 +++++++++++++----\n string-list.h |  4 ++++\n 2 files changed, 17 insertions(+), 4 deletions(-)\n\ndiff --git a/string-list.c b/string-list.c\nindex 397e6cf..6f3d8cf 100644\n--- a/string-list.c\n+++ b/string-list.c\n@@ -7,10 +7,11 @@ static int get_entry_index(const struct string_list *list, const char *string,\n \t\tint *exact_match)\n {\n \tint left = -1, right = list->nr;\n+\tcompare_strings_fn cmp = list->cmp ? list->cmp : strcmp;\n \n \twhile (left + 1 < right) {\n \t\tint middle = (left + right) / 2;\n-\t\tint compare = strcmp(string, list->items[middle].string);\n+\t\tint compare = cmp(string, list->items[middle].string);\n \t\tif (compare < 0)\n \t\t\tright = middle;\n \t\telse if (compare > 0)\n@@ -96,8 +97,9 @@ void string_list_remove_duplicates(struct string_list *list, int free_util)\n {\n \tif (list->nr > 1) {\n \t\tint src, dst;\n+\t\tcompare_strings_fn cmp = list->cmp ? list->cmp : strcmp;\n \t\tfor (src = dst = 1; src < list->nr; src++) {\n-\t\t\tif (!strcmp(list->items[dst - 1].string, list->items[src].string)) {\n+\t\t\tif (!cmp(list->items[dst - 1].string, list->items[src].string)) {\n \t\t\t\tif (list->strdup_strings)\n \t\t\t\t\tfree(list->items[src].string);\n \t\t\t\tif (free_util)\n@@ -230,15 +232,20 @@ struct string_list_item *string_list_append(struct string_list *list,\n \t\t\tlist->strdup_strings ? xstrdup(string) : (char *)string);\n }\n \n+/* Yuck */\n+static compare_strings_fn compare_for_qsort;\n+\n+/* Only call this from inside sort_string_list! */\n static int cmp_items(const void *a, const void *b)\n {\n \tconst struct string_list_item *one = a;\n \tconst struct string_list_item *two = b;\n-\treturn strcmp(one->string, two->string);\n+\treturn compare_for_qsort(one->string, two->string);\n }\n \n void sort_string_list(struct string_list *list)\n {\n+\tcompare_for_qsort = list->cmp ? list->cmp : strcmp;\n \tqsort(list->items, list->nr, sizeof(*list->items), cmp_items);\n }\n \n@@ -246,8 +253,10 @@ struct string_list_item *unsorted_string_list_lookup(struct string_list *list,\n \t\t\t\t\t\t     const char *string)\n {\n \tint i;\n+\tcompare_strings_fn cmp = list->cmp ? list->cmp : strcmp;\n+\n \tfor (i = 0; i < list->nr; i++)\n-\t\tif (!strcmp(string, list->items[i].string))\n+\t\tif (!cmp(string, list->items[i].string))\n \t\t\treturn list->items + i;\n \treturn NULL;\n }\ndiff --git a/string-list.h b/string-list.h\nindex c50b0d0..446e79e 100644\n--- a/string-list.h\n+++ b/string-list.h\n@@ -5,10 +5,14 @@ struct string_list_item {\n \tchar *string;\n \tvoid *util;\n };\n+\n+typedef int (*compare_strings_fn)(const char *, const char *);\n+\n struct string_list {\n \tstruct string_list_item *items;\n \tunsigned int nr, alloc;\n \tunsigned int strdup_strings:1;\n+\tcompare_strings_fn cmp; /* NULL uses strcmp() */\n };\n \n #define STRING_LIST_INIT_NODUP { NULL, 0, 0, 0 }\n-- \n1.8.1.304.gf036638\n"},{"id":"206253","messageId":"1357603821-8647-3-git-send-email-gitster@pobox.com","threadId":"32553","inReplyTo":"1357603821-8647-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 02/10] Use split_ident_line to parse author and committer","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-01-08T00:10:13Z","receivedAt":"2013-01-08T00:10:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"From: Antoine Pelisse <apelisse@gmail.com>\n\nCurrently blame.c::get_acline(), pretty.c::pp_user_info() and\nshortlog.c::insert_one_record() are parsing author name, email, time\nand tz themselves.\n\nUse ident.c::split_ident_line() for better code reuse.\n\nSigned-off-by: Antoine Pelisse <apelisse@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/blame.c    | 59 +++++++++++++++++++-----------------------------------\n builtin/shortlog.c | 36 +++++++++------------------------\n pretty.c           | 35 +++++++++++++++++++-------------\n 3 files changed, 52 insertions(+), 78 deletions(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex cfae569..dd4aff9 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -1343,8 +1343,9 @@ static void get_ac_line(const char *inbuf, const char *what,\n \t\t\tint mail_len, char *mail,\n \t\t\tunsigned long *time, const char **tz)\n {\n-\tint len, tzlen, maillen;\n-\tchar *tmp, *endp, *timepos, *mailpos;\n+\tstruct ident_split ident;\n+\tint len, tzlen, maillen, namelen;\n+\tchar *tmp, *endp, *mailpos;\n \n \ttmp = strstr(inbuf, what);\n \tif (!tmp)\n@@ -1355,7 +1356,10 @@ static void get_ac_line(const char *inbuf, const char *what,\n \t\tlen = strlen(tmp);\n \telse\n \t\tlen = endp - tmp;\n-\tif (person_len <= len) {\n+\tif (person_len <= len)\n+\t\tgoto error_out;\n+\n+\tif (split_ident_line(&ident, tmp, len)) {\n \terror_out:\n \t\t/* Ugh */\n \t\t*tz = \"(unknown)\";\n@@ -1364,47 +1368,26 @@ static void get_ac_line(const char *inbuf, const char *what,\n \t\t*time = 0;\n \t\treturn;\n \t}\n-\tmemcpy(person, tmp, len);\n \n-\ttmp = person;\n-\ttmp += len;\n-\t*tmp = 0;\n-\twhile (person < tmp && *tmp != ' ')\n-\t\ttmp--;\n-\tif (tmp <= person)\n-\t\tgoto error_out;\n-\t*tz = tmp+1;\n-\ttzlen = (person+len)-(tmp+1);\n+\tnamelen = ident.name_end - ident.name_begin;\n+\tmemcpy(person, ident.name_begin, namelen);\n+\tperson[namelen] = 0;\n \n-\t*tmp = 0;\n-\twhile (person < tmp && *tmp != ' ')\n-\t\ttmp--;\n-\tif (tmp <= person)\n-\t\tgoto error_out;\n-\t*time = strtoul(tmp, NULL, 10);\n-\ttimepos = tmp;\n+\tmaillen = ident.mail_end - ident.mail_begin + 2;\n+\tmemcpy(mail, ident.mail_begin - 1, maillen);\n+\tmail[maillen] = 0;\n \n-\t*tmp = 0;\n-\twhile (person < tmp && !(*tmp == ' ' && tmp[1] == '<'))\n-\t\ttmp--;\n-\tif (tmp <= person)\n-\t\treturn;\n-\tmailpos = tmp + 1;\n-\t*tmp = 0;\n-\tmaillen = timepos - tmp;\n-\tmemcpy(mail, mailpos, maillen);\n+\t*time = strtoul(ident.date_begin, NULL, 10);\n \n-\tif (!mailmap.nr)\n-\t\treturn;\n+\ttzlen = ident.tz_end - ident.tz_begin;\n \n-\t/*\n-\t * mailmap expansion may make the name longer.\n-\t * make room by pushing stuff down.\n-\t */\n-\ttmp = person + person_len - (tzlen + 1);\n-\tmemmove(tmp, *tz, tzlen);\n+\t/* Place tz at the end of person */\n+\t*tz = tmp = person + person_len - (tzlen + 1);\n+\tmemcpy(tmp, ident.tz_begin, tzlen);\n \ttmp[tzlen] = 0;\n-\t*tz = tmp;\n+\n+\tif (!mailmap.nr)\n+\t\treturn;\n \n \t/*\n \t * Now, convert both name and e-mail using mailmap\ndiff --git a/builtin/shortlog.c b/builtin/shortlog.c\nindex b316cf3..03c6cd7 100644\n--- a/builtin/shortlog.c\n+++ b/builtin/shortlog.c\n@@ -40,40 +40,24 @@ static void insert_one_record(struct shortlog *log,\n \tchar emailbuf[1024];\n \tsize_t len;\n \tconst char *eol;\n-\tconst char *boemail, *eoemail;\n \tstruct strbuf subject = STRBUF_INIT;\n+\tstruct ident_split ident;\n \n-\tboemail = strchr(author, '<');\n-\tif (!boemail)\n-\t\treturn;\n-\teoemail = strchr(boemail, '>');\n-\tif (!eoemail)\n+\tif (split_ident_line(&ident, author, strlen(author)))\n \t\treturn;\n \n \t/* copy author name to namebuf, to support matching on both name and email */\n-\tmemcpy(namebuf, author, boemail - author);\n-\tlen = boemail - author;\n-\twhile (len > 0 && isspace(namebuf[len-1]))\n-\t\tlen--;\n+\tlen = ident.name_end - ident.name_begin;\n+\tmemcpy(namebuf, ident.name_begin, len);\n \tnamebuf[len] = 0;\n \n \t/* copy email name to emailbuf, to allow email replacement as well */\n-\tmemcpy(emailbuf, boemail+1, eoemail - boemail);\n-\temailbuf[eoemail - boemail - 1] = 0;\n-\n-\tif (!map_user(&log->mailmap, emailbuf, sizeof(emailbuf), namebuf, sizeof(namebuf))) {\n-\t\twhile (author < boemail && isspace(*author))\n-\t\t\tauthor++;\n-\t\tfor (len = 0;\n-\t\t     len < sizeof(namebuf) - 1 && author + len < boemail;\n-\t\t     len++)\n-\t\t\tnamebuf[len] = author[len];\n-\t\twhile (0 < len && isspace(namebuf[len-1]))\n-\t\t\tlen--;\n-\t\tnamebuf[len] = '\\0';\n-\t}\n-\telse\n-\t\tlen = strlen(namebuf);\n+\tlen = ident.mail_end - ident.mail_begin;\n+\tmemcpy(emailbuf, ident.mail_begin, len);\n+\temailbuf[len] = 0;\n+\n+\tmap_user(&log->mailmap, emailbuf, sizeof(emailbuf), namebuf, sizeof(namebuf));\n+\tlen = strlen(namebuf);\n \n \tif (log->email) {\n \t\tsize_t room = sizeof(namebuf) - len - 1;\ndiff --git a/pretty.c b/pretty.c\nindex 5bdc2e7..350d1df 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -387,29 +387,36 @@ void pp_user_info(const struct pretty_print_context *pp,\n \t\t  const char *what, struct strbuf *sb,\n \t\t  const char *line, const char *encoding)\n {\n+\tstruct ident_split ident;\n+\tint linelen, namelen;\n+\tchar *line_end, *date;\n \tint max_length = 78; /* per rfc2822 */\n-\tchar *date;\n-\tint namelen;\n \tunsigned long time;\n \tint tz;\n \n \tif (pp->fmt == CMIT_FMT_ONELINE)\n \t\treturn;\n-\tdate = strchr(line, '>');\n-\tif (!date)\n+\n+\tline_end = strchr(line, '\\n');\n+\tif (!line_end) {\n+\t\tline_end = strchr(line, '\\0');\n+\t\tif (!line_end)\n+\t\t\treturn;\n+\t}\n+\n+\tlinelen = ++line_end - line;\n+\tif (split_ident_line(&ident, line, linelen))\n \t\treturn;\n-\tnamelen = ++date - line;\n-\ttime = strtoul(date, &date, 10);\n+\n+\tnamelen = ident.mail_end - ident.name_begin + 1;\n+\ttime = strtoul(ident.date_begin, &date, 10);\n \ttz = strtol(date, NULL, 10);\n \n \tif (pp->fmt == CMIT_FMT_EMAIL) {\n-\t\tchar *name_tail = strchr(line, '<');\n \t\tint display_name_length;\n-\t\tif (!name_tail)\n-\t\t\treturn;\n-\t\twhile (line < name_tail && isspace(name_tail[-1]))\n-\t\t\tname_tail--;\n-\t\tdisplay_name_length = name_tail - line;\n+\n+\t\tdisplay_name_length = ident.name_end - ident.name_begin;\n+\n \t\tstrbuf_addstr(sb, \"From: \");\n \t\tif (needs_rfc2047_encoding(line, display_name_length, RFC2047_ADDRESS)) {\n \t\t\tadd_rfc2047(sb, line, display_name_length,\n@@ -427,10 +434,10 @@ void pp_user_info(const struct pretty_print_context *pp,\n \t\t}\n \t\tif (namelen - display_name_length + last_line_length(sb) > max_length) {\n \t\t\tstrbuf_addch(sb, '\\n');\n-\t\t\tif (!isspace(name_tail[0]))\n+\t\t\tif (!isspace(ident.name_end[0]))\n \t\t\t\tstrbuf_addch(sb, ' ');\n \t\t}\n-\t\tstrbuf_add(sb, name_tail, namelen - display_name_length);\n+\t\tstrbuf_add(sb, ident.name_end, namelen - display_name_length);\n \t\tstrbuf_addch(sb, '\\n');\n \t} else {\n \t\tstrbuf_addf(sb, \"%s: %.*s%.*s\\n\", what,\n-- \n1.8.1.304.gf036638\n"},{"id":"206254","messageId":"1357603821-8647-4-git-send-email-gitster@pobox.com","threadId":"32553","inReplyTo":"1357603821-8647-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 03/10] mailmap: remove email copy and length limitation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-01-08T00:10:14Z","receivedAt":"2013-01-08T00:10:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"In map_user(), we have email pointer that points at the beginning of\nan e-mail address, but the buffer is not terminated with a NUL after\nthe e-mail address.  It typically has \">\" after the address, and it\ncould have even more if it comes from author/committer line in a\ncommit object.  Or it may not have \">\" after it.\n\nWe used to copy the e-mail address proper into a temporary buffer\nbefore asking the string-list API to find the e-mail address in the\nmailmap, because string_list_lookup() function only takes a NUL\nterminated full string.\n\nIntroduce a helper function lookup_prefix that takes the email\npointer and the length, and finds a matching entry in the string\nlist used for the mailmap, by doing the following:\n\n - First ask string_list_find_insert_index() where in its sorted\n   list the e-mail address we have (including the possible trailing\n   junk \">...\") would be inserted.\n\n - It could find an exact match (e.g. we had a clean e-mail address\n   without any trailing junk).  We can return the item in that case.\n\n - Or it could return the index of an item that sorts after the\n   e-mail address we have.\n\n - If we did not find an exact match against a clean e-mail address,\n   then the record we are looking for in the mailmap has to exist\n   before the index returned by the function (i.e. \"email>junk\"\n   always sorts later than \"email\").  Iterate, starting from that\n   index, down the map->items[] array until we find the exact record\n   we are looking for, or we see a record with a key that definitely\n   sorts earlier than the e-mail we are looking for (i.e. when we\n   are looking for \"email\" in \"email>junk\", a record in the mailmap\n   that begins with \"emaik\" strictly sorts before \"email\", if such a\n   key existed in the mailmap).\n\nThis, together with the earlier enhancement to support\ncase-insensitive sorting, allow us to remove an extra copy of email\nbuffer to downcase it.\n\nA part of this is based on Antoine Pelisse's previous work.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n mailmap.c | 61 +++++++++++++++++++++++++++++++++++++++++++++----------------\n 1 file changed, 45 insertions(+), 16 deletions(-)\n\ndiff --git a/mailmap.c b/mailmap.c\nindex ea4b471..1a0b769 100644\n--- a/mailmap.c\n+++ b/mailmap.c\n@@ -174,6 +174,7 @@ static int read_single_mailmap(struct string_list *map, const char *filename, ch\n int read_mailmap(struct string_list *map, char **repo_abbrev)\n {\n \tmap->strdup_strings = 1;\n+\tmap->cmp = strcasecmp;\n \t/* each failure returns 1, so >1 means both calls failed */\n \treturn read_single_mailmap(map, \".mailmap\", repo_abbrev) +\n \t       read_single_mailmap(map, git_mailmap_file, repo_abbrev) > 1;\n@@ -187,14 +188,50 @@ void clear_mailmap(struct string_list *map)\n \tdebug_mm(\"mailmap: cleared\\n\");\n }\n \n+static struct string_list_item *lookup_prefix(struct string_list *map,\n+\t\t\t\t\t      const char *string, size_t len)\n+{\n+\tint i = string_list_find_insert_index(map, string, 1);\n+\tif (i < 0) {\n+\t\t/* exact match */\n+\t\ti = -1 - i;\n+\t\t/* does it match exactly? */\n+\t\tif (!map->items[i].string[len])\n+\t\t\treturn &map->items[i];\n+\t}\n+\n+\t/*\n+\t * i is at the exact match to an overlong key, or\n+\t * location the possibly overlong key would be inserted,\n+\t * which must be after the real location of the key.\n+\t */\n+\twhile (0 <= --i && i < map->nr) {\n+\t\tint cmp = strncasecmp(map->items[i].string, string, len);\n+\t\tif (cmp < 0)\n+\t\t\t/*\n+\t\t\t * \"i\" points at a key definitely below the prefix;\n+\t\t\t * the map does not have string[0:len] in it.\n+\t\t\t */\n+\t\t\tbreak;\n+\t\telse if (!cmp && !map->items[i].string[len])\n+\t\t\t/* found it */\n+\t\t\treturn &map->items[i];\n+\t\t/*\n+\t\t * otherwise, the string at \"i\" may be string[0:len]\n+\t\t * followed by a string that sorts later than string[len:];\n+\t\t * keep trying.\n+\t\t */\n+\t}\n+\treturn NULL;\n+}\n+\n int map_user(struct string_list *map,\n \t     char *email, int maxlen_email, char *name, int maxlen_name)\n {\n \tchar *end_of_email;\n \tstruct string_list_item *item;\n \tstruct mailmap_entry *me;\n-\tchar buf[1024], *mailbuf;\n-\tint i;\n+\tsize_t maillen;\n \n \t/* figure out space requirement for email */\n \tend_of_email = strchr(email, '>');\n@@ -204,18 +241,12 @@ int map_user(struct string_list *map,\n \t\tif (!end_of_email)\n \t\t\treturn 0;\n \t}\n-\tif (end_of_email - email + 1 < sizeof(buf))\n-\t\tmailbuf = buf;\n-\telse\n-\t\tmailbuf = xmalloc(end_of_email - email + 1);\n-\n-\t/* downcase the email address */\n-\tfor (i = 0; i < end_of_email - email; i++)\n-\t\tmailbuf[i] = tolower(email[i]);\n-\tmailbuf[i] = 0;\n-\n-\tdebug_mm(\"map_user: map '%s' <%s>\\n\", name, mailbuf);\n-\titem = string_list_lookup(map, mailbuf);\n+\n+\tmaillen = end_of_email - email;\n+\n+\tdebug_mm(\"map_user: map '%s' <%.*s>\\n\", name, maillen, email);\n+\n+\titem = lookup_prefix(map, email, maillen);\n \tif (item != NULL) {\n \t\tme = (struct mailmap_entry *)item->util;\n \t\tif (me->namemap.nr) {\n@@ -226,8 +257,6 @@ int map_user(struct string_list *map,\n \t\t\t\titem = subitem;\n \t\t}\n \t}\n-\tif (mailbuf != buf)\n-\t\tfree(mailbuf);\n \tif (item != NULL) {\n \t\tstruct mailmap_info *mi = (struct mailmap_info *)item->util;\n \t\tif (mi->name == NULL && (mi->email == NULL || maxlen_email == 0)) {\n-- \n1.8.1.304.gf036638\n"},{"id":"206256","messageId":"1357603821-8647-5-git-send-email-gitster@pobox.com","threadId":"32553","inReplyTo":"1357603821-8647-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 04/10] mailmap: simplify map_user() interface","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-01-08T00:10:15Z","receivedAt":"2013-01-08T00:10:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"From: Antoine Pelisse <apelisse@gmail.com>\n\nSimplify map_user(), mostly to avoid copies of string buffers. It\nalso simplifies caller functions.\n\nmap_user() directly receive pointers and length from the commit buffer\nas mail and name. If mapping of the user and mail can be done, the\npointer is updated to a new location. Lengths are also updated if\nnecessary.\n\nThe caller of map_user() can then copy the new email and name if\nnecessary.\n\nSigned-off-by: Antoine Pelisse <apelisse@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/blame.c    | 156 +++++++++++++++++++++++++++--------------------------\n builtin/shortlog.c |  32 +++++------\n mailmap.c          |  43 +++++++--------\n mailmap.h          |   4 +-\n pretty.c           |  35 +++++-------\n 5 files changed, 126 insertions(+), 144 deletions(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex dd4aff9..86450e3 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -1321,31 +1321,31 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)\n  * Information on commits, used for output.\n  */\n struct commit_info {\n-\tconst char *author;\n-\tconst char *author_mail;\n+\tstruct strbuf author;\n+\tstruct strbuf author_mail;\n \tunsigned long author_time;\n-\tconst char *author_tz;\n+\tstruct strbuf author_tz;\n \n \t/* filled only when asked for details */\n-\tconst char *committer;\n-\tconst char *committer_mail;\n+\tstruct strbuf committer;\n+\tstruct strbuf committer_mail;\n \tunsigned long committer_time;\n-\tconst char *committer_tz;\n+\tstruct strbuf committer_tz;\n \n-\tconst char *summary;\n+\tstruct strbuf summary;\n };\n \n /*\n  * Parse author/committer line in the commit object buffer\n  */\n static void get_ac_line(const char *inbuf, const char *what,\n-\t\t\tint person_len, char *person,\n-\t\t\tint mail_len, char *mail,\n-\t\t\tunsigned long *time, const char **tz)\n+\tstruct strbuf *name, struct strbuf *mail,\n+\tunsigned long *time, struct strbuf *tz)\n {\n \tstruct ident_split ident;\n-\tint len, tzlen, maillen, namelen;\n-\tchar *tmp, *endp, *mailpos;\n+\tsize_t len, maillen, namelen;\n+\tchar *tmp, *endp;\n+\tconst char *namebuf, *mailbuf;\n \n \ttmp = strstr(inbuf, what);\n \tif (!tmp)\n@@ -1356,51 +1356,61 @@ static void get_ac_line(const char *inbuf, const char *what,\n \t\tlen = strlen(tmp);\n \telse\n \t\tlen = endp - tmp;\n-\tif (person_len <= len)\n-\t\tgoto error_out;\n \n \tif (split_ident_line(&ident, tmp, len)) {\n \terror_out:\n \t\t/* Ugh */\n-\t\t*tz = \"(unknown)\";\n-\t\tstrcpy(person, *tz);\n-\t\tstrcpy(mail, *tz);\n+\t\ttmp = \"(unknown)\";\n+\t\tstrbuf_addstr(name, tmp);\n+\t\tstrbuf_addstr(mail, tmp);\n+\t\tstrbuf_addstr(tz, tmp);\n \t\t*time = 0;\n \t\treturn;\n \t}\n \n \tnamelen = ident.name_end - ident.name_begin;\n-\tmemcpy(person, ident.name_begin, namelen);\n-\tperson[namelen] = 0;\n+\tnamebuf = ident.name_begin;\n \n-\tmaillen = ident.mail_end - ident.mail_begin + 2;\n-\tmemcpy(mail, ident.mail_begin - 1, maillen);\n-\tmail[maillen] = 0;\n+\tmaillen = ident.mail_end - ident.mail_begin;\n+\tmailbuf = ident.mail_begin;\n \n \t*time = strtoul(ident.date_begin, NULL, 10);\n \n-\ttzlen = ident.tz_end - ident.tz_begin;\n-\n-\t/* Place tz at the end of person */\n-\t*tz = tmp = person + person_len - (tzlen + 1);\n-\tmemcpy(tmp, ident.tz_begin, tzlen);\n-\ttmp[tzlen] = 0;\n-\n-\tif (!mailmap.nr)\n-\t\treturn;\n+\tlen = ident.tz_end - ident.tz_begin;\n+\tstrbuf_add(tz, ident.tz_begin, len);\n \n \t/*\n \t * Now, convert both name and e-mail using mailmap\n \t */\n-\tif (map_user(&mailmap, mail+1, mail_len-1, person, tmp-person-1)) {\n-\t\t/* Add a trailing '>' to email, since map_user returns plain emails\n-\t\t   Note: It already has '<', since we replace from mail+1 */\n-\t\tmailpos = memchr(mail, '\\0', mail_len);\n-\t\tif (mailpos && mailpos-mail < mail_len - 1) {\n-\t\t\t*mailpos = '>';\n-\t\t\t*(mailpos+1) = '\\0';\n-\t\t}\n-\t}\n+\tmap_user(&mailmap, &mailbuf, &maillen,\n+\t\t &namebuf, &namelen);\n+\n+\tstrbuf_addf(mail, \"<%.*s>\", (int)maillen, mailbuf);\n+\tstrbuf_add(name, namebuf, namelen);\n+}\n+\n+static void commit_info_init(struct commit_info *ci)\n+{\n+\n+\tstrbuf_init(&ci->author, 0);\n+\tstrbuf_init(&ci->author_mail, 0);\n+\tstrbuf_init(&ci->author_tz, 0);\n+\tstrbuf_init(&ci->committer, 0);\n+\tstrbuf_init(&ci->committer_mail, 0);\n+\tstrbuf_init(&ci->committer_tz, 0);\n+\tstrbuf_init(&ci->summary, 0);\n+}\n+\n+static void commit_info_destroy(struct commit_info *ci)\n+{\n+\n+\tstrbuf_release(&ci->author);\n+\tstrbuf_release(&ci->author_mail);\n+\tstrbuf_release(&ci->author_tz);\n+\tstrbuf_release(&ci->committer);\n+\tstrbuf_release(&ci->committer_mail);\n+\tstrbuf_release(&ci->committer_tz);\n+\tstrbuf_release(&ci->summary);\n }\n \n static void get_commit_info(struct commit *commit,\n@@ -1410,11 +1420,8 @@ static void get_commit_info(struct commit *commit,\n \tint len;\n \tconst char *subject, *encoding;\n \tchar *reencoded, *message;\n-\tstatic char author_name[1024];\n-\tstatic char author_mail[1024];\n-\tstatic char committer_name[1024];\n-\tstatic char committer_mail[1024];\n-\tstatic char summary_buf[1024];\n+\n+\tcommit_info_init(ret);\n \n \t/*\n \t * We've operated without save_commit_buffer, so\n@@ -1432,11 +1439,8 @@ static void get_commit_info(struct commit *commit,\n \tencoding = get_log_output_encoding();\n \treencoded = logmsg_reencode(commit, encoding);\n \tmessage   = reencoded ? reencoded : commit->buffer;\n-\tret->author = author_name;\n-\tret->author_mail = author_mail;\n \tget_ac_line(message, \"\\nauthor \",\n-\t\t    sizeof(author_name), author_name,\n-\t\t    sizeof(author_mail), author_mail,\n+\t\t    &ret->author, &ret->author_mail,\n \t\t    &ret->author_time, &ret->author_tz);\n \n \tif (!detailed) {\n@@ -1444,21 +1448,16 @@ static void get_commit_info(struct commit *commit,\n \t\treturn;\n \t}\n \n-\tret->committer = committer_name;\n-\tret->committer_mail = committer_mail;\n \tget_ac_line(message, \"\\ncommitter \",\n-\t\t    sizeof(committer_name), committer_name,\n-\t\t    sizeof(committer_mail), committer_mail,\n+\t\t    &ret->committer, &ret->committer_mail,\n \t\t    &ret->committer_time, &ret->committer_tz);\n \n-\tret->summary = summary_buf;\n \tlen = find_commit_subject(message, &subject);\n-\tif (len && len < sizeof(summary_buf)) {\n-\t\tmemcpy(summary_buf, subject, len);\n-\t\tsummary_buf[len] = 0;\n-\t} else {\n-\t\tsprintf(summary_buf, \"(%s)\", sha1_to_hex(commit->object.sha1));\n-\t}\n+\tif (len)\n+\t\tstrbuf_add(&ret->summary, subject, len);\n+\telse\n+\t\tstrbuf_addf(&ret->summary, \"(%s)\", sha1_to_hex(commit->object.sha1));\n+\n \tfree(reencoded);\n }\n \n@@ -1487,15 +1486,15 @@ static int emit_one_suspect_detail(struct origin *suspect, int repeat)\n \n \tsuspect->commit->object.flags |= METAINFO_SHOWN;\n \tget_commit_info(suspect->commit, &ci, 1);\n-\tprintf(\"author %s\\n\", ci.author);\n-\tprintf(\"author-mail %s\\n\", ci.author_mail);\n+\tprintf(\"author %s\\n\", ci.author.buf);\n+\tprintf(\"author-mail %s\\n\", ci.author_mail.buf);\n \tprintf(\"author-time %lu\\n\", ci.author_time);\n-\tprintf(\"author-tz %s\\n\", ci.author_tz);\n-\tprintf(\"committer %s\\n\", ci.committer);\n-\tprintf(\"committer-mail %s\\n\", ci.committer_mail);\n+\tprintf(\"author-tz %s\\n\", ci.author_tz.buf);\n+\tprintf(\"committer %s\\n\", ci.committer.buf);\n+\tprintf(\"committer-mail %s\\n\", ci.committer_mail.buf);\n \tprintf(\"committer-time %lu\\n\", ci.committer_time);\n-\tprintf(\"committer-tz %s\\n\", ci.committer_tz);\n-\tprintf(\"summary %s\\n\", ci.summary);\n+\tprintf(\"committer-tz %s\\n\", ci.committer_tz.buf);\n+\tprintf(\"summary %s\\n\", ci.summary.buf);\n \tif (suspect->commit->object.flags & UNINTERESTING)\n \t\tprintf(\"boundary\\n\");\n \tif (suspect->previous) {\n@@ -1503,6 +1502,9 @@ static int emit_one_suspect_detail(struct origin *suspect, int repeat)\n \t\tprintf(\"previous %s \", sha1_to_hex(prev->commit->object.sha1));\n \t\twrite_name_quoted(prev->path, stdout, '\\n');\n \t}\n+\n+\tcommit_info_destroy(&ci);\n+\n \treturn 1;\n }\n \n@@ -1689,11 +1691,11 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)\n \t\tif (opt & OUTPUT_ANNOTATE_COMPAT) {\n \t\t\tconst char *name;\n \t\t\tif (opt & OUTPUT_SHOW_EMAIL)\n-\t\t\t\tname = ci.author_mail;\n+\t\t\t\tname = ci.author_mail.buf;\n \t\t\telse\n-\t\t\t\tname = ci.author;\n+\t\t\t\tname = ci.author.buf;\n \t\t\tprintf(\"\\t(%10s\\t%10s\\t%d)\", name,\n-\t\t\t       format_time(ci.author_time, ci.author_tz,\n+\t\t\t       format_time(ci.author_time, ci.author_tz.buf,\n \t\t\t\t\t   show_raw_time),\n \t\t\t       ent->lno + 1 + cnt);\n \t\t} else {\n@@ -1712,14 +1714,14 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)\n \t\t\t\tconst char *name;\n \t\t\t\tint pad;\n \t\t\t\tif (opt & OUTPUT_SHOW_EMAIL)\n-\t\t\t\t\tname = ci.author_mail;\n+\t\t\t\t\tname = ci.author_mail.buf;\n \t\t\t\telse\n-\t\t\t\t\tname = ci.author;\n+\t\t\t\t\tname = ci.author.buf;\n \t\t\t\tpad = longest_author - utf8_strwidth(name);\n \t\t\t\tprintf(\" (%s%*s %10s\",\n \t\t\t\t       name, pad, \"\",\n \t\t\t\t       format_time(ci.author_time,\n-\t\t\t\t\t\t   ci.author_tz,\n+\t\t\t\t\t\t   ci.author_tz.buf,\n \t\t\t\t\t\t   show_raw_time));\n \t\t\t}\n \t\t\tprintf(\" %*d) \",\n@@ -1734,6 +1736,8 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)\n \n \tif (sb->final_buf_size && cp[-1] != '\\n')\n \t\tputchar('\\n');\n+\n+\tcommit_info_destroy(&ci);\n }\n \n static void output(struct scoreboard *sb, int option)\n@@ -1858,9 +1862,9 @@ static void find_alignment(struct scoreboard *sb, int *option)\n \t\t\tsuspect->commit->object.flags |= METAINFO_SHOWN;\n \t\t\tget_commit_info(suspect->commit, &ci, 1);\n \t\t\tif (*option & OUTPUT_SHOW_EMAIL)\n-\t\t\t\tnum = utf8_strwidth(ci.author_mail);\n+\t\t\t\tnum = utf8_strwidth(ci.author_mail.buf);\n \t\t\telse\n-\t\t\t\tnum = utf8_strwidth(ci.author);\n+\t\t\t\tnum = utf8_strwidth(ci.author.buf);\n \t\t\tif (longest_author < num)\n \t\t\t\tlongest_author = num;\n \t\t}\n@@ -1872,6 +1876,8 @@ static void find_alignment(struct scoreboard *sb, int *option)\n \t\t\tlongest_dst_lines = num;\n \t\tif (largest_score < ent_score(sb, e))\n \t\t\tlargest_score = ent_score(sb, e);\n+\n+\t\tcommit_info_destroy(&ci);\n \t}\n \tmax_orig_digits = decimal_width(longest_src_lines);\n \tmax_digits = decimal_width(longest_dst_lines);\ndiff --git a/builtin/shortlog.c b/builtin/shortlog.c\nindex 03c6cd7..1eeed0f 100644\n--- a/builtin/shortlog.c\n+++ b/builtin/shortlog.c\n@@ -36,36 +36,28 @@ static void insert_one_record(struct shortlog *log,\n \tconst char *dot3 = log->common_repo_prefix;\n \tchar *buffer, *p;\n \tstruct string_list_item *item;\n-\tchar namebuf[1024];\n-\tchar emailbuf[1024];\n-\tsize_t len;\n+\tconst char *mailbuf, *namebuf;\n+\tsize_t namelen, maillen;\n \tconst char *eol;\n \tstruct strbuf subject = STRBUF_INIT;\n+\tstruct strbuf namemailbuf = STRBUF_INIT;\n \tstruct ident_split ident;\n \n \tif (split_ident_line(&ident, author, strlen(author)))\n \t\treturn;\n \n-\t/* copy author name to namebuf, to support matching on both name and email */\n-\tlen = ident.name_end - ident.name_begin;\n-\tmemcpy(namebuf, ident.name_begin, len);\n-\tnamebuf[len] = 0;\n+\tnamebuf = ident.name_begin;\n+\tmailbuf = ident.mail_begin;\n+\tnamelen = ident.name_end - ident.name_begin;\n+\tmaillen = ident.mail_end - ident.mail_begin;\n \n-\t/* copy email name to emailbuf, to allow email replacement as well */\n-\tlen = ident.mail_end - ident.mail_begin;\n-\tmemcpy(emailbuf, ident.mail_begin, len);\n-\temailbuf[len] = 0;\n+\tmap_user(&log->mailmap, &mailbuf, &maillen, &namebuf, &namelen);\n+\tstrbuf_add(&namemailbuf, namebuf, namelen);\n \n-\tmap_user(&log->mailmap, emailbuf, sizeof(emailbuf), namebuf, sizeof(namebuf));\n-\tlen = strlen(namebuf);\n+\tif (log->email)\n+\t\tstrbuf_addf(&namemailbuf, \" <%.*s>\", (int)maillen, mailbuf);\n \n-\tif (log->email) {\n-\t\tsize_t room = sizeof(namebuf) - len - 1;\n-\t\tint maillen = strlen(emailbuf);\n-\t\tsnprintf(namebuf + len, room, \" <%.*s>\", maillen, emailbuf);\n-\t}\n-\n-\titem = string_list_insert(&log->list, namebuf);\n+\titem = string_list_insert(&log->list, namemailbuf.buf);\n \tif (item->util == NULL)\n \t\titem->util = xcalloc(1, sizeof(struct string_list));\n \ndiff --git a/mailmap.c b/mailmap.c\nindex 1a0b769..5ba5c37 100644\n--- a/mailmap.c\n+++ b/mailmap.c\n@@ -226,50 +226,43 @@ static struct string_list_item *lookup_prefix(struct string_list *map,\n }\n \n int map_user(struct string_list *map,\n-\t     char *email, int maxlen_email, char *name, int maxlen_name)\n+\t\t\t const char **email, size_t *emaillen,\n+\t\t\t const char **name, size_t *namelen)\n {\n-\tchar *end_of_email;\n \tstruct string_list_item *item;\n \tstruct mailmap_entry *me;\n-\tsize_t maillen;\n-\n-\t/* figure out space requirement for email */\n-\tend_of_email = strchr(email, '>');\n-\tif (!end_of_email) {\n-\t\t/* email passed in might not be wrapped in <>, but end with a \\0 */\n-\t\tend_of_email = memchr(email, '\\0', maxlen_email);\n-\t\tif (!end_of_email)\n-\t\t\treturn 0;\n-\t}\n-\n-\tmaillen = end_of_email - email;\n \n-\tdebug_mm(\"map_user: map '%s' <%.*s>\\n\", name, maillen, email);\n+\tdebug_mm(\"map_user: map '%.*s' <%.*s>\\n\",\n+\t\t *name, *namelen, *emaillen, *email);\n \n-\titem = lookup_prefix(map, email, maillen);\n+\titem = lookup_prefix(map, *email, *emaillen);\n \tif (item != NULL) {\n \t\tme = (struct mailmap_entry *)item->util;\n \t\tif (me->namemap.nr) {\n \t\t\t/* The item has multiple items, so we'll look up on name too */\n \t\t\t/* If the name is not found, we choose the simple entry      */\n-\t\t\tstruct string_list_item *subitem = string_list_lookup(&me->namemap, name);\n+\t\t\tstruct string_list_item *subitem;\n+\t\t\tsubitem = lookup_prefix(&me->namemap, *name, *namelen);\n \t\t\tif (subitem)\n \t\t\t\titem = subitem;\n \t\t}\n \t}\n \tif (item != NULL) {\n \t\tstruct mailmap_info *mi = (struct mailmap_info *)item->util;\n-\t\tif (mi->name == NULL && (mi->email == NULL || maxlen_email == 0)) {\n+\t\tif (mi->name == NULL && mi->email == NULL) {\n \t\t\tdebug_mm(\"map_user:  -- (no simple mapping)\\n\");\n \t\t\treturn 0;\n \t\t}\n-\t\tif (maxlen_email && mi->email)\n-\t\t\tstrlcpy(email, mi->email, maxlen_email);\n-\t\telse\n-\t\t\t*end_of_email = '\\0';\n-\t\tif (maxlen_name && mi->name)\n-\t\t\tstrlcpy(name, mi->name, maxlen_name);\n-\t\tdebug_mm(\"map_user:  to '%s' <%s>\\n\", name, mi->email ? mi->email : \"\");\n+\t\tif (mi->email) {\n+\t\t\t\t*email = mi->email;\n+\t\t\t\t*emaillen = strlen(*email);\n+\t\t}\n+\t\tif (mi->name) {\n+\t\t\t\t*name = mi->name;\n+\t\t\t\t*namelen = strlen(*name);\n+\t\t}\n+\t\tdebug_mm(\"map_user:  to '%.*s' <.*%s>\\n\", *namelen, *name,\n+\t\t\t\t *emaillen, *email);\n \t\treturn 1;\n \t}\n \tdebug_mm(\"map_user:  --\\n\");\ndiff --git a/mailmap.h b/mailmap.h\nindex d5c3664..ed7c93b 100644\n--- a/mailmap.h\n+++ b/mailmap.h\n@@ -4,7 +4,7 @@\n int read_mailmap(struct string_list *map, char **repo_abbrev);\n void clear_mailmap(struct string_list *map);\n \n-int map_user(struct string_list *mailmap,\n-\t     char *email, int maxlen_email, char *name, int maxlen_name);\n+int map_user(struct string_list *map,\n+\t\t\t const char **email, size_t *emaillen, const char **name, size_t *namelen);\n \n #endif\ndiff --git a/pretty.c b/pretty.c\nindex 350d1df..dffcade 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -593,7 +593,8 @@ char *logmsg_reencode(const struct commit *commit,\n \treturn out;\n }\n \n-static int mailmap_name(char *email, int email_len, char *name, int name_len)\n+static int mailmap_name(const char **email, size_t *email_len,\n+\t\t\tconst char **name, size_t *name_len)\n {\n \tstatic struct string_list *mail_map;\n \tif (!mail_map) {\n@@ -610,36 +611,26 @@ static size_t format_person_part(struct strbuf *sb, char part,\n \tconst int placeholder_len = 2;\n \tint tz;\n \tunsigned long date = 0;\n-\tchar person_name[1024];\n-\tchar person_mail[1024];\n \tstruct ident_split s;\n-\tconst char *name_start, *name_end, *mail_start, *mail_end;\n+\tconst char *name, *mail;\n+\tsize_t maillen, namelen;\n \n \tif (split_ident_line(&s, msg, len) < 0)\n \t\tgoto skip;\n \n-\tname_start = s.name_begin;\n-\tname_end = s.name_end;\n-\tmail_start = s.mail_begin;\n-\tmail_end = s.mail_end;\n-\n-\tif (part == 'N' || part == 'E') { /* mailmap lookup */\n-\t\tsnprintf(person_name, sizeof(person_name), \"%.*s\",\n-\t\t\t (int)(name_end - name_start), name_start);\n-\t\tsnprintf(person_mail, sizeof(person_mail), \"%.*s\",\n-\t\t\t (int)(mail_end - mail_start), mail_start);\n-\t\tmailmap_name(person_mail, sizeof(person_mail), person_name, sizeof(person_name));\n-\t\tname_start = person_name;\n-\t\tname_end = name_start + strlen(person_name);\n-\t\tmail_start = person_mail;\n-\t\tmail_end = mail_start +  strlen(person_mail);\n-\t}\n+\tname = s.name_begin;\n+\tnamelen = s.name_end - s.name_begin;\n+\tmail = s.mail_begin;\n+\tmaillen = s.mail_end - s.mail_begin;\n+\n+\tif (part == 'N' || part == 'E') /* mailmap lookup */\n+\t\tmailmap_name(&mail, &maillen, &name, &namelen);\n \tif (part == 'n' || part == 'N') {\t/* name */\n-\t\tstrbuf_add(sb, name_start, name_end-name_start);\n+\t\tstrbuf_add(sb, name, namelen);\n \t\treturn placeholder_len;\n \t}\n \tif (part == 'e' || part == 'E') {\t/* email */\n-\t\tstrbuf_add(sb, mail_start, mail_end-mail_start);\n+\t\tstrbuf_add(sb, mail, maillen);\n \t\treturn placeholder_len;\n \t}\n \n-- \n1.8.1.304.gf036638\n"},{"id":"206257","messageId":"1357603821-8647-6-git-send-email-gitster@pobox.com","threadId":"32553","inReplyTo":"1357603821-8647-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 05/10] mailmap: add mailmap structure to rev_info and pp","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-01-08T00:10:16Z","receivedAt":"2013-01-08T00:10:16Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"From: Antoine Pelisse <apelisse@gmail.com>\n\nPass a mailmap from rev_info to pretty_print_context to so that the\npretty printer can use rewritten name and email address when showing\ncommits.\n\nSigned-off-by: Antoine Pelisse <apelisse@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n commit.h   | 1 +\n log-tree.c | 1 +\n revision.h | 1 +\n 3 files changed, 3 insertions(+)\n\ndiff --git a/commit.h b/commit.h\nindex b6ad8f3..7f8f987 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -89,6 +89,7 @@ struct pretty_print_context {\n \tchar *notes_message;\n \tstruct reflog_walk_info *reflog_info;\n \tconst char *output_encoding;\n+\tstruct string_list *mailmap;\n };\n \n struct userformat_want {\ndiff --git a/log-tree.c b/log-tree.c\nindex 4f86def..92254fd 100644\n--- a/log-tree.c\n+++ b/log-tree.c\n@@ -671,6 +671,7 @@ void show_log(struct rev_info *opt)\n \tctx.preserve_subject = opt->preserve_subject;\n \tctx.reflog_info = opt->reflog_info;\n \tctx.fmt = opt->commit_format;\n+\tctx.mailmap = opt->mailmap;\n \tpretty_print_commit(&ctx, commit, &msgbuf);\n \n \tif (opt->add_signoff)\ndiff --git a/revision.h b/revision.h\nindex 059bfff..83a79f5 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -143,6 +143,7 @@ struct rev_info {\n \tconst char\t*subject_prefix;\n \tint\t\tno_inline;\n \tint\t\tshow_log_size;\n+\tstruct string_list *mailmap;\n \n \t/* Filter by commit log message */\n \tstruct grep_opt\tgrep_filter;\n-- \n1.8.1.304.gf036638\n"},{"id":"206258","messageId":"1357603821-8647-7-git-send-email-gitster@pobox.com","threadId":"32553","inReplyTo":"1357603821-8647-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 06/10] pretty: use mailmap to display username and email","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-01-08T00:10:17Z","receivedAt":"2013-01-08T00:10:17Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"From: Antoine Pelisse <apelisse@gmail.com>\n\nUse the mailmap information to display the rewritten\nusername and email address in all log commands.\n\nSigned-off-by: Antoine Pelisse <apelisse@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n pretty.c | 58 +++++++++++++++++++++++++++++++++++++---------------------\n 1 file changed, 37 insertions(+), 21 deletions(-)\n\ndiff --git a/pretty.c b/pretty.c\nindex dffcade..622275c 100644\n--- a/pretty.c\n+++ b/pretty.c\n@@ -387,9 +387,13 @@ void pp_user_info(const struct pretty_print_context *pp,\n \t\t  const char *what, struct strbuf *sb,\n \t\t  const char *line, const char *encoding)\n {\n+\tstruct strbuf name;\n+\tstruct strbuf mail;\n \tstruct ident_split ident;\n-\tint linelen, namelen;\n+\tint linelen;\n \tchar *line_end, *date;\n+\tconst char *mailbuf, *namebuf;\n+\tsize_t namelen, maillen;\n \tint max_length = 78; /* per rfc2822 */\n \tunsigned long time;\n \tint tz;\n@@ -408,42 +412,54 @@ void pp_user_info(const struct pretty_print_context *pp,\n \tif (split_ident_line(&ident, line, linelen))\n \t\treturn;\n \n-\tnamelen = ident.mail_end - ident.name_begin + 1;\n+\n+\tmailbuf = ident.mail_begin;\n+\tmaillen = ident.mail_end - ident.mail_begin;\n+\tnamebuf = ident.name_begin;\n+\tnamelen = ident.name_end - ident.name_begin;\n+\n+\tif (pp->mailmap)\n+\t\tmap_user(pp->mailmap, &mailbuf, &maillen, &namebuf, &namelen);\n+\n+\tstrbuf_init(&mail, 0);\n+\tstrbuf_init(&name, 0);\n+\n+\tstrbuf_add(&mail, mailbuf, maillen);\n+\tstrbuf_add(&name, namebuf, namelen);\n+\n+\tnamelen = name.len + mail.len + 3; /* ' ' + '<' + '>' */\n \ttime = strtoul(ident.date_begin, &date, 10);\n \ttz = strtol(date, NULL, 10);\n \n \tif (pp->fmt == CMIT_FMT_EMAIL) {\n-\t\tint display_name_length;\n-\n-\t\tdisplay_name_length = ident.name_end - ident.name_begin;\n-\n \t\tstrbuf_addstr(sb, \"From: \");\n-\t\tif (needs_rfc2047_encoding(line, display_name_length, RFC2047_ADDRESS)) {\n-\t\t\tadd_rfc2047(sb, line, display_name_length,\n-\t\t\t\t\t\tencoding, RFC2047_ADDRESS);\n+\t\tif (needs_rfc2047_encoding(name.buf, name.len, RFC2047_ADDRESS)) {\n+\t\t\tadd_rfc2047(sb, name.buf, name.len,\n+\t\t\t\t    encoding, RFC2047_ADDRESS);\n \t\t\tmax_length = 76; /* per rfc2047 */\n-\t\t} else if (needs_rfc822_quoting(line, display_name_length)) {\n+\t\t} else if (needs_rfc822_quoting(name.buf, name.len)) {\n \t\t\tstruct strbuf quoted = STRBUF_INIT;\n-\t\t\tadd_rfc822_quoted(&quoted, line, display_name_length);\n+\t\t\tadd_rfc822_quoted(&quoted, name.buf, name.len);\n \t\t\tstrbuf_add_wrapped_bytes(sb, quoted.buf, quoted.len,\n \t\t\t\t\t\t\t-6, 1, max_length);\n \t\t\tstrbuf_release(&quoted);\n \t\t} else {\n-\t\t\tstrbuf_add_wrapped_bytes(sb, line, display_name_length,\n-\t\t\t\t\t\t\t-6, 1, max_length);\n+\t\t\tstrbuf_add_wrapped_bytes(sb, name.buf, name.len,\n+\t\t\t\t\t\t -6, 1, max_length);\n \t\t}\n-\t\tif (namelen - display_name_length + last_line_length(sb) > max_length) {\n+\t\tif (namelen - name.len + last_line_length(sb) > max_length)\n \t\t\tstrbuf_addch(sb, '\\n');\n-\t\t\tif (!isspace(ident.name_end[0]))\n-\t\t\t\tstrbuf_addch(sb, ' ');\n-\t\t}\n-\t\tstrbuf_add(sb, ident.name_end, namelen - display_name_length);\n-\t\tstrbuf_addch(sb, '\\n');\n+\n+\t\tstrbuf_addf(sb, \" <%s>\\n\", mail.buf);\n \t} else {\n-\t\tstrbuf_addf(sb, \"%s: %.*s%.*s\\n\", what,\n+\t\tstrbuf_addf(sb, \"%s: %.*s%s <%s>\\n\", what,\n \t\t\t      (pp->fmt == CMIT_FMT_FULLER) ? 4 : 0,\n-\t\t\t      \"    \", namelen, line);\n+\t\t\t      \"    \", name.buf, mail.buf);\n \t}\n+\n+\tstrbuf_release(&mail);\n+\tstrbuf_release(&name);\n+\n \tswitch (pp->fmt) {\n \tcase CMIT_FMT_MEDIUM:\n \t\tstrbuf_addf(sb, \"Date:   %s\\n\", show_date(time, tz, pp->date_mode));\n-- \n1.8.1.304.gf036638\n"},{"id":"206255","messageId":"1357603821-8647-8-git-send-email-gitster@pobox.com","threadId":"32553","inReplyTo":"1357603821-8647-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 07/10] log: add --use-mailmap option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-01-08T00:10:18Z","receivedAt":"2013-01-08T00:10:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"From: Antoine Pelisse <apelisse@gmail.com>\n\nAdd the --use-mailmap option to log commands. It allows to display\nnames from mailmap file when displaying logs, whatever the format\nused.\n\nSigned-off-by: Antoine Pelisse <apelisse@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/git-log.txt | 5 +++++\n builtin/log.c             | 9 ++++++++-\n 2 files changed, 13 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-log.txt b/Documentation/git-log.txt\nindex 585dac4..a99be97 100644\n--- a/Documentation/git-log.txt\n+++ b/Documentation/git-log.txt\n@@ -47,6 +47,11 @@ OPTIONS\n \tPrint out the ref name given on the command line by which each\n \tcommit was reached.\n \n+--use-mailmap::\n+\tUse mailmap file to map author and committer names and email\n+\tto canonical real names and email addresses. See\n+\tlinkgit:git-shortlog[1].\n+\n --full-diff::\n \tWithout this flag, \"git log -p <path>...\" shows commits that\n \ttouch the specified paths, and diffs about the same specified\ndiff --git a/builtin/log.c b/builtin/log.c\nindex e7b7db1..d2bd8ce 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -22,6 +22,7 @@\n #include \"branch.h\"\n #include \"streaming.h\"\n #include \"version.h\"\n+#include \"mailmap.h\"\n \n /* Set a default date-time format for git log (\"log.date\" config variable) */\n static const char *default_date_mode = NULL;\n@@ -94,11 +95,12 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,\n \t\t\t struct rev_info *rev, struct setup_revision_opt *opt)\n {\n \tstruct userformat_want w;\n-\tint quiet = 0, source = 0;\n+\tint quiet = 0, source = 0, mailmap = 0;\n \n \tconst struct option builtin_log_options[] = {\n \t\tOPT_BOOLEAN(0, \"quiet\", &quiet, N_(\"suppress diff output\")),\n \t\tOPT_BOOLEAN(0, \"source\", &source, N_(\"show source\")),\n+\t\tOPT_BOOLEAN(0, \"use-mailmap\", &mailmap, N_(\"Use mail map file\")),\n \t\t{ OPTION_CALLBACK, 0, \"decorate\", NULL, NULL, N_(\"decorate options\"),\n \t\t  PARSE_OPT_OPTARG, decorate_callback},\n \t\tOPT_END()\n@@ -136,6 +138,11 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,\n \tif (source)\n \t\trev->show_source = 1;\n \n+\tif (mailmap) {\n+\t\trev->mailmap = xcalloc(1, sizeof(struct string_list));\n+\t\tread_mailmap(rev->mailmap, NULL);\n+\t}\n+\n \tif (rev->pretty_given && rev->commit_format == CMIT_FMT_RAW) {\n \t\t/*\n \t\t * \"log --pretty=raw\" is special; ignore UI oriented\n-- \n1.8.1.304.gf036638\n"},{"id":"206261","messageId":"1357603821-8647-9-git-send-email-gitster@pobox.com","threadId":"32553","inReplyTo":"1357603821-8647-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 08/10] test: add test for --use-mailmap option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-01-08T00:10:19Z","receivedAt":"2013-01-08T00:10:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"From: Antoine Pelisse <apelisse@gmail.com>\n\nThe new option '--use-mailmap' can be used to make sure that mailmap\nfile is used to convert name when running log commands.\n\nThe test is simple and checks that the Author line\nis correctly replaced when running log.\n\nSigned-off-by: Antoine Pelisse <apelisse@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n t/t4203-mailmap.sh | 14 ++++++++++++++\n 1 file changed, 14 insertions(+)\n\ndiff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh\nindex 1f182f6..db043dc 100755\n--- a/t/t4203-mailmap.sh\n+++ b/t/t4203-mailmap.sh\n@@ -239,6 +239,20 @@ test_expect_success 'Log output (complex mapping)' '\n \ttest_cmp expect actual\n '\n \n+cat >expect <<\\EOF\n+Author: CTO <cto@company.xx>\n+Author: Santa Claus <santa.claus@northpole.xx>\n+Author: Santa Claus <santa.claus@northpole.xx>\n+Author: Other Author <other@author.xx>\n+Author: Other Author <other@author.xx>\n+Author: Some Dude <some@dude.xx>\n+Author: A U Thor <author@example.com>\n+EOF\n+test_expect_success 'Log output with --use-mailmap' '\n+\tgit log --use-mailmap | grep Author >actual &&\n+\ttest_cmp expect actual\n+'\n+\n # git blame\n cat >expect <<\\EOF\n ^OBJI (A U Thor     DATE 1) one\n-- \n1.8.1.304.gf036638\n"},{"id":"206260","messageId":"1357603821-8647-10-git-send-email-gitster@pobox.com","threadId":"32553","inReplyTo":"1357603821-8647-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 09/10] log: grep author/committer using mailmap","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-01-08T00:10:20Z","receivedAt":"2013-01-08T00:10:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"From: Antoine Pelisse <apelisse@gmail.com>\n\nCurrently you can use mailmap to display log authors and committers\nbut you can't use the mailmap to find commits with mapped values.\n\nThis commit allows you to run:\n\n    git log --use-mailmap --author mapped_name_or_email\n    git log --use-mailmap --committer mapped_name_or_email\n\nOf course it only works if the --use-mailmap option is used.\n\nThe new name and email are copied only when necessary.\n\nSigned-off-by: Antoine Pelisse <apelisse@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n revision.c         | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++\n t/t4203-mailmap.sh | 18 ++++++++++++++++++\n 2 files changed, 72 insertions(+)\n\ndiff --git a/revision.c b/revision.c\nindex 95d21e6..2cce85a 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -13,6 +13,7 @@\n #include \"decorate.h\"\n #include \"log-tree.h\"\n #include \"string-list.h\"\n+#include \"mailmap.h\"\n \n volatile show_early_output_fn_t show_early_output;\n \n@@ -2219,6 +2220,51 @@ static int rewrite_parents(struct rev_info *revs, struct commit *commit)\n \treturn 0;\n }\n \n+static int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap)\n+{\n+\tchar *person, *endp;\n+\tsize_t len, namelen, maillen;\n+\tconst char *name;\n+\tconst char *mail;\n+\tstruct ident_split ident;\n+\n+\tperson = strstr(buf->buf, what);\n+\tif (!person)\n+\t\treturn 0;\n+\n+\tperson += strlen(what);\n+\tendp = strchr(person, '\\n');\n+\tif (!endp)\n+\t\treturn 0;\n+\n+\tlen = endp - person;\n+\n+\tif (split_ident_line(&ident, person, len))\n+\t\treturn 0;\n+\n+\tmail = ident.mail_begin;\n+\tmaillen = ident.mail_end - ident.mail_begin;\n+\tname = ident.name_begin;\n+\tnamelen = ident.name_end - ident.name_begin;\n+\n+\tif (map_user(mailmap, &mail, &maillen, &name, &namelen)) {\n+\t\tstruct strbuf namemail = STRBUF_INIT;\n+\n+\t\tstrbuf_addf(&namemail, \"%.*s <%.*s>\",\n+\t\t\t    (int)namelen, name, (int)maillen, mail);\n+\n+\t\tstrbuf_splice(buf, ident.name_begin - buf->buf,\n+\t\t\t      ident.mail_end - ident.name_begin + 1,\n+\t\t\t      namemail.buf, namemail.len);\n+\n+\t\tstrbuf_release(&namemail);\n+\n+\t\treturn 1;\n+\t}\n+\n+\treturn 0;\n+}\n+\n static int commit_match(struct commit *commit, struct rev_info *opt)\n {\n \tint retval;\n@@ -2237,6 +2283,14 @@ static int commit_match(struct commit *commit, struct rev_info *opt)\n \tif (buf.len)\n \t\tstrbuf_addstr(&buf, commit->buffer);\n \n+\tif (opt->mailmap) {\n+\t\tif (!buf.len)\n+\t\t\tstrbuf_addstr(&buf, commit->buffer);\n+\n+\t\tcommit_rewrite_person(&buf, \"\\nauthor \", opt->mailmap);\n+\t\tcommit_rewrite_person(&buf, \"\\ncommitter \", opt->mailmap);\n+\t}\n+\n \t/* Append \"fake\" message parts as needed */\n \tif (opt->show_notes) {\n \t\tif (!buf.len)\ndiff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh\nindex db043dc..e16187f 100755\n--- a/t/t4203-mailmap.sh\n+++ b/t/t4203-mailmap.sh\n@@ -248,11 +248,29 @@ Author: Other Author <other@author.xx>\n Author: Some Dude <some@dude.xx>\n Author: A U Thor <author@example.com>\n EOF\n+\n test_expect_success 'Log output with --use-mailmap' '\n \tgit log --use-mailmap | grep Author >actual &&\n \ttest_cmp expect actual\n '\n \n+cat >expect <<\\EOF\n+Author: Santa Claus <santa.claus@northpole.xx>\n+Author: Santa Claus <santa.claus@northpole.xx>\n+EOF\n+\n+test_expect_success 'Grep author with --use-mailmap' '\n+\tgit log --use-mailmap --author Santa | grep Author >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+>expect\n+\n+test_expect_success 'Only grep replaced author with --use-mailmap' '\n+\tgit log --use-mailmap --author \"<cto@coompany.xx>\" >actual &&\n+\ttest_cmp expect actual\n+'\n+\n # git blame\n cat >expect <<\\EOF\n ^OBJI (A U Thor     DATE 1) one\n-- \n1.8.1.304.gf036638\n"},{"id":"206259","messageId":"1357603821-8647-11-git-send-email-gitster@pobox.com","threadId":"32553","inReplyTo":"1357603821-8647-1-git-send-email-gitster@pobox.com","subject":"[PATCH v2 10/10] log: add log.mailmap configuration option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-01-08T00:10:21Z","receivedAt":"2013-01-08T00:10:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"From: Antoine Pelisse <apelisse@gmail.com>\n\nTeach \"log.mailmap\" configuration variable to turn \"--use-mailmap\"\noption on to \"git log\", \"git show\" and \"git whatchanged\".\n\nThe \"--no-use-mailmap\" option from the command line can countermand\nthe setting.\n\nSigned-off-by: Antoine Pelisse <apelisse@gmail.com>\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/config.txt |  4 ++++\n builtin/log.c            |  7 +++++++\n t/t4203-mailmap.sh       | 24 ++++++++++++++++++++++++\n 3 files changed, 35 insertions(+)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex bf8f911..226362a 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -1509,6 +1509,10 @@ log.showroot::\n \tTools like linkgit:git-log[1] or linkgit:git-whatchanged[1], which\n \tnormally hide the root commit will now show it. True by default.\n \n+log.mailmap::\n+\tIf true, makes linkgit:git-log[1], linkgit:git-show[1], and\n+\tlinkgit:git-whatchanged[1] assume `--use-mailmap`.\n+\n mailmap.file::\n \tThe location of an augmenting mailmap file. The default\n \tmailmap, located in the root of the repository, is loaded\ndiff --git a/builtin/log.c b/builtin/log.c\nindex d2bd8ce..16e6520 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -31,6 +31,7 @@ static int default_abbrev_commit;\n static int default_show_root = 1;\n static int decoration_style;\n static int decoration_given;\n+static int use_mailmap_config;\n static const char *fmt_patch_subject_prefix = \"PATCH\";\n static const char *fmt_pretty;\n \n@@ -106,6 +107,7 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix,\n \t\tOPT_END()\n \t};\n \n+\tmailmap = use_mailmap_config;\n \targc = parse_options(argc, argv, prefix,\n \t\t\t     builtin_log_options, builtin_log_usage,\n \t\t\t     PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_KEEP_UNKNOWN |\n@@ -358,6 +360,11 @@ static int git_log_config(const char *var, const char *value, void *cb)\n \t}\n \tif (!prefixcmp(var, \"color.decorate.\"))\n \t\treturn parse_decorate_color_config(var, 15, value);\n+\tif (!strcmp(var, \"log.mailmap\")) {\n+\t\tuse_mailmap_config = git_config_bool(var, value);\n+\t\treturn 0;\n+\t}\n+\n \tif (grep_config(var, value, cb) < 0)\n \t\treturn -1;\n \treturn git_diff_ui_config(var, value, cb);\ndiff --git a/t/t4203-mailmap.sh b/t/t4203-mailmap.sh\nindex e16187f..7d4d31c 100755\n--- a/t/t4203-mailmap.sh\n+++ b/t/t4203-mailmap.sh\n@@ -255,6 +255,21 @@ test_expect_success 'Log output with --use-mailmap' '\n '\n \n cat >expect <<\\EOF\n+Author: CTO <cto@company.xx>\n+Author: Santa Claus <santa.claus@northpole.xx>\n+Author: Santa Claus <santa.claus@northpole.xx>\n+Author: Other Author <other@author.xx>\n+Author: Other Author <other@author.xx>\n+Author: Some Dude <some@dude.xx>\n+Author: A U Thor <author@example.com>\n+EOF\n+\n+test_expect_success 'Log output with log.mailmap' '\n+\tgit -c log.mailmap=True log | grep Author >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+cat >expect <<\\EOF\n Author: Santa Claus <santa.claus@northpole.xx>\n Author: Santa Claus <santa.claus@northpole.xx>\n EOF\n@@ -263,6 +278,15 @@ test_expect_success 'Grep author with --use-mailmap' '\n \tgit log --use-mailmap --author Santa | grep Author >actual &&\n \ttest_cmp expect actual\n '\n+cat >expect <<\\EOF\n+Author: Santa Claus <santa.claus@northpole.xx>\n+Author: Santa Claus <santa.claus@northpole.xx>\n+EOF\n+\n+test_expect_success 'Grep author with log.mailmap' '\n+\tgit -c log.mailmap=True log --author Santa | grep Author >actual &&\n+\ttest_cmp expect actual\n+'\n \n >expect\n \n-- \n1.8.1.304.gf036638\n"},{"id":"206267","messageId":"CALWbr2w8z2iVx2PxM2sn3yDQzB5rTXc4EuZD9GCKSCofHzEzLQ@mail.gmail.com","threadId":"32553","inReplyTo":"1357603821-8647-1-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v2 00/10] reroll of ap/log-mailmap","fromName":"Antoine Pelisse","fromEmail":"apelisse@gmail.com","sentAt":"2013-01-08T07:27:24Z","receivedAt":"2013-01-08T07:27:24Z","isPatch":true,"sender":{"key":"apelisse@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1929644?v=4"},"body":"On Tue, Jan 8, 2013 at 1:10 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> This is a reroll of the previous series Antoine posted on Saturday.\n\nThanks a lot for the reroll Junio\n\n> A new patch \"string-list: allow case-insensitive string list\"\n> teaches the string-list API that some string lists can be sorted\n> case insensitively (actually, you can feed any custom two string\n> comparison functions).\n>\n> The string_list_lookup_extended() function introduced by the\n> previous series has been discarded.  Instead, the third patch\n> \"mailmap: remove email copy and length limitation\" introduces a\n> helper function that takes a <char *, size_t> key that is not NUL\n> terminated to look for a matching item in a string list, and uses\n> that to update map_user() function, together with the fourth\n> patch \"mailmap: simplify map_user() interface\".\n>\n> All other patches are unmodified from Antoine's series (modulo\n> wording tweaks here and there).\n>\n> Antoine Pelisse (9):\n>   Use split_ident_line to parse author and committer\n>   mailmap: remove email copy and length limitation\n>   mailmap: simplify map_user() interface\n>   mailmap: add mailmap structure to rev_info and pp\n>   pretty: use mailmap to display username and email\n>   log: add --use-mailmap option\n>   test: add test for --use-mailmap option\n>   log: grep author/committer using mailmap\n>   log: add log.mailmap configuration option\n>\n> Junio C Hamano (1):\n>   string-list: allow case-insensitive string list\n\nI think this one is missing (and I forgot to reroll it before):\nlog --use-mailmap: optimize for cases without --author/--committer search\n\n>\n>  Documentation/config.txt  |   4 +\n>  Documentation/git-log.txt |   5 ++\n>  builtin/blame.c           | 183 ++++++++++++++++++++++------------------------\n>  builtin/log.c             |  16 +++-\n>  builtin/shortlog.c        |  54 ++++----------\n>  commit.h                  |   1 +\n>  log-tree.c                |   1 +\n>  mailmap.c                 |  94 +++++++++++++++---------\n>  mailmap.h                 |   4 +-\n>  pretty.c                  | 114 ++++++++++++++++-------------\n>  revision.c                |  54 ++++++++++++++\n>  revision.h                |   1 +\n>  string-list.c             |  17 ++++-\n>  string-list.h             |   4 +\n>  t/t4203-mailmap.sh        |  56 ++++++++++++++\n>  15 files changed, 379 insertions(+), 229 deletions(-)\n\nHave you been able to measure a speed increase due to less copies ?\n\nThanks,\nAntoine\n"},{"id":"206272","messageId":"7v4nisgm3l.fsf@alter.siamese.dyndns.org","threadId":"32553","inReplyTo":"CALWbr2w8z2iVx2PxM2sn3yDQzB5rTXc4EuZD9GCKSCofHzEzLQ@mail.gmail.com","subject":"Re: [PATCH v2 00/10] reroll of ap/log-mailmap","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-01-08T07:39:10Z","receivedAt":"2013-01-08T07:39:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Antoine Pelisse <apelisse@gmail.com> writes:\n\n> Have you been able to measure a speed increase due to less copies ?\n\nNo.\n\nThis topic was not strictly my itch, but I did the rewrite because I\ncouldn't stand staring at that *_extended() function ;-)\n"},{"id":"206273","messageId":"7vzk0kf6fq.fsf@alter.siamese.dyndns.org","threadId":"32553","inReplyTo":"7v4nisgm3l.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v2 00/10] reroll of ap/log-mailmap","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-01-08T08:02:49Z","receivedAt":"2013-01-08T08:02:49Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Antoine Pelisse <apelisse@gmail.com> writes:\n>\n>> Have you been able to measure a speed increase due to less copies ?\n>\n> No.\n>\n> This topic was not strictly my itch, but I did the rewrite because I\n> couldn't stand staring at that *_extended() function ;-)\n\nNow I have.  The overall numbers are larger primarily because the\nkernel history has more commits than back when I did the previous\ncommit (thanks for reminding me of that one, by the way), but the\nbasic trend is the same.\n\nThe patch with updated numbers in the log is attached.\n\nI am not absolutely sure about the correctness of the third patch in\nthe series; a review on the logic that uses the insertion point\nsearch to implement the prefix match is very much appreciated.\n\nThanks.\n\n-- >8 --\nSubject: [PATCH] log --use-mailmap: optimize for cases without --author/--committer search\n\nWhen we taught the commit_match() mechanism to pay attention to the\nnew --use-mailmap option, we started to unconditionally copy the\ncommit object to a temporary buffer, just in case we need the author\nand committer lines updated via the mailmap mechanism, and rewrite\nauthor and committer using the mailmap.\n\nIt turns out that this has a rather unpleasant performance\nimplications.  In the linux kernel repository, running\n\n  $ git log --author='Junio C Hamano' --pretty=short >/dev/null\n\nunder /usr/bin/time, with and without --use-mailmap (the .mailmap\nfile is 118 entries long, the particular author does not appear in\nit), cost (with warm cache):\n\n  [without --use-mailmap]\n  5.42user 0.26system 0:05.70elapsed 99%CPU (0avgtext+0avgdata 2005936maxresident)k\n  0inputs+0outputs (0major+137669minor)pagefaults 0swaps\n\n  [with --use-mailmap]\n  6.47user 0.30system 0:06.78elapsed 99%CPU (0avgtext+0avgdata 2006288maxresident)k\n  0inputs+0outputs (0major+137692minor)pagefaults 0swaps\n\nwhich incurs about 20% overhead.  The command is doing extra work,\nso the extra cost may be justified.\n\nBut it is inexcusable to pay the cost when we do not need\nauthor/committer match.  In the same repository,\n\n  $ git log --grep='fix menuconfig on debian lenny' --pretty=short >/dev/null\n\nshows very similar numbers as the above:\n\n  [without --use-mailmap]\n  5.32user 0.30system 0:05.63elapsed 99%CPU (0avgtext+0avgdata 2005984maxresident)k\n  0inputs+0outputs (0major+137672minor)pagefaults 0swaps\n\n  [with --use-mailmap]\n  6.64user 0.24system 0:06.89elapsed 99%CPU (0avgtext+0avgdata 2006320maxresident)k\n  0inputs+0outputs (0major+137694minor)pagefaults 0swaps\n\nThe latter case is an unnecessary performance regression.  We may\nwant to _show_ the result with mailmap applied, but we do not have\nto copy and rewrite the author/committer of all commits we try to\nmatch if we do not query for these fields.\n\nTrivially optimize this performace regression by limiting the\nrewrites for only when we are matching with author/committer fields.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n revision.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/revision.c b/revision.c\nindex 2cce85a..d7562ee 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -2283,7 +2283,7 @@ static int commit_match(struct commit *commit, struct rev_info *opt)\n \tif (buf.len)\n \t\tstrbuf_addstr(&buf, commit->buffer);\n \n-\tif (opt->mailmap) {\n+\tif (opt->grep_filter.header_list && opt->mailmap) {\n \t\tif (!buf.len)\n \t\t\tstrbuf_addstr(&buf, commit->buffer);\n \n-- \n1.8.1.304.gf036638\n"},{"id":"206393","messageId":"CALWbr2wp7rV7Vh0=gwmWaZE5hLHQNL+UciDsL+z-1GyhS9pTkQ@mail.gmail.com","threadId":"32553","inReplyTo":"1357603821-8647-4-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v2 03/10] mailmap: remove email copy and length limitation","fromName":"Antoine Pelisse","fromEmail":"apelisse@gmail.com","sentAt":"2013-01-09T17:35:21Z","receivedAt":"2013-01-09T17:35:21Z","isPatch":true,"sender":{"key":"apelisse@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1929644?v=4"},"body":"> +static struct string_list_item *lookup_prefix(struct string_list *map,\n> +                                             const char *string, size_t len)\n> +{\n> +       int i = string_list_find_insert_index(map, string, 1);\n> +       if (i < 0) {\n> +               /* exact match */\n> +               i = -1 - i;\n> +               /* does it match exactly? */\n> +               if (!map->items[i].string[len])\n> +                       return &map->items[i];\n\nI'm not sure the condition above is necessary, as I don't see why an\nexact match would not be an exact match.\nWe have to trust the cmp function (that mailmap sets itself) to not\nreturn 0 when the lengths are different.\n\n> +       }\n> +\n> +       /*\n> +        * i is at the exact match to an overlong key, or\n> +        * location the possibly overlong key would be inserted,\n> +        * which must be after the real location of the key.\n> +        */\n> +       while (0 <= --i && i < map->nr) {\n> +               int cmp = strncasecmp(map->items[i].string, string, len);\n> +               if (cmp < 0)\n> +                       /*\n> +                        * \"i\" points at a key definitely below the prefix;\n> +                        * the map does not have string[0:len] in it.\n> +                        */\n> +                       break;\n> +               else if (!cmp && !map->items[i].string[len])\n> +                       /* found it */\n> +                       return &map->items[i];\n> +               /*\n> +                * otherwise, the string at \"i\" may be string[0:len]\n> +                * followed by a string that sorts later than string[len:];\n> +                * keep trying.\n> +                */\n> +       }\n> +       return NULL;\n> +}\n> +\n\nI've tried to think about nasty use cases but everything seems fine.\n"},{"id":"206395","messageId":"7vfw2a6yh5.fsf@alter.siamese.dyndns.org","threadId":"32553","inReplyTo":"CALWbr2wp7rV7Vh0=gwmWaZE5hLHQNL+UciDsL+z-1GyhS9pTkQ@mail.gmail.com","subject":"Re: [PATCH v2 03/10] mailmap: remove email copy and length limitation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-01-09T17:46:30Z","receivedAt":"2013-01-09T17:46:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Antoine Pelisse <apelisse@gmail.com> writes:\n\n>> +static struct string_list_item *lookup_prefix(struct string_list *map,\n>> +                                             const char *string, size_t len)\n>> +{\n>> +       int i = string_list_find_insert_index(map, string, 1);\n>> +       if (i < 0) {\n>> +               /* exact match */\n>> +               i = -1 - i;\n>> +               /* does it match exactly? */\n>> +               if (!map->items[i].string[len])\n>> +                       return &map->items[i];\n>\n> I'm not sure the condition above is necessary, as I don't see why an\n> exact match would not be an exact match.\n\nYou have a overlong string \"ABCDEFG\", but you only want to look for\n\"ABCDEF\", i.e. len=6.  The string_list happens to have an existing\nstring \"ABCDEFG\".  The insert-index function will report an exact\nmatch, but that does not mean you found what you are looking for. \n\nFor the particular case of \"looking up e-mail from a string-list\nused for the mailmap, using a string that potentially has an extra\n'>' at the end\", it may not be an issue (i.e. your overlong string\nwould be \"ABCDEF>\", and the string-list used for the mailmap will\nnot have an entry that ends with '>'), but it is likely that people\nwill try to mimic this function or try to generalize and move it to\nstrbuf.c and at that point, such a special case condition will no\nlonger hold and the bug will manifest itself.  Being defensive like\nthe above is a way to avoid that.\n"},{"id":"206397","messageId":"7vbocy6y0n.fsf@alter.siamese.dyndns.org","threadId":"32553","inReplyTo":"7vfw2a6yh5.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH v2 03/10] mailmap: remove email copy and length limitation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2013-01-09T17:56:24Z","receivedAt":"2013-01-09T17:56:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Antoine Pelisse <apelisse@gmail.com> writes:\n>\n>>> +static struct string_list_item *lookup_prefix(struct string_list *map,\n>>> +                                             const char *string, size_t len)\n>>> +{\n>>> +       int i = string_list_find_insert_index(map, string, 1);\n>>> +       if (i < 0) {\n>>> +               /* exact match */\n>>> +               i = -1 - i;\n>>> +               /* does it match exactly? */\n>>> +               if (!map->items[i].string[len])\n>>> +                       return &map->items[i];\n>>\n>> I'm not sure the condition above is necessary, as I don't see why an\n>> exact match would not be an exact match.\n>\n> You have a overlong string \"ABCDEFG\", but you only want to look for\n> \"ABCDEF\", i.e. len=6.  The string_list happens to have an existing\n> string \"ABCDEFG\".  The insert-index function will report an exact\n> match, but that does not mean you found what you are looking for. \n\nTo put it another way, we can further clarify the situation by\nrewording the comment \"Does it match exactly?\", perhaps like this\n\n\tif (i < 0) {\n                /* exact match */\n                i = -1 - i;\n                if (!string[len])\n                        return &map->items[i];\n                /*\n                 * It matched exactly even to the cruft at the end\n                 * of the string, so it is not really a match.\n                 */\n\t}\n"},{"id":"206470","messageId":"50EF3409.6050805@lsrfire.ath.cx","threadId":"32553","inReplyTo":"1357603821-8647-2-git-send-email-gitster@pobox.com","subject":"Re: [PATCH v2 01/10] string-list: allow case-insensitive string list","fromName":"René Scharfe","fromEmail":"rene.scharfe@lsrfire.ath.cx","sentAt":"2013-01-10T21:35:05Z","receivedAt":"2013-01-10T21:35:05Z","isPatch":true,"sender":{"key":"l.s.r@web.de","avatar":"https://avatars.githubusercontent.com/u/26122331?v=4"},"body":"Am 08.01.2013 01:10, schrieb Junio C Hamano:\n> Some string list needs to be searched case insensitively, and for\n> that to work correctly, the string needs to be sorted case\n> insensitively from the beginning.\n> \n> Allow a custom comparison function to be defined on a string list\n> instance and use it throughout in place of strcmp().\n> \n> Signed-off-by: Junio C Hamano <gitster@pobox.com>\n\nWe can avoid using a static variable to pass the comparison function from\nsort_string_list() to cmp_items() by dialling back the flexibility a bit\nand only have a flag to switch between strcmp() and strcasecmp().  I bet\nthis suffices for quite a while yet.  Slightly more code, less yuck,\nsquashable.\n\nRené\n\n\n---\n mailmap.c     |  2 +-\n string-list.c | 23 ++++++++++++++---------\n string-list.h |  4 +---\n 3 files changed, 16 insertions(+), 13 deletions(-)\n\ndiff --git a/mailmap.c b/mailmap.c\nindex 276c54f..08126b1 100644\n--- a/mailmap.c\n+++ b/mailmap.c\n@@ -235,7 +235,7 @@ int read_mailmap(struct string_list *map, char **repo_abbrev)\n \tint err = 0;\n \n \tmap->strdup_strings = 1;\n-\tmap->cmp = strcasecmp;\n+\tmap->ignore_case = 1;\n \n \tif (!git_mailmap_blob && is_bare_repository())\n \t\tgit_mailmap_blob = \"HEAD:.mailmap\";\ndiff --git a/string-list.c b/string-list.c\nindex aabb25e..ddecc23 100644\n--- a/string-list.c\n+++ b/string-list.c\n@@ -1,13 +1,15 @@\n #include \"cache.h\"\n #include \"string-list.h\"\n \n+typedef int (*compare_strings_fn)(const char *, const char *);\n+\n /* if there is no exact match, point to the index where the entry could be\n  * inserted */\n static int get_entry_index(const struct string_list *list, const char *string,\n \t\tint *exact_match)\n {\n \tint left = -1, right = list->nr;\n-\tcompare_strings_fn cmp = list->cmp ? list->cmp : strcmp;\n+\tcompare_strings_fn cmp = list->ignore_case ? strcasecmp : strcmp;\n \n \twhile (left + 1 < right) {\n \t\tint middle = (left + right) / 2;\n@@ -97,7 +99,7 @@ void string_list_remove_duplicates(struct string_list *list, int free_util)\n {\n \tif (list->nr > 1) {\n \t\tint src, dst;\n-\t\tcompare_strings_fn cmp = list->cmp ? list->cmp : strcmp;\n+\t\tcompare_strings_fn cmp = list->ignore_case ? strcasecmp : strcmp;\n \t\tfor (src = dst = 1; src < list->nr; src++) {\n \t\t\tif (!cmp(list->items[dst - 1].string, list->items[src].string)) {\n \t\t\t\tif (list->strdup_strings)\n@@ -212,28 +214,31 @@ struct string_list_item *string_list_append(struct string_list *list,\n \t\t\tlist->strdup_strings ? xstrdup(string) : (char *)string);\n }\n \n-/* Yuck */\n-static compare_strings_fn compare_for_qsort;\n+static int cmp_items_ignore_case(const void *a, const void *b)\n+{\n+\tconst struct string_list_item *one = a;\n+\tconst struct string_list_item *two = b;\n+\treturn strcasecmp(one->string, two->string);\n+}\n \n-/* Only call this from inside sort_string_list! */\n static int cmp_items(const void *a, const void *b)\n {\n \tconst struct string_list_item *one = a;\n \tconst struct string_list_item *two = b;\n-\treturn compare_for_qsort(one->string, two->string);\n+\treturn strcmp(one->string, two->string);\n }\n \n void sort_string_list(struct string_list *list)\n {\n-\tcompare_for_qsort = list->cmp ? list->cmp : strcmp;\n-\tqsort(list->items, list->nr, sizeof(*list->items), cmp_items);\n+\tqsort(list->items, list->nr, sizeof(*list->items),\n+\t      list->ignore_case ? cmp_items_ignore_case : cmp_items);\n }\n \n struct string_list_item *unsorted_string_list_lookup(struct string_list *list,\n \t\t\t\t\t\t     const char *string)\n {\n \tint i;\n-\tcompare_strings_fn cmp = list->cmp ? list->cmp : strcmp;\n+\tcompare_strings_fn cmp = list->ignore_case ? strcasecmp : strcmp;\n \n \tfor (i = 0; i < list->nr; i++)\n \t\tif (!cmp(string, list->items[i].string))\ndiff --git a/string-list.h b/string-list.h\nindex de6769c..33f2e9c 100644\n--- a/string-list.h\n+++ b/string-list.h\n@@ -6,13 +6,11 @@ struct string_list_item {\n \tvoid *util;\n };\n \n-typedef int (*compare_strings_fn)(const char *, const char *);\n-\n struct string_list {\n \tstruct string_list_item *items;\n \tunsigned int nr, alloc;\n \tunsigned int strdup_strings:1;\n-\tcompare_strings_fn cmp; /* NULL uses strcmp() */\n+\tunsigned int ignore_case:1;\n };\n \n #define STRING_LIST_INIT_NODUP { NULL, 0, 0, 0 }\n-- \n1.8.0\n"}]}