.
[gnulib.git] / lib / quotearg.c
index 7ccb759..9d43959 100644 (file)
@@ -1,5 +1,5 @@
 /* quotearg.c - quote arguments for output
-   Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
+   Copyright (C) 1998, 1999, 2000, 2001 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
@@ -21,6 +21,9 @@
 # include <config.h>
 #endif
 
+#if HAVE_STDDEF_H
+# include <stddef.h>  /* For the definition of size_t on windows w/MSVC.  */
+#endif
 #include <sys/types.h>
 #include <quotearg.h>
 #include <xalloc.h>
 #endif
 
 #if HAVE_WCHAR_H
+
+/* BSD/OS 4.1 wchar.h requires FILE and struct tm to be declared.  */
+# include <stdio.h>
+# include <time.h>
+
 # include <wchar.h>
 #endif
 
-#if HAVE_MBRTOWC && HAVE_WCHAR_H
-size_t mbrtowc ();
-# if !HAVE_MBSTATE_T_OBJECT
-#  define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
-# endif
-#else
+#if !HAVE_MBRTOWC
+/* Disable multibyte processing entirely.  Since MB_CUR_MAX is 1, the
+   other macros are defined only for documentation and to satisfy C
+   syntax.  */
+# undef MB_CUR_MAX
+# define MB_CUR_MAX 1
 # define mbrtowc(pwc, s, n, ps) ((*(pwc) = *(s)) != 0)
 # define mbsinit(ps) 1
 # define iswprint(wc) ISPRINT ((unsigned char) (wc))
@@ -86,15 +94,14 @@ size_t mbrtowc ();
 #define INT_BITS (sizeof (int) * CHAR_BIT)
 
 #if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
-/* Undefine to protect against the definition in wctype.h of solaris2.6.   */
-# undef ISASCII
-# define ISASCII(c) 1
+# define IN_CTYPE_DOMAIN(c) 1
 #else
-# define ISASCII(c) isascii (c)
+# define IN_CTYPE_DOMAIN(c) isascii(c)
 #endif
+
 /* Undefine to protect against the definition in wctype.h of solaris2.6.   */
 #undef ISPRINT
-#define ISPRINT(c) (ISASCII (c) && isprint (c))
+#define ISPRINT(c) (IN_CTYPE_DOMAIN (c) && isprint (c))
 
 struct quoting_options
 {
@@ -115,6 +122,7 @@ char const *const quoting_style_args[] =
   "c",
   "escape",
   "locale",
+  "clocale",
   0
 };
 
@@ -126,7 +134,8 @@ enum quoting_style const quoting_style_vals[] =
   shell_always_quoting_style,
   c_quoting_style,
   escape_quoting_style,
-  locale_quoting_style
+  locale_quoting_style,
+  clocale_quoting_style
 };
 
 /* The default quoting options.  */
@@ -175,13 +184,15 @@ set_char_quoting (struct quoting_options *o, char c, int i)
   return r;
 }
 
-/* Return the translation of MSGID if there is one, and
-   DEFAULT_TRANSLATION otherwise.  */
+/* MSGID approximates a quotation mark.  Return its translation if it
+   has one; otherwise, return either it or "\"", depending on S.  */
 static char const *
-gettext_default (char const *msgid, char const *default_translation)
+gettext_quote (char const *msgid, enum quoting_style s)
 {
   char const *translation = _(msgid);
-  return translation == msgid ? default_translation : translation;
+  if (translation == msgid && s == clocale_quoting_style)
+    translation = "\"";
+  return translation;
 }
 
 /* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
@@ -208,6 +219,7 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
   char const *quote_string = 0;
   size_t quote_string_len = 0;
   int backslash_escapes = 0;
+  int unibyte_locale = MB_CUR_MAX == 1;
 
 #define STORE(c) \
     do \
@@ -232,30 +244,25 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
       break;
 
     case locale_quoting_style:
+    case clocale_quoting_style:
       {
        /* Get translations for open and closing quotation marks.
 
-          The message catalog should translate "{LEFT QUOTATION
-          MARK}" to a left quotation mark suitable for the locale,
-          and similarly for "{RIGHT QUOTATION MARK}".  If the catalog
-          has no translation, the code below uses a neutral
-          (vertical) quotation mark instead, as it is the most
-          appropriate for the C locale.
+          The message catalog should translate "`" to a left
+          quotation mark suitable for the locale, and similarly for
+          "'".  If the catalog has no translation,
+          locale_quoting_style quotes `like this', and
+          clocale_quoting_style quotes "like this".
 
           For example, an American English Unicode locale should
-          translate the string "{LEFT QUOTATION MARK}" to the
-          character U+201C (LEFT DOUBLE QUOTATION MARK), and should
-          translate the string "{RIGHT QUOTATION MARK}" to the
-          character U+201D (RIGHT DOUBLE QUOTATION MARK).  A British
-          English Unicode locale should instead translate these to
-          U+2018 (LEFT SINGLE QUOTATION MARK) and U+2019 (RIGHT
-          SINGLE QUOTATION MARK), respectively.  */
-
-       static char const quotation_mark[] = "\"";
-       char const *left = gettext_default (N_("{LEFT QUOTATION MARK}"),
-                                           quotation_mark);
-       char const *right = gettext_default (N_("{RIGHT QUOTATION MARK}"),
-                                            quotation_mark);
+          translate "`" to U+201C (LEFT DOUBLE QUOTATION MARK), and
+          should translate "'" to U+201D (RIGHT DOUBLE QUOTATION
+          MARK).  A British English Unicode locale should instead
+          translate these to U+2018 (LEFT SINGLE QUOTATION MARK) and
+          U+2019 (RIGHT SINGLE QUOTATION MARK), respectively.  */
+
+       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);
        backslash_escapes = 1;
