Coverage Report

Created: 2025-12-31 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/git/ident.c
Line
Count
Source
1
/*
2
 * ident.c
3
 *
4
 * create git identifier lines of the form "name <email> date"
5
 *
6
 * Copyright (C) 2005 Linus Torvalds
7
 */
8
#include "git-compat-util.h"
9
#include "ident.h"
10
#include "config.h"
11
#include "date.h"
12
#include "gettext.h"
13
#include "mailmap.h"
14
#include "strbuf.h"
15
16
static struct strbuf git_default_name = STRBUF_INIT;
17
static struct strbuf git_default_email = STRBUF_INIT;
18
static struct strbuf git_default_date = STRBUF_INIT;
19
static struct strbuf git_author_name = STRBUF_INIT;
20
static struct strbuf git_author_email = STRBUF_INIT;
21
static struct strbuf git_committer_name = STRBUF_INIT;
22
static struct strbuf git_committer_email = STRBUF_INIT;
23
static int default_email_is_bogus;
24
static int default_name_is_bogus;
25
26
static int ident_use_config_only;
27
28
0
#define IDENT_NAME_GIVEN 01
29
0
#define IDENT_MAIL_GIVEN 02
30
#define IDENT_ALL_GIVEN (IDENT_NAME_GIVEN|IDENT_MAIL_GIVEN)
31
static int committer_ident_explicitly_given;
32
static int author_ident_explicitly_given;
33
static int ident_config_given;
34
35
#ifdef NO_GECOS_IN_PWENT
36
#define get_gecos(ignored) "&"
37
#else
38
0
#define get_gecos(struct_passwd) ((struct_passwd)->pw_gecos)
39
#endif
40
41
static struct passwd *xgetpwuid_self(int *is_bogus)
42
0
{
43
0
  struct passwd *pw;
44
45
0
  errno = 0;
46
0
  pw = getpwuid(getuid());
47
0
  if (!pw) {
48
0
    static struct passwd fallback;
49
0
    fallback.pw_name = (char *) "unknown";
50
0
#ifndef NO_GECOS_IN_PWENT
51
0
    fallback.pw_gecos = (char *) "Unknown";
52
0
#endif
53
0
    pw = &fallback;
54
0
    if (is_bogus)
55
0
      *is_bogus = 1;
56
0
  }
57
0
  return pw;
58
0
}
59
60
static void copy_gecos(const struct passwd *w, struct strbuf *name)
61
0
{
62
0
  const char *src;
63
64
  /* Traditionally GECOS field had office phone numbers etc, separated
65
   * with commas.  Also & stands for capitalized form of the login name.
66
   */
67
68
0
  for (src = get_gecos(w); *src && *src != ','; src++) {
69
0
    int ch = *src;
70
0
    if (ch != '&')
71
0
      strbuf_addch(name, ch);
72
0
    else {
73
      /* Sorry, Mr. McDonald... */
74
0
      strbuf_addch(name, toupper(*w->pw_name));
75
0
      strbuf_addstr(name, w->pw_name + 1);
76
0
    }
77
0
  }
78
0
}
79
80
static int add_mailname_host(struct strbuf *buf)
81
0
{
82
0
  FILE *mailname;
83
0
  struct strbuf mailnamebuf = STRBUF_INIT;
84
85
0
  mailname = fopen_or_warn("/etc/mailname", "r");
86
0
  if (!mailname)
87
0
    return -1;
88
89
0
  if (strbuf_getline(&mailnamebuf, mailname) == EOF) {
90
0
    if (ferror(mailname))
91
0
      warning_errno("cannot read /etc/mailname");
92
0
    strbuf_release(&mailnamebuf);
93
0
    fclose(mailname);
94
0
    return -1;
95
0
  }
96
  /* success! */
97
0
  strbuf_addbuf(buf, &mailnamebuf);
98
0
  strbuf_release(&mailnamebuf);
99
0
  fclose(mailname);
100
0
  return 0;
101
0
}
102
103
static int canonical_name(const char *host, struct strbuf *out)
104
0
{
105
0
  int status = -1;
106
107
0
#ifndef NO_IPV6
108
0
  struct addrinfo hints, *ai;
109
0
  memset (&hints, '\0', sizeof (hints));
110
0
  hints.ai_flags = AI_CANONNAME;
111
0
  if (!getaddrinfo(host, NULL, &hints, &ai)) {
112
0
    if (ai && ai->ai_canonname && strchr(ai->ai_canonname, '.')) {
113
0
      strbuf_addstr(out, ai->ai_canonname);
114
0
      status = 0;
115
0
    }
116
0
    freeaddrinfo(ai);
117
0
  }
118
#else
119
  struct hostent *he = gethostbyname(host);
120
  if (he && strchr(he->h_name, '.')) {
121
    strbuf_addstr(out, he->h_name);
122
    status = 0;
123
  }
124
#endif /* NO_IPV6 */
125
126
0
  return status;
127
0
}
128
129
static void add_domainname(struct strbuf *out, int *is_bogus)
130
0
{
131
0
  char buf[HOST_NAME_MAX + 1];
132
133
0
  if (xgethostname(buf, sizeof(buf))) {
134
0
    warning_errno("cannot get host name");
135
0
    strbuf_addstr(out, "(none)");
136
0
    *is_bogus = 1;
137
0
    return;
138
0
  }
139
0
  if (strchr(buf, '.'))
140
0
    strbuf_addstr(out, buf);
141
0
  else if (canonical_name(buf, out) < 0) {
142
0
    strbuf_addf(out, "%s.(none)", buf);
143
0
    *is_bogus = 1;
144
0
  }
145
0
}
146
147
static void copy_email(const struct passwd *pw, struct strbuf *email,
148
           int *is_bogus)
