bug-gnulib
[Top][All Lists]
Advanced

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

Re: filenames in error messages


From: Eric Blake
Subject: Re: filenames in error messages
Date: Fri, 8 Feb 2008 00:22:44 +0000 (UTC)
User-agent: Loom/3.14 (http://gmane.org/)

According to Jim Meyering on 2/7/2008 1:49 AM:

I'm submitting this for review.  Any comments before I apply?

> 
>> Is there any reason that shortcuts like quotearg_style_mem are not
>> defined, in contrast with quotearg_style(s,a) short for
>> quotearg_n_style(0,s,a)?
> 
> I suspect no one noticed.

Fixed in part 1, by adding several new *_mem variants.

>> resulting quoted buffer).  Sure, you can use quotearg_buffer or
>> quotearg_alloc, but then you have to manage the string yourself, whereas
>> it would be kind of nice being able to do
>> ~ error (...,"%s", quotearg_n_style_mem (n, shell_quoting_style, str, len))
> 
> I agree.

After more thought, here's the approach I took.  Since the choice of "literal" 
vs. some other mode might be made based on whether output is a tty or a file 
(at least, I'm planning on doing exactly that in m4, where I've just finished a 
patch to transparently support embedded NUL in m4 macro names), and embedded 
NUL makes sense to a file, it must be possible to preserve embedded NULs.  But 
when using one of the quotearg methods that feeds a char* into error() or 
similar, it is nicer to follow suit with bash and just elide NUL as non-
representable.  After all, POSIX states that the shell is not required to 
handle binary files (ie. embedded NULs).

So for part 2, I added a flag into struct quoting_options, which the user can 
control.  By default, the flag is clear and you get the old behavior (embedded 
NUL) when using APIs that can return a length; when set, the three problematic 
quoting styles elide NUL instead.  I made the quotearg*_mem variants set the 
flag unconditionally, since the quotearg interface is intended for use in error
(), and there is no way to return a length.  The non-_mem variants never output 
embedded NUL in the first place.  Therefore, the only place where the state of 
the flag matters is if the user calls quotearg_buffer or (the new) 
quotearg_alloc_mem.

>> program:file:line: message
>>
>> program:"embedded colon:, quote\", and spaces":line: message
>> program:"http://example.com/file":line: message
> 
> That sounds fine.
> 
>> Should I go ahead and hack on a new quoting style in quotearg.c that can
>> be used in this manner, adding "" around the string only if an escape
>> sequence or quote_these_too character is encountered?
> 
> Please do.

For part 3, I added the "c-maybe" style.  I then factored based on the 
relationship of styles with optional outer quotes:
"shell"->"shell-always"
"c-maybe"->"c"

by adding another flag.  Since the point of this exercise was to come up with a 
uniform quoting style for warning messages, and we already mentioned "" 
quoting, I didn't think it was worth adding a style "locale-maybe" or "clocale-
maybe"; but you can use the new flag to acheive the same effect of optional `' 
quoting.

2008-02-07  Eric Blake  <address@hidden>

        Quotearg part 3: add flag to control outer quote elision.
        * lib/quotearg.h (c_maybe_quoting_style): New style.
        (enum quoting_flags): Better documentation of flags.
        * lib/quotearg.c (quoting_style_args, quoting_style_vals): Add
        c-maybe style.
        (quotearg_buffer_restyled): Handle new flag to elide outer
        quotes.

        Quotearg part 2: add flag that can control NUL elision.
        * lib/quotearg.h (set_quoting_flags): New prototype.
        * lib/quotearg.c (struct quoting_options): Add flag field.
        (set_quoting_flags): New function.
        (quotearg_buffer_restyled): Add flags parameter.
        (quotearg_alloc_mem): Set the flag if length cannot be returned.
        (quotearg_n_options): Set the flag, since length cannot be
        returned.
        (quoting_options_from_style): Default flags correctly.

        Quotearg part 1: more wrappers, restore quotearg_char state.
        * lib/quotearg.h (quotearg_alloc_mem, quotearg_n_mem)
        (quotearg_mem, quotearg_style_mem, quotearg_char_mem)
        (quotearg_colon_mem): New wrappers.
        * lib/quotearg.c (quotearg_alloc, quotearg_char): Rewrite...
        (quotearg_alloc_mem, quotearg_char_mem): ...in terms of these new
        functions.
        (quotearg_n_mem, quotearg_mem, quotearg_style_mem)
        (quotearg_colon_mem): New functions.

-- 
Eric Blake

>From 1c58cf7c6b3663b1c43c4d2326c229eead84dd07 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Thu, 7 Feb 2008 06:39:57 -0700
Subject: [PATCH] Quotearg part 1: more wrappers, restore quotearg_char state.

