{"thread":{"id":"26178","subject":"[RFC/PATCH] Documentation/technical: document quoting API","startedAt":"2011-01-03T06:35:34Z","lastAt":"2011-01-04T19:21:07Z","messageCount":3,"participants":["Jonathan Nieder","Nguyen Thai Ngoc Duy","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"158840","messageId":"20110103063534.GA3661@burratino","threadId":"26178","inReplyTo":null,"subject":"[RFC/PATCH] Documentation/technical: document quoting API","fromName":"Jonathan Nieder","fromEmail":"jrnieder@gmail.com","sentAt":"2011-01-03T06:35:34Z","receivedAt":"2011-01-03T06:35:34Z","isPatch":true,"sender":{"key":"jrnieder@gmail.com","avatar":"https://avatars.githubusercontent.com/u/281595?v=4"},"body":"Briefly explain the zoo of quoting functions.\n\nSigned-off-by: Jonathan Nieder <jrnieder@gmail.com>\n---\nThis is just a starting point, I fear.  Not even compile-tested.\nProblems:\n\n - not very brief\n - not a great overview\n\nBut I was happy to have the chance to read through the available\nfunctions.\n\nSuggestions and other improvements welcome.\n\n Documentation/technical/api-quote.txt |  124 ++++++++++++++++++++++++++++++---\n quote.h                               |   14 ++--\n 2 files changed, 121 insertions(+), 17 deletions(-)\n rewrite Documentation/technical/api-quote.txt (84%)\n\ndiff --git a/Documentation/technical/api-quote.txt b/Documentation/technical/api-quote.txt\ndissimilarity index 84%\nindex e8a1bce..18da370 100644\n--- a/Documentation/technical/api-quote.txt\n+++ b/Documentation/technical/api-quote.txt\n@@ -1,10 +1,114 @@\n-quote API\n-=========\n-\n-Talk about <quote.h>, things like\n-\n-* sq_quote and unquote\n-* c_style quote and unquote\n-* quoting for foreign languages\n-\n-(JC)\n+quote API\n+=========\n+\n+The quoting API can be used to replace unusual characters for\n+shell safety or for output readability and parseability.\n+It also can be used to perform the inverse operation and recover\n+the unusual characters again.\n+\n+C-style quoting\n+---------------\n+\n+`quote_c_style` quotes a string in a manner that might be familiar\n+to C programmers.  This can be used to quote newlines and tabs in\n+filenames for patches, for example.\n+\n+. if sb and fp are both NULL, it returns the number of bytes needed\n+  to hold the quoted version of \"name\", counting the double quotes\n+  around it but not terminating NUL.  If \"name\" does not need quoting,\n+  it returns 0.\n+\n+. otherwise, it emits the quoted version of \"name\" to a stream,\n+  strbuf, or both.  Output will have enclosing double quotes\n+  suppressed if requested with the \"no_dq\" parameter.\n+\n+`quote_two_c_style`::\n+\tQuote two paths (prefix + path) in C-style and concatenate them.\n+\tOne should use this instead of calling `quote_c_style` twice\n+\tto avoid unsightly quotation marks in the middle.\n+\n+`unquote_c_style`::\n+\tThis unwraps what quote_c_style() produces in place,\n+\tbut returns -1 and doesn't touch if the input does not start with\n+\ta double-quote or otherwise differs from what quote_c_style\n+\twould have produced.  Though note that this function will\n+\tallocate memory in the strbuf, so calling `strbuf_release`\n+\tis mandatory regardless of the result `unquote_c_style` returns.\n++\n+Updates the endp pointer to point at one past the ending double quote\n+if given.\n+\n+`write_name_quoted`::\n+\t`write_name_quoted` is like `quote_c_style` but takes a\n+\tdifferent set of arguments.\n+\tInstead of asking for quotes or not, you pass a \"terminator\".\n+\tIf it's \\0 then we assume you don't want to escape, else C\n+\tescaping is performed. In any case, the terminator is also\n+\tappended to the stream.\n+\n+`write_name_quotedpfx`::\n+\t`write_name_quotedpfx` works like `write_name_quoted` but takes\n+\tprefix/prefix_len arguments.  The first \"prefix_len\" characters\n+\tof \"prefix\" will be prepended when emiting \"name\".\n+\n+`write_name_quoted_relative`::\n+\tThis is a sort of converse to `write_name_quotedpfx`.\n+\tThe path \"name\" is made relative to the directory described by\n+\tprefix and prefix_len by stripping away path components and\n+\tprepending `../` when necessary before quoting.\n+\n+Quoting for the shell\n+---------------------\n+\n+`sq_quote` copies its argument quoted for the shell safety.\n+Any single quote is replaced with '\\'', any exclamation point\n+is replaced with '\\!', and the whole thing is enclosed in a\n+single-quote pair.\n+\n+For example, if you are passing the result to `system()` as an\n+argument:\n+--------------\n+sprintf(cmd, \"foobar %s %s\", sq_quote(arg0), sq_quote(arg1))\n+--------------\n+would be appropriate.  If the `system()` is going to call 'ssh' to\n+run the command on the other side:\n+--------------\n+sprintf(cmd, \"git-diff-tree %s %s\", sq_quote(arg0), sq_quote(arg1));\n+sprintf(rcmd, \"ssh %s %s\", sq_quote(host), sq_quote(cmd));\n+--------------\n+Note that the above examples leak memory!  Remember to free result from\n+`sq_quote()` in a real application.\n+\n+`sq_quote_print`::\n+\tWrites to a stream instead of a new buffer.\n+\n+`sq_quote_buf`::\n+\tAppends to a strbuf instead of allocating a new buffer.\n+\n+`sq_quote_argv`::\n+\tAppends a list of command-line-ready arguments to \"dst\",\n+\teach preceded by a space character.  This function is\n+\tavailable for scripted use as 'git rev-parse --sq-quote'.\n+\n+`sq_dequote`::\n+\tThis unwraps what sq_quote() produces in place, but returns\n+\tNULL if the input does not look like what sq_quote would have\n+\tproduced.\n+\n+`sq_dequote_to_argv`::\n+\tLike the above, but unwrap many arguments in the same string\n+\tseparated by space. \"*argv\", \"*nr\", and \"*alloc\" should be a\n+\tpointer to a malloc-ed array (or NULL), its current number of\n+\tvalid elements, and the number of allocated elements, for\n+\texample as managed with ALLOC_GROW.  The result is appended\n+\tafter the valid part of *argv.\n+\n+Quoting for other languages\n+---------------------------\n+\n+`perl_quote_print`::\n+`python_quote_print`::\n+`tcl_quote_print`::\n+\tQuote as a string literal for evaluation in the specified\n+\tlanguage.  This is used by 'git for-each-ref' to output\n+\tvarious aspects of objects for use by language bindings.\ndiff --git a/quote.h b/quote.h\nindex 38003bf..cec40b0 100644\n--- a/quote.h\n+++ b/quote.h\n@@ -23,9 +23,8 @@\n  * Note that the above examples leak memory!  Remember to free result from\n  * sq_quote() in a real application.\n  *\n- * sq_quote_buf() writes to an existing buffer of specified size; it\n- * will return the number of characters that would have been written\n- * excluding the final null regardless of the buffer size.\n+ * sq_quote_buf() writes to the end of a strbuf instead of\n+ * allocating a new buffer.\n  */\n \n extern void sq_quote_print(FILE *stream, const char *src);\n@@ -40,10 +39,11 @@ extern void sq_quote_argv(struct strbuf *, const char **argv, size_t maxlen);\n extern char *sq_dequote(char *);\n \n /*\n- * Same as the above, but can be used to unwrap many arguments in the\n- * same string separated by space. \"next\" is changed to point to the\n- * next argument that should be passed as first parameter. When there\n- * is no more argument to be dequoted, \"next\" is updated to point to NULL.\n+ * Similar to the above, but unwraps many arguments in the\n+ * same string separated by space. \"*argv\" is expanded to hold\n+ * the dequoted arguments in positions (*argv)[*nr], *argv[*nr+1], etc\n+ * and *nr and *alloc updated to hold the new number of entries\n+ * and allocated size of the array.\n  */\n extern int sq_dequote_to_argv(char *arg, const char ***argv, int *nr, int *alloc);\n \n-- \n1.7.4.rc0.580.g89dc.dirty\n"},{"id":"158841","messageId":"AANLkTi=9EfDnj+koYHPejoz1bok=FaMXhM=DQirOFp1D@mail.gmail.com","threadId":"26178","inReplyTo":"20110103063534.GA3661@burratino","subject":"Re: [RFC/PATCH] Documentation/technical: document quoting API","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2011-01-03T07:39:24Z","receivedAt":"2011-01-03T07:39:24Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Jan 3, 2011 at 1:35 PM, Jonathan Nieder <jrnieder@gmail.com> wrote:\n> Briefly explain the zoo of quoting functions.\n\nI rarely read these documents. One of the reasons is sometimes I don't\nknow such document exists. Can we put a pointer to the document in\nquote.h? I assume that anyone who wants to use these will at least\nlook at quote.h first.\n-- \nDuy\n"},{"id":"158908","messageId":"7v8vz0fpb0.fsf@alter.siamese.dyndns.org","threadId":"26178","inReplyTo":"20110103063534.GA3661@burratino","subject":"Re: [RFC/PATCH] Documentation/technical: document quoting API","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-01-04T19:21:07Z","receivedAt":"2011-01-04T19:21:07Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jonathan Nieder <jrnieder@gmail.com> writes:\n\n> +C-style quoting\n> +---------------\n> +\n> +`quote_c_style` quotes a string in a manner that might be familiar\n> +to C programmers.  This can be used to quote newlines and tabs in\n> +filenames for patches, for example.\n> +\n> +. if sb and fp are both NULL, it returns the number of bytes needed\n> +  to hold the quoted version of \"name\", counting the double quotes\n> +  around it but not terminating NUL.  If \"name\" does not need quoting,\n> +  it returns 0.\n> +\n> +. otherwise, it emits the quoted version of \"name\" to a stream,\n> +  strbuf, or both.  Output will have enclosing double quotes\n> +  suppressed if requested with the \"no_dq\" parameter.\n\nHeh, I didn't know about the \"both\" case.  That is probably unintended\nmisfeature that would not hurt but would not be useful in practice either\n;-)\n\n> +`quote_two_c_style`::\n> +\tQuote two paths (prefix + path) in C-style and concatenate them.\n> +\tOne should use this instead of calling `quote_c_style` twice\n> +\tto avoid unsightly quotation marks in the middle.\n\nJust for the record, \"Avoid dqdq in the middle\" was never the motivation;\nyou can run two no_dq invocations and put dq around the result yourself.\nThe main motivation for using this, before the strbuf was widely used, was\nto avoid having to allocate memory only to call quote_c_style, because it\nhappens so often that we have prefix and path as separate strings.\n\n> +`unquote_c_style`::\n> +\tThis unwraps what quote_c_style() produces in place,\n> +\tbut returns -1 and doesn't touch if the input does not start with\n> +\ta double-quote or otherwise differs from what quote_c_style\n> +\twould have produced.  Though note that this function will\n> +\tallocate memory in the strbuf, so calling `strbuf_release`\n> +\tis mandatory regardless of the result `unquote_c_style` returns.\n\ns/Though note/Note/ perhaps?\n\n> +Quoting for the shell\n> +---------------------\n> +\n> +`sq_quote` copies its argument quoted for the shell safety.\n> +Any single quote is replaced with '\\'', any exclamation point\n> +is replaced with '\\!', and the whole thing is enclosed in a\n> +single-quote pair.\n> +\n> +For example, if you are passing the result to `system()` as an\n> +argument:\n\n\"... if you are preparing a command line to give to `system(3)`\"?\n\nI first misread the above and thought you were doing some operation on the\nresult coming back from \"system()\", which of course is nonsensical and not\nwhat you meant.\n\nThanks.\n"}]}