149
0
{
150
  /*
151
   * Make up a fake email address
152
   * (name + '@' + hostname [+ '.' + domainname])
153
   */
154
0
  strbuf_addstr(email, pw->pw_name);
155
0
  strbuf_addch(email, '@');
156
157
0
  if (!add_mailname_host(email))
158
0
    return; /* read from "/etc/mailname" (Debian) */
159
0
  add_domainname(email, is_bogus);
160
0
}
161
162
const char *ident_default_name(void)
163
0
{
164
0
  if (!(ident_config_given & IDENT_NAME_GIVEN) && !git_default_name.len) {
165
0
    copy_gecos(xgetpwuid_self(&default_name_is_bogus), &git_default_name);
166
0
    strbuf_trim(&git_default_name);
167
0
  }
168
0
  return git_default_name.buf;
169
0
}
170
171
const char *ident_default_email(void)
172
0
{
173
0
  if (!(ident_config_given & IDENT_MAIL_GIVEN) && !git_default_email.len) {
174
0
    const char *email = getenv("EMAIL");
175
176
0
    if (email && email[0]) {
177
0
      strbuf_addstr(&git_default_email, email);
178
0
      committer_ident_explicitly_given |= IDENT_MAIL_GIVEN;
179
0
      author_ident_explicitly_given |= IDENT_MAIL_GIVEN;
180
0
    } else if ((email = query_user_email()) && email[0]) {
181
0
      strbuf_addstr(&git_default_email, email);
182
0
      free((char *)email);
183
0
    } else
184
0
      copy_email(xgetpwuid_self(&default_email_is_bogus),
185
0
           &git_default_email, &default_email_is_bogus);
186
0
    strbuf_trim(&git_default_email);
187
0
  }
188
0
  return git_default_email.buf;
189
0
}
190
191
static const char *ident_default_date(void)
192
0
{
193
0
  if (!git_default_date.len)
194
0
    datestamp(&git_default_date);
195
0
  return git_default_date.buf;
196
0
}
197
198
void reset_ident_date(void)
199
0
{
200
0
  strbuf_reset(&git_default_date);
201
0
}
202
203
static int crud(unsigned char c)
204
0
{
205
0
  return  c <= 32  ||
206
0
    c == ',' ||
207
0
    c == ':' ||
208
0
    c == ';' ||
209
0
    c == '<' ||
210
0
    c == '>' ||
211
0
    c == '"' ||
212
0
    c == '\\' ||
213
0
    c == '\'';
214
0
}
215
216
static int has_non_crud(const char *str)
217
0
{
218
0
  for (; *str; str++) {
219
0
    if (!crud(*str))
220
0
      return 1;
221
0
  }
222
0
  return 0;
223
0
}
224
225
/*
226
 * Copy over a string to the destination, but avoid special
227
 * characters ('\n', '<' and '>') and remove crud at the end
228
 */
