source src/mailmap.c
| Line | Flow | Count | Block(s) | Source |
|---|---|---|---|---|
| 1 | - | /* | ||
| 2 | - | * Copyright (C) the libgit2 contributors. All rights reserved. | ||
| 3 | - | * | ||
| 4 | - | * This file is part of libgit2, distributed under the GNU GPL v2 with | ||
| 5 | - | * a Linking Exception. For full terms see the included COPYING file. | ||
| 6 | - | */ | ||
| 7 | - | |||
| 8 | - | #include "mailmap.h" | ||
| 9 | - | |||
| 10 | - | #include "common.h" | ||
| 11 | - | #include "path.h" | ||
| 12 | - | #include "repository.h" | ||
| 13 | - | #include "signature.h" | ||
| 14 | - | #include "git2/config.h" | ||
| 15 | - | #include "git2/revparse.h" | ||
| 16 | - | #include "blob.h" | ||
| 17 | - | #include "parse.h" | ||
| 18 | - | |||
| 19 | - | #define MM_FILE ".mailmap" | ||
| 20 | - | #define MM_FILE_CONFIG "mailmap.file" | ||
| 21 | - | #define MM_BLOB_CONFIG "mailmap.blob" | ||
| 22 | - | #define MM_BLOB_DEFAULT "HEAD:" MM_FILE | ||
| 23 | - | |||
| 24 | 81 | 2 | static void mailmap_entry_free(git_mailmap_entry *entry) | |
| 25 | - | { | ||
| 26 | 81 | 2 | if (!entry) | |
| 27 | 81 | 3,9 | return; | |
| 28 | - | |||
| 29 | 81 | 4 | git__free(entry->real_name); | |
| 30 | 81 | 5 | git__free(entry->real_email); | |
| 31 | 81 | 6 | git__free(entry->replace_name); | |
| 32 | 81 | 7 | git__free(entry->replace_email); | |
| 33 | 81 | 8 | git__free(entry); | |
| 34 | - | } | ||
| 35 | - | |||
| 36 | - | /* | ||
| 37 | - | * First we sort by replace_email, then replace_name (if present). | ||
| 38 | - | * Entries with names are greater than entries without. | ||
| 39 | - | */ | ||
| 40 | ![]() |
500 | 2 | static int mailmap_entry_cmp(const void *a_raw, const void *b_raw) |
| 41 | - | { | ||
| 42 | 500 | 2 | const git_mailmap_entry *a = (const git_mailmap_entry *)a_raw; | |
| 43 | 500 | 2 | const git_mailmap_entry *b = (const git_mailmap_entry *)b_raw; | |
| 44 | - | int cmp; | ||
| 45 | - | |||
| 46 | 500 | 2-6 | assert(a && b && a->replace_email && b->replace_email); | |
| 47 | - | |||
| 48 | 500 | 7 | cmp = git__strcmp(a->replace_email, b->replace_email); | |
| 49 | 500 | 7 | if (cmp) | |
| 50 | 299 | 8 | return cmp; | |
| 51 | - | |||
| 52 | - | /* NULL replace_names are less than not-NULL ones */ | ||
| 53 | 201 | 9,10 | if (a->replace_name == NULL || b->replace_name == NULL) | |
| 54 | 180 | 11 | return (int)(a->replace_name != NULL) - (int)(b->replace_name != NULL); | |
| 55 | - | |||
| 56 | 21 | 12 | return git__strcmp(a->replace_name, b->replace_name); | |
| 57 | - | } | ||
| 58 | - | |||
| 59 | - | /* Replace the old entry with the new on duplicate. */ | ||
| 60 | 2 | 2 | static int mailmap_entry_replace(void **old_raw, void *new_raw) | |
| 61 | - | { | ||
| 62 | 2 | 2 | mailmap_entry_free((git_mailmap_entry *)*old_raw); | |
| 63 | 2 | 3 | *old_raw = new_raw; | |
| 64 | 2 | 3 | return GIT_EEXISTS; | |
| 65 | - | } | ||
| 66 | - | |||
| 67 | - | /* Check if we're at the end of line, w/ comments */ | ||
| 68 | 334 | 2 | static bool is_eol(git_parse_ctx *ctx) | |
| 69 | - | { | ||
| 70 | - | char c; | ||
| 71 | 334 | 2 | return git_parse_peek(&c, ctx, GIT_PARSE_PEEK_SKIP_WHITESPACE) < 0 || c == '#'; | |
| 72 | - | } | ||
| 73 | - | |||
| 74 | ![]() |
291 | 2 | static int advance_until( |
| 75 | - | const char **start, size_t *len, git_parse_ctx *ctx, char needle) | ||
| 76 | - | { | ||
| 77 | 291 | 2 | *start = ctx->line; | |
| 78 | 3423 | 2,4-6 | while (ctx->line_len > 0 && *ctx->line != '#' && *ctx->line != needle) | |
| 79 | 3132 | 3 | git_parse_advance_chars(ctx, 1); | |
| 80 | - | |||
| 81 | 291 | 7,8 | if (ctx->line_len == 0 || *ctx->line == '#') | |
| 82 | 5 | 9 | return -1; /* end of line */ | |
| 83 | - | |||
| 84 | 286 | 10 | *len = ctx->line - *start; | |
| 85 | 286 | 10 | git_parse_advance_chars(ctx, 1); /* advance past needle */ | |
| 86 | 286 | 11 | return 0; | |
| 87 | - | } | ||
| 88 | - | |||
| 89 | - | /* | ||
| 90 | - | * Parse a single entry from a mailmap file. | ||
| 91 | - | * | ||
| 92 | - | * The output git_bufs will be non-owning, and should be copied before being | ||
| 93 | - | * persisted. | ||
| 94 | - | */ | ||
| 95 | 172 | 2 | static int parse_mailmap_entry( | |
| 96 | - | git_buf *real_name, git_buf *real_email, | ||
| 97 | - | git_buf *replace_name, git_buf *replace_email, | ||
| 98 | - | git_parse_ctx *ctx) | ||
| 99 | - | { | ||
| 100 | - | const char *start; | ||
| 101 | - | size_t len; | ||
| 102 | - | |||
| 103 | 172 | 2 | git_buf_clear(real_name); | |
| 104 | 172 | 3 | git_buf_clear(real_email); | |
| 105 | 172 | 4 | git_buf_clear(replace_name); | |
| 106 | 172 | 5 | git_buf_clear(replace_email); | |
| 107 | - | |||
| 108 | 172 | 6 | git_parse_advance_ws(ctx); | |
| 109 | 172 | 7,8 | if (is_eol(ctx)) | |
| 110 | 86 | 9 | return -1; /* blank line */ | |
| 111 | - | |||
| 112 | - | /* Parse the real name */ | ||
| 113 | 86 | 10,11 | if (advance_until(&start, &len, ctx, '<') < 0) | |
| 114 | 5 | 12 | return -1; | |
| 115 | - | |||
| 116 | 81 | 13 | git_buf_attach_notowned(real_name, start, len); | |
| 117 | 81 | 14 | git_buf_rtrim(real_name); | |
| 118 | - | |||
| 119 | - | /* | ||
| 120 | - | * If this is the last email in the line, this is the email to replace, | ||
| 121 | - | * otherwise, it's the real email. | ||
| 122 | - | */ | ||
| 123 | 81 | 15,16 | if (advance_until(&start, &len, ctx, '>') < 0) | |
| 124 | ##### | 17 | return -1; | |
| 125 | - | |||
| 126 | - | /* If we aren't at the end of the line, parse a second name and email */ | ||
| 127 | 81 | 18,19 | if (!is_eol(ctx)) { | |
| 128 | 62 | 20 | git_buf_attach_notowned(real_email, start, len); | |
| 129 | - | |||
| 130 | 62 | 21 | git_parse_advance_ws(ctx); | |
| 131 | 62 | 22,23 | if (advance_until(&start, &len, ctx, '<') < 0) | |
| 132 | ##### | 24 | return -1; | |
| 133 | 62 | 25 | git_buf_attach_notowned(replace_name, start, len); | |
| 134 | 62 | 26 | git_buf_rtrim(replace_name); | |
| 135 | - | |||
| 136 | 62 | 27,28 | if (advance_until(&start, &len, ctx, '>') < 0) | |
| 137 | ##### | 29 | return -1; | |
| 138 | - | } | ||
| 139 | - | |||
| 140 | 81 | 30 | git_buf_attach_notowned(replace_email, start, len); | |
| 141 | - | |||
| 142 | 81 | 31,32 | if (!is_eol(ctx)) | |
| 143 | ##### | 33 | return -1; | |
| 144 | - | |||
| 145 | 81 | 34 | return 0; | |
| 146 | - | } | ||
| 147 | - | |||
| 148 | 13 | 2 | int git_mailmap_new(git_mailmap **out) | |
| 149 | - | { | ||
| 150 | - | int error; | ||
| 151 | 13 | 2 | git_mailmap *mm = git__calloc(1, sizeof(git_mailmap)); | |
| 152 | 13 | 3,4 | GIT_ERROR_CHECK_ALLOC(mm); | |
| 153 | - | |||
| 154 | 13 | 5 | error = git_vector_init(&mm->entries, 0, mailmap_entry_cmp); | |
| 155 | 13 | 6 | if (error < 0) { | |
| 156 | ##### | 7 | git__free(mm); | |
| 157 | ##### | 8 | return error; | |
| 158 | - | } | ||
| 159 | 13 | 9 | *out = mm; | |
| 160 | 13 | 9 | return 0; | |
| 161 | - | } | ||
| 162 | - | |||
| 163 | 43 | 2 | void git_mailmap_free(git_mailmap *mm) | |
| 164 | - | { | ||
| 165 | - | size_t idx; | ||
| 166 | - | git_mailmap_entry *entry; | ||
| 167 | 43 | 2 | if (!mm) | |
| 168 | 43 | 3,11 | return; | |
| 169 | - | |||
| 170 | 92 | 4,6-8 | git_vector_foreach(&mm->entries, idx, entry) | |
| 171 | 79 | 5 | mailmap_entry_free(entry); | |
| 172 | - | |||
| 173 | 13 | 9 | git_vector_free(&mm->entries); | |
| 174 | 13 | 10 | git__free(mm); | |
| 175 | - | } | ||
| 176 | - | |||
| 177 | ![]() |
81 | 2 | static int mailmap_add_entry_unterminated( |
| 178 | - | git_mailmap *mm, | ||
| 179 | - | const char *real_name, size_t real_name_size, | ||
| 180 | - | const char *real_email, size_t real_email_size, | ||
| 181 | - | const char *replace_name, size_t replace_name_size, | ||
| 182 | - | const char *replace_email, size_t replace_email_size) | ||
| 183 | - | { | ||
| 184 | - | int error; | ||
| 185 | 81 | 2 | git_mailmap_entry *entry = git__calloc(1, sizeof(git_mailmap_entry)); | |
| 186 | 81 | 3,4 | GIT_ERROR_CHECK_ALLOC(entry); | |
| 187 | - | |||
| 188 | 81 | 5-8 | assert(mm && replace_email && *replace_email); | |
| 189 | - | |||
| 190 | 81 | 9 | if (real_name_size > 0) { | |
| 191 | 57 | 10 | entry->real_name = git__substrdup(real_name, real_name_size); | |
| 192 | 57 | 11,12 | GIT_ERROR_CHECK_ALLOC(entry->real_name); | |
| 193 | - | } | ||
| 194 | 81 | 13 | if (real_email_size > 0) { | |
| 195 | 62 | 14 | entry->real_email = git__substrdup(real_email, real_email_size); | |
| 196 | 62 | 15,16 | GIT_ERROR_CHECK_ALLOC(entry->real_email); | |
| 197 | - | } | ||
| 198 | 81 | 17 | if (replace_name_size > 0) { | |
| 199 | 26 | 18 | entry->replace_name = git__substrdup(replace_name, replace_name_size); | |
| 200 | 26 | 19,20 | GIT_ERROR_CHECK_ALLOC(entry->replace_name); | |
| 201 | - | } | ||
| 202 | 81 | 21 | entry->replace_email = git__substrdup(replace_email, replace_email_size); | |
| 203 | 81 | 22,23 | GIT_ERROR_CHECK_ALLOC(entry->replace_email); | |
| 204 | - | |||
| 205 | 81 | 24 | error = git_vector_insert_sorted(&mm->entries, entry, mailmap_entry_replace); | |
| 206 | 81 | 25 | if (error == GIT_EEXISTS) | |
| 207 | 2 | 26 | error = GIT_OK; | |
| 208 | 79 | 27 | else if (error < 0) | |
| 209 | ##### | 28 | mailmap_entry_free(entry); | |
| 210 | - | |||
| 211 | 81 | 29 | return error; | |
| 212 | - | } | ||
| 213 | - | |||
| 214 | ##### | 2 | int git_mailmap_add_entry( | |
| 215 | - | git_mailmap *mm, const char *real_name, const char *real_email, | ||
| 216 | - | const char *replace_name, const char *replace_email) | ||
| 217 | - | { | ||
| 218 | ##### | 2 | return mailmap_add_entry_unterminated( | |
| 219 | - | mm, | ||
| 220 | - | real_name, real_name ? strlen(real_name) : 0, | ||
| 221 | - | real_email, real_email ? strlen(real_email) : 0, | ||
| 222 | - | replace_name, replace_name ? strlen(replace_name) : 0, | ||
| 223 | - | replace_email, strlen(replace_email)); | ||
| 224 | - | } | ||
| 225 | - | |||
| 226 | ![]() |
15 | 2 | static int mailmap_add_buffer(git_mailmap *mm, const char *buf, size_t len) |
| 227 | - | { | ||
| 228 | 15 | 2 | int error = 0; | |
| 229 | - | git_parse_ctx ctx; | ||
| 230 | - | |||
| 231 | - | /* Scratch buffers containing the real parsed names & emails */ | ||
| 232 | 15 | 2 | git_buf real_name = GIT_BUF_INIT; | |
| 233 | 15 | 2 | git_buf real_email = GIT_BUF_INIT; | |
| 234 | 15 | 2 | git_buf replace_name = GIT_BUF_INIT; | |
| 235 | 15 | 2 | git_buf replace_email = GIT_BUF_INIT; | |
| 236 | - | |||
| 237 | - | /* Buffers may not contain '\0's. */ | ||
| 238 | 15 | 2 | if (memchr(buf, '\0', len) != NULL) | |
| 239 | ##### | 3 | return -1; | |
| 240 | - | |||
| 241 | 15 | 4 | git_parse_ctx_init(&ctx, buf, len); | |
| 242 | - | |||
| 243 | - | /* Run the parser */ | ||
| 244 | 187 | 5,14 | while (ctx.remain_len > 0) { | |
| 245 | 172 | 6 | error = parse_mailmap_entry( | |
| 246 | - | &real_name, &real_email, &replace_name, &replace_email, &ctx); | ||
| 247 | 172 | 7 | if (error < 0) { | |
| 248 | 91 | 8 | error = 0; /* Skip lines which don't contain a valid entry */ | |
| 249 | 91 | 8 | git_parse_advance_line(&ctx); | |
| 250 | 91 | 9 | continue; /* TODO: warn */ | |
| 251 | - | } | ||
| 252 | - | |||
| 253 | - | /* NOTE: Can't use add_entry(...) as our buffers aren't terminated */ | ||
| 254 | 81 | 10,10,10,10,10 | error = mailmap_add_entry_unterminated( | |
| 255 | 81 | 10,10 | mm, real_name.ptr, real_name.size, real_email.ptr, real_email.size, | |
| 256 | 81 | 10,10 | replace_name.ptr, replace_name.size, replace_email.ptr, replace_email.size); | |
| 257 | 81 | 11 | if (error < 0) | |
| 258 | ##### | 12 | goto cleanup; | |
| 259 | - | |||
| 260 | 81 | 13 | error = 0; | |
| 261 | - | } | ||
| 262 | - | |||
| 263 | - | cleanup: | ||
| 264 | 15 | 15 | git_buf_dispose(&real_name); | |
| 265 | 15 | 16 | git_buf_dispose(&real_email); | |
| 266 | 15 | 17 | git_buf_dispose(&replace_name); | |
| 267 | 15 | 18 | git_buf_dispose(&replace_email); | |
| 268 | 15 | 19 | return error; | |
| 269 | - | } | ||
| 270 | - | |||
| 271 | 7 | 2 | int git_mailmap_from_buffer(git_mailmap **out, const char *data, size_t len) | |
| 272 | - | { | ||
| 273 | 7 | 2 | int error = git_mailmap_new(out); | |
| 274 | 7 | 3 | if (error < 0) | |
| 275 | ##### | 4 | return error; | |
| 276 | - | |||
| 277 | 7 | 5 | error = mailmap_add_buffer(*out, data, len); | |
| 278 | 7 | 6 | if (error < 0) { | |
| 279 | ##### | 7 | git_mailmap_free(*out); | |
| 280 | ##### | 8 | *out = NULL; | |
| 281 | - | } | ||
| 282 | 7 | 9 | return error; | |
| 283 | - | } | ||
| 284 | - | |||
| 285 | ![]() |
3 | 2 | static int mailmap_add_blob( |
| 286 | - | git_mailmap *mm, git_repository *repo, const char *rev) | ||
| 287 | - | { | ||
| 288 | 3 | 2 | git_object *object = NULL; | |
| 289 | 3 | 2 | git_blob *blob = NULL; | |
| 290 | 3 | 2 | git_buf content = GIT_BUF_INIT; | |
| 291 | - | int error; | ||
| 292 | - | |||
| 293 | 3 | 2-4 | assert(mm && repo); | |
| 294 | - | |||
| 295 | 3 | 5 | error = git_revparse_single(&object, repo, rev); | |
| 296 | 3 | 6 | if (error < 0) | |
| 297 | ##### | 7 | goto cleanup; | |
| 298 | - | |||
| 299 | 3 | 8 | error = git_object_peel((git_object **)&blob, object, GIT_OBJECT_BLOB); | |
| 300 | 3 | 9 | if (error < 0) | |
| 301 | ##### | 10 | goto cleanup; | |
| 302 | - | |||
| 303 | 3 | 11 | error = git_blob__getbuf(&content, blob); | |
| 304 | 3 | 12 | if (error < 0) | |
| 305 | ##### | 13 | goto cleanup; | |
| 306 | - | |||
| 307 | 3 | 14 | error = mailmap_add_buffer(mm, content.ptr, content.size); | |
| 308 | 3 | 15 | if (error < 0) | |
| 309 | ##### | 16 | goto cleanup; | |
| 310 | - | |||
| 311 | - | cleanup: | ||
| 312 | 3 | 17 | git_buf_dispose(&content); | |
| 313 | 3 | 18 | git_blob_free(blob); | |
| 314 | 3 | 19 | git_object_free(object); | |
| 315 | 3 | 20 | return error; | |
| 316 | - | } | ||
| 317 | - | |||
| 318 | ![]() |
5 | 2 | static int mailmap_add_file_ondisk( |
| 319 | - | git_mailmap *mm, const char *path, git_repository *repo) | ||
| 320 | - | { | ||
| 321 | 5 | 2-4 | const char *base = repo ? git_repository_workdir(repo) : NULL; | |
| 322 | 5 | 5 | git_buf fullpath = GIT_BUF_INIT; | |
| 323 | 5 | 5 | git_buf content = GIT_BUF_INIT; | |
| 324 | - | int error; | ||
| 325 | - | |||
| 326 | 5 | 5 | error = git_path_join_unrooted(&fullpath, path, base, NULL); | |
| 327 | 5 | 6 | if (error < 0) | |
| 328 | ##### | 7 | goto cleanup; | |
| 329 | - | |||
| 330 | 5 | 8 | error = git_futils_readbuffer(&content, fullpath.ptr); | |
| 331 | 5 | 9 | if (error < 0) | |
| 332 | ##### | 10 | goto cleanup; | |
| 333 | - | |||
| 334 | 5 | 11 | error = mailmap_add_buffer(mm, content.ptr, content.size); | |
| 335 | 5 | 12 | if (error < 0) | |
| 336 | ##### | 13 | goto cleanup; | |
| 337 | - | |||
| 338 | - | cleanup: | ||
| 339 | 5 | 14 | git_buf_dispose(&fullpath); | |
| 340 | 5 | 15 | git_buf_dispose(&content); | |
| 341 | 5 | 16 | return error; | |
| 342 | - | } | ||
| 343 | - | |||
| 344 | - | /* NOTE: Only expose with an error return, currently never errors */ | ||
| 345 | ![]() |
6 | 2 | static void mailmap_add_from_repository(git_mailmap *mm, git_repository *repo) |
| 346 | - | { | ||
| 347 | 6 | 2 | git_config *config = NULL; | |
| 348 | 6 | 2 | git_buf rev_buf = GIT_BUF_INIT; | |
| 349 | 6 | 2 | git_buf path_buf = GIT_BUF_INIT; | |
| 350 | 6 | 2 | const char *rev = NULL; | |
| 351 | 6 | 2 | const char *path = NULL; | |
| 352 | - | |||
| 353 | 6 | 2-4 | assert(mm && repo); | |
| 354 | - | |||
| 355 | - | /* If we're in a bare repo, default blob to 'HEAD:.mailmap' */ | ||
| 356 | 6 | 5 | if (repo->is_bare) | |
| 357 | 2 | 6 | rev = MM_BLOB_DEFAULT; | |
| 358 | - | |||
| 359 | - | /* Try to load 'mailmap.file' and 'mailmap.blob' cfgs from the repo */ | ||
| 360 | 6 | 7,8 | if (git_repository_config(&config, repo) == 0) { | |
| 361 | 6 | 9,10 | if (git_config_get_string_buf(&rev_buf, config, MM_BLOB_CONFIG) == 0) | |
| 362 | 2 | 11 | rev = rev_buf.ptr; | |
| 363 | 6 | 12,13 | if (git_config_get_path(&path_buf, config, MM_FILE_CONFIG) == 0) | |
| 364 | 1 | 14 | path = path_buf.ptr; | |
| 365 | - | } | ||
| 366 | - | |||
| 367 | - | /* | ||
| 368 | - | * Load mailmap files in order, overriding previous entries with new ones. | ||
| 369 | - | * 1. The '.mailmap' file in the repository's workdir root, | ||
| 370 | - | * 2. The blob described by the 'mailmap.blob' config (default HEAD:.mailmap), | ||
| 371 | - | * 3. The file described by the 'mailmap.file' config. | ||
| 372 | - | * | ||
| 373 | - | * We ignore errors from these loads, as these files may not exist, or may | ||
| 374 | - | * contain invalid information, and we don't want to report that error. | ||
| 375 | - | * | ||
| 376 | - | * XXX: Warn? | ||
| 377 | - | */ | ||
| 378 | 6 | 15 | if (!repo->is_bare) | |
| 379 | 4 | 16 | mailmap_add_file_ondisk(mm, MM_FILE, repo); | |
| 380 | 6 | 17 | if (rev != NULL) | |
| 381 | 3 | 18 | mailmap_add_blob(mm, repo, rev); | |
| 382 | 6 | 19 | if (path != NULL) | |
| 383 | 1 | 20 | mailmap_add_file_ondisk(mm, path, repo); | |
| 384 | - | |||
| 385 | 6 | 21 | git_buf_dispose(&rev_buf); | |
| 386 | 6 | 22 | git_buf_dispose(&path_buf); | |
| 387 | 6 | 23 | git_config_free(config); | |
| 388 | 6 | 24 | } | |
| 389 | - | |||
| 390 | 6 | 2 | int git_mailmap_from_repository(git_mailmap **out, git_repository *repo) | |
| 391 | - | { | ||
| 392 | 6 | 2 | int error = git_mailmap_new(out); | |
| 393 | 6 | 3 | if (error < 0) | |
| 394 | ##### | 4 | return error; | |
| 395 | 6 | 5 | mailmap_add_from_repository(*out, repo); | |
| 396 | 6 | 6 | return 0; | |
| 397 | - | } | ||
| 398 | - | |||
| 399 | ![]() |
290 | 2 | const git_mailmap_entry *git_mailmap_entry_lookup( |
| 400 | - | const git_mailmap *mm, const char *name, const char *email) | ||
| 401 | - | { | ||
| 402 | - | int error; | ||
| 403 | 290 | 2 | ssize_t fallback = -1; | |
| 404 | - | size_t idx; | ||
| 405 | - | git_mailmap_entry *entry; | ||
| 406 | - | |||
| 407 | - | /* The lookup needle we want to use only sets the replace_email. */ | ||
| 408 | 290 | 2 | git_mailmap_entry needle = { NULL }; | |
| 409 | 290 | 2 | needle.replace_email = (char *)email; | |
| 410 | - | |||
| 411 | 290 | 2,3 | assert(email); | |
| 412 | - | |||
| 413 | 290 | 4 | if (!mm) | |
| 414 | 163 | 5 | return NULL; | |
| 415 | - | |||
| 416 | - | /* | ||
| 417 | - | * We want to find the place to start looking. so we do a binary search for | ||
| 418 | - | * the "fallback" nameless entry. If we find it, we advance past it and record | ||
| 419 | - | * the index. | ||
| 420 | - | */ | ||
| 421 | 127 | 6 | error = git_vector_bsearch(&idx, (git_vector *)&mm->entries, &needle); | |
| 422 | 127 | 7 | if (error >= 0) | |
| 423 | 66 | 8 | fallback = idx++; | |
| 424 | 61 | 9 | else if (error != GIT_ENOTFOUND) | |
| 425 | ##### | 10 | return NULL; | |
| 426 | - | |||
| 427 | - | /* do a linear search for an exact match */ | ||
| 428 | 182 | 11,20-22 | for (; idx < git_vector_length(&mm->entries); ++idx) { | |
| 429 | 171 | 12 | entry = git_vector_get(&mm->entries, idx); | |
| 430 | - | |||
| 431 | 171 | 13 | if (git__strcmp(entry->replace_email, email)) | |
| 432 | 81 | 14 | break; /* it's a different email, so we're done looking */ | |
| 433 | - | |||
| 434 | 90 | 15,16 | assert(entry->replace_name); /* should be specific */ | |
| 435 | 90 | 17,18 | if (!name || !git__strcmp(entry->replace_name, name)) | |
| 436 | 35 | 19 | return entry; | |
| 437 | - | } | ||
| 438 | - | |||
| 439 | 92 | 23 | if (fallback < 0) | |
| 440 | 26 | 24 | return NULL; /* no fallback */ | |
| 441 | 66 | 25 | return git_vector_get(&mm->entries, fallback); | |
| 442 | - | } | ||
| 443 | - | |||
| 444 | ![]() |
253 | 2 | int git_mailmap_resolve( |
| 445 | - | const char **real_name, const char **real_email, | ||
| 446 | - | const git_mailmap *mailmap, | ||
| 447 | - | const char *name, const char *email) | ||
| 448 | - | { | ||
| 449 | 253 | 2 | const git_mailmap_entry *entry = NULL; | |
| 450 | 253 | 2-4 | assert(name && email); | |
| 451 | - | |||
| 452 | 253 | 5 | *real_name = name; | |
| 453 | 253 | 5 | *real_email = email; | |
| 454 | - | |||
| 455 | 253 | 5,6 | if ((entry = git_mailmap_entry_lookup(mailmap, name, email))) { | |
| 456 | 65 | 7 | if (entry->real_name) | |
| 457 | 42 | 8 | *real_name = entry->real_name; | |
| 458 | 65 | 9 | if (entry->real_email) | |
| 459 | 51 | 10 | *real_email = entry->real_email; | |
| 460 | - | } | ||
| 461 | 253 | 11 | return 0; | |
| 462 | - | } | ||
| 463 | - | |||
| 464 | 173 | 2 | int git_mailmap_resolve_signature( | |
| 465 | - | git_signature **out, const git_mailmap *mailmap, const git_signature *sig) | ||
| 466 | - | { | ||
| 467 | 173 | 2 | const char *name = NULL; | |
| 468 | 173 | 2 | const char *email = NULL; | |
| 469 | - | int error; | ||
| 470 | - | |||
| 471 | 173 | 2 | if (!sig) | |
| 472 | ##### | 3 | return 0; | |
| 473 | - | |||
| 474 | 173 | 4 | error = git_mailmap_resolve(&name, &email, mailmap, sig->name, sig->email); | |
| 475 | 173 | 5 | if (error < 0) | |
| 476 | ##### | 6 | return error; | |
| 477 | - | |||
| 478 | 173 | 7 | error = git_signature_new(out, name, email, sig->when.time, sig->when.offset); | |
| 479 | 173 | 8 | if (error < 0) | |
| 480 | ##### | 9 | return error; | |
| 481 | - | |||
| 482 | - | /* Copy over the sign, as git_signature_new doesn't let you pass it. */ | ||
| 483 | 173 | 10 | (*out)->when.sign = sig->when.sign; | |
| 484 | 173 | 10 | return 0; | |
| 485 | - | } |