Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
import BSD license str2argv from: https://github.com/ryanflannery/str2argv
Baptiste Daroussin committed 12 years ago
commit b2c41fb9da4dd9782f52dac730351eb209ab6440
parent 89beaa5
3 files changed +313 -1
modified external/Makefile
@@ -1,4 +1,4 @@
-
SUBDIR=	sqlite
+
SUBDIR=	sqlite str2argv

.if !exists(/usr/include/bsdyml.h)
SUBDIR+= libyaml
added external/str2argv/str2argv.c
@@ -0,0 +1,257 @@
+
/*
+
 * Copyright (c) 2010, 2011, 2012 Ryan Flannery <ryan.flannery@gmail.com>
+
 *
+
 * Permission to use, copy, modify, and distribute this software for any
+
 * purpose with or without fee is hereby granted, provided that the above
+
 * copyright notice and this permission notice appear in all copies.
+
 *
+
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
 */
+

+
#include "str2argv.h"
+

+
/* initialize empty argc/argv struct */
+
static void
+
argv_init(int *argc, char ***argv)
+
{
+
   if ((*argv = calloc(ARGV_MAX_ENTRIES, sizeof(char*))) == NULL)
+
      err(1, "argv_init: argv calloc fail");
+

+
   if (((*argv)[0] = calloc(ARGV_MAX_TOKEN_LEN, sizeof(char))) == NULL)
+
      err(1, "argv_init: argv[i] calloc fail");
+

+
   bzero((*argv)[0], ARGV_MAX_TOKEN_LEN * sizeof(char));
+
   *argc = 0;
+
}
+

+
/* free all memory in an arc/argv */
+
void
+
argv_free(int *argc, char ***argv)
+
{
+
   int i;
+

+
   for (i = 0; i <= *argc; i++)
+
      free((*argv)[i]);
+

+
   free(*argv);
+
   *argc = 0;
+
}
+

+
/* add a character to the end of the current entry in an argc/argv */
+
static void
+
argv_addch(int argc, char **argv, int c)
+
{
+
   int n;
+

+
   n = strlen(argv[argc]);
+
   if (n == ARGV_MAX_TOKEN_LEN - 1)
+
      errx(1, "argv_addch: reached max token length (%d)", ARGV_MAX_TOKEN_LEN);
+

+
   argv[argc][n] = c;
+
}
+

+
/* complete the current entry in the argc/argv and setup the next one */
+
static void
+
argv_finish_token(int *argc, char ***argv)
+
{
+
   if (*argc == ARGV_MAX_ENTRIES - 1)
+
      errx(1, "argv_finish_token: reached max argv entries(%d)", ARGV_MAX_ENTRIES);
+

+
   if (strlen((*argv)[*argc]) == 0)
+
      return;
+

+
   *argc = *argc + 1;
+
   if (((*argv)[*argc] = calloc(ARGV_MAX_TOKEN_LEN, sizeof(char))) == NULL)
+
      err(1, "argv_finish_token: failed to calloc argv[i]");
+

+
   bzero((*argv)[*argc], ARGV_MAX_TOKEN_LEN * sizeof(char));
+
}
+

+
/*
+
 * Main parser used for converting a string (str) to an argc/argv style
+
 * parameter list.  This handles escape sequences and quoting.  Possibly
+
 * correctly.  :D
+
 * The argc/argv parameters passed are over-written.  After they have been
+
 * built by this function, the caller should use argv_free() on them to
+
 * free() all associated memory.
+
 * If the parsing goes correctly, 0 is returned.  Otherwise, 1 is returned
+
 * and the errmsg parameter is set to some appropriate error message and
+
 * both argc/argv are set to 0/NULL.
+
 */
