Update from patch-2.5.3.
[gnulib.git] / lib / quotearg.c
1 /* quotearg.c - quote arguments for output
2    Copyright (C) 1998 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 #if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
30 # define ISASCII(c) 1
31 #else
32 # define ISASCII(c) isascii (c)
33 #endif
34 #ifdef isgraph
35 # define ISGRAPH(c) (ISASCII (c) && isgraph (c))
36 #else
37 # define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
38 #endif
39
40 #if HAVE_LIMITS_H
41 # include <limits.h>
42 #endif
43 #ifndef CHAR_BIT
44 # define CHAR_BIT 8
45 #endif
46 #ifndef UCHAR_MAX
47 # define UCHAR_MAX ((unsigned char) -1)
48 #endif
49
50 #if HAVE_STDLIB_H
51 # include <stdlib.h>
52 #endif
53
54 #if HAVE_STRING_H
55 # include <string.h>
56 #endif
57
58 #define INT_BITS (sizeof (int) * CHAR_BIT)
59
60 struct quoting_options
61 {
62   /* Basic quoting style.  */
63   enum quoting_style style;
64
65   /* Quote the chararacters indicated by this bit vector even if the
66      quoting style would not normally require them to be quoted.  */
67   int quote_these_too[((UCHAR_MAX + 1) / INT_BITS
68                        + ((UCHAR_MAX + 1) % INT_BITS != 0))];
69 };
70
71 /* Names of quoting styles.  */
72 char const *const quoting_style_args[] =
73 {
74   "literal", "shell", "shell-always", "c", "escape", 0
75 };
76
77 /* The default quoting options.  */
78 static struct quoting_options default_quoting_options;
79
80 /* Allocate a new set of quoting options, with contents initially identical
81    to O if O is not null, or to the default if O is null.
82    It is the caller's responsibility to free the result.  */
83 struct quoting_options *
84 clone_quoting_options (struct quoting_options *o)
85 {
86   struct quoting_options *p
87     = (struct quoting_options *) xmalloc (sizeof (struct quoting_options));
88   *p = *(o ? o : &default_quoting_options);
89   return p;
90 }
91
92 /* Get the value of O's quoting style.  If O is null, use the default.  */
93 enum quoting_style
94 get_quoting_style (struct quoting_options *o)
95 {
96   return (o ? o : &default_quoting_options)->style;
97 }
98
99 /* In O (or in the default if O is null),
100    set the value of the quoting style to S.  */
101 void
102 set_quoting_style (struct quoting_options *o, enum quoting_style s)
103 {
104   (o ? o : &default_quoting_options)->style = s;
105 }
106
107 /* In O (or in the default if O is null),
108    set the value of the quoting options for character C to I.
109    Return the old value.  Currently, the only values defined for I are
110    0 (the default) and 1 (which means to quote the character even if
111    it would not otherwise be quoted).  */
112 int
113 set_char_quoting (struct quoting_options *o, char c, int i)
114 {
115   unsigned char uc = c;
116   int *p = (o ? o : &default_quoting_options)->quote_these_too + uc / INT_BITS;
117   int shift = uc % INT_BITS;
118   int r = (*p >> shift) & 1;
119   *p ^= ((i & 1) ^ r) << shift;
120   return r;
121 }
122
123 /* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
124    argument ARG (of size ARGSIZE), using O to control quoting.
125    If O is null, use the default.
126    Terminate the output with a null character, and return the written
127    size of the output, not counting the terminating null.
128    If BUFFERSIZE is too small to store the output string, return the
129    value that would have been returned had BUFFERSIZE been large enough.
130    If ARGSIZE is -1, use the string length of the argument for ARGSIZE.  */
131 size_t
132 quotearg_buffer (char *buffer, size_t buffersize,
133                  char const *arg, size_t argsize,
134                  struct quoting_options const *o)
135 {
136   unsigned char c;
137   size_t i;
138   size_t len;
139   int quote_mark;
140   struct quoting_options const *p = o ? o : &default_quoting_options;
141   enum quoting_style quoting_style = p->style;
142 #define STORE(c) \
143     do \
144       { \
145         if (len < buffersize) \
146           buffer[len] = (c); \
147           len++; \
148       } \
149     while (0)
150
151   switch (quoting_style)
152     {
153     case shell_quoting_style:
154       if (! (argsize == -1 ? arg[0] == '\0' : argsize == 0))
155         {
156           switch (arg[0])
157             {
158             case '#': case '~':
159               break;
160
161             default:
162               len = 0;
163               for (i = 0; ; i++)
164                 {
165                   if (argsize == -1 ? arg[i] == '\0' : i == argsize)
166                     goto done;
167
168                   c = arg[i];
169
170                   switch (c)
171                     {
172                     case '\t': case '\n': case ' ':
173                     case '!': /* special in csh */
174                     case '"': case '$': case '&': case '\'':
175                     case '(': case ')': case '*': case ';':
176                     case '<': case '>': case '?': case '[': case '\\':
177                     case '^': /* special in old /bin/sh, e.g. SunOS 4.1.4 */
178                     case '`': case '|':
179                       goto needs_quoting;
180                     }
181
182                   if (p->quote_these_too[c / INT_BITS] & (1 << (c % INT_BITS)))
183                     goto needs_quoting;
184
185                   STORE (c);
186                 }
187
188             needs_quoting:;
189               break;
190             }
191         }
192       /* Fall through.  */
193
194     case shell_always_quoting_style:
195       quote_mark = '\'';
196       break;
197
198     case c_quoting_style:
199       quote_mark = '"';
200       break;
201
202     default:
203       quote_mark = 0;
204       break;
205     }
206
207   len = 0;
208
209   if (quote_mark)
210     STORE (quote_mark);
211
212   for (i = 0;  ! (argsize == -1 ? arg[i] == '\0' : i == argsize);  i++)
213     {
214       c = arg[i];
215
216       switch (quoting_style)
217         {
218         case literal_quoting_style:
219           break;
220
221         case shell_quoting_style:
222         case shell_always_quoting_style:
223           if (c == '\'')
224             {
225               STORE ('\'');
226               STORE ('\\');
227               STORE ('\'');
228             }
229           break;
230
231         case c_quoting_style:
232         case escape_quoting_style:
233           switch (c)
234             {
235             case '?': /* Do not generate trigraphs.  */
236             case '\\': goto store_escape;
237               /* Not all C compilers know what \a means.  */
238             case   7 : c = 'a'; goto store_escape;
239             case '\b': c = 'b'; goto store_escape;
240             case '\f': c = 'f'; goto store_escape;
241             case '\n': c = 'n'; goto store_escape;
242             case '\r': c = 'r'; goto store_escape;
243             case '\t': c = 't'; goto store_escape;
244             case '\v': c = 'v'; goto store_escape;
245
246             case ' ':
247               if (quoting_style == escape_quoting_style)
248                 goto store_escape;
249               break;
250
251             case '"':
252               if (quoting_style == c_quoting_style)
253                 goto store_escape;
254               break;
255
256             default:
257               if (!ISGRAPH (c))
258                 {
259                   STORE ('\\');
260                   STORE ('0' + (c >> 6));
261                   STORE ('0' + ((c >> 3) & 3));
262                   c = '0' + (c & 3);
263                   goto store_c;
264                 }
265               break;
266             }
267
268           if (! (p->quote_these_too[c / INT_BITS] & (1 << (c % INT_BITS))))
269             goto store_c;
270
271         store_escape:
272           STORE ('\\');
273         }
274
275     store_c:
276       STORE (c);
277     }
278
279   if (quote_mark)
280     STORE (quote_mark);
281
282  done:
283   if (len < buffersize)
284     buffer[len] = '\0';
285   return len;
286 }
287
288 /* Use storage slot N to return a quoted version of the string ARG.
289    OPTIONS specifies the quoting options.
290    The returned value points to static storage that can be
291    reused by the next call to this function with the same value of N.
292    N must be nonnegative.  */
293 static char *
294 quotearg_n_options (int n, char const *arg, struct quoting_options *options)
295 {
296   static unsigned nslots;
297   static struct slotvec
298     {
299       size_t size;
300       char *val;
301     } *slotvec;
302
303   if (nslots <= n)
304     {
305       int n1 = n + 1;
306       size_t s = n1 * sizeof (struct slotvec);
307       if (! (0 < n1 && n1 == s / sizeof (struct slotvec)))
308         abort ();
309       slotvec = (struct slotvec *) xrealloc (slotvec, s);
310       memset (slotvec + nslots, 0, (n1 - nslots) * sizeof (struct slotvec));
311       nslots = n;
312     }
313
314   {
315     size_t size = slotvec[n].size;
316     char *val = slotvec[n].val;
317     size_t qsize = quotearg_buffer (val, size, arg, (size_t) -1, options);
318
319     if (size <= qsize)
320       {
321         slotvec[n].size = size = qsize + 1;
322         slotvec[n].val = val = xrealloc (val, size);
323         quotearg_buffer (val, size, arg, (size_t) -1, options);
324       }
325
326     return val;
327   }
328 }
329
330 char *
331 quotearg_n (int n, char const *arg)
332 {
333   return quotearg_n_options (n, arg, &default_quoting_options);
334 }
335
336 char *
337 quotearg (char const *arg)
338 {
339   return quotearg_n (0, arg);
340 }
341
342 char *
343 quotearg_char (char const *arg, char ch)
344 {
345   struct quoting_options options;
346   options = default_quoting_options;
347   set_char_quoting (&options, ch, 1);
348   return quotearg_n_options (0, arg, &options);
349 }
350
351 char *
352 quotearg_colon (char const *arg)
353 {
354   return quotearg_char (arg, ':');
355 }