Merge branch 'bb/unicode-12'
[gitweb.git] / ident.c
diff --git a/ident.c b/ident.c
index e20a772dde4230b0871ffe85a5204919402aaf94..9c2eb0a2d02ac823a6bf3f01603dfdc7164728c8 100644 (file)
--- a/ident.c
+++ b/ident.c
@@ -6,10 +6,15 @@
  * 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;
 
@@ -72,12 +77,10 @@ static int add_mailname_host(struct strbuf *buf)
        FILE *mailname;
        struct strbuf mailnamebuf = STRBUF_INIT;
 
-       mailname = fopen("/etc/mailname", "r");
-       if (!mailname) {
-               if (errno != ENOENT)
-                       warning_errno("cannot open /etc/mailname");
+       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");
@@ -101,7 +104,7 @@ static int canonical_name(const char *host, struct strbuf *out)
        memset (&hints, '\0', sizeof (hints));
        hints.ai_flags = AI_CANONNAME;
        if (!getaddrinfo(host, NULL, &hints, &ai)) {
-               if (ai && strchr(ai->ai_canonname, '.')) {
+               if (ai && ai->ai_canonname && strchr(ai->ai_canonname, '.')) {
                        strbuf_addstr(out, ai->ai_canonname);
                        status = 0;
                }
@@ -120,9 +123,9 @@ static int canonical_name(const char *host, struct strbuf *out)
 
 static void add_domainname(struct strbuf *out, int *is_bogus)
 {
-       char buf[1024];
+       char buf[HOST_NAME_MAX + 1];
 
-       if (gethostname(buf, sizeof(buf))) {
+       if (xgethostname(buf, sizeof(buf))) {
                warning_errno("cannot get host name");
                strbuf_addstr(out, "(none)");
                *is_bogus = 1;
@@ -153,7 +156,7 @@ static void copy_email(const struct passwd *pw, struct strbuf *email,
 
 const char *ident_default_name(void)
 {
-       if (!git_default_name.len) {
+       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);
        }
@@ -162,13 +165,16 @@ const char *ident_default_name(void)
 
 const char *ident_default_email(void)
 {
-       if (!git_default_email.len) {
+       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);
@@ -203,6 +209,15 @@ static int crud(unsigned char 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
@@ -331,64 +346,79 @@ int split_ident_line(struct ident_split *split, const char *line, int len)
 }
 
 static const char *env_hint =
-"\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";
+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,
-                     const char *date_str, int flag)
+                     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");
+                               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);
+                               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);
+                                       fputs(_(env_hint), stderr);
+                               die(_("empty ident name (for <%s>) not allowed"), email);
                        }
                        pw = xgetpwuid_self(NULL);
                        name = pw->pw_name;
                }
-       }
-
-       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 (strict && !has_non_crud(name))
+                       die(_("name consists only of disallowed characters: %s"), name);
        }
 
        strbuf_reset(&ident);
@@ -403,7 +433,7 @@ const char *fmt_ident(const char *name, const char *email,
                strbuf_addch(&ident, ' ');
                if (date_str && date_str[0]) {
                        if (parse_date(date_str, &ident) < 0)
-                               die("invalid date format: %s", date_str);
+                               die(_("invalid date format: %s"), date_str);
                }
                else
                        strbuf_addstr(&ident, ident_default_date());
@@ -412,9 +442,25 @@ const char *fmt_ident(const char *name, const char *email,
        return ident.buf;
 }
 
-const char *fmt_name(const char *name, const char *email)
+const char *fmt_name(enum want_ident whose_ident)
 {
-       return fmt_ident(name, email, NULL, IDENT_STRICT | IDENT_NO_DATE);
+       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)
@@ -425,6 +471,7 @@ const char *git_author_info(int flag)
                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);
 }
@@ -437,6 +484,7 @@ const char *git_committer_info(int flag)
                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);
 }
@@ -460,10 +508,45 @@ int author_ident_sufficiently_given(void)
        return ident_is_sufficient(author_ident_explicitly_given);
 }
 
-int git_ident_config(const char *var, const char *value, void *data)
+static int set_ident(const char *var, const char *value)
 {
-       if (!strcmp(var, "user.useconfigonly")) {
-               ident_use_config_only = git_config_bool(var, 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;
        }
 
@@ -492,6 +575,16 @@ int git_ident_config(const char *var, const char *value, void *data)
        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 int buf_cmp(const char *a_begin, const char *a_end,
                   const char *b_begin, const char *b_end)
 {