bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

quotearg: implement custom_quoting_style


From: Joel E. Denny
Subject: quotearg: implement custom_quoting_style
Date: Sat, 22 Aug 2009 22:01:10 -0400 (EDT)
User-agent: Alpine 1.00 (DEB 882 2007-12-20)

The following patch series implements custom quotation marks in quotearg.  
My main motivation is to be able to handle single-quoted strings.  For 
example, you can invoke this:

  quotearg_custom ("'", "'", "joel's\tstring");

to produce this:

  "'joel\\'s\\tstring'"

However, I figured it was probably better to generalize.  For example, you 
can also invoke this:

  quotearg_custom ("(", ")", "(joel's)\tstring");

to produce this:

  "((joel's\\)\\tstring)"

As a somewhat separate issue, the last patch in this series documents a 
limitation of the quote_these_too array that I discovered while working on 
the other patches: quote_these_too should not contain a digit or a letter 
that's special after a backslash.  It looks straightforward to overcome 
this limitation, but I'm not sure anyone would benefit, so I didn't 
bother.  I just documented it.

>From f81fc0cf92afa6a6b3f7a87bc898b344fb73c6a8 Mon Sep 17 00:00:00 2001
From: Joel E. Denny <address@hidden>
Date: Sat, 22 Aug 2009 17:55:15 -0400
Subject: [PATCH] quotearg-tests: test escaping of embedded locale quotes

* tests/test-quotearg.c (struct result_strings): Add member for
new input.
(LQ_ENC, RQ_ENC, RQ_ESC): New macros.
(inputs): Add new input.
(results_g): Add expected results.
(flag_results): Likewise.
(locale_results): Likewise.
(compare_strings): Check those.
---
 ChangeLog             |   12 +++++
 tests/test-quotearg.c |  115 ++++++++++++++++++++++++++++++-------------------
 2 files changed, 83 insertions(+), 44 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 4e33717..361914b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2009-08-22  Joel E. Denny  <address@hidden>
+
+       quotearg-tests: test escaping of embedded locale quotes
+       * tests/test-quotearg.c (struct result_strings): Add member for
+       new input.
+       (LQ_ENC, RQ_ENC, RQ_ESC): New macros.
+       (inputs): Add new input.
+       (results_g): Add expected results.
+       (flag_results): Likewise.
+       (locale_results): Likewise.
+       (compare_strings): Check those.
+
 2009-08-22  Bruno Haible  <address@hidden>
 
        * modules/binary-io (License): Relicense under LGPL.
