{"thread":{"id":"8259","subject":"[RFC] Implementing git config handling in Git.pm","startedAt":"2007-05-20T22:59:54Z","lastAt":"2007-06-27T02:14:07Z","messageCount":34,"participants":["Frank Lichtenheld","Petr Baudis","Junio C Hamano","Johannes Schindelin","Jan Hudec","Jakub Narebski","David Kastrup"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"42821","messageId":"20070520225953.GK4085@planck.djpig.de","threadId":"8259","inReplyTo":null,"subject":"[RFC] Implementing git config handling in Git.pm","fromName":"Frank Lichtenheld","fromEmail":"frank@lichtenheld.de","sentAt":"2007-05-20T22:59:54Z","receivedAt":"2007-05-20T22:59:54Z","isPatch":false,"sender":{"key":"frank@lichtenheld.de","avatar":"https://gravatar.com/avatar/b9f1d4b120e138f157c9e480d0818197c474628923786adb98f30017cdb99c3c?d=mp&s=160"},"body":"Hi.\n\nA week ago or so when I presented my GITCVS::config patch I mentioned\nthat we should better implement most of it in Git.pm. I would like to\ndo so but get a bit of input first on how to implement it.\n\nTargets:\n 1) We should offer to parse the config only once since that is\n   a huge performance gain if the caller wants to use several\n   values from it.\n 2) The parsing should be complete and safe.\n 3) If at all possible, we should not have to implement a\n   complete parser in Perl, since that is just needless\n   code to maintain.\n\nPossible Solutions:\n 1) Call git-config.\n   Pro: Easy to implement\n   Contra: Violates at least target 2. Neither git-config --get nor\n   git-config --list offer a complete and safe view on the config\n   file. Just try including = in a subsection name (--list) or newlines in\n   a value (both) to see what I mean.\n 2) Extend git-config to give a machine parsable output and then\n    proceed with solution 1\n   Pro: Still reasonably easy to implement (?). Would benefit\n    other scripts, too.\n   Contra: Neither the fastest nor the most flexible\n    solution.\n 3) Try to use the C code from config.c directly.\n   Pro: Probably the fastest solution due to avoiding the\n    forks.\n   Contra: Probably a bit more complex (any XS experts here?),\n    both to implement and to maintain.\n 4) Implement an own git config parser in Perl\n   Pro: Might be actually easier than 3 and faster than 2\n   Contra: See target 3\n\nI would go for solution 2. Any reason to prefer one of the\nothers (or one I didn't even think of)?\n\nGruesse,\n-- \nFrank Lichtenheld <frank@lichtenheld.de>\nwww: http://www.djpig.de/\n"},{"id":"42826","messageId":"20070520231413.GE4489@pasky.or.cz","threadId":"8259","inReplyTo":"20070520225953.GK4085@planck.djpig.de","subject":"Re: [RFC] Implementing git config handling in Git.pm","fromName":"Petr Baudis","fromEmail":"pasky@suse.cz","sentAt":"2007-05-20T23:14:14Z","receivedAt":"2007-05-20T23:14:14Z","isPatch":false,"sender":{"key":"pasky@ucw.cz","avatar":"https://avatars.githubusercontent.com/u/18439?v=4"},"body":"  Hi,\n\nOn Mon, May 21, 2007 at 12:59:54AM CEST, Frank Lichtenheld wrote:\n> Possible Solutions:\n>  1) Call git-config.\n>    Pro: Easy to implement\n>    Contra: Violates at least target 2. Neither git-config --get nor\n>    git-config --list offer a complete and safe view on the config\n>    file. Just try including = in a subsection name (--list) or newlines in\n>    a value (both) to see what I mean.\n>  2) Extend git-config to give a machine parsable output and then\n>     proceed with solution 1\n>    Pro: Still reasonably easy to implement (?). Would benefit\n>     other scripts, too.\n>    Contra: Neither the fastest nor the most flexible\n>     solution.\n\n  Yes, this might be fine for you. The argument for 4 (implementing our\nown in Perl) is that we would like it to be _real_ fast for gitweb\n(especially the summary page needs to look at each repository). But it\nwould be a question of a benchmark to look really how much would calling\ngit-config slow us down. So as at least a proof-of-concept and initial\nimplementation I think this is more than fine, and we can proceed to\nimplement our own parser only when it's clearly needed.\n\n>  3) Try to use the C code from config.c directly.\n>    Pro: Probably the fastest solution due to avoiding the\n>     forks.\n>    Contra: Probably a bit more complex (any XS experts here?),\n>     both to implement and to maintain.\n\n  There was various trouble with XS in the past, and I think the general\nfeel was that we want to get back to using XS again sometime, but only\nwhen Git will be reasonably libified (to support multiple repositories\nat once, etc.).\n\n>  4) Implement an own git config parser in Perl\n>    Pro: Might be actually easier than 3 and faster than 2\n>    Contra: See target 3\n\n-- \n\t\t\t\tPetr \"Pasky\" Baudis\nStuff: http://pasky.or.cz/\nEver try. Ever fail. No matter. // Try again. Fail again. Fail better.\n\t\t-- Samuel Beckett\n"},{"id":"42906","messageId":"11797696193384-git-send-email-frank@lichtenheld.de","threadId":"8259","inReplyTo":"20070520225953.GK4085@planck.djpig.de","subject":"[PATCH] config: Add --quoted option to produce machine-parsable output","fromName":"Frank Lichtenheld","fromEmail":"frank@lichtenheld.de","sentAt":"2007-05-21T17:46:59Z","receivedAt":"2007-05-21T17:46:59Z","isPatch":true,"sender":{"key":"frank@lichtenheld.de","avatar":"https://gravatar.com/avatar/b9f1d4b120e138f157c9e480d0818197c474628923786adb98f30017cdb99c3c?d=mp&s=160"},"body":"This option will enclose key names in quotes (\") if they\ncontain a subsection and then escape \" and \\. It will also\nescape line breaks in values. Together this should produce\nan easily parsable output.\n\nAffects --list and --get-*\n\nSigned-off-by: Frank Lichtenheld <frank@lichtenheld.de>\n---\n builtin-config.c |   92 ++++++++++++++++++++++++++++++++++++++++++++++++-----\n 1 files changed, 83 insertions(+), 9 deletions(-)\n\n Will add asciidoc documentation and test cases if people think that this is\n a good idea.\n\n I'm writing C about once a year, so I really don't mind being told if it's\n crap ;)\n\ndiff --git a/builtin-config.c b/builtin-config.c\nindex b2515f7..454cf4e 100644\n--- a/builtin-config.c\n+++ b/builtin-config.c\n@@ -2,7 +2,7 @@\n #include \"cache.h\"\n \n static const char git_config_set_usage[] =\n-\"git-config [ --global | --system ] [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list\";\n+\"git-config [ --global | --system ] [ --bool | --int ] [--quoted] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list\";\n \n static char *key;\n static regex_t *key_regexp;\n@@ -12,14 +12,73 @@ static int use_key_regexp;\n static int do_all;\n static int do_not_match;\n static int seen;\n+static int quoted;\n static enum { T_RAW, T_INT, T_BOOL } type = T_RAW;\n \n+static char* quote_key(const char *key_)\n+{\n+\tchar *pos1, *pos2;\n+\tchar* key_quot;\n+\n+\tpos1 = strchr(key_, '.');\n+\tpos2 = strrchr(key_, '.');\n+\tif (pos1 != pos2) { /* has subsection */\n+\t\tchar* key;\n+\t\tkey = xmalloc(strlen(key_)*2 + 1);\n+\t\tkey_quot = key;\n+\t\t*key++ = '\"';\n+\t\twhile (*key_) {\n+\t\t\tif (*key_ == '\"' || *key_ == '\\\\')\n+\t\t\t\t*key++ = '\\\\';\n+\t\t\t*key++ = *key_++;\n+\t\t}\n+\t\t*key++ = '\"';\n+\t\t*key = 0;\n+\t} else {\n+\t\tkey_quot = xstrdup(key_);\n+\t}\n+\treturn key_quot;\n+}\n+\n+static char* quote_value(const char* value_)\n+{\n+\tchar *val_quot, *val;\n+\tval = xmalloc(strlen(value_)*2 + 1);\n+\tval_quot = val;\n+\n+\twhile (*value_) {\n+\t\tif (*value_ == '\\n') {\n+\t\t\t*val++ = '\\\\';\n+\t\t\t*val++ = 'n';\n+\t\t\tvalue_ += 2;\n+\t\t} else\n+\t\t\t*val++ = *value_++;\n+\t}\n+\t*val = 0;\n+\n+\treturn val_quot;\n+}\n+\n static int show_all_config(const char *key_, const char *value_)\n {\n-\tif (value_)\n-\t\tprintf(\"%s=%s\\n\", key_, value_);\n-\telse\n-\t\tprintf(\"%s\\n\", key_);\n+\tif (!quoted) {\n+\t\tif (value_)\n+\t\t\tprintf(\"%s=%s\\n\", key_, value_);\n+\t\telse\n+\t\t\tprintf(\"%s\\n\", key_);\n+\t} else {\n+\t\tchar* key_quot = quote_key(key_);\n+\n+\t\tif (value_) {\n+\t\t\tchar* val_quot = quote_value(value_);\n+\t\t\tprintf(\"%s=%s\\n\", key_quot, val_quot);\n+\t\t\tfree(val_quot);\n+\t\t} else\n+\t\t\tprintf(\"%s\\n\", key_quot);\n+\n+\t\tfree(key_quot);\n+\t}\n+\n \treturn 0;\n }\n \n@@ -38,16 +97,26 @@ static int show_config(const char* key_, const char* value_)\n \t\t\t  regexec(regexp, (value_?value_:\"\"), 0, NULL, 0)))\n \t\treturn 0;\n \n-\tif (show_keys)\n-\t\tprintf(\"%s \", key_);\n+\tif (show_keys) {\n+\t\tif (quoted) {\n+\t\t\tchar* key = quote_key(key_);\n+\t\t\tprintf(\"%s \", key);\n+\t\t\tfree(key);\n+\t\t} else\n+\t\t\tprintf(\"%s \", key_);\n+\t}\n \tif (seen && !do_all)\n \t\tdup_error = 1;\n \tif (type == T_INT)\n \t\tsprintf(value, \"%d\", git_config_int(key_, value_?value_:\"\"));\n \telse if (type == T_BOOL)\n \t\tvptr = git_config_bool(key_, value_) ? \"true\" : \"false\";\n-\telse\n-\t\tvptr = value_?value_:\"\";\n+\telse {\n+\t\tif (quoted)\n+\t\t\tvptr = value_?quote_value(value_):\"\";\n+\t\telse\n+\t\t\tvptr = value_?value_:\"\";\n+\t}\n \tseen++;\n \tif (dup_error) {\n \t\terror(\"More than one value for the key %s: %s\",\n@@ -56,6 +125,9 @@ static int show_config(const char* key_, const char* value_)\n \telse\n \t\tprintf(\"%s\\n\", vptr);\n \n+\tif (quoted && value_)\n+\t\tfree((char *)vptr);\n+\n \treturn 0;\n }\n \n@@ -141,6 +213,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)\n \t\t\ttype = T_INT;\n \t\telse if (!strcmp(argv[1], \"--bool\"))\n \t\t\ttype = T_BOOL;\n+\t\telse if (!strcmp(argv[1], \"--quoted\"))\n+\t\t\tquoted = 1;\n \t\telse if (!strcmp(argv[1], \"--list\") || !strcmp(argv[1], \"-l\"))\n \t\t\treturn git_config(show_all_config);\n \t\telse if (!strcmp(argv[1], \"--global\")) {\n-- \n1.5.2-rc3.GIT\n"},{"id":"42908","messageId":"7vejladpfr.fsf@assigned-by-dhcp.cox.net","threadId":"8259","inReplyTo":"11797696193384-git-send-email-frank@lichtenheld.de","subject":"Re: [PATCH] config: Add --quoted option to produce machine-parsable output","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-05-21T18:03:36Z","receivedAt":"2007-05-21T18:03:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Frank Lichtenheld <frank@lichtenheld.de> writes:\n\n> This option will enclose key names in quotes (\") if they\n> contain a subsection and then escape \" and \\. It will also\n> escape line breaks in values. Together this should produce\n> an easily parsable output.\n>\n> Affects --list and --get-*\n>\n> Signed-off-by: Frank Lichtenheld <frank@lichtenheld.de>\n> ---\n>  builtin-config.c |   92 ++++++++++++++++++++++++++++++++++++++++++++++++-----\n>  1 files changed, 83 insertions(+), 9 deletions(-)\n>\n>  Will add asciidoc documentation and test cases if people think that this is\n>  a good idea.\n>\n>  I'm writing C about once a year, so I really don't mind being told if it's\n>  crap ;)\n\nWe probably would want to make this compatible with the quoting\nrules various fo \"host\" language have.  quote.c has host\nlanguage support to implement {perl,python,tcl}_quote_print()\nfor single string values or keys, so we should extend that idea.\n\nIn your application, what you are trying to do is to show a\n\"hash\" (key => value) in a notation that is friendly to the host\nlanguage.\n\nGit.pm could simply do:\n\n\tmy $eval = `git config --perl --get-regexp 'gitcvs\\..*'`;\n\tmy $cfg = eval \"$eval\";\n\nif you code your \"perl\" notation to produce:\n\n\t+{\n\t\t'gitcvs.ext.enabled' => 'false',\n                'gitcvs.logfile' => '/var/log/gitcvs.log',\n\t}\n\nin order to read things in.\n\nHmm?\n"},{"id":"42915","messageId":"Pine.LNX.4.64.0705211945470.6410@racer.site","threadId":"8259","inReplyTo":"7vejladpfr.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] config: Add --quoted option to produce machine-parsable output","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-05-21T18:46:54Z","receivedAt":"2007-05-21T18:46:54Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 21 May 2007, Junio C Hamano wrote:\n\n> Frank Lichtenheld <frank@lichtenheld.de> writes:\n> \n> > This option will enclose key names in quotes (\") if they\n> > contain a subsection and then escape \" and \\. It will also\n> > escape line breaks in values. Together this should produce\n> > an easily parsable output.\n> >\n> > Affects --list and --get-*\n> >\n> > Signed-off-by: Frank Lichtenheld <frank@lichtenheld.de>\n> > ---\n> >  builtin-config.c |   92 ++++++++++++++++++++++++++++++++++++++++++++++++-----\n> >  1 files changed, 83 insertions(+), 9 deletions(-)\n> >\n> > Will add asciidoc documentation and test cases if people think that \n> > this is a good idea.\n> >\n> > I'm writing C about once a year, so I really don't mind being told if \n> > it's crap ;)\n> \n> We probably would want to make this compatible with the quoting rules \n> various fo \"host\" language have.  quote.c has host language support to \n> implement {perl,python,tcl}_quote_print() for single string values or \n> keys, so we should extend that idea.\n> \n> In your application, what you are trying to do is to show a \"hash\" (key \n> => value) in a notation that is friendly to the host language.\n> \n> Git.pm could simply do:\n> \n> \tmy $eval = `git config --perl --get-regexp 'gitcvs\\..*'`;\n> \tmy $cfg = eval \"$eval\";\n> \n> if you code your \"perl\" notation to produce:\n> \n> \t+{\n> \t\t'gitcvs.ext.enabled' => 'false',\n>                 'gitcvs.logfile' => '/var/log/gitcvs.log',\n> \t}\n> \n> in order to read things in.\n> \n> Hmm?\n\nIOW, something like \nhttp://article.gmane.org/gmane.comp.version-control.git/36922\n\nHmm?\n\nCiao,\nDscho\n"},{"id":"42918","messageId":"20070521195423.GC5082@efreet.light.src","threadId":"8259","inReplyTo":"11797696193384-git-send-email-frank@lichtenheld.de","subject":"Re: [PATCH] config: Add --quoted option to produce machine-parsable output","fromName":"Jan Hudec","fromEmail":"bulb@ucw.cz","sentAt":"2007-05-21T19:54:23Z","receivedAt":"2007-05-21T19:54:23Z","isPatch":true,"sender":{"key":"bulb@ucw.cz","avatar":null},"body":"On Mon, May 21, 2007 at 19:46:59 +0200, Frank Lichtenheld wrote:\n> This option will enclose key names in quotes (\") if they\n> contain a subsection and then escape \" and \\. It will also\n> escape line breaks in values. Together this should produce\n> an easily parsable output.\n\nThat will lead to either eval (which runs perl parser and probably won't win\nanything) or regexps (which is not big win over parsing the .ini directly\nwith them) on the perl side. IMHO only thing that would actually be faster is\nNUL-separated entries.\n\nEither:\n    KEY <NUL> VALUE <NUL>\n\nor:\n    KEY <TAB> VALUE <NUL>\n\nI am not sure whether there can be multi-valued entries. If so, than there\nare three options:\n\n1. Simply repeated key/value pairs:\n   KEY <NUL> VALUE1 <NUL> KEY <NUL> VALUE2 <NUL>.\n   KEY <TAB> VALUE1 <NUL> KEY <TAB> VALUE2 <NUL> resp.\n\n2. Key/count/values:\n   KEY <NUL> 1 <NUL> VALUE <NUL>\n   KEY <NUL> 2 <NUL> VALUE1 <NUL> VALUE2 <NUL>\n   (there's probably no benefit for the tab-nul format, because the first\n   value must be terminated with NUL)\n\n3. Empty-entry terminated:\n   KEY <NUL> VALUE <NUL> <NUL>\n   KEY <NUL> VALUE1 <NUL> VALUE2 <NUL> <NUL>\n   (again no point in terminating the KEY with tab)\n\nThe advantage of such format is, that it can be parsed with:\n    local $/ = \"\\0\";\n    while(<INPUT>) {\n\t$hash{$_} = <INPUT>;\n    }\nand slight variations for the other variants. It should be similarly easy\nfrom python and C. Shell won't like it, though.\n\nNote: In both bash and zsh, read -d '' line reads NUL-terminated \"lines\".\nHowever, dash does not have -d option to read :-(.\n\n-- \n\t\t\t\t\t\t Jan 'Bulb' Hudec <bulb@ucw.cz>\n"},{"id":"42925","messageId":"20070521205812.GO4085@planck.djpig.de","threadId":"8259","inReplyTo":"20070521195423.GC5082@efreet.light.src","subject":"Re: [PATCH] config: Add --quoted option to produce machine-parsable output","fromName":"Frank Lichtenheld","fromEmail":"frank@lichtenheld.de","sentAt":"2007-05-21T20:58:12Z","receivedAt":"2007-05-21T20:58:12Z","isPatch":true,"sender":{"key":"frank@lichtenheld.de","avatar":"https://gravatar.com/avatar/b9f1d4b120e138f157c9e480d0818197c474628923786adb98f30017cdb99c3c?d=mp&s=160"},"body":"On Mon, May 21, 2007 at 09:54:23PM +0200, Jan Hudec wrote:\n> On Mon, May 21, 2007 at 19:46:59 +0200, Frank Lichtenheld wrote:\n> > This option will enclose key names in quotes (\") if they\n> > contain a subsection and then escape \" and \\. It will also\n> > escape line breaks in values. Together this should produce\n> > an easily parsable output.\n> \n> That will lead to either eval (which runs perl parser and probably won't win\n> anything) or regexps (which is not big win over parsing the .ini directly\n> with them) on the perl side. IMHO only thing that would actually be faster is\n> NUL-separated entries.\n\n> Either:\n>     KEY <NUL> VALUE <NUL>\n> \n> or:\n>     KEY <TAB> VALUE <NUL>\n\nBoth subsection names and values can contain <TAB> characters, so the\nlatter isn't possible.\n\nGruesse,\n-- \nFrank Lichtenheld <frank@lichtenheld.de>\nwww: http://www.djpig.de/\n"},{"id":"42928","messageId":"7vbqgddgff.fsf@assigned-by-dhcp.cox.net","threadId":"8259","inReplyTo":"Pine.LNX.4.64.0705211945470.6410@racer.site","subject":"Re: [PATCH] config: Add --quoted option to produce machine-parsable output","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-05-21T21:18:12Z","receivedAt":"2007-05-21T21:18:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> Git.pm could simply do:\n>> \n>> \tmy $eval = `git config --perl --get-regexp 'gitcvs\\..*'`;\n>> \tmy $cfg = eval \"$eval\";\n>> \n>> if you code your \"perl\" notation to produce:\n>> \n>> \t+{\n>> \t\t'gitcvs.ext.enabled' => 'false',\n>>                 'gitcvs.logfile' => '/var/log/gitcvs.log',\n>> \t}\n>> \n>> in order to read things in.\n>> \n>> Hmm?\n>\n> IOW, something like \n> http://article.gmane.org/gmane.comp.version-control.git/36922\n\nIndeed (perhaps except fixing minor details like not hijacking\nthe variable name).  Care to resubmit with docs and tests?\n"},{"id":"42930","messageId":"Pine.LNX.4.64.0705212252570.6410@racer.site","threadId":"8259","inReplyTo":"7vbqgddgff.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] config: Add --quoted option to produce machine-parsable output","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-05-21T21:53:34Z","receivedAt":"2007-05-21T21:53:34Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 21 May 2007, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> Git.pm could simply do:\n> >> \n> >> \tmy $eval = `git config --perl --get-regexp 'gitcvs\\..*'`;\n> >> \tmy $cfg = eval \"$eval\";\n> >> \n> >> if you code your \"perl\" notation to produce:\n> >> \n> >> \t+{\n> >> \t\t'gitcvs.ext.enabled' => 'false',\n> >>                 'gitcvs.logfile' => '/var/log/gitcvs.log',\n> >> \t}\n> >> \n> >> in order to read things in.\n> >> \n> >> Hmm?\n> >\n> > IOW, something like \n> > http://article.gmane.org/gmane.comp.version-control.git/36922\n> \n> Indeed (perhaps except fixing minor details like not hijacking\n> the variable name).  Care to resubmit with docs and tests?\n\nWell, my version was not good, as Eric pointed out.\n\nDo you want me to clean up Eric's version (according to my own comments, \nthat is)?\n\nCiao,\nDscho\n"},{"id":"42931","messageId":"f2t6na$5bi$1@sea.gmane.org","threadId":"8259","inReplyTo":"20070521205812.GO4085@planck.djpig.de","subject":"Re: [PATCH] config: Add --quoted option to produce machine-parsable output","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-05-21T22:37:57Z","receivedAt":"2007-05-21T22:37:57Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Frank Lichtenheld wrote:\n\n> On Mon, May 21, 2007 at 09:54:23PM +0200, Jan Hudec wrote:\n>> On Mon, May 21, 2007 at 19:46:59 +0200, Frank Lichtenheld wrote:\n>> > This option will enclose key names in quotes (\") if they\n>> > contain a subsection and then escape \" and \\. It will also\n>> > escape line breaks in values. Together this should produce\n>> > an easily parsable output.\n>> \n>> That will lead to either eval (which runs perl parser and probably won't win\n>> anything) or regexps (which is not big win over parsing the .ini directly\n>> with them) on the perl side. IMHO only thing that would actually be faster is\n>> NUL-separated entries.\n> \n>> Either:\n>>     KEY <NUL> VALUE <NUL>\n>> \n>> or:\n>>     KEY <TAB> VALUE <NUL>\n> \n> Both subsection names and values can contain <TAB> characters, so the\n> latter isn't possible.\n\nBut neither subsection names (even [section \"subsection\"] style) not key\nnames cannot contain newline <LF>. I.e.\n\n        KEY <LF> VALUE <NUL>\n\n-- \nJakub Narebski\nWarsaw, Poland\nShadeHawk on #git\n"},{"id":"45249","messageId":"11821227322913-git-send-email-frank@lichtenheld.de","threadId":"8259","inReplyTo":"f2t6na$5bi$1@sea.gmane.org","subject":"[PATCH/RFC] config: Add --null/-z option for null-delimted output","fromName":"Frank Lichtenheld","fromEmail":"frank@lichtenheld.de","sentAt":"2007-06-17T23:25:32Z","receivedAt":"2007-06-17T23:25:32Z","isPatch":true,"sender":{"key":"frank@lichtenheld.de","avatar":"https://gravatar.com/avatar/b9f1d4b120e138f157c9e480d0818197c474628923786adb98f30017cdb99c3c?d=mp&s=160"},"body":"Use \\n as delimiter between key and value and \\0 as\ndelimiter after each key/value pair. This should be\neasily parsable output.\n\nSigned-off-by: Frank Lichtenheld <frank@lichtenheld.de>\n---\n builtin-config.c |   15 +++++++++++----\n 1 files changed, 11 insertions(+), 4 deletions(-)\n\n Note the FIXME. Does anyone remember the reason why --get-regexp\n and --list use different output format?\n\n On Tue, May 22, 2007 at 12:37:57AM +0200, Jakub Narebski wrote:\n > Frank Lichtenheld wrote:\n > > On Mon, May 21, 2007 at 09:54:23PM +0200, Jan Hudec wrote:\n > >>     KEY <TAB> VALUE <NUL>\n > > Both subsection names and values can contain <TAB> characters, so the\n > > latter isn't possible.\n > But neither subsection names (even [section \"subsection\"] style) not key\n > names cannot contain newline <LF>. I.e.\n >         KEY <LF> VALUE <NUL>\n\ndiff --git a/builtin-config.c b/builtin-config.c\nindex b2515f7..bed2722 100644\n--- a/builtin-config.c\n+++ b/builtin-config.c\n@@ -2,7 +2,7 @@\n #include \"cache.h\"\n \n static const char git_config_set_usage[] =\n-\"git-config [ --global | --system ] [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list\";\n+\"git-config [ --global | --system ] [ --bool | --int ] [ -z | --null ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list\";\n \n static char *key;\n static regex_t *key_regexp;\n@@ -12,14 +12,16 @@ static int use_key_regexp;\n static int do_all;\n static int do_not_match;\n static int seen;\n+static char delim = '=';\n+static char term = '\\n';\n static enum { T_RAW, T_INT, T_BOOL } type = T_RAW;\n \n static int show_all_config(const char *key_, const char *value_)\n {\n \tif (value_)\n-\t\tprintf(\"%s=%s\\n\", key_, value_);\n+\t\tprintf(\"%s%c%s%c\", key_, delim, value_, term);\n \telse\n-\t\tprintf(\"%s\\n\", key_);\n+\t\tprintf(\"%s%c\", key_, term);\n \treturn 0;\n }\n \n@@ -39,6 +41,7 @@ static int show_config(const char* key_, const char* value_)\n \t\treturn 0;\n \n \tif (show_keys)\n+\t\t/* FIXME: not useful with --null */\n \t\tprintf(\"%s \", key_);\n \tif (seen && !do_all)\n \t\tdup_error = 1;\n@@ -54,7 +57,7 @@ static int show_config(const char* key_, const char* value_)\n \t\t\t\tkey_, vptr);\n \t}\n \telse\n-\t\tprintf(\"%s\\n\", vptr);\n+\t\tprintf(\"%s%c\", vptr, term);\n \n \treturn 0;\n }\n@@ -155,6 +158,10 @@ int cmd_config(int argc, const char **argv, const char *prefix)\n \t\t}\n \t\telse if (!strcmp(argv[1], \"--system\"))\n \t\t\tsetenv(\"GIT_CONFIG\", ETC_GITCONFIG, 1);\n+\t\telse if (!strcmp(argv[1], \"--null\") || !strcmp(argv[1], \"-z\")) {\n+\t\t\tterm = '\\0';\n+\t\t\tdelim = '\\n';\n+\t\t}\n \t\telse if (!strcmp(argv[1], \"--rename-section\")) {\n \t\t\tint ret;\n \t\t\tif (argc != 4)\n-- \n1.5.2.1\n"},{"id":"45303","messageId":"Pine.LNX.4.64.0706190151160.4059@racer.site","threadId":"8259","inReplyTo":"11821227322913-git-send-email-frank@lichtenheld.de","subject":"Re: [PATCH/RFC] config: Add --null/-z option for null-delimted output","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-06-19T00:55:24Z","receivedAt":"2007-06-19T00:55:24Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 18 Jun 2007, Frank Lichtenheld wrote:\n\n>  Note the FIXME. Does anyone remember the reason why --get-regexp\n>  and --list use different output format?\n\nAFAIK --list was meant as a replacement to git-var --list. Thus, it had to \nbehave exactly the same.\n\nAs for the FIXME: If you have a config like this:\n\n\t[core]\n\t\tSome = where\n\t\tover\n\t\tthe = core.rainbow\n\ngit-config -z would output something like this:\n\n\tcore.some\\0where\\0core.over\\0core.the\\0core.rainbow\\0\n\nRight?\n\nAs you can see, it is quite hard for a parser to find out what is key, and \nwhat is value. That FIXME is _exactly_ about this dilemma.\n\nIIRC I stated once that -z should output a value of \"true\" for these \ncases, since they only make sense as booleans. But AFAIR nothing \nconclusive came out of that thread.\n\nCiao,\nDscho\n"},{"id":"45307","messageId":"200706190316.33340.jnareb@gmail.com","threadId":"8259","inReplyTo":"Pine.LNX.4.64.0706190151160.4059@racer.site","subject":"Re: [PATCH/RFC] config: Add --null/-z option for null-delimted output","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-06-19T01:16:32Z","receivedAt":"2007-06-19T01:16:32Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Johannes Schindelin wrote:\n\n> As for the FIXME: [...]\n\nPlease read original message carefully:\n\n>>  Note the FIXME. Does anyone remember the reason why --get-regexp\n>>  and --list use different output format?\n\nI think the FIXME is for --get-regexp. And was added by the patch.\n\n> If you have a config like this: \n> \n>         [core]\n>                 Some = where\n>                 over\n>                 the = core.rainbow\n> \n> git-config -z would output something like this:\n> \n>         core.some\\0where\\0core.over\\0core.the\\0core.rainbow\\0\n> \n> Right?\n\nFalse. Delim is different from term. You would get\n\n\tcore.some\\nwhere\\0core.over\\0core.the\\ncore.rainbow\\0\n\n> As you can see, it is quite hard for a parser to find out what is\n> key, and what is value.\n\n\tlocal $/ = \"\\0\";\n\n\twhile (my $line = <$fd>) {\n\t\tchomp $line;\n\t\tmy ($key, $value) = split(/\\n/, $line, 2);\n\n\t\tpush @{$config{$key}}, $value if defined $key;\n\t}\n\n-- \nJakub Narebski\nPoland\n"},{"id":"45308","messageId":"20070619011734.GD19725@planck.djpig.de","threadId":"8259","inReplyTo":"Pine.LNX.4.64.0706190151160.4059@racer.site","subject":"Re: [PATCH/RFC] config: Add --null/-z option for null-delimted output","fromName":"Frank Lichtenheld","fromEmail":"frank@lichtenheld.de","sentAt":"2007-06-19T01:17:34Z","receivedAt":"2007-06-19T01:17:34Z","isPatch":true,"sender":{"key":"frank@lichtenheld.de","avatar":"https://gravatar.com/avatar/b9f1d4b120e138f157c9e480d0818197c474628923786adb98f30017cdb99c3c?d=mp&s=160"},"body":"On Tue, Jun 19, 2007 at 01:55:24AM +0100, Johannes Schindelin wrote:\n> Hi,\n> \n> On Mon, 18 Jun 2007, Frank Lichtenheld wrote:\n> \n> >  Note the FIXME. Does anyone remember the reason why --get-regexp\n> >  and --list use different output format?\n> \n> AFAIK --list was meant as a replacement to git-var --list. Thus, it had to \n> behave exactly the same.\n> \n> As for the FIXME: If you have a config like this:\n> \n> \t[core]\n> \t\tSome = where\n> \t\tover\n> \t\tthe = core.rainbow\n> \n> git-config -z would output something like this:\n> \n> \tcore.some\\0where\\0core.over\\0core.the\\0core.rainbow\\0\n> \n> Right?\n\nNo. At least not with my patch. As you noted that would be\nincredibly stupid and worthless. Instead we output something like\n\ncore.some\\nwhere\\0core.over\\0core.the\\ncore.rainbow\\0\n\nSo you just can split on \\0 and then split on \\n. If there is\nno \\n between two \\0, you have a key without value.\n\nGruesse,\n-- \nFrank Lichtenheld <frank@lichtenheld.de>\nwww: http://www.djpig.de/\n"},{"id":"45309","messageId":"Pine.LNX.4.64.0706190232550.4059@racer.site","threadId":"8259","inReplyTo":"20070619011734.GD19725@planck.djpig.de","subject":"Re: [PATCH/RFC] config: Add --null/-z option for null-delimted output","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-06-19T01:32:59Z","receivedAt":"2007-06-19T01:32:59Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 19 Jun 2007, Frank Lichtenheld wrote:\n\n> Instead we output something like\n> \n> core.some\\nwhere\\0core.over\\0core.the\\ncore.rainbow\\0\n\nAh, I missed that. Maybe because I expected \"--null\" not to be \n\"--newline-and-null\" ;-)\n\nCiao,\nDscho\n"},{"id":"45311","messageId":"7v645kyba8.fsf@assigned-by-dhcp.pobox.com","threadId":"8259","inReplyTo":"Pine.LNX.4.64.0706190151160.4059@racer.site","subject":"Re: [PATCH/RFC] config: Add --null/-z option for null-delimted output","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-06-19T01:37:35Z","receivedAt":"2007-06-19T01:37:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> As for the FIXME: If you have a config like this:\n>\n> \t[core]\n> \t\tSome = where\n> \t\tover\n> \t\tthe = core.rainbow\n>\n> git-config -z would output something like this:\n>\n> \tcore.some\\0where\\0core.over\\0core.the\\0core.rainbow\\0\n>\n> Right?\n>\n> As you can see, it is quite hard for a parser to find out what is key, and \n> what is value. That FIXME is _exactly_ about this dilemma.\n>\n> IIRC I stated once that -z should output a value of \"true\" for these \n> cases, since they only make sense as booleans. But AFAIR nothing \n> conclusive came out of that thread.\n\nI do not remember the thread, but I think that may make sense.\n\"over = 1\", \"over = true\" etc. cannot be canonicalized to \"true\"\nwithout knowing core.over is boolean, but core.over by itself\nwithout any assignment cannot be anything but a boolean.\n\nAnother possibility, though, is to say:\n\n\tcore.some\\0where\\0core.over\\0\\0core.the\\0core.rainbow\\0\n"},{"id":"45312","messageId":"20070619021252.GE19725@planck.djpig.de","threadId":"8259","inReplyTo":"7v645kyba8.fsf@assigned-by-dhcp.pobox.com","subject":"Re: [PATCH/RFC] config: Add --null/-z option for null-delimted output","fromName":"Frank Lichtenheld","fromEmail":"frank@lichtenheld.de","sentAt":"2007-06-19T02:12:52Z","receivedAt":"2007-06-19T02:12:52Z","isPatch":true,"sender":{"key":"frank@lichtenheld.de","avatar":"https://gravatar.com/avatar/b9f1d4b120e138f157c9e480d0818197c474628923786adb98f30017cdb99c3c?d=mp&s=160"},"body":"On Mon, Jun 18, 2007 at 06:37:35PM -0700, Junio C Hamano wrote:\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> Another possibility, though, is to say:\n> \n> \tcore.some\\0where\\0core.over\\0\\0core.the\\0core.rainbow\\0\n\nHow do you denote empty values then?\n\n[section]\n\tkey=\n\tkey\n\nthis are two very different statements atm (e.g. the one is false and\nthe other one is true).\n\nI still think using two different delimiters is the simplest choice.\n\nGruesse,\n-- \nFrank Lichtenheld <frank@lichtenheld.de>\nwww: http://www.djpig.de/\n"},{"id":"45339","messageId":"Pine.LNX.4.64.0706191208300.4059@racer.site","threadId":"8259","inReplyTo":"20070619021252.GE19725@planck.djpig.de","subject":"Re: [PATCH/RFC] config: Add --null/-z option for null-delimted output","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-06-19T11:09:18Z","receivedAt":"2007-06-19T11:09:18Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 19 Jun 2007, Frank Lichtenheld wrote:\n\n> On Mon, Jun 18, 2007 at 06:37:35PM -0700, Junio C Hamano wrote:\n> > Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> > Another possibility, though, is to say:\n> > \n> > \tcore.some\\0where\\0core.over\\0\\0core.the\\0core.rainbow\\0\n> \n> How do you denote empty values then?\n> \n> [section]\n> \tkey=\n> \tkey\n> \n> this are two very different statements atm (e.g. the one is false and\n> the other one is true).\n> \n> I still think using two different delimiters is the simplest choice.\n\nOkay, good point. But of course, you have to use a delimiter for the key \nname that cannot be part of the keyname. You picked '\\n'. The original was \n'='. Both work.\n\nCiao,\nDscho\n"},{"id":"45342","messageId":"86myywtcn3.fsf@lola.quinscape.zz","threadId":"8259","inReplyTo":"Pine.LNX.4.64.0706191208300.4059@racer.site","subject":"Re: [PATCH/RFC] config: Add --null/-z option for null-delimted output","fromName":"David Kastrup","fromEmail":"dak@gnu.org","sentAt":"2007-06-19T11:19:28Z","receivedAt":"2007-06-19T11:19:28Z","isPatch":true,"sender":{"key":"dak@gnu.org","avatar":"https://avatars.githubusercontent.com/u/52141349?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> Hi,\n>\n> On Tue, 19 Jun 2007, Frank Lichtenheld wrote:\n>\n>> On Mon, Jun 18, 2007 at 06:37:35PM -0700, Junio C Hamano wrote:\n>> > Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n>> > Another possibility, though, is to say:\n>> > \n>> > \tcore.some\\0where\\0core.over\\0\\0core.the\\0core.rainbow\\0\n>> \n>> How do you denote empty values then?\n>> \n>> [section]\n>> \tkey=\n>> \tkey\n>> \n>> this are two very different statements atm (e.g. the one is false and\n>> the other one is true).\n>> \n>> I still think using two different delimiters is the simplest choice.\n>\n> Okay, good point. But of course, you have to use a delimiter for the key \n> name that cannot be part of the keyname. You picked '\\n'. The original was \n> '='. Both work.\n\nIn the interest of simplicity, it would appear reasonable to use just\n= and not introduce an additional delimiter.  This is similar to how\nenvironments are handled and passed in Unix (though not necessarily\nrelevant).\n\n-- \nDavid Kastrup\n"},{"id":"45364","messageId":"200706191350.34714.jnareb@gmail.com","threadId":"8259","inReplyTo":"Pine.LNX.4.64.0706191208300.4059@racer.site","subject":"Re: [PATCH/RFC] config: Add --null/-z option for null-delimted output","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-06-19T11:50:34Z","receivedAt":"2007-06-19T11:50:34Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Johannes Schindelin wrote:\n> On Tue, 19 Jun 2007, Frank Lichtenheld wrote:\n>> On Mon, Jun 18, 2007 at 06:37:35PM -0700, Junio C Hamano wrote:\n\n>>> Another possibility, though, is to say:\n>>> \n>>> \tcore.some\\0where\\0core.over\\0\\0core.the\\0core.rainbow\\0\n>> \n>> How do you denote empty values then?\n>> \n>> [section]\n>> \tkey=\n>> \tkey\n>> \n>> this are two very different statements atm (e.g. the one is false and\n>> the other one is true).\n>> \n>> I still think using two different delimiters is the simplest choice.\n> \n> Okay, good point. But of course, you have to use a delimiter for the key \n> name that cannot be part of the keyname. You picked '\\n'. The original was \n> '='. Both work.\n\nIf I remember correctly (and what I checked to be true), while '=' cannot\nbe part of keyname nor section name, it can be part of subsection name,\ntherefore it can be part of fuly qualified key name.\n\nThe '\\n' can _not_ be part of subsection name, therefore it can not be\npart of fully qualified key name.\n\n  $ cat > conftest <<EOF\n  [section \"sub=section\"]\n       truekey=true\n       emptykey=\n       novalkey\n  EOF\n\n  $ GIT_CONFIG=conftest git-config -l\n  section.sub=section.truekey=true\n  section.sub=section.emptykey=\n  section.sub=section.novalkey\n\n-- \nJakub Narebski\nPoland\n"},{"id":"45361","messageId":"20070619152139.GF19725@planck.djpig.de","threadId":"8259","inReplyTo":"Pine.LNX.4.64.0706191208300.4059@racer.site","subject":"Re: [PATCH/RFC] config: Add --null/-z option for null-delimted output","fromName":"Frank Lichtenheld","fromEmail":"frank@lichtenheld.de","sentAt":"2007-06-19T15:21:40Z","receivedAt":"2007-06-19T15:21:40Z","isPatch":true,"sender":{"key":"frank@lichtenheld.de","avatar":"https://gravatar.com/avatar/b9f1d4b120e138f157c9e480d0818197c474628923786adb98f30017cdb99c3c?d=mp&s=160"},"body":"On Tue, Jun 19, 2007 at 12:09:18PM +0100, Johannes Schindelin wrote:\n> Okay, good point. But of course, you have to use a delimiter for the key \n> name that cannot be part of the keyname. You picked '\\n'. The original was \n> '='. Both work.\n\nNo, they actually don't.\n\nExample:\n\n$ cat .git/config\n[foo \"bar=baz\"]\n\tkey = value\n[foo]\n\tkey = key=value\n$ git config -l\nfoo.bar=baz.key=value\nfoo.key=key=value\n\nSo how do I parse that?\n\nGruesse,\n-- \nFrank Lichtenheld <frank@lichtenheld.de>\nwww: http://www.djpig.de/\n"},{"id":"45363","messageId":"Pine.LNX.4.64.0706191655490.4059@racer.site","threadId":"8259","inReplyTo":"20070619152139.GF19725@planck.djpig.de","subject":"Re: [PATCH/RFC] config: Add --null/-z option for null-delimted output","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-06-19T15:57:21Z","receivedAt":"2007-06-19T15:57:21Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 19 Jun 2007, Frank Lichtenheld wrote:\n\n> On Tue, Jun 19, 2007 at 12:09:18PM +0100, Johannes Schindelin wrote:\n> > Okay, good point. But of course, you have to use a delimiter for the key \n> > name that cannot be part of the keyname. You picked '\\n'. The original was \n> > '='. Both work.\n> \n> No, they actually don't.\n\nRight, I completely forgot that we actually allow all kinds of special \ncharacters, in order to be able to say \"branch.<branchname>.merge\" for all \nkinds of branchnames.\n\nIncidentally, I think I found a bug:\n\n[foo \"bar\\nbaz\"]\n\tkey = value\n\ngives\n\nfoo.barbaz.key=value\n\nCiao,\nDscho\n"},{"id":"45370","messageId":"20070619172619.GH19725@planck.djpig.de","threadId":"8259","inReplyTo":"Pine.LNX.4.64.0706191655490.4059@racer.site","subject":"Re: [PATCH/RFC] config: Add --null/-z option for null-delimted output","fromName":"Frank Lichtenheld","fromEmail":"frank@lichtenheld.de","sentAt":"2007-06-19T17:26:19Z","receivedAt":"2007-06-19T17:26:19Z","isPatch":true,"sender":{"key":"frank@lichtenheld.de","avatar":"https://gravatar.com/avatar/b9f1d4b120e138f157c9e480d0818197c474628923786adb98f30017cdb99c3c?d=mp&s=160"},"body":"On Tue, Jun 19, 2007 at 04:57:21PM +0100, Johannes Schindelin wrote:\n> [foo \"bar\\nbaz\"]\n> \tkey = value\n> gives\n> \n> foo.barbaz.key=value\n\nfor me this gives\n\nfoo.barnbaz.key=value\n\nwhich is the intended behaviour AFAICT\n(you mean the actual string '\\' 'n' here, right? '\\n' gives a syntax\nerror, also the intended behaviour)\n\nGruesse,\n-- \nFrank Lichtenheld <frank@lichtenheld.de>\nwww: http://www.djpig.de/\n"},{"id":"45427","messageId":"Pine.LNX.4.64.0706201129550.4059@racer.site","threadId":"8259","inReplyTo":"20070619172619.GH19725@planck.djpig.de","subject":"Re: [PATCH/RFC] config: Add --null/-z option for null-delimted output","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-06-20T10:31:02Z","receivedAt":"2007-06-20T10:31:02Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Tue, 19 Jun 2007, Frank Lichtenheld wrote:\n\n> On Tue, Jun 19, 2007 at 04:57:21PM +0100, Johannes Schindelin wrote:\n> > [foo \"bar\\nbaz\"]\n> > \tkey = value\n> > gives\n> > \n> > foo.barbaz.key=value\n> \n> for me this gives\n> \n> foo.barnbaz.key=value\n\nYes, of course I had to have a typo in my message. *sigh*\n\nThe point is, that I would not expect a \"\\\" to be _ignored_. Either \ninterpreted, or throwing an error, but just ignored?\n\nCiao,\nDscho\n"},{"id":"45433","messageId":"200706201854.41571.jnareb@gmail.com","threadId":"8259","inReplyTo":"Pine.LNX.4.64.0706201129550.4059@racer.site","subject":"Re: [PATCH/RFC] config: Add --null/-z option for null-delimted output","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-06-20T16:54:40Z","receivedAt":"2007-06-20T16:54:40Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Johannes Schindelin wrote:\n> On Tue, 19 Jun 2007, Frank Lichtenheld wrote:\n> > On Tue, Jun 19, 2007 at 04:57:21PM +0100, Johannes Schindelin wrote:\n\n> > > [foo \"bar\\nbaz\"]\n> > > \tkey = value\n> > > gives\n> > > \n> > > foo.barbaz.key=value\n> > \n> > for me this gives\n> > \n> > foo.barnbaz.key=value\n> \n> Yes, of course I had to have a typo in my message. *sigh*\n> \n> The point is, that I would not expect a \"\\\" to be _ignored_. Either \n> interpreted, or throwing an error, but just ignored?\n\nIt is interpreted. Perhaps not what you thought it is interpreted, but \nit is interpreted. '\\x' => 'x' for 'x' which are not in some limited \nset. ;-)))\n\n-- \nJakub Narebski\nPoland\n"},{"id":"45532","messageId":"200706220156.01175.jnareb@gmail.com","threadId":"8259","inReplyTo":"11821227322913-git-send-email-frank@lichtenheld.de","subject":"Re: [PATCH/RFC] config: Add --null/-z option for null-delimted output","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-06-21T23:56:00Z","receivedAt":"2007-06-21T23:56:00Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"On Mon, 18 Jun 2007, Frank Lichtenheld wrote:\n> Use \\n as delimiter between key and value and \\0 as\n> delimiter after each key/value pair. This should be\n> easily parsable output.\n> \n> Signed-off-by: Frank Lichtenheld <frank@lichtenheld.de>\n> ---\n>  builtin-config.c |   15 +++++++++++----\n>  1 files changed, 11 insertions(+), 4 deletions(-)\n\nNo documentation. But this is an RFC.\n \n>  Note the FIXME. Does anyone remember the reason why --get-regexp\n>  and --list use different output format?\n\nI don't know, but at least two scripts use --get-regexp, namely\ngit-remote and git-submodule. So we would have to be careful about\nchanging that.\n \n\nI would be enough to add the following to your patch:\n\n> @@ -12,14 +12,16 @@ static int use_key_regexp;\n>  static int do_all;\n>  static int do_not_match;\n>  static int seen;\n> +static char delim = '=';\n> +static char term = '\\n';\n  +static char key_delim = ' ';\n>  static enum { T_RAW, T_INT, T_BOOL } type = T_RAW;\n[...]\n> @@ -39,6 +41,7 @@ static int show_config(const char* key_, const char* value_)\n>  \t\treturn 0;\n>  \n>  \tif (show_keys)\n> +\t\t/* FIXME: not useful with --null */\n  - \t\tprintf(\"%s \", key_);\n  + \t\tprintf(\"%s%c\", key_, key_delim);\n>  \tif (seen && !do_all)\n>  \t\tdup_error = 1;\n[...]\n> @@ -155,6 +158,10 @@ int cmd_config(int argc, const char **argv, const char *prefix)\n>  \t\t}\n>  \t\telse if (!strcmp(argv[1], \"--system\"))\n>  \t\t\tsetenv(\"GIT_CONFIG\", ETC_GITCONFIG, 1);\n> +\t\telse if (!strcmp(argv[1], \"--null\") || !strcmp(argv[1], \"-z\")) {\n> +\t\t\tterm = '\\0';\n> +\t\t\tdelim = '\\n';\n  +\t\t\tkey_delim = '\\n';\n> +\t\t}\n>  \t\telse if (!strcmp(argv[1], \"--rename-section\")) {\n>  \t\t\tint ret;\n>  \t\t\tif (argc != 4)\n\n\nBy the way, I have tried to use git-config --null to redo config\nfile parsing in gitweb, so one git-config call would be needed for\nall the config. I have noticed that --bool option description does\nnot describe the observed behavior fully. For example it returns\n'true' not only for '1', but for any integer != 0, including 0xdeadbeef.\n\nBy the way, the error message when key value _cannot_ be converted to\nthe boolean is somewhat misleading:\n\n  $ GIT_CONFIG=conftest git config --bool bool.key7\n  fatal: bad config value for 'bool.key7' in conftest\n\n-- \nJakub Narebski\nPoland\n"},{"id":"45565","messageId":"20070622120217.GP19725@planck.djpig.de","threadId":"8259","inReplyTo":"200706220156.01175.jnareb@gmail.com","subject":"Re: [PATCH/RFC] config: Add --null/-z option for null-delimted output","fromName":"Frank Lichtenheld","fromEmail":"frank@lichtenheld.de","sentAt":"2007-06-22T12:02:18Z","receivedAt":"2007-06-22T12:02:18Z","isPatch":true,"sender":{"key":"frank@lichtenheld.de","avatar":"https://gravatar.com/avatar/b9f1d4b120e138f157c9e480d0818197c474628923786adb98f30017cdb99c3c?d=mp&s=160"},"body":"On Fri, Jun 22, 2007 at 01:56:00AM +0200, Jakub Narebski wrote:\n> On Mon, 18 Jun 2007, Frank Lichtenheld wrote:\n> >  Note the FIXME. Does anyone remember the reason why --get-regexp\n> >  and --list use different output format?\n> \n> I don't know, but at least two scripts use --get-regexp, namely\n> git-remote and git-submodule. So we would have to be careful about\n> changing that.\n>  \n> \n> I would be enough to add the following to your patch:\n\nYeah, I found this a but ugly though so I left it out of the first\npatch in case someone had a better idea. Will include that in the\nsecond version (which will also include documentation).\n\n> By the way, I have tried to use git-config --null to redo config\n> file parsing in gitweb, so one git-config call would be needed for\n> all the config. I have noticed that --bool option description does\n> not describe the observed behavior fully. For example it returns\n> 'true' not only for '1', but for any integer != 0, including 0xdeadbeef.\n\nYeah, the description of --bool is very incomplete. Note that empty\nvalues are false, and keys without values are true. I think this all\nare valid choices, but they are indeed not documented.\n\nGruesse.\n-- \nFrank Lichtenheld <frank@lichtenheld.de>\nwww: http://www.djpig.de/\n"},{"id":"45768","messageId":"11827802353409-git-send-email-frank@lichtenheld.de","threadId":"8259","inReplyTo":"200706220156.01175.jnareb@gmail.com","subject":"[PATCH 1/3] config: Complete documentation of --get-regexp","fromName":"Frank Lichtenheld","fromEmail":"frank@lichtenheld.de","sentAt":"2007-06-25T14:03:53Z","receivedAt":"2007-06-25T14:03:53Z","isPatch":true,"sender":{"key":"frank@lichtenheld.de","avatar":"https://gravatar.com/avatar/b9f1d4b120e138f157c9e480d0818197c474628923786adb98f30017cdb99c3c?d=mp&s=160"},"body":"The asciidoc documentation of the --get-regexp option was\nincomplete. Add some missing pieces:\n - List the option in SYNOPSIS\n - Mention that key names are printed\n\nSigned-off-by: Frank Lichtenheld <frank@lichtenheld.de>\n---\n Documentation/git-config.txt |    2 ++\n 1 files changed, 2 insertions(+), 0 deletions(-)\n\ndiff --git a/Documentation/git-config.txt b/Documentation/git-config.txt\nindex f2c6717..bb6dbb0 100644\n--- a/Documentation/git-config.txt\n+++ b/Documentation/git-config.txt\n@@ -14,6 +14,7 @@ SYNOPSIS\n 'git-config' [--system | --global] --replace-all name [value [value_regex]]\n 'git-config' [--system | --global] [type] --get name [value_regex]\n 'git-config' [--system | --global] [type] --get-all name [value_regex]\n+'git-config' [--system | --global] [type] --get-regexp name_regex [value_regex]\n 'git-config' [--system | --global] --unset name [value_regex]\n 'git-config' [--system | --global] --unset-all name [value_regex]\n 'git-config' [--system | --global] --rename-section old_name new_name\n@@ -73,6 +74,7 @@ OPTIONS\n \n --get-regexp::\n \tLike --get-all, but interprets the name as a regular expression.\n+\tAlso outputs the key names.\n \n --global::\n \tFor writing options: write to global ~/.gitconfig file rather than\n-- \n1.5.2.1\n"},{"id":"45769","messageId":"11827802363555-git-send-email-frank@lichtenheld.de","threadId":"8259","inReplyTo":"200706220156.01175.jnareb@gmail.com","subject":"[PATCH 2/3] config: Change output of --get-regexp for valueless keys","fromName":"Frank Lichtenheld","fromEmail":"frank@lichtenheld.de","sentAt":"2007-06-25T14:03:54Z","receivedAt":"2007-06-25T14:03:54Z","isPatch":true,"sender":{"key":"frank@lichtenheld.de","avatar":"https://gravatar.com/avatar/b9f1d4b120e138f157c9e480d0818197c474628923786adb98f30017cdb99c3c?d=mp&s=160"},"body":"Print no space after the name of a key without value.\nOtherwise keys without values are printed exactly the\nsame as keys with empty values.\n\nSigned-off-by: Frank Lichtenheld <frank@lichtenheld.de>\n---\n builtin-config.c       |    8 ++++++--\n t/t1300-repo-config.sh |    6 ++++++\n 2 files changed, 12 insertions(+), 2 deletions(-)\n\n I hope that nobody depends on this specific behaviour.\n Backwards compatibilty would be a pain here, since the --null\n patch would get really complicated\n\ndiff --git a/builtin-config.c b/builtin-config.c\nindex b2515f7..dbc2339 100644\n--- a/builtin-config.c\n+++ b/builtin-config.c\n@@ -38,8 +38,12 @@ static int show_config(const char* key_, const char* value_)\n \t\t\t  regexec(regexp, (value_?value_:\"\"), 0, NULL, 0)))\n \t\treturn 0;\n \n-\tif (show_keys)\n-\t\tprintf(\"%s \", key_);\n+\tif (show_keys) {\n+\t\tif (value_)\n+\t\t\tprintf(\"%s \", key_);\n+\t\telse\n+\t\t\tprintf(\"%s\", key_);\n+\t}\n \tif (seen && !do_all)\n \t\tdup_error = 1;\n \tif (type == T_INT)\ndiff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh\nindex 7731fa7..8b5e9fc 100755\n--- a/t/t1300-repo-config.sh\n+++ b/t/t1300-repo-config.sh\n@@ -283,6 +283,12 @@ EOF\n test_expect_success 'get variable with no value' \\\n \t'git-config --get novalue.variable ^$'\n \n+echo novalue.variable > expect\n+\n+test_expect_success 'get-regexp variable with no value' \\\n+\t'git-config --get-regexp novalue > output &&\n+\t cmp output expect' \n+\n git-config > output 2>&1\n \n test_expect_success 'no arguments, but no crash' \\\n-- \n1.5.2.1\n"},{"id":"45770","messageId":"11827802382221-git-send-email-frank@lichtenheld.de","threadId":"8259","inReplyTo":"200706220156.01175.jnareb@gmail.com","subject":"[PATCH 3/3] config: Add --null/-z option for null-delimted output","fromName":"Frank Lichtenheld","fromEmail":"frank@lichtenheld.de","sentAt":"2007-06-25T14:03:55Z","receivedAt":"2007-06-25T14:03:55Z","isPatch":true,"sender":{"key":"frank@lichtenheld.de","avatar":"https://gravatar.com/avatar/b9f1d4b120e138f157c9e480d0818197c474628923786adb98f30017cdb99c3c?d=mp&s=160"},"body":"Use \\n as delimiter between key and value and \\0 as\ndelimiter after each key/value pair. This should be\neasily parsable output.\n\nSigned-off-by: Frank Lichtenheld <frank@lichtenheld.de>\n---\n Documentation/git-config.txt |   18 +++++++++++++-----\n builtin-config.c             |   20 ++++++++++++++------\n t/t1300-repo-config.sh       |   32 ++++++++++++++++++++++++++++++++\n 3 files changed, 59 insertions(+), 11 deletions(-)\n\n This time with documentation and test cases.\n\ndiff --git a/Documentation/git-config.txt b/Documentation/git-config.txt\nindex bb6dbb0..8c09b88 100644\n--- a/Documentation/git-config.txt\n+++ b/Documentation/git-config.txt\n@@ -9,17 +9,17 @@ git-config - Get and set repository or global options\n SYNOPSIS\n --------\n [verse]\n-'git-config' [--system | --global] name [value [value_regex]]\n+'git-config' [--system | --global] [-z|--null] name [value [value_regex]]\n 'git-config' [--system | --global] --add name value\n 'git-config' [--system | --global] --replace-all name [value [value_regex]]\n-'git-config' [--system | --global] [type] --get name [value_regex]\n-'git-config' [--system | --global] [type] --get-all name [value_regex]\n-'git-config' [--system | --global] [type] --get-regexp name_regex [value_regex]\n+'git-config' [--system | --global] [type] [-z|--null] --get name [value_regex]\n+'git-config' [--system | --global] [type] [-z|--null] --get-all name [value_regex]\n+'git-config' [--system | --global] [type] [-z|--null] --get-regexp name_regex [value_regex]\n 'git-config' [--system | --global] --unset name [value_regex]\n 'git-config' [--system | --global] --unset-all name [value_regex]\n 'git-config' [--system | --global] --rename-section old_name new_name\n 'git-config' [--system | --global] --remove-section name\n-'git-config' [--system | --global] -l | --list\n+'git-config' [--system | --global] [-z|--null] -l | --list\n \n DESCRIPTION\n -----------\n@@ -118,6 +118,14 @@ See also <<FILES>>.\n \tin the config file will cause the value to be multiplied\n \tby 1024, 1048576, or 1073741824 prior to output.\n \n+-z, --null::\n+\tFor all options that output values and/or keys, always\n+\tend values with with the null character (instead of a\n+\tnewline). Use newline instead as a delimiter between\n+\tkey and value. This allows for secure parsing of the\n+\toutput without getting confused e.g. by values that\n+\tcontain line breaks. \n+\n \n [[FILES]]\n FILES\ndiff --git a/builtin-config.c b/builtin-config.c\nindex dbc2339..9d52ba8 100644\n--- a/builtin-config.c\n+++ b/builtin-config.c\n@@ -2,7 +2,7 @@\n #include \"cache.h\"\n \n static const char git_config_set_usage[] =\n-\"git-config [ --global | --system ] [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list\";\n+\"git-config [ --global | --system ] [ --bool | --int ] [ -z | --null ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list\";\n \n static char *key;\n static regex_t *key_regexp;\n@@ -12,14 +12,17 @@ static int use_key_regexp;\n static int do_all;\n static int do_not_match;\n static int seen;\n+static char delim = '=';\n+static char key_delim = ' ';\n+static char term = '\\n';\n static enum { T_RAW, T_INT, T_BOOL } type = T_RAW;\n \n static int show_all_config(const char *key_, const char *value_)\n {\n \tif (value_)\n-\t\tprintf(\"%s=%s\\n\", key_, value_);\n+\t\tprintf(\"%s%c%s%c\", key_, delim, value_, term);\n \telse\n-\t\tprintf(\"%s\\n\", key_);\n+\t\tprintf(\"%s%c\", key_, term);\n \treturn 0;\n }\n \n@@ -40,9 +43,9 @@ static int show_config(const char* key_, const char* value_)\n \n \tif (show_keys) {\n \t\tif (value_)\n-\t\t\tprintf(\"%s \", key_);\n+\t\t\tprintf(\"%s%c\", key_, key_delim);\n \t\telse\n-\t\t\tprintf(\"%s\", key_);\n+\t\t\tprintf(\"%s\",key_);\n \t}\n \tif (seen && !do_all)\n \t\tdup_error = 1;\n@@ -58,7 +61,7 @@ static int show_config(const char* key_, const char* value_)\n \t\t\t\tkey_, vptr);\n \t}\n \telse\n-\t\tprintf(\"%s\\n\", vptr);\n+\t\tprintf(\"%s%c\", vptr, term);\n \n \treturn 0;\n }\n@@ -159,6 +162,11 @@ int cmd_config(int argc, const char **argv, const char *prefix)\n \t\t}\n \t\telse if (!strcmp(argv[1], \"--system\"))\n \t\t\tsetenv(\"GIT_CONFIG\", ETC_GITCONFIG, 1);\n+\t\telse if (!strcmp(argv[1], \"--null\") || !strcmp(argv[1], \"-z\")) {\n+\t\t\tterm = '\\0';\n+\t\t\tdelim = '\\n';\n+\t\t\tkey_delim = '\\n';\n+\t\t}\n \t\telse if (!strcmp(argv[1], \"--rename-section\")) {\n \t\t\tint ret;\n \t\t\tif (argc != 4)\ndiff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh\nindex 8b5e9fc..99d84cc 100755\n--- a/t/t1300-repo-config.sh\n+++ b/t/t1300-repo-config.sh\n@@ -519,4 +519,36 @@ git config --list > result\n \n test_expect_success 'value continued on next line' 'cmp result expect'\n \n+cat > .git/config <<\\EOF\n+[section \"sub=section\"]\n+\tval1 = foo=bar\n+\tval2 = foo\\nbar\n+\tval3 = \\n\\n\n+\tval4 =\n+\tval5\n+EOF\n+\n+cat > expect <<\\EOF\n+Key: section.sub=section.val1\n+Value: foo=bar\n+Key: section.sub=section.val2\n+Value: foo\n+bar\n+Key: section.sub=section.val3\n+Value: \n+\n+\n+Key: section.sub=section.val4\n+Value: \n+Key: section.sub=section.val5\n+EOF\n+\n+git config --null --list | perl -0ne 'chop;($key,$value)=split(/\\n/,$_,2);print \"Key: $key\\n\";print \"Value: $value\\n\" if defined($value)' > result\n+\n+test_expect_success '--null --list' 'cmp result expect'\n+\n+git config --null --get-regexp 'val[0-9]' | perl -0ne 'chop;($key,$value)=split(/\\n/,$_,2);print \"Key: $key\\n\";print \"Value: $value\\n\" if defined($value)' > result\n+\n+test_expect_success '--null --get-regexp' 'cmp result expect'\n+\n test_done\n-- \n1.5.2.1\n"},{"id":"45809","messageId":"200706260129.47518.jnareb@gmail.com","threadId":"8259","inReplyTo":"11827802382221-git-send-email-frank@lichtenheld.de","subject":"Re: [PATCH 3/3] config: Add --null/-z option for null-delimted output","fromName":"Jakub Narebski","fromEmail":"jnareb@gmail.com","sentAt":"2007-06-25T23:29:46Z","receivedAt":"2007-06-25T23:29:46Z","isPatch":true,"sender":{"key":"jnareb@gmail.com","avatar":"https://avatars.githubusercontent.com/u/2706?v=4"},"body":"Frank Lichtenheld wrote:\n\n>                 else\n> -                       printf(\"%s\", key_);\n> +                       printf(\"%s\",key_);\n>         }\n\nThat is a mistake, I think?\n\n-- \nJakub Narebski\nPoland\n"},{"id":"45829","messageId":"20070626104701.GA12721@planck.djpig.de","threadId":"8259","inReplyTo":"200706260129.47518.jnareb@gmail.com","subject":"Re: [PATCH 3/3] config: Add --null/-z option for null-delimted output","fromName":"Frank Lichtenheld","fromEmail":"frank@lichtenheld.de","sentAt":"2007-06-26T10:47:02Z","receivedAt":"2007-06-26T10:47:02Z","isPatch":true,"sender":{"key":"frank@lichtenheld.de","avatar":"https://gravatar.com/avatar/b9f1d4b120e138f157c9e480d0818197c474628923786adb98f30017cdb99c3c?d=mp&s=160"},"body":"On Tue, Jun 26, 2007 at 01:29:46AM +0200, Jakub Narebski wrote:\n> Frank Lichtenheld wrote:\n> >                 else\n> > -                       printf(\"%s\", key_);\n> > +                       printf(\"%s\",key_);\n> >         }\n> \n> That is a mistake, I think?\n\nIndeed. I remember I saw and fixed that before sending. Must've\nbeen a halluzination ;)\n\nGruesse,\n-- \nFrank Lichtenheld <frank@lichtenheld.de>\nwww: http://www.djpig.de/\n"},{"id":"45882","messageId":"7vzm2mrvo2.fsf@assigned-by-dhcp.pobox.com","threadId":"8259","inReplyTo":"11827802363555-git-send-email-frank@lichtenheld.de","subject":"Re: [PATCH 2/3] config: Change output of --get-regexp for valueless keys","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-06-27T02:14:05Z","receivedAt":"2007-06-27T02:14:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Frank Lichtenheld <frank@lichtenheld.de> writes:\n\n> Print no space after the name of a key without value.\n> Otherwise keys without values are printed exactly the\n> same as keys with empty values.\n\nI think this can be defended as a bugfix even though it is a\nchange in the behaviour.  Thanks.\n"},{"id":"45883","messageId":"7vodj2rvo0.fsf@assigned-by-dhcp.pobox.com","threadId":"8259","inReplyTo":"200706260129.47518.jnareb@gmail.com","subject":"Re: [PATCH 3/3] config: Add --null/-z option for null-delimted output","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-06-27T02:14:07Z","receivedAt":"2007-06-27T02:14:07Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Thanks for the sharp eyes.\n"}]}