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