* lib/quotearg.h (quotearg_alloc_mem, quotearg_n_mem)
(quotearg_mem, quotearg_style_mem, quotearg_char_mem)
(quotearg_colon_mem): New wrappers.
* lib/quotearg.c (quotearg_alloc, quotearg_char): Rewrite...
(quotearg_alloc_mem, quotearg_char_mem): ...in terms of these new
functions.
(quotearg_n_mem, quotearg_mem, quotearg_style_mem)
(quotearg_colon_mem): New functions.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog      |   12 ++++++++++++
 lib/quotearg.c |   55 +++++++++++++++++++++++++++++++++++++++++++++++++------
 lib/quotearg.h |   31 +++++++++++++++++++++++++++++--
 3 files changed, 90 insertions(+), 8 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 649d127..9aaf5c9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2008-02-07  Eric Blake  <address@hidden>
+
+       Quotearg part 1: more wrappers, restore quotearg_char state.
+       * lib/quotearg.h (quotearg_alloc_mem, quotearg_n_mem)
+       (quotearg_mem, quotearg_style_mem, quotearg_char_mem)
+       (quotearg_colon_mem): New wrappers.
+       * lib/quotearg.c (quotearg_alloc, quotearg_char): Rewrite...
+       (quotearg_alloc_mem, quotearg_char_mem): ...in terms of these new
+       functions.
+       (quotearg_n_mem, quotearg_mem, quotearg_style_mem)
+       (quotearg_colon_mem): New functions.
+
 2008-02-06  Bruno Haible  <address@hidden>
 
        Fix *printf behaviour regarding the left-adjust flag on HP-UX 10.20.
diff --git a/lib/quotearg.c b/lib/quotearg.c
index 00d397c..34a9e77 100644
--- a/lib/quotearg.c
+++ b/lib/quotearg.c
@@ -1,7 +1,7 @@
 /* quotearg.c - quote arguments for output
 
-   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007 Free
-   Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007,
+   2008 Free Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -529,17 +529,30 @@ quotearg_buffer (char *buffer, size_t buffersize,
   return r;
 }
 
-/* Like quotearg_buffer (..., ARG, ARGSIZE, O), except return newly
-   allocated storage containing the quoted string.  */
+/* Equivalent to quotearg_alloc (ARG, ARGSIZE, NULL, O).  */
 char *
 quotearg_alloc (char const *arg, size_t argsize,
                struct quoting_options const *o)
 {
+  return quotearg_alloc_mem (arg, argsize, NULL, o);
+}
+
+/* Like quotearg_buffer (..., ARG, ARGSIZE, O), except return newly
+   allocated storage containing the quoted string, and store the
+   resulting size into *SIZE, if non-NULL.  If SIZE is NULL, then
+   either ARGSIZE should be -1, or O should escape or elide any
+   embedded null bytes.  */
+char *
+quotearg_alloc_mem (char const *arg, size_t argsize, size_t *size,
+                   struct quoting_options const *o)
+{
   int e = errno;
   size_t bufsize = quotearg_buffer (0, 0, arg, argsize, o) + 1;
   char *buf = xcharalloc (bufsize);
   quotearg_buffer (buf, bufsize, arg, argsize, o);
   errno = e;
+  if (size)
+    *size = bufsize - 1;
   return buf;
 }
 
@@ -644,11 +657,23 @@ quotearg_n (int n, char const *arg)
 }
 
 char *
+quotearg_n_mem (int n, char const *arg, size_t argsize)
+{
+  return quotearg_n_options (n, arg, argsize, &default_quoting_options);
+}
+
+char *
 quotearg (char const *arg)
 {
   return quotearg_n (0, arg);
 }
 
+char *
+quotearg_mem (char const *arg, size_t argsize)
+{
+  return quotearg_n_mem (0, arg, argsize);
+}
+
 /* Return quoting options for STYLE, with no extra quoting.  */
 static struct quoting_options
 quoting_options_from_style (enum quoting_style style)
@@ -681,12 +706,24 @@ quotearg_style (enum quoting_style s, char const *arg)
 }
 
 char *
-quotearg_char (char const *arg, char ch)
+quotearg_style_mem (enum quoting_style s, char const *arg, size_t argsize)
+{
+  return quotearg_n_style_mem (0, s, arg, argsize);
+}
+
+char *
+quotearg_char_mem (char const *arg, size_t argsize, char ch)
 {
   struct quoting_options options;
   options = default_quoting_options;
   set_char_quoting (&options, ch, 1);
-  return quotearg_n_options (0, arg, SIZE_MAX, &options);
+  return quotearg_n_options (0, arg, argsize, &options);
+}
+
+char *
+quotearg_char (char const *arg, char ch)
+{
+  return quotearg_char_mem (arg, SIZE_MAX, ch);
 }
 
 char *
@@ -694,3 +731,9 @@ quotearg_colon (char const *arg)
 {
   return quotearg_char (arg, ':');
 }