diff --git a/tests/test-quotearg.c b/tests/test-quotearg.c
index 73bb1f9..ef91c80 100644
--- a/tests/test-quotearg.c
+++ b/tests/test-quotearg.c
@@ -52,6 +52,7 @@ struct result_strings {
   char const *str4; /* Translation of " \t\n'\"\033?""?/\\".  */
   char const *str5; /* Translation of "a:b".  */
   char const *str6; /* Translation of "a\\b".  */
+  char const *str7; /* Translation of LQ RQ.  */
 };
 
 struct result_groups {
@@ -60,118 +61,140 @@ struct result_groups {
   struct result_strings group3; /* Via quotearg_colon{,_mem}.  */
 };
 
+/* These quotes are borrowed from a pt_PT.utf8 translation.  */
+# define LQ "\302\253"
+# define RQ "\302\273"
+# define LQ_ENC "\\302\\253"
+# define RQ_ENC "\\302\\273"
+# define RQ_ESC "\\\302\273"
+
 static struct result_strings inputs = {
-  "", "\0001\0", 3, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b"
+  "", "\0001\0", 3, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b",
+  LQ RQ
 };
 
 static struct result_groups results_g[] = {
   /* literal_quoting_style */
-  { { "", "\0""1\0", 3, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b" },
-    { "", "1", 1, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b" },
-    { "", "1", 1, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b" } },
+  { { "", "\0""1\0", 3, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b",
+      LQ RQ },
+    { "", "1", 1, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b",
+      LQ RQ },
+    { "", "1", 1, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b",
+      LQ RQ } },
 
   /* shell_quoting_style */
   { { "''", "\0""1\0", 3, "simple", "' \t\n'\\''\"\033?""?/\\'", "a:b",
-      "'a\\b'" },
+      "'a\\b'", LQ RQ },
     { "''", "1", 1, "simple", "' \t\n'\\''\"\033?""?/\\'", "a:b",
-      "'a\\b'" },
+      "'a\\b'", LQ RQ },
     { "''", "1", 1, "simple", "' \t\n'\\''\"\033?""?/\\'", "'a:b'",
-      "'a\\b'" } },
+      "'a\\b'", LQ RQ } },
 
   /* shell_always_quoting_style */
   { { "''", "'\0""1\0'", 5, "'simple'", "' \t\n'\\''\"\033?""?/\\'", "'a:b'",
-      "'a\\b'" },
+      "'a\\b'", "'" LQ RQ "'" },
     { "''", "'1'", 3, "'simple'", "' \t\n'\\''\"\033?""?/\\'", "'a:b'",
-      "'a\\b'" },
+      "'a\\b'", "'" LQ RQ "'" },
     { "''", "'1'", 3, "'simple'", "' \t\n'\\''\"\033?""?/\\'", "'a:b'",
-      "'a\\b'" } },
+      "'a\\b'", "'" LQ RQ "'" } },
 
   /* c_quoting_style */
   { { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
-      "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a:b\"", "\"a\\\\b\"" },
+      "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a:b\"", "\"a\\\\b\"",
+      "\"" LQ_ENC RQ_ENC "\"" },
     { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
-      "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a:b\"", "\"a\\\\b\"" },
+      "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a:b\"", "\"a\\\\b\"",
+      "\"" LQ_ENC RQ_ENC "\"" },
     { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
-      "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a\\:b\"", "\"a\\\\b\"" } },
+      "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a\\:b\"", "\"a\\\\b\"",
+      "\"" LQ_ENC RQ_ENC "\"" } },
 
   /* c_maybe_quoting_style */
   { { "", "\"\\0001\\0\"", 9, "simple", "\" \\t\\n'\\\"\\033?""?/\\\\\"",
-      "a:b", "a\\b" },
+      "a:b", "a\\b", "\"" LQ_ENC RQ_ENC "\"" },
     { "", "\"\\0001\\0\"", 9, "simple", "\" \\t\\n'\\\"\\033?""?/\\\\\"",
-      "a:b", "a\\b" },
+      "a:b", "a\\b", "\"" LQ_ENC RQ_ENC "\"" },
     { "", "\"\\0001\\0\"", 9, "simple", "\" \\t\\n'\\\"\\033?""?/\\\\\"",
-      "\"a:b\"", "a\\b" } },
+      "\"a:b\"", "a\\b", "\"" LQ_ENC RQ_ENC "\"" } },
 
   /* escape_quoting_style */
   { { "", "\\0001\\0", 7, "simple", " \\t\\n'\"\\033?""?/\\\\", "a:b",
-      "a\\\\b" },
+      "a\\\\b", LQ_ENC RQ_ENC },
     { "", "\\0001\\0", 7, "simple", " \\t\\n'\"\\033?""?/\\\\", "a:b",
-      "a\\\\b" },
+      "a\\\\b", LQ_ENC RQ_ENC },
     { "", "\\0001\\0", 7, "simple", " \\t\\n'\"\\033?""?/\\\\", "a\\:b",
-      "a\\\\b" } },
+      "a\\\\b", LQ_ENC RQ_ENC } },
 
   /* locale_quoting_style */
   { { "`'", "`\\0001\\0'", 9, "`simple'", "` \\t\\n\\'\"\\033?""?/\\\\'",
-      "`a:b'", "`a\\\\b'" },
+      "`a:b'", "`a\\\\b'", "`" LQ_ENC RQ_ENC "'" },
     { "`'", "`\\0001\\0'", 9, "`simple'", "` \\t\\n\\'\"\\033?""?/\\\\'",
-      "`a:b'", "`a\\\\b'" },
+      "`a:b'", "`a\\\\b'", "`" LQ_ENC RQ_ENC "'" },
     { "`'", "`\\0001\\0'", 9, "`simple'", "` \\t\\n\\'\"\\033?""?/\\\\'",
-      "`a\\:b'", "`a\\\\b'" } },
+      "`a\\:b'", "`a\\\\b'", "`" LQ_ENC RQ_ENC "'" } },
 
   /* clocale_quoting_style */
   { { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
-      "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a:b\"", "\"a\\\\b\"" },
+      "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a:b\"", "\"a\\\\b\"",
+      "\"" LQ_ENC RQ_ENC "\"" },
     { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
-      "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a:b\"", "\"a\\\\b\"" },
+      "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a:b\"", "\"a\\\\b\"",
+      "\"" LQ_ENC RQ_ENC "\"" },
     { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
-      "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a\\:b\"", "\"a\\\\b\"" } }
+      "\" \\t\\n'\\\"\\033?""?/\\\\\"", "\"a\\:b\"", "\"a\\\\b\"",
+      "\"" LQ_ENC RQ_ENC "\"" } }
 };
 
 static struct result_groups flag_results[] = {
   /* literal_quoting_style and QA_ELIDE_NULL_BYTES */
-  { { "", "1", 1, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b" },
-    { "", "1", 1, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b" },
-    { "", "1", 1, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b" } },
+  { { "", "1", 1, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b", LQ RQ },
+    { "", "1", 1, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b", LQ RQ },
+    { "", "1", 1, "simple", " \t\n'\"\033?""?/\\", "a:b", "a\\b", LQ RQ } },
 
   /* c_quoting_style and QA_ELIDE_OUTER_QUOTES */
   { { "", "\"\\0001\\0\"", 9, "simple", "\" \\t\\n'\\\"\\033?""?/\\\\\"",
-      "a:b", "a\\b" },
+      "a:b", "a\\b", "\"" LQ_ENC RQ_ENC "\"" },
     { "", "\"\\0001\\0\"", 9, "simple", "\" \\t\\n'\\\"\\033?""?/\\\\\"",
-      "a:b", "a\\b" },
+      "a:b", "a\\b", "\"" LQ_ENC RQ_ENC "\"" },
     { "", "\"\\0001\\0\"", 9, "simple", "\" \\t\\n'\\\"\\033?""?/\\\\\"",
-      "\"a:b\"", "a\\b" } },
+      "\"a:b\"", "a\\b", "\"" LQ_ENC RQ_ENC "\"" } },
 
   /* c_quoting_style and QA_SPLIT_TRIGRAPHS */
   { { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
-      "\" \\t\\n'\\\"\\033?\"\"?/\\\\\"", "\"a:b\"", "\"a\\\\b\"" },
+      "\" \\t\\n'\\\"\\033?\"\"?/\\\\\"", "\"a:b\"", "\"a\\\\b\"",
+      "\"" LQ_ENC RQ_ENC "\"" },
     { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
-      "\" \\t\\n'\\\"\\033?\"\"?/\\\\\"", "\"a:b\"", "\"a\\\\b\"" },
+      "\" \\t\\n'\\\"\\033?\"\"?/\\\\\"", "\"a:b\"", "\"a\\\\b\"",
+      "\"" LQ_ENC RQ_ENC "\"" },
     { "\"\"", "\"\\0001\\0\"", 9, "\"simple\"",
-      "\" \\t\\n'\\\"\\033?\"\"?/\\\\\"", "\"a\\:b\"", "\"a\\\\b\"" } }
+      "\" \\t\\n'\\\"\\033?\"\"?/\\\\\"", "\"a\\:b\"", "\"a\\\\b\"",
+      "\"" LQ_ENC RQ_ENC "\"" } }
 };
 
 #if ENABLE_NLS
 
