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