]> diplodocus.org Git - nmh/commitdiff
Beginning of implementation of new argsplit() function to handle arguments
authorKen Hornstein <kenh@pobox.com>
Fri, 18 Jan 2013 21:03:26 +0000 (16:03 -0500)
committerKen Hornstein <kenh@pobox.com>
Fri, 18 Jan 2013 21:03:26 +0000 (16:03 -0500)
to profile-defined commands.

Makefile.am
sbr/arglist.c [new file with mode: 0644]

index 0fbf441a49515ab0036d56d0da1b7b7cce21d002..b79e930dc7f349f068b6b1e722376754cd20e965 100644 (file)
@@ -472,7 +472,8 @@ uninstall-hook:
 ##
 ## Our rules to build our internal libraries (libmh.a, libmts.a)
 ##
-sbr_libmh_a_SOURCES = sbr/addrsbr.c sbr/ambigsw.c sbr/atooi.c sbr/base64.c \
+sbr_libmh_a_SOURCES = sbr/addrsbr.c sbr/ambigsw.c sbr/atooi.c sbr/arglist.c \
+                     sbr/base64.c \
                      sbr/brkstring.c sbr/check_charset.c sbr/client.c \
                      sbr/closefds.c sbr/concat.c sbr/context_del.c \
                      sbr/context_find.c sbr/context_foil.c sbr/context_read.c \
diff --git a/sbr/arglist.c b/sbr/arglist.c
new file mode 100644 (file)
index 0000000..20bf84c
--- /dev/null
@@ -0,0 +1,124 @@
+
+/*
+ * arglist.c -- Routines for handling argument lists for execvp() and friends
+ *
+ * This code is Copyright (c) 2013, by the authors of nmh.  See the
+ * COPYRIGHT file in the root directory of the nmh distribution for
+ * complete copyright information.
+ */
+
+#include <h/mh.h>
+#include <h/utils.h>
+
+/*
+ * Split up a command into an appropriate array to pass to execvp()
+ * or similar function.  Returns an allocated argv[] array.
+ *
+ * Function arguments:
+ *
+ * command - String to split up
+ * file    - the first argument to "command", suitable for the first argument
+ *           to execvp().  Returns allocated memory that must be free()d.
+ * argp    - Index to last element (NULL) of returned argv[] array.
+ *
+ * Our basic algorithm is this:
+ *
+ * - If there are no spaces or shell metacharacters in "command", then
+ *   take it as-is.
+ * - If there are spaces in command, space-split command string and
+ *   append an argument list to it.
+ * - If we have shell metacharacters, run the command using
+ *   /bin/sh -c 'command "${@}"'.
+ *
+ * In all cases additional arguments can be added to the argv[] array.
+ */
+
+/* Shell metacharacters we use to trigger a call to the shell */
+
+#define METACHARS      "$&*(){}[]'\";\\|?<>~`\n"
+
+char **
+argsplit(char *command, char **file, int *argp)
+{
+    char **argvarray, *p;
+    int space = 0, metachar = 0, i;
+
+    for (p = command; *p; p++) {
+       if (*p == ' ' || *p == '\t') {
+               space = 1;
+       } else if (strchr(METACHARS, *p)) {
+               metachar = 1;
+               break;
+       }
+    }
+
+    argvarray = (char **) mh_xmalloc((sizeof(char **) * MAXARGS));
+
+    /*
+     * The simple case - no spaces or shell metacharacters
+     */
+
+    if (!space && !metachar) {
+       argvarray[0] = getcpy(r1bindex(command, '/'));
+       argvarray[1] = NULL;
+       *file = getcpy(command);
+       if (argp)
+           *argp = 1;
+       return argvarray;
+    }
+
+    /*
+     * Spaces, but no shell metacharacters; space-split into seperate
+     * arguments
+     */
+
+    if (space && !metachar) {
+       char **split;
+       p = getcpy(command);
+       split = brkstring(p, " \t", NULL);
+       if (split[0] == NULL) {
+           adios(NULL, "Invalid blank command found");
+       }
+       argvarray[0] = getcpy(r1bindex(split[0], '/'));
+       for (i = 1; split[i] != NULL; i++) {
+           if (i > MAXARGS) {
+               adios(NULL, "Command exceeded argument limit");
+           }
+           argvarray[i] = getcpy(split[i]);
+       }
+       argvarray[i] = NULL;
+       *file = getcpy(split[0]);
+       if (argp)
+           *argp = i;
+       return argvarray;
+    }
+
+    /*
+     * Remaining option - pass to the shell.
+     *
+     * Some notes here:
+     *
+     * - The command passed to "sh -c" is actually:
+     *      command "$@"
+     *
+     *   If there are additional arguments they will be expanded by the
+     *   shell, otherwise "$@" expands to nothing.
+     *
+     * - Every argument after the -c string gets put into positional
+     *   parameters starting at $0, but $@ starts expanding with $1.
+     *   So we put in a dummy argument (we just use /bin/sh)
+     */
+
+    *file = getcpy("/bin/sh");
+    argvarray[0] = getcpy("sh");
+    argvarray[1] = getcpy("-c");
+    argvarray[2] = getcpy(command);
+    argvarray[2] = add(" \"$@\"", argvarray[2]);
+    argvarray[3] = getcpy("/bin/sh");
+    argvarray[4] = NULL;
+
+    if (argp)
+       *argp = 4;
+
+    return argvarray;
+}