1327Sjkh/* quotearg.c - quote arguments for output
2379Sjkh   Copyright (C) 1998, 1999 Free Software Foundation, Inc.
3327Sjkh
4327Sjkh   This program is free software; you can redistribute it and/or modify
5327Sjkh   it under the terms of the GNU General Public License as published by
6327Sjkh   the Free Software Foundation; either version 2, or (at your option)
7327Sjkh   any later version.
8327Sjkh
9327Sjkh   This program is distributed in the hope that it will be useful,
10327Sjkh   but WITHOUT ANY WARRANTY; without even the implied warranty of
11327Sjkh   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12327Sjkh   GNU General Public License for more details.
13327Sjkh
14327Sjkh   You should have received a copy of the GNU General Public License
15327Sjkh   along with this program; if not, write to the Free Software Foundation,
16327Sjkh   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17327Sjkh
18327Sjkh/* Written by Paul Eggert <eggert@twinsun.com> */
19327Sjkh
20327Sjkh/* FIXME: Multibyte characters are not supported yet.  */
21327Sjkh
22327Sjkh#if HAVE_CONFIG_H
23327Sjkh# include <config.h>
24327Sjkh#endif
25327Sjkh
26327Sjkh#include <sys/types.h>
27327Sjkh#include <quotearg.h>
28327Sjkh#include <xalloc.h>
29327Sjkh
30327Sjkh#include <ctype.h>
31327Sjkh#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
32327Sjkh# define ISASCII(c) 1
33327Sjkh#else
34327Sjkh# define ISASCII(c) isascii (c)
35327Sjkh#endif
36327Sjkh#ifdef isgraph
37327Sjkh# define ISGRAPH(c) (ISASCII (c) && isgraph (c))
38327Sjkh#else
39327Sjkh# define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
40392Sjkh#endif
41327Sjkh
42327Sjkh#if ENABLE_NLS
43327Sjkh# include <libintl.h>
44327Sjkh# define _(text) gettext (text)
45327Sjkh#else
46327Sjkh# define _(text) text
47327Sjkh#endif
48392Sjkh
49392Sjkh#if HAVE_LIMITS_H
50392Sjkh# include <limits.h>
51392Sjkh#endif
52392Sjkh#ifndef CHAR_BIT
53392Sjkh# define CHAR_BIT 8
54392Sjkh#endif
55392Sjkh#ifndef UCHAR_MAX
56327Sjkh# define UCHAR_MAX ((unsigned char) -1)
57327Sjkh#endif
58392Sjkh
59392Sjkh#if HAVE_STDLIB_H
60327Sjkh# include <stdlib.h>
61327Sjkh#endif
62327Sjkh
63327Sjkh#if HAVE_STRING_H
64327Sjkh# include <string.h>
65327Sjkh#endif
66327Sjkh
67327Sjkh#define INT_BITS (sizeof (int) * CHAR_BIT)
68327Sjkh
69327Sjkhstruct quoting_options
70327Sjkh{
71327Sjkh  /* Basic quoting style.  */
72327Sjkh  enum quoting_style style;
73327Sjkh
74327Sjkh  /* Quote the characters indicated by this bit vector even if the
75327Sjkh     quoting style would not normally require them to be quoted.  */
76327Sjkh  int quote_these_too[((UCHAR_MAX + 1) / INT_BITS
77327Sjkh		       + ((UCHAR_MAX + 1) % INT_BITS != 0))];
78327Sjkh};
79327Sjkh
80327Sjkh/* Names of quoting styles.  */
81327Sjkhchar const *const quoting_style_args[] =
82383Sjkh{
83327Sjkh  "literal",
84327Sjkh  "shell",
85327Sjkh  "shell-always",
86327Sjkh  "c",
87327Sjkh  "escape",
88327Sjkh  "locale",
89327Sjkh  0
90327Sjkh};
91327Sjkh
92327Sjkh/* Correspondences to quoting style names.  */
93327Sjkhenum quoting_style const quoting_style_vals[] =
94327Sjkh{
95327Sjkh  literal_quoting_style,
96327Sjkh  shell_quoting_style,
97327Sjkh  shell_always_quoting_style,
98327Sjkh  c_quoting_style,
99327Sjkh  escape_quoting_style,
100327Sjkh  locale_quoting_style
101327Sjkh};
102327Sjkh
103327Sjkh/* The default quoting options.  */
104327Sjkhstatic struct quoting_options default_quoting_options;
105327Sjkh
106327Sjkh/* Allocate a new set of quoting options, with contents initially identical
107327Sjkh   to O if O is not null, or to the default if O is null.
108327Sjkh   It is the caller's responsibility to free the result.  */
109327Sjkhstruct quoting_options *
110327Sjkhclone_quoting_options (struct quoting_options *o)
111327Sjkh{
112327Sjkh  struct quoting_options *p
113327Sjkh    = (struct quoting_options *) xmalloc (sizeof (struct quoting_options));
114327Sjkh  *p = *(o ? o : &default_quoting_options);
115327Sjkh  return p;
116327Sjkh}
117327Sjkh
118327Sjkh/* Get the value of O's quoting style.  If O is null, use the default.  */
119327Sjkhenum quoting_style
120327Sjkhget_quoting_style (struct quoting_options *o)
121327Sjkh{
122327Sjkh  return (o ? o : &default_quoting_options)->style;
123327Sjkh}
124327Sjkh
125327Sjkh/* In O (or in the default if O is null),
126327Sjkh   set the value of the quoting style to S.  */
127327Sjkhvoid
128411Sjkhset_quoting_style (struct quoting_options *o, enum quoting_style s)
129411Sjkh{
130327Sjkh  (o ? o : &default_quoting_options)->style = s;
131379Sjkh}
132327Sjkh
133379Sjkh/* In O (or in the default if O is null),
134327Sjkh   set the value of the quoting options for character C to I.
135379Sjkh   Return the old value.  Currently, the only values defined for I are
136327Sjkh   0 (the default) and 1 (which means to quote the character even if
137379Sjkh   it would not otherwise be quoted).  */
138327Sjkhint
139379Sjkhset_char_quoting (struct quoting_options *o, char c, int i)
140327Sjkh{
141379Sjkh  unsigned char uc = c;
142411Sjkh  int *p = (o ? o : &default_quoting_options)->quote_these_too + uc / INT_BITS;
143411Sjkh  int shift = uc % INT_BITS;
144411Sjkh  int r = (*p >> shift) & 1;
145411Sjkh  *p ^= ((i & 1) ^ r) << shift;
146327Sjkh  return r;
147327Sjkh}
148327Sjkh
149327Sjkh/* Place into buffer BUFFER (of size BUFFERSIZE) a quoted version of
150327Sjkh   argument ARG (of size ARGSIZE), using O to control quoting.
151327Sjkh   If O is null, use the default.
152327Sjkh   Terminate the output with a null character, and return the written
153327Sjkh   size of the output, not counting the terminating null.
154327Sjkh   If BUFFERSIZE is too small to store the output string, return the
155327Sjkh   value that would have been returned had BUFFERSIZE been large enough.
156327Sjkh   If ARGSIZE is -1, use the string length of the argument for ARGSIZE.  */
157size_t
158quotearg_buffer (char *buffer, size_t buffersize,
159		 char const *arg, size_t argsize,
160		 struct quoting_options const *o)
161{
162  unsigned char c;
163  size_t i;
164  size_t len = 0;
165  char const *quote_string;
166  size_t quote_string_len;
167  struct quoting_options const *p = o ? o : &default_quoting_options;
168  enum quoting_style quoting_style = p->style;
169#define STORE(c) \
170    do \
171      { \
172	if (len < buffersize) \
173	  buffer[len] = (c); \
174	  len++; \
175      } \
176    while (0)
177
178  switch (quoting_style)
179    {
180    case shell_quoting_style:
181      if (! (argsize == (size_t) -1 ? arg[0] == '\0' : argsize == 0))
182	{
183	  switch (arg[0])
184	    {
185	    case '#': case '~':
186	      break;
187
188	    default:
189	      for (i = 0; ; i++)
190		{
191		  if (argsize == (size_t) -1 ? arg[i] == '\0' : i == argsize)
192		    goto done;
193
194		  c = arg[i];
195
196		  switch (c)
197		    {
198		    case '\t': case '\n': case ' ':
199		    case '!': /* special in csh */
200		    case '"': case '$': case '&': case '\'':
201		    case '(': case ')': case '*': case ';':
202		    case '<': case '>': case '?': case '[': case '\\':
203		    case '^': /* special in old /bin/sh, e.g. SunOS 4.1.4 */
204		    case '`': case '|':
205		      goto needs_quoting;
206		    }
207
208		  if (p->quote_these_too[c / INT_BITS] & (1 << (c % INT_BITS)))
209		    goto needs_quoting;
210
211		  STORE (c);
212		}
213	    needs_quoting:;
214
215	      len = 0;
216	      break;
217	    }
218	}
219      /* Fall through.  */
220
221    case shell_always_quoting_style:
222      STORE ('\'');
223      quote_string = "'";
224      quote_string_len = 1;
225      break;
226
227    case c_quoting_style:
228      STORE ('"');
229      quote_string = "\"";
230      quote_string_len = 1;
231      break;
232
233    case locale_quoting_style:
234      for (quote_string = _("`"); *quote_string; quote_string++)
235	STORE (*quote_string);
236      quote_string = _("'");
237      quote_string_len = strlen (quote_string);
238      break;
239
240    default:
241      quote_string = 0;
242      quote_string_len = 0;
243      break;
244    }
245
246  for (i = 0;  ! (argsize == (size_t) -1 ? arg[i] == '\0' : i == argsize);  i++)
247    {
248      c = arg[i];
249
250      switch (quoting_style)
251	{
252	case literal_quoting_style:
253	  break;
254
255	case shell_quoting_style:
256	case shell_always_quoting_style:
257	  if (c == '\'')
258	    {
259	      STORE ('\'');
260	      STORE ('\\');
261	      STORE ('\'');
262	    }
263	  break;
264
265	case c_quoting_style:
266	case escape_quoting_style:
267	case locale_quoting_style:
268	  switch (c)
269	    {
270	    case '?': /* Do not generate trigraphs.  */
271	    case '\\': goto store_escape;
272	      /* Not all C compilers know what \a means.  */
273	    case   7 : c = 'a'; goto store_escape;
274	    case '\b': c = 'b'; goto store_escape;
275	    case '\f': c = 'f'; goto store_escape;
276	    case '\n': c = 'n'; goto store_escape;
277	    case '\r': c = 'r'; goto store_escape;
278	    case '\t': c = 't'; goto store_escape;
279	    case '\v': c = 'v'; goto store_escape;
280
281	    case ' ': break;
282
283	    default:
284	      if (quote_string_len
285		  && strncmp (arg + i, quote_string, quote_string_len) == 0)
286		goto store_escape;
287	      if (!ISGRAPH (c))
288		{
289		  STORE ('\\');
290		  STORE ('0' + (c >> 6));
291		  STORE ('0' + ((c >> 3) & 7));
292		  c = '0' + (c & 7);
293		  goto store_c;
294		}
295	      break;
296	    }
297
298	  if (! (p->quote_these_too[c / INT_BITS] & (1 << (c % INT_BITS))))
299	    goto store_c;
300
301	store_escape:
302	  STORE ('\\');
303	}
304
305    store_c:
306      STORE (c);
307    }
308
309  if (quote_string)
310    for (; *quote_string; quote_string++)
311      STORE (*quote_string);
312
313 done:
314  if (len < buffersize)
315    buffer[len] = '\0';
316  return len;
317}
318
319/* Use storage slot N to return a quoted version of the string ARG.
320   OPTIONS specifies the quoting options.
321   The returned value points to static storage that can be
322   reused by the next call to this function with the same value of N.
323   N must be nonnegative.  N is deliberately declared with type `int'
324   to allow for future extensions (using negative values).  */
325static char *
326quotearg_n_options (int n, char const *arg,
327		    struct quoting_options const *options)
328{
329  static unsigned int nslots;
330  static struct slotvec
331    {
332      size_t size;
333      char *val;
334    } *slotvec;
335
336  if (nslots <= n)
337    {
338      int n1 = n + 1;
339      size_t s = n1 * sizeof (struct slotvec);
340      if (! (0 < n1 && n1 == s / sizeof (struct slotvec)))
341	abort ();
342      slotvec = (struct slotvec *) xrealloc (slotvec, s);
343      memset (slotvec + nslots, 0, (n1 - nslots) * sizeof (struct slotvec));
344      nslots = n;
345    }
346
347  {
348    size_t size = slotvec[n].size;
349    char *val = slotvec[n].val;
350    size_t qsize = quotearg_buffer (val, size, arg, (size_t) -1, options);
351
352    if (size <= qsize)
353      {
354	slotvec[n].size = size = qsize + 1;
355	slotvec[n].val = val = xrealloc (val, size);
356	quotearg_buffer (val, size, arg, (size_t) -1, options);
357      }
358
359    return val;
360  }
361}
362
363char *
364quotearg_n (unsigned int n, char const *arg)
365{
366  return quotearg_n_options (n, arg, &default_quoting_options);
367}
368
369char *
370quotearg (char const *arg)
371{
372  return quotearg_n (0, arg);
373}
374
375char *
376quotearg_n_style (unsigned int n, enum quoting_style s, char const *arg)
377{
378  struct quoting_options o;
379  o.style = s;
380  memset (o.quote_these_too, 0, sizeof o.quote_these_too);
381  return quotearg_n_options (n, arg, &o);
382}
383
384char *
385quotearg_style (enum quoting_style s, char const *arg)
386{
387  return quotearg_n_style (0, s, arg);
388}
389
390char *
391quotearg_char (char const *arg, char ch)
392{
393  struct quoting_options options;
394  options = default_quoting_options;
395  set_char_quoting (&options, ch, 1);
396  return quotearg_n_options (0, arg, &options);
397}
398
399char *
400quotearg_colon (char const *arg)
401{
402  return quotearg_char (arg, ':');
403}
404