4 * create git identifier lines of the form "name <email> date"
6 * Copyright (C) 2005 Linus Torvalds
10 static struct strbuf git_default_name
= STRBUF_INIT
;
11 static struct strbuf git_default_email
= STRBUF_INIT
;
12 static char git_default_date
[50];
14 #define IDENT_NAME_GIVEN 01
15 #define IDENT_MAIL_GIVEN 02
16 #define IDENT_ALL_GIVEN (IDENT_NAME_GIVEN|IDENT_MAIL_GIVEN)
17 static int committer_ident_explicitly_given
;
18 static int author_ident_explicitly_given
;
20 #ifdef NO_GECOS_IN_PWENT
21 #define get_gecos(ignored) "&"
23 #define get_gecos(struct_passwd) ((struct_passwd)->pw_gecos)
26 static void copy_gecos(const struct passwd
*w
, struct strbuf
*name
)
30 /* Traditionally GECOS field had office phone numbers etc, separated
31 * with commas. Also & stands for capitalized form of the login name.
34 for (src
= get_gecos(w
); *src
&& *src
!= ','; src
++) {
37 strbuf_addch(name
, ch
);
39 /* Sorry, Mr. McDonald... */
40 strbuf_addch(name
, toupper(*w
->pw_name
));
41 strbuf_addstr(name
, w
->pw_name
+ 1);
46 static int add_mailname_host(struct strbuf
*buf
)
49 struct strbuf mailnamebuf
= STRBUF_INIT
;
51 mailname
= fopen("/etc/mailname", "r");
54 warning("cannot open /etc/mailname: %s",
58 if (strbuf_getline(&mailnamebuf
, mailname
, '\n') == EOF
) {
60 warning("cannot read /etc/mailname: %s",
62 strbuf_release(&mailnamebuf
);
67 strbuf_addbuf(buf
, &mailnamebuf
);
68 strbuf_release(&mailnamebuf
);
73 static void add_domainname(struct strbuf
*out
)
78 if (gethostname(buf
, sizeof(buf
))) {
79 warning("cannot get host name: %s", strerror(errno
));
80 strbuf_addstr(out
, "(none)");
84 strbuf_addstr(out
, buf
);
85 else if ((he
= gethostbyname(buf
)) && strchr(he
->h_name
, '.'))
86 strbuf_addstr(out
, he
->h_name
);
88 strbuf_addf(out
, "%s.(none)", buf
);
91 static void copy_email(const struct passwd
*pw
, struct strbuf
*email
)
94 * Make up a fake email address
95 * (name + '@' + hostname [+ '.' + domainname])
97 strbuf_addstr(email
, pw
->pw_name
);
98 strbuf_addch(email
, '@');
100 if (!add_mailname_host(email
))
101 return; /* read from "/etc/mailname" (Debian) */
102 add_domainname(email
);
105 const char *ident_default_name(void)
107 if (!git_default_name
.len
) {
108 copy_gecos(xgetpwuid_self(), &git_default_name
);
109 strbuf_trim(&git_default_name
);
111 return git_default_name
.buf
;
114 const char *ident_default_email(void)
116 if (!git_default_email
.len
) {
117 const char *email
= getenv("EMAIL");
119 if (email
&& email
[0]) {
120 strbuf_addstr(&git_default_email
, email
);
121 committer_ident_explicitly_given
|= IDENT_MAIL_GIVEN
;
122 author_ident_explicitly_given
|= IDENT_MAIL_GIVEN
;
124 copy_email(xgetpwuid_self(), &git_default_email
);
125 strbuf_trim(&git_default_email
);
127 return git_default_email
.buf
;
130 static const char *ident_default_date(void)
132 if (!git_default_date
[0])
133 datestamp(git_default_date
, sizeof(git_default_date
));
134 return git_default_date
;
137 static int crud(unsigned char c
)
152 * Copy over a string to the destination, but avoid special
153 * characters ('\n', '<' and '>') and remove crud at the end
155 static void strbuf_addstr_without_crud(struct strbuf
*sb
, const char *src
)
160 /* Remove crud from the beginning.. */
161 while ((c
= *src
) != 0) {
167 /* Remove crud from the end.. */
177 * Copy the rest to the buffer, but avoid the special
178 * characters '\n' '<' and '>' that act as delimiters on
179 * an identification line. We can only remove crud, never add it,
180 * so 'len' is our maximum.
182 strbuf_grow(sb
, len
);
183 for (i
= 0; i
< len
; i
++) {
186 case '\n': case '<': case '>':
189 sb
->buf
[sb
->len
++] = c
;
191 sb
->buf
[sb
->len
] = '\0';
195 * Reverse of fmt_ident(); given an ident line, split the fields
196 * to allow the caller to parse it.
197 * Signal a success by returning 0, but date/tz fields of the result
198 * can still be NULL if the input line only has the name/email part
199 * (e.g. reading from a reflog entry).
201 int split_ident_line(struct ident_split
*split
, const char *line
, int len
)
207 memset(split
, 0, sizeof(*split
));
209 split
->name_begin
= line
;
210 for (cp
= line
; *cp
&& cp
< line
+ len
; cp
++)
212 split
->mail_begin
= cp
+ 1;
215 if (!split
->mail_begin
)
218 for (cp
= split
->mail_begin
- 2; line
<= cp
; cp
--)
220 split
->name_end
= cp
+ 1;
223 if (!split
->name_end
) {
224 /* no human readable name */
225 split
->name_end
= split
->name_begin
;
228 for (cp
= split
->mail_begin
; cp
< line
+ len
; cp
++)
230 split
->mail_end
= cp
;
233 if (!split
->mail_end
)
237 * Look from the end-of-line to find the trailing ">" of the mail
238 * address, even though we should already know it as split->mail_end.
239 * This can help in cases of broken idents with an extra ">" somewhere
240 * in the email address. Note that we are assuming the timestamp will
241 * never have a ">" in it.
243 * Note that we will always find some ">" before going off the front of
244 * the string, because will always hit the split->mail_end closing
247 for (cp
= line
+ len
- 1; *cp
!= '>'; cp
--)
250 for (cp
= cp
+ 1; cp
< line
+ len
&& isspace(*cp
); cp
++)
252 if (line
+ len
<= cp
)
254 split
->date_begin
= cp
;
255 span
= strspn(cp
, "0123456789");
258 split
->date_end
= split
->date_begin
+ span
;
259 for (cp
= split
->date_end
; cp
< line
+ len
&& isspace(*cp
); cp
++)
261 if (line
+ len
<= cp
|| (*cp
!= '+' && *cp
!= '-'))
263 split
->tz_begin
= cp
;
264 span
= strspn(cp
+ 1, "0123456789");
267 split
->tz_end
= split
->tz_begin
+ 1 + span
;
271 split
->date_begin
= NULL
;
272 split
->date_end
= NULL
;
273 split
->tz_begin
= NULL
;
274 split
->tz_end
= NULL
;
278 static const char *env_hint
=
280 "*** Please tell me who you are.\n"
284 " git config --global user.email \"you@example.com\"\n"
285 " git config --global user.name \"Your Name\"\n"
287 "to set your account\'s default identity.\n"
288 "Omit --global to set the identity only in this repository.\n"
291 const char *fmt_ident(const char *name
, const char *email
,
292 const char *date_str
, int flag
)
294 static struct strbuf ident
= STRBUF_INIT
;
296 int strict
= (flag
& IDENT_STRICT
);
297 int want_date
= !(flag
& IDENT_NO_DATE
);
298 int want_name
= !(flag
& IDENT_NO_NAME
);
300 if (want_name
&& !name
)
301 name
= ident_default_name();
303 email
= ident_default_email();
305 if (want_name
&& !*name
) {
309 if (name
== git_default_name
.buf
)
310 fputs(env_hint
, stderr
);
311 die("empty ident name (for <%s>) not allowed", email
);
313 pw
= xgetpwuid_self();
317 if (strict
&& email
== git_default_email
.buf
&&
318 strstr(email
, "(none)")) {
319 fputs(env_hint
, stderr
);
320 die("unable to auto-detect email address (got '%s')", email
);
324 if (date_str
&& date_str
[0]) {
325 if (parse_date(date_str
, date
, sizeof(date
)) < 0)
326 die("invalid date format: %s", date_str
);
329 strcpy(date
, ident_default_date());
332 strbuf_reset(&ident
);
334 strbuf_addstr_without_crud(&ident
, name
);
335 strbuf_addstr(&ident
, " <");
337 strbuf_addstr_without_crud(&ident
, email
);
339 strbuf_addch(&ident
, '>');
341 strbuf_addch(&ident
, ' ');
342 strbuf_addstr_without_crud(&ident
, date
);
347 const char *fmt_name(const char *name
, const char *email
)
349 return fmt_ident(name
, email
, NULL
, IDENT_STRICT
| IDENT_NO_DATE
);
352 const char *git_author_info(int flag
)
354 if (getenv("GIT_AUTHOR_NAME"))
355 author_ident_explicitly_given
|= IDENT_NAME_GIVEN
;
356 if (getenv("GIT_AUTHOR_EMAIL"))
357 author_ident_explicitly_given
|= IDENT_MAIL_GIVEN
;
358 return fmt_ident(getenv("GIT_AUTHOR_NAME"),
359 getenv("GIT_AUTHOR_EMAIL"),
360 getenv("GIT_AUTHOR_DATE"),
364 const char *git_committer_info(int flag
)
366 if (getenv("GIT_COMMITTER_NAME"))
367 committer_ident_explicitly_given
|= IDENT_NAME_GIVEN
;
368 if (getenv("GIT_COMMITTER_EMAIL"))
369 committer_ident_explicitly_given
|= IDENT_MAIL_GIVEN
;
370 return fmt_ident(getenv("GIT_COMMITTER_NAME"),
371 getenv("GIT_COMMITTER_EMAIL"),
372 getenv("GIT_COMMITTER_DATE"),
376 static int ident_is_sufficient(int user_ident_explicitly_given
)
379 return (user_ident_explicitly_given
& IDENT_MAIL_GIVEN
);
381 return (user_ident_explicitly_given
== IDENT_ALL_GIVEN
);
385 int committer_ident_sufficiently_given(void)
387 return ident_is_sufficient(committer_ident_explicitly_given
);
390 int author_ident_sufficiently_given(void)
392 return ident_is_sufficient(author_ident_explicitly_given
);
395 int git_ident_config(const char *var
, const char *value
, void *data
)
397 if (!strcmp(var
, "user.name")) {
399 return config_error_nonbool(var
);
400 strbuf_reset(&git_default_name
);
401 strbuf_addstr(&git_default_name
, value
);
402 committer_ident_explicitly_given
|= IDENT_NAME_GIVEN
;
403 author_ident_explicitly_given
|= IDENT_NAME_GIVEN
;
407 if (!strcmp(var
, "user.email")) {
409 return config_error_nonbool(var
);
410 strbuf_reset(&git_default_email
);
411 strbuf_addstr(&git_default_email
, value
);
412 committer_ident_explicitly_given
|= IDENT_MAIL_GIVEN
;
413 author_ident_explicitly_given
|= IDENT_MAIL_GIVEN
;
420 static int buf_cmp(const char *a_begin
, const char *a_end
,
421 const char *b_begin
, const char *b_end
)
423 int a_len
= a_end
- a_begin
;
424 int b_len
= b_end
- b_begin
;
425 int min
= a_len
< b_len
? a_len
: b_len
;
428 cmp
= memcmp(a_begin
, b_begin
, min
);
432 return a_len
- b_len
;
435 int ident_cmp(const struct ident_split
*a
,
436 const struct ident_split
*b
)
440 cmp
= buf_cmp(a
->mail_begin
, a
->mail_end
,
441 b
->mail_begin
, b
->mail_end
);
445 return buf_cmp(a
->name_begin
, a
->name_end
,
446 b
->name_begin
, b
->name_end
);