home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.2 (Developer) / NS_dev_3.2.iso / NextDeveloper / Source / GNU / libg++ / libiberty / argv.c < prev    next >
C/C++ Source or Header  |  1993-06-29  |  7KB  |  333 lines

  1. /* Create and destroy argument vectors (argv's)
  2.    Copyright (C) 1992 Free Software Foundation, Inc.
  3.    Written by Fred Fish @ Cygnus Support
  4.  
  5. This file is part of the libiberty library.
  6. Libiberty is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU Library General Public
  8. License as published by the Free Software Foundation; either
  9. version 2 of the License, or (at your option) any later version.
  10.  
  11. Libiberty is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14. Library General Public License for more details.
  15.  
  16. You should have received a copy of the GNU Library General Public
  17. License along with libiberty; see the file COPYING.LIB.  If
  18. not, write to the Free Software Foundation, Inc., 675 Mass Ave,
  19. Cambridge, MA 02139, USA.  */
  20.  
  21.  
  22. /*  Create and destroy argument vectors.  An argument vector is simply an
  23.     array of string pointers, terminated by a NULL pointer. */
  24.  
  25. /* AIX requires this to be the first thing in the file. */
  26. #ifdef __GNUC__
  27. #define alloca __builtin_alloca
  28. #else /* not __GNUC__ */
  29. #ifdef sparc
  30. #include <alloca.h>
  31. extern char *__builtin_alloca();  /* Stupid include file doesn't declare it */
  32. #else
  33. #ifdef _AIX
  34.  #pragma alloca
  35. #else
  36. char *alloca ();
  37. #endif
  38. #endif /* sparc */
  39. #endif /* not __GNUC__ */
  40.  
  41. #define isspace(ch) ((ch) == ' ' || (ch) == '\t')
  42.  
  43. #include "alloca-conf.h"
  44.  
  45. /*  Routines imported from standard C runtime libraries. */
  46.  
  47. #ifdef __STDC__
  48.  
  49. #include <stddef.h>
  50. extern void *memcpy (void *s1, const void *s2, size_t n);    /* 4.11.2.1 */
  51. extern size_t strlen (const char *s);                /* 4.11.6.3 */
  52. extern void *malloc (size_t size);                /* 4.10.3.3 */
  53. extern void *realloc (void *ptr, size_t size);            /* 4.10.3.4 */
  54. extern void free (void *ptr);                    /* 4.10.3.2 */
  55. extern char *strdup (const char *s);                /* Non-ANSI */
  56.  
  57. #else    /* !__STDC__ */
  58.  
  59. extern char *memcpy ();        /* Copy memory region */
  60. extern int strlen ();        /* Count length of string */
  61. extern char *malloc ();        /* Standard memory allocater */
  62. extern char *realloc ();    /* Standard memory reallocator */
  63. extern void free ();        /* Free malloc'd memory */
  64. extern char *strdup ();        /* Duplicate a string */
  65.  
  66. #endif    /* __STDC__ */
  67.  
  68. #ifndef NULL
  69. #define NULL 0
  70. #endif
  71.  
  72. #ifndef EOS
  73. #define EOS '\0'
  74. #endif
  75.  
  76. #define INITIAL_MAXARGC 8    /* Number of args + NULL in initial argv */
  77.  
  78.  
  79. /*
  80.  
  81. NAME
  82.  
  83.     freeargv -- free an argument vector
  84.  
  85. SYNOPSIS
  86.  
  87.     void freeargv (vector)
  88.     char **vector;
  89.  
  90. DESCRIPTION
  91.  
  92.     Free an argument vector that was built using buildargv.  Simply scans
  93.     through the vector, freeing the memory for each argument until the
  94.     terminating NULL is found, and then frees the vector itself.
  95.  
  96. RETURNS
  97.  
  98.     No value.
  99.  
  100. */
  101.  
  102. void freeargv (vector)
  103. char **vector;
  104. {
  105.   register char **scan;
  106.  
  107.   if (vector != NULL)
  108.     {
  109.       for (scan = vector; *scan != NULL; scan++)
  110.     {
  111.       free (*scan);
  112.     }
  113.       free (vector);
  114.     }
  115. }
  116.  
  117. /*
  118.  
  119. NAME
  120.  
  121.     buildargv -- build an argument vector from a string
  122.  
  123. SYNOPSIS
  124.  
  125.     char **buildargv (sp)
  126.     char *sp;
  127.  
  128. DESCRIPTION
  129.  
  130.     Given a pointer to a string, parse the string extracting fields
  131.     separated by whitespace and optionally enclosed within either single
  132.     or double quotes (which are stripped off), and build a vector of
  133.     pointers to copies of the string for each field.  The input string
  134.     remains unchanged.
  135.  
  136.     All of the memory for the pointer array and copies of the string
  137.     is obtained from malloc.  All of the memory can be returned to the
  138.     system with the single function call freeargv, which takes the
  139.     returned result of buildargv, as it's argument.
  140.  
  141.     The memory for the argv array is dynamically expanded as necessary.
  142.  
  143. RETURNS
  144.  
  145.     Returns a pointer to the argument vector if successful. Returns NULL
  146.     if the input string pointer is NULL or if there is insufficient
  147.     memory to complete building the argument vector.
  148.  
  149. NOTES
  150.  
  151.     In order to provide a working buffer for extracting arguments into,
  152.     with appropriate stripping of quotes and translation of backslash
  153.     sequences, we allocate a working buffer at least as long as the input
  154.     string.  This ensures that we always have enough space in which to
  155.     work, since the extracted arg is never larger than the input string.
  156.  
  157.     If the input is a null string (as opposed to a NULL pointer), then
  158.     buildarg returns an argv that has one arg, a null string.
  159.  
  160.     Argv is always kept terminated with a NULL arg pointer, so it can
  161.     be passed to freeargv at any time, or returned, as appropriate.
  162. */
  163.  
  164. char **buildargv (input)
  165. char *input;
  166. {
  167.   char *arg;
  168.   char *copybuf;
  169.   int squote = 0;
  170.   int dquote = 0;
  171.   int bsquote = 0;
  172.   int argc = 0;
  173.   int maxargc = 0;
  174.   char **argv = NULL;
  175.   char **nargv;
  176.  
  177.   if (input != NULL)
  178.     {
  179.       copybuf = alloca (strlen (input) + 1);
  180.       /* Is a do{}while to always execute the loop once.  Always return an
  181.      argv, even for null strings.  See NOTES above, test case below. */
  182.       do
  183.     {
  184.       /* Pick off argv[argc] */
  185.       while (isspace (*input))
  186.         {
  187.           input++;
  188.         }
  189.       if ((maxargc == 0) || (argc >= (maxargc - 1)))
  190.         {
  191.           /* argv needs initialization, or expansion */
  192.           if (argv == NULL)
  193.         {
  194.           maxargc = INITIAL_MAXARGC;
  195.           nargv = (char **) malloc (maxargc * sizeof (char *));
  196.         }
  197.           else
  198.         {
  199.           maxargc *= 2;
  200.           nargv = (char **) realloc (argv, maxargc * sizeof (char *));
  201.         }
  202.           if (nargv == NULL)
  203.         {
  204.           if (argv != NULL)
  205.             {
  206.               freeargv (argv);
  207.               argv = NULL;
  208.             }
  209.           break;
  210.         }
  211.           argv = nargv;
  212.           argv[argc] = NULL;
  213.         }
  214.       /* Begin scanning arg */
  215.       arg = copybuf;
  216.       while (*input != EOS)
  217.         {
  218.           if (isspace (*input) && !squote && !dquote && !bsquote)
  219.         {
  220.           break;
  221.         }
  222.           else
  223.         {
  224.           if (bsquote)
  225.             {
  226.               bsquote = 0;
  227.               *arg++ = *input;
  228.             }
  229.           else if (*input == '\\')
  230.             {
  231.               bsquote = 1;
  232.             }
  233.           else if (squote)
  234.             {
  235.               if (*input == '\'')
  236.             {
  237.               squote = 0;
  238.             }
  239.               else
  240.             {
  241.               *arg++ = *input;
  242.             }
  243.             }
  244.           else if (dquote)
  245.             {
  246.               if (*input == '"')
  247.             {
  248.               dquote = 0;
  249.             }
  250.               else
  251.             {
  252.               *arg++ = *input;
  253.             }
  254.             }
  255.           else
  256.             {
  257.               if (*input == '\'')
  258.             {
  259.               squote = 1;
  260.             }
  261.               else if (*input == '"')
  262.             {
  263.               dquote = 1;
  264.             }
  265.               else
  266.             {
  267.               *arg++ = *input;
  268.             }
  269.             }
  270.           input++;
  271.         }
  272.         }
  273.       *arg = EOS;
  274.       argv[argc] = strdup (copybuf);
  275.       if (argv[argc] == NULL)
  276.         {
  277.           freeargv (argv);
  278.           argv = NULL;
  279.           break;
  280.         }
  281.       argc++;
  282.       argv[argc] = NULL;
  283.     }
  284.       while (*input != EOS);
  285.     }
  286.   return (argv);
  287. }
  288.  
  289. #ifdef MAIN
  290.  
  291. /* Simple little test driver. */
  292.  
  293. static char *tests[] =
  294. {
  295.   "a simple command line",
  296.   "arg 'foo' is single quoted",
  297.   "arg \"bar\" is double quoted",
  298.   "arg \"foo bar\" has embedded whitespace",
  299.   "arg 'Jack said \\'hi\\'' has single quotes",
  300.   "arg 'Jack said \\\"hi\\\"' has double quotes",
  301.   "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",
  302.   "",
  303.   NULL
  304. };
  305.  
  306. main ()
  307. {
  308.   char **argv;
  309.   char **test;
  310.   char **targs;
  311.  
  312.   for (test = tests; *test != NULL; test++)
  313.     {
  314.       printf ("buildargv(\"%s\")\n", *test);
  315.       if ((argv = buildargv (*test)) == NULL)
  316.     {
  317.       printf ("failed!\n\n");
  318.     }
  319.       else
  320.     {
  321.       for (targs = argv; *targs != NULL; targs++)
  322.         {
  323.           printf ("\t\"%s\"\n", *targs);
  324.         }
  325.       printf ("\n");
  326.     }
  327.       freeargv (argv);
  328.     }
  329.  
  330. }
  331.  
  332. #endif    /* MAIN */
  333.