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
This commit is contained in:
106
mailmap.c
106
mailmap.c
@ -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");
|
||||
}
|
||||
|
||||
int map_user(struct string_list *map,
|
||||
char *email, int maxlen_email, char *name, int maxlen_name)
|
||||
/*
|
||||
* 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,
|
||||
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);
|
||||
debug_mm("map_user: map '%.*s' <%.*s>\n",
|
||||
*name, *namelen, *emaillen, *email);
|
||||
|
||||
/* 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);
|
||||
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");
|
||||
|
Reference in New Issue
Block a user