summaryrefslogtreecommitdiffstats
path: root/src/libs/libgroff/quotearg.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/libgroff/quotearg.c')
-rw-r--r--src/libs/libgroff/quotearg.c213
1 files changed, 213 insertions, 0 deletions
diff --git a/src/libs/libgroff/quotearg.c b/src/libs/libgroff/quotearg.c
new file mode 100644
index 0000000..75eaca8
--- /dev/null
+++ b/src/libs/libgroff/quotearg.c
@@ -0,0 +1,213 @@
+/* Copyright (C) 2004-2020 Free Software Foundation, Inc.
+ Written by: Jeff Conrad (jeff_conrad@msn.com)
+ and Keith Marshall (keith.d.marshall@ntlworld.com)
+
+This file is part of groff.
+
+groff is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+groff is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <limits.h>
+
+/* Define the default mechanism, and messages, for error reporting
+ * (user may substitute a preferred alternative, by defining his own
+ * implementation of the macros REPORT_ERROR, QUOTE_ARG_MALLOC_FAILED
+ * and QUOTE_ARG_REALLOC_FAILED, in the header file 'nonposix.h').
+ */
+
+#include "nonposix.h"
+
+#ifndef REPORT_ERROR
+# define REPORT_ERROR(WHY) fprintf(stderr, "%s:%s\n", program_name, WHY)
+#endif
+#ifndef QUOTE_ARG_MALLOC_ERROR
+# define QUOTE_ARG_MALLOC_ERROR "malloc: Buffer allocation failed"
+#endif
+#ifndef QUOTE_ARG_REALLOC_ERROR
+# define QUOTE_ARG_REALLOC_ERROR "realloc: Buffer resize failed"
+#endif
+
+extern char *program_name; /* main program must define this */
+
+/* Prototypes */
+char *quote_arg(char *);
+void purge_quoted_args(char **);
+
+#undef FALSE
+#undef TRUE
+#define FALSE 0
+#define TRUE 1
+
+static int
+needs_quoting(const char *string)
+{
+ /* Scan 'string' to see whether it needs quoting for MSVC 'spawn'/'exec'
+ * (i.e., whether it contains whitespace or embedded quotes).
+ */
+
+ if (string == NULL) /* ignore NULL strings */
+ return FALSE;
+
+ if (*string == '\0') /* explicit arguments of zero length */
+ return TRUE; /* need quoting, so they aren't discarded */
+
+ while (*string) {
+ /* Scan non-NULL strings, up to '\0' terminator,
+ * returning 'TRUE' if quote or white space found.
+ */
+
+ if (*string == '"' || isspace(*string))
+ return TRUE;
+
+ /* otherwise, continue scanning to end of string */
+
+ ++string;
+ }
+
+ /* Fall through, if no quotes or white space found,
+ * in which case, return 'FALSE'.
+ */
+
+ return FALSE;
+}
+
+char *
+quote_arg(char *string)
+{
+ /* Enclose arguments in double quotes so that the parsing done in the
+ * MSVC runtime startup code doesn't split them at whitespace. Escape
+ * embedded double quotes so that they emerge intact from the parsing.
+ */
+
+ int backslashes;
+ char *quoted, *p, *q;
+
+ if (needs_quoting(string)) {
+ /* Need to create a quoted copy of 'string';
+ * maximum buffer space needed is twice the original length,
+ * plus two enclosing quotes and one '\0' terminator.
+ */
+
+ if ((quoted = (char *)malloc(2 * strlen(string) + 3)) == NULL) {
+ /* Couldn't get a buffer for the quoted string,
+ * so complain, and bail out gracefully.
+ */
+
+ REPORT_ERROR(QUOTE_ARG_MALLOC_ERROR);
+ exit(1);
+ }
+
+ /* Ok to proceed:
+ * insert the opening quote, then copy the source string,
+ * adding escapes as required.
+ */
+
+ *quoted = '"';
+ for (backslashes = 0, p = string, q = quoted; *p; p++) {
+ if (*p == '\\') {
+ /* Just count backslashes when we find them.
+ * We will copy them out later, when we know if the count
+ * needs to be adjusted, to escape an embedded quote.
+ */
+
+ ++backslashes;
+ }
+ else if (*p == '"') {
+ /* This embedded quote character must be escaped,
+ * but first double up any immediately preceding backslashes,
+ * with one extra, as the escape character.
+ */
+
+ for (backslashes += backslashes + 1; backslashes; backslashes--)
+ *++q = '\\';
+
+ /* and now, add the quote character itself */
+
+ *++q = '"';
+ }
+ else {
+ /* Any other character is simply copied,
+ * but first, if we have any pending backslashes,
+ * we must now insert them, without any count adjustment.
+ */
+
+ while (backslashes) {
+ *++q = '\\';
+ --backslashes;
+ }
+
+ /* and then, copy the current character */
+
+ *++q = *p;
+ }
+ }
+
+ /* At end of argument:
+ * If any backslashes remain to be copied out, append them now,
+ * doubling the actual count to protect against reduction by MSVC,
+ * as a consequence of the immediately following closing quote.
+ */
+
+ for (backslashes += backslashes; backslashes; backslashes--)
+ *++q = '\\';
+
+ /* Finally,
+ * add the closing quote, terminate the quoted string,
+ * and adjust its size to what was actually required,
+ * ready for return.
+ */
+
+ *++q = '"';
+ *++q = '\0';
+ if ((string = (char *)realloc(quoted, strlen(quoted) + 1)) == NULL) {
+ /* but bail out gracefully, on error */
+
+ REPORT_ERROR(QUOTE_ARG_REALLOC_ERROR);
+ exit(1);
+ }
+ }
+
+ /* 'string' now refers to the argument,
+ * quoted and escaped, as required.
+ */
+
+ return string;
+}
+
+void
+purge_quoted_args(char **argv)
+{
+ /* To avoid memory leaks,
+ * free all memory previously allocated by 'quoted_arg()',
+ * within the scope of the referring argument vector, 'argv'.
+ */
+
+ if (argv)
+ while (*argv) {
+ /* Any argument beginning with a double quote
+ * SHOULD have been allocated by 'quoted_arg()'.
+ */
+
+ if (**argv == '"')
+ free( *argv ); /* so free its allocation */
+ ++argv; /* and continue to the next argument */
+ }
+}
+
+/* quotearg.c: end of file */