-/* These quotes are borrowed from a pt_PT.utf8 translation.  */
-# define LQ "\302\253"
-# define RQ "\302\273"
-
 static struct result_groups locale_results[] = {
   /* locale_quoting_style */
   { { LQ RQ, LQ "\\0001\\0" RQ, 11, LQ "simple" RQ,
-      LQ " \\t\\n'\"\\033?""?/\\\\" RQ, LQ "a:b" RQ, LQ "a\\\\b" RQ },
+      LQ " \\t\\n'\"\\033?""?/\\\\" RQ, LQ "a:b" RQ, LQ "a\\\\b" RQ,
+      LQ LQ RQ_ESC RQ },
     { LQ RQ, LQ "\\0001\\0" RQ, 11, LQ "simple" RQ,
-      LQ " \\t\\n'\"\\033?""?/\\\\" RQ, LQ "a:b" RQ, LQ "a\\\\b" RQ },
+      LQ " \\t\\n'\"\\033?""?/\\\\" RQ, LQ "a:b" RQ, LQ "a\\\\b" RQ,
+      LQ LQ RQ_ESC RQ },
     { LQ RQ, LQ "\\0001\\0" RQ, 11, LQ "simple" RQ,
-      LQ " \\t\\n'\"\\033?""?/\\\\" RQ, LQ "a\\:b" RQ, LQ "a\\\\b" RQ } },
+      LQ " \\t\\n'\"\\033?""?/\\\\" RQ, LQ "a\\:b" RQ, LQ "a\\\\b" RQ,
+      LQ LQ RQ_ESC RQ } },
 
   /* clocale_quoting_style */
   { { LQ RQ, LQ "\\0001\\0" RQ, 11, LQ "simple" RQ,
-      LQ " \\t\\n'\"\\033?""?/\\\\" RQ, LQ "a:b" RQ, LQ "a\\\\b" RQ },
+      LQ " \\t\\n'\"\\033?""?/\\\\" RQ, LQ "a:b" RQ, LQ "a\\\\b" RQ,
+      LQ LQ RQ_ESC RQ },
     { LQ RQ, LQ "\\0001\\0" RQ, 11, LQ "simple" RQ,
-      LQ " \\t\\n'\"\\033?""?/\\\\" RQ, LQ "a:b" RQ, LQ "a\\\\b" RQ },
+      LQ " \\t\\n'\"\\033?""?/\\\\" RQ, LQ "a:b" RQ, LQ "a\\\\b" RQ,
+      LQ LQ RQ_ESC RQ },
     { LQ RQ, LQ "\\0001\\0" RQ, 11, LQ "simple" RQ,
-      LQ " \\t\\n'\"\\033?""?/\\\\" RQ, LQ "a\\:b" RQ, LQ "a\\\\b" RQ } }
+      LQ " \\t\\n'\"\\033?""?/\\\\" RQ, LQ "a\\:b" RQ, LQ "a\\\\b" RQ,
+      LQ LQ RQ_ESC RQ } }
 };
 
 #endif /* ENABLE_NLS */
@@ -214,6 +237,10 @@ compare_strings (char *(func) (char const *, size_t *),
   len = strlen (inputs.str6);
   p = func (inputs.str6, &len);
   compare (results->str6, strlen (results->str6), p, len);
+
+  len = strlen (inputs.str7);
+  p = func (inputs.str7, &len);
+  compare (results->str7, strlen (results->str7), p, len);
 }
 
 static char *
-- 
1.5.4.3


>From 47bd1531d990bddf3ba09419ccc6309b9fe3ed4e Mon Sep 17 00:00:00 2001
From: Joel E. Denny <address@hidden>
Date: Sat, 22 Aug 2009 20:26:46 -0400
Subject: [PATCH] quotearg: fix right quote escaping when it's in quote_these_too

* lib/quotearg.c (quotearg_buffer_restyled): Upon seeing a right
quote, be sure to prepend only one backslash.
* tests/test-quotearg.c (use_quote_double_quotes): New function.
(main): Test it.
---
 ChangeLog             |    8 ++++++++
 lib/quotearg.c        |   11 +++++++++--
 tests/test-quotearg.c |   13 +++++++++++++
 3 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 361914b..5f1ec94 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2009-08-22  Joel E. Denny  <address@hidden>
 
