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