openenvutils/commandshell/shell/src/modules/zutil.c
changeset 0 2e3d3ce01487
child 1 0fdb7f6b0309
equal deleted inserted replaced
-1:000000000000 0:2e3d3ce01487
       
     1 #ifndef __SYMBIAN32__
       
     2 // zutil.c - misc utilities
       
     3 //
       
     4 // © Portions Copyright (c) Symbian Software Ltd 2007. All rights reserved.
       
     5 //
       
     6 /*
       
     7  * This file is part of zsh, the Z shell.
       
     8  *
       
     9  * Copyright (c) 1999 Sven Wischnowsky
       
    10  * All rights reserved.
       
    11  *
       
    12  * Permission is hereby granted, without written agreement and without
       
    13  * license or royalty fees, to use, copy, modify, and distribute this
       
    14  * software and to distribute modified versions of this software for any
       
    15  * purpose, provided that the above copyright notice and the following
       
    16  * two paragraphs appear in all copies of this software.
       
    17  *
       
    18  * In no event shall Sven Wischnowsky or the Zsh Development Group be liable
       
    19  * to any party for direct, indirect, special, incidental, or consequential
       
    20  * damages arising out of the use of this software and its documentation,
       
    21  * even if Sven Wischnowsky and the Zsh Development Group have been advised of
       
    22  * the possibility of such damage.
       
    23  *
       
    24  * Sven Wischnowsky and the Zsh Development Group specifically disclaim any
       
    25  * warranties, including, but not limited to, the implied warranties of
       
    26  * merchantability and fitness for a particular purpose.  The software
       
    27  * provided hereunder is on an "as is" basis, and Sven Wischnowsky and the
       
    28  * Zsh Development Group have no obligation to provide maintenance,
       
    29  * support, updates, enhancements, or modifications.
       
    30  *
       
    31  */
       
    32 #include "zutil.mdh"
       
    33 #include "zutil.pro"
       
    34 
       
    35 #ifdef __SYMBIAN32__
       
    36 #ifdef __WINSCW__
       
    37 #pragma warn_unusedarg off
       
    38 #pragma warn_possunwant off
       
    39 #endif//__WINSCW__
       
    40 #endif//__SYMBIAN32__
       
    41 
       
    42 /* Style stuff. */
       
    43 
       
    44 typedef struct stypat *Stypat;
       
    45 typedef struct style *Style;
       
    46 
       
    47 /* A pattern and the styles for it. */
       
    48 
       
    49 struct style {
       
    50     Style next;			/* next in stypat list */
       
    51     Stypat pats;		/* patterns */
       
    52     char *name;
       
    53 };
       
    54 
       
    55 struct stypat {
       
    56     Stypat next;
       
    57     char *pat;			/* pattern string */
       
    58     Patprog prog;		/* compiled pattern */
       
    59     int weight;			/* how specific is the pattern? */
       
    60     Eprog eval;			/* eval-on-retrieve? */
       
    61     char **vals;
       
    62 };
       
    63     
       
    64 /* List of styles. */
       
    65 
       
    66 static Style zstyles, zlstyles;
       
    67 
       
    68 /* Memory stuff. */
       
    69 
       
    70 static void
       
    71 freestypat(Stypat p)
       
    72 {
       
    73     zsfree(p->pat);
       
    74     freepatprog(p->prog);
       
    75     if (p->vals)
       
    76 	freearray(p->vals);
       
    77     if (p->eval)
       
    78 	freeeprog(p->eval);
       
    79     zfree(p, sizeof(*p));
       
    80 }
       
    81 
       
    82 static void
       
    83 freeallstyles(void)
       
    84 {
       
    85     Style s, sn;
       
    86     Stypat p, pn;
       
    87 
       
    88     for (s = zstyles; s; s = sn) {
       
    89 	sn = s->next;
       
    90 	for (p = s->pats; p; p = pn) {
       
    91 	    pn = p->next;
       
    92 	    freestypat(p);
       
    93 	}
       
    94 	zsfree(s->name);
       
    95 	zfree(s, sizeof(*s));
       
    96     }
       
    97     zstyles = zlstyles = NULL;
       
    98 }
       
    99 
       
   100 /* Get the style struct for a name. */
       
   101 
       
   102 static Style
       
   103 getstyle(char *name)
       
   104 {
       
   105     Style s;
       
   106 
       
   107     for (s = zstyles; s; s = s->next)
       
   108 	if (!strcmp(name, s->name))
       
   109 	    return s;
       
   110 
       
   111     return NULL;
       
   112 }
       
   113 
       
   114 /* Store a value for a style. */
       
   115 
       
   116 static int
       
   117 setstypat(Style s, char *pat, Patprog prog, char **vals, int eval)
       
   118 {
       
   119     int weight, tmp, first;
       
   120     char *str;
       
   121     Stypat p, q, qq;
       
   122     Eprog eprog = NULL;
       
   123 
       
   124     if (eval) {
       
   125 	int ef = errflag;
       
   126 
       
   127 	eprog = parse_string(zjoin(vals, ' ', 1));
       
   128 	errflag = ef;
       
   129 
       
   130 	if (!eprog)
       
   131 	{
       
   132 	    freepatprog(prog);
       
   133 	    return 1;
       
   134 	}
       
   135 
       
   136 	eprog = dupeprog(eprog, 0);
       
   137     }
       
   138     for (p = s->pats; p; p = p->next)
       
   139 	if (!strcmp(pat, p->pat)) {
       
   140 
       
   141 	    /* Exists -> replace. */
       
   142 
       
   143 	    if (p->vals)
       
   144 		freearray(p->vals);
       
   145 	    if (p->eval)
       
   146 		freeeprog(p->eval);
       
   147 	    p->vals = zarrdup(vals);
       
   148 	    p->eval = eprog;
       
   149 	    freepatprog(prog);
       
   150 
       
   151 	    return 0;
       
   152 	}
       
   153 
       
   154     /* New pattern. */
       
   155 
       
   156     p = (Stypat) zalloc(sizeof(*p));
       
   157     p->pat = ztrdup(pat);
       
   158     p->prog = prog;
       
   159     p->vals = zarrdup(vals);
       
   160     p->eval = eprog;
       
   161     p->next = NULL;
       
   162 
       
   163     /* Calculate the weight. */
       
   164 
       
   165     for (weight = 0, tmp = 2, first = 1, str = pat; *str; str++) {
       
   166 	if (first && *str == '*' && (!str[1] || str[1] == ':')) {
       
   167 	    /* Only `*' in this component. */
       
   168 	    tmp = 0;
       
   169 	    continue;
       
   170 	}
       
   171 	first = 0;
       
   172 
       
   173 	if (*str == '(' || *str == '|' || *str == '*' || *str == '[' ||
       
   174 	    *str == '<' ||  *str == '?' || *str == '#' || *str == '^')
       
   175 	    /* Is pattern. */
       
   176 	    tmp = 1;
       
   177 
       
   178 	if (*str == ':') {
       
   179 	    /* Yet another component. */
       
   180 
       
   181 	    first = 1;
       
   182 	    weight += tmp;
       
   183 	    tmp = 2;
       
   184 	}
       
   185     }
       
   186     p->weight = (weight += tmp);
       
   187 
       
   188     for (qq = NULL, q = s->pats; q && q->weight >= weight;
       
   189 	 qq = q, q = q->next);
       
   190 
       
   191     p->next = q;
       
   192     if (qq)
       
   193 	qq->next = p;
       
   194     else
       
   195 	s->pats = p;
       
   196 
       
   197     return 0;
       
   198 }
       
   199 
       
   200 /* Add a new style. */
       
   201 
       
   202 static Style
       
   203 addstyle(char *name)
       
   204 {
       
   205     Style s;
       
   206 
       
   207     s = (Style) zalloc(sizeof(*s));
       
   208     s->next = NULL;
       
   209     s->pats = NULL;
       
   210     s->name = ztrdup(name);
       
   211 
       
   212     if (zlstyles)
       
   213 	zlstyles->next = s;
       
   214     else
       
   215 	zstyles = s;
       
   216     zlstyles = s;
       
   217 
       
   218     return s;
       
   219 }
       
   220 
       
   221 static char **
       
   222 evalstyle(Stypat p)
       
   223 {
       
   224     int ef = errflag;
       
   225     char **ret, *str;
       
   226 
       
   227     unsetparam("reply");
       
   228     execode(p->eval, 1, 0);
       
   229     if (errflag) {
       
   230 	errflag = ef;
       
   231 	return NULL;
       
   232     }
       
   233     errflag = ef;
       
   234 
       
   235     queue_signals();
       
   236     if ((ret = getaparam("reply")))
       
   237 	ret = arrdup(ret);
       
   238     else if ((str = getsparam("reply"))) {
       
   239 	ret = (char **) hcalloc(2 * sizeof(char *));
       
   240 	ret[0] = dupstring(str);
       
   241     }
       
   242     unqueue_signals();
       
   243     unsetparam("reply");
       
   244 
       
   245     return ret;
       
   246 }
       
   247 
       
   248 /* Look up a style for a context pattern. This does the matching. */
       
   249 
       
   250 static char **
       
   251 lookupstyle(char *ctxt, char *style)
       
   252 {
       
   253     Style s;
       
   254     Stypat p;
       
   255 
       
   256     for (s = zstyles; s; s = s->next)
       
   257 	if (!strcmp(s->name, style))
       
   258 	    for (p = s->pats; p; p = p->next)
       
   259 		if (pattry(p->prog, ctxt))
       
   260 		    return (p->eval ? evalstyle(p) : p->vals);
       
   261 
       
   262     return NULL;
       
   263 }
       
   264 
       
   265 static int
       
   266 bin_zstyle(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
       
   267 {
       
   268     int min, max, n, add = 0, list = 0, eval = 0;
       
   269 
       
   270     if (!args[0])
       
   271 	list = 1;
       
   272     else if (args[0][0] == '-') {
       
   273 	char oc;
       
   274 
       
   275 	if ((oc = args[0][1]) && oc != '-') {
       
   276 	    if (args[0][2]) {
       
   277 		zwarnnam(nam, "invalid argument: %s", args[0], 0);
       
   278 		return 1;
       
   279 	    }
       
   280 	    if (oc == 'L')
       
   281 		list = 2;
       
   282 	    else if (oc == 'e') {
       
   283 		eval = add = 1;
       
   284 		args++;
       
   285 	    }
       
   286 	} else {
       
   287 	    add = 1;
       
   288 	    args++;
       
   289 	}
       
   290     } else
       
   291 	add = 1;
       
   292 
       
   293     if (add) {
       
   294 	Style s;
       
   295 	Patprog prog;
       
   296 	char *pat;
       
   297 
       
   298 	if (arrlen(args) < 2) {
       
   299 	    zwarnnam(nam, "not enough arguments", NULL, 0);
       
   300 	    return 1;
       
   301 	}
       
   302 	pat = dupstring(args[0]);
       
   303 	tokenize(pat);
       
   304 
       
   305 	if (!(prog = patcompile(pat, PAT_ZDUP, NULL))) {
       
   306 	    zwarnnam(nam, "invalid pattern: %s", args[0], 0);
       
   307 	    return 1;
       
   308 	}
       
   309 	if (!(s = getstyle(args[1])))
       
   310 	    s = addstyle(args[1]);
       
   311 	return setstypat(s, args[0], prog, args + 2, eval);
       
   312     }
       
   313     if (list) {
       
   314 	Style s;
       
   315 	Stypat p;
       
   316 	char **v;
       
   317 
       
   318 	for (s = zstyles; s; s = s->next) {
       
   319 	    if (list == 1) {
       
   320 		quotedzputs(s->name, stdout);
       
   321 		putchar('\n');
       
   322 	    }
       
   323 	    for (p = s->pats; p; p = p->next) {
       
   324 		if (list == 1)
       
   325 		    printf("%s  %s", (p->eval ? "(eval)" : "      "), p->pat);
       
   326 		else {
       
   327 		    printf("zstyle %s", (p->eval ? "-e " : ""));
       
   328 		    quotedzputs(p->pat, stdout);
       
   329 		    printf(" %s", s->name);
       
   330 		}
       
   331 		for (v = p->vals; *v; v++) {
       
   332 		    putchar(' ');
       
   333 		    quotedzputs(*v, stdout);
       
   334 		}
       
   335 		putchar('\n');
       
   336 	    }
       
   337 	}
       
   338 	return 0;
       
   339     }
       
   340     switch (args[0][1]) {
       
   341     case 'd': min = 0; max = -1; break;
       
   342     case 's': min = 3; max =  4; break;
       
   343     case 'b': min = 3; max =  3; break;
       
   344     case 'a': min = 3; max =  3; break;
       
   345     case 't': min = 2; max = -1; break;
       
   346     case 'T': min = 2; max = -1; break;
       
   347     case 'm': min = 3; max =  3; break;
       
   348     case 'g': min = 1; max =  3; break;
       
   349     default:
       
   350 	zwarnnam(nam, "invalid option: %s", args[0], 0);
       
   351 	return 1;
       
   352     }
       
   353     n = arrlen(args) - 1;
       
   354     if (n < min) {
       
   355 	zwarnnam(nam, "not enough arguments", NULL, 0);
       
   356 	return 1;
       
   357     } else if (max >= 0 && n > max) {
       
   358 	zwarnnam(nam, "too many arguments", NULL, 0);
       
   359 	return 1;
       
   360     }
       
   361     switch (args[0][1]) {
       
   362     case 'd':
       
   363 	{
       
   364 	    Style s;
       
   365 
       
   366 	    if (args[1]) {
       
   367 		if (args[2]) {
       
   368 		    char *pat = args[1];
       
   369 
       
   370 		    for (args += 2; *args; args++) {
       
   371 			if ((s = getstyle(*args))) {
       
   372 			    Stypat p, q;
       
   373 
       
   374 			    for (q = NULL, p = s->pats; p;
       
   375 				 q = p, p = p->next) {
       
   376 				if (!strcmp(p->pat, pat)) {
       
   377 				    if (q)
       
   378 					q->next = p->next;
       
   379 				    else
       
   380 					s->pats = p->next;
       
   381 				    freestypat(p);
       
   382 				    break;
       
   383 				}
       
   384 			    }
       
   385 			}
       
   386 		    }
       
   387 		} else {
       
   388 		    Stypat p, q;
       
   389 
       
   390 		    for (s = zstyles; s; s = s->next) {
       
   391 			for (q = NULL, p = s->pats; p; q = p, p = p->next) {
       
   392 			    if (!strcmp(p->pat, args[1])) {
       
   393 				if (q)
       
   394 				    q->next = p->next;
       
   395 				else
       
   396 				    s->pats = p->next;
       
   397 				freestypat(p);
       
   398 				break;
       
   399 			    }
       
   400 			}
       
   401 		    }
       
   402 		}
       
   403 	    } else
       
   404 		freeallstyles();
       
   405 	}
       
   406 	break;
       
   407     case 's':
       
   408 	{
       
   409 	    char **vals, *ret;
       
   410 	    int val;
       
   411 
       
   412 	    if ((vals = lookupstyle(args[1], args[2])) && vals[0]) {
       
   413 		ret = sepjoin(vals, (args[4] ? args[4] : " "), 0);
       
   414 		val = 0;
       
   415 	    } else {
       
   416 		ret = ztrdup("");
       
   417 		val = 1;
       
   418 	    }
       
   419 	    setsparam(args[3], ret);
       
   420 
       
   421 	    return val;
       
   422 	}
       
   423 	break;
       
   424     case 'b':
       
   425 	{
       
   426 	    char **vals, *ret;
       
   427 	    int val;
       
   428 
       
   429 	    if ((vals = lookupstyle(args[1], args[2])) &&
       
   430 		vals[0] && !vals[1] &&
       
   431 		(!strcmp(vals[0], "yes") ||
       
   432 		 !strcmp(vals[0], "true") ||
       
   433 		 !strcmp(vals[0], "on") ||
       
   434 		 !strcmp(vals[0], "1"))) {
       
   435 		ret = "yes";
       
   436 		val = 0;
       
   437 	    } else {
       
   438 		ret = "no";
       
   439 		val = 1;
       
   440 	    }
       
   441 	    setsparam(args[3], ztrdup(ret));
       
   442 
       
   443 	    return val;
       
   444 	}
       
   445 	break;
       
   446     case 'a':
       
   447 	{
       
   448 	    char **vals, **ret;
       
   449 	    int val;
       
   450 
       
   451 	    if ((vals = lookupstyle(args[1], args[2]))) {
       
   452 		ret = zarrdup(vals);
       
   453 		val = 0;
       
   454 	    } else {
       
   455 		char *dummy = NULL;
       
   456 
       
   457 		ret = zarrdup(&dummy);
       
   458 		val = 1;
       
   459 	    }
       
   460 	    setaparam(args[3], ret);
       
   461 
       
   462 	    return val;
       
   463 	}
       
   464 	break;
       
   465     case 't':
       
   466     case 'T':
       
   467 	{
       
   468 	    char **vals;
       
   469 
       
   470 	    if ((vals = lookupstyle(args[1], args[2])) && vals[0]) {
       
   471 		if (args[3]) {
       
   472 		    char **ap = args + 3, **p;
       
   473 
       
   474 		    while (*ap) {
       
   475 			p = vals;
       
   476 			while (*p)
       
   477 			    if (!strcmp(*ap, *p++))
       
   478 				return 0;
       
   479 			ap++;
       
   480 		    }
       
   481 		    return 1;
       
   482 		} else
       
   483 		    return !(!strcmp(vals[0], "true") ||
       
   484 			     !strcmp(vals[0], "yes") ||
       
   485 			     !strcmp(vals[0], "on") ||
       
   486 			     !strcmp(vals[0], "1"));
       
   487 	    }
       
   488 	    return (args[0][1] == 't' ? (vals ? 1 : 2) : 0);
       
   489 	}
       
   490 	break;
       
   491     case 'm':
       
   492 	{
       
   493 	    char **vals;
       
   494 	    Patprog prog;
       
   495 
       
   496 	    tokenize(args[3]);
       
   497 
       
   498 	    if ((vals = lookupstyle(args[1], args[2])) &&
       
   499 		(prog = patcompile(args[3], PAT_STATIC, NULL))) {
       
   500 		while (*vals)
       
   501 		    if (pattry(prog, *vals++))
       
   502 			return 0;
       
   503 	    }
       
   504 	    return 1;
       
   505 	}
       
   506 	break;
       
   507     case 'g':
       
   508 	{
       
   509 	    LinkList l = newlinklist();
       
   510 	    int ret = 1;
       
   511 	    Style s;
       
   512 	    Stypat p;
       
   513 
       
   514 	    if (args[2]) {
       
   515 		if (args[3]) {
       
   516 		    if ((s = getstyle(args[3]))) {
       
   517 			for (p = s->pats; p; p = p->next) {
       
   518 			    if (!strcmp(args[2], p->pat)) {
       
   519 				char **v = p->vals;
       
   520 
       
   521 				while (*v)
       
   522 				    addlinknode(l, *v++);
       
   523 
       
   524 				ret = 0;
       
   525 				break;
       
   526 			    }
       
   527 			}
       
   528 		    }
       
   529 		} else {
       
   530 		    for (s = zstyles; s; s = s->next)
       
   531 			for (p = s->pats; p; p = p->next)
       
   532 			    if (!strcmp(args[2], p->pat)) {
       
   533 				addlinknode(l, s->name);
       
   534 				break;
       
   535 			    }
       
   536 		    ret = 0;
       
   537 		}
       
   538 	    } else {
       
   539 		LinkNode n;
       
   540 
       
   541 		for (s = zstyles; s; s = s->next)
       
   542 		    for (p = s->pats; p; p = p->next) {
       
   543 			for (n = firstnode(l); n; incnode(n))
       
   544 			    if (!strcmp(p->pat, (char *) getdata(n)))
       
   545 				break;
       
   546 			if (!n)
       
   547 			    addlinknode(l, p->pat);
       
   548 		    }
       
   549 		ret = 0;
       
   550 	    }
       
   551 	    set_list_array(args[1], l);
       
   552 
       
   553 	    return ret;
       
   554 	}
       
   555     }
       
   556     return 0;
       
   557 }
       
   558 
       
   559 /* Format stuff. */
       
   560 
       
   561 /*
       
   562  * One chunk of text, to allow recursive handling of ternary
       
   563  * expressions in zformat -f output.
       
   564  *   instr	The input string.
       
   565  *   specs	The format specifiers, specs[c] is the string from c:string
       
   566  *   outp	*outp is the start of the output string
       
   567  *   ousedp	(*outp)[*ousedp] is where to write next
       
   568  *   olenp	*olenp is the size allocated for *outp
       
   569  *   endchar    Terminator character in addition to `\0' (may be '\0')
       
   570  *   skip	If 1, don't output, just parse.
       
   571  */
       
   572 static char *zformat_substring(char* instr, char **specs, char **outp,
       
   573 			       int *ousedp, int *olenp, int endchar, int skip)
       
   574 {
       
   575     char *s;
       
   576 
       
   577     for (s = instr; *s && *s != endchar; s++) {
       
   578 	if (*s == '%') {
       
   579 	    int right, min = -1, max = -1, outl, testit;
       
   580 	    char *spec, *start = s;
       
   581 
       
   582 	    if ((right = (*++s == '-')))
       
   583 		s++;
       
   584 
       
   585 	    if (*s >= '0' && *s <= '9') {
       
   586 		for (min = 0; *s >= '0' && *s <= '9'; s++)
       
   587 		    min = (min * 10) + (int) STOUC(*s) - '0';
       
   588 	    }
       
   589 
       
   590 	    /* Ternary expressions */
       
   591 	    testit = (STOUC(*s) == '(');
       
   592 	    if (testit && s[1] == '-')
       
   593 	    {
       
   594 		/* Allow %(-1... etc. */
       
   595 		right = 1;
       
   596 		s++;
       
   597 	    }
       
   598 	    if ((*s == '.' || testit) && s[1] >= '0' && s[1] <= '9') {
       
   599 		for (max = 0, s++; *s >= '0' && *s <= '9'; s++)
       
   600 		    max = (max * 10) + (int) STOUC(*s) - '0';
       
   601 	    }
       
   602 	    else if (testit)
       
   603 		s++;
       
   604 
       
   605 	    if (testit && STOUC(*s)) {
       
   606 		int actval, testval, endcharl;
       
   607 
       
   608 		/*
       
   609 		 * One one number is useful for ternary expressions.
       
   610 		 * Remember to put the sign back.
       
   611 		 */
       
   612 		testval = (min >= 0) ? min : (max >= 0) ? max : 0;
       
   613 		if (right)
       
   614 		    testval *= -1;
       
   615 
       
   616 		if (specs[STOUC(*s)])
       
   617 		    actval = (int)mathevali(specs[STOUC(*s)]);
       
   618 		else
       
   619 		    actval = 0;
       
   620 		/* zero means values are equal, i.e. true */
       
   621 		actval -= testval;
       
   622 
       
   623 		/* careful about premature end of string */
       
   624 		if (!(endcharl = *++s))
       
   625 		    return NULL;
       
   626 
       
   627 		/*
       
   628 		 * Either skip true text and output false text, or
       
   629 		 * vice versa... unless we are already skipping.
       
   630 		 */
       
   631 		if (!(s = zformat_substring(s+1, specs, outp, ousedp,
       
   632 					    olenp, endcharl, skip || actval)))
       
   633 		    return NULL;
       
   634 		if (!(s = zformat_substring(s+1, specs, outp, ousedp,
       
   635 					    olenp, ')', skip || !actval)))
       
   636 		    return NULL;
       
   637 	    } else if (skip) {
       
   638 		continue;
       
   639 	    } else if ((spec = specs[STOUC(*s)])) {
       
   640 		int len;
       
   641 
       
   642 		if ((len = strlen(spec)) > max && max >= 0)
       
   643 		    len = max;
       
   644 		outl = (min >= 0 ? (min > len ? min : len) : len);
       
   645 
       
   646 		if (*ousedp + outl >= *olenp) {
       
   647 		    int nlen = *olenp + outl + 128;
       
   648 		    char *tmp = (char *) zhalloc(nlen);
       
   649 
       
   650 		    memcpy(tmp, *outp, *olenp);
       
   651 		    *olenp = nlen;
       
   652 		    *outp = tmp;
       
   653 		}
       
   654 		if (len >= outl) {
       
   655 		    memcpy(*outp + *ousedp, spec, outl);
       
   656 		    *ousedp += outl;
       
   657 		} else {
       
   658 		    int diff = outl - len;
       
   659 
       
   660 		    if (right) {
       
   661 			while (diff--)
       
   662 			    (*outp)[(*ousedp)++] = ' ';
       
   663 			memcpy(*outp + *ousedp, spec, len);
       
   664 			*ousedp += len;
       
   665 		    } else {
       
   666 			memcpy(*outp + *ousedp, spec, len);
       
   667 			*ousedp += len;
       
   668 			while (diff--)
       
   669 			    (*outp)[(*ousedp)++] = ' ';
       
   670 		    }
       
   671 		}
       
   672 	    } else {
       
   673 		int len = s - start + 1;
       
   674 
       
   675 		if (*ousedp + len >= *olenp) {
       
   676 		    int nlen = *olenp + len + 128;
       
   677 		    char *tmp = (char *) zhalloc(nlen);
       
   678 
       
   679 		    memcpy(tmp, *outp, *olenp);
       
   680 		    *olenp = nlen;
       
   681 		    *outp = tmp;
       
   682 		}
       
   683 		memcpy(*outp + *ousedp, start, len);
       
   684 		*ousedp += len;
       
   685 	    }
       
   686 	} else {
       
   687 	    if (skip)
       
   688 		continue;
       
   689 	    if (*ousedp + 1 >= *olenp) {
       
   690 		char *tmp = (char *) zhalloc((*olenp) << 1);
       
   691 
       
   692 		memcpy(tmp, *outp, *olenp);
       
   693 		*olenp <<= 1;
       
   694 		*outp = tmp;
       
   695 	    }
       
   696 	    (*outp)[(*ousedp)++] = *s;
       
   697 	}
       
   698     }
       
   699 
       
   700     return s;
       
   701 }
       
   702 
       
   703 static int
       
   704 bin_zformat(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
       
   705 {
       
   706     char opt;
       
   707 
       
   708     if (args[0][0] != '-' || !(opt = args[0][1]) || args[0][2]) {
       
   709 	zwarnnam(nam, "invalid argument: %s", args[0], 0);
       
   710 	return 1;
       
   711     }
       
   712     args++;
       
   713 
       
   714     switch (opt) {
       
   715     case 'f':
       
   716 	{
       
   717 	    char **ap, *specs[256], *out;
       
   718 	    int olen, oused = 0;
       
   719 
       
   720 	    memset(specs, 0, 256 * sizeof(char *));
       
   721 
       
   722 	    specs['%'] = "%";
       
   723 	    specs[')'] = ")";
       
   724 	    for (ap = args + 2; *ap; ap++) {
       
   725 		if (!ap[0][0] || ap[0][0] == '-' || ap[0][0] == '.' ||
       
   726 		    (ap[0][0] >= '0' && ap[0][0] <= '9') ||
       
   727 		    ap[0][1] != ':') {
       
   728 		    zwarnnam(nam, "invalid argument: %s", *ap, 0);
       
   729 		    return 1;
       
   730 		}
       
   731 		specs[STOUC(ap[0][0])] = ap[0] + 2;
       
   732 	    }
       
   733 	    out = (char *) zhalloc(olen = 128);
       
   734 
       
   735 	    zformat_substring(args[1], specs, &out, &oused, &olen, '\0', 0);
       
   736 	    out[oused] = '\0';
       
   737 
       
   738 	    setsparam(args[0], ztrdup(out));
       
   739 	    return 0;
       
   740 	}
       
   741 	break;
       
   742     case 'a':
       
   743 	{
       
   744 	    char **ap, *cp;
       
   745 	    int nbc = 0, colon = 0, pre = 0, suf = 0;
       
   746 
       
   747 	    for (ap = args + 2; *ap; ap++) {
       
   748 		for (nbc = 0, cp = *ap; *cp && *cp != ':'; cp++)
       
   749 		    if (*cp == '\\' && cp[1])
       
   750 			cp++, nbc++;
       
   751 		if (*cp == ':' && cp[1]) {
       
   752 		    int d;
       
   753 
       
   754 		    colon++;
       
   755 		    if ((d = cp - *ap - nbc) > pre)
       
   756 			pre = d;
       
   757 		    if ((d = strlen(cp + 1)) > suf)
       
   758 			suf = d;
       
   759 		}
       
   760 	    }
       
   761 	    {
       
   762 		int sl = strlen(args[1]);
       
   763 		VARARR(char, buf, pre + suf + sl + 1);
       
   764 		char **ret, **rp, *copy, *cpp, oldc;
       
   765 
       
   766 		ret = (char **) zalloc((arrlen(args + 2) + 1) *
       
   767 				       sizeof(char *));
       
   768 
       
   769 		memcpy(buf + pre, args[1], sl);
       
   770 		suf = pre + sl;
       
   771 
       
   772 		for (rp = ret, ap = args + 2; *ap; ap++) {
       
   773 		    copy = dupstring(*ap);
       
   774 		    for (cp = cpp = copy; *cp && *cp != ':'; cp++) {
       
   775 			if (*cp == '\\' && cp[1])
       
   776 			    cp++;
       
   777 			*cpp++ = *cp;
       
   778 		    }
       
   779 		    oldc = *cpp;
       
   780 		    *cpp = '\0';
       
   781 		    if (((cpp == cp && oldc == ':') || *cp == ':') && cp[1]) {
       
   782 			memset(buf, ' ', pre);
       
   783 			memcpy(buf, copy, (cpp - copy));
       
   784 			strcpy(buf + suf, cp + 1);
       
   785 			*rp++ = ztrdup(buf);
       
   786 		    } else
       
   787 			*rp++ = ztrdup(copy);
       
   788 		}
       
   789 		*rp = NULL;
       
   790 
       
   791 		setaparam(args[0], ret);
       
   792 		return 0;
       
   793 	    }
       
   794 	}
       
   795 	break;
       
   796     }
       
   797     zwarnnam(nam, "invalid option: -%c", 0, opt);
       
   798     return 1;
       
   799 }
       
   800 
       
   801 /* Zregexparse stuff. */
       
   802 
       
   803 typedef struct {
       
   804     char **match;
       
   805     char **mbegin;
       
   806     char **mend;
       
   807 } MatchData;
       
   808 
       
   809 static void
       
   810 savematch(MatchData *m)
       
   811 {
       
   812     char **a;
       
   813 
       
   814     queue_signals();
       
   815     a = getaparam("match");
       
   816     m->match = a ? zarrdup(a) : NULL;
       
   817     a = getaparam("mbegin");
       
   818     m->mbegin = a ? zarrdup(a) : NULL;
       
   819     a = getaparam("mend");
       
   820     m->mend = a ? zarrdup(a) : NULL;
       
   821     unqueue_signals();
       
   822 }
       
   823 
       
   824 static void
       
   825 restorematch(MatchData *m)
       
   826 {
       
   827     if (m->match)
       
   828 	setaparam("match", m->match);
       
   829     else
       
   830 	unsetparam("match");
       
   831     if (m->mbegin)
       
   832 	setaparam("mbegin", m->mbegin);
       
   833     else
       
   834 	unsetparam("mbegin");
       
   835     if (m->mend)
       
   836 	setaparam("mend", m->mend);
       
   837     else
       
   838 	unsetparam("mend");
       
   839 }
       
   840 
       
   841 static void
       
   842 freematch(MatchData *m)
       
   843 {
       
   844     if (m->match)
       
   845 	freearray(m->match);
       
   846     if (m->mbegin)
       
   847 	freearray(m->mbegin);
       
   848     if (m->mend)
       
   849 	freearray(m->mend);
       
   850 }
       
   851 
       
   852 typedef struct {
       
   853     int cutoff;
       
   854     char *pattern;
       
   855     Patprog patprog;
       
   856     char *guard;
       
   857     char *action;
       
   858     LinkList branches;
       
   859 } RParseState;
       
   860 
       
   861 typedef struct {
       
   862     RParseState *state;
       
   863     LinkList actions;
       
   864 } RParseBranch;
       
   865 
       
   866 typedef struct {
       
   867     LinkList nullacts;
       
   868     LinkList in;
       
   869     LinkList out;
       
   870 } RParseResult;
       
   871 
       
   872 static char **rparseargs;
       
   873 static LinkList rparsestates;
       
   874 
       
   875 static int rparsealt(RParseResult *result, jmp_buf *perr);
       
   876 
       
   877 static void
       
   878 connectstates(LinkList out, LinkList in)
       
   879 {
       
   880     LinkNode outnode, innode, ln;
       
   881 
       
   882     for (outnode = firstnode(out); outnode; outnode = nextnode(outnode)) {
       
   883 	RParseBranch *outbranch = getdata(outnode);
       
   884 
       
   885 	for (innode = firstnode(in); innode; innode = nextnode(innode)) {
       
   886 	    RParseBranch *inbranch = getdata(innode);
       
   887 	    RParseBranch *br = hcalloc(sizeof(*br));
       
   888 
       
   889 	    br->state = inbranch->state;
       
   890 	    br->actions = newlinklist();
       
   891 	    for (ln = firstnode(outbranch->actions); ln; ln = nextnode(ln))
       
   892 		addlinknode(br->actions, getdata(ln));
       
   893 	    for (ln = firstnode(inbranch->actions); ln; ln = nextnode(ln))
       
   894 		addlinknode(br->actions, getdata(ln));
       
   895 	    addlinknode(outbranch->state->branches, br);
       
   896 	}
       
   897     }
       
   898 }
       
   899 
       
   900 static int
       
   901 rparseelt(RParseResult *result, jmp_buf *perr)
       
   902 {
       
   903     int l;
       
   904     char *s = *rparseargs;
       
   905 
       
   906     if (!s)
       
   907         return 1;
       
   908 
       
   909     switch (s[0]) {
       
   910     case '/': {
       
   911 	RParseState *st;
       
   912 	RParseBranch *br;
       
   913 	char *pattern, *lookahead;
       
   914 	int patternlen, lookaheadlen = 0;
       
   915 
       
   916 	l = strlen(s);
       
   917 	if (!((2 <= l && s[l - 1] == '/') ||
       
   918 	      (3 <= l && s[l - 2] == '/' && (s[l - 1] == '+' ||
       
   919 					     s[l - 1] == '-'))))
       
   920 	    return 1;
       
   921 	st = hcalloc(sizeof(*st));
       
   922 	st->branches = newlinklist();
       
   923 	st->cutoff = s[l - 1];
       
   924 	if (s[l - 1] == '/') {
       
   925 	    pattern = s + 1;
       
   926 	    patternlen = l - 2;
       
   927 	} else {
       
   928 	    pattern = s + 1;
       
   929 	    patternlen = l - 3;
       
   930 	}
       
   931 	rparseargs++;
       
   932 	if ((s = *rparseargs) && s[0] == '%' &&
       
   933 	   2 <= (l = strlen(s)) && s[l - 1] == '%') {
       
   934 	    rparseargs++;
       
   935 	    lookahead = s + 1;
       
   936 	    lookaheadlen = l - 2;
       
   937 	} else {
       
   938 	    lookahead = NULL;
       
   939 	}
       
   940 	if (patternlen == 2 && !strncmp(pattern, "[]", 2))
       
   941 	    st->pattern = NULL;
       
   942 	else {
       
   943 	    char *cp;
       
   944 	    int l = patternlen + 12; /* (#b)((#B)...)...* */
       
   945 	    if(lookahead)
       
   946 	        l += lookaheadlen + 4; /* (#B)... */
       
   947 	    cp = st->pattern = hcalloc(l);
       
   948 	    strcpy(cp, "(#b)((#B)");
       
   949 	    cp += 9;
       
   950 	    strcpy(cp, pattern);
       
   951 	    cp += patternlen;
       
   952 	    strcpy(cp, ")");
       
   953 	    cp += 1;
       
   954 	    if (lookahead) {
       
   955 		strcpy(cp, "(#B)");
       
   956 		cp += 4;
       
   957 		strcpy(cp, lookahead);
       
   958 		cp += lookaheadlen;
       
   959 	    }
       
   960 	    strcpy(cp, "*");
       
   961 	}
       
   962 	st->patprog = NULL;
       
   963 	if ((s = *rparseargs) && *s == '-') {
       
   964 	    rparseargs++;
       
   965 	    l = strlen(s);
       
   966 	    st->guard = hcalloc(l);
       
   967 	    memcpy(st->guard, s + 1, l - 1);
       
   968 	    st->guard[l - 1] = '\0';
       
   969 	} else
       
   970 	    st->guard = NULL;
       
   971 	if ((s = *rparseargs) && *s == ':') {
       
   972 	    rparseargs++;
       
   973 	    l = strlen(s);
       
   974 	    st->action = hcalloc(l);
       
   975 	    memcpy(st->action, s + 1, l - 1);
       
   976 	    st->action[l - 1] = '\0';
       
   977 	} else
       
   978 	    st->action = NULL;
       
   979 	result->nullacts = NULL;
       
   980 	result->in = newlinklist();
       
   981 	br = hcalloc(sizeof(*br));
       
   982 	br->state = st;
       
   983 	br->actions = newlinklist();
       
   984 	addlinknode(result->in, br);
       
   985 	result->out = newlinklist();
       
   986 	br = hcalloc(sizeof(*br));
       
   987 	br->state = st;
       
   988 	br->actions = newlinklist();
       
   989 	addlinknode(result->out, br);
       
   990 	break;
       
   991     }
       
   992     case '(':
       
   993 	if (s[1])
       
   994 	    return 1;
       
   995 	rparseargs++;
       
   996 	if (rparsealt(result, perr))
       
   997 	    longjmp(*perr, 2);
       
   998 	s = *rparseargs;
       
   999 	if (!s || s[0] != ')' || s[1] != '\0')
       
  1000 	    longjmp(*perr, 2);
       
  1001 	rparseargs++;
       
  1002         break;
       
  1003     default:
       
  1004         return 1;
       
  1005     }
       
  1006 
       
  1007     return 0;
       
  1008 }
       
  1009 
       
  1010 static int
       
  1011 rparseclo(RParseResult *result, jmp_buf *perr)
       
  1012 {
       
  1013     if (rparseelt(result, perr))
       
  1014 	return 1;
       
  1015 
       
  1016     if (*rparseargs && !strcmp(*rparseargs, "#")) {
       
  1017 	rparseargs++;
       
  1018 	while (*rparseargs && !strcmp(*rparseargs, "#"))
       
  1019 	    rparseargs++;
       
  1020 
       
  1021 	connectstates(result->out, result->in);
       
  1022 	result->nullacts = newlinklist();
       
  1023     }
       
  1024     return 0;
       
  1025 }
       
  1026 
       
  1027 static void
       
  1028 prependactions(LinkList acts, LinkList branches)
       
  1029 {
       
  1030     LinkNode aln, bln;
       
  1031 
       
  1032     for (bln = firstnode(branches); bln; bln = nextnode(bln)) {
       
  1033 	RParseBranch *br = getdata(bln);
       
  1034 
       
  1035 	for (aln = lastnode(acts); aln != (LinkNode)acts; aln = prevnode(aln))
       
  1036 	    pushnode(br->actions, getdata(aln));
       
  1037     }
       
  1038 }
       
  1039 
       
  1040 static void
       
  1041 appendactions(LinkList acts, LinkList branches)
       
  1042 {
       
  1043     LinkNode aln, bln;
       
  1044     for (bln = firstnode(branches); bln; bln = nextnode(bln)) {
       
  1045 	RParseBranch *br = getdata(bln);
       
  1046 
       
  1047 	for (aln = firstnode(acts); aln; aln = nextnode(aln))
       
  1048 	    addlinknode(br->actions, getdata(aln));
       
  1049     }
       
  1050 }
       
  1051 
       
  1052 static int
       
  1053 rparseseq(RParseResult *result, jmp_buf *perr)
       
  1054 {
       
  1055     int l;
       
  1056     char *s;
       
  1057     RParseResult sub;
       
  1058 
       
  1059     result->nullacts = newlinklist();
       
  1060     result->in = newlinklist();
       
  1061     result->out = newlinklist();
       
  1062 
       
  1063     while (1) {
       
  1064 	if ((s = *rparseargs) && s[0] == '{' && s[(l = strlen(s)) - 1] == '}') {
       
  1065 	    char *action = hcalloc(l - 1);
       
  1066 	    LinkNode ln;
       
  1067 
       
  1068 	    rparseargs++;
       
  1069 	    memcpy(action, s + 1, l - 2);
       
  1070 	    action[l - 2] = '\0';
       
  1071 	    if (result->nullacts)
       
  1072 		addlinknode(result->nullacts, action);
       
  1073 	    for (ln = firstnode(result->out); ln; ln = nextnode(ln)) {
       
  1074 		RParseBranch *br = getdata(ln);
       
  1075 		addlinknode(br->actions, action);
       
  1076 	    }
       
  1077 	}
       
  1078         else if (!rparseclo(&sub, perr)) {
       
  1079 	    connectstates(result->out, sub.in);
       
  1080 
       
  1081 	    if (result->nullacts) {
       
  1082 		prependactions(result->nullacts, sub.in);
       
  1083 		insertlinklist(sub.in, lastnode(result->in), result->in);
       
  1084 	    }
       
  1085 	    if (sub.nullacts) {
       
  1086 		appendactions(sub.nullacts, result->out);
       
  1087 		insertlinklist(sub.out, lastnode(result->out), result->out);
       
  1088 	    } else
       
  1089 		result->out = sub.out;
       
  1090 
       
  1091 	    if (result->nullacts && sub.nullacts)
       
  1092 		insertlinklist(sub.nullacts, lastnode(result->nullacts),
       
  1093 			       result->nullacts);
       
  1094 	    else
       
  1095 		result->nullacts = NULL;
       
  1096 	}
       
  1097 	else
       
  1098 	    break;
       
  1099     }
       
  1100     return 0;
       
  1101 }
       
  1102 
       
  1103 static int
       
  1104 rparsealt(RParseResult *result, jmp_buf *perr)
       
  1105 {
       
  1106     RParseResult sub;
       
  1107 
       
  1108     if (rparseseq(result, perr))
       
  1109 	return 1;
       
  1110 
       
  1111     while (*rparseargs && !strcmp(*rparseargs, "|")) {
       
  1112 	rparseargs++;
       
  1113 	if (rparseseq(&sub, perr))
       
  1114 	    longjmp(*perr, 2);
       
  1115 	if (!result->nullacts && sub.nullacts)
       
  1116 	    result->nullacts = sub.nullacts;
       
  1117 
       
  1118 	insertlinklist(sub.in, lastnode(result->in), result->in);
       
  1119 	insertlinklist(sub.out, lastnode(result->out), result->out);
       
  1120     }
       
  1121     return 0;
       
  1122 }
       
  1123 
       
  1124 static int
       
  1125 rmatch(RParseResult *sm, char *subj, char *var1, char *var2, int comp)
       
  1126 {
       
  1127     LinkNode ln, lnn;
       
  1128     LinkList nexts;
       
  1129     LinkList nextslist;
       
  1130     RParseBranch *br;
       
  1131     RParseState *st = NULL;
       
  1132     int point1 = 0, point2 = 0;
       
  1133 
       
  1134     setiparam(var1, point1);
       
  1135     setiparam(var2, point2);
       
  1136 
       
  1137     if (!comp && !*subj && sm->nullacts) {
       
  1138 	for (ln = firstnode(sm->nullacts); ln; ln = nextnode(ln)) {
       
  1139 	    char *action = getdata(ln);
       
  1140 
       
  1141 	    if (action)
       
  1142 		execstring(action, 1, 0);
       
  1143 	}
       
  1144 	return 0;
       
  1145     }
       
  1146 
       
  1147     nextslist = newlinklist();
       
  1148     nexts = sm->in;
       
  1149     addlinknode(nextslist, nexts);
       
  1150     do {
       
  1151 	MatchData match1, match2;
       
  1152 
       
  1153 	savematch(&match1);
       
  1154 
       
  1155 	for (ln = firstnode(nexts); ln; ln = nextnode(ln)) {
       
  1156 	    int i;
       
  1157 	    RParseState *next;
       
  1158 
       
  1159 	    br = getdata(ln);
       
  1160 	    next = br->state;
       
  1161 	    if (next->pattern && !next->patprog) {
       
  1162 	        tokenize(next->pattern);
       
  1163 		if (!(next->patprog = patcompile(next->pattern, 0, NULL)))
       
  1164 		    return 3;
       
  1165 	    }
       
  1166 	    if (next->pattern && pattry(next->patprog, subj) &&
       
  1167 		(!next->guard || (execstring(next->guard, 1, 0), !lastval))) {
       
  1168 		LinkNode aln;
       
  1169 		char **mend;
       
  1170 		int len;
       
  1171 
       
  1172 		queue_signals();
       
  1173 		mend = getaparam("mend");
       
  1174 		len = atoi(mend[0]);
       
  1175 		unqueue_signals();
       
  1176 
       
  1177 		for (i = len; i; i--)
       
  1178 		  if (*subj++ == Meta)
       
  1179 		    subj++;
       
  1180 
       
  1181 		savematch(&match2);
       
  1182 		restorematch(&match1);
       
  1183 
       
  1184 		for (aln = firstnode(br->actions); aln; aln = nextnode(aln)) {
       
  1185 		    char *action = getdata(aln);
       
  1186 
       
  1187 		    if (action)
       
  1188 			execstring(action, 1, 0);
       
  1189 		}
       
  1190 		restorematch(&match2);
       
  1191 
       
  1192 		point2 += len;
       
  1193 		setiparam(var2, point2);
       
  1194 		st = br->state;
       
  1195 		nexts = st->branches;
       
  1196 		if (next->cutoff == '-' || (next->cutoff == '/' && len)) {
       
  1197 		    nextslist = newlinklist();
       
  1198 		    point1 = point2;
       
  1199 		    setiparam(var1, point1);
       
  1200 		}
       
  1201 		addlinknode(nextslist, nexts);
       
  1202 		break;
       
  1203 	    }
       
  1204 	}
       
  1205 	if (!ln)
       
  1206 	    freematch(&match1);
       
  1207     } while (ln);
       
  1208 
       
  1209     if (!comp && !*subj)
       
  1210 	for (ln = firstnode(sm->out); ln; ln = nextnode(ln)) {
       
  1211 	    br = getdata(ln);
       
  1212 	    if (br->state == st) {
       
  1213 		for (ln = firstnode(br->actions); ln; ln = nextnode(ln)) {
       
  1214 		    char *action = getdata(ln);
       
  1215 
       
  1216 		    if (action)
       
  1217 			execstring(action, 1, 0);
       
  1218 		}
       
  1219 		return 0;
       
  1220 	    }
       
  1221 	}
       
  1222 
       
  1223     for (lnn = firstnode(nextslist); lnn; lnn = nextnode(lnn)) {
       
  1224 	nexts = getdata(lnn);
       
  1225 	for (ln = firstnode(nexts); ln; ln = nextnode(ln)) {
       
  1226 	    br = getdata(ln);
       
  1227 	    if (br->state->action)
       
  1228 		execstring(br->state->action, 1, 0);
       
  1229 	}
       
  1230     }
       
  1231     return empty(nexts) ? 2 : 1;
       
  1232 }
       
  1233 
       
  1234 /*
       
  1235   usage: zregexparse [-c] var1 var2 string regex...
       
  1236   status:
       
  1237     0: matched
       
  1238     1: unmatched (all next state candidates are failed)
       
  1239     2: unmatched (there is no next state candidates)
       
  1240     3: regex parse error
       
  1241 */
       
  1242 
       
  1243 static int
       
  1244 bin_zregexparse(char *nam, char **args, Options ops, UNUSED(int func))
       
  1245 {
       
  1246     int oldextendedglob = opts[EXTENDEDGLOB];
       
  1247     char *var1 = args[0];
       
  1248     char *var2 = args[1];
       
  1249     char *subj = args[2];
       
  1250     int ret;
       
  1251     jmp_buf rparseerr;
       
  1252     RParseResult result;
       
  1253 
       
  1254     opts[EXTENDEDGLOB] = 1;
       
  1255 
       
  1256     rparseargs = args + 3;
       
  1257 
       
  1258     pushheap();
       
  1259     rparsestates = newlinklist();
       
  1260     if (setjmp(rparseerr) || rparsealt(&result, &rparseerr) || *rparseargs) {
       
  1261 	if (*rparseargs)
       
  1262 	    zwarnnam(nam, "invalid regex : %s", *rparseargs, 0);
       
  1263 	else
       
  1264 	    zwarnnam(nam, "not enough regex arguments", NULL, 0);
       
  1265 	ret = 3;
       
  1266     } else
       
  1267 	ret = 0;
       
  1268 
       
  1269     if (!ret)
       
  1270 	ret = rmatch(&result, subj, var1, var2, OPT_ISSET(ops,'c'));
       
  1271     popheap();
       
  1272 
       
  1273     opts[EXTENDEDGLOB] = oldextendedglob;
       
  1274     return ret;
       
  1275 }
       
  1276 
       
  1277 typedef struct zoptdesc *Zoptdesc;
       
  1278 typedef struct zoptarr *Zoptarr;
       
  1279 typedef struct zoptval *Zoptval;
       
  1280 
       
  1281 struct zoptdesc {
       
  1282     Zoptdesc next;
       
  1283     char *name;
       
  1284     int flags;
       
  1285     Zoptarr arr;
       
  1286     Zoptval vals, last;
       
  1287 };
       
  1288 
       
  1289 #define ZOF_ARG  1
       
  1290 #define ZOF_OPT  2
       
  1291 #define ZOF_MULT 4
       
  1292 #define ZOF_SAME 8
       
  1293 
       
  1294 struct zoptarr {
       
  1295     Zoptarr next;
       
  1296     char *name;
       
  1297     Zoptval vals, last;
       
  1298     int num;
       
  1299 };
       
  1300 
       
  1301 struct zoptval {
       
  1302     Zoptval next, onext;
       
  1303     char *name;
       
  1304     char *arg;
       
  1305     char *str;
       
  1306 };
       
  1307 
       
  1308 static Zoptdesc opt_descs;
       
  1309 static Zoptarr opt_arrs;
       
  1310 
       
  1311 static Zoptdesc
       
  1312 get_opt_desc(char *name)
       
  1313 {
       
  1314     Zoptdesc p;
       
  1315 
       
  1316     for (p = opt_descs; p; p = p->next)
       
  1317 	if (!strcmp(name, p->name))
       
  1318 	    return p;
       
  1319 
       
  1320     return NULL;
       
  1321 }
       
  1322 
       
  1323 static Zoptdesc
       
  1324 lookup_opt(char *str)
       
  1325 {
       
  1326     Zoptdesc p;
       
  1327 
       
  1328     for (p = opt_descs; p; p = p->next) {
       
  1329 	if ((p->flags & ZOF_ARG) ? strpfx(p->name, str) : !strcmp(p->name, str))
       
  1330 	    return p;
       
  1331     }
       
  1332     return NULL;
       
  1333 }
       
  1334 
       
  1335 static Zoptarr
       
  1336 get_opt_arr(char *name)
       
  1337 {
       
  1338     Zoptarr p;
       
  1339 
       
  1340     for (p = opt_arrs; p; p = p->next)
       
  1341 	if (!strcmp(name, p->name))
       
  1342 	    return p;
       
  1343 
       
  1344     return NULL;
       
  1345 }
       
  1346 
       
  1347 static void
       
  1348 add_opt_val(Zoptdesc d, char *arg)
       
  1349 {
       
  1350     Zoptval v = NULL;
       
  1351     char *n = dyncat("-", d->name);
       
  1352     int new = 0;
       
  1353 
       
  1354     if (!(d->flags & ZOF_MULT))
       
  1355 	v = d->vals;
       
  1356     if (!v) {
       
  1357 	v = (Zoptval) zhalloc(sizeof(*v));
       
  1358 	v->next = v->onext = NULL;
       
  1359 	v->name = n;
       
  1360 	new = 1;
       
  1361     }
       
  1362     v->arg = arg;
       
  1363     if ((d->flags & ZOF_ARG) && !(d->flags & (ZOF_OPT | ZOF_SAME))) {
       
  1364 	v->str = NULL;
       
  1365 	if (d->arr)
       
  1366 	    d->arr->num += (arg ? 2 : 1);
       
  1367     } else if (arg) {
       
  1368 	char *s = (char *) zhalloc(strlen(d->name) + strlen(arg) + 2);
       
  1369 
       
  1370 	*s = '-';
       
  1371 	strcpy(s + 1, d->name);
       
  1372 	strcat(s, arg);
       
  1373 	v->str = s;
       
  1374 	if (d->arr)
       
  1375 	    d->arr->num += 1;
       
  1376     } else {
       
  1377 	v->str = NULL;
       
  1378 	if (d->arr)
       
  1379 	    d->arr->num += 1;
       
  1380     }
       
  1381     if (new) {
       
  1382 	if (d->arr) {
       
  1383 	    if (d->arr->last)
       
  1384 		d->arr->last->next = v;
       
  1385 	    else
       
  1386 		d->arr->vals = v;
       
  1387 	    d->arr->last = v;
       
  1388 	}
       
  1389 	if (d->last)
       
  1390 	    d->last->onext = v;
       
  1391 	else
       
  1392 	    d->vals = v;
       
  1393 	d->last = v;
       
  1394     }
       
  1395 }
       
  1396 
       
  1397 static int
       
  1398 bin_zparseopts(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
       
  1399 {
       
  1400     char *o, *p, *n, **pp, **aval, **ap, *assoc = NULL, **cp, **np;
       
  1401     int del = 0, f, extract = 0, keep = 0;
       
  1402     Zoptdesc sopts[256], d;
       
  1403     Zoptarr a, defarr = NULL;
       
  1404     Zoptval v;
       
  1405 
       
  1406     opt_descs = NULL;
       
  1407     opt_arrs = NULL;
       
  1408     memset(sopts, 0, 256 * sizeof(Zoptdesc));
       
  1409 
       
  1410     while ((o = *args++)) {
       
  1411 	if (*o == '-') {
       
  1412 	    switch (o[1]) {
       
  1413 	    case '\0':
       
  1414 		o = NULL;
       
  1415 		break;
       
  1416 	    case '-':
       
  1417 		if (o[2])
       
  1418 		    args--;
       
  1419 		o = NULL;
       
  1420 		break;
       
  1421 	    case 'D':
       
  1422 		if (o[2]) {
       
  1423 		    args--;
       
  1424 		    o = NULL;
       
  1425 		    break;
       
  1426 		}
       
  1427 		del = 1;
       
  1428 		break;
       
  1429 	    case 'E':
       
  1430 		if (o[2]) {
       
  1431 		    args--;
       
  1432 		    o = NULL;
       
  1433 		    break;
       
  1434 		}
       
  1435 		extract = 1;
       
  1436 		break;
       
  1437 	    case 'K':
       
  1438 		if (o[2]) {
       
  1439 		    args--;
       
  1440 		    o = NULL;
       
  1441 		    break;
       
  1442 		}
       
  1443 		keep = 1;
       
  1444 		break;
       
  1445 	    case 'a':
       
  1446 		if (defarr) {
       
  1447 		    zwarnnam(nam, "default array given more than once", NULL, 0);
       
  1448 		    return 1;
       
  1449 		}
       
  1450 		if (o[2])
       
  1451 		    n = o + 2;
       
  1452 		else if (*args)
       
  1453 		    n = *args++;
       
  1454 		else {
       
  1455 		    zwarnnam(nam, "missing array name", NULL, 0);
       
  1456 		    return 1;
       
  1457 		}
       
  1458 		defarr = (Zoptarr) zhalloc(sizeof(*defarr));
       
  1459 		defarr->name = n;
       
  1460 		defarr->num = 0;
       
  1461 		defarr->vals = defarr->last = NULL;
       
  1462 		defarr->next = NULL;
       
  1463 		opt_arrs = defarr;
       
  1464 		break;
       
  1465 	    case 'A':
       
  1466 		if (o[2]) 
       
  1467 		    assoc = o + 2;
       
  1468 		else if (*args)
       
  1469 		    assoc = *args++;
       
  1470 		else {
       
  1471 		    zwarnnam(nam, "missing array name", NULL, 0);
       
  1472 		    return 1;
       
  1473 		}
       
  1474 		break;
       
  1475 	    }
       
  1476 	    if (!o) {
       
  1477 		o = "";
       
  1478 		break;
       
  1479 	    }
       
  1480 	} else {
       
  1481 	    args--;
       
  1482 	    break;
       
  1483 	}
       
  1484     }
       
  1485     if (!o) {
       
  1486 	zwarnnam(nam, "missing option descriptions", NULL, 0);
       
  1487 	return 1;
       
  1488     }
       
  1489     while ((o = dupstring(*args++))) {
       
  1490 	if (!*o) {
       
  1491 	    zwarnnam(nam, "invalid option description: %s", o, 0);
       
  1492 	    return 1;
       
  1493 	}
       
  1494 	f = 0;
       
  1495 	for (p = o; *p; p++) {
       
  1496 	    if (*p == '\\' && p[1])
       
  1497 		p++;
       
  1498 	    else if (*p == '+') {
       
  1499 		f |= ZOF_MULT;
       
  1500 		*p = '\0';
       
  1501 		p++;
       
  1502 		break;
       
  1503 	    } else if (*p == ':' || *p == '=')
       
  1504 		break;
       
  1505 	}
       
  1506 	if (*p == ':') {
       
  1507 	    f |= ZOF_ARG;
       
  1508 	    *p = '\0';
       
  1509 	    if (*++p == ':') {
       
  1510 		p++;
       
  1511 		f |= ZOF_OPT;
       
  1512 	    }
       
  1513 	    if (*p == '-') {
       
  1514 		p++;
       
  1515 		f |= ZOF_SAME;
       
  1516 	    }
       
  1517 	}
       
  1518 	a = NULL;
       
  1519 	if (*p == '=') {
       
  1520 	    *p++ = '\0';
       
  1521 	    if (!(a = get_opt_arr(p))) {
       
  1522 		a = (Zoptarr) zhalloc(sizeof(*a));
       
  1523 		a->name = p;
       
  1524 		a->num = 0;
       
  1525 		a->vals = a->last = NULL;
       
  1526 		a->next = opt_arrs;
       
  1527 		opt_arrs = a;
       
  1528 	    }
       
  1529 	} else if (*p) {
       
  1530 	    zwarnnam(nam, "invalid option description: %s", args[-1], 0);
       
  1531 	    return 1;
       
  1532 	} else if (!(a = defarr) && !assoc) {
       
  1533 	    zwarnnam(nam, "no default array defined: %s", args[-1], 0);
       
  1534 	    return 1;
       
  1535 	}
       
  1536 	for (p = n = o; *p; p++) {
       
  1537 	    if (*p == '\\' && p[1])
       
  1538 		p++;
       
  1539 	    *n++ = *p;
       
  1540 	}
       
  1541 	if (get_opt_desc(o)) {
       
  1542 	    zwarnnam(nam, "option defined more than once: %s", o, 0);
       
  1543 	    return 1;
       
  1544 	}
       
  1545 	d = (Zoptdesc) zhalloc(sizeof(*d));
       
  1546 	d->name = o;
       
  1547 	d->flags = f;
       
  1548 	d->arr = a;
       
  1549 	d->next = opt_descs;
       
  1550 	d->vals = d->last = NULL;
       
  1551 	opt_descs = d;
       
  1552 	if (!o[1])
       
  1553 	    sopts[STOUC(*o)] = d;
       
  1554     }
       
  1555     np = cp = pp = ((extract && del) ? arrdup(pparams) : pparams);
       
  1556     for (; (o = *pp); pp++) {
       
  1557 	if (*o != '-') {
       
  1558 	    if (extract) {
       
  1559 		if (del)
       
  1560 		    *cp++ = o;
       
  1561 		continue;
       
  1562 	    } else
       
  1563 		break;
       
  1564 	}
       
  1565 	if (!o[1] || (o[1] == '-' && !o[2])) {
       
  1566 	    if (del && extract)
       
  1567 		*cp++ = o;
       
  1568 	    pp++;
       
  1569 	    break;
       
  1570 	}
       
  1571 	if (!(d = lookup_opt(o + 1))) {
       
  1572 	    while (*++o) {
       
  1573 		if (!(d = sopts[STOUC(*o)])) {
       
  1574 		    o = NULL;
       
  1575 		    break;
       
  1576 		}
       
  1577 		if (d->flags & ZOF_ARG) {
       
  1578 		    if (o[1]) {
       
  1579 			add_opt_val(d, o + 1);
       
  1580 			break;
       
  1581 		    } else if (!(d->flags & ZOF_OPT)) {
       
  1582 			if (!pp[1]) {
       
  1583 			    zwarnnam(nam, "missing argument for option: %s",
       
  1584 				    d->name, 0);
       
  1585 			    return 1;
       
  1586 			}
       
  1587 			add_opt_val(d, *++pp);
       
  1588 		    } else
       
  1589 			add_opt_val(d, NULL);
       
  1590 		} else
       
  1591 		    add_opt_val(d, NULL);
       
  1592 	    }
       
  1593 	    if (!o) {
       
  1594 		if (extract) {
       
  1595 		    if (del)
       
  1596 			*cp++ = *pp;
       
  1597 		    continue;
       
  1598 		} else
       
  1599 		    break;
       
  1600 	    }
       
  1601 	} else {
       
  1602 	    if (d->flags & ZOF_ARG) {
       
  1603 		char *e = o + strlen(d->name) + 1;
       
  1604 
       
  1605 		if (*e)
       
  1606 		    add_opt_val(d, e);
       
  1607 		else if (!(d->flags & ZOF_OPT)) {
       
  1608 		    if (!pp[1]) {
       
  1609 			zwarnnam(nam, "missing argument for option: %s",
       
  1610 				d->name, 0);
       
  1611 			return 1;
       
  1612 		    }
       
  1613 		    add_opt_val(d, *++pp);
       
  1614 		} else
       
  1615 		    add_opt_val(d, NULL);
       
  1616 	    } else
       
  1617 		add_opt_val(d, NULL);
       
  1618 	}
       
  1619     }
       
  1620     if (extract && del)
       
  1621 	while (*pp)
       
  1622 	    *cp++ = *pp++;
       
  1623 
       
  1624     for (a = opt_arrs; a; a = a->next) {
       
  1625 	if (!keep || a->num) {
       
  1626 	    aval = (char **) zalloc((a->num + 1) * sizeof(char *));
       
  1627 	    for (ap = aval, v = a->vals; v; ap++, v = v->next) {
       
  1628 		if (v->str)
       
  1629 		    *ap = ztrdup(v->str);
       
  1630 		else {
       
  1631 		    *ap = ztrdup(v->name);
       
  1632 		    if (v->arg)
       
  1633 			*++ap = ztrdup(v->arg);
       
  1634 		}
       
  1635 	    }
       
  1636 	    *ap = NULL;
       
  1637 	    setaparam(a->name, aval);
       
  1638 	}
       
  1639     }
       
  1640     if (assoc) {
       
  1641 	int num;
       
  1642 
       
  1643 	for (num = 0, d = opt_descs; d; d = d->next)
       
  1644 	    if (d->vals)
       
  1645 		num++;
       
  1646 
       
  1647 	if (!keep || num) {
       
  1648 	    aval = (char **) zalloc(((num * 2) + 1) * sizeof(char *));
       
  1649 	    for (ap = aval, d = opt_descs; d; d = d->next) {
       
  1650 		if (d->vals) {
       
  1651 		    *ap++ = n = (char *) zalloc(strlen(d->name) + 2);
       
  1652 		    *n = '-';
       
  1653 		    strcpy(n + 1, d->name);
       
  1654 
       
  1655 		    for (num = 1, v = d->vals; v; v = v->onext) {
       
  1656 			num += (v->arg ? strlen(v->arg) : 0);
       
  1657 			if (v->next)
       
  1658 			    num++;
       
  1659 		    }
       
  1660 		    *ap++ = n = (char *) zalloc(num);
       
  1661 		    for (v = d->vals; v; v = v->onext) {
       
  1662 			if (v->arg) {
       
  1663 			    strcpy(n, v->arg);
       
  1664 			    n += strlen(v->arg);
       
  1665 			}
       
  1666 			*n = ' ';
       
  1667 		    }
       
  1668 		    *n = '\0';
       
  1669 		}
       
  1670 	    }
       
  1671 	    *ap = NULL;
       
  1672 	    sethparam(assoc, aval);
       
  1673 	}
       
  1674     }
       
  1675     if (del) {
       
  1676 	if (extract) {
       
  1677 	    *cp = NULL;
       
  1678 	    freearray(pparams);
       
  1679 	    pparams = zarrdup(np);
       
  1680 	} else {
       
  1681 	    pp = zarrdup(pp);
       
  1682 	    freearray(pparams);
       
  1683 	    pparams = pp;
       
  1684 	}
       
  1685     }
       
  1686     return 0;
       
  1687 }
       
  1688 
       
  1689 static struct builtin bintab[] = {
       
  1690     BUILTIN("zstyle", 0, bin_zstyle, 0, -1, 0, NULL, NULL),
       
  1691     BUILTIN("zformat", 0, bin_zformat, 3, -1, 0, NULL, NULL),
       
  1692     BUILTIN("zregexparse", 0, bin_zregexparse, 3, -1, 0, "c", NULL),
       
  1693     BUILTIN("zparseopts", 0, bin_zparseopts, 1, -1, 0, NULL, NULL),
       
  1694 };
       
  1695 
       
  1696 
       
  1697 /**/
       
  1698 int
       
  1699 setup_(UNUSED(Module m))
       
  1700 {
       
  1701     zstyles = zlstyles = NULL;
       
  1702 
       
  1703     return 0;
       
  1704 }
       
  1705 
       
  1706 /**/
       
  1707 int
       
  1708 boot_(Module m)
       
  1709 {
       
  1710     return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
       
  1711 }
       
  1712 
       
  1713 /**/
       
  1714 int
       
  1715 cleanup_(Module m)
       
  1716 {
       
  1717     deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
       
  1718     return 0;
       
  1719 }
       
  1720 
       
  1721 /**/
       
  1722 int
       
  1723 finish_(UNUSED(Module m))
       
  1724 {
       
  1725     freeallstyles();
       
  1726 
       
  1727     return 0;
       
  1728 }
       
  1729 
       
  1730 #endif //__SYMBIAN32__