Sync-to-go: update copyright for 2015
[s-roff.git] / src / lib-roff / quotearg.c
blob119ceb84cfcd652432974638cddc3838dab8ab01
1 /*@
2 * Copyright (c) 2014 - 2015 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
4 * Copyright (C) 2004
5 * Free Software Foundation, Inc.
6 * Written by: Jeff Conrad (jeff_conrad@msn.com)
7 * and Keith Marshall (keith.d.marshall@ntlworld.com)
9 * This is free software; you can redistribute it and/or modify it under
10 * the terms of the GNU General Public License as published by the Free
11 * Software Foundation; either version 2, or (at your option) any later
12 * version.
14 * This is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 * for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with groff; see the file COPYING. If not, write to the Free Software
21 * Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA.
24 #include "config.h"
26 #include <ctype.h>
27 #include <limits.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
32 #include "nonposix.h"
34 /* Define the default mechanism, and messages, for error reporting
35 * (user may substitute a preferred alternative, by defining his own
36 * implementation of the macros REPORT_ERROR, QUOTE_ARG_MALLOC_FAILED
37 * and QUOTE_ARG_REALLOC_FAILED, in the header file `nonposix.h').
40 #ifndef REPORT_ERROR
41 # define REPORT_ERROR(WHY) fprintf(stderr, "%s:%s\n", program_name, WHY)
42 #endif
43 #ifndef QUOTE_ARG_MALLOC_ERROR
44 # define QUOTE_ARG_MALLOC_ERROR "malloc: Buffer allocation failed"
45 #endif
46 #ifndef QUOTE_ARG_REALLOC_ERROR
47 # define QUOTE_ARG_REALLOC_ERROR "realloc: Buffer resize failed"
48 #endif
50 extern char *program_name; /* FIXME main program must define this */
52 static int
53 needs_quoting(const char *string)
55 /* Scan `string' to see whether it needs quoting for MSVC `spawn'/`exec'
56 * (i.e., whether it contains whitespace or embedded quotes).
59 if (string == NULL) /* ignore NULL strings */
60 return false;
62 if (*string == '\0') /* explicit arguments of zero length */
63 return true; /* need quoting, so they aren't discarded */
65 while (*string) {
66 /* Scan non-NULL strings, up to '\0' terminator,
67 * returning 'true' if quote or white space found.
70 if (*string == '"' || isspace(*string))
71 return true;
73 /* otherwise, continue scanning to end of string */
75 ++string;
78 /* Fall through, if no quotes or white space found,
79 * in which case, return `false'.
81 return false;
84 char *
85 quote_arg(char *string)
87 /* Enclose arguments in double quotes so that the parsing done in the
88 * MSVC runtime startup code doesn't split them at whitespace. Escape
89 * embedded double quotes so that they emerge intact from the parsing.
92 int backslashes;
93 char *quoted, *p, *q;
95 if (needs_quoting(string)) {
96 /* Need to create a quoted copy of `string';
97 * maximum buffer space needed is twice the original length,
98 * plus two enclosing quotes and one `\0' terminator.
101 if ((quoted = (char *)malloc(2 * strlen(string) + 3)) == NULL) {
102 /* Couldn't get a buffer for the quoted string,
103 * so complain, and bail out gracefully.
106 REPORT_ERROR(QUOTE_ARG_MALLOC_ERROR);
107 exit(1);
110 /* Ok to proceed:
111 * insert the opening quote, then copy the source string,
112 * adding escapes as required.
115 *quoted = '"';
116 for (backslashes = 0, p = string, q = quoted; *p; p++) {
117 if (*p == '\\') {
118 /* Just count backslashes when we find them.
119 * We will copy them out later, when we know if the count
120 * needs to be adjusted, to escape an embedded quote.
123 ++backslashes;
125 else if (*p == '"') {
126 /* This embedded quote character must be escaped,
127 * but first double up any immediately preceding backslashes,
128 * with one extra, as the escape character.
131 for (backslashes += backslashes + 1; backslashes; backslashes--)
132 *++q = '\\';
134 /* and now, add the quote character itself */
136 *++q = '"';
138 else {
139 /* Any other character is simply copied,
140 * but first, if we have any pending backslashes,
141 * we must now insert them, without any count adjustment.
144 while (backslashes) {
145 *++q = '\\';
146 --backslashes;
149 /* and then, copy the current character */
151 *++q = *p;
155 /* At end of argument:
156 * If any backslashes remain to be copied out, append them now,
157 * doubling the actual count to protect against reduction by MSVC,
158 * as a consequence of the immediately following closing quote.
161 for (backslashes += backslashes; backslashes; backslashes--)
162 *++q = '\\';
164 /* Finally,
165 * add the closing quote, terminate the quoted string,
166 * and adjust its size to what was actually required,
167 * ready for return.
170 *++q = '"';
171 *++q = '\0';
172 if ((string = (char *)realloc(quoted, strlen(quoted) + 1)) == NULL) {
173 /* but bail out gracefully, on error */
175 REPORT_ERROR(QUOTE_ARG_REALLOC_ERROR);
176 exit(1);
180 /* `string' now refers to the argument,
181 * quoted and escaped, as required.
184 return string;
187 void
188 purge_quoted_args(char **argv)
190 /* To avoid memory leaks,
191 * free all memory previously allocated by `quoted_arg()',
192 * within the scope of the referring argument vector, `argv'.
195 if (argv)
196 while (*argv) {
197 /* Any argument beginning with a double quote
198 * SHOULD have been allocated by `quoted_arg()'.
201 if (**argv == '"')
202 free( *argv ); /* so free its allocation */
203 ++argv; /* and continue to the next argument */
207 // s-it2-mode