+
int
+
str2argv(char *str, int *argc, char ***argv, const char **errmsg)
+
{
+
   bool in_token;
+
   bool in_container;
+
   bool escaped;
+
   char container_start;
+
   char c;
+
   int  len;
+
   int  i;
+

+
   const char *ERRORS[2] = {
+
      "Unmatched quotes",
+
      "Unused/Dangling escape sequence"
+
   };
+
   *errmsg = NULL;
+

+
   container_start = 0;
+
   in_token = false;
+
   in_container = false;
+
   escaped = false;
+

+
   len = strlen(str);
+

+
   argv_init(argc, argv);
+
   for (i = 0; i < len; i++) {
+
      c = str[i];
+

+
      switch (c) {
+
         /* handle whitespace */
+
         case ' ':
+
         case '\t':
+
         case '\n':
+
            if (!in_token)
+
               continue;
+

+
            if (in_container) {
+
               argv_addch(*argc, *argv, c);
+
               continue;
+
            }
+

+
            if (escaped) {
+
               escaped = false;
+
               argv_addch(*argc, *argv, c);
+
               continue;
+
            }
+

+
            /* if reached here, we're at end of token */
+
            in_token = false;
+
            argv_finish_token(argc, argv);
+
            break;
+

+
         /* handle quotes */
+
         case '\'':
+
         case '\"':
+

+
            if (escaped) {
+
               argv_addch(*argc, *argv, c);
+
               escaped = false;
+
               continue;
+
            }
+

+
            if (!in_token) {
+
               in_token = true;
+
               in_container = true;
+
               container_start = c;
+
               continue;
+
            }
+

+
            if (in_token && !in_container) {
+
               in_container = true;
+
               container_start = c;
+
               continue;
+
            }
+

+
            if (in_container) {
+
               if (c == container_start) {
+
                  in_container = false;
+
                  in_token = false;
+
                  argv_finish_token(argc, argv);
+
                  continue;
+
               } else {
+
                  argv_addch(*argc, *argv, c);
+
                  continue;
+
               }
+
            }
+

+
            *errmsg = ERRORS[0];
+
            argv_free(argc, argv);
+
            return 1;
+

+
         case '\\':
+
            if (in_container && str[i+1] != container_start) {
+
               argv_addch(*argc, *argv, c);
+
               continue;
+
            }
+

+
            if (escaped) {
+
               escaped = false;
+
               argv_addch(*argc, *argv, c);
+
               continue;
+
            }
+

+
            escaped = true;
+
            break;
+

+
         default:
+
            if (!in_token)
+
               in_token = true;
+

+
            if (escaped)
+
               escaped = false;
+

+
            argv_addch(*argc, *argv, c);
+
      }
+
   }
+
   argv_finish_token(argc, argv);
+

+
   if (in_container) {
+
      argv_free(argc, argv);
+
      *errmsg = ERRORS[0];
+
      return 1;
+
   }
+

+
   if (escaped) {
+
      argv_free(argc, argv);
+
      *errmsg = ERRORS[1];
+
      return 1;
+
   }
+

+
   (*argv)[*argc] = NULL;/*XXX*/
+

+
   return 0;
+
}
+

+
char *
+
argv2str(int argc, char *argv[])
+
{
+
   char *result;
+
   int   len;
+
   int   off;
+
   int   i;
+

+
   /* handle empty case */
+
   if (0 >= argc)
+
      return NULL;
+

+
   /* determine length of resulting string */
+
   len = 0;
+
   for (i = 0; i < argc; i++) {
+
      len += strlen(argv[i]) + 1;
+
      if (strstr(argv[i], " ") != NULL)
+
         len += 2;
+
   }
+

+
   /* allocate result */
+
   if ((result = calloc(len, sizeof(char))) == NULL)
+
      err(1, "argv2str: calloc failed");
+
   bzero(result, len);
+

+
   /* build result */
+
   off = 0;
+
   for (i = 0; i < argc; i++) {
+
      if (strstr(argv[i], " ") == NULL)
+
         off += snprintf(result + off, len, "%s ", argv[i]);
+
      else
+
         off += snprintf(result + off, len, "\'%s\' ", argv[i]);
+
   }
+

+
   return result;
+
}
added external/str2argv/str2argv.h
@@ -0,0 +1,55 @@
+
/*
+
 * Copyright (c) 2010, 2011 Ryan Flannery <ryan.flannery@gmail.com>
+
 *
+
 * Permission to use, copy, modify, and distribute this software for any
+
 * purpose with or without fee is hereby granted, provided that the above
+
 * copyright notice and this permission notice appear in all copies.
+
 *
+
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
 */
+

+
#ifndef STR2ARGV_H
+
#define STR2ARGV_H
+

+
#include <err.h>
+
#include <stdbool.h>
+
#include <stdio.h>
+
#include <stdlib.h>
+
#include <string.h>
+

+

+
/* hard limits on the size of an argv and each entry/token w/in an argv */
+
#define ARGV_MAX_ENTRIES    255
+
#define ARGV_MAX_TOKEN_LEN  255
+

+
/*
+
 * Given a string (str), it parses it taking into account escape sequence (\),
+
 * quoting, etc., and builds an argc/argv style set of parameters that are
+
 * suitable for passing to any of the cmd_* or ecmd_* functions.
+
 *
+
 * This has been tricky for me.  It no doubt has bugs.
+
 * str2argv.c contains a small driver program that can be used for testing.
+
 * The Makefile contains the necessary build target "test_str2argv"
+
 */
+
int str2argv(char *str, int *argc, char ***argv, const char **errmsg);
+

+
/*
+
 * After the above function is used to build an argc/argv set of parameters,
+
 * this function should be used to free() all of the allocated memory.
+
 */
+
void argv_free(int *argc, char ***argv);
+

+
/*
+
 * This is used to un-tokenize an argv array.  Given argc/argv, this
+
 * constructs a string containing all of the tokens in order, with a single
+
 * space between each.  Tokens with multiple words are quoted.
+
 */
+
char *argv2str(int argc, char *argv[]);
+

+
#endif