merge(third_party/git): Merge squashed git subtree at v2.23.0
Merge commit '1b593e1ea4' as 'third_party/git'
This commit is contained in:
commit
7ef0d62730
3629 changed files with 1139935 additions and 0 deletions
635
third_party/git/ident.c
vendored
Normal file
635
third_party/git/ident.c
vendored
Normal file
|
|
@ -0,0 +1,635 @@
|
|||
/*
|
||||
* ident.c
|
||||
*
|
||||
* create git identifier lines of the form "name <email> date"
|
||||
*
|
||||
* Copyright (C) 2005 Linus Torvalds
|
||||
*/
|
||||
#include "cache.h"
|
||||
#include "config.h"
|
||||
|
||||
static struct strbuf git_default_name = STRBUF_INIT;
|
||||
static struct strbuf git_default_email = STRBUF_INIT;
|
||||
static struct strbuf git_default_date = STRBUF_INIT;
|
||||
static struct strbuf git_author_name = STRBUF_INIT;
|
||||
static struct strbuf git_author_email = STRBUF_INIT;
|
||||
static struct strbuf git_committer_name = STRBUF_INIT;
|
||||
static struct strbuf git_committer_email = STRBUF_INIT;
|
||||
static int default_email_is_bogus;
|
||||
static int default_name_is_bogus;
|
||||
|
||||
static int ident_use_config_only;
|
||||
|
||||
#define IDENT_NAME_GIVEN 01
|
||||
#define IDENT_MAIL_GIVEN 02
|
||||
#define IDENT_ALL_GIVEN (IDENT_NAME_GIVEN|IDENT_MAIL_GIVEN)
|
||||
static int committer_ident_explicitly_given;
|
||||
static int author_ident_explicitly_given;
|
||||
static int ident_config_given;
|
||||
|
||||
#ifdef NO_GECOS_IN_PWENT
|
||||
#define get_gecos(ignored) "&"
|
||||
#else
|
||||
#define get_gecos(struct_passwd) ((struct_passwd)->pw_gecos)
|
||||
#endif
|
||||
|
||||
static struct passwd *xgetpwuid_self(int *is_bogus)
|
||||
{
|
||||
struct passwd *pw;
|
||||
|
||||
errno = 0;
|
||||
pw = getpwuid(getuid());
|
||||
if (!pw) {
|
||||
static struct passwd fallback;
|
||||
fallback.pw_name = "unknown";
|
||||
#ifndef NO_GECOS_IN_PWENT
|
||||
fallback.pw_gecos = "Unknown";
|
||||
#endif
|
||||
pw = &fallback;
|
||||
if (is_bogus)
|
||||
*is_bogus = 1;
|
||||
}
|
||||
return pw;
|
||||
}
|
||||
|
||||
static void copy_gecos(const struct passwd *w, struct strbuf *name)
|
||||
{
|
||||
char *src;
|
||||
|
||||
/* Traditionally GECOS field had office phone numbers etc, separated
|
||||
* with commas. Also & stands for capitalized form of the login name.
|
||||
*/
|
||||
|
||||
for (src = get_gecos(w); *src && *src != ','; src++) {
|
||||
int ch = *src;
|
||||
if (ch != '&')
|
||||
strbuf_addch(name, ch);
|
||||
else {
|
||||
/* Sorry, Mr. McDonald... */
|
||||
strbuf_addch(name, toupper(*w->pw_name));
|
||||
strbuf_addstr(name, w->pw_name + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int add_mailname_host(struct strbuf *buf)
|
||||
{
|
||||
FILE *mailname;
|
||||
struct strbuf mailnamebuf = STRBUF_INIT;
|
||||
|
||||
mailname = fopen_or_warn("/etc/mailname", "r");
|
||||
if (!mailname)
|
||||
return -1;
|
||||
|
||||
if (strbuf_getline(&mailnamebuf, mailname) == EOF) {
|
||||
if (ferror(mailname))
|
||||
warning_errno("cannot read /etc/mailname");
|
||||
strbuf_release(&mailnamebuf);
|
||||
fclose(mailname);
|
||||
return -1;
|
||||
}
|
||||
/* success! */
|
||||
strbuf_addbuf(buf, &mailnamebuf);
|
||||
strbuf_release(&mailnamebuf);
|
||||
fclose(mailname);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int canonical_name(const char *host, struct strbuf *out)
|
||||
{
|
||||
int status = -1;
|
||||
|
||||
#ifndef NO_IPV6
|
||||
struct addrinfo hints, *ai;
|
||||
memset (&hints, '\0', sizeof (hints));
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
if (!getaddrinfo(host, NULL, &hints, &ai)) {
|
||||
if (ai && ai->ai_canonname && strchr(ai->ai_canonname, '.')) {
|
||||
strbuf_addstr(out, ai->ai_canonname);
|
||||
status = 0;
|
||||
}
|
||||
freeaddrinfo(ai);
|
||||
}
|
||||
#else
|
||||
struct hostent *he = gethostbyname(host);
|
||||
if (he && strchr(he->h_name, '.')) {
|
||||
strbuf_addstr(out, he->h_name);
|
||||
status = 0;
|
||||
}
|
||||
#endif /* NO_IPV6 */
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void add_domainname(struct strbuf *out, int *is_bogus)
|
||||
{
|
||||
char buf[HOST_NAME_MAX + 1];
|
||||
|
||||
if (xgethostname(buf, sizeof(buf))) {
|
||||
warning_errno("cannot get host name");
|
||||
strbuf_addstr(out, "(none)");
|
||||
*is_bogus = 1;
|
||||
return;
|
||||
}
|
||||
if (strchr(buf, '.'))
|
||||
strbuf_addstr(out, buf);
|
||||
else if (canonical_name(buf, out) < 0) {
|
||||
strbuf_addf(out, "%s.(none)", buf);
|
||||
*is_bogus = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static void copy_email(const struct passwd *pw, struct strbuf *email,
|
||||
int *is_bogus)
|
||||
{
|
||||
/*
|
||||
* Make up a fake email address
|
||||
* (name + '@' + hostname [+ '.' + domainname])
|
||||
*/
|
||||
strbuf_addstr(email, pw->pw_name);
|
||||
strbuf_addch(email, '@');
|
||||
|
||||
if (!add_mailname_host(email))
|
||||
return; /* read from "/etc/mailname" (Debian) */
|
||||
add_domainname(email, is_bogus);
|
||||
}
|
||||
|
||||
const char *ident_default_name(void)
|
||||
{
|
||||
if (!(ident_config_given & IDENT_NAME_GIVEN) && !git_default_name.len) {
|
||||
copy_gecos(xgetpwuid_self(&default_name_is_bogus), &git_default_name);
|
||||
strbuf_trim(&git_default_name);
|
||||
}
|
||||
return git_default_name.buf;
|
||||
}
|
||||
|
||||
const char *ident_default_email(void)
|
||||
{
|
||||
if (!(ident_config_given & IDENT_MAIL_GIVEN) && !git_default_email.len) {
|
||||
const char *email = getenv("EMAIL");
|
||||
|
||||
if (email && email[0]) {
|
||||
strbuf_addstr(&git_default_email, email);
|
||||
committer_ident_explicitly_given |= IDENT_MAIL_GIVEN;
|
||||
author_ident_explicitly_given |= IDENT_MAIL_GIVEN;
|
||||
} else if ((email = query_user_email()) && email[0]) {
|
||||
strbuf_addstr(&git_default_email, email);
|
||||
free((char *)email);
|
||||
} else
|
||||
copy_email(xgetpwuid_self(&default_email_is_bogus),
|
||||
&git_default_email, &default_email_is_bogus);
|
||||
strbuf_trim(&git_default_email);
|
||||
}
|
||||
return git_default_email.buf;
|
||||
}
|
||||
|
||||
static const char *ident_default_date(void)
|
||||
{
|
||||
if (!git_default_date.len)
|
||||
datestamp(&git_default_date);
|
||||
return git_default_date.buf;
|
||||
}
|
||||
|
||||
void reset_ident_date(void)
|
||||
{
|
||||
strbuf_reset(&git_default_date);
|
||||
}
|
||||
|
||||
static int crud(unsigned char c)
|
||||
{
|
||||
return c <= 32 ||
|
||||
c == '.' ||
|
||||
c == ',' ||
|
||||
c == ':' ||
|
||||
c == ';' ||
|
||||
c == '<' ||
|
||||
c == '>' ||
|
||||
c == '"' ||
|
||||
c == '\\' ||
|
||||
c == '\'';
|
||||
}
|
||||
|
||||
static int has_non_crud(const char *str)
|
||||
{
|
||||
for (; *str; str++) {
|
||||
if (!crud(*str))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy over a string to the destination, but avoid special
|
||||
* characters ('\n', '<' and '>') and remove crud at the end
|
||||
*/
|
||||
static void strbuf_addstr_without_crud(struct strbuf *sb, const char *src)
|
||||
{
|
||||
size_t i, len;
|
||||
unsigned char c;
|
||||
|
||||
/* Remove crud from the beginning.. */
|
||||
while ((c = *src) != 0) {
|
||||
if (!crud(c))
|
||||
break;
|
||||
src++;
|
||||
}
|
||||
|
||||
/* Remove crud from the end.. */
|
||||
len = strlen(src);
|
||||
while (len > 0) {
|
||||
c = src[len-1];
|
||||
if (!crud(c))
|
||||
break;
|
||||
--len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the rest to the buffer, but avoid the special
|
||||
* characters '\n' '<' and '>' that act as delimiters on
|
||||
* an identification line. We can only remove crud, never add it,
|
||||
* so 'len' is our maximum.
|
||||
*/
|
||||
strbuf_grow(sb, len);
|
||||
for (i = 0; i < len; i++) {
|
||||
c = *src++;
|
||||
switch (c) {
|
||||
case '\n': case '<': case '>':
|
||||
continue;
|
||||
}
|
||||
sb->buf[sb->len++] = c;
|
||||
}
|
||||
sb->buf[sb->len] = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* Reverse of fmt_ident(); given an ident line, split the fields
|
||||
* to allow the caller to parse it.
|
||||
* Signal a success by returning 0, but date/tz fields of the result
|
||||
* can still be NULL if the input line only has the name/email part
|
||||
* (e.g. reading from a reflog entry).
|
||||
*/
|
||||
int split_ident_line(struct ident_split *split, const char *line, int len)
|
||||
{
|
||||
const char *cp;
|
||||
size_t span;
|
||||
int status = -1;
|
||||
|
||||
memset(split, 0, sizeof(*split));
|
||||
|
||||
split->name_begin = line;
|
||||
for (cp = line; *cp && cp < line + len; cp++)
|
||||
if (*cp == '<') {
|
||||
split->mail_begin = cp + 1;
|
||||
break;
|
||||
}
|
||||
if (!split->mail_begin)
|
||||
return status;
|
||||
|
||||
for (cp = split->mail_begin - 2; line <= cp; cp--)
|
||||
if (!isspace(*cp)) {
|
||||
split->name_end = cp + 1;
|
||||
break;
|
||||
}
|
||||
if (!split->name_end) {
|
||||
/* no human readable name */
|
||||
split->name_end = split->name_begin;
|
||||
}
|
||||
|
||||
for (cp = split->mail_begin; cp < line + len; cp++)
|
||||
if (*cp == '>') {
|
||||
split->mail_end = cp;
|
||||
break;
|
||||
}
|
||||
if (!split->mail_end)
|
||||
return status;
|
||||
|
||||
/*
|
||||
* Look from the end-of-line to find the trailing ">" of the mail
|
||||
* address, even though we should already know it as split->mail_end.
|
||||
* This can help in cases of broken idents with an extra ">" somewhere
|
||||
* in the email address. Note that we are assuming the timestamp will
|
||||
* never have a ">" in it.
|
||||
*
|
||||
* Note that we will always find some ">" before going off the front of
|
||||
* the string, because will always hit the split->mail_end closing
|
||||
* bracket.
|
||||
*/
|
||||
for (cp = line + len - 1; *cp != '>'; cp--)
|
||||
;
|
||||
|
||||
for (cp = cp + 1; cp < line + len && isspace(*cp); cp++)
|
||||
;
|
||||
if (line + len <= cp)
|
||||
goto person_only;
|
||||
split->date_begin = cp;
|
||||
span = strspn(cp, "0123456789");
|
||||
if (!span)
|
||||
goto person_only;
|
||||
split->date_end = split->date_begin + span;
|
||||
for (cp = split->date_end; cp < line + len && isspace(*cp); cp++)
|
||||
;
|
||||
if (line + len <= cp || (*cp != '+' && *cp != '-'))
|
||||
goto person_only;
|
||||
split->tz_begin = cp;
|
||||
span = strspn(cp + 1, "0123456789");
|
||||
if (!span)
|
||||
goto person_only;
|
||||
split->tz_end = split->tz_begin + 1 + span;
|
||||
return 0;
|
||||
|
||||
person_only:
|
||||
split->date_begin = NULL;
|
||||
split->date_end = NULL;
|
||||
split->tz_begin = NULL;
|
||||
split->tz_end = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *env_hint =
|
||||
N_("\n"
|
||||
"*** Please tell me who you are.\n"
|
||||
"\n"
|
||||
"Run\n"
|
||||
"\n"
|
||||
" git config --global user.email \"you@example.com\"\n"
|
||||
" git config --global user.name \"Your Name\"\n"
|
||||
"\n"
|
||||
"to set your account\'s default identity.\n"
|
||||
"Omit --global to set the identity only in this repository.\n"
|
||||
"\n");
|
||||
|
||||
const char *fmt_ident(const char *name, const char *email,
|
||||
enum want_ident whose_ident, const char *date_str, int flag)
|
||||
{
|
||||
static struct strbuf ident = STRBUF_INIT;
|
||||
int strict = (flag & IDENT_STRICT);
|
||||
int want_date = !(flag & IDENT_NO_DATE);
|
||||
int want_name = !(flag & IDENT_NO_NAME);
|
||||
|
||||
if (!email) {
|
||||
if (whose_ident == WANT_AUTHOR_IDENT && git_author_email.len)
|
||||
email = git_author_email.buf;
|
||||
else if (whose_ident == WANT_COMMITTER_IDENT && git_committer_email.len)
|
||||
email = git_committer_email.buf;
|
||||
}
|
||||
if (!email) {
|
||||
if (strict && ident_use_config_only
|
||||
&& !(ident_config_given & IDENT_MAIL_GIVEN)) {
|
||||
fputs(_(env_hint), stderr);
|
||||
die(_("no email was given and auto-detection is disabled"));
|
||||
}
|
||||
email = ident_default_email();
|
||||
if (strict && default_email_is_bogus) {
|
||||
fputs(_(env_hint), stderr);
|
||||
die(_("unable to auto-detect email address (got '%s')"), email);
|
||||
}
|
||||
}
|
||||
|
||||
if (want_name) {
|
||||
int using_default = 0;
|
||||
if (!name) {
|
||||
if (whose_ident == WANT_AUTHOR_IDENT && git_author_name.len)
|
||||
name = git_author_name.buf;
|
||||
else if (whose_ident == WANT_COMMITTER_IDENT &&
|
||||
git_committer_name.len)
|
||||
name = git_committer_name.buf;
|
||||
}
|
||||
if (!name) {
|
||||
if (strict && ident_use_config_only
|
||||
&& !(ident_config_given & IDENT_NAME_GIVEN)) {
|
||||
fputs(_(env_hint), stderr);
|
||||
die(_("no name was given and auto-detection is disabled"));
|
||||
}
|
||||
name = ident_default_name();
|
||||
using_default = 1;
|
||||
if (strict && default_name_is_bogus) {
|
||||
fputs(_(env_hint), stderr);
|
||||
die(_("unable to auto-detect name (got '%s')"), name);
|
||||
}
|
||||
}
|
||||
if (!*name) {
|
||||
struct passwd *pw;
|
||||
if (strict) {
|
||||
if (using_default)
|
||||
fputs(_(env_hint), stderr);
|
||||
die(_("empty ident name (for <%s>) not allowed"), email);
|
||||
}
|
||||
pw = xgetpwuid_self(NULL);
|
||||
name = pw->pw_name;
|
||||
}
|
||||
if (strict && !has_non_crud(name))
|
||||
die(_("name consists only of disallowed characters: %s"), name);
|
||||
}
|
||||
|
||||
strbuf_reset(&ident);
|
||||
if (want_name) {
|
||||
strbuf_addstr_without_crud(&ident, name);
|
||||
strbuf_addstr(&ident, " <");
|
||||
}
|
||||
strbuf_addstr_without_crud(&ident, email);
|
||||
if (want_name)
|
||||
strbuf_addch(&ident, '>');
|
||||
if (want_date) {
|
||||
strbuf_addch(&ident, ' ');
|
||||
if (date_str && date_str[0]) {
|
||||
if (parse_date(date_str, &ident) < 0)
|
||||
die(_("invalid date format: %s"), date_str);
|
||||
}
|
||||
else
|
||||
strbuf_addstr(&ident, ident_default_date());
|
||||
}
|
||||
|
||||
return ident.buf;
|
||||
}
|
||||
|
||||
const char *fmt_name(enum want_ident whose_ident)
|
||||
{
|
||||
char *name = NULL;
|
||||
char *email = NULL;
|
||||
|
||||
switch (whose_ident) {
|
||||
case WANT_BLANK_IDENT:
|
||||
break;
|
||||
case WANT_AUTHOR_IDENT:
|
||||
name = getenv("GIT_AUTHOR_NAME");
|
||||
email = getenv("GIT_AUTHOR_EMAIL");
|
||||
break;
|
||||
case WANT_COMMITTER_IDENT:
|
||||
name = getenv("GIT_COMMITTER_NAME");
|
||||
email = getenv("GIT_COMMITTER_EMAIL");
|
||||
break;
|
||||
}
|
||||
return fmt_ident(name, email, whose_ident, NULL,
|
||||
IDENT_STRICT | IDENT_NO_DATE);
|
||||
}
|
||||
|
||||
const char *git_author_info(int flag)
|
||||
{
|
||||
if (getenv("GIT_AUTHOR_NAME"))
|
||||
author_ident_explicitly_given |= IDENT_NAME_GIVEN;
|
||||
if (getenv("GIT_AUTHOR_EMAIL"))
|
||||
author_ident_explicitly_given |= IDENT_MAIL_GIVEN;
|
||||
return fmt_ident(getenv("GIT_AUTHOR_NAME"),
|
||||
getenv("GIT_AUTHOR_EMAIL"),
|
||||
WANT_AUTHOR_IDENT,
|
||||
getenv("GIT_AUTHOR_DATE"),
|
||||
flag);
|
||||
}
|
||||
|
||||
const char *git_committer_info(int flag)
|
||||
{
|
||||
if (getenv("GIT_COMMITTER_NAME"))
|
||||
committer_ident_explicitly_given |= IDENT_NAME_GIVEN;
|
||||
if (getenv("GIT_COMMITTER_EMAIL"))
|
||||
committer_ident_explicitly_given |= IDENT_MAIL_GIVEN;
|
||||
return fmt_ident(getenv("GIT_COMMITTER_NAME"),
|
||||
getenv("GIT_COMMITTER_EMAIL"),
|
||||
WANT_COMMITTER_IDENT,
|
||||
getenv("GIT_COMMITTER_DATE"),
|
||||
flag);
|
||||
}
|
||||
|
||||
static int ident_is_sufficient(int user_ident_explicitly_given)
|
||||
{
|
||||
#ifndef WINDOWS
|
||||
return (user_ident_explicitly_given & IDENT_MAIL_GIVEN);
|
||||
#else
|
||||
return (user_ident_explicitly_given == IDENT_ALL_GIVEN);
|
||||
#endif
|
||||
}
|
||||
|
||||
int committer_ident_sufficiently_given(void)
|
||||
{
|
||||
return ident_is_sufficient(committer_ident_explicitly_given);
|
||||
}
|
||||
|
||||
int author_ident_sufficiently_given(void)
|
||||
{
|
||||
return ident_is_sufficient(author_ident_explicitly_given);
|
||||
}
|
||||
|
||||
static int set_ident(const char *var, const char *value)
|
||||
{
|
||||
if (!strcmp(var, "author.name")) {
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
strbuf_reset(&git_author_name);
|
||||
strbuf_addstr(&git_author_name, value);
|
||||
author_ident_explicitly_given |= IDENT_NAME_GIVEN;
|
||||
ident_config_given |= IDENT_NAME_GIVEN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "author.email")) {
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
strbuf_reset(&git_author_email);
|
||||
strbuf_addstr(&git_author_email, value);
|
||||
author_ident_explicitly_given |= IDENT_MAIL_GIVEN;
|
||||
ident_config_given |= IDENT_MAIL_GIVEN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "committer.name")) {
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
strbuf_reset(&git_committer_name);
|
||||
strbuf_addstr(&git_committer_name, value);
|
||||
committer_ident_explicitly_given |= IDENT_NAME_GIVEN;
|
||||
ident_config_given |= IDENT_NAME_GIVEN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "committer.email")) {
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
strbuf_reset(&git_committer_email);
|
||||
strbuf_addstr(&git_committer_email, value);
|
||||
committer_ident_explicitly_given |= IDENT_MAIL_GIVEN;
|
||||
ident_config_given |= IDENT_MAIL_GIVEN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "user.name")) {
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
strbuf_reset(&git_default_name);
|
||||
strbuf_addstr(&git_default_name, value);
|
||||
committer_ident_explicitly_given |= IDENT_NAME_GIVEN;
|
||||
author_ident_explicitly_given |= IDENT_NAME_GIVEN;
|
||||
ident_config_given |= IDENT_NAME_GIVEN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!strcmp(var, "user.email")) {
|
||||
if (!value)
|
||||
return config_error_nonbool(var);
|
||||
strbuf_reset(&git_default_email);
|
||||
strbuf_addstr(&git_default_email, value);
|
||||
committer_ident_explicitly_given |= IDENT_MAIL_GIVEN;
|
||||
author_ident_explicitly_given |= IDENT_MAIL_GIVEN;
|
||||
ident_config_given |= IDENT_MAIL_GIVEN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int git_ident_config(const char *var, const char *value, void *data)
|
||||
{
|
||||
if (!strcmp(var, "user.useconfigonly")) {
|
||||
ident_use_config_only = git_config_bool(var, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return set_ident(var, value);
|
||||
}
|
||||
|
||||
static void set_env_if(const char *key, const char *value, int *given, int bit)
|
||||
{
|
||||
if ((*given & bit) || getenv(key))
|
||||
return; /* nothing to do */
|
||||
setenv(key, value, 0);
|
||||
*given |= bit;
|
||||
}
|
||||
|
||||
void prepare_fallback_ident(const char *name, const char *email)
|
||||
{
|
||||
set_env_if("GIT_AUTHOR_NAME", name,
|
||||
&author_ident_explicitly_given, IDENT_NAME_GIVEN);
|
||||
set_env_if("GIT_AUTHOR_EMAIL", email,
|
||||
&author_ident_explicitly_given, IDENT_MAIL_GIVEN);
|
||||
set_env_if("GIT_COMMITTER_NAME", name,
|
||||
&committer_ident_explicitly_given, IDENT_NAME_GIVEN);
|
||||
set_env_if("GIT_COMMITTER_EMAIL", email,
|
||||
&committer_ident_explicitly_given, IDENT_MAIL_GIVEN);
|
||||
}
|
||||
|
||||
static int buf_cmp(const char *a_begin, const char *a_end,
|
||||
const char *b_begin, const char *b_end)
|
||||
{
|
||||
int a_len = a_end - a_begin;
|
||||
int b_len = b_end - b_begin;
|
||||
int min = a_len < b_len ? a_len : b_len;
|
||||
int cmp;
|
||||
|
||||
cmp = memcmp(a_begin, b_begin, min);
|
||||
if (cmp)
|
||||
return cmp;
|
||||
|
||||
return a_len - b_len;
|
||||
}
|
||||
|
||||
int ident_cmp(const struct ident_split *a,
|
||||
const struct ident_split *b)
|
||||
{
|
||||
int cmp;
|
||||
|
||||
cmp = buf_cmp(a->mail_begin, a->mail_end,
|
||||
b->mail_begin, b->mail_end);
|
||||
if (cmp)
|
||||
return cmp;
|
||||
|
||||
return buf_cmp(a->name_begin, a->name_end,
|
||||
b->name_begin, b->name_end);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue