mailmap: always return a plain mail address from map_user()

The callers of map_user() give email and name to it, and expect to get the up-to-date email and/or name to be used in their output. The function rewrites the given buffers in place. To optimize the majority of cases, the function returns 0 when it did not do anything, and it returns 1 when the caller should use the updated contents. The 'email' input to the function is terminated by '>' or a NUL (whichever comes first) for historical reasons, but when a rewrite happens, the value is replaced with the mailbox inside the <> pair. However, it failed to meet this expectation when it only rewrote the name part without rewriting the email part, and the email in the input was terminated by '>'. This causes an extra '>' to appear in the output of "blame -e", because the caller does send in '>'-terminated email, and when the function returned 1 to tell it that rewriting happened, it appends '>' that is necessary when the email part was rewritten. The patch looks bigger than it actually is, because this change makes a variable that points at the end of the email part in the input 'p' live much longer than it used to, deserving a more descriptive name. Noticed and diagnosed by Felipe Contreras and Jeff King. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Feb 5, 2012 at 17:31 UTC f026358ef20e0c252388a41fcc8eff125b00927c
1 file changed +10 -8
mailmap.c
+10 -8
@@ -190,27 +190,27 @@ void clear_mailmap(struct string_list *map)
190 int map_user(struct string_list *map,
191 char *email, int maxlen_email, char *name, int maxlen_name)
192 {
193 - char *p;
193 + char *end_of_email;
194 struct string_list_item *item;
195 struct mailmap_entry *me;
196 char buf[1024], *mailbuf;
197 int i;
198
199 /* figure out space requirement for email */
200 - p = strchr(email, '>');
201 - if (!p) {
200 + end_of_email = strchr(email, '>');
201 + if (!end_of_email) {
202 /* email passed in might not be wrapped in <>, but end with a \0 */
203 - p = memchr(email, '\0', maxlen_email);
204 - if (!p)
203 + end_of_email = memchr(email, '\0', maxlen_email);
204 + if (!end_of_email)
205 return 0;
206 }
207 - if (p - email + 1 < sizeof(buf))
207 + if (end_of_email - email + 1 < sizeof(buf))
208 mailbuf = buf;
209 else
210 - mailbuf = xmalloc(p - email + 1);
210 + mailbuf = xmalloc(end_of_email - email + 1);
211
212 /* downcase the email address */
213 - for (i = 0; i < p - email; i++)
213 + for (i = 0; i < end_of_email - email; i++)
214 mailbuf[i] = tolower(email[i]);
215 mailbuf[i] = 0;
216
@@ -236,6 +236,8 @@ int map_user(struct string_list *map,
236 }
237 if (maxlen_email && mi->email)
238 strlcpy(email, mi->email, maxlen_email);
239 + else
240 + *end_of_email = '\0';
241 if (maxlen_name && mi->name)
242 strlcpy(name, mi->name, maxlen_name);
243 debug_mm("map_user: to '%s' <%s>\n", name, mi->email ? mi->email : "");