Home | History | Annotate | Line # | Download | only in libgroff
      1 /*	$NetBSD: quotearg.c,v 1.1.1.1 2016/01/13 18:41:48 christos Exp $	*/
      2 
      3 /* Copyright (C) 2004
      4    Free Software Foundation, Inc.
      5      Written by:  Jeff Conrad    (jeff_conrad (at) msn.com)
      6        and        Keith Marshall (keith.d.marshall (at) ntlworld.com)
      7 
      8 This file is part of groff.
      9 
     10 groff is free software; you can redistribute it and/or modify it under
     11 the terms of the GNU General Public License as published by the Free
     12 Software Foundation; either version 2, or (at your option) any later
     13 version.
     14 
     15 groff is distributed in the hope that it will be useful, but WITHOUT ANY
     16 WARRANTY; without even the implied warranty of MERCHANTABILITY or
     17 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     18 for more details.
     19 
     20 You should have received a copy of the GNU General Public License along
     21 with groff; see the file COPYING.  If not, write to the Free Software
     22 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
     23 
     24 #include <stdio.h>
     25 #include <stdlib.h>
     26 #include <string.h>
     27 #include <ctype.h>
     28 #include <limits.h>
     29 
     30 /* Define the default mechanism, and messages, for error reporting
     31  * (user may substitute a preferred alternative, by defining his own
     32  *  implementation of the macros REPORT_ERROR, QUOTE_ARG_MALLOC_FAILED
     33  *  and QUOTE_ARG_REALLOC_FAILED, in the header file `nonposix.h').
     34  */
     35 
     36 #include "nonposix.h"
     37 
     38 #ifndef  REPORT_ERROR
     39 # define REPORT_ERROR(WHY)  fprintf(stderr, "%s:%s\n", program_name, WHY)
     40 #endif
     41 #ifndef  QUOTE_ARG_MALLOC_ERROR
     42 # define QUOTE_ARG_MALLOC_ERROR   "malloc: Buffer allocation failed"
     43 #endif
     44 #ifndef  QUOTE_ARG_REALLOC_ERROR
     45 # define QUOTE_ARG_REALLOC_ERROR  "realloc: Buffer resize failed"
     46 #endif
     47 
     48 extern char *program_name;	/* main program must define this */
     49 
     50 #undef FALSE
     51 #undef TRUE
     52 #define FALSE 0
     53 #define TRUE  1
     54 
     55 static int
     56 needs_quoting(const char *string)
     57 {
     58   /* Scan `string' to see whether it needs quoting for MSVC `spawn'/`exec'
     59    * (i.e., whether it contains whitespace or embedded quotes).
     60    */
     61 
     62   if (string == NULL)		/* ignore NULL strings */
     63     return FALSE;
     64 
     65   if (*string == '\0')		/* explicit arguments of zero length	  */
     66     return TRUE;		/* need quoting, so they aren't discarded */
     67 
     68   while (*string) {
     69     /* Scan non-NULL strings, up to '\0' terminator,
     70      * returning 'TRUE' if quote or white space found.
     71      */
     72 
     73     if (*string == '"' || isspace(*string))
     74       return TRUE;
     75 
     76     /* otherwise, continue scanning to end of string */
     77 
     78     ++string;
     79   }
     80 
     81   /* Fall through, if no quotes or white space found,
     82    * in which case, return `FALSE'.
     83    */
     84 
     85   return FALSE;
     86 }
     87 
     88 char *
     89 quote_arg(char *string)
     90 {
     91   /* Enclose arguments in double quotes so that the parsing done in the
     92    * MSVC runtime startup code doesn't split them at whitespace.  Escape
     93    * embedded double quotes so that they emerge intact from the parsing.
     94    */
     95 
     96   int backslashes;
     97   char *quoted, *p, *q;
     98 
     99   if (needs_quoting(string)) {
    100     /* Need to create a quoted copy of `string';
    101      * maximum buffer space needed is twice the original length,
    102      * plus two enclosing quotes and one `\0' terminator.
    103      */
    104 
    105     if ((quoted = (char *)malloc(2 * strlen(string) + 3)) == NULL) {
    106       /* Couldn't get a buffer for the quoted string,
    107        * so complain, and bail out gracefully.
    108        */
    109 
    110       REPORT_ERROR(QUOTE_ARG_MALLOC_ERROR);
    111       exit(1);
    112     }
    113 
    114     /* Ok to proceed:
    115      * insert the opening quote, then copy the source string,
    116      * adding escapes as required.
    117      */
    118 
    119     *quoted = '"';
    120     for (backslashes = 0, p = string, q = quoted; *p; p++) {
    121       if (*p == '\\') {
    122 	/* Just count backslashes when we find them.
    123 	 * We will copy them out later, when we know if the count
    124 	 * needs to be adjusted, to escape an embedded quote.
    125 	 */
    126 
    127 	++backslashes;
    128       }
    129       else if (*p == '"') {
    130 	/* This embedded quote character must be escaped,
    131 	 * but first double up any immediately preceding backslashes,
    132 	 * with one extra, as the escape character.
    133 	 */
    134 
    135 	for (backslashes += backslashes + 1; backslashes; backslashes--)
    136 	  *++q = '\\';
    137 
    138 	/* and now, add the quote character itself */
    139 
    140 	*++q = '"';
    141       }
    142       else {
    143 	/* Any other character is simply copied,
    144 	 * but first, if we have any pending backslashes,
    145 	 * we must now insert them, without any count adjustment.
    146 	 */
    147 
    148 	while (backslashes) {
    149 	  *++q = '\\';
    150 	  --backslashes;
    151 	}
    152 
    153 	/* and then, copy the current character */
    154 
    155 	*++q = *p;
    156       }
    157     }
    158 
    159     /* At end of argument:
    160      * If any backslashes remain to be copied out, append them now,
    161      * doubling the actual count to protect against reduction by MSVC,
    162      * as a consequence of the immediately following closing quote.
    163      */
    164 
    165     for (backslashes += backslashes; backslashes; backslashes--)
    166       *++q = '\\';
    167 
    168     /* Finally,
    169      * add the closing quote, terminate the quoted string,
    170      * and adjust its size to what was actually required,
    171      * ready for return.
    172      */
    173 
    174     *++q = '"';
    175     *++q = '\0';
    176     if ((string = (char *)realloc(quoted, strlen(quoted) + 1)) == NULL) {
    177       /* but bail out gracefully, on error */
    178 
    179       REPORT_ERROR(QUOTE_ARG_REALLOC_ERROR);
    180       exit(1);
    181     }
    182   }
    183 
    184   /* `string' now refers to the argument,
    185    * quoted and escaped, as required.
    186    */
    187 
    188   return string;
    189 }
    190 
    191 void
    192 purge_quoted_args(char **argv)
    193 {
    194   /* To avoid memory leaks,
    195    * free all memory previously allocated by `quoted_arg()',
    196    * within the scope of the referring argument vector, `argv'.
    197    */
    198 
    199   if (argv)
    200     while (*argv) {
    201       /* Any argument beginning with a double quote
    202        * SHOULD have been allocated by `quoted_arg()'.
    203        */
    204 
    205       if (**argv == '"')
    206         free( *argv );		/* so free its allocation */
    207       ++argv;			/* and continue to the next argument */
    208     }
    209 }
    210 
    211 /* quotearg.c: end of file */
    212