summaryrefslogtreecommitdiff
path: root/mailmap.c
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2013-01-20 17:06:52 -0800
committerJunio C Hamano <gitster@pobox.com>2013-01-20 17:06:53 -0800
commit577f63e781d2f9b9a6862389b6e9d2ca2467afa2 (patch)
treeff7eb1668b21b118caa34a71fcde1026c0a932f4 /mailmap.c
parent02f55e660ccbd2fa1e3b2c686200f0037568f854 (diff)
parentdf874fa82ef06c8c438b9a19c56c0b5eb089c012 (diff)
downloadgit-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.c108
1 files changed, 72 insertions, 36 deletions
diff --git a/mailmap.c b/mailmap.c
index b16542febe..2a7b36628c 100644
--- a/mailmap.c
+++ b/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");
}
+/*
+ * 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");