1151497Sru/* Copyright (C) 2004 2151497Sru Free Software Foundation, Inc. 3151497Sru Written by: Jeff Conrad (jeff_conrad@msn.com) 4151497Sru and Keith Marshall (keith.d.marshall@ntlworld.com) 5151497Sru 6151497SruThis file is part of groff. 7151497Sru 8151497Srugroff is free software; you can redistribute it and/or modify it under 9151497Sruthe terms of the GNU General Public License as published by the Free 10151497SruSoftware Foundation; either version 2, or (at your option) any later 11151497Sruversion. 12151497Sru 13151497Srugroff is distributed in the hope that it will be useful, but WITHOUT ANY 14151497SruWARRANTY; without even the implied warranty of MERCHANTABILITY or 15151497SruFITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16151497Srufor more details. 17151497Sru 18151497SruYou should have received a copy of the GNU General Public License along 19151497Sruwith groff; see the file COPYING. If not, write to the Free Software 20151497SruFoundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */ 21151497Sru 22151497Sru#include <stdio.h> 23151497Sru#include <stdlib.h> 24151497Sru#include <string.h> 25151497Sru#include <ctype.h> 26151497Sru#include <limits.h> 27151497Sru 28151497Sru/* Define the default mechanism, and messages, for error reporting 29151497Sru * (user may substitute a preferred alternative, by defining his own 30151497Sru * implementation of the macros REPORT_ERROR, QUOTE_ARG_MALLOC_FAILED 31151497Sru * and QUOTE_ARG_REALLOC_FAILED, in the header file `nonposix.h'). 32151497Sru */ 33151497Sru 34151497Sru#include "nonposix.h" 35151497Sru 36151497Sru#ifndef REPORT_ERROR 37151497Sru# define REPORT_ERROR(WHY) fprintf(stderr, "%s:%s\n", program_name, WHY) 38151497Sru#endif 39151497Sru#ifndef QUOTE_ARG_MALLOC_ERROR 40151497Sru# define QUOTE_ARG_MALLOC_ERROR "malloc: Buffer allocation failed" 41151497Sru#endif 42151497Sru#ifndef QUOTE_ARG_REALLOC_ERROR 43151497Sru# define QUOTE_ARG_REALLOC_ERROR "realloc: Buffer resize failed" 44151497Sru#endif 45151497Sru 46151497Sruextern char *program_name; /* main program must define this */ 47151497Sru 48151497Sru#undef FALSE 49151497Sru#undef TRUE 50151497Sru#define FALSE 0 51151497Sru#define TRUE 1 52151497Sru 53151497Srustatic int 54151497Sruneeds_quoting(const char *string) 55151497Sru{ 56151497Sru /* Scan `string' to see whether it needs quoting for MSVC `spawn'/`exec' 57151497Sru * (i.e., whether it contains whitespace or embedded quotes). 58151497Sru */ 59151497Sru 60151497Sru if (string == NULL) /* ignore NULL strings */ 61151497Sru return FALSE; 62151497Sru 63151497Sru if (*string == '\0') /* explicit arguments of zero length */ 64151497Sru return TRUE; /* need quoting, so they aren't discarded */ 65151497Sru 66151497Sru while (*string) { 67151497Sru /* Scan non-NULL strings, up to '\0' terminator, 68151497Sru * returning 'TRUE' if quote or white space found. 69151497Sru */ 70151497Sru 71151497Sru if (*string == '"' || isspace(*string)) 72151497Sru return TRUE; 73151497Sru 74151497Sru /* otherwise, continue scanning to end of string */ 75151497Sru 76151497Sru ++string; 77151497Sru } 78151497Sru 79151497Sru /* Fall through, if no quotes or white space found, 80151497Sru * in which case, return `FALSE'. 81151497Sru */ 82151497Sru 83151497Sru return FALSE; 84151497Sru} 85151497Sru 86151497Sruchar * 87151497Sruquote_arg(char *string) 88151497Sru{ 89151497Sru /* Enclose arguments in double quotes so that the parsing done in the 90151497Sru * MSVC runtime startup code doesn't split them at whitespace. Escape 91151497Sru * embedded double quotes so that they emerge intact from the parsing. 92151497Sru */ 93151497Sru 94151497Sru int backslashes; 95151497Sru char *quoted, *p, *q; 96151497Sru 97151497Sru if (needs_quoting(string)) { 98151497Sru /* Need to create a quoted copy of `string'; 99151497Sru * maximum buffer space needed is twice the original length, 100151497Sru * plus two enclosing quotes and one `\0' terminator. 101151497Sru */ 102151497Sru 103151497Sru if ((quoted = (char *)malloc(2 * strlen(string) + 3)) == NULL) { 104151497Sru /* Couldn't get a buffer for the quoted string, 105151497Sru * so complain, and bail out gracefully. 106151497Sru */ 107151497Sru 108151497Sru REPORT_ERROR(QUOTE_ARG_MALLOC_ERROR); 109151497Sru exit(1); 110151497Sru } 111151497Sru 112151497Sru /* Ok to proceed: 113151497Sru * insert the opening quote, then copy the source string, 114151497Sru * adding escapes as required. 115151497Sru */ 116151497Sru 117151497Sru *quoted = '"'; 118151497Sru for (backslashes = 0, p = string, q = quoted; *p; p++) { 119151497Sru if (*p == '\\') { 120151497Sru /* Just count backslashes when we find them. 121151497Sru * We will copy them out later, when we know if the count 122151497Sru * needs to be adjusted, to escape an embedded quote. 123151497Sru */ 124151497Sru 125151497Sru ++backslashes; 126151497Sru } 127151497Sru else if (*p == '"') { 128151497Sru /* This embedded quote character must be escaped, 129151497Sru * but first double up any immediately preceding backslashes, 130151497Sru * with one extra, as the escape character. 131151497Sru */ 132151497Sru 133151497Sru for (backslashes += backslashes + 1; backslashes; backslashes--) 134151497Sru *++q = '\\'; 135151497Sru 136151497Sru /* and now, add the quote character itself */ 137151497Sru 138151497Sru *++q = '"'; 139151497Sru } 140151497Sru else { 141151497Sru /* Any other character is simply copied, 142151497Sru * but first, if we have any pending backslashes, 143151497Sru * we must now insert them, without any count adjustment. 144151497Sru */ 145151497Sru 146151497Sru while (backslashes) { 147151497Sru *++q = '\\'; 148151497Sru --backslashes; 149151497Sru } 150151497Sru 151151497Sru /* and then, copy the current character */ 152151497Sru 153151497Sru *++q = *p; 154151497Sru } 155151497Sru } 156151497Sru 157151497Sru /* At end of argument: 158151497Sru * If any backslashes remain to be copied out, append them now, 159151497Sru * doubling the actual count to protect against reduction by MSVC, 160151497Sru * as a consequence of the immediately following closing quote. 161151497Sru */ 162151497Sru 163151497Sru for (backslashes += backslashes; backslashes; backslashes--) 164151497Sru *++q = '\\'; 165151497Sru 166151497Sru /* Finally, 167151497Sru * add the closing quote, terminate the quoted string, 168151497Sru * and adjust its size to what was actually required, 169151497Sru * ready for return. 170151497Sru */ 171151497Sru 172151497Sru *++q = '"'; 173151497Sru *++q = '\0'; 174151497Sru if ((string = (char *)realloc(quoted, strlen(quoted) + 1)) == NULL) { 175151497Sru /* but bail out gracefully, on error */ 176151497Sru 177151497Sru REPORT_ERROR(QUOTE_ARG_REALLOC_ERROR); 178151497Sru exit(1); 179151497Sru } 180151497Sru } 181151497Sru 182151497Sru /* `string' now refers to the argument, 183151497Sru * quoted and escaped, as required. 184151497Sru */ 185151497Sru 186151497Sru return string; 187151497Sru} 188151497Sru 189151497Sruvoid 190151497Srupurge_quoted_args(char **argv) 191151497Sru{ 192151497Sru /* To avoid memory leaks, 193151497Sru * free all memory previously allocated by `quoted_arg()', 194151497Sru * within the scope of the referring argument vector, `argv'. 195151497Sru */ 196151497Sru 197151497Sru if (argv) 198151497Sru while (*argv) { 199151497Sru /* Any argument beginning with a double quote 200151497Sru * SHOULD have been allocated by `quoted_arg()'. 201151497Sru */ 202151497Sru 203151497Sru if (**argv == '"') 204151497Sru free( *argv ); /* so free its allocation */ 205151497Sru ++argv; /* and continue to the next argument */ 206151497Sru } 207151497Sru} 208151497Sru 209151497Sru/* quotearg.c: end of file */ 210