@@ -398,57 +405,59 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
             we can't easily escape single characters within it.  */
          {
            /* Length of multibyte sequence found so far.  */
-           size_t m = 0;
-
-           int printable = 1;
-           mbstate_t mbstate;
-           memset (&mbstate, 0, sizeof mbstate);
+           size_t m;
 
-           if (argsize == (size_t) -1)
-             argsize = strlen (arg);
+           int printable;
 
-           do
+           if (unibyte_locale)
              {
-               wchar_t w;
-               size_t bytes = mbrtowc (&w, &arg[i + m],
-                                       argsize - (i + m), &mbstate);
-               if (bytes == 0)
-                 break;
-               else if (bytes == (size_t) -1)
-                 {
-                   printable = 0;
-                   break;
-                 }
-               else if (bytes == (size_t) -2)
-                 {
-                   printable = 0;
-                   while (i + m < argsize && arg[i + m])
-                     m++;
-                   break;
-                 }
-               else
-                 {
-                   if (! iswprint (w))
-                     printable = 0;
-                   m += bytes;
-                 }
+               m = 1;
+               printable = ISPRINT (c);
              }
-           while (! mbsinit (&mbstate));
-
-           if (m <= 1)
+           else
              {
-               /* Escape a unibyte character like a multibyte
-                  sequence if using backslash escapes, and if the
-                  character is not printable.  */
-               m = backslash_escapes && ! ISPRINT (c);
-               printable = 0;
+               mbstate_t mbstate;
+               memset (&mbstate, 0, sizeof mbstate);
+
+               m = 0;
+               printable = 1;
+               if (argsize == (size_t) -1)
+                 argsize = strlen (arg);
+
+               do
+                 {
+                   wchar_t w;
+                   size_t bytes = mbrtowc (&w, &arg[i + m],
+                                           argsize - (i + m), &mbstate);
+                   if (bytes == 0)
+                     break;
+                   else if (bytes == (size_t) -1)
+                     {
+                       printable = 0;
+                       break;
+                     }
+                   else if (bytes == (size_t) -2)
+                     {
+                       printable = 0;
+                       while (i + m < argsize && arg[i + m])
+                         m++;
+                       break;
+                     }
+                   else
+                     {
+                       if (! iswprint (w))
+                         printable = 0;
+                       m += bytes;
+                     }
+                 }
+               while (! mbsinit (&mbstate));
              }
 
-           if (m)
+           if (1 < m || (backslash_escapes && ! printable))
              {
                /* Output a multibyte sequence, or an escaped
                   unprintable unibyte character.  */
-               size_t imax = i + m - 1;
+               size_t ilim = i + m;
 
                for (;;)
                  {
@@ -459,7 +468,7 @@ quotearg_buffer_restyled (char *buffer, size_t buffersize,
                        STORE ('0' + ((c >> 3) & 7));
                        c = '0' + (c & 7);
                      }
-                   if (i == imax)
+                   if (ilim <= i + 1)
                      break;
                    STORE (c);
                    c = arg[++i];
@@ -522,12 +531,17 @@ static char *
 quotearg_n_options (int n, char const *arg,
                    struct quoting_options const *options)
 {
-  static unsigned int nslots;
-  static struct slotvec
+  /* Preallocate a slot 0 buffer, so that the caller can always quote
+     one small component of a "memory exhausted" message in slot 0.  */
+  static char slot0[256];
+  static unsigned int nslots = 1;
+  struct slotvec
     {
       size_t size;
       char *val;
-    } *slotvec;
+    };
+  static struct slotvec slotvec0 = {sizeof slot0, slot0};
+  static struct slotvec *slotvec = &slotvec0;
 
   if (nslots <= n)
     {
@@ -535,6 +549,11 @@ quotearg_n_options (int n, char const *arg,
       size_t s = n1 * sizeof (struct slotvec);
       if (! (0 < n1 && n1 == s / sizeof (struct slotvec)))
        abort ();
+      if (slotvec == &slotvec0)
+       {
+         slotvec = (struct slotvec *) xmalloc (sizeof (struct slotvec));
+         *slotvec = slotvec0;
+       }
       slotvec = (struct slotvec *) xrealloc (slotvec, s);
       memset (slotvec + nslots, 0, (n1 - nslots) * sizeof (struct slotvec));
       nslots = n;
@@ -548,7 +567,7 @@ quotearg_n_options (int n, char const *arg,
     if (size <= qsize)
       {
        slotvec[n].size = size = qsize + 1;
-       slotvec[n].val = val = xrealloc (val, size);
+       slotvec[n].val = val = xrealloc (val == slot0 ? 0 : val, size);
        quotearg_buffer (val, size, arg, (size_t) -1, options);
       }