22#include "string-list.h"
33#include "mailmap.h"
44
5+ #define DEBUG_MAILMAP 0
6+ #if DEBUG_MAILMAP
7+ #define debug_mm (...) fprintf(stderr, __VA_ARGS__)
8+ #else
9+ static inline void debug_mm (const char * format , ...) {}
10+ #endif
11+
512const char * git_mailmap_file ;
13+
14+ struct mailmap_info {
15+ char * name ;
16+ char * email ;
17+ };
18+
19+ struct mailmap_entry {
20+ /* name and email for the simple mail-only case */
21+ char * name ;
22+ char * email ;
23+
24+ /* name and email for the complex mail and name matching case */
25+ struct string_list namemap ;
26+ };
27+
28+ static void free_mailmap_info (void * p , const char * s )
29+ {
30+ struct mailmap_info * mi = (struct mailmap_info * )p ;
31+ debug_mm ("mailmap: -- complex: '%s' -> '%s' <%s>\n" , s , mi -> name , mi -> email );
32+ free (mi -> name );
33+ free (mi -> email );
34+ }
35+
36+ static void free_mailmap_entry (void * p , const char * s )
37+ {
38+ struct mailmap_entry * me = (struct mailmap_entry * )p ;
39+ debug_mm ("mailmap: removing entries for <%s>, with %d sub-entries\n" , s , me -> namemap .nr );
40+ debug_mm ("mailmap: - simple: '%s' <%s>\n" , me -> name , me -> email );
41+ free (me -> name );
42+ free (me -> email );
43+
44+ me -> namemap .strdup_strings = 1 ;
45+ string_list_clear_func (& me -> namemap , free_mailmap_info );
46+ }
47+
48+ static void add_mapping (struct string_list * map ,
49+ char * new_name , char * new_email , char * old_name , char * old_email )
50+ {
51+ struct mailmap_entry * me ;
52+ int index ;
53+ if (old_email == NULL ) {
54+ old_email = new_email ;
55+ new_email = NULL ;
56+ }
57+
58+ if ((index = string_list_find_insert_index (map , old_email , 1 )) < 0 ) {
59+ /* mailmap entry exists, invert index value */
60+ index = -1 - index ;
61+ } else {
62+ /* create mailmap entry */
63+ struct string_list_item * item = string_list_insert_at_index (index , old_email , map );
64+ item -> util = xmalloc (sizeof (struct mailmap_entry ));
65+ memset (item -> util , 0 , sizeof (struct mailmap_entry ));
66+ ((struct mailmap_entry * )item -> util )-> namemap .strdup_strings = 1 ;
67+ }
68+ me = (struct mailmap_entry * )map -> items [index ].util ;
69+
70+ if (old_name == NULL ) {
71+ debug_mm ("mailmap: adding (simple) entry for %s at index %d\n" , old_email , index );
72+ /* Replace current name and new email for simple entry */
73+ free (me -> name );
74+ free (me -> email );
75+ if (new_name )
76+ me -> name = xstrdup (new_name );
77+ if (new_email )
78+ me -> email = xstrdup (new_email );
79+ } else {
80+ struct mailmap_info * mi = xmalloc (sizeof (struct mailmap_info ));
81+ debug_mm ("mailmap: adding (complex) entry for %s at index %d\n" , old_email , index );
82+ if (new_name )
83+ mi -> name = xstrdup (new_name );
84+ if (new_email )
85+ mi -> email = xstrdup (new_email );
86+ string_list_insert (old_name , & me -> namemap )-> util = mi ;
87+ }
88+
89+ debug_mm ("mailmap: '%s' <%s> -> '%s' <%s>\n" ,
90+ old_name , old_email , new_name , new_email );
91+ }
92+
93+ static char * parse_name_and_email (char * buffer , char * * name , char * * email )
94+ {
95+ char * left , * right , * nstart , * nend ;
96+ * name = * email = 0 ;
97+
98+ if ((left = strchr (buffer , '<' )) == NULL )
99+ return NULL ;
100+ if ((right = strchr (left + 1 , '>' )) == NULL )
101+ return NULL ;
102+ if (left + 1 == right )
103+ return NULL ;
104+
105+ /* remove whitespace from beginning and end of name */
106+ nstart = buffer ;
107+ while (isspace (* nstart ) && nstart < left )
108+ ++ nstart ;
109+ nend = left - 1 ;
110+ while (isspace (* nend ) && nend > nstart )
111+ -- nend ;
112+
113+ * name = (nstart < nend ? nstart : NULL );
114+ * email = left + 1 ;
115+ * (nend + 1 ) = '\0' ;
116+ * right ++ = '\0' ;
117+
118+ return (* right == '\0' ? NULL : right );
119+ }
120+
6121static int read_single_mailmap (struct string_list * map , const char * filename , char * * repo_abbrev )
7122{
8123 char buffer [1024 ];
@@ -11,9 +126,7 @@ static int read_single_mailmap(struct string_list *map, const char *filename, ch
11126 if (f == NULL )
12127 return 1 ;
13128 while (fgets (buffer , sizeof (buffer ), f ) != NULL ) {
14- char * end_of_name , * left_bracket , * right_bracket ;
15- char * name , * email ;
16- int i ;
129+ char * name1 = 0 , * email1 = 0 , * name2 = 0 , * email2 = 0 ;
17130 if (buffer [0 ] == '#' ) {
18131 static const char abbrev [] = "# repo-abbrev:" ;
19132 int abblen = sizeof (abbrev ) - 1 ;
@@ -37,48 +150,49 @@ static int read_single_mailmap(struct string_list *map, const char *filename, ch
37150 }
38151 continue ;
39152 }
40- if ((left_bracket = strchr (buffer , '<' )) == NULL )
41- continue ;
42- if ((right_bracket = strchr (left_bracket + 1 , '>' )) == NULL )
43- continue ;
44- if (right_bracket == left_bracket + 1 )
45- continue ;
46- for (end_of_name = left_bracket ;
47- end_of_name != buffer && isspace (end_of_name [-1 ]);
48- end_of_name -- )
49- ; /* keep on looking */
50- if (end_of_name == buffer )
51- continue ;
52- name = xmalloc (end_of_name - buffer + 1 );
53- strlcpy (name , buffer , end_of_name - buffer + 1 );
54- email = xmalloc (right_bracket - left_bracket );
55- for (i = 0 ; i < right_bracket - left_bracket - 1 ; i ++ )
56- email [i ] = tolower (left_bracket [i + 1 ]);
57- email [right_bracket - left_bracket - 1 ] = '\0' ;
58- string_list_insert (email , map )-> util = name ;
153+ if ((name2 = parse_name_and_email (buffer , & name1 , & email1 )) != NULL )
154+ parse_name_and_email (name2 , & name2 , & email2 );
155+
156+ if (email1 )
157+ add_mapping (map , name1 , email1 , name2 , email2 );
59158 }
60159 fclose (f );
61160 return 0 ;
62161}
63162
64163int read_mailmap (struct string_list * map , char * * repo_abbrev )
65164{
165+ map -> strdup_strings = 1 ;
66166 /* each failure returns 1, so >1 means both calls failed */
67167 return read_single_mailmap (map , ".mailmap" , repo_abbrev ) +
68168 read_single_mailmap (map , git_mailmap_file , repo_abbrev ) > 1 ;
69169}
70170
71- int map_email (struct string_list * map , const char * email , char * name , int maxlen )
171+ void clear_mailmap (struct string_list * map )
172+ {
173+ debug_mm ("mailmap: clearing %d entries...\n" , map -> nr );
174+ map -> strdup_strings = 1 ;
175+ string_list_clear_func (map , free_mailmap_entry );
176+ debug_mm ("mailmap: cleared\n" );
177+ }
178+
179+ int map_user (struct string_list * map ,
180+ char * email , int maxlen_email , char * name , int maxlen_name )
72181{
73182 char * p ;
74183 struct string_list_item * item ;
184+ struct mailmap_entry * me ;
75185 char buf [1024 ], * mailbuf ;
76186 int i ;
77187
78- /* autocomplete common developers */
188+ /* figure out space requirement for email */
79189 p = strchr (email , '>' );
80- if (!p )
81- return 0 ;
190+ if (!p ) {
191+ /* email passed in might not be wrapped in <>, but end with a \0 */
192+ p = memchr (email , '\0' , maxlen_email );
193+ if (p == 0 )
194+ return 0 ;
195+ }
82196 if (p - email + 1 < sizeof (buf ))
83197 mailbuf = buf ;
84198 else
@@ -88,13 +202,39 @@ int map_email(struct string_list *map, const char *email, char *name, int maxlen
88202 for (i = 0 ; i < p - email ; i ++ )
89203 mailbuf [i ] = tolower (email [i ]);
90204 mailbuf [i ] = 0 ;
205+
206+ debug_mm ("map_user: map '%s' <%s>\n" , name , mailbuf );
91207 item = string_list_lookup (mailbuf , map );
208+ if (item != NULL ) {
209+ me = (struct mailmap_entry * )item -> util ;
210+ if (me -> namemap .nr ) {
211+ /* The item has multiple items, so we'll look up on name too */
212+ /* If the name is not found, we choose the simple entry */
213+ struct string_list_item * subitem = string_list_lookup (name , & me -> namemap );
214+ if (subitem )
215+ item = subitem ;
216+ }
217+ }
92218 if (mailbuf != buf )
93219 free (mailbuf );
94220 if (item != NULL ) {
95- const char * realname = (const char * )item -> util ;
96- strlcpy (name , realname , maxlen );
221+ struct mailmap_info * mi = (struct mailmap_info * )item -> util ;
222+ if (mi -> name == NULL && (mi -> email == NULL || maxlen_email == 0 )) {
223+ debug_mm ("map_user: -- (no simple mapping)\n" );
224+ return 0 ;
225+ }
226+ if (maxlen_email && mi -> email )
227+ strlcpy (email , mi -> email , maxlen_email );
228+ if (maxlen_name && mi -> name )
229+ strlcpy (name , mi -> name , maxlen_name );
230+ debug_mm ("map_user: to '%s' <%s>\n" , name , mi -> email ? mi -> email : "" );
97231 return 1 ;
98232 }
233+ debug_mm ("map_user: --\n" );
99234 return 0 ;
100235}
236+
237+ int map_email (struct string_list * map , const char * email , char * name , int maxlen )
238+ {
239+ return map_user (map , (char * )email , 0 , name , maxlen );
240+ }
0 commit comments