Use a copy of @str_qword@ for word splitting, to handle quotes
authormdw <mdw>
Sun, 8 Oct 2000 09:57:31 +0000 (09:57 +0000)
committermdw <mdw>
Sun, 8 Oct 2000 09:57:31 +0000 (09:57 +0000)
properly.  If building in mLib, use the real thing directly rather than
the copy.

mdwopt.c

index fcea1b6..167772b 100644 (file)
--- a/mdwopt.c
+++ b/mdwopt.c
@@ -1,6 +1,6 @@
 /* -*-c-*-
  *
- * $Id: mdwopt.c,v 1.8 1999/08/19 18:35:27 mdw Exp $
+ * $Id: mdwopt.c,v 1.9 2000/10/08 09:57:31 mdw Exp $
  *
  * Options parsing, similar to GNU @getopt_long@
  *
 /*----- Revision history --------------------------------------------------*
  *
  * $Log: mdwopt.c,v $
+ * Revision 1.9  2000/10/08 09:57:31  mdw
+ * Use a copy of @str_qword@ for word splitting, to handle quotes
+ * properly.  If building in mLib, use the real thing directly rather than
+ * the copy.
+ *
  * Revision 1.8  1999/08/19 18:35:27  mdw
  * Lots of reformatting.  Spurious wing comments expunged.
  *
@@ -115,9 +120,96 @@ enum {
   ORD_NEGATE = 4                       /* Magic negate-next-thing flag */
 };
 
+/*----- Word splitting ----------------------------------------------------*/
+
+#ifdef BUILDING_MLIB
+#  include "str.h"
+#  define qword str_qword
+#else
+
+/* --- @qword@ --- *
+ *
+ * Arguments:  @char **pp@ = address of pointer into string
+ *             @unsigned f@ = various flags
+ *
+ * Returns:    Pointer to the next space-separated possibly-quoted word from
+ *             the string, or null.
+ *
+ * Use:                Fetches the next word from a string.  If the flag
+ *             @STRF_QUOTE@ is set, the `\' character acts as an escape, and
+ *             single and double quotes protect whitespace.
+ */
+
+#define STRF_QUOTE 1u
+
+static char *qword(char **pp, unsigned f)
+{
+  char *p = *pp, *q, *qq;
+  int st = 0, pst = 0;
+
+  /* --- Preliminaries --- */
+
+  if (!p)
+    return (0);
+  while (isspace((unsigned char)*p))
+    p++;
+  if (!*p) {
+    *pp = 0;
+    return (0);
+  }
+
+  /* --- Main work --- */
+
+  for (q = qq = p; *q; q++) {
+    switch (st) {
+      case '\\':
+       *qq++ = *q;
+       st = pst;
+       break;
+      case '\'':
+      case '\"':
+       if (*q == st)
+         st = pst = 0;
+       else if (*q == '\\')
+         st = '\\';
+       else
+         *qq++ = *q;
+       break;
+      default:
+       if (isspace((unsigned char)*q)) {
+         do q++; while (*q && isspace((unsigned char)*q));
+         goto done;
+       } else if (!(f & STRF_QUOTE))
+         goto stdchar;
+       switch (*q) {
+         case '\\':
+           st = '\\';
+           break;
+         case '\'':
+         case '\"':
+           st = pst = *q;
+           break;
+         default:
+         stdchar:
+           *qq++ = *q;
+           break;
+       }
+    }
+  }
+
+  /* --- Finished --- */
+
+done:
+  *pp = *q ? q : 0;
+  *qq++ = 0;
+  return (p);
+}
+
+#endif
+
 /*----- Main code ---------------------------------------------------------*/
 
-/* --- @nextWord@ --- *
+/* --- @nextword@ --- *
  *
  * Arguments:   @int argc@ = number of command line options
  *              @char *argv[]@ = pointer to command line options
@@ -129,22 +221,12 @@ enum {
  *              variable.
  */
 
-static char *nextWord(int argc, char *const *argv, mdwopt_data *data)
+static char *nextword(int argc, char *const *argv, mdwopt_data *data)
 {
   if (data->ind == -1) {
-    char *p = data->env;
-    char *q;
-    while (isspace((unsigned char)*p))
-      p++;
-    q = p;
-    while (*p && !isspace((unsigned char)*p))
-      p++;
-    if (*p)
-      *p++ = 0;
-    data->env = p;
-    if (p != q)
-      return (q);
-    data->env = 0;
+    char *p;
+    if ((p = qword(&data->env, STRF_QUOTE)) != 0)
+      return (p);
     data->ind = 1;
   }
 
@@ -558,7 +640,7 @@ int mdwopt(int argc, char *const *argv,
      */
 
     for (;;) {
-      p = nextWord(argc, argv, data);
+      p = nextword(argc, argv, data);
       if (!p)
        return (EOF);
 
@@ -707,7 +789,7 @@ int mdwopt(int argc, char *const *argv,
 
        case OPTF_ARGREQ:
          if (!p) {
-           p = nextWord(argc, argv, data);
+           p = nextword(argc, argv, data);
 
            if (!p) {
              if (data->err) {
@@ -787,7 +869,7 @@ int mdwopt(int argc, char *const *argv,
 
       /* --- Same code as before --- */
 
-      q = nextWord(argc, argv, data);
+      q = nextword(argc, argv, data);
       if (!q) {
        if (data->err) {
          fprintf(stderr, "%s: option `%c%c' requires an argument\n",