+       quotearg: fix right quote escaping when it's in quote_these_too
+       * lib/quotearg.c (quotearg_buffer_restyled): Upon seeing a right
+       quote, be sure to prepend only one backslash.
+       * tests/test-quotearg.c (use_quote_double_quotes): New function.
+       (main): Test it.
+
+2009-08-22  Joel E. Denny  <address@hidden>
+
        quotearg-tests: test escaping of embedded locale quotes
        * tests/test-quotearg.c (struct result_strings): Add member for
        new input.
diff --git a/lib/quotearg.c b/lib/quotearg.c
index 339bf34..3f9e628 100644
--- a/lib/quotearg.c
+++ b/lib/quotearg.c
@@ -280,6 +280,7 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
     {
       unsigned char c;
       unsigned char esc;
+      bool is_right_quote = false;
 
       if (backslash_escapes
          && quote_string_len
@@ -288,7 +289,7 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
        {
          if (elide_outer_quotes)
            goto force_outer_quoting_style;
-         STORE ('\\');
+         is_right_quote = true;
        }
 
       c = arg[i];
@@ -521,6 +522,11 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
                        STORE ('0' + ((c >> 3) & 7));
                        c = '0' + (c & 7);
                      }
+                   else if (is_right_quote)
+                     {
+                       STORE ('\\');
+                       is_right_quote = false;
+                     }
                    if (ilim <= i + 1)
                      break;
                    STORE (c);
@@ -534,7 +540,8 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
 
       if (! ((backslash_escapes || elide_outer_quotes)
             && quote_these_too
-            && quote_these_too[c / INT_BITS] & (1 << (c % INT_BITS))))
+            && quote_these_too[c / INT_BITS] & (1 << (c % INT_BITS)))
+         && !is_right_quote)
        goto store_c;
 
     store_escape:
diff --git a/tests/test-quotearg.c b/tests/test-quotearg.c
index ef91c80..2e2c56b 100644
--- a/tests/test-quotearg.c
+++ b/tests/test-quotearg.c
@@ -264,6 +264,15 @@ use_quotearg (const char *str, size_t *len)
 }
 
 static char *
+use_quote_double_quotes (const char *str, size_t *len)
+{
+  char *p = *len == SIZE_MAX ? quotearg_char (str, '"')
+                               : quotearg_char_mem (str, *len, '"');
+  *len = strlen (p);
+  return p;
+}
+
+static char *
 use_quotearg_colon (const char *str, size_t *len)
 {
   char *p = (*len == SIZE_MAX ? quotearg_colon (str)
@@ -287,6 +296,8 @@ main (int argc, char *argv[])
       set_quoting_style (NULL, i);
       compare_strings (use_quotearg_buffer, &results_g[i].group1);
       compare_strings (use_quotearg, &results_g[i].group2);
+      if (i == c_quoting_style)
+        compare_strings (use_quote_double_quotes, &results_g[i].group2);
       compare_strings (use_quotearg_colon, &results_g[i].group3);
     }
 
@@ -301,12 +312,14 @@ main (int argc, char *argv[])
          == QA_ELIDE_NULL_BYTES);
   compare_strings (use_quotearg_buffer, &flag_results[1].group1);
   compare_strings (use_quotearg, &flag_results[1].group2);
+  compare_strings (use_quote_double_quotes, &flag_results[1].group2);
   compare_strings (use_quotearg_colon, &flag_results[1].group3);
 
   ASSERT (set_quoting_flags (NULL, QA_SPLIT_TRIGRAPHS)
          == QA_ELIDE_OUTER_QUOTES);
   compare_strings (use_quotearg_buffer, &flag_results[2].group1);
   compare_strings (use_quotearg, &flag_results[2].group2);
+  compare_strings (use_quote_double_quotes, &flag_results[2].group2);
   compare_strings (use_quotearg_colon, &flag_results[2].group3);
 
   ASSERT (set_quoting_flags (NULL, 0) == QA_SPLIT_TRIGRAPHS);
-- 
1.5.4.3


>From 814f12a49687047a2e9a5b03f8373a3986ca2c3b Mon Sep 17 00:00:00 2001
From: Joel E. Denny <address@hidden>
Date: Sat, 22 Aug 2009 04:21:49 -0400
Subject: [PATCH] quotearg: implement custom_quoting_style

* lib/quotearg.c: (struct quoting_options): Add left and right
fields to store quotes.
(set_custom_quoting): New public function.
(quotearg_buffer_restyled): Add left and right arguments,
handle them very much like locale quoting, and update all uses.
(quotearg_n_custom): New public function.
(quotearg_n_custom_mem): New public function.
(quotearg_custom): New public function.
(quotearg_custom_mem): New public function.
* lib/quotearg.h: Prototype and document new public functions.
(enum quoting_style): Add custom_quoting_style member and
document.
* tests/test-quotearg.c (custom_quotes): New array.
(custom_results): New array.
(main): Extend to test custom quoting.
---
 ChangeLog             |   19 ++++++++++
 lib/quotearg.c        |   89 +++++++++++++++++++++++++++++++++++++++++++-----
 lib/quotearg.h        |   61 +++++++++++++++++++++++++++++++++-
 tests/test-quotearg.c |   86 +++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 244 insertions(+), 11 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 5f1ec94..255e17e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,24 @@
 2009-08-22  Joel E. Denny  <address@hidden>
 
