The old behavior of quoting `like this' doesn't look good with
[pspp] / lib / quotearg.c
1 /* quotearg.c - quote arguments for output
2    Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2, or (at your option)
7    any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software Foundation,
16    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 /* Written by Paul Eggert <eggert@twinsun.com> */
19
20 #if HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <sys/types.h>
25 #include <quotearg.h>
26 #include <xalloc.h>
27
28 #include <ctype.h>
29
30 #if ENABLE_NLS
31 # include <libintl.h>
32 # define _(text) gettext (text)
33 #else
34 # define _(text) text
35 #endif
36 #define N_(text) text
37
38 #if HAVE_LIMITS_H
39 # include <limits.h>
40 #endif
41 #ifndef CHAR_BIT
42 # define CHAR_BIT 8
43 #endif
44 #ifndef UCHAR_MAX
45 # define UCHAR_MAX ((unsigned char) -1)
46 #endif
47
48 #if HAVE_C_BACKSLASH_A
49 # define ALERT_CHAR '\a'
50 #else
51 # define ALERT_CHAR '\7'
52 #endif
53
54 #if HAVE_STDLIB_H
55 # include <stdlib.h>
56 #endif
57
58 #if HAVE_STRING_H
59 # include <string.h>
60 #endif
61
62 #if HAVE_WCHAR_H
63 # include <wchar.h>
64 #endif
65
66 #if HAVE_MBRTOWC && HAVE_WCHAR_H
67 size_t mbrtowc ();
68 # if !HAVE_MBSTATE_T_OBJECT
69 #  define mbrtowc(pwc, s, n, ps) (mbrtowc) (pwc, s, n, 0)
70 # endif
71 #else
72 # define mbrtowc(pwc, s, n, ps) ((*(pwc) = *(s)) != 0)
73 # define mbsinit(ps) 1
74 # define iswprint(wc) ISPRINT ((unsigned char) (wc))
75 #endif
76
77 #ifndef iswprint
78 # if HAVE_WCTYPE_H
79 #  include <wctype.h>
80 # endif
81 # if !defined iswprint && !HAVE_ISWPRINT
82 #  define iswprint(wc) 1
83 # endif
84 #endif
85
86 #define INT_BITS (sizeof (int) * CHAR_BIT)
87
88 #if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
89 /* Undefine to protect against the definition in wctype.h of solaris2.6.   */
90 # undef ISASCII
91 # define ISASCII(c) 1
92 #else
93 # define ISASCII(c) isascii (c)
94 #endif
95 /* Undefine to protect against the definition in wctype.h of solaris2.6.   */
96 #undef ISPRINT
97 #define ISPRINT(c) (ISASCII (c) && isprint (c))
98
99 struct quoting_options
100 {
101   /* Basic quoting style.  */
102   enum quoting_style style;
103
104   /* Quote the characters indicated by this bit vector even if the
105      quoting style would not normally require them to be quoted.  */
106   int quote_these_too[(UCHAR_MAX / INT_BITS) + 1];
107 };
108
109 /* Names of quoting styles.  */
110 char const *const quoting_style_args[] =
111 {
112   "literal",
113   "shell",
114   "shell-always",
115   "c",
116   "escape",
117   "locale",
118   0
119 };
120
121 /* Correspondences to quoting style names.  */
122 enum quoting_style const quoting_style_vals[] =
123 {
124   literal_quoting_style,
125   shell_quoting_style,
126   shell_always_quoting_style,
127   c_quoting_style,
128   escape_quoting_style,
129   locale_quoting_style
130 };
131
132 /* The default quoting options.  */
133 static struct quoting_options default_quoting_options;
134
135 /* Allocate a new set of quoting options, with contents initially identical
136    to O if O is not null, or to the default if O is null.
137    It is the caller's responsibility to free the result.  */
138 struct quoting_options *
139 clone_quoting_options (struct quoting_options *o)
140 {
141   struct quoting_options *p
142     = (struct quoting_options *) xmalloc (sizeof (struct quoting_options));
143   *p = *(o ? o : &default_quoting_options);
144   return p;
145 }
146
147 /* Get the value of O's quoting style.  If O is null, use the default.  */
148 enum quoting_style
149 get_quoting_style (struct quoting_options *o)
150 {
151   return (o ? o : &default_quoting_options)->style;
152 }
153
154 /* In O (or in the default if O is null),
155    set the value of the quoting style to S.  */
156 void
157 set_quoting_style (struct quoting_options *o, enum quoting_style s)
158 {
159   (o ? o : &default_quoting_options)->style = s;
160 }
161
162 /* In O (or in the default if O is null),
163    set the value of the quoting options for character C to I.
164    Return the old value.  Currently, the only values defined for I are
165    0 (the default) and 1 (which means to quote the character even if
166    it would not otherwise be quoted).  */
167 int
168 set_char_quoting (struct quoting_options *o, char c, int i)
169 {
170   unsigned char uc = c;
171   int *p = (o ? o : &default_quoting_options)->quote_these_too + uc / INT_BITS;
172   int shift = uc % INT_BITS;
173   int r = (*p >> shift) & 1;
174   *p ^= ((i & 1) ^ r) << shift;
175   return r;
176 }
177
178 /* Return the translation of MSGID if there is one, and
179    DEFAULT_TRANSLATION otherwise.  */
180 static char const *
181 gettext_default (char const *msgid, char const *default_translation)
182 {
183   char const *translation = _(msgid);
184   return translation == msgid ? default_translation : translation;
185 }
186
187 /* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
188    argument ARG (of size ARGSIZE), using QUOTING_STYLE and the
189    non-quoting-style part of O to control quoting.
190    Terminate the output with a null character, and return the written
191    size of the output, not counting the terminating null.
192    If BUFFERSIZE is too small to store the output string, return the
193    value that would have been returned had BUFFERSIZE been large enough.
194    If ARGSIZE is -1, use the string length of the argument for ARGSIZE.
195
196    This function acts like quotearg_buffer (BUFFER, BUFFERSIZE, ARG,
197    ARGSIZE, O), except it uses QUOTING_STYLE instead of the quoting
198    style specified by O, and O may not be null.  */
199
200 static size_t
201 quotearg_buffer_restyled (char *buffer, size_t buffersize,
202                           char const *arg, size_t argsize,
203                           enum quoting_style quoting_style,
204                           struct quoting_options const *o)
205 {
206   size_t i;
207   size_t len = 0;
208   char const *quote_string = 0;
209   size_t quote_string_len = 0;
210   int backslash_escapes = 0;
211
212 #define STORE(c) \
213     do \
214       { \
215         if (len < buffersize) \
216           buffer[len] = (c); \
217         len++; \
218       } \
219     while (0)
220
221   switch (quoting_style)
222     {
223     case c_quoting_style:
224       STORE ('"');
225       backslash_escapes = 1;
226       quote_string = "\"";
227       quote_string_len = 1;
228       break;
229
230     case escape_quoting_style:
231       backslash_escapes = 1;
232       break;
233
234     case locale_quoting_style:
235       {
236         /* Get translations for open and closing quotation marks.
237
238            The message catalog should translate "{LEFT QUOTATION
239            MARK}" to a left quotation mark suitable for the locale,
240            and similarly for "{RIGHT QUOTATION MARK}".  If the catalog
241            has no translation, the code below uses a neutral
242            (vertical) quotation mark instead, as it is the most
243            appropriate for the C locale.
244
245            For example, an American English Unicode locale should
246            translate the string "{LEFT QUOTATION MARK}" to the
247            character U+201C (LEFT DOUBLE QUOTATION MARK), and should
248            translate the string "{RIGHT QUOTATION MARK}" to the
249            character U+201D (RIGHT DOUBLE QUOTATION MARK).  A British
250            English Unicode locale should instead translate these to
251            U+2018 (LEFT SINGLE QUOTATION MARK) and U+2019 (RIGHT
252            SINGLE QUOTATION MARK), respectively.  */
253
254         static char const quotation_mark[] = "\"";
255         char const *left = gettext_default (N_("{LEFT QUOTATION MARK}"),
256                                             quotation_mark);
257         char const *right = gettext_default (N_("{RIGHT QUOTATION MARK}"),
258                                              quotation_mark);
259         for (quote_string = left; *quote_string; quote_string++)
260           STORE (*quote_string);
261         backslash_escapes = 1;
262         quote_string = right;
263         quote_string_len = strlen (quote_string);
264       }
265       break;
266
267     case shell_always_quoting_style:
268       STORE ('\'');
269       quote_string = "'";
270       quote_string_len = 1;
271       break;
272
273     default:
274       break;
275     }
276
277   for (i = 0;  ! (argsize == (size_t) -1 ? arg[i] == '\0' : i == argsize);  i++)
278     {
279       unsigned char c;
280       unsigned char esc;
281
282       if (backslash_escapes
283           && quote_string_len
284           && i + quote_string_len <= argsize
285           && memcmp (arg + i, quote_string, quote_string_len) == 0)
286         STORE ('\\');
287
288       c = arg[i];
289       switch (c)
290         {
291         case '?':
292           switch (quoting_style)
293             {
294             case shell_quoting_style:
295               goto use_shell_always_quoting_style;
296
297             case c_quoting_style:
298               if (i + 2 < argsize && arg[i + 1] == '?')
299                 switch (arg[i + 2])
300                   {
301                   case '!': case '\'':
302                   case '(': case ')': case '-': case '/':
303                   case '<': case '=': case '>':
304                     /* Escape the second '?' in what would otherwise be
305                        a trigraph.  */
306                     i += 2;
307                     c = arg[i + 2];
308                     STORE ('?');
309                     STORE ('\\');
310                     STORE ('?');
311                     break;
312                   }
313               break;
314
315             default:
316               break;
317             }
318           break;
319
320         case ALERT_CHAR: esc = 'a'; goto c_escape;
321         case '\b': esc = 'b'; goto c_escape;
322         case '\f': esc = 'f'; goto c_escape;
323         case '\n': esc = 'n'; goto c_and_shell_escape;
324         case '\r': esc = 'r'; goto c_and_shell_escape;
325         case '\t': esc = 't'; goto c_and_shell_escape;
326         case '\v': esc = 'v'; goto c_escape;
327         case '\\': esc = c; goto c_and_shell_escape;
328
329         c_and_shell_escape:
330           if (quoting_style == shell_quoting_style)
331             goto use_shell_always_quoting_style;
332         c_escape:
333           if (backslash_escapes)
334             {
335               c = esc;
336               goto store_escape;
337             }
338           break;
339
340         case '#': case '~':
341           if (i != 0)
342             break;
343           /* Fall through.  */
344         case ' ':
345         case '!': /* special in bash */
346         case '"': case '$': case '&':
347         case '(': case ')': case '*': case ';':
348         case '<': case '>': case '[':
349         case '^': /* special in old /bin/sh, e.g. SunOS 4.1.4 */
350         case '`': case '|':
351           /* A shell special character.  In theory, '$' and '`' could
352              be the first bytes of multibyte characters, which means
353              we should check them with mbrtowc, but in practice this
354              doesn't happen so it's not worth worrying about.  */
355           if (quoting_style == shell_quoting_style)
356             goto use_shell_always_quoting_style;
357           break;
358
359         case '\'':
360           switch (quoting_style)
361             {
362             case shell_quoting_style:
363               goto use_shell_always_quoting_style;
364
365             case shell_always_quoting_style:
366               STORE ('\'');
367               STORE ('\\');
368               STORE ('\'');
369               break;
370
371             default:
372               break;
373             }
374           break;
375
376         case '%': case '+': case ',': case '-': case '.': case '/':
377         case '0': case '1': case '2': case '3': case '4': case '5':
378         case '6': case '7': case '8': case '9': case ':': case '=':
379         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
380         case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
381         case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
382         case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
383         case 'Y': case 'Z': case ']': case '_': case 'a': case 'b':
384         case 'c': case 'd': case 'e': case 'f': case 'g': case 'h':
385         case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
386         case 'o': case 'p': case 'q': case 'r': case 's': case 't':
387         case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
388         case '{': case '}':
389           /* These characters don't cause problems, no matter what the
390              quoting style is.  They cannot start multibyte sequences.  */
391           break;
392
393         default:
394           /* If we have a multibyte sequence, copy it until we reach
395              its end, find an error, or come back to the initial shift
396              state.  For C-like styles, if the sequence has
397              unprintable characters, escape the whole sequence, since
398              we can't easily escape single characters within it.  */
399           {
400             /* Length of multibyte sequence found so far.  */
401             size_t m = 0;
402
403             int printable = 1;
404             mbstate_t mbstate;
405             memset (&mbstate, 0, sizeof mbstate);
406
407             if (argsize == (size_t) -1)
408               argsize = strlen (arg);
409
410             do
411               {
412                 wchar_t w;
413                 size_t bytes = mbrtowc (&w, &arg[i + m],
414                                         argsize - (i + m), &mbstate);
415                 if (bytes == 0)
416                   break;
417                 else if (bytes == (size_t) -1)
418                   {
419                     printable = 0;
420                     break;
421                   }
422                 else if (bytes == (size_t) -2)
423                   {
424                     printable = 0;
425                     while (i + m < argsize && arg[i + m])
426                       m++;
427                     break;
428                   }
429                 else
430                   {
431                     if (! iswprint (w))
432                       printable = 0;
433                     m += bytes;
434                   }
435               }
436             while (! mbsinit (&mbstate));
437
438             if (m <= 1)
439               {
440                 /* Escape a unibyte character like a multibyte
441                    sequence if using backslash escapes, and if the
442                    character is not printable.  */
443                 m = backslash_escapes && ! ISPRINT (c);
444                 printable = 0;
445               }
446
447             if (m)
448               {
449                 /* Output a multibyte sequence, or an escaped
450                    unprintable unibyte character.  */
451                 size_t imax = i + m - 1;
452
453                 for (;;)
454                   {
455                     if (backslash_escapes && ! printable)
456                       {
457                         STORE ('\\');
458                         STORE ('0' + (c >> 6));
459                         STORE ('0' + ((c >> 3) & 7));
460                         c = '0' + (c & 7);
461                       }
462                     if (i == imax)
463                       break;
464                     STORE (c);
465                     c = arg[++i];
466                   }
467
468                 goto store_c;
469               }
470           }
471         }
472
473       if (! (backslash_escapes
474              && o->quote_these_too[c / INT_BITS] & (1 << (c % INT_BITS))))
475         goto store_c;
476
477     store_escape:
478       STORE ('\\');
479
480     store_c:
481       STORE (c);
482     }
483
484   if (quote_string)
485     for (; *quote_string; quote_string++)
486       STORE (*quote_string);
487
488   if (len < buffersize)
489     buffer[len] = '\0';
490   return len;
491
492  use_shell_always_quoting_style:
493   return quotearg_buffer_restyled (buffer, buffersize, arg, argsize,
494                                    shell_always_quoting_style, o);
495 }
496
497 /* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
498    argument ARG (of size ARGSIZE), using O to control quoting.
499    If O is null, use the default.
500    Terminate the output with a null character, and return the written
501    size of the output, not counting the terminating null.
502    If BUFFERSIZE is too small to store the output string, return the
503    value that would have been returned had BUFFERSIZE been large enough.
504    If ARGSIZE is -1, use the string length of the argument for ARGSIZE.  */
505 size_t
506 quotearg_buffer (char *buffer, size_t buffersize,
507                  char const *arg, size_t argsize,
508                  struct quoting_options const *o)
509 {
510   struct quoting_options const *p = o ? o : &default_quoting_options;
511   return quotearg_buffer_restyled (buffer, buffersize, arg, argsize,
512                                    p->style, p);
513 }
514
515 /* Use storage slot N to return a quoted version of the string ARG.
516    OPTIONS specifies the quoting options.
517    The returned value points to static storage that can be
518    reused by the next call to this function with the same value of N.
519    N must be nonnegative.  N is deliberately declared with type "int"
520    to allow for future extensions (using negative values).  */
521 static char *
522 quotearg_n_options (int n, char const *arg,
523                     struct quoting_options const *options)
524 {
525   static unsigned int nslots;
526   static struct slotvec
527     {
528       size_t size;
529       char *val;
530     } *slotvec;
531
532   if (nslots <= n)
533     {
534       int n1 = n + 1;
535       size_t s = n1 * sizeof (struct slotvec);
536       if (! (0 < n1 && n1 == s / sizeof (struct slotvec)))
537         abort ();
538       slotvec = (struct slotvec *) xrealloc (slotvec, s);
539       memset (slotvec + nslots, 0, (n1 - nslots) * sizeof (struct slotvec));
540       nslots = n;
541     }
542
543   {
544     size_t size = slotvec[n].size;
545     char *val = slotvec[n].val;
546     size_t qsize = quotearg_buffer (val, size, arg, (size_t) -1, options);
547
548     if (size <= qsize)
549       {
550         slotvec[n].size = size = qsize + 1;
551         slotvec[n].val = val = xrealloc (val, size);
552         quotearg_buffer (val, size, arg, (size_t) -1, options);
553       }
554
555     return val;
556   }
557 }
558
559 char *
560 quotearg_n (unsigned int n, char const *arg)
561 {
562   return quotearg_n_options (n, arg, &default_quoting_options);
563 }
564
565 char *
566 quotearg (char const *arg)
567 {
568   return quotearg_n (0, arg);
569 }
570
571 char *
572 quotearg_n_style (unsigned int n, enum quoting_style s, char const *arg)
573 {
574   struct quoting_options o;
575   o.style = s;
576   memset (o.quote_these_too, 0, sizeof o.quote_these_too);
577   return quotearg_n_options (n, arg, &o);
578 }
579
580 char *
581 quotearg_style (enum quoting_style s, char const *arg)
582 {
583   return quotearg_n_style (0, s, arg);
584 }
585
586 char *
587 quotearg_char (char const *arg, char ch)
588 {
589   struct quoting_options options;
590   options = default_quoting_options;
591   set_char_quoting (&options, ch, 1);
592   return quotearg_n_options (0, arg, &options);
593 }
594
595 char *
596 quotearg_colon (char const *arg)
597 {
598   return quotearg_char (arg, ':');
599 }