mailmap: simplify map_user() interface

Simplify map_user(), mostly to avoid copies of string buffers. It
also simplifies caller functions.

map_user() directly receive pointers and length from the commit buffer
as mail and name. If mapping of the user and mail can be done, the
pointer is updated to a new location. Lengths are also updated if
necessary.

The caller of map_user() can then copy the new email and name if
necessary.

Signed-off-by: Antoine Pelisse <apelisse@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Antoine Pelisse 2013-01-05 22:26:40 +01:00 committed by Junio C Hamano
parent 388c7f8a27
commit ea02ffa385
5 changed files with 125 additions and 143 deletions

View file

@ -1321,31 +1321,31 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
* Information on commits, used for output. * Information on commits, used for output.
*/ */
struct commit_info { struct commit_info {
const char *author; struct strbuf author;
const char *author_mail; struct strbuf author_mail;
unsigned long author_time; unsigned long author_time;
const char *author_tz; struct strbuf author_tz;
/* filled only when asked for details */ /* filled only when asked for details */
const char *committer; struct strbuf committer;
const char *committer_mail; struct strbuf committer_mail;
unsigned long committer_time; unsigned long committer_time;
const char *committer_tz; struct strbuf committer_tz;
const char *summary; struct strbuf summary;
}; };
/* /*
* Parse author/committer line in the commit object buffer * Parse author/committer line in the commit object buffer
*/ */
static void get_ac_line(const char *inbuf, const char *what, static void get_ac_line(const char *inbuf, const char *what,
int person_len, char *person, struct strbuf *name, struct strbuf *mail,
int mail_len, char *mail, unsigned long *time, struct strbuf *tz)
unsigned long *time, const char **tz)
{ {
struct ident_split ident; struct ident_split ident;
int len, tzlen, maillen, namelen; size_t len, maillen, namelen;
char *tmp, *endp, *mailpos; char *tmp, *endp;
const char *namebuf, *mailbuf;
tmp = strstr(inbuf, what); tmp = strstr(inbuf, what);
if (!tmp) if (!tmp)
@ -1356,51 +1356,61 @@ static void get_ac_line(const char *inbuf, const char *what,
len = strlen(tmp); len = strlen(tmp);
else else
len = endp - tmp; len = endp - tmp;
if (person_len <= len)
goto error_out;
if (split_ident_line(&ident, tmp, len)) { if (split_ident_line(&ident, tmp, len)) {
error_out: error_out:
/* Ugh */ /* Ugh */
*tz = "(unknown)"; tmp = "(unknown)";
strcpy(person, *tz); strbuf_addstr(name, tmp);
strcpy(mail, *tz); strbuf_addstr(mail, tmp);
strbuf_addstr(tz, tmp);
*time = 0; *time = 0;
return; return;
} }
namelen = ident.name_end - ident.name_begin; namelen = ident.name_end - ident.name_begin;
memcpy(person, ident.name_begin, namelen); namebuf = ident.name_begin;
person[namelen] = 0;
maillen = ident.mail_end - ident.mail_begin + 2; maillen = ident.mail_end - ident.mail_begin;
memcpy(mail, ident.mail_begin - 1, maillen); mailbuf = ident.mail_begin;
mail[maillen] = 0;
*time = strtoul(ident.date_begin, NULL, 10); *time = strtoul(ident.date_begin, NULL, 10);
tzlen = ident.tz_end - ident.tz_begin; len = ident.tz_end - ident.tz_begin;
strbuf_add(tz, ident.tz_begin, len);
/* Place tz at the end of person */
*tz = tmp = person + person_len - (tzlen + 1);
memcpy(tmp, ident.tz_begin, tzlen);
tmp[tzlen] = 0;
if (!mailmap.nr)
return;
/* /*
* Now, convert both name and e-mail using mailmap * Now, convert both name and e-mail using mailmap
*/ */
if (map_user(&mailmap, mail+1, mail_len-1, person, tmp-person-1)) { map_user(&mailmap, &mailbuf, &maillen,
/* Add a trailing '>' to email, since map_user returns plain emails &namebuf, &namelen);
Note: It already has '<', since we replace from mail+1 */
mailpos = memchr(mail, '\0', mail_len); strbuf_addf(mail, "<%.*s>", (int)maillen, mailbuf);
if (mailpos && mailpos-mail < mail_len - 1) { strbuf_add(name, namebuf, namelen);
*mailpos = '>';
*(mailpos+1) = '\0';
} }
static void commit_info_init(struct commit_info *ci)
{
strbuf_init(&ci->author, 0);
strbuf_init(&ci->author_mail, 0);
strbuf_init(&ci->author_tz, 0);
strbuf_init(&ci->committer, 0);
strbuf_init(&ci->committer_mail, 0);
strbuf_init(&ci->committer_tz, 0);
strbuf_init(&ci->summary, 0);
} }
static void commit_info_destroy(struct commit_info *ci)
{
strbuf_release(&ci->author);
strbuf_release(&ci->author_mail);
strbuf_release(&ci->author_tz);
strbuf_release(&ci->committer);
strbuf_release(&ci->committer_mail);
strbuf_release(&ci->committer_tz);
strbuf_release(&ci->summary);
} }
static void get_commit_info(struct commit *commit, static void get_commit_info(struct commit *commit,
@ -1410,11 +1420,8 @@ static void get_commit_info(struct commit *commit,
int len; int len;
const char *subject, *encoding; const char *subject, *encoding;
char *reencoded, *message; char *reencoded, *message;
static char author_name[1024];
static char author_mail[1024]; commit_info_init(ret);
static char committer_name[1024];
static char committer_mail[1024];
static char summary_buf[1024];
/* /*
* We've operated without save_commit_buffer, so * We've operated without save_commit_buffer, so
@ -1432,11 +1439,8 @@ static void get_commit_info(struct commit *commit,
encoding = get_log_output_encoding(); encoding = get_log_output_encoding();
reencoded = logmsg_reencode(commit, encoding); reencoded = logmsg_reencode(commit, encoding);
message = reencoded ? reencoded : commit->buffer; message = reencoded ? reencoded : commit->buffer;
ret->author = author_name;
ret->author_mail = author_mail;
get_ac_line(message, "\nauthor ", get_ac_line(message, "\nauthor ",
sizeof(author_name), author_name, &ret->author, &ret->author_mail,
sizeof(author_mail), author_mail,
&ret->author_time, &ret->author_tz); &ret->author_time, &ret->author_tz);
if (!detailed) { if (!detailed) {
@ -1444,21 +1448,16 @@ static void get_commit_info(struct commit *commit,
return; return;
} }
ret->committer = committer_name;
ret->committer_mail = committer_mail;
get_ac_line(message, "\ncommitter ", get_ac_line(message, "\ncommitter ",
sizeof(committer_name), committer_name, &ret->committer, &ret->committer_mail,
sizeof(committer_mail), committer_mail,
&ret->committer_time, &ret->committer_tz); &ret->committer_time, &ret->committer_tz);
ret->summary = summary_buf;
len = find_commit_subject(message, &subject); len = find_commit_subject(message, &subject);
if (len && len < sizeof(summary_buf)) { if (len)
memcpy(summary_buf, subject, len); strbuf_add(&ret->summary, subject, len);
summary_buf[len] = 0; else
} else { strbuf_addf(&ret->summary, "(%s)", sha1_to_hex(commit->object.sha1));
sprintf(summary_buf, "(%s)", sha1_to_hex(commit->object.sha1));
}
free(reencoded); free(reencoded);
} }
@ -1487,15 +1486,15 @@ static int emit_one_suspect_detail(struct origin *suspect, int repeat)
suspect->commit->object.flags |= METAINFO_SHOWN; suspect->commit->object.flags |= METAINFO_SHOWN;
get_commit_info(suspect->commit, &ci, 1); get_commit_info(suspect->commit, &ci, 1);
printf("author %s\n", ci.author); printf("author %s\n", ci.author.buf);
printf("author-mail %s\n", ci.author_mail); printf("author-mail %s\n", ci.author_mail.buf);
printf("author-time %lu\n", ci.author_time); printf("author-time %lu\n", ci.author_time);
printf("author-tz %s\n", ci.author_tz); printf("author-tz %s\n", ci.author_tz.buf);
printf("committer %s\n", ci.committer); printf("committer %s\n", ci.committer.buf);
printf("committer-mail %s\n", ci.committer_mail); printf("committer-mail %s\n", ci.committer_mail.buf);
printf("committer-time %lu\n", ci.committer_time); printf("committer-time %lu\n", ci.committer_time);
printf("committer-tz %s\n", ci.committer_tz); printf("committer-tz %s\n", ci.committer_tz.buf);
printf("summary %s\n", ci.summary); printf("summary %s\n", ci.summary.buf);
if (suspect->commit->object.flags & UNINTERESTING) if (suspect->commit->object.flags & UNINTERESTING)
printf("boundary\n"); printf("boundary\n");
if (suspect->previous) { if (suspect->previous) {
@ -1503,6 +1502,9 @@ static int emit_one_suspect_detail(struct origin *suspect, int repeat)
printf("previous %s ", sha1_to_hex(prev->commit->object.sha1)); printf("previous %s ", sha1_to_hex(prev->commit->object.sha1));
write_name_quoted(prev->path, stdout, '\n'); write_name_quoted(prev->path, stdout, '\n');
} }
commit_info_destroy(&ci);
return 1; return 1;
} }
@ -1689,11 +1691,11 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)
if (opt & OUTPUT_ANNOTATE_COMPAT) { if (opt & OUTPUT_ANNOTATE_COMPAT) {
const char *name; const char *name;
if (opt & OUTPUT_SHOW_EMAIL) if (opt & OUTPUT_SHOW_EMAIL)
name = ci.author_mail; name = ci.author_mail.buf;
else else
name = ci.author; name = ci.author.buf;
printf("\t(%10s\t%10s\t%d)", name, printf("\t(%10s\t%10s\t%d)", name,
format_time(ci.author_time, ci.author_tz, format_time(ci.author_time, ci.author_tz.buf,
show_raw_time), show_raw_time),
ent->lno + 1 + cnt); ent->lno + 1 + cnt);
} else { } else {
@ -1712,14 +1714,14 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)
const char *name; const char *name;
int pad; int pad;
if (opt & OUTPUT_SHOW_EMAIL) if (opt & OUTPUT_SHOW_EMAIL)
name = ci.author_mail; name = ci.author_mail.buf;
else else
name = ci.author; name = ci.author.buf;
pad = longest_author - utf8_strwidth(name); pad = longest_author - utf8_strwidth(name);
printf(" (%s%*s %10s", printf(" (%s%*s %10s",
name, pad, "", name, pad, "",
format_time(ci.author_time, format_time(ci.author_time,
ci.author_tz, ci.author_tz.buf,
show_raw_time)); show_raw_time));
} }
printf(" %*d) ", printf(" %*d) ",
@ -1734,6 +1736,8 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)
if (sb->final_buf_size && cp[-1] != '\n') if (sb->final_buf_size && cp[-1] != '\n')
putchar('\n'); putchar('\n');
commit_info_destroy(&ci);
} }
static void output(struct scoreboard *sb, int option) static void output(struct scoreboard *sb, int option)
@ -1858,9 +1862,9 @@ static void find_alignment(struct scoreboard *sb, int *option)
suspect->commit->object.flags |= METAINFO_SHOWN; suspect->commit->object.flags |= METAINFO_SHOWN;
get_commit_info(suspect->commit, &ci, 1); get_commit_info(suspect->commit, &ci, 1);
if (*option & OUTPUT_SHOW_EMAIL) if (*option & OUTPUT_SHOW_EMAIL)
num = utf8_strwidth(ci.author_mail); num = utf8_strwidth(ci.author_mail.buf);
else else
num = utf8_strwidth(ci.author); num = utf8_strwidth(ci.author.buf);
if (longest_author < num) if (longest_author < num)
longest_author = num; longest_author = num;
} }
@ -1872,6 +1876,8 @@ static void find_alignment(struct scoreboard *sb, int *option)
longest_dst_lines = num; longest_dst_lines = num;
if (largest_score < ent_score(sb, e)) if (largest_score < ent_score(sb, e))
largest_score = ent_score(sb, e); largest_score = ent_score(sb, e);
commit_info_destroy(&ci);
} }
max_orig_digits = decimal_width(longest_src_lines); max_orig_digits = decimal_width(longest_src_lines);
max_digits = decimal_width(longest_dst_lines); max_digits = decimal_width(longest_dst_lines);

View file

@ -36,36 +36,28 @@ static void insert_one_record(struct shortlog *log,
const char *dot3 = log->common_repo_prefix; const char *dot3 = log->common_repo_prefix;
char *buffer, *p; char *buffer, *p;
struct string_list_item *item; struct string_list_item *item;
char namebuf[1024]; const char *mailbuf, *namebuf;
char emailbuf[1024]; size_t namelen, maillen;
size_t len;
const char *eol; const char *eol;
struct strbuf subject = STRBUF_INIT; struct strbuf subject = STRBUF_INIT;
struct strbuf namemailbuf = STRBUF_INIT;
struct ident_split ident; struct ident_split ident;
if (split_ident_line(&ident, author, strlen(author))) if (split_ident_line(&ident, author, strlen(author)))
return; return;
/* copy author name to namebuf, to support matching on both name and email */ namebuf = ident.name_begin;
len = ident.name_end - ident.name_begin; mailbuf = ident.mail_begin;
memcpy(namebuf, ident.name_begin, len); namelen = ident.name_end - ident.name_begin;
namebuf[len] = 0; maillen = ident.mail_end - ident.mail_begin;
/* copy email name to emailbuf, to allow email replacement as well */ map_user(&log->mailmap, &mailbuf, &maillen, &namebuf, &namelen);
len = ident.mail_end - ident.mail_begin; strbuf_add(&namemailbuf, namebuf, namelen);
memcpy(emailbuf, ident.mail_begin, len);
emailbuf[len] = 0;
map_user(&log->mailmap, emailbuf, sizeof(emailbuf), namebuf, sizeof(namebuf)); if (log->email)
len = strlen(namebuf); strbuf_addf(&namemailbuf, " <%.*s>", (int)maillen, mailbuf);
if (log->email) { item = string_list_insert(&log->list, namemailbuf.buf);
size_t room = sizeof(namebuf) - len - 1;
int maillen = strlen(emailbuf);
snprintf(namebuf + len, room, " <%.*s>", maillen, emailbuf);
}
item = string_list_insert(&log->list, namebuf);
if (item->util == NULL) if (item->util == NULL)
item->util = xcalloc(1, sizeof(struct string_list)); item->util = xcalloc(1, sizeof(struct string_list));

View file

@ -240,50 +240,43 @@ static struct string_list_item *lookup_prefix(struct string_list *map,
} }
int map_user(struct string_list *map, 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 string_list_item *item;
struct mailmap_entry *me; struct mailmap_entry *me;
size_t maillen;
/* figure out space requirement for email */ debug_mm("map_user: map '%.*s' <%.*s>\n",
end_of_email = strchr(email, '>'); *name, *namelen, *emaillen, *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;
}
maillen = end_of_email - email; item = lookup_prefix(map, *email, *emaillen);
debug_mm("map_user: map '%s' <%.*s>\n", name, maillen, email);
item = lookup_prefix(map, email, maillen);
if (item != NULL) { if (item != NULL) {
me = (struct mailmap_entry *)item->util; me = (struct mailmap_entry *)item->util;
if (me->namemap.nr) { if (me->namemap.nr) {
/* The item has multiple items, so we'll look up on name too */ /* The item has multiple items, so we'll look up on name too */
/* If the name is not found, we choose the simple entry */ /* 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) if (subitem)
item = subitem; item = subitem;
} }
} }
if (item != NULL) { if (item != NULL) {
struct mailmap_info *mi = (struct mailmap_info *)item->util; 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"); debug_mm("map_user: -- (no simple mapping)\n");
return 0; return 0;
} }
if (maxlen_email && mi->email) if (mi->email) {
strlcpy(email, mi->email, maxlen_email); *email = mi->email;
else *emaillen = strlen(*email);
*end_of_email = '\0'; }
if (maxlen_name && mi->name) if (mi->name) {
strlcpy(name, mi->name, maxlen_name); *name = mi->name;
debug_mm("map_user: to '%s' <%s>\n", name, mi->email ? mi->email : ""); *namelen = strlen(*name);
}
debug_mm("map_user: to '%.*s' <.*%s>\n", *namelen, *name,
*emaillen, *email);
return 1; return 1;
} }
debug_mm("map_user: --\n"); debug_mm("map_user: --\n");

View file

@ -4,7 +4,7 @@
int read_mailmap(struct string_list *map, char **repo_abbrev); int read_mailmap(struct string_list *map, char **repo_abbrev);
void clear_mailmap(struct string_list *map); void clear_mailmap(struct string_list *map);
int map_user(struct string_list *mailmap, 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);
#endif #endif

View file

@ -593,7 +593,8 @@ char *logmsg_reencode(const struct commit *commit,
return out; return out;
} }
static int mailmap_name(char *email, int email_len, char *name, int name_len) static int mailmap_name(const char **email, size_t *email_len,
const char **name, size_t *name_len)
{ {
static struct string_list *mail_map; static struct string_list *mail_map;
if (!mail_map) { if (!mail_map) {
@ -610,36 +611,26 @@ static size_t format_person_part(struct strbuf *sb, char part,
const int placeholder_len = 2; const int placeholder_len = 2;
int tz; int tz;
unsigned long date = 0; unsigned long date = 0;
char person_name[1024];
char person_mail[1024];
struct ident_split s; struct ident_split s;
const char *name_start, *name_end, *mail_start, *mail_end; const char *name, *mail;
size_t maillen, namelen;
if (split_ident_line(&s, msg, len) < 0) if (split_ident_line(&s, msg, len) < 0)
goto skip; goto skip;
name_start = s.name_begin; name = s.name_begin;
name_end = s.name_end; namelen = s.name_end - s.name_begin;
mail_start = s.mail_begin; mail = s.mail_begin;
mail_end = s.mail_end; maillen = s.mail_end - s.mail_begin;
if (part == 'N' || part == 'E') { /* mailmap lookup */ if (part == 'N' || part == 'E') /* mailmap lookup */
snprintf(person_name, sizeof(person_name), "%.*s", mailmap_name(&mail, &maillen, &name, &namelen);
(int)(name_end - name_start), name_start);
snprintf(person_mail, sizeof(person_mail), "%.*s",
(int)(mail_end - mail_start), mail_start);
mailmap_name(person_mail, sizeof(person_mail), person_name, sizeof(person_name));
name_start = person_name;
name_end = name_start + strlen(person_name);
mail_start = person_mail;
mail_end = mail_start + strlen(person_mail);
}
if (part == 'n' || part == 'N') { /* name */ if (part == 'n' || part == 'N') { /* name */
strbuf_add(sb, name_start, name_end-name_start); strbuf_add(sb, name, namelen);
return placeholder_len; return placeholder_len;
} }
if (part == 'e' || part == 'E') { /* email */ if (part == 'e' || part == 'E') { /* email */
strbuf_add(sb, mail_start, mail_end-mail_start); strbuf_add(sb, mail, maillen);
return placeholder_len; return placeholder_len;
} }