+       quotearg: implement custom_quoting_style
+       * lib/quotearg.c: (struct quoting_options): Add left and right
+       fields to store quotes.
+       (set_custom_quoting): New public function.
+       (quotearg_buffer_restyled): Add left and right arguments,
+       handle them very much like locale quoting, and update all uses.
+       (quotearg_n_custom): New public function.
+       (quotearg_n_custom_mem): New public function.
+       (quotearg_custom): New public function.
+       (quotearg_custom_mem): New public function.
+       * lib/quotearg.h: Prototype and document new public functions.
+       (enum quoting_style): Add custom_quoting_style member and
+       document.
+       * tests/test-quotearg.c (custom_quotes): New array.
+       (custom_results): New array.
+       (main): Extend to test custom quoting.
+
+2009-08-22  Joel E. Denny  <address@hidden>
+
        quotearg: fix right quote escaping when it's in quote_these_too
        * lib/quotearg.c (quotearg_buffer_restyled): Upon seeing a right
        quote, be sure to prepend only one backslash.
diff --git a/lib/quotearg.c b/lib/quotearg.c
index 3f9e628..9e5f038 100644
--- a/lib/quotearg.c
+++ b/lib/quotearg.c
@@ -54,6 +54,12 @@ struct quoting_options
   /* Quote the characters indicated by this bit vector even if the
      quoting style would not normally require them to be quoted.  */
   unsigned int quote_these_too[(UCHAR_MAX / INT_BITS) + 1];
+
+  /* The left quote for custom_quoting_style.  */
+  char const *left;
+
+  /* The right quote for custom_quoting_style.  */
+  char const *right;
 };
 
 /* Names of quoting styles.  */
@@ -146,6 +152,19 @@ set_quoting_flags (struct quoting_options *o, int i)
   return r;
 }
 
+void
+set_custom_quoting (struct quoting_options *o,
+                    char const *l, char const *r)
+{
+  if (!o)
+    o = &default_quoting_options;
+  o->style = custom_quoting_style;
+  if (!l || !r)
+    abort ();
+  o->left = l;
+  o->right = r;
+}
+
 /* Return quoting options for STYLE, with no extra quoting.  */
 static struct quoting_options
 quoting_options_from_style (enum quoting_style style)
@@ -185,7 +204,8 @@ static size_t
 quotearg_buffer_restyled (char *buffer, size_t buffersize,
                          char const *arg, size_t argsize,
                          enum quoting_style quoting_style, int flags,
-                         unsigned int const *quote_these_too)
+                         unsigned int const *quote_these_too,
+                         char const *left, char const *right)
 {
   size_t i;
   size_t len = 0;
@@ -225,6 +245,7 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
 
     case locale_quoting_style:
     case clocale_quoting_style:
+    case custom_quoting_style:
       {
        /* TRANSLATORS:
           Get translations for open and closing quotation marks.
@@ -246,8 +267,11 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
           <http://en.wikipedia.org/wiki/Quotation_mark#Glyphs>
           and use glyphs suitable for your language.  */
 
-       char const *left = gettext_quote (N_("`"), quoting_style);
-       char const *right = gettext_quote (N_("'"), quoting_style);
+       if (quoting_style != custom_quoting_style)
+         {
+           left = gettext_quote (N_("`"), quoting_style);
+           right = gettext_quote (N_("'"), quoting_style);
+         }
        if (!elide_outer_quotes)
          for (quote_string = left; *quote_string; quote_string++)
            STORE (*quote_string);
@@ -301,6 +325,11 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
              if (elide_outer_quotes)
                goto force_outer_quoting_style;
              STORE ('\\');
+             /* If quote_string were to begin with digits, we'd need to
+                test for the end of the arg as well.  However, it's
+                hard to imagine any locale that would use digits in
+                quotes, and set_custom_quoting is documented not to
+                accept them.  */
              if (i + 1 < argsize && '0' <= arg[i + 1] && arg[i + 1] <= '9')
                {
                  STORE ('0');
@@ -426,7 +455,13 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
        case 'o': case 'p': case 'q': case 'r': case 's': case 't':
        case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
          /* These characters don't cause problems, no matter what the
-            quoting style is.  They cannot start multibyte sequences.  */
+            quoting style is.  They cannot start multibyte sequences.
+            A digit or a special letter would cause trouble if it
+            appeared at the beginning of quote_string because we'd then
+            escape by prepending a backslash.  However, it's hard to
+            imagine any locale that would use digits or letters as
+            quotes, and set_custom_quoting is documented not to accept
+            them.  */
          break;
 
        default:
@@ -570,7 +605,8 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
      sufficiently quotes the specified characters.  */
   return quotearg_buffer_restyled (buffer, buffersize, arg, argsize,
                                   quoting_style,
-                                  flags & ~QA_ELIDE_OUTER_QUOTES, NULL);
+                                  flags & ~QA_ELIDE_OUTER_QUOTES, NULL,
+                                  left, right);
 }
 
 /* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
@@ -590,7 +626,8 @@ quotearg_buffer (char *buffer, size_t buffersize,
   struct quoting_options const *p = o ? o : &default_quoting_options;
   int e = errno;
   size_t r = quotearg_buffer_restyled (buffer, buffersize, arg, argsize,
-                                      p->style, p->flags, p->quote_these_too);
+                                      p->style, p->flags, p->quote_these_too,
+                                      p->left, p->right);
   errno = e;
   return r;
 }
@@ -618,10 +655,11 @@ quotearg_alloc_mem (char const *arg, size_t argsize, 
size_t *size,
   /* Elide embedded null bytes if we can't return a size.  */
   int flags = p->flags | (size ? 0 : QA_ELIDE_NULL_BYTES);
   size_t bufsize = quotearg_buffer_restyled (0, 0, arg, argsize, p->style,
-                                            flags, p->quote_these_too) + 1;
+                                            flags, p->quote_these_too,
+                                            p->left, p->right) + 1;
   char *buf = xcharalloc (bufsize);
   quotearg_buffer_restyled (buf, bufsize, arg, argsize, p->style, flags,
-                           p->quote_these_too);
+                           p->quote_these_too, p->left, p->right);
   errno = e;
   if (size)
     *size = bufsize - 1;