+
+char *
+quotearg_colon_mem (char const *arg, size_t argsize)
+{
+  return quotearg_char_mem (arg, argsize, ':');
+}
diff --git a/lib/quotearg.h b/lib/quotearg.h
index d11d059..d59ccd6 100644
--- a/lib/quotearg.h
+++ b/lib/quotearg.h
@@ -1,6 +1,6 @@
 /* quotearg.h - quote arguments for output
 
-   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2006 Free
+   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2006, 2008 Free
    Software Foundation, Inc.
 
    This program is free software: you can redistribute it and/or modify
@@ -99,10 +99,19 @@ size_t quotearg_buffer (char *buffer, size_t buffersize,
                        struct quoting_options const *o);
 
 /* Like quotearg_buffer, except return the result in a newly allocated
-   buffer.  It is the caller's responsibility to free the result.  */
+   buffer.  It is the caller's responsibility to free the result.
+   Either ARGSIZE should be -1, or O should not permit embedded null
+   bytes in the output.  */
 char *quotearg_alloc (char const *arg, size_t argsize,
                      struct quoting_options const *o);
 
+/* Like quotearg_alloc, except that the length of the result,
+   excluding the terminating null byte, is stored into SIZE if it is
+   non-NULL.  Thus, this can be safe to use even when O specifies
+   embedded null bytes.  */
+char *quotearg_alloc_mem (char const *arg, size_t argsize,
+                         size_t *size, struct quoting_options const *o);
+
 /* Use storage slot N to return a quoted version of the string ARG.
    Use the default quoting options.
    The returned value points to static storage that can be
@@ -113,6 +122,14 @@ char *quotearg_n (int n, char const *arg);
 /* Equivalent to quotearg_n (0, ARG).  */
 char *quotearg (char const *arg);
 
+/* Use storage slot N to return a quoted version of the argument ARG
+   of size ARGSIZE.  This is like quotearg_n (N, ARG), except it can
+   quote null bytes.  */
+char *quotearg_n_mem (int n, char const *arg, size_t argsize);
+
+/* Equivalent to quotearg_n_mem (0, ARG, ARGSIZE).  */
+char *quotearg_mem (char const *arg, size_t argsize);
+
 /* Use style S and storage slot N to return a quoted version of the string ARG.
    This is like quotearg_n (N, ARG), except that it uses S with no other
    options to specify the quoting method.  */
@@ -127,12 +144,22 @@ char *quotearg_n_style_mem (int n, enum quoting_style s,
 /* Equivalent to quotearg_n_style (0, S, ARG).  */
 char *quotearg_style (enum quoting_style s, char const *arg);
 
+/* Equivalent to quotearg_n_style_mem (0, S, ARG, ARGSIZE).  */
+char *quotearg_style_mem (enum quoting_style s,
+                         char const *arg, size_t argsize);
+
 /* Like quotearg (ARG), except also quote any instances of CH.  */
 char *quotearg_char (char const *arg, char ch);
 
+/* Like quotearg_char (ARG, CH), except it can quote null bytes.  */
+char *quotearg_char_mem (char const *arg, size_t argsize, char ch);
+
 /* Equivalent to quotearg_char (ARG, ':').  */
 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);
+
 /* Free any dynamically allocated memory.  */
 void quotearg_free (void);
 
-- 
1.5.4


>From 58acdd6e4dad5d690403826cf6f3afe8040801d6 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Thu, 7 Feb 2008 14:35:51 -0700
Subject: [PATCH] Quotearg part 2: add flag that can control NUL elision.

* lib/quotearg.h (set_quoting_flags): New prototype.
* lib/quotearg.c (struct quoting_options): Add flag field.
(set_quoting_flags): New function.
(quotearg_buffer_restyled): Add flags parameter.
(quotearg_alloc_mem): Set the flag if length cannot be returned.
(quotearg_n_options): Set the flag, since length cannot be
returned.
(quoting_options_from_style): Default flags correctly.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog      |   16 ++++++++++++--
 lib/quotearg.c |   61 +++++++++++++++++++++++++++++++++++++++++++------------
 lib/quotearg.h |   36 +++++++++++++++++++++++---------
 3 files changed, 86 insertions(+), 27 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 9aaf5c9..120fafc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,15 @@
 2008-02-07  Eric Blake  <address@hidden>
 
+       Quotearg part 2: add flag that can control NUL elision.
+       * lib/quotearg.h (set_quoting_flags): New prototype.
+       * lib/quotearg.c (struct quoting_options): Add flag field.
+       (set_quoting_flags): New function.
+       (quotearg_buffer_restyled): Add flags parameter.
+       (quotearg_alloc_mem): Set the flag if length cannot be returned.
+       (quotearg_n_options): Set the flag, since length cannot be
+       returned.
+       (quoting_options_from_style): Default flags correctly.
+
        Quotearg part 1: more wrappers, restore quotearg_char state.
        * lib/quotearg.h (quotearg_alloc_mem, quotearg_n_mem)
        (quotearg_mem, quotearg_style_mem, quotearg_char_mem)
@@ -137,7 +147,7 @@
        * lib/sha1.h: Likewise.
 
 2008-01-30  Andreas Schwab  <address@hidden>
-            Bruno Haible  <address@hidden>
+           Bruno Haible  <address@hidden>
 
        * m4/frexpl.m4 (gl_FUNC_FREXPL_WORKS): Include <float.h> and ensure a
        correct definition of LDBL_MIN_EXP.
@@ -242,7 +252,7 @@
        * NEWS: Mention the change.
 
 2008-01-25  Paul Eggert  <address@hidden>
