diff options
author | wlemb <wlemb> | 2004-02-23 11:08:13 +0000 |
---|---|---|
committer | wlemb <wlemb> | 2004-02-23 11:08:13 +0000 |
commit | c2450629493cecca7425c7e753942fc940c15de5 (patch) | |
tree | cf0fe1c46460c8e73194069380b4f5318870a5df | |
parent | 52911304ea8b0eaf55947013a6524abff547fa39 (diff) | |
download | groff-c2450629493cecca7425c7e753942fc940c15de5.tar.gz |
New files.
-rw-r--r-- | src/libs/libgroff/quotearg.c | 207 | ||||
-rw-r--r-- | src/libs/libgroff/spawnvp.c | 116 |
2 files changed, 323 insertions, 0 deletions
diff --git a/src/libs/libgroff/quotearg.c b/src/libs/libgroff/quotearg.c new file mode 100644 index 00000000..62edfd27 --- /dev/null +++ b/src/libs/libgroff/quotearg.c @@ -0,0 +1,207 @@ +/* Copyright (C) 2004 + 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 2, 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#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 a header file called '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 */ + +#undef FALSE +#undef TRUE + +static enum {FALSE=0, TRUE} +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') /* preserve explicit null arguments */ + return TRUE; + + 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 = 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 = 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 */ diff --git a/src/libs/libgroff/spawnvp.c b/src/libs/libgroff/spawnvp.c new file mode 100644 index 00000000..3022fdbd --- /dev/null +++ b/src/libs/libgroff/spawnvp.c @@ -0,0 +1,116 @@ +/* Copyright (C) 2004 + Free Software Foundation, Inc. + Written by: 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 2, 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 groff; see the file COPYING. If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> +#include <stdlib.h> + +#ifdef HAVE_PROCESS_H +# include <process.h> +#endif + +#define SPAWNVP_C 1 + +/* 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 a header file called 'nonposix.h'). + */ + +#include "nonposix.h" + +#ifndef REPORT_ERROR +# define REPORT_ERROR(WHY) fprintf(stderr, "%s:%s\n", program_name, WHY) +#endif +#ifndef SPAWNVP_MALLOC_ERROR +# define SPAWNVP_MALLOC_ERROR "malloc:allocation for 'argv' failed" +#endif + +extern char *program_name; + +extern char *quote_arg(char *string); +extern void purge_quoted_args(char **argv); + +int +spawnvp_wrapper(int mode, char *path, char **argv) +{ + /* Invoke the system `spawnvp' service + * enclosing the passed arguments in double quotes, as required, + * so that the (broken) default parsing in the MSVC runtime doesn't + * split them at whitespace. */ + + char **quoted_argv; /* used to build a quoted local copy of `argv' */ + + int i; /* used as an index into `argv' or `quoted_argv' */ + int status = -1; /* initialise return code, in case we fail */ + int argc = 0; /* initialise argument count; may be none */ + + /* First count the number of arguments + * which are actually present in the passed `argv'. */ + + if (argv) + for (quoted_argv = argv; *quoted_argv; ++argc, ++quoted_argv) + ; + + /* If we do not now have an argument count, + * then we must fall through and fail. */ + + if (argc) { + /* We do have at least one argument: + * We will use a copy of the `argv', in which to do the quoting, + * so we must allocate space for it. */ + + if ((quoted_argv = malloc(++argc * sizeof(char **))) == NULL) { + /* If we didn't get enough space, + * then complain, and bail out gracefully. */ + + REPORT_ERROR(SPAWNVP_MALLOC_ERROR); + exit(1); + } + + /* Now copy the passed `argv' into our new vector, + * quoting it contents as required. */ + + for (i = 0; i < argc; i++) + quoted_argv[i] = quote_arg(argv[i]); + + /* Invoke the MSVC `spawnvp' service + * passing our now appropriately quoted copy of `argv'. */ + + status = spawnvp(mode, path, quoted_argv); + + /* Clean up our memory allocations + * for the quoted copy of `argv', which is no longer required. */ + + purge_quoted_args(quoted_argv); + free(quoted_argv); + } + + /* Finally, + * return the status code returned by `spawnvp', + * or a failure code if we fell through. */ + + return status; +} + +/* spawnvp.c: end of file */ |