229
static void strbuf_addstr_without_crud(struct strbuf *sb, const char *src)
230
0
{
231
0
  size_t i, len;
232
0
  unsigned char c;
233
234
  /* Remove crud from the beginning.. */
235
0
  while ((c = *src) != 0) {
236
0
    if (!crud(c))
237
0
      break;
238
0
    src++;
239
0
  }
240
241
  /* Remove crud from the end.. */
242
0
  len = strlen(src);
243
0
  while (len > 0) {
244
0
    c = src[len-1];
245
0
    if (!crud(c))
246
0
      break;
247
0
    --len;
248
0
  }
249
250
  /*
251
   * Copy the rest to the buffer, but avoid the special
252
   * characters '\n' '<' and '>' that act as delimiters on
253
   * an identification line. We can only remove crud, never add it,
254
   * so 'len' is our maximum.
255
   */
256
0
  strbuf_grow(sb, len);
257
0
  for (i = 0; i < len; i++) {
258
0
    c = *src++;
259
0
    switch (c) {
260
0
    case '\n': case '<': case '>':
261
0
      continue;
262
0
    }
263
0
    sb->buf[sb->len++] = c;
264
0
  }
265
0
  sb->buf[sb->len] = '\0';
266
0
}
267
268
/*
269
 * Reverse of fmt_ident(); given an ident line, split the fields
270
 * to allow the caller to parse it.
271
 * Signal a success by returning 0, but date/tz fields of the result
272
 * can still be NULL if the input line only has the name/email part
273
 * (e.g. reading from a reflog entry).
274
 */
275
int split_ident_line(struct ident_split *split, const char *line, size_t len)
276
0
{
277
0
  const char *cp;
278
0
  size_t span;
279
0
  int status = -1;
280
281
0
  memset(split, 0, sizeof(*split));
282
283
0
  split->name_begin = line;
284
0
  for (cp = line; *cp && cp < line + len; cp++)
285
0
    if (*cp == '<') {
286
0
      split->mail_begin = cp + 1;
287
0
      break;
288
0
    }
289
0
  if (!split->mail_begin)
290
0
    return status;
291
292
0
  for (cp = split->mail_begin - 2; line <= cp; cp--)
293
0
    if (!isspace(*cp)) {
294
0
      split->name_end = cp + 1;
295
0
      break;
296
0
    }
297
0
  if (!split->name_end) {
298
    /* no human readable name */
299
0
    split->name_end = split->name_begin;
300
0
  }
301
302
0
  for (cp = split->mail_begin; cp < line + len; cp++)
303
0
    if (*cp == '>') {
304
0
      split->mail_end = cp;
305
0
      break;
306
0
    }
307
0
  if (!split->mail_end)
308
0
    return status;
309
310
  /*
311
   * Look from the end-of-line to find the trailing ">" of the mail
312
   * address, even though we should already know it as split->mail_end.
313
   * This can help in cases of broken idents with an extra ">" somewhere
314
   * in the email address.  Note that we are assuming the timestamp will
315
   * never have a ">" in it.
316
   *
317
   * Note that we will always find some ">" before going off the front of
318
   * the string, because will always hit the split->mail_end closing
319
   * bracket.
320
   */
321
0
  for (cp = line + len - 1; *cp != '>'; cp--)
322
0
    ;
323
324
0
  for (cp = cp + 1; cp < line + len && isspace(*cp); cp++)
325
0
    ;
326
0
  if (line + len <= cp)
327
0
    goto person_only;
328
0
  split->date_begin = cp;
329
0
  span = strspn(cp, "0123456789");
330
0
  if (!span)
331
0
    goto person_only;
332
0
  split->date_end = split->date_begin + span;
333
0
  for (cp = split->date_end; cp < line + len && isspace(*cp); cp++)
334
0
    ;
335
0
  if (line + len <= cp || (*cp != '+' && *cp != '-'))
336
0
    goto person_only;
337
0
  split->tz_begin = cp;
338
0
  span = strspn(cp + 1, "0123456789");
339
0
  if (!span)
340
0
    goto person_only;
341
0
  split->tz_end = split->tz_begin + 1 + span;
342
0
  return 0;
343
344
0
person_only:
345
0
  split->date_begin = NULL;
346
0
  split->date_end = NULL;
347
0
  split->tz_begin = NULL;
348
0
  split->tz_end = NULL;
349
0
  return 0;
350
0
}
351
352
/*
353
 * Returns the difference between the new and old length of the ident line.
354
 */
