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