a0863606b1146fc0533048d200e2499eb5b15a0d
[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 == escape_quoting_style)
263                 goto store_escape;
264               break;
265
266             case '"':
267               if (quoting_style == c_quoting_style)
268                 goto store_escape;
269               break;
270
271             default:
272               if (!ISGRAPH (c))
273                 {
274                   STORE ('\\');
275                   STORE ('0' + (c >> 6));
276                   STORE ('0' + ((c >> 3) & 7));
277                   c = '0' + (c & 7);
278                   goto store_c;
279                 }
280               break;
281             }
282
283           if (! (p->quote_these_too[c / INT_BITS] & (1 << (c % INT_BITS))))
284             goto store_c;
285
286         store_escape:
287           STORE ('\\');
288         }
289
290     store_c:
291       STORE (c);
292     }
293
294   if (quote_mark)
295     STORE (quote_mark);
296
297  done:
298   if (len < buffersize)
299     buffer[len] = '\0';
300   return len;
301 }
302
303 /* Use storage slot N to return a quoted version of the string ARG.
304    OPTIONS specifies the quoting options.
305    The returned value points to static storage that can be
306    reused by the next call to this function with the same value of N.
307    N must be nonnegative.  */
308 static char *
309 quotearg_n_options (unsigned int n, char const *arg,
310                     struct quoting_options *options)
311 {
312   static unsigned int nslots;
313   static struct slotvec
314     {
315       size_t size;
316       char *val;
317     } *slotvec;
318
319   if (nslots <= n)
320     {
321       int n1 = n + 1;
322       size_t s = n1 * sizeof (struct slotvec);
323       if (! (0 < n1 && n1 == s / sizeof (struct slotvec)))
324         abort ();
325       slotvec = (struct slotvec *) xrealloc (slotvec, s);
326       memset (slotvec + nslots, 0, (n1 - nslots) * sizeof (struct slotvec));
327       nslots = n;
328     }
329
330   {
331     size_t size = slotvec[n].size;
332     char *val = slotvec[n].val;
333     size_t qsize = quotearg_buffer (val, size, arg, (size_t) -1, options);
334
335     if (size <= qsize)
336       {
337         slotvec[n].size = size = qsize + 1;
338         slotvec[n].val = val = xrealloc (val, size);
339         quotearg_buffer (val, size, arg, (size_t) -1, options);
340       }
341
342     return val;
343   }
344 }
345
346 char *
347 quotearg_n (unsigned int n, char const *arg)
348 {
349   return quotearg_n_options (n, arg, &default_quoting_options);
350 }
351
352 char *
353 quotearg (char const *arg)
354 {
355   return quotearg_n (0, arg);
356 }
357
358 char *
359 quotearg_char (char const *arg, char ch)
360 {
361   struct quoting_options options;
362   options = default_quoting_options;
363   set_char_quoting (&options, ch, 1);
364   return quotearg_n_options (0, arg, &options);
365 }
366
367 char *
368 quotearg_colon (char const *arg)
369 {
370   return quotearg_char (arg, ':');
371 }