355
static ssize_t rewrite_ident_line(const char *person, size_t len,
356
           struct strbuf *buf,
357
           struct string_list *mailmap)
358
0
{
359
0
  size_t namelen, maillen;
360
0
  const char *name;
361
0
  const char *mail;
362
0
  struct ident_split ident;
363
364
0
  if (split_ident_line(&ident, person, len))
365
0
    return 0;
366
367
0
  mail = ident.mail_begin;
368
0
  maillen = ident.mail_end - ident.mail_begin;
369
0
  name = ident.name_begin;
370
0
  namelen = ident.name_end - ident.name_begin;
371
372
0
  if (map_user(mailmap, &mail, &maillen, &name, &namelen)) {
373
0
    struct strbuf namemail = STRBUF_INIT;
374
0
    size_t newlen;
375
376
0
    strbuf_addf(&namemail, "%.*s <%.*s>",
377
0
          (int)namelen, name, (int)maillen, mail);
378
379
0
    strbuf_splice(buf, ident.name_begin - buf->buf,
380
0
            ident.mail_end - ident.name_begin + 1,
381
0
            namemail.buf, namemail.len);
382
0
    newlen = namemail.len;
383
384
0
    strbuf_release(&namemail);
385
386
0
    return newlen - (ident.mail_end - ident.name_begin);
387
0
  }
388
389
0
  return 0;
390
0
}
391
392
void apply_mailmap_to_header(struct strbuf *buf, const char **header,
393
             struct string_list *mailmap)
394
0
{
395
0
  size_t buf_offset = 0;
396
397
0
  if (!mailmap)
398
0
    return;
399
400
0
  for (;;) {
401
0
    const char *person, *line;
402
0
    size_t i;
403
0
    int found_header = 0;
404
405
0
    line = buf->buf + buf_offset;
406
0
    if (!*line || *line == '\n')
407
0
      return; /* End of headers */
408
409
0
    for (i = 0; header[i]; i++)
410
0
      if (skip_prefix(line, header[i], &person)) {
411
0
        const char *endp = strchrnul(person, '\n');
412
0
        found_header = 1;
413
0
        buf_offset += endp - line;
414
0
        buf_offset += rewrite_ident_line(person, endp - person, buf, mailmap);
415
        /* Recompute endp after potential buffer reallocation */
416
0
        endp = buf->buf + buf_offset;
417
0
        if (*endp == '\n')
418
0
          buf_offset++;
419
0
        break;
420
0
      }
421
422
0
    if (!found_header) {
423
0
      buf_offset = strchrnul(line, '\n') - buf->buf;
424
0
      if (buf->buf[buf_offset] == '\n')
425
0
        buf_offset++;
426
0
    }
427
0
  }
428
0
}
429
430
static void ident_env_hint(enum want_ident whose_ident)
431
0
{
432
0
  switch (whose_ident) {
433
0
  case WANT_AUTHOR_IDENT:
434
0
    fputs(_("Author identity unknown\n"), stderr);
435
0
    break;
436
0
  case WANT_COMMITTER_IDENT:
437
0
    fputs(_("Committer identity unknown\n"), stderr);
438
0
    break;
439
0
  default:
440
0
    break;
441
0
  }
442
443
0
  fputs(_("\n"
444
0
    "*** Please tell me who you are.\n"
445
0
    "\n"
446
0
    "Run\n"
447
0
    "\n"
448
0
    "  git config --global user.email \"you@example.com\"\n"
449
0
    "  git config --global user.name \"Your Name\"\n"
450
0
    "\n"
451
0
    "to set your account\'s default identity.\n"
452
0
    "Omit --global to set the identity only in this repository.\n"
453
0
    "\n"), stderr);
454
0
}
455
456
const char *fmt_ident(const char *name, const char *email,
457
          enum want_ident whose_ident, const char *date_str, int flag)
