/* -*-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.
*
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
* 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;
}
*/
for (;;) {
- p = nextWord(argc, argv, data);
+ p = nextword(argc, argv, data);
if (!p)
return (EOF);
case OPTF_ARGREQ:
if (!p) {
- p = nextWord(argc, argv, data);
+ p = nextword(argc, argv, data);
if (!p) {
if (data->err) {
/* --- 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",