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