@@ -710,7 +748,9 @@ quotearg_n_options (int n, char const *arg, size_t argsize,
     int flags = options->flags | QA_ELIDE_NULL_BYTES;
     size_t qsize = quotearg_buffer_restyled (val, size, arg, argsize,
                                             options->style, flags,
-                                            options->quote_these_too);
+                                            options->quote_these_too,
+                                            options->left,
+                                            options->right);
 
     if (size <= qsize)
       {
@@ -719,7 +759,8 @@ quotearg_n_options (int n, char const *arg, size_t argsize,
          free (val);
        sv[n].val = val = xcharalloc (size);
        quotearg_buffer_restyled (val, size, arg, argsize, options->style,
-                                 flags, options->quote_these_too);
+                                 flags, options->quote_these_too,
+                                 options->left, options->right);
       }
 
     errno = e;
@@ -804,3 +845,31 @@ quotearg_colon_mem (char const *arg, size_t argsize)
 {
   return quotearg_char_mem (arg, argsize, ':');
 }
+
+char *
+quotearg_n_custom (int n, char const *l, char const *r, char const *arg)
+{
+  return quotearg_n_custom_mem (n, l, r, arg, SIZE_MAX);
+}
+
+char *
+quotearg_n_custom_mem (int n, char const *l, char const *r,
+                      char const *arg, size_t argsize)
+{
+  struct quoting_options o = default_quoting_options;
+  set_custom_quoting (&o, l, r);
+  return quotearg_n_options (n, arg, argsize, &o);
+}
+
+char *
+quotearg_custom (char const *l, char const *r, char const *arg)
+{
+  return quotearg_n_custom (0, l, r, arg);
+}
+
+char *
+quotearg_custom_mem (char const *l, char const *r, char const *arg,
+                    size_t argsize)
+{
+  return quotearg_n_custom_mem (0, l, r, arg, argsize);
+}
diff --git a/lib/quotearg.h b/lib/quotearg.h
index 7700107..6704b32 100644
--- a/lib/quotearg.h
+++ b/lib/quotearg.h
@@ -157,7 +157,37 @@ enum quoting_style
        "\302\253simple\302\273",
        "\302\253\\0 \\t\\n'\"\\033??/\\\\\302\253", "\302\253a\\:b\302\273"
     */
-    clocale_quoting_style
+    clocale_quoting_style,
+
+    /* Like c_quoting_style except use the custom quotation marks set by
+       set_custom_quoting.  If custom quotation marks are not set, the
+       behavior is undefined.
+
+       left = right = "'"
+       quotearg_buffer:
+       "'simple'", "'\\0 \\t\\n\\'\"\\033??/\\\\'", "'a:b'"
+       quotearg:
+       "'simple'", "'\\0 \\t\\n\\'\"\\033??/\\\\'", "'a:b'"
+       quotearg_colon:
+       "'simple'", "'\\0 \\t\\n\\'\"\\033??/\\\\'", "'a\\:b'"
+
+       left = "(" and right = ")"
+       quotearg_buffer:
+       "(simple)", "(\\0 \\t\\n'\"\\033??/\\\\)", "(a:b)"
+       quotearg:
+       "(simple)", "(\\0 \\t\\n'\"\\033??/\\\\)", "(a:b)"
+       quotearg_colon:
+       "(simple)", "(\\0 \\t\\n'\"\\033??/\\\\)", "(a\\:b)"
+
+       left = ":" and right = " "
+       quotearg_buffer:
+       ":simple ", ":\\0\\ \\t\\n'\"\\033??/\\\\ ", ":a:b "
+       quotearg:
+       ":simple ", ":\\0\\ \\t\\n'\"\\033??/\\\\ ", ":a:b "
+       quotearg_colon:
+       ":simple ", ":\\0\\ \\t\\n'\"\\033??/\\\\ ", ":a\\:b "
+    */
+    custom_quoting_style
   };
 
 /* Flags for use in set_quoting_flags.  */
@@ -219,6 +249,17 @@ int set_char_quoting (struct quoting_options *o, char c, 
int i);
    behavior.  Return the old value.  */
 int set_quoting_flags (struct quoting_options *o, int i);
 
+/* In O (or in the default if O is null),
+   set the value of the quoting style to custom_quoting_style,
+   set the left quote to L, and set the right quote to R.
+   Each of L and R must be null-terminated and can be the empty
+   string.  Because backslashes are used for escaping, it does not make
+   sense for R to contain a backslash.  R must not begin with a digit or
+   a letter that has special meaning after a backslash (for example,
+   "\t" for tab).  */
+void set_custom_quoting (struct quoting_options *o,
+                        char const *l, char const *r);
+
 /* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
    argument ARG (of size ARGSIZE), using O to control quoting.
    If O is null, use the default.
@@ -299,6 +340,24 @@ char *quotearg_colon (char const *arg);
 /* Like quotearg_colon (ARG), except it can quote null bytes.  */
 char *quotearg_colon_mem (char const *arg, size_t argsize);
 
