/* -*-c-*-
*
- * $Id: mdwopt.c,v 1.8 1999/08/19 18:35:27 mdw Exp $
+ * $Id: mdwopt.c,v 1.10 2004/04/08 01:36:24 mdw Exp $
*
* Options parsing, similar to GNU @getopt_long@
*
* 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>
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",