THIS IS A TEST INSTANCE ONLY! REPOSITORIES CAN BE DELETED AT ANY TIME!

Git Source Code Mirror - This is a publish-only repository and all pull requests are ignored. Please follow Documentation/SubmittingPatches procedure for any of your improvements.
git
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

364 lines
8.9KB

  1. #include "cache.h"
  2. #include "string-list.h"
  3. #include "mailmap.h"
  4. #include "object-store.h"
  5. #define DEBUG_MAILMAP 0
  6. #if DEBUG_MAILMAP
  7. #define debug_mm(...) fprintf(stderr, __VA_ARGS__)
  8. #define debug_str(X) ((X) ? (X) : "(none)")
  9. #else
  10. static inline void debug_mm(const char *format, ...) {}
  11. static inline const char *debug_str(const char *s) { return s; }
  12. #endif
  13. const char *git_mailmap_file;
  14. const char *git_mailmap_blob;
  15. struct mailmap_info {
  16. char *name;
  17. char *email;
  18. };
  19. struct mailmap_entry {
  20. /* name and email for the simple mail-only case */
  21. char *name;
  22. char *email;
  23. /* name and email for the complex mail and name matching case */
  24. struct string_list namemap;
  25. };
  26. static void free_mailmap_info(void *p, const char *s)
  27. {
  28. struct mailmap_info *mi = (struct mailmap_info *)p;
  29. debug_mm("mailmap: -- complex: '%s' -> '%s' <%s>\n",
  30. s, debug_str(mi->name), debug_str(mi->email));
  31. free(mi->name);
  32. free(mi->email);
  33. }
  34. static void free_mailmap_entry(void *p, const char *s)
  35. {
  36. struct mailmap_entry *me = (struct mailmap_entry *)p;
  37. debug_mm("mailmap: removing entries for <%s>, with %d sub-entries\n",
  38. s, me->namemap.nr);
  39. debug_mm("mailmap: - simple: '%s' <%s>\n",
  40. debug_str(me->name), debug_str(me->email));
  41. free(me->name);
  42. free(me->email);
  43. me->namemap.strdup_strings = 1;
  44. string_list_clear_func(&me->namemap, free_mailmap_info);
  45. }
  46. /*
  47. * On some systems (e.g. MinGW 4.0), string.h has _only_ inline
  48. * definition of strcasecmp and no non-inline implementation is
  49. * supplied anywhere, which is, eh, "unusual"; we cannot take an
  50. * address of such a function to store it in namemap.cmp. This is
  51. * here as a workaround---do not assign strcasecmp directly to
  52. * namemap.cmp until we know no systems that matter have such an
  53. * "unusual" string.h.
  54. */
  55. static int namemap_cmp(const char *a, const char *b)
  56. {
  57. return strcasecmp(a, b);
  58. }
  59. static void add_mapping(struct string_list *map,
  60. char *new_name, char *new_email,
  61. char *old_name, char *old_email)
  62. {
  63. struct mailmap_entry *me;
  64. struct string_list_item *item;
  65. if (old_email == NULL) {
  66. old_email = new_email;
  67. new_email = NULL;
  68. }
  69. item = string_list_insert(map, old_email);
  70. if (item->util) {
  71. me = (struct mailmap_entry *)item->util;
  72. } else {
  73. me = xcalloc(1, sizeof(struct mailmap_entry));
  74. me->namemap.strdup_strings = 1;
  75. me->namemap.cmp = namemap_cmp;
  76. item->util = me;
  77. }
  78. if (old_name == NULL) {
  79. debug_mm("mailmap: adding (simple) entry for '%s'\n", old_email);
  80. /* Replace current name and new email for simple entry */
  81. if (new_name) {
  82. free(me->name);
  83. me->name = xstrdup(new_name);
  84. }
  85. if (new_email) {
  86. free(me->email);
  87. me->email = xstrdup(new_email);
  88. }
  89. } else {
  90. struct mailmap_info *mi = xcalloc(1, sizeof(struct mailmap_info));
  91. debug_mm("mailmap: adding (complex) entry for '%s'\n", old_email);
  92. mi->name = xstrdup_or_null(new_name);
  93. mi->email = xstrdup_or_null(new_email);
  94. string_list_insert(&me->namemap, old_name)->util = mi;
  95. }
  96. debug_mm("mailmap: '%s' <%s> -> '%s' <%s>\n",
  97. debug_str(old_name), old_email,
  98. debug_str(new_name), debug_str(new_email));
  99. }
  100. static char *parse_name_and_email(char *buffer, char **name,
  101. char **email, int allow_empty_email)
  102. {
  103. char *left, *right, *nstart, *nend;
  104. *name = *email = NULL;
  105. if ((left = strchr(buffer, '<')) == NULL)
  106. return NULL;
  107. if ((right = strchr(left+1, '>')) == NULL)
  108. return NULL;
  109. if (!allow_empty_email && (left+1 == right))
  110. return NULL;
  111. /* remove whitespace from beginning and end of name */
  112. nstart = buffer;
  113. while (isspace(*nstart) && nstart < left)
  114. ++nstart;
  115. nend = left-1;
  116. while (nend > nstart && isspace(*nend))
  117. --nend;
  118. *name = (nstart <= nend ? nstart : NULL);
  119. *email = left+1;
  120. *(nend+1) = '\0';
  121. *right++ = '\0';
  122. return (*right == '\0' ? NULL : right);
  123. }
  124. static void read_mailmap_line(struct string_list *map, char *buffer,
  125. char **repo_abbrev)
  126. {
  127. char *name1 = NULL, *email1 = NULL, *name2 = NULL, *email2 = NULL;
  128. if (buffer[0] == '#') {
  129. static const char abbrev[] = "# repo-abbrev:";
  130. int abblen = sizeof(abbrev) - 1;
  131. int len = strlen(buffer);
  132. if (!repo_abbrev)
  133. return;
  134. if (len && buffer[len - 1] == '\n')
  135. buffer[--len] = 0;
  136. if (!strncmp(buffer, abbrev, abblen)) {
  137. char *cp;
  138. free(*repo_abbrev);
  139. for (cp = buffer + abblen; isspace(*cp); cp++)
  140. ; /* nothing */
  141. *repo_abbrev = xstrdup(cp);
  142. }
  143. return;
  144. }
  145. if ((name2 = parse_name_and_email(buffer, &name1, &email1, 0)) != NULL)
  146. parse_name_and_email(name2, &name2, &email2, 1);
  147. if (email1)
  148. add_mapping(map, name1, email1, name2, email2);
  149. }
  150. static int read_mailmap_file(struct string_list *map, const char *filename,
  151. char **repo_abbrev)
  152. {
  153. char buffer[1024];
  154. FILE *f;
  155. if (!filename)
  156. return 0;
  157. f = fopen(filename, "r");
  158. if (!f) {
  159. if (errno == ENOENT)
  160. return 0;
  161. return error_errno("unable to open mailmap at %s", filename);
  162. }
  163. while (fgets(buffer, sizeof(buffer), f) != NULL)
  164. read_mailmap_line(map, buffer, repo_abbrev);
  165. fclose(f);
  166. return 0;
  167. }
  168. static void read_mailmap_string(struct string_list *map, char *buf,
  169. char **repo_abbrev)
  170. {
  171. while (*buf) {
  172. char *end = strchrnul(buf, '\n');
  173. if (*end)
  174. *end++ = '\0';
  175. read_mailmap_line(map, buf, repo_abbrev);
  176. buf = end;
  177. }
  178. }
  179. static int read_mailmap_blob(struct string_list *map,
  180. const char *name,
  181. char **repo_abbrev)
  182. {
  183. struct object_id oid;
  184. char *buf;
  185. unsigned long size;
  186. enum object_type type;
  187. if (!name)
  188. return 0;
  189. if (get_oid(name, &oid) < 0)
  190. return 0;
  191. buf = read_object_file(&oid, &type, &size);
  192. if (!buf)
  193. return error("unable to read mailmap object at %s", name);
  194. if (type != OBJ_BLOB)
  195. return error("mailmap is not a blob: %s", name);
  196. read_mailmap_string(map, buf, repo_abbrev);
  197. free(buf);
  198. return 0;
  199. }
  200. int read_mailmap(struct string_list *map, char **repo_abbrev)
  201. {
  202. int err = 0;
  203. map->strdup_strings = 1;
  204. map->cmp = namemap_cmp;
  205. if (!git_mailmap_blob && is_bare_repository())
  206. git_mailmap_blob = "HEAD:.mailmap";
  207. err |= read_mailmap_file(map, ".mailmap", repo_abbrev);
  208. if (startup_info->have_repository)
  209. err |= read_mailmap_blob(map, git_mailmap_blob, repo_abbrev);
  210. err |= read_mailmap_file(map, git_mailmap_file, repo_abbrev);
  211. return err;
  212. }
  213. void clear_mailmap(struct string_list *map)
  214. {
  215. debug_mm("mailmap: clearing %d entries...\n", map->nr);
  216. map->strdup_strings = 1;
  217. string_list_clear_func(map, free_mailmap_entry);
  218. debug_mm("mailmap: cleared\n");
  219. }
  220. /*
  221. * Look for an entry in map that match string[0:len]; string[len]
  222. * does not have to be NUL (but it could be).
  223. */
  224. static struct string_list_item *lookup_prefix(struct string_list *map,
  225. const char *string, size_t len)
  226. {
  227. int i = string_list_find_insert_index(map, string, 1);
  228. if (i < 0) {
  229. /* exact match */
  230. i = -1 - i;
  231. if (!string[len])
  232. return &map->items[i];
  233. /*
  234. * that map entry matches exactly to the string, including
  235. * the cruft at the end beyond "len". That is not a match
  236. * with string[0:len] that we are looking for.
  237. */
  238. } else if (!string[len]) {
  239. /*
  240. * asked with the whole string, and got nothing. No
  241. * matching entry can exist in the map.
  242. */
  243. return NULL;
  244. }
  245. /*
  246. * i is at the exact match to an overlong key, or location the
  247. * overlong key would be inserted, which must come after the
  248. * real location of the key if one exists.
  249. */
  250. while (0 <= --i && i < map->nr) {
  251. int cmp = strncasecmp(map->items[i].string, string, len);
  252. if (cmp < 0)
  253. /*
  254. * "i" points at a key definitely below the prefix;
  255. * the map does not have string[0:len] in it.
  256. */
  257. break;
  258. else if (!cmp && !map->items[i].string[len])
  259. /* found it */
  260. return &map->items[i];
  261. /*
  262. * otherwise, the string at "i" may be string[0:len]
  263. * followed by a string that sorts later than string[len:];
  264. * keep trying.
  265. */
  266. }
  267. return NULL;
  268. }
  269. int map_user(struct string_list *map,
  270. const char **email, size_t *emaillen,
  271. const char **name, size_t *namelen)
  272. {
  273. struct string_list_item *item;
  274. struct mailmap_entry *me;
  275. debug_mm("map_user: map '%.*s' <%.*s>\n",
  276. (int)*namelen, debug_str(*name),
  277. (int)*emaillen, debug_str(*email));
  278. item = lookup_prefix(map, *email, *emaillen);
  279. if (item != NULL) {
  280. me = (struct mailmap_entry *)item->util;
  281. if (me->namemap.nr) {
  282. /*
  283. * The item has multiple items, so we'll look up on
  284. * name too. If the name is not found, we choose the
  285. * simple entry.
  286. */
  287. struct string_list_item *subitem;
  288. subitem = lookup_prefix(&me->namemap, *name, *namelen);
  289. if (subitem)
  290. item = subitem;
  291. }
  292. }
  293. if (item != NULL) {
  294. struct mailmap_info *mi = (struct mailmap_info *)item->util;
  295. if (mi->name == NULL && mi->email == NULL) {
  296. debug_mm("map_user: -- (no simple mapping)\n");
  297. return 0;
  298. }
  299. if (mi->email) {
  300. *email = mi->email;
  301. *emaillen = strlen(*email);
  302. }
  303. if (mi->name) {
  304. *name = mi->name;
  305. *namelen = strlen(*name);
  306. }
  307. debug_mm("map_user: to '%.*s' <%.*s>\n",
  308. (int)*namelen, debug_str(*name),
  309. (int)*emaillen, debug_str(*email));
  310. return 1;
  311. }
  312. debug_mm("map_user: --\n");
  313. return 0;
  314. }