+/* Like quotearg_n_style (N, S, ARG) but with S as custom_quoting_style
+   with left quote as L and right quote as R.  See set_custom_quoting
+   for a description of acceptable L and R values.  */
+char *quotearg_n_custom (int n, char const *l, char const *r,
+                        char const *arg);
+
+/* Like quotearg_n_custom (N, L, R, ARG) except it can quote null
+   bytes.  */
+char *quotearg_n_custom_mem (int n, char const *l, char const *r,
+                            char const *arg, size_t argsize);
+
+/* Equivalent to quotearg_n_custom (0, L, R, ARG).  */
+char *quotearg_custom (char const *l, char const *r, char const *arg);
+
+/* Equivalent to quotearg_n_custom_mem (0, L, R, ARG, ARGSIZE).  */
+char *quotearg_custom_mem (char const *l, char const *r,
+                          char const *arg, size_t argsize);
+
 /* Free any dynamically allocated memory.  */
 void quotearg_free (void);
 
diff --git a/tests/test-quotearg.c b/tests/test-quotearg.c
index 2e2c56b..5a680d9 100644
--- a/tests/test-quotearg.c
+++ b/tests/test-quotearg.c
@@ -199,6 +199,83 @@ static struct result_groups locale_results[] = {
 
 #endif /* ENABLE_NLS */
 
+static char const *custom_quotes[][2] = {
+  { "", ""  },
+  { "'", "'"  },
+  { "(", ")"  },
+  { ":", " "  },
+  { " ", ":"  },
+  { "# ", "\n\n" }
+};
+
+static struct result_groups custom_results[] = {
+  /* left = right = "" */
+  { { "", "\\0001\\0", 7, "simple",
+      " \\t\\n'\"\\033?""?/\\\\", "a:b", "a\\\\b",
+      LQ_ENC RQ_ENC },
+    { "", "\\0001\\0", 7, "simple",
+      " \\t\\n'\"\\033?""?/\\\\", "a:b", "a\\\\b",
+      LQ_ENC RQ_ENC },
+    { "", "\\0001\\0", 7, "simple",
+      " \\t\\n'\"\\033?""?/\\\\", "a\\:b", "a\\\\b",
+      LQ_ENC RQ_ENC } },
+
+  /* left = right = "'" */
+  { { "''", "'\\0001\\0'", 9, "'simple'",
+      "' \\t\\n\\'\"\\033?""?/\\\\'", "'a:b'", "'a\\\\b'",
+      "'" LQ_ENC RQ_ENC "'" },
+    { "''", "'\\0001\\0'", 9, "'simple'",
+      "' \\t\\n\\'\"\\033?""?/\\\\'", "'a:b'", "'a\\\\b'",
+      "'" LQ_ENC RQ_ENC "'" },
+    { "''", "'\\0001\\0'", 9, "'simple'",
+      "' \\t\\n\\'\"\\033?""?/\\\\'", "'a\\:b'", "'a\\\\b'",
+      "'" LQ_ENC RQ_ENC "'" } },
+
+  /* left = "(" and right = ")" */
+  { { "()", "(\\0001\\0)", 9, "(simple)",
+      "( \\t\\n'\"\\033?""?/\\\\)", "(a:b)", "(a\\\\b)",
+      "(" LQ_ENC RQ_ENC ")" },
+    { "()", "(\\0001\\0)", 9, "(simple)",
+      "( \\t\\n'\"\\033?""?/\\\\)", "(a:b)", "(a\\\\b)",
+      "(" LQ_ENC RQ_ENC ")" },
+    { "()", "(\\0001\\0)", 9, "(simple)",
+      "( \\t\\n'\"\\033?""?/\\\\)", "(a\\:b)", "(a\\\\b)",
+      "(" LQ_ENC RQ_ENC ")" } },
+
+  /* left = ":" and right = " " */
+  { { ": ", ":\\0001\\0 ", 9, ":simple ",
+      ":\\ \\t\\n'\"\\033?""?/\\\\ ", ":a:b ", ":a\\\\b ",
+      ":" LQ_ENC RQ_ENC " " },
+    { ": ", ":\\0001\\0 ", 9, ":simple ",
+      ":\\ \\t\\n'\"\\033?""?/\\\\ ", ":a:b ", ":a\\\\b ",
+      ":" LQ_ENC RQ_ENC " " },
+    { ": ", ":\\0001\\0 ", 9, ":simple ",
+      ":\\ \\t\\n'\"\\033?""?/\\\\ ", ":a\\:b ", ":a\\\\b ",
+      ":" LQ_ENC RQ_ENC " " } },
+
+  /* left = " " and right = ":" */
+  { { " :", " \\0001\\0:", 9, " simple:",
+      "  \\t\\n'\"\\033?""?/\\\\:", " a\\:b:", " a\\\\b:",
+      " " LQ_ENC RQ_ENC ":" },
+    { " :", " \\0001\\0:", 9, " simple:",
+      "  \\t\\n'\"\\033?""?/\\\\:", " a\\:b:", " a\\\\b:",
+      " " LQ_ENC RQ_ENC ":" },
+    { " :", " \\0001\\0:", 9, " simple:",
+      "  \\t\\n'\"\\033?""?/\\\\:", " a\\:b:", " a\\\\b:",
+      " " LQ_ENC RQ_ENC ":" } },
+
+  /* left = "# " and right = "\n\n" */
+  { { "# \n\n", "# \\0001\\0\n\n", 11, "# simple\n\n",
+      "#  \\t\\n'\"\\033?""?/\\\\\n\n", "# a:b\n\n", "# a\\\\b\n\n",
+      "# " LQ_ENC RQ_ENC "\n\n" },
+    { "# \n\n", "# \\0001\\0\n\n", 11, "# simple\n\n",
+      "#  \\t\\n'\"\\033?""?/\\\\\n\n", "# a:b\n\n", "# a\\\\b\n\n",
+      "# " LQ_ENC RQ_ENC "\n\n" },
+    { "# \n\n", "# \\0001\\0\n\n", 11, "# simple\n\n",
+      "#  \\t\\n'\"\\033?""?/\\\\\n\n", "# a\\:b\n\n", "# a\\\\b\n\n",
+      "# " LQ_ENC RQ_ENC "\n\n" } }
+};
+
 static void
 compare (char const *a, size_t la, char const *b, size_t lb)
 {
@@ -324,6 +401,15 @@ main (int argc, char *argv[])
 
   ASSERT (set_quoting_flags (NULL, 0) == QA_SPLIT_TRIGRAPHS);
 
+  for (i = 0; i < sizeof custom_quotes / sizeof *custom_quotes; ++i)
+    {
+      set_custom_quoting (NULL,
+                          custom_quotes[i][0], custom_quotes[i][1]);
+      compare_strings (use_quotearg_buffer, &custom_results[i].group1);
+      compare_strings (use_quotearg, &custom_results[i].group2);
+      compare_strings (use_quotearg_colon, &custom_results[i].group3);
+    }
+
 #if ENABLE_NLS
   /* Clean up environment.  */
   unsetenv ("LANGUAGE");
-- 
1.5.4.3


>From f4414fcbb869bda06d8c66d95451228cb016e034 Mon Sep 17 00:00:00 2001
From: Joel E. Denny <address@hidden>
Date: Sat, 22 Aug 2009 20:55:17 -0400
Subject: [PATCH] quotearg: document limitations of quote_these_too

* lib/quotearg.c (quotearg_buffer_restyled): Add comments where
those limitations are created.
* lib/quotearg.h (set_char_quoting): Document that digits and
letters that are special after backslash are not permitted.
(quotearg_char): Cross-reference set_char_quoting documentation.
---
 ChangeLog      |    9 +++++++++
 lib/quotearg.c |    8 +++++++-
 lib/quotearg.h |    7 +++++--
 3 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 255e17e..42b96f4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
 2009-08-22  Joel E. Denny  <address@hidden>
 
+       quotearg: document limitations of quote_these_too
+       * lib/quotearg.c (quotearg_buffer_restyled): Add comments where
+       those limitations are created.
+       * lib/quotearg.h (set_char_quoting): Document that digits and
+       letters that are special after backslash are not permitted.
+       (quotearg_char): Cross-reference set_char_quoting documentation.
+
+2009-08-22  Joel E. Denny  <address@hidden>
+
        quotearg: implement custom_quoting_style
        * lib/quotearg.c: (struct quoting_options): Add left and right
        fields to store quotes.
diff --git a/lib/quotearg.c b/lib/quotearg.c
index 9e5f038..0c11a62 100644
--- a/lib/quotearg.c
+++ b/lib/quotearg.c
@@ -336,6 +336,10 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
                  STORE ('0');
                }
              c = '0';
+             /* We don't have to worry that this last '0' will be
+                backslash-escaped because, again, quote_string should
+                not start with it and because quote_these_too is
+                documented as not accepting it.  */
            }
          else if (flags & QA_ELIDE_NULL_BYTES)
            continue;