458
0
{
459
0
  static int index;
460
0
  static struct strbuf ident_pool[2] = { STRBUF_INIT, STRBUF_INIT };
461
0
  int strict = (flag & IDENT_STRICT);
462
0
  int want_date = !(flag & IDENT_NO_DATE);
463
0
  int want_name = !(flag & IDENT_NO_NAME);
464
465
0
  struct strbuf *ident = &ident_pool[index];
466
0
  index = (index + 1) % ARRAY_SIZE(ident_pool);
467
468
0
  if (!email) {
469
0
    if (whose_ident == WANT_AUTHOR_IDENT && git_author_email.len)
470
0
      email = git_author_email.buf;
471
0
    else if (whose_ident == WANT_COMMITTER_IDENT && git_committer_email.len)
472
0
      email = git_committer_email.buf;
473
0
  }
474
0
  if (!email) {
475
0
    if (strict && ident_use_config_only
476
0
        && !(ident_config_given & IDENT_MAIL_GIVEN)) {
477
0
      ident_env_hint(whose_ident);
478
0
      die(_("no email was given and auto-detection is disabled"));
479
0
    }
480
0
    email = ident_default_email();
481
0
    if (strict && default_email_is_bogus) {
482
0
      ident_env_hint(whose_ident);
483
0
      die(_("unable to auto-detect email address (got '%s')"), email);
484
0
    }
485
0
  }
486
487
0
  if (want_name) {
488
0
    int using_default = 0;
489
0
    if (!name) {
490
0
      if (whose_ident == WANT_AUTHOR_IDENT && git_author_name.len)
491
0
        name = git_author_name.buf;
492
0
      else if (whose_ident == WANT_COMMITTER_IDENT &&
493
0
          git_committer_name.len)
494
0
        name = git_committer_name.buf;
495
0
    }
496
0
    if (!name) {
497
0
      if (strict && ident_use_config_only
498
0
          && !(ident_config_given & IDENT_NAME_GIVEN)) {
499
0
        ident_env_hint(whose_ident);
500
0
        die(_("no name was given and auto-detection is disabled"));
501
0
      }
502
0
      name = ident_default_name();
503
0
      using_default = 1;
504
0
      if (strict && default_name_is_bogus) {
505
0
        ident_env_hint(whose_ident);
506
0
        die(_("unable to auto-detect name (got '%s')"), name);
507
0
      }
508
0
    }
509
0
    if (!*name) {
510
0
      struct passwd *pw;
511
0
      if (strict) {
512
0
        if (using_default)
513
0
          ident_env_hint(whose_ident);
514
0
        die(_("empty ident name (for <%s>) not allowed"), email);
515
0
      }
516
0
      pw = xgetpwuid_self(NULL);
517
0
      name = pw->pw_name;
518
0
    }
519
0
    if (strict && !has_non_crud(name))
520
0
      die(_("name consists only of disallowed characters: %s"), name);
521
0
  }
522
523
0
  strbuf_reset(ident);
524
0
  if (want_name) {
525
0
    strbuf_addstr_without_crud(ident, name);
526
0
    strbuf_addstr(ident, " <");
527
0
  }
528
0
  strbuf_addstr_without_crud(ident, email);
529
0
  if (want_name)
530
0
    strbuf_addch(ident, '>');
531
0
  if (want_date) {
532
0
    strbuf_addch(ident, ' ');
533
0
    if (date_str && date_str[0]) {
534
0
      if (parse_date(date_str, ident) < 0)
535
0
        die(_("invalid date format: %s"), date_str);
536
0
    }
537
0
    else
538
0
      strbuf_addstr(ident, ident_default_date());
539
0
  }
540
541
0
  return ident->buf;
542
0
}
543
544
const char *fmt_name(enum want_ident whose_ident)
545
0
{
546
0
  char *name = NULL;
547
0
  char *email = NULL;
548
549
0
  switch (whose_ident) {
550
0
  case WANT_BLANK_IDENT:
551
0
    break;
552
0
  case WANT_AUTHOR_IDENT:
553
0
    name = getenv("GIT_AUTHOR_NAME");
554
0
    email = getenv("GIT_AUTHOR_EMAIL");
555
0
    break;
556
0
  case WANT_COMMITTER_IDENT:
557
0
    name = getenv("GIT_COMMITTER_NAME");
558
0
    email = getenv("GIT_COMMITTER_EMAIL");
559
0
    break;
560
0
  }
561
0
  return fmt_ident(name, email, whose_ident, NULL,
562
0
      IDENT_STRICT | IDENT_NO_DATE);
563
0
}
564
565
const char *git_author_info(int flag)
566
0
{
567
0
  if (getenv("GIT_AUTHOR_NAME"))
568
0
    author_ident_explicitly_given |= IDENT_NAME_GIVEN;
569
0
  if (getenv("GIT_AUTHOR_EMAIL"))
570
0
    author_ident_explicitly_given |= IDENT_MAIL_GIVEN;
571
0
  return fmt_ident(getenv("GIT_AUTHOR_NAME"),
572
0
       getenv("GIT_AUTHOR_EMAIL"),
573
0
       WANT_AUTHOR_IDENT,
574
0
       getenv("GIT_AUTHOR_DATE"),
575
0
       flag);
576
0
}
577
578
const char *git_committer_info(int flag)
579
0
{
580
0
  if (getenv("GIT_COMMITTER_NAME"))
581
0
    committer_ident_explicitly_given |= IDENT_NAME_GIVEN;
582
0
  if (getenv("GIT_COMMITTER_EMAIL"))
583
0
    committer_ident_explicitly_given |= IDENT_MAIL_GIVEN;
584
0
  return fmt_ident(getenv("GIT_COMMITTER_NAME"),
585
0
       getenv("GIT_COMMITTER_EMAIL"),
586
0
       WANT_COMMITTER_IDENT,
587
0
       getenv("GIT_COMMITTER_DATE"),
588
0
       flag);
589
0
}
590
591
static int ident_is_sufficient(int user_ident_explicitly_given)
592
0
{
593
0
#ifndef WINDOWS
594
0
  return (user_ident_explicitly_given & IDENT_MAIL_GIVEN);
595
#else
596
  return (user_ident_explicitly_given == IDENT_ALL_GIVEN);
597
#endif
598
0
}
599
600
int committer_ident_sufficiently_given(void)
601
0
{
602
0
  return ident_is_sufficient(committer_ident_explicitly_given);
603
0
}
604
605
int author_ident_sufficiently_given(void)
606
0
{
607
0
  return ident_is_sufficient(author_ident_explicitly_given);
608
0
}
609
610
static int set_ident(const char *var, const char *value)
611
0
{
612
0
  if (!strcmp(var, "author.name")) {
613
0
    if (!value)
614
0
      return config_error_nonbool(var);
615
0
    strbuf_reset(&git_author_name);
616
0
    strbuf_addstr(&git_author_name, value);
617
0
    author_ident_explicitly_given |= IDENT_NAME_GIVEN;
618
0
    ident_config_given |= IDENT_NAME_GIVEN;
619
0
    return 0;
620
0
  }
621
622
0
  if (!strcmp(var, "author.email")) {
623
0
    if (!value)
624
0
      return config_error_nonbool(var);
625
0
    strbuf_reset(&git_author_email);
626
0
    strbuf_addstr(&git_author_email, value);
627
0
    author_ident_explicitly_given |= IDENT_MAIL_GIVEN;
628
0
    ident_config_given |= IDENT_MAIL_GIVEN;
629
0
    return 0;
630
0
  }
631
632
0
  if (!strcmp(var, "committer.name")) {
633
0
    if (!value)
634
0
      return config_error_nonbool(var);
635
0
    strbuf_reset(&git_committer_name);
636
0
    strbuf_addstr(&git_committer_name, value);
637
0
    committer_ident_explicitly_given |= IDENT_NAME_GIVEN;
638
0
    ident_config_given |= IDENT_NAME_GIVEN;
639
0
    return 0;
640
0
  }
641
642
0
  if (!strcmp(var, "committer.email")) {
643
0
    if (!value)
644
0
      return config_error_nonbool(var);
645
0
    strbuf_reset(&git_committer_email);
646
0
    strbuf_addstr(&git_committer_email, value);
647
0
    committer_ident_explicitly_given |= IDENT_MAIL_GIVEN;
648
0
    ident_config_given |= IDENT_MAIL_GIVEN;
649
0
    return 0;
650
0
  }
651
652
0
  if (!strcmp(var, "user.name")) {
653
0
    if (!value)
654
0
      return config_error_nonbool(var);
655
0
    strbuf_reset(&git_default_name);
656
0
    strbuf_addstr(&git_default_name, value);
657
0
    committer_ident_explicitly_given |= IDENT_NAME_GIVEN;
658
0
    author_ident_explicitly_given |= IDENT_NAME_GIVEN;
659
0
    ident_config_given |= IDENT_NAME_GIVEN;
660
0
    return 0;
661
0
  }
662
663
0
  if (!strcmp(var, "user.email")) {
664
0
    if (!value)
665
0
      return config_error_nonbool(var);
666
0
    strbuf_reset(&git_default_email);
667
0
    strbuf_addstr(&git_default_email, value);
668
0
    committer_ident_explicitly_given |= IDENT_MAIL_GIVEN;
669
0
    author_ident_explicitly_given |= IDENT_MAIL_GIVEN;
670
0
    ident_config_given |= IDENT_MAIL_GIVEN;
671
0
    return 0;
672
0
  }
673
674
0
  return 0;
675
0
}
676
677
int git_ident_config(const char *var, const char *value,
678
         const struct config_context *ctx UNUSED,
679
         void *data UNUSED)
