No empty .Rs/.Re
[netbsd-mini2440.git] / gnu / dist / groff / src / libs / libgroff / quotearg.c
blob2a9862180b3ac598f2319f488d0625c761bce5dd
1 /* $NetBSD$ */
3 /* Copyright (C) 2004
4 Free Software Foundation, Inc.
5 Written by: Jeff Conrad (jeff_conrad@msn.com)
6 and Keith Marshall (keith.d.marshall@ntlworld.com)
8 This file is part of groff.
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.
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.
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. */
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <ctype.h>
28 #include <limits.h>
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').
36 #include "nonposix.h"
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
48 extern char *program_name; /* main program must define this */
50 #undef FALSE
51 #undef TRUE
52 #define FALSE 0
53 #define TRUE 1
55 static int
56 needs_quoting(const char *string)
58 /* Scan `string' to see whether it needs quoting for MSVC `spawn'/`exec'
59 * (i.e., whether it contains whitespace or embedded quotes).
62 if (string == NULL) /* ignore NULL strings */
63 return FALSE;
65 if (*string == '\0') /* explicit arguments of zero length */
66 return TRUE; /* need quoting, so they aren't discarded */
68 while (*string) {
69 /* Scan non-NULL strings, up to '\0' terminator,
70 * returning 'TRUE' if quote or white space found.
73 if (*string == '"' || isspace(*string))
74 return TRUE;
76 /* otherwise, continue scanning to end of string */
78 ++string;
81 /* Fall through, if no quotes or white space found,
82 * in which case, return `FALSE'.
85 return FALSE;
88 char *
89 quote_arg(char *string)
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.
96 int backslashes;
97 char *quoted, *p, *q;
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.
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.
110 REPORT_ERROR(QUOTE_ARG_MALLOC_ERROR);
111 exit(1);
114 /* Ok to proceed:
115 * insert the opening quote, then copy the source string,
116 * adding escapes as required.
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.
127 ++backslashes;
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.
135 for (backslashes += backslashes + 1; backslashes; backslashes--)
136 *++q = '\\';
138 /* and now, add the quote character itself */
140 *++q = '"';
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.
148 while (backslashes) {
149 *++q = '\\';
150 --backslashes;
153 /* and then, copy the current character */
155 *++q = *p;
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.
165 for (backslashes += backslashes; backslashes; backslashes--)
166 *++q = '\\';
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.
174 *++q = '"';
175 *++q = '\0';
176 if ((string = (char *)realloc(quoted, strlen(quoted) + 1)) == NULL) {
177 /* but bail out gracefully, on error */
179 REPORT_ERROR(QUOTE_ARG_REALLOC_ERROR);
180 exit(1);
184 /* `string' now refers to the argument,
185 * quoted and escaped, as required.
188 return string;
191 void
192 purge_quoted_args(char **argv)
194 /* To avoid memory leaks,
195 * free all memory previously allocated by `quoted_arg()',
196 * within the scope of the referring argument vector, `argv'.
199 if (argv)
200 while (*argv) {
201 /* Any argument beginning with a double quote
202 * SHOULD have been allocated by `quoted_arg()'.
205 if (**argv == '"')
206 free( *argv ); /* so free its allocation */
207 ++argv; /* and continue to the next argument */
211 /* quotearg.c: end of file */