-            Bruno Haible  <address@hidden>
+           Bruno Haible  <address@hidden>
 
        * m4/signbit.m4 (gl_SIGNBIT): Require a macro definition. Test whether
        the GCC builtins for signbits are present and set
@@ -378,7 +388,7 @@
        here, since it is not a POSIX function.
 
 2008-01-14  Colin Watson  <address@hidden>
-            Bruno Haible  <address@hidden>
+           Bruno Haible  <address@hidden>
 
        * m4/strsignal.m4 (gl_FUNC_STRSIGNAL): Also check whether strsignal
        works fine; if not, set REPLACE_STRSIGNAL.
diff --git a/lib/quotearg.c b/lib/quotearg.c
index 34a9e77..f9628e5 100644
--- a/lib/quotearg.c
+++ b/lib/quotearg.c
@@ -65,6 +65,11 @@ struct quoting_options
   /* Basic quoting style.  */
   enum quoting_style style;
 
+  /* Additional flags.  Behavior is altered according to these bits:
+     0x01: Elide null bytes rather than embed them unquoted.
+   */
+  int flags;
+
   /* 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];
@@ -143,6 +148,22 @@ set_char_quoting (struct quoting_options *o, char c, int i)
   return r;
 }
 
+/* In O (or in the default if O is null),
+   set the value of the quoting options flag to I.
+   Return the old value.  Currently, the only values defined for I are
+   0 (the default) and 1 (which means to elide null bytes from styles
+   that would otherwise output them unquoted).  */
+int
+set_quoting_flags (struct quoting_options *o, int i)
+{
+  int r;
+  if (!o)
+    o = &default_quoting_options;
+  r = o->flags;
+  o->flags = i;
+  return r;
+}
+
 /* MSGID approximates a quotation mark.  Return its translation if it
    has one; otherwise, return either it or "\"", depending on S.  */
 static char const *
@@ -155,8 +176,8 @@ gettext_quote (char const *msgid, enum quoting_style s)
 }
 
 /* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
-   argument ARG (of size ARGSIZE), using QUOTING_STYLE and the
-   non-quoting-style part of O to control quoting.
+   argument ARG (of size ARGSIZE), using QUOTING_STYLE, FLAGS, and the
+   remaining part of O to control quoting.
    Terminate the output with a null character, and return the written
    size of the output, not counting the terminating null.
    If BUFFERSIZE is too small to store the output string, return the
@@ -164,13 +185,13 @@ gettext_quote (char const *msgid, enum quoting_style s)
    If ARGSIZE is SIZE_MAX, use the string length of the argument for ARGSIZE.
 
    This function acts like quotearg_buffer (BUFFER, BUFFERSIZE, ARG,
-   ARGSIZE, O), except it uses QUOTING_STYLE instead of the quoting
-   style specified by O, and O may not be null.  */
+   ARGSIZE, O), except it uses QUOTING_STYLE and FLAGS instead of the
+   quoting style specified by O, and O may not be null.  */
 
 static size_t
 quotearg_buffer_restyled (char *buffer, size_t buffersize,
                          char const *arg, size_t argsize,
-                         enum quoting_style quoting_style,
+                         enum quoting_style quoting_style, int flags,
                          struct quoting_options const *o)
 {
   size_t i;
@@ -267,6 +288,8 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
              STORE ('0');
              c = '0';
            }
+         else if (flags & 0x1)
+           continue;
          break;
 
        case '?':
