diff options
author | Junio C Hamano <gitster@pobox.com> | 2013-01-20 17:06:52 -0800 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2013-01-20 17:06:53 -0800 |
commit | 577f63e781d2f9b9a6862389b6e9d2ca2467afa2 (patch) | |
tree | ff7eb1668b21b118caa34a71fcde1026c0a932f4 /mailmap.c | |
parent | 02f55e660ccbd2fa1e3b2c686200f0037568f854 (diff) | |
parent | df874fa82ef06c8c438b9a19c56c0b5eb089c012 (diff) | |
download | git-577f63e781d2f9b9a6862389b6e9d2ca2467afa2.tar.gz |
Merge branch 'ap/log-mailmap'
Teach commands in the "log" family to optionally pay attention to
the mailmap.
* ap/log-mailmap:
log --use-mailmap: optimize for cases without --author/--committer search
log: add log.mailmap configuration option
log: grep author/committer using mailmap
test: add test for --use-mailmap option
log: add --use-mailmap option
pretty: use mailmap to display username and email
mailmap: add mailmap structure to rev_info and pp
mailmap: simplify map_user() interface
mailmap: remove email copy and length limitation
Use split_ident_line to parse author and committer
string-list: allow case-insensitive string list
Diffstat (limited to 'mailmap.c')
-rw-r--r-- | mailmap.c | 108 |
1 files changed, 72 insertions, 36 deletions
@@ -235,6 +235,7 @@ int read_mailmap(struct string_list *map, char **repo_abbrev) int err = 0; map->strdup_strings = 1; + map->cmp = strcasecmp; if (!git_mailmap_blob && is_bare_repository()) git_mailmap_blob = "HEAD:.mailmap"; @@ -253,60 +254,95 @@ void clear_mailmap(struct string_list *map) debug_mm("mailmap: cleared\n"); } +/* + * Look for an entry in map that match string[0:len]; string[len] + * does not have to be NUL (but it could be). + */ +static struct string_list_item *lookup_prefix(struct string_list *map, + const char *string, size_t len) +{ + int i = string_list_find_insert_index(map, string, 1); + if (i < 0) { + /* exact match */ + i = -1 - i; + if (!string[len]) + return &map->items[i]; + /* + * that map entry matches exactly to the string, including + * the cruft at the end beyond "len". That is not a match + * with string[0:len] that we are looking for. + */ + } else if (!string[len]) { + /* + * asked with the whole string, and got nothing. No + * matching entry can exist in the map. + */ + return NULL; + } + + /* + * i is at the exact match to an overlong key, or location the + * overlong key would be inserted, which must come after the + * real location of the key if one exists. + */ + while (0 <= --i && i < map->nr) { + int cmp = strncasecmp(map->items[i].string, string, len); + if (cmp < 0) + /* + * "i" points at a key definitely below the prefix; + * the map does not have string[0:len] in it. + */ + break; + else if (!cmp && !map->items[i].string[len]) + /* found it */ + return &map->items[i]; + /* + * otherwise, the string at "i" may be string[0:len] + * followed by a string that sorts later than string[len:]; + * keep trying. + */ + } + return NULL; +} + int map_user(struct string_list *map, - char *email, int maxlen_email, char *name, int maxlen_name) + const char **email, size_t *emaillen, + const char **name, size_t *namelen) { - char *end_of_email; struct string_list_item *item; struct mailmap_entry *me; - char buf[1024], *mailbuf; - int i; - - /* figure out space requirement for email */ - end_of_email = strchr(email, '>'); - if (!end_of_email) { - /* email passed in might not be wrapped in <>, but end with a \0 */ - end_of_email = memchr(email, '\0', maxlen_email); - if (!end_of_email) - return 0; - } - if (end_of_email - email + 1 < sizeof(buf)) - mailbuf = buf; - else - mailbuf = xmalloc(end_of_email - email + 1); - - /* downcase the email address */ - for (i = 0; i < end_of_email - email; i++) - mailbuf[i] = tolower(email[i]); - mailbuf[i] = 0; - - debug_mm("map_user: map '%s' <%s>\n", name, mailbuf); - item = string_list_lookup(map, mailbuf); + + debug_mm("map_user: map '%.*s' <%.*s>\n", + *name, *namelen, *emaillen, *email); + + item = lookup_prefix(map, *email, *emaillen); if (item != NULL) { me = (struct mailmap_entry *)item->util; if (me->namemap.nr) { /* The item has multiple items, so we'll look up on name too */ /* If the name is not found, we choose the simple entry */ - struct string_list_item *subitem = string_list_lookup(&me->namemap, name); + struct string_list_item *subitem; + subitem = lookup_prefix(&me->namemap, *name, *namelen); if (subitem) item = subitem; } } - if (mailbuf != buf) - free(mailbuf); if (item != NULL) { struct mailmap_info *mi = (struct mailmap_info *)item->util; - if (mi->name == NULL && (mi->email == NULL || maxlen_email == 0)) { + if (mi->name == NULL && mi->email == NULL) { debug_mm("map_user: -- (no simple mapping)\n"); return 0; } - if (maxlen_email && mi->email) - strlcpy(email, mi->email, maxlen_email); - else - *end_of_email = '\0'; - if (maxlen_name && mi->name) - strlcpy(name, mi->name, maxlen_name); - debug_mm("map_user: to '%s' <%s>\n", name, mi->email ? mi->email : ""); + if (mi->email) { + *email = mi->email; + *emaillen = strlen(*email); + } + if (mi->name) { + *name = mi->name; + *namelen = strlen(*name); + } + debug_mm("map_user: to '%.*s' <.*%s>\n", *namelen, *name, + *emaillen, *email); return 1; } debug_mm("map_user: --\n"); |