summaryrefslogtreecommitdiff
path: root/libiberty/argv.c
diff options
context:
space:
mode:
Diffstat (limited to 'libiberty/argv.c')
-rw-r--r--libiberty/argv.c333
1 files changed, 333 insertions, 0 deletions
diff --git a/libiberty/argv.c b/libiberty/argv.c
new file mode 100644
index 00000000000..60694f919bb
--- /dev/null
+++ b/libiberty/argv.c
@@ -0,0 +1,333 @@
+/* Create and destroy argument vectors (argv's)
+ Copyright (C) 1992 Free Software Foundation, Inc.
+ Written by Fred Fish @ Cygnus Support
+
+This file is part of the libiberty library.
+Libiberty is free software; you can redistribute it and/or
+modify it under the terms of the GNU Library General Public
+License as published by the Free Software Foundation; either
+version 2 of the License, or (at your option) any later version.
+
+Libiberty 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
+Library General Public License for more details.
+
+You should have received a copy of the GNU Library General Public
+License along with libiberty; see the file COPYING.LIB. If
+not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+/* Create and destroy argument vectors. An argument vector is simply an
+ array of string pointers, terminated by a NULL pointer. */
+
+#include "ansidecl.h"
+#include "libiberty.h"
+
+#ifdef isspace
+#undef isspace
+#endif
+#define isspace(ch) ((ch) == ' ' || (ch) == '\t')
+
+/* Routines imported from standard C runtime libraries. */
+
+#ifdef __STDC__
+
+#include <stddef.h>
+extern void *memcpy (void *s1, const void *s2, size_t n); /* 4.11.2.1 */
+extern size_t strlen (const char *s); /* 4.11.6.3 */
+extern void *malloc (size_t size); /* 4.10.3.3 */
+extern void *realloc (void *ptr, size_t size); /* 4.10.3.4 */
+extern void free (void *ptr); /* 4.10.3.2 */
+extern char *strdup (const char *s); /* Non-ANSI */
+
+#else /* !__STDC__ */
+
+#if !defined _WIN32 || defined __GNUC__
+extern char *memcpy (); /* Copy memory region */
+extern int strlen (); /* Count length of string */
+extern char *malloc (); /* Standard memory allocater */
+extern char *realloc (); /* Standard memory reallocator */
+extern void free (); /* Free malloc'd memory */
+extern char *strdup (); /* Duplicate a string */
+#endif
+
+#endif /* __STDC__ */
+
+#include "alloca-conf.h"
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef EOS
+#define EOS '\0'
+#endif
+
+#define INITIAL_MAXARGC 8 /* Number of args + NULL in initial argv */
+
+
+/*
+
+NAME
+
+ freeargv -- free an argument vector
+
+SYNOPSIS
+
+ void freeargv (vector)
+ char **vector;
+
+DESCRIPTION
+
+ Free an argument vector that was built using buildargv. Simply scans
+ through the vector, freeing the memory for each argument until the
+ terminating NULL is found, and then frees the vector itself.
+
+RETURNS
+
+ No value.
+
+*/
+
+void freeargv (vector)
+char **vector;
+{
+ register char **scan;
+
+ if (vector != NULL)
+ {
+ for (scan = vector; *scan != NULL; scan++)
+ {
+ free (*scan);
+ }
+ free (vector);
+ }
+}
+
+/*
+
+NAME
+
+ buildargv -- build an argument vector from a string
+
+SYNOPSIS
+
+ char **buildargv (sp)
+ char *sp;
+
+DESCRIPTION
+
+ Given a pointer to a string, parse the string extracting fields
+ separated by whitespace and optionally enclosed within either single
+ or double quotes (which are stripped off), and build a vector of
+ pointers to copies of the string for each field. The input string
+ remains unchanged.
+
+ All of the memory for the pointer array and copies of the string
+ is obtained from malloc. All of the memory can be returned to the
+ system with the single function call freeargv, which takes the
+ returned result of buildargv, as it's argument.
+
+ The memory for the argv array is dynamically expanded as necessary.
+
+RETURNS
+
+ Returns a pointer to the argument vector if successful. Returns NULL
+ if the input string pointer is NULL or if there is insufficient
+ memory to complete building the argument vector.
+
+NOTES
+
+ In order to provide a working buffer for extracting arguments into,
+ with appropriate stripping of quotes and translation of backslash
+ sequences, we allocate a working buffer at least as long as the input
+ string. This ensures that we always have enough space in which to
+ work, since the extracted arg is never larger than the input string.
+
+ If the input is a null string (as opposed to a NULL pointer), then
+ buildarg returns an argv that has one arg, a null string.
+
+ Argv is always kept terminated with a NULL arg pointer, so it can
+ be passed to freeargv at any time, or returned, as appropriate.
+*/
+
+char **buildargv (input)
+char *input;
+{
+ char *arg;
+ char *copybuf;
+ int squote = 0;
+ int dquote = 0;
+ int bsquote = 0;
+ int argc = 0;
+ int maxargc = 0;
+ char **argv = NULL;
+ char **nargv;
+
+ if (input != NULL)
+ {
+ copybuf = alloca (strlen (input) + 1);
+ /* Is a do{}while to always execute the loop once. Always return an
+ argv, even for null strings. See NOTES above, test case below. */
+ do
+ {
+ /* Pick off argv[argc] */
+ while (isspace (*input))
+ {
+ input++;
+ }
+ if ((maxargc == 0) || (argc >= (maxargc - 1)))
+ {
+ /* argv needs initialization, or expansion */
+ if (argv == NULL)
+ {
+ maxargc = INITIAL_MAXARGC;
+ nargv = (char **) malloc (maxargc * sizeof (char *));
+ }
+ else
+ {
+ maxargc *= 2;
+ nargv = (char **) realloc (argv, maxargc * sizeof (char *));
+ }
+ if (nargv == NULL)
+ {
+ if (argv != NULL)
+ {
+ freeargv (argv);
+ argv = NULL;
+ }
+ break;
+ }
+ argv = nargv;
+ argv[argc] = NULL;
+ }
+ /* Begin scanning arg */
+ arg = copybuf;
+ while (*input != EOS)
+ {
+ if (isspace (*input) && !squote && !dquote && !bsquote)
+ {
+ break;
+ }
+ else
+ {
+ if (bsquote)
+ {
+ bsquote = 0;
+ *arg++ = *input;
+ }
+ else if (*input == '\\')
+ {
+ bsquote = 1;
+ }
+ else if (squote)
+ {
+ if (*input == '\'')
+ {
+ squote = 0;
+ }
+ else
+ {
+ *arg++ = *input;
+ }
+ }
+ else if (dquote)
+ {
+ if (*input == '"')
+ {
+ dquote = 0;
+ }
+ else
+ {
+ *arg++ = *input;
+ }
+ }
+ else
+ {
+ if (*input == '\'')
+ {
+ squote = 1;
+ }
+ else if (*input == '"')
+ {
+ dquote = 1;
+ }
+ else
+ {
+ *arg++ = *input;
+ }
+ }
+ input++;
+ }
+ }
+ *arg = EOS;
+ argv[argc] = strdup (copybuf);
+ if (argv[argc] == NULL)
+ {
+ freeargv (argv);
+ argv = NULL;
+ break;
+ }
+ argc++;
+ argv[argc] = NULL;
+
+ while (isspace (*input))
+ {
+ input++;
+ }
+ }
+ while (*input != EOS);
+ }
+ return (argv);
+}
+
+#ifdef MAIN
+
+/* Simple little test driver. */
+
+static char *tests[] =
+{
+ "a simple command line",
+ "arg 'foo' is single quoted",
+ "arg \"bar\" is double quoted",
+ "arg \"foo bar\" has embedded whitespace",
+ "arg 'Jack said \\'hi\\'' has single quotes",
+ "arg 'Jack said \\\"hi\\\"' has double quotes",
+ "a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9",
+
+ /* This should be expanded into only one argument. */
+ "trailing-whitespace ",
+
+ "",
+ NULL
+};
+
+main ()
+{
+ char **argv;
+ char **test;
+ char **targs;
+
+ for (test = tests; *test != NULL; test++)
+ {
+ printf ("buildargv(\"%s\")\n", *test);
+ if ((argv = buildargv (*test)) == NULL)
+ {
+ printf ("failed!\n\n");
+ }
+ else
+ {
+ for (targs = argv; *targs != NULL; targs++)
+ {
+ printf ("\t\"%s\"\n", *targs);
+ }
+ printf ("\n");
+ }
+ freeargv (argv);
+ }
+
+}
+
+#endif /* MAIN */