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