@@ -461,7 +465,9 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
             escape by prepending a backslash.  However, it's hard to
             imagine any locale that would use digits or letters as
             quotes, and set_custom_quoting is documented not to accept
-            them.  */
+            them.  Also, a digit or a special letter would cause
+            trouble if it appeared in quote_these_too, but that's also
+            documented as not accepting them.  */
          break;
 
        default:
diff --git a/lib/quotearg.h b/lib/quotearg.h
index 6704b32..0701d73 100644
--- a/lib/quotearg.h
+++ b/lib/quotearg.h
@@ -240,7 +240,9 @@ void set_quoting_style (struct quoting_options *o, enum 
quoting_style s);
    set the value of the quoting options for character C to I.
    Return the old value.  Currently, the only values defined for I are
    0 (the default) and 1 (which means to quote the character even if
-   it would not otherwise be quoted).  */
+   it would not otherwise be quoted).  C must never be a digit or a
+   letter that has special meaning after a backslash (for example, "\t"
+   for tab).  */
 int set_char_quoting (struct quoting_options *o, char c, int i);
 
 /* In O (or in the default if O is null),
@@ -328,7 +330,8 @@ char *quotearg_style (enum quoting_style s, char const 
*arg);
 char *quotearg_style_mem (enum quoting_style s,
                          char const *arg, size_t argsize);
 
-/* Like quotearg (ARG), except also quote any instances of CH.  */
+/* Like quotearg (ARG), except also quote any instances of CH.
+   See set_char_quoting for a description of acceptable CH values.  */
 char *quotearg_char (char const *arg, char ch);
 
 /* Like quotearg_char (ARG, CH), except it can quote null bytes.  */
-- 
1.5.4.3





reply via email to

[Prev in Thread] Current Thread [Next in Thread]