680
0
{
681
0
  if (!strcmp(var, "user.useconfigonly")) {
682
0
    ident_use_config_only = git_config_bool(var, value);
683
0
    return 0;
684
0
  }
685
686
0
  return set_ident(var, value);
687
0
}
688
689
static void set_env_if(const char *key, const char *value, int *given, int bit)
690
0
{
691
0
  if ((*given & bit) || getenv(key))
692
0
    return; /* nothing to do */
693
0
  setenv(key, value, 0);
694
0
  *given |= bit;
695
0
}
696
697
void prepare_fallback_ident(const char *name, const char *email)
698
0
{
699
0
  set_env_if("GIT_AUTHOR_NAME", name,
700
0
       &author_ident_explicitly_given, IDENT_NAME_GIVEN);
701
0
  set_env_if("GIT_AUTHOR_EMAIL", email,
702
0
       &author_ident_explicitly_given, IDENT_MAIL_GIVEN);
703
0
  set_env_if("GIT_COMMITTER_NAME", name,
704
0
       &committer_ident_explicitly_given, IDENT_NAME_GIVEN);
705
0
  set_env_if("GIT_COMMITTER_EMAIL", email,
706
0
       &committer_ident_explicitly_given, IDENT_MAIL_GIVEN);
707
0
}
708
709
static int buf_cmp(const char *a_begin, const char *a_end,
710
       const char *b_begin, const char *b_end)
711
0
{
712
0
  int a_len = a_end - a_begin;
713
0
  int b_len = b_end - b_begin;
714
0
  int min = a_len < b_len ? a_len : b_len;
715
0
  int cmp;
716
717
0
  cmp = memcmp(a_begin, b_begin, min);
718
0
  if (cmp)
719
0
    return cmp;
720
721
0
  return a_len - b_len;
722
0
}
723
724
int ident_cmp(const struct ident_split *a,
725
        const struct ident_split *b)
726
0
{
727
0
  int cmp;
728
729
0
  cmp = buf_cmp(a->mail_begin, a->mail_end,
730
0
          b->mail_begin, b->mail_end);
731
0
  if (cmp)
732
0
    return cmp;
733
734
0
  return buf_cmp(a->name_begin, a->name_end,
735
0
           b->name_begin, b->name_end);
736
0
}