Makefile.am: Ship `debian/compat'.
[cfd] / mdwopt.c
index fcea1b6..fc76635 100644 (file)
--- a/mdwopt.c
+++ b/mdwopt.c
@@ -1,7 +1,5 @@
 /* -*-c-*-
  *
- * $Id: mdwopt.c,v 1.8 1999/08/19 18:35:27 mdw Exp $
- *
  * Options parsing, similar to GNU @getopt_long@
  *
  * (c) 1996 Straylight/Edgeware
  * MA 02111-1307, USA.
  */
 
-/*----- Revision history --------------------------------------------------*
- *
- * $Log: mdwopt.c,v $
- * Revision 1.8  1999/08/19 18:35:27  mdw
- * Lots of reformatting.  Spurious wing comments expunged.
- *
- * Revision 1.7  1999/06/18 21:59:46  mdw
- * Fix stupid bug which only read one word from environment variables.
- *
- * Revision 1.6  1999/05/20 23:00:42  mdw
- * Little formatting things.
- *
- * Revision 1.5  1999/05/19 20:23:59  mdw
- * Change naming to match newer mLib conventions.
- *
- * Revision 1.4  1999/05/15 10:25:38  mdw
- * Fix copyright information.
- *
- * Revision 1.3  1999/05/14 18:51:42  mdw
- * Reformat the LGPL notice slightly.
- *
- * Revision 1.2  1999/05/13 22:57:23  mdw
- * Change `-ise' to `-ize' throughout.
- *
- * Revision 1.1.1.1  1999/05/05 19:23:47  mdw
- * New import.  The old CVS repository was lost in a disk disaster.
- *
- * --- Previous lives ---
- *
- * %Log: mdwopt.c,v %
- * Revision 1.7  1997/09/11 09:19:11  mdw
- * (mo__nextWord): Arrrgh.  Don't free the environment variable buffer!
- * People are still using it!
- *
- * Revision 1.6  1997/09/11 09:05:54  mdw
- * (mo__nextWord): Fix bug which returns too many words from environment
- * variables.
- *
- * Revision 1.5  1997/08/09 20:27:59  mdw
- * Fix spelling of `Licensing'.
- *
- * Revision 1.4  1997/07/29 21:11:35  mdw
- * Reformatted.  Fixed buffer overflow when dealing with environment
- * variables.  Included NT in list of daft operating systems with `\' as a
- * path separator.  Fixed address of the FSF.
- *
- * Revision 1.3  1997/02/26 00:41:10  mdw
- * Added GPL notice to the top.  Slight formatting changes.
- *
- * Revision 1.2  1996/10/28 13:12:13  mdw
- * Fixed calls to ctype.h routines.  Arguments are cast to unsigned char
- * to avoid invoking undefined behaviour caused by signedness of chars.
- *
- * Revision 1.1  1996/09/24 18:01:28  mdw
- * Initial revision
- *
- */
-
 /*----- External dependencies ---------------------------------------------*/
 
 #include <ctype.h>
@@ -115,9 +55,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 +156,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 +575,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 +724,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 +804,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",