2
2
#include "string-list.h"
3
3
#include "mailmap.h"
4
4
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
+
5
12
const 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
+
6
121
static int read_single_mailmap (struct string_list * map , const char * filename , char * * repo_abbrev )
7
122
{
8
123
char buffer [1024 ];
@@ -11,9 +126,7 @@ static int read_single_mailmap(struct string_list *map, const char *filename, ch
11
126
if (f == NULL )
12
127
return 1 ;
13
128
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 ;
17
130
if (buffer [0 ] == '#' ) {
18
131
static const char abbrev [] = "# repo-abbrev:" ;
19
132
int abblen = sizeof (abbrev ) - 1 ;
@@ -37,48 +150,49 @@ static int read_single_mailmap(struct string_list *map, const char *filename, ch
37
150
}
38
151
continue ;
39
152
}
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 );
59
158
}
60
159
fclose (f );
61
160
return 0 ;
62
161
}
63
162
64
163
int read_mailmap (struct string_list * map , char * * repo_abbrev )
65
164
{
165
+ map -> strdup_strings = 1 ;
66
166
/* each failure returns 1, so >1 means both calls failed */
67
167
return read_single_mailmap (map , ".mailmap" , repo_abbrev ) +
68
168
read_single_mailmap (map , git_mailmap_file , repo_abbrev ) > 1 ;
69
169
}
70
170
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 )
72
181
{
73
182
char * p ;
74
183
struct string_list_item * item ;
184
+ struct mailmap_entry * me ;
75
185
char buf [1024 ], * mailbuf ;
76
186
int i ;
77
187
78
- /* autocomplete common developers */
188
+ /* figure out space requirement for email */
79
189
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
+ }
82
196
if (p - email + 1 < sizeof (buf ))
83
197
mailbuf = buf ;
84
198
else
@@ -88,13 +202,39 @@ int map_email(struct string_list *map, const char *email, char *name, int maxlen
88
202
for (i = 0 ; i < p - email ; i ++ )
89
203
mailbuf [i ] = tolower (email [i ]);
90
204
mailbuf [i ] = 0 ;
205
+
206
+ debug_mm ("map_user: map '%s' <%s>\n" , name , mailbuf );
91
207
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
+ }
92
218
if (mailbuf != buf )
93
219
free (mailbuf );
94
220
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 : "" );
97
231
return 1 ;
98
232
}
233
+ debug_mm ("map_user: --\n" );
99
234
return 0 ;
100
235
}
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