@@ -504,7 +527,7 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
 
  use_shell_always_quoting_style:
   return quotearg_buffer_restyled (buffer, buffersize, arg, argsize,
-                                  shell_always_quoting_style, o);
+                                  shell_always_quoting_style, flags, o);
 }
 
 /* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
@@ -524,7 +547,7 @@ 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);
+                                      p->style, p->flags, p);
   errno = e;
   return r;
 }
@@ -539,17 +562,22 @@ quotearg_alloc (char const *arg, size_t argsize,
 
 /* Like quotearg_buffer (..., ARG, ARGSIZE, O), except return newly
    allocated storage containing the quoted string, and store the
-   resulting size into *SIZE, if non-NULL.  If SIZE is NULL, then
-   either ARGSIZE should be -1, or O should escape or elide any
-   embedded null bytes.  */
+   resulting size into *SIZE, if non-NULL.  The result can contain
+   embedded null bytes only if ARGSIZE is not SIZE_MAX, SIZE is not
+   NULL, and set_quoting_flags has not set the null byte elision
+   flag.  */
 char *
 quotearg_alloc_mem (char const *arg, size_t argsize, size_t *size,
                    struct quoting_options const *o)
 {
+  struct quoting_options const *p = o ? o : &default_quoting_options;
   int e = errno;
-  size_t bufsize = quotearg_buffer (0, 0, arg, argsize, o) + 1;
+  /* Elide embedded null bytes if we can't return a size.  */
+  int flags = p->flags | (size ? 0 : 0x1);
+  size_t bufsize = quotearg_buffer_restyled (0, 0, arg, argsize, p->style,
+                                            flags, p) + 1;
   char *buf = xcharalloc (bufsize);
-  quotearg_buffer (buf, bufsize, arg, argsize, o);
+  quotearg_buffer_restyled (buf, bufsize, arg, argsize, p->style, flags, p);
   errno = e;
   if (size)
     *size = bufsize - 1;
@@ -634,7 +662,10 @@ quotearg_n_options (int n, char const *arg, size_t argsize,
   {
     size_t size = sv[n].size;
     char *val = sv[n].val;
-    size_t qsize = quotearg_buffer (val, size, arg, argsize, options);
+    /* Elide embedded null bytes since we don't return a size.  */
+    size_t qsize = quotearg_buffer_restyled (val, size, arg, argsize,
+                                            options->style,
+                                            options->flags | 0x1, options);
 
     if (size <= qsize)
       {
@@ -642,7 +673,8 @@ quotearg_n_options (int n, char const *arg, size_t argsize,
        if (val != slot0)
          free (val);
        sv[n].val = val = xcharalloc (size);
-       quotearg_buffer (val, size, arg, argsize, options);
+       quotearg_buffer_restyled (val, size, arg, argsize, options->style,
+                                 options->flags | 0x1, options);
       }
 
     errno = e;
@@ -680,6 +712,7 @@ quoting_options_from_style (enum quoting_style style)
 {
   struct quoting_options o;
   o.style = style;
+  o.flags = 0;
   memset (o.quote_these_too, 0, sizeof o.quote_these_too);
   return o;
 }
diff --git a/lib/quotearg.h b/lib/quotearg.h
index d59ccd6..501c856 100644
--- a/lib/quotearg.h
+++ b/lib/quotearg.h
@@ -26,15 +26,18 @@
 /* Basic quoting styles.  */
 enum quoting_style
   {
-    /* Output names as-is (ls --quoting-style=literal).  */
+    /* Output names as-is (ls --quoting-style=literal).  Can result in
+       embedded null bytes in some cases.  */
     literal_quoting_style,
 
     /* Quote names for the shell if they contain shell metacharacters
-       or would cause ambiguous output (ls --quoting-style=shell).  */
+       or would cause ambiguous output (ls --quoting-style=shell).
+       Can result in embedded null bytes in some cases.  */
     shell_quoting_style,
 
     /* Quote names for the shell, even if they would normally not
-       require quoting (ls --quoting-style=shell-always).  */
+       require quoting (ls --quoting-style=shell-always).  Can result
+       in embedded null bytes in some cases.  */
     shell_always_quoting_style,
 
     /* Quote names as for a C language string (ls --quoting-style=c).  */
@@ -86,6 +89,13 @@ void set_quoting_style (struct quoting_options *o, enum 
quoting_style s);
    it would not otherwise be quoted).  */
 int set_char_quoting (struct quoting_options *o, char c, int i);
 
+/* In O (or in the default if O is null),
+   set the value of the quoting options flag to I.
+   Return the old value.  Currently, the only values defined for I are
+   0 (the default) and 1 (which means to elide null bytes from styles
+   that would otherwise output them unquoted).  */
+int set_quoting_flags (struct quoting_options *o, int i);
+
 /* 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.
@@ -93,22 +103,26 @@ int set_char_quoting (struct quoting_options *o, char c, 
int i);
    size of the output, not counting the terminating null.
    If BUFFERSIZE is too small to store the output string, return the
    value that would have been returned had BUFFERSIZE been large enough.
-   If ARGSIZE is -1, use the string length of the argument for ARGSIZE.  */
+   If ARGSIZE is -1, use the string length of the argument for ARGSIZE.
+   On output, BUFFER might contain embedded null bytes if ARGSIZE was
+   not -1, the style of O does not use backslash escapes, and the
+   flags of O do not request elision of null bytes.*/
 size_t quotearg_buffer (char *buffer, size_t buffersize,
                        char const *arg, size_t argsize,
                        struct quoting_options const *o);
 
 /* Like quotearg_buffer, except return the result in a newly allocated
-   buffer.  It is the caller's responsibility to free the result.
-   Either ARGSIZE should be -1, or O should not permit embedded null
-   bytes in the output.  */
+   buffer.  It is the caller's responsibility to free the result.  The
+   result will not contain embedded null bytes.  */
 char *quotearg_alloc (char const *arg, size_t argsize,
                      struct quoting_options const *o);
 
 /* Like quotearg_alloc, except that the length of the result,
    excluding the terminating null byte, is stored into SIZE if it is
-   non-NULL.  Thus, this can be safe to use even when O specifies
-   embedded null bytes.  */
+   non-NULL.  The result might contain embedded null bytes if ARGSIZE
+   was not -1, SIZE was not NULL, the style of O does not use
+   backslash escapes, and the flags of O do not request elision of
+   null bytes.*/
 char *quotearg_alloc_mem (char const *arg, size_t argsize,
                          size_t *size, struct quoting_options const *o);
 
@@ -116,7 +130,9 @@ char *quotearg_alloc_mem (char const *arg, size_t argsize,
    Use the default quoting options.
    The returned value points to static storage that can be
    reused by the next call to this function with the same value of N.
-   N must be nonnegative.  */
+   N must be nonnegative.  The output of all functions in the
+   quotearg_n family are guaranteed to not contain embedded null
+   bytes.*/
 char *quotearg_n (int n, char const *arg);
 
 /* Equivalent to quotearg_n (0, ARG).  */
-- 
1.5.4


>From 622f38003aabdadef672e390338f35b6aa1a29f3 Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Thu, 7 Feb 2008 16:44:01 -0700
Subject: [PATCH] Quotearg part 3: add flag to control outer quote elision.

* lib/quotearg.h (c_maybe_quoting_style): New style.
(enum quoting_flags): Better documentation of flags.
* lib/quotearg.c (quoting_style_args, quoting_style_vals): Add
c-maybe style.
(quotearg_buffer_restyled): Handle new flag to elide outer
quotes.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog      |    8 ++++
 lib/quotearg.c |  110 +++++++++++++++++++++++++++++++++++--------------------
 lib/quotearg.h |   40 ++++++++++++++++-----
 3 files changed, 109 insertions(+), 49 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 120fafc..73c8db0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,13 @@
 2008-02-07  Eric Blake  <address@hidden>
 
+       Quotearg part 3: add flag to control outer quote elision.
+       * lib/quotearg.h (c_maybe_quoting_style): New style.
+       (enum quoting_flags): Better documentation of flags.
+       * lib/quotearg.c (quoting_style_args, quoting_style_vals): Add
+       c-maybe style.
+       (quotearg_buffer_restyled): Handle new flag to elide outer
+       quotes.
+
        Quotearg part 2: add flag that can control NUL elision.
        * lib/quotearg.h (set_quoting_flags): New prototype.
        * lib/quotearg.c (struct quoting_options): Add flag field.
diff --git a/lib/quotearg.c b/lib/quotearg.c
index f9628e5..b6237b0 100644
--- a/lib/quotearg.c
+++ b/lib/quotearg.c
@@ -65,9 +65,7 @@ struct quoting_options
   /* Basic quoting style.  */
   enum quoting_style style;
 
-  /* Additional flags.  Behavior is altered according to these bits:
-     0x01: Elide null bytes rather than embed them unquoted.
-   */
+  /* Additional flags.  Bitwise combination of enum quoting_flags.  */
   int flags;
 
   /* Quote the characters indicated by this bit vector even if the
@@ -82,6 +80,7 @@ char const *const quoting_style_args[] =
   "shell",
   "shell-always",
   "c",
+  "c-maybe",
   "escape",
   "locale",
   "clocale",
@@ -95,6 +94,7 @@ enum quoting_style const quoting_style_vals[] =
   shell_quoting_style,
   shell_always_quoting_style,
   c_quoting_style,
+  c_maybe_quoting_style,
   escape_quoting_style,
   locale_quoting_style,
   clocale_quoting_style
@@ -149,10 +149,9 @@ set_char_quoting (struct quoting_options *o, char c, int i)
 }
 
 /* In O (or in the default if O is null),
-   set the value of the quoting options flag to I.
-   Return the old value.  Currently, the only values defined for I are
-   0 (the default) and 1 (which means to elide null bytes from styles
-   that would otherwise output them unquoted).  */
+   set the value of the quoting options flag to I, which can be a
+   bitwise combination of enum quoting_flags, or 0 for default
+   behavior.  Return the old value.  */
 int
 set_quoting_flags (struct quoting_options *o, int i)
 {
@@ -200,6 +199,7 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
   size_t quote_string_len = 0;
   bool backslash_escapes = false;
   bool unibyte_locale = MB_CUR_MAX == 1;
+  bool elide_outer_quotes = (flags & QA_ELIDE_OUTER_QUOTES) != 0;
 
 #define STORE(c) \
     do \
@@ -212,8 +212,13 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
 
   switch (quoting_style)
     {
+    case c_maybe_quoting_style:
+      quoting_style = c_quoting_style;
+      elide_outer_quotes = true;
+      /* Fall through.  */
     case c_quoting_style:
-      STORE ('"');
+      if (!elide_outer_quotes)
+       STORE ('"');
       backslash_escapes = true;
       quote_string = "\"";
       quote_string_len = 1;
@@ -221,6 +226,7 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
 
     case escape_quoting_style:
       backslash_escapes = true;
+      elide_outer_quotes = false;
       break;
 
     case locale_quoting_style:
@@ -248,22 +254,32 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
 
        char const *left = gettext_quote (N_("`"), quoting_style);
        char const *right = gettext_quote (N_("'"), quoting_style);
-       for (quote_string = left; *quote_string; quote_string++)
-         STORE (*quote_string);
+       if (!elide_outer_quotes)
+         for (quote_string = left; *quote_string; quote_string++)
+           STORE (*quote_string);
        backslash_escapes = true;
        quote_string = right;
        quote_string_len = strlen (quote_string);
       }
       break;
 
+    case shell_quoting_style:
+      quoting_style = shell_always_quoting_style;
+      elide_outer_quotes = true;
+      /* Fall through.  */
     case shell_always_quoting_style:
-      STORE ('\'');
+      if (!elide_outer_quotes)
+       STORE ('\'');
       quote_string = "'";
       quote_string_len = 1;
       break;
 
-    default:
+    case literal_quoting_style:
+      elide_outer_quotes = false;
       break;
+
+    default:
+      abort ();
     }
 
   for (i = 0;  ! (argsize == SIZE_MAX ? arg[i] == '\0' : i == argsize);  i++)
@@ -275,7 +291,11 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
          && quote_string_len
          && i + quote_string_len <= argsize
          && memcmp (arg + i, quote_string, quote_string_len) == 0)
-       STORE ('\\');
+       {
+         if (elide_outer_quotes)
+           goto force_outer_quoting_style;
+         STORE ('\\');
+       }
 
       c = arg[i];
       switch (c)
@@ -283,20 +303,24 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
        case '\0':
          if (backslash_escapes)
            {
+             if (elide_outer_quotes)
+               goto force_outer_quoting_style;
              STORE ('\\');
              STORE ('0');
              STORE ('0');
              c = '0';
            }
-         else if (flags & 0x1)
+         else if (flags & QA_ELIDE_NULL_BYTES)
            continue;
          break;
 
        case '?':
          switch (quoting_style)
            {
-           case shell_quoting_style:
-             goto use_shell_always_quoting_style;
+           case shell_always_quoting_style:
+             if (elide_outer_quotes)
+               goto force_outer_quoting_style;
+             break;
 
            case c_quoting_style:
              if (i + 2 < argsize && arg[i + 1] == '?')
@@ -307,6 +331,8 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
                  case '<': case '=': case '>':
                    /* Escape the second '?' in what would otherwise be
                       a trigraph.  */
+                   if (elide_outer_quotes)
+                     goto force_outer_quoting_style;
                    c = arg[i + 2];
                    i += 2;
                    STORE ('?');
@@ -334,8 +360,10 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
        case '\\': esc = c; goto c_and_shell_escape;
 
        c_and_shell_escape:
-         if (quoting_style == shell_quoting_style)
-           goto use_shell_always_quoting_style;
+         if (quoting_style == shell_always_quoting_style
+             && elide_outer_quotes)
+           goto force_outer_quoting_style;
+         /* Fall through.  */
        c_escape:
          if (backslash_escapes)
            {
@@ -365,24 +393,19 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
             be the first bytes of multibyte characters, which means
             we should check them with mbrtowc, but in practice this
             doesn't happen so it's not worth worrying about.  */
-         if (quoting_style == shell_quoting_style)
-           goto use_shell_always_quoting_style;
+         if (quoting_style == shell_always_quoting_style
+             && elide_outer_quotes)
+           goto force_outer_quoting_style;
          break;
 
        case '\'':
-         switch (quoting_style)
+         if (quoting_style == shell_always_quoting_style)
            {
-           case shell_quoting_style:
-             goto use_shell_always_quoting_style;
-
-           case shell_always_quoting_style:
+             if (elide_outer_quotes)
+               goto force_outer_quoting_style;
              STORE ('\'');
              STORE ('\\');
              STORE ('\'');
-             break;
-
-           default:
-             break;
            }
          break;
 
@@ -454,7 +477,8 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
                           that is really the 2nd byte of a multibyte character.
                           In practice the problem is limited to ASCII
                           chars >= '@' that are shell special chars.  */
-                       if ('[' == 0x5b && quoting_style == shell_quoting_style)
+                       if ('[' == 0x5b && elide_outer_quotes
+                           && quoting_style == shell_always_quoting_style)
                          {
                            size_t j;
                            for (j = 1; j < bytes; j++)
@@ -462,7 +486,7 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
                                {
                                case '[': case '\\': case '^':
                                case '`': case '|':
-                                 goto use_shell_always_quoting_style;
+                                 goto force_outer_quoting_style;
 
                                default:
                                  break;
@@ -487,6 +511,8 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
                  {
                    if (backslash_escapes && ! printable)
                      {
+                       if (elide_outer_quotes)
+                         goto force_outer_quoting_style;
                        STORE ('\\');
                        STORE ('0' + (c >> 6));
                        STORE ('0' + ((c >> 3) & 7));
@@ -508,16 +534,19 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
        goto store_c;
 
     store_escape:
+      if (elide_outer_quotes)
+       goto force_outer_quoting_style;
       STORE ('\\');
 
     store_c:
       STORE (c);
     }
 
-  if (i == 0 && quoting_style == shell_quoting_style)
-    goto use_shell_always_quoting_style;
+  if (i == 0 && quoting_style == shell_always_quoting_style
+      && elide_outer_quotes)
+    goto force_outer_quoting_style;
 
-  if (quote_string)
+  if (quote_string && !elide_outer_quotes)
     for (; *quote_string; quote_string++)
       STORE (*quote_string);
 
@@ -525,9 +554,10 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
     buffer[len] = '\0';
   return len;
 
- use_shell_always_quoting_style:
+ force_outer_quoting_style:
   return quotearg_buffer_restyled (buffer, buffersize, arg, argsize,
-                                  shell_always_quoting_style, flags, o);
+                                  quoting_style,
+                                  flags & ~QA_ELIDE_OUTER_QUOTES, o);
 }
 
 /* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
@@ -573,7 +603,7 @@ quotearg_alloc_mem (char const *arg, size_t argsize, size_t 
*size,
   struct quoting_options const *p = o ? o : &default_quoting_options;
   int e = errno;
   /* Elide embedded null bytes if we can't return a size.  */
-  int flags = p->flags | (size ? 0 : 0x1);
+  int flags = p->flags | (size ? 0 : QA_ELIDE_NULL_BYTES);
   size_t bufsize = quotearg_buffer_restyled (0, 0, arg, argsize, p->style,
                                             flags, p) + 1;
   char *buf = xcharalloc (bufsize);
@@ -663,9 +693,9 @@ quotearg_n_options (int n, char const *arg, size_t argsize,
     size_t size = sv[n].size;
     char *val = sv[n].val;
     /* Elide embedded null bytes since we don't return a size.  */
+    int flags = options->flags | QA_ELIDE_NULL_BYTES;
     size_t qsize = quotearg_buffer_restyled (val, size, arg, argsize,
-                                            options->style,
-                                            options->flags | 0x1, options);
+                                            options->style, flags, options);
 
     if (size <= qsize)
       {
@@ -674,7 +704,7 @@ 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,
-                                 options->flags | 0x1, options);
+                                 flags, options);
       }
 
     errno = e;
diff --git a/lib/quotearg.h b/lib/quotearg.h
index 501c856..5d3ca47 100644
--- a/lib/quotearg.h
+++ b/lib/quotearg.h
@@ -27,24 +27,34 @@
 enum quoting_style
   {
     /* Output names as-is (ls --quoting-style=literal).  Can result in
-       embedded null bytes in some cases.  */
+       embedded null bytes if QA_ELIDE_NULL_BYTES is not in
+       effect.  */
     literal_quoting_style,
 
     /* Quote names for the shell if they contain shell metacharacters
        or would cause ambiguous output (ls --quoting-style=shell).
-       Can result in embedded null bytes in some cases.  */
+       Can result in embedded null bytes if QA_ELIDE_NULL_BYTES is not
+       in effect.  */
     shell_quoting_style,
 
     /* Quote names for the shell, even if they would normally not
        require quoting (ls --quoting-style=shell-always).  Can result
-       in embedded null bytes in some cases.  */
+       in embedded null bytes if QA_ELIDE_NULL_BYTES is not in effect.
+       Behaves like shell_quoting_style if QA_ELIDE_OUTER_QUOTES is in
+       effect.  */
     shell_always_quoting_style,
 
-    /* Quote names as for a C language string (ls --quoting-style=c).  */
+    /* Quote names as for a C language string (ls --quoting-style=c).
+       Behaves like c_maybe_quoting_style if QA_ELIDE_OUTER_QUOTES is
+       in effect.  */
     c_quoting_style,
 
     /* Like c_quoting_style except omit the surrounding double-quote
-       characters (ls --quoting-style=escape).  */
+       characters if no quoted characters are encountered.  */
+    c_maybe_quoting_style,
+
+    /* Like c_quoting_style except always omit the surrounding
+       double-quote characters (ls --quoting-style=escape).  */
     escape_quoting_style,
 
     /* Like clocale_quoting_style, but quote `like this' instead of
@@ -56,6 +66,19 @@ enum quoting_style
     clocale_quoting_style
   };
 
+/* Flags for use in set_quoting_flags.  */
+enum quoting_flags
+  {
+    /* Always elide null bytes from styles that do not quote them,
+       even when the length of the result is available to the
+       caller.  */
+    QA_ELIDE_NULL_BYTES = 0x01,
+
+    /* Omit the surrounding quote characters if no escaped characters
+       are encountered.  */
+    QA_ELIDE_OUTER_QUOTES = 0x02
+  };
+
 /* For now, --quoting-style=literal is the default, but this may change.  */
 # ifndef DEFAULT_QUOTING_STYLE
 #  define DEFAULT_QUOTING_STYLE literal_quoting_style
@@ -90,10 +113,9 @@ void set_quoting_style (struct quoting_options *o, enum 
quoting_style s);
 int set_char_quoting (struct quoting_options *o, char c, int i);
 
 /* In O (or in the default if O is null),
-   set the value of the quoting options flag to I.
-   Return the old value.  Currently, the only values defined for I are
-   0 (the default) and 1 (which means to elide null bytes from styles
-   that would otherwise output them unquoted).  */
+   set the value of the quoting options flag to I, which can be a
+   bitwise combination of enum quoting_flags, or 0 for default
+   behavior.  Return the old value.  */
 int set_quoting_flags (struct quoting_options *o, int i);
 
 /* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
-- 
1.5.4







reply via email to

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