{"thread":{"id":"42942","subject":"[PATCH] i18n: config: unfold error messages marked for translation","startedAt":"2016-07-27T18:00:33Z","lastAt":"2016-07-28T16:17:56Z","messageCount":7,"participants":["Vasco Almeida","Junio C Hamano","Jeff King"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"292345","messageId":"1469642375-27305-1-git-send-email-vascomalmeida@sapo.pt","threadId":"42942","inReplyTo":null,"subject":"[PATCH] i18n: config: unfold error messages marked for translation","fromName":"Vasco Almeida","fromEmail":"vascomalmeida@sapo.pt","sentAt":"2016-07-27T17:59:35Z","receivedAt":"2016-07-27T18:00:33Z","isPatch":true,"sender":{"key":"vascomalmeida@sapo.pt","avatar":"https://avatars.githubusercontent.com/u/9001556?v=4"},"body":"Introduced in 473166b (\"config: add 'origin_type' to config_source\nstruct\", 2016-02-19), Git can inform the user about the origin of a\nconfig error, but the implementation does not allow translators to\ntranslate the keywords 'file', 'blob, 'standard input', and\n'submodule-blob'. Moreover, for the second message, a reason for the\nerror is appended to the message, not allowing translators to translate\nthat reason either.\n\nUnfold the message into several templates for each known origin_type.\nThat would result in better translation at the expense of code\nverbosity.\n\nAdd enum config_oringin_type to ease management of the various\nconfiguration origin types (blob, file, etc).  Previously origin type\nwas considered from command line if cf->origin_type == NULL, i.e.,\nuninitialized. Now we set origin_type to CONFIG_ORIGIN_CMDLINE in\ngit_config_from_parameters() and configset_add_value().\n\nFor error message in git_parse_source(), use xstrfmt() function to\nprepare the message string, instead of doing something like it's done\nfor die_bad_number(), because intelligibility and code conciseness are\nimproved for that instance.\n\nSigned-off-by: Vasco Almeida <vascomalmeida@sapo.pt>\n---\n cache.h            |  12 +++++-\n config.c           | 117 ++++++++++++++++++++++++++++++++++++++++++++---------\n submodule-config.c |   2 +-\n 3 files changed, 109 insertions(+), 22 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 3855ddf..c802098 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1566,10 +1566,18 @@ struct git_config_source {\n \tconst char *blob;\n };\n \n+enum config_origin_type {\n+\tCONFIG_ORIGIN_BLOB,\n+\tCONFIG_ORIGIN_FILE,\n+\tCONFIG_ORIGIN_STDIN,\n+\tCONFIG_ORIGIN_SUBMODULE_BLOB,\n+\tCONFIG_ORIGIN_CMDLINE\n+};\n+\n typedef int (*config_fn_t)(const char *, const char *, void *);\n extern int git_default_config(const char *, const char *, void *);\n extern int git_config_from_file(config_fn_t fn, const char *, void *);\n-extern int git_config_from_mem(config_fn_t fn, const char *origin_type,\n+extern int git_config_from_mem(config_fn_t fn, const enum config_origin_type,\n \t\t\t\t\tconst char *name, const char *buf, size_t len, void *data);\n extern void git_config_push_parameter(const char *text);\n extern int git_config_from_parameters(config_fn_t fn, void *data);\n@@ -1713,7 +1721,7 @@ extern int ignore_untracked_cache_config;\n struct key_value_info {\n \tconst char *filename;\n \tint linenr;\n-\tconst char *origin_type;\n+\tenum config_origin_type origin_type;\n \tenum config_scope scope;\n };\n \ndiff --git a/config.c b/config.c\nindex bea937e..2b12730 100644\n--- a/config.c\n+++ b/config.c\n@@ -24,7 +24,7 @@ struct config_source {\n \t\t\tsize_t pos;\n \t\t} buf;\n \t} u;\n-\tconst char *origin_type;\n+\tenum config_origin_type origin_type;\n \tconst char *name;\n \tconst char *path;\n \tint die_on_error;\n@@ -245,6 +245,7 @@ int git_config_from_parameters(config_fn_t fn, void *data)\n \n \tmemset(&source, 0, sizeof(source));\n \tsource.prev = cf;\n+\tsource.origin_type = CONFIG_ORIGIN_CMDLINE;\n \tcf = &source;\n \n \t/* sq_dequote will write over it */\n@@ -453,6 +454,8 @@ static int git_parse_source(config_fn_t fn, void *data)\n \tint comment = 0;\n \tint baselen = 0;\n \tstruct strbuf *var = &cf->var;\n+\tint error_return = 0;\n+\tchar *error_msg = NULL;\n \n \t/* U+FEFF Byte Order Mark in UTF8 */\n \tconst char *bomptr = utf8_bom;\n@@ -507,10 +510,40 @@ static int git_parse_source(config_fn_t fn, void *data)\n \t\tif (get_value(fn, data, var) < 0)\n \t\t\tbreak;\n \t}\n+\n+\tswitch (cf->origin_type) {\n+\tcase CONFIG_ORIGIN_BLOB:\n+\t\terror_msg = xstrfmt(_(\"bad config line %d in blob %s\"),\n+\t\t\t\t      cf->linenr, cf->name);\n+\t\tbreak;\n+\tcase CONFIG_ORIGIN_FILE:\n+\t\terror_msg = xstrfmt(_(\"bad config line %d in file %s\"),\n+\t\t\t\t      cf->linenr, cf->name);\n+\t\tbreak;\n+\tcase CONFIG_ORIGIN_STDIN:\n+\t\terror_msg = xstrfmt(_(\"bad config line %d in standard input %s\"),\n+\t\t\t\t      cf->linenr, cf->name);\n+\t\tbreak;\n+\tcase CONFIG_ORIGIN_SUBMODULE_BLOB:\n+\t\terror_msg = xstrfmt(_(\"bad config line %d in submodule-blob %s\"),\n+\t\t\t\t       cf->linenr, cf->name);\n+\t\tbreak;\n+\tcase CONFIG_ORIGIN_CMDLINE:\n+\t\terror_msg = xstrfmt(_(\"bad config line %d in command line %s\"),\n+\t\t\t\t       cf->linenr, cf->name);\n+\t\tbreak;\n+\tdefault:\n+\t\terror_msg = xstrfmt(_(\"bad config line %d in %s\"),\n+\t\t\t\t      cf->linenr, cf->name);\n+\t}\n+\n \tif (cf->die_on_error)\n-\t\tdie(_(\"bad config line %d in %s %s\"), cf->linenr, cf->origin_type, cf->name);\n+\t\tdie(error_msg);\n \telse\n-\t\treturn error(_(\"bad config line %d in %s %s\"), cf->linenr, cf->origin_type, cf->name);\n+\t\terror_return =  error(error_msg);\n+\n+\tfree(error_msg);\n+\treturn error_return;\n }\n \n static int parse_unit_factor(const char *end, uintmax_t *val)\n@@ -619,16 +652,47 @@ int git_parse_ulong(const char *value, unsigned long *ret)\n NORETURN\n static void die_bad_number(const char *name, const char *value)\n {\n-\tconst char *reason = errno == ERANGE ?\n-\t\t\t     \"out of range\" :\n-\t\t\t     \"invalid unit\";\n \tif (!value)\n \t\tvalue = \"\";\n \n-\tif (cf && cf->origin_type && cf->name)\n-\t\tdie(_(\"bad numeric config value '%s' for '%s' in %s %s: %s\"),\n-\t\t    value, name, cf->origin_type, cf->name, reason);\n-\tdie(_(\"bad numeric config value '%s' for '%s': %s\"), value, name, reason);\n+\tif (!(cf && cf->name))\n+\t\tdie(errno == ERANGE\n+\t\t    ? _(\"bad numeric config value '%s' for '%s': out of range\")\n+\t\t    : _(\"bad numeric config value '%s' for '%s': invalid unit\"),\n+\t\t    value, name);\n+\n+\tswitch (cf->origin_type) {\n+\tcase CONFIG_ORIGIN_BLOB:\n+\t\tdie(errno == ERANGE\n+\t\t    ? _(\"bad numeric config value '%s' for '%s' in blob %s: out of range\")\n+\t\t    : _(\"bad numeric config value '%s' for '%s' in blob %s: invalid unit\"),\n+\t\t    value, name, cf->name);\n+\tcase CONFIG_ORIGIN_FILE:\n+\t\tdie(errno == ERANGE\n+\t\t    ? _(\"bad numeric config value '%s' for '%s' in file %s: out of range\")\n+\t\t    : _(\"bad numeric config value '%s' for '%s' in file %s: invalid unit\"),\n+\t\t    value, name, cf->name);\n+\tcase CONFIG_ORIGIN_STDIN:\n+\t\tdie(errno == ERANGE\n+\t\t    ? _(\"bad numeric config value '%s' for '%s' in standard input %s: out of range\")\n+\t\t    : _(\"bad numeric config value '%s' for '%s' in standard input %s: invalid unit\"),\n+\t\t    value, name, cf->name);\n+\tcase CONFIG_ORIGIN_SUBMODULE_BLOB:\n+\t\tdie(errno == ERANGE\n+\t\t    ? _(\"bad numeric config value '%s' for '%s' in submodule-blob %s: out of range\")\n+\t\t    : _(\"bad numeric config value '%s' for '%s' in submodule-blob %s: invalid unit\"),\n+\t\t    value, name, cf->name);\n+\tcase CONFIG_ORIGIN_CMDLINE:\n+\t\tdie(errno == ERANGE\n+\t\t    ? _(\"bad numeric config value '%s' for '%s' in command line %s: out of range\")\n+\t\t    : _(\"bad numeric config value '%s' for '%s' in command line %s: invalid unit\"),\n+\t\t    value, name, cf->name);\n+\tdefault:\n+\t\tdie(errno == ERANGE\n+\t\t    ? _(\"bad numeric config value '%s' for '%s' in %s: out of range\")\n+\t\t    : _(\"bad numeric config value '%s' for '%s' in %s: invalid unit\"),\n+\t\t    value, name, cf->name);\n+\t}\n }\n \n int git_config_int(const char *name, const char *value)\n@@ -1105,7 +1169,8 @@ static int do_config_from(struct config_source *top, config_fn_t fn, void *data)\n }\n \n static int do_config_from_file(config_fn_t fn,\n-\t\tconst char *origin_type, const char *name, const char *path, FILE *f,\n+\t\tconst enum config_origin_type origin_type,\n+\t\tconst char *name, const char *path, FILE *f,\n \t\tvoid *data)\n {\n \tstruct config_source top;\n@@ -1124,7 +1189,7 @@ static int do_config_from_file(config_fn_t fn,\n \n static int git_config_from_stdin(config_fn_t fn, void *data)\n {\n-\treturn do_config_from_file(fn, \"standard input\", \"\", NULL, stdin, data);\n+\treturn do_config_from_file(fn, CONFIG_ORIGIN_STDIN, \"\", NULL, stdin, data);\n }\n \n int git_config_from_file(config_fn_t fn, const char *filename, void *data)\n@@ -1135,14 +1200,14 @@ int git_config_from_file(config_fn_t fn, const char *filename, void *data)\n \tf = fopen(filename, \"r\");\n \tif (f) {\n \t\tflockfile(f);\n-\t\tret = do_config_from_file(fn, \"file\", filename, filename, f, data);\n+\t\tret = do_config_from_file(fn, CONFIG_ORIGIN_FILE, filename, filename, f, data);\n \t\tfunlockfile(f);\n \t\tfclose(f);\n \t}\n \treturn ret;\n }\n \n-int git_config_from_mem(config_fn_t fn, const char *origin_type,\n+int git_config_from_mem(config_fn_t fn, const enum config_origin_type origin_type,\n \t\t\tconst char *name, const char *buf, size_t len, void *data)\n {\n \tstruct config_source top;\n@@ -1179,7 +1244,7 @@ static int git_config_from_blob_sha1(config_fn_t fn,\n \t\treturn error(\"reference '%s' does not point to a blob\", name);\n \t}\n \n-\tret = git_config_from_mem(fn, \"blob\", name, buf, size, data);\n+\tret = git_config_from_mem(fn, CONFIG_ORIGIN_BLOB, name, buf, size, data);\n \tfree(buf);\n \n \treturn ret;\n@@ -1390,12 +1455,12 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha\n \tif (cf->name) {\n \t\tkv_info->filename = strintern(cf->name);\n \t\tkv_info->linenr = cf->linenr;\n-\t\tkv_info->origin_type = strintern(cf->origin_type);\n+\t\tkv_info->origin_type = cf->origin_type;\n \t} else {\n \t\t/* for values read from `git_config_from_parameters()` */\n \t\tkv_info->filename = NULL;\n \t\tkv_info->linenr = -1;\n-\t\tkv_info->origin_type = NULL;\n+\t\tkv_info->origin_type = CONFIG_ORIGIN_CMDLINE;\n \t}\n \tkv_info->scope = current_parsing_scope;\n \tsi->util = kv_info;\n@@ -2476,14 +2541,28 @@ int parse_config_key(const char *var,\n \n const char *current_config_origin_type(void)\n {\n-\tconst char *type;\n+\tint type;\n \tif (current_config_kvi)\n \t\ttype = current_config_kvi->origin_type;\n \telse if(cf)\n \t\ttype = cf->origin_type;\n \telse\n \t\tdie(\"BUG: current_config_origin_type called outside config callback\");\n-\treturn type ? type : \"command line\";\n+\n+\tswitch (type) {\n+\tcase CONFIG_ORIGIN_BLOB:\n+\t\treturn \"blob\";\n+\tcase CONFIG_ORIGIN_FILE:\n+\t\treturn \"file\";\n+\tcase CONFIG_ORIGIN_STDIN:\n+\t\treturn \"standard input\";\n+\tcase CONFIG_ORIGIN_SUBMODULE_BLOB:\n+\t\treturn \"submodule-blob\";\n+\tcase CONFIG_ORIGIN_CMDLINE:\n+\t\treturn \"command line\";\n+\tdefault:\n+\t\tdie(\"BUG: unknown config origin type\");\n+\t}\n }\n \n const char *current_config_name(void)\ndiff --git a/submodule-config.c b/submodule-config.c\nindex 077db40..1753e01 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -448,7 +448,7 @@ static const struct submodule *config_from(struct submodule_cache *cache,\n \tparameter.commit_sha1 = commit_sha1;\n \tparameter.gitmodules_sha1 = sha1;\n \tparameter.overwrite = 0;\n-\tgit_config_from_mem(parse_config, \"submodule-blob\", rev.buf,\n+\tgit_config_from_mem(parse_config, CONFIG_ORIGIN_SUBMODULE_BLOB, rev.buf,\n \t\t\tconfig, config_size, &parameter);\n \tfree(config);\n \n-- \n2.7.4\n\n"},{"id":"292365","messageId":"xmqqy44mvol9.fsf@gitster.mtv.corp.google.com","threadId":"42942","inReplyTo":"1469642375-27305-1-git-send-email-vascomalmeida@sapo.pt","subject":"Re: [PATCH] i18n: config: unfold error messages marked for translation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-07-27T20:00:02Z","receivedAt":"2016-07-27T20:00:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Vasco Almeida <vascomalmeida@sapo.pt> writes:\n\n> +\n> +\tswitch (cf->origin_type) {\n> +\tcase CONFIG_ORIGIN_BLOB:\n> +\t\terror_msg = xstrfmt(_(\"bad config line %d in blob %s\"),\n> +\t\t\t\t      cf->linenr, cf->name);\n> +\t\tbreak;\n> +\tcase CONFIG_ORIGIN_FILE:\n> +\t\terror_msg = xstrfmt(_(\"bad config line %d in file %s\"),\n> +\t\t\t\t      cf->linenr, cf->name);\n> +\t\tbreak;\n\nHmm, if we were to switch the message based on the origin type, then\nthings like this:\n\n> +\tcase CONFIG_ORIGIN_STDIN:\n> +\t\terror_msg = xstrfmt(_(\"bad config line %d in standard input %s\"),\n> +\t\t\t\t      cf->linenr, cf->name);\n> +\t\tbreak;\n\nand this:\n\n> +\tcase CONFIG_ORIGIN_STDIN:\n> +\t\tdie(errno == ERANGE\n> +\t\t    ? _(\"bad numeric config value '%s' for '%s' in standard input %s: out of range\")\n> +\t\t    : _(\"bad numeric config value '%s' for '%s' in standard input %s: invalid unit\"),\n> +\t\t    value, name, cf->name);\n\nthat does not have any useful cf->name can be improved even more, no?\n\nThe only reason why we pass an empty string here:\n\n>  static int git_config_from_stdin(config_fn_t fn, void *data)\n>  {\n> -\treturn do_config_from_file(fn, \"standard input\", \"\", NULL, stdin, data);\n> +\treturn do_config_from_file(fn, CONFIG_ORIGIN_STDIN, \"\", NULL, stdin, data);\n>  }\n\nis because do_config_from_file() function whose primary purpose is\nto read from file was reused, the interface to that function\nrequires the filename there for reporting, and we do not have\nanything useful when reading from the standard input.\n"},{"id":"292381","messageId":"xmqqvazqu2ke.fsf@gitster.mtv.corp.google.com","threadId":"42942","inReplyTo":"1469642375-27305-1-git-send-email-vascomalmeida@sapo.pt","subject":"Re: [PATCH] i18n: config: unfold error messages marked for translation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-07-27T22:41:05Z","receivedAt":"2016-07-27T22:41:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Vasco Almeida <vascomalmeida@sapo.pt> writes:\n\n> +\tdefault:\n> +\t\terror_msg = xstrfmt(_(\"bad config line %d in %s\"),\n> +\t\t\t\t      cf->linenr, cf->name);\n> +\t}\n> +\n>  \tif (cf->die_on_error)\n> -\t\tdie(_(\"bad config line %d in %s %s\"), cf->linenr, cf->origin_type, cf->name);\n> +\t\tdie(error_msg);\n\nAs error_msg is a result of xstrfmt() and there is no further\ninterpolation needed, you would want to say\n\n\tdie(\"%s\", error_msg);\n\nhere.  It triggers \n\nconfig.c:541:3: error: format not a string literal and no format arguments [-Werror=format-security]\n\nSimilarly for error() below.\n\n>  \telse\n> -\t\treturn error(_(\"bad config line %d in %s %s\"), cf->linenr, cf->origin_type, cf->name);\n> +\t\terror_return =  error(error_msg);\n\n"},{"id":"292392","messageId":"1469702302.1884.8.camel@sapo.pt","threadId":"42942","inReplyTo":"xmqqy44mvol9.fsf@gitster.mtv.corp.google.com","subject":"Re: [PATCH] i18n: config: unfold error messages marked for translation","fromName":"Vasco Almeida","fromEmail":"vascomalmeida@sapo.pt","sentAt":"2016-07-28T10:38:22Z","receivedAt":"2016-07-28T10:38:35Z","isPatch":true,"sender":{"key":"vascomalmeida@sapo.pt","avatar":"https://avatars.githubusercontent.com/u/9001556?v=4"},"body":"A Qua, 27-07-2016 às 13:00 -0700, Junio C Hamano escreveu:\n> Vasco Almeida <vascomalmeida@sapo.pt> writes:\n> \n> > \n> > +\n> > +\tswitch (cf->origin_type) {\n> > +\tcase CONFIG_ORIGIN_BLOB:\n> > +\t\terror_msg = xstrfmt(_(\"bad config line %d in blob\n> > %s\"),\n> > +\t\t\t\t      cf->linenr, cf->name);\n> > +\t\tbreak;\n> > +\tcase CONFIG_ORIGIN_FILE:\n> > +\t\terror_msg = xstrfmt(_(\"bad config line %d in file\n> > %s\"),\n> > +\t\t\t\t      cf->linenr, cf->name);\n> > +\t\tbreak;\n> \n> Hmm, if we were to switch the message based on the origin type, then\n> things like this:\n> \n> > \n> > +\tcase CONFIG_ORIGIN_STDIN:\n> > +\t\terror_msg = xstrfmt(_(\"bad config line %d in\n> > standard input %s\"),\n> > +\t\t\t\t      cf->linenr, cf->name);\n> > +\t\tbreak;\n> \n> and this:\n> \n> > \n> > +\tcase CONFIG_ORIGIN_STDIN:\n> > +\t\tdie(errno == ERANGE\n> > +\t\t    ? _(\"bad numeric config value '%s' for '%s' in\n> > standard input %s: out of range\")\n> > +\t\t    : _(\"bad numeric config value '%s' for '%s' in\n> > standard input %s: invalid unit\"),\n> > +\t\t    value, name, cf->name);\n> \n> that does not have any useful cf->name can be improved even more, no?\n> \n> The only reason why we pass an empty string here:\n> \n> > \n> >  static int git_config_from_stdin(config_fn_t fn, void *data)\n> >  {\n> > -\treturn do_config_from_file(fn, \"standard input\", \"\", NULL,\n> > stdin, data);\n> > +\treturn do_config_from_file(fn, CONFIG_ORIGIN_STDIN, \"\",\n> > NULL, stdin, data);\n> >  }\n> \n> is because do_config_from_file() function whose primary purpose is\n> to read from file was reused, the interface to that function\n> requires the filename there for reporting, and we do not have\n> anything useful when reading from the standard input.\n\nProbably that is why I have omitted cf->name for CONFIG_ORIGIN_STDIN\ninstance first time I sent this patch [1]. This patch was dropped from\nprevious i18n batch because it conflicted with other changes in flux.\nForgot about that and, for no good reason, added cf->name.\nThank you for pointing out.\n\n[1] http://www.mail-archive.com/git%40vger.kernel.org/msg96368.html\n"},{"id":"292403","messageId":"1469711643-10367-1-git-send-email-vascomalmeida@sapo.pt","threadId":"42942","inReplyTo":"1469642375-27305-1-git-send-email-vascomalmeida@sapo.pt","subject":"[PATCH v2] i18n: config: unfold error messages marked for translation","fromName":"Vasco Almeida","fromEmail":"vascomalmeida@sapo.pt","sentAt":"2016-07-28T13:14:03Z","receivedAt":"2016-07-28T13:14:39Z","isPatch":true,"sender":{"key":"vascomalmeida@sapo.pt","avatar":"https://avatars.githubusercontent.com/u/9001556?v=4"},"body":"Introduced in 473166b (\"config: add 'origin_type' to config_source\nstruct\", 2016-02-19), Git can inform the user about the origin of a\nconfig error, but the implementation does not allow translators to\ntranslate the keywords 'file', 'blob, 'standard input', and\n'submodule-blob'. Moreover, for the second message, a reason for the\nerror is appended to the message, not allowing translators to translate\nthat reason either.\n\nUnfold the message into several templates for each known origin_type.\nThat would result in better translation at the expense of code\nverbosity.\n\nAdd enum config_oringin_type to ease management of the various\nconfiguration origin types (blob, file, etc).  Previously origin type\nwas considered from command line if cf->origin_type == NULL, i.e.,\nuninitialized. Now we set origin_type to CONFIG_ORIGIN_CMDLINE in\ngit_config_from_parameters() and configset_add_value().\n\nFor error message in git_parse_source(), use xstrfmt() function to\nprepare the message string, instead of doing something like it's done\nfor die_bad_number(), because intelligibility and code conciseness are\nimproved for that instance.\n\nSigned-off-by: Vasco Almeida <vascomalmeida@sapo.pt>\n---\n cache.h            |  12 +++++-\n config.c           | 117 ++++++++++++++++++++++++++++++++++++++++++++---------\n submodule-config.c |   2 +-\n 3 files changed, 109 insertions(+), 22 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 3855ddf..c802098 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1566,10 +1566,18 @@ struct git_config_source {\n \tconst char *blob;\n };\n \n+enum config_origin_type {\n+\tCONFIG_ORIGIN_BLOB,\n+\tCONFIG_ORIGIN_FILE,\n+\tCONFIG_ORIGIN_STDIN,\n+\tCONFIG_ORIGIN_SUBMODULE_BLOB,\n+\tCONFIG_ORIGIN_CMDLINE\n+};\n+\n typedef int (*config_fn_t)(const char *, const char *, void *);\n extern int git_default_config(const char *, const char *, void *);\n extern int git_config_from_file(config_fn_t fn, const char *, void *);\n-extern int git_config_from_mem(config_fn_t fn, const char *origin_type,\n+extern int git_config_from_mem(config_fn_t fn, const enum config_origin_type,\n \t\t\t\t\tconst char *name, const char *buf, size_t len, void *data);\n extern void git_config_push_parameter(const char *text);\n extern int git_config_from_parameters(config_fn_t fn, void *data);\n@@ -1713,7 +1721,7 @@ extern int ignore_untracked_cache_config;\n struct key_value_info {\n \tconst char *filename;\n \tint linenr;\n-\tconst char *origin_type;\n+\tenum config_origin_type origin_type;\n \tenum config_scope scope;\n };\n \ndiff --git a/config.c b/config.c\nindex bea937e..62b83d9 100644\n--- a/config.c\n+++ b/config.c\n@@ -24,7 +24,7 @@ struct config_source {\n \t\t\tsize_t pos;\n \t\t} buf;\n \t} u;\n-\tconst char *origin_type;\n+\tenum config_origin_type origin_type;\n \tconst char *name;\n \tconst char *path;\n \tint die_on_error;\n@@ -245,6 +245,7 @@ int git_config_from_parameters(config_fn_t fn, void *data)\n \n \tmemset(&source, 0, sizeof(source));\n \tsource.prev = cf;\n+\tsource.origin_type = CONFIG_ORIGIN_CMDLINE;\n \tcf = &source;\n \n \t/* sq_dequote will write over it */\n@@ -453,6 +454,8 @@ static int git_parse_source(config_fn_t fn, void *data)\n \tint comment = 0;\n \tint baselen = 0;\n \tstruct strbuf *var = &cf->var;\n+\tint error_return = 0;\n+\tchar *error_msg = NULL;\n \n \t/* U+FEFF Byte Order Mark in UTF8 */\n \tconst char *bomptr = utf8_bom;\n@@ -507,10 +510,40 @@ static int git_parse_source(config_fn_t fn, void *data)\n \t\tif (get_value(fn, data, var) < 0)\n \t\t\tbreak;\n \t}\n+\n+\tswitch (cf->origin_type) {\n+\tcase CONFIG_ORIGIN_BLOB:\n+\t\terror_msg = xstrfmt(_(\"bad config line %d in blob %s\"),\n+\t\t\t\t      cf->linenr, cf->name);\n+\t\tbreak;\n+\tcase CONFIG_ORIGIN_FILE:\n+\t\terror_msg = xstrfmt(_(\"bad config line %d in file %s\"),\n+\t\t\t\t      cf->linenr, cf->name);\n+\t\tbreak;\n+\tcase CONFIG_ORIGIN_STDIN:\n+\t\terror_msg = xstrfmt(_(\"bad config line %d in standard input\"),\n+\t\t\t\t      cf->linenr);\n+\t\tbreak;\n+\tcase CONFIG_ORIGIN_SUBMODULE_BLOB:\n+\t\terror_msg = xstrfmt(_(\"bad config line %d in submodule-blob %s\"),\n+\t\t\t\t       cf->linenr, cf->name);\n+\t\tbreak;\n+\tcase CONFIG_ORIGIN_CMDLINE:\n+\t\terror_msg = xstrfmt(_(\"bad config line %d in command line %s\"),\n+\t\t\t\t       cf->linenr, cf->name);\n+\t\tbreak;\n+\tdefault:\n+\t\terror_msg = xstrfmt(_(\"bad config line %d in %s\"),\n+\t\t\t\t      cf->linenr, cf->name);\n+\t}\n+\n \tif (cf->die_on_error)\n-\t\tdie(_(\"bad config line %d in %s %s\"), cf->linenr, cf->origin_type, cf->name);\n+\t\tdie(\"%s\", error_msg);\n \telse\n-\t\treturn error(_(\"bad config line %d in %s %s\"), cf->linenr, cf->origin_type, cf->name);\n+\t\terror_return =  error(\"%s\", error_msg);\n+\n+\tfree(error_msg);\n+\treturn error_return;\n }\n \n static int parse_unit_factor(const char *end, uintmax_t *val)\n@@ -619,16 +652,47 @@ int git_parse_ulong(const char *value, unsigned long *ret)\n NORETURN\n static void die_bad_number(const char *name, const char *value)\n {\n-\tconst char *reason = errno == ERANGE ?\n-\t\t\t     \"out of range\" :\n-\t\t\t     \"invalid unit\";\n \tif (!value)\n \t\tvalue = \"\";\n \n-\tif (cf && cf->origin_type && cf->name)\n-\t\tdie(_(\"bad numeric config value '%s' for '%s' in %s %s: %s\"),\n-\t\t    value, name, cf->origin_type, cf->name, reason);\n-\tdie(_(\"bad numeric config value '%s' for '%s': %s\"), value, name, reason);\n+\tif (!(cf && cf->name))\n+\t\tdie(errno == ERANGE\n+\t\t    ? _(\"bad numeric config value '%s' for '%s': out of range\")\n+\t\t    : _(\"bad numeric config value '%s' for '%s': invalid unit\"),\n+\t\t    value, name);\n+\n+\tswitch (cf->origin_type) {\n+\tcase CONFIG_ORIGIN_BLOB:\n+\t\tdie(errno == ERANGE\n+\t\t    ? _(\"bad numeric config value '%s' for '%s' in blob %s: out of range\")\n+\t\t    : _(\"bad numeric config value '%s' for '%s' in blob %s: invalid unit\"),\n+\t\t    value, name, cf->name);\n+\tcase CONFIG_ORIGIN_FILE:\n+\t\tdie(errno == ERANGE\n+\t\t    ? _(\"bad numeric config value '%s' for '%s' in file %s: out of range\")\n+\t\t    : _(\"bad numeric config value '%s' for '%s' in file %s: invalid unit\"),\n+\t\t    value, name, cf->name);\n+\tcase CONFIG_ORIGIN_STDIN:\n+\t\tdie(errno == ERANGE\n+\t\t    ? _(\"bad numeric config value '%s' for '%s' in standard input: out of range\")\n+\t\t    : _(\"bad numeric config value '%s' for '%s' in standard input: invalid unit\"),\n+\t\t    value, name);\n+\tcase CONFIG_ORIGIN_SUBMODULE_BLOB:\n+\t\tdie(errno == ERANGE\n+\t\t    ? _(\"bad numeric config value '%s' for '%s' in submodule-blob %s: out of range\")\n+\t\t    : _(\"bad numeric config value '%s' for '%s' in submodule-blob %s: invalid unit\"),\n+\t\t    value, name, cf->name);\n+\tcase CONFIG_ORIGIN_CMDLINE:\n+\t\tdie(errno == ERANGE\n+\t\t    ? _(\"bad numeric config value '%s' for '%s' in command line %s: out of range\")\n+\t\t    : _(\"bad numeric config value '%s' for '%s' in command line %s: invalid unit\"),\n+\t\t    value, name, cf->name);\n+\tdefault:\n+\t\tdie(errno == ERANGE\n+\t\t    ? _(\"bad numeric config value '%s' for '%s' in %s: out of range\")\n+\t\t    : _(\"bad numeric config value '%s' for '%s' in %s: invalid unit\"),\n+\t\t    value, name, cf->name);\n+\t}\n }\n \n int git_config_int(const char *name, const char *value)\n@@ -1105,7 +1169,8 @@ static int do_config_from(struct config_source *top, config_fn_t fn, void *data)\n }\n \n static int do_config_from_file(config_fn_t fn,\n-\t\tconst char *origin_type, const char *name, const char *path, FILE *f,\n+\t\tconst enum config_origin_type origin_type,\n+\t\tconst char *name, const char *path, FILE *f,\n \t\tvoid *data)\n {\n \tstruct config_source top;\n@@ -1124,7 +1189,7 @@ static int do_config_from_file(config_fn_t fn,\n \n static int git_config_from_stdin(config_fn_t fn, void *data)\n {\n-\treturn do_config_from_file(fn, \"standard input\", \"\", NULL, stdin, data);\n+\treturn do_config_from_file(fn, CONFIG_ORIGIN_STDIN, \"\", NULL, stdin, data);\n }\n \n int git_config_from_file(config_fn_t fn, const char *filename, void *data)\n@@ -1135,14 +1200,14 @@ int git_config_from_file(config_fn_t fn, const char *filename, void *data)\n \tf = fopen(filename, \"r\");\n \tif (f) {\n \t\tflockfile(f);\n-\t\tret = do_config_from_file(fn, \"file\", filename, filename, f, data);\n+\t\tret = do_config_from_file(fn, CONFIG_ORIGIN_FILE, filename, filename, f, data);\n \t\tfunlockfile(f);\n \t\tfclose(f);\n \t}\n \treturn ret;\n }\n \n-int git_config_from_mem(config_fn_t fn, const char *origin_type,\n+int git_config_from_mem(config_fn_t fn, const enum config_origin_type origin_type,\n \t\t\tconst char *name, const char *buf, size_t len, void *data)\n {\n \tstruct config_source top;\n@@ -1179,7 +1244,7 @@ static int git_config_from_blob_sha1(config_fn_t fn,\n \t\treturn error(\"reference '%s' does not point to a blob\", name);\n \t}\n \n-\tret = git_config_from_mem(fn, \"blob\", name, buf, size, data);\n+\tret = git_config_from_mem(fn, CONFIG_ORIGIN_BLOB, name, buf, size, data);\n \tfree(buf);\n \n \treturn ret;\n@@ -1390,12 +1455,12 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha\n \tif (cf->name) {\n \t\tkv_info->filename = strintern(cf->name);\n \t\tkv_info->linenr = cf->linenr;\n-\t\tkv_info->origin_type = strintern(cf->origin_type);\n+\t\tkv_info->origin_type = cf->origin_type;\n \t} else {\n \t\t/* for values read from `git_config_from_parameters()` */\n \t\tkv_info->filename = NULL;\n \t\tkv_info->linenr = -1;\n-\t\tkv_info->origin_type = NULL;\n+\t\tkv_info->origin_type = CONFIG_ORIGIN_CMDLINE;\n \t}\n \tkv_info->scope = current_parsing_scope;\n \tsi->util = kv_info;\n@@ -2476,14 +2541,28 @@ int parse_config_key(const char *var,\n \n const char *current_config_origin_type(void)\n {\n-\tconst char *type;\n+\tint type;\n \tif (current_config_kvi)\n \t\ttype = current_config_kvi->origin_type;\n \telse if(cf)\n \t\ttype = cf->origin_type;\n \telse\n \t\tdie(\"BUG: current_config_origin_type called outside config callback\");\n-\treturn type ? type : \"command line\";\n+\n+\tswitch (type) {\n+\tcase CONFIG_ORIGIN_BLOB:\n+\t\treturn \"blob\";\n+\tcase CONFIG_ORIGIN_FILE:\n+\t\treturn \"file\";\n+\tcase CONFIG_ORIGIN_STDIN:\n+\t\treturn \"standard input\";\n+\tcase CONFIG_ORIGIN_SUBMODULE_BLOB:\n+\t\treturn \"submodule-blob\";\n+\tcase CONFIG_ORIGIN_CMDLINE:\n+\t\treturn \"command line\";\n+\tdefault:\n+\t\tdie(\"BUG: unknown config origin type\");\n+\t}\n }\n \n const char *current_config_name(void)\ndiff --git a/submodule-config.c b/submodule-config.c\nindex 077db40..1753e01 100644\n--- a/submodule-config.c\n+++ b/submodule-config.c\n@@ -448,7 +448,7 @@ static const struct submodule *config_from(struct submodule_cache *cache,\n \tparameter.commit_sha1 = commit_sha1;\n \tparameter.gitmodules_sha1 = sha1;\n \tparameter.overwrite = 0;\n-\tgit_config_from_mem(parse_config, \"submodule-blob\", rev.buf,\n+\tgit_config_from_mem(parse_config, CONFIG_ORIGIN_SUBMODULE_BLOB, rev.buf,\n \t\t\tconfig, config_size, &parameter);\n \tfree(config);\n \n-- \n2.7.4\n\n"},{"id":"292421","messageId":"xmqqwpk5spvy.fsf@gitster.mtv.corp.google.com","threadId":"42942","inReplyTo":"1469711643-10367-1-git-send-email-vascomalmeida@sapo.pt","subject":"Re: [PATCH v2] i18n: config: unfold error messages marked for translation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2016-07-28T16:12:33Z","receivedAt":"2016-07-28T16:12:41Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Vasco Almeida <vascomalmeida@sapo.pt> writes:\n\n> Unfold the message into several templates for each known origin_type.\n> That would result in better translation at the expense of code\n> verbosity.\n\nLooks good now, except one minor nit I'll tweak out while queuing.\n\n>  \tif (cf->die_on_error)\n> -\t\tdie(_(\"bad config line %d in %s %s\"), cf->linenr, cf->origin_type, cf->name);\n> +\t\tdie(\"%s\", error_msg);\n>  \telse\n> -\t\treturn error(_(\"bad config line %d in %s %s\"), cf->linenr, cf->origin_type, cf->name);\n> +\t\terror_return =  error(\"%s\", error_msg);\n\ns/ =  / = /;\n\nThanks.\n"},{"id":"292422","messageId":"20160728161748.GA18515@sigill.intra.peff.net","threadId":"42942","inReplyTo":"1469711643-10367-1-git-send-email-vascomalmeida@sapo.pt","subject":"Re: [PATCH v2] i18n: config: unfold error messages marked for translation","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2016-07-28T16:17:49Z","receivedAt":"2016-07-28T16:17:56Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Jul 28, 2016 at 01:14:03PM +0000, Vasco Almeida wrote:\n\n>  static void die_bad_number(const char *name, const char *value)\n>  {\n> -\tconst char *reason = errno == ERANGE ?\n> -\t\t\t     \"out of range\" :\n> -\t\t\t     \"invalid unit\";\n>  \tif (!value)\n>  \t\tvalue = \"\";\n>  \n> -\tif (cf && cf->origin_type && cf->name)\n> -\t\tdie(_(\"bad numeric config value '%s' for '%s' in %s %s: %s\"),\n> -\t\t    value, name, cf->origin_type, cf->name, reason);\n> -\tdie(_(\"bad numeric config value '%s' for '%s': %s\"), value, name, reason);\n> +\tif (!(cf && cf->name))\n> +\t\tdie(errno == ERANGE\n> +\t\t    ? _(\"bad numeric config value '%s' for '%s': out of range\")\n> +\t\t    : _(\"bad numeric config value '%s' for '%s': invalid unit\"),\n> +\t\t    value, name);\n> +\n> +\tswitch (cf->origin_type) {\n> +\tcase CONFIG_ORIGIN_BLOB:\n> +\t\tdie(errno == ERANGE\n> +\t\t    ? _(\"bad numeric config value '%s' for '%s' in blob %s: out of range\")\n> +\t\t    : _(\"bad numeric config value '%s' for '%s' in blob %s: invalid unit\"),\n> +\t\t    value, name, cf->name);\n\nI get that the point of this patch is to make more complete sentences\nfor translation, rather than the lego-brick construction. And that makes\nsense to me. But it seems like the \":\" is a natural separator, and it\nwould be OK to make these:\n\n  die(_(\"bad numeric config value '%s' for '%s' in blob %s: %s\"),\n\tvalue, name, cf->name, reason);\n\ninstead of having two separate strings for the errno values.  After all,\nthat's what we do everywhere else where \"reason\" is supplied by\nstrerror(). It's just in this case that there is no errno value matching\n\"invalid unit\", so we have to fill it in ourselves.\n\n-Peff\n"}]}