|         |      1 // subst.c - various substitutions | 
|         |      2 // | 
|         |      3 // © Portions Copyright (c) Symbian Software Ltd 2007. All rights reserved. | 
|         |      4 // | 
|         |      5 /* | 
|         |      6  * This file is part of zsh, the Z shell. | 
|         |      7  * | 
|         |      8  * Copyright (c) 1992-1997 Paul Falstad | 
|         |      9  * All rights reserved. | 
|         |     10  * | 
|         |     11  * Permission is hereby granted, without written agreement and without | 
|         |     12  * license or royalty fees, to use, copy, modify, and distribute this | 
|         |     13  * software and to distribute modified versions of this software for any | 
|         |     14  * purpose, provided that the above copyright notice and the following | 
|         |     15  * two paragraphs appear in all copies of this software. | 
|         |     16  * | 
|         |     17  * In no event shall Paul Falstad or the Zsh Development Group be liable | 
|         |     18  * to any party for direct, indirect, special, incidental, or consequential | 
|         |     19  * damages arising out of the use of this software and its documentation, | 
|         |     20  * even if Paul Falstad and the Zsh Development Group have been advised of | 
|         |     21  * the possibility of such damage. | 
|         |     22  * | 
|         |     23  * Paul Falstad and the Zsh Development Group specifically disclaim any | 
|         |     24  * warranties, including, but not limited to, the implied warranties of | 
|         |     25  * merchantability and fitness for a particular purpose.  The software | 
|         |     26  * provided hereunder is on an "as is" basis, and Paul Falstad and the | 
|         |     27  * Zsh Development Group have no obligation to provide maintenance, | 
|         |     28  * support, updates, enhancements, or modifications. | 
|         |     29  * | 
|         |     30  */ | 
|         |     31  | 
|         |     32 #include "zsh.mdh" | 
|         |     33 #include "subst.pro" | 
|         |     34  | 
|         |     35 #ifdef __SYMBIAN32__ | 
|         |     36 #ifdef __WINSCW__ | 
|         |     37 #pragma warn_possunwant off | 
|         |     38 #endif//__WINSCW__ | 
|         |     39 #endif//__SYMBIAN32__ | 
|         |     40  | 
|         |     41 /**/ | 
|         |     42 char nulstring[] = {Nularg, '\0'}; | 
|         |     43  | 
|         |     44 /* Do substitutions before fork. These are: | 
|         |     45  *  - Process substitution: <(...), >(...), =(...) | 
|         |     46  *  - Parameter substitution | 
|         |     47  *  - Command substitution | 
|         |     48  * Followed by | 
|         |     49  *  - Quote removal | 
|         |     50  *  - Brace expansion | 
|         |     51  *  - Tilde and equals substitution | 
|         |     52  * | 
|         |     53  * PF_* flags are defined in zsh.h | 
|         |     54  */ | 
|         |     55  | 
|         |     56 /**/ | 
|         |     57 mod_export void | 
|         |     58 prefork(LinkList list, int flags) | 
|         |     59 { | 
|         |     60     LinkNode node, stop = 0; | 
|         |     61     int keep = 0, asssub = (flags & PF_TYPESET) && isset(KSHTYPESET); | 
|         |     62  | 
|         |     63     queue_signals(); | 
|         |     64     for (node = firstnode(list); node; incnode(node)) { | 
|         |     65 	char *str, c; | 
|         |     66  | 
|         |     67 	str = (char *)getdata(node); | 
|         |     68 	if (((c = *str) == Inang || c == Outang || c == Equals) && | 
|         |     69 	    str[1] == Inpar) { | 
|         |     70 	    if (c == Inang || c == Outang) | 
|         |     71 		setdata(node, (void *) getproc(str));	/* <(...) or >(...) */ | 
|         |     72 	    else | 
|         |     73 		setdata(node, (void *) getoutputfile(str));	/* =(...) */ | 
|         |     74 	    if (!getdata(node)) { | 
|         |     75 		unqueue_signals(); | 
|         |     76 		return; | 
|         |     77 	    } | 
|         |     78 	} else { | 
|         |     79 	    if (isset(SHFILEEXPANSION)) | 
|         |     80 		filesub((char **)getaddrdata(node), | 
|         |     81 			flags & (PF_TYPESET|PF_ASSIGN)); | 
|         |     82 	    if (!(node = stringsubst(list, node, flags & PF_SINGLE, asssub))) { | 
|         |     83 		unqueue_signals(); | 
|         |     84 		return; | 
|         |     85 	    } | 
|         |     86 	} | 
|         |     87     } | 
|         |     88     for (node = firstnode(list); node; incnode(node)) { | 
|         |     89 	if (node == stop) | 
|         |     90 	    keep = 0; | 
|         |     91 	if (*(char *)getdata(node)) { | 
|         |     92 	    remnulargs(getdata(node)); | 
|         |     93 	    if (unset(IGNOREBRACES) && !(flags & PF_SINGLE)) { | 
|         |     94 		if (!keep) | 
|         |     95 		    stop = nextnode(node); | 
|         |     96 		while (hasbraces(getdata(node))) { | 
|         |     97 		    keep = 1; | 
|         |     98 		    xpandbraces(list, &node); | 
|         |     99 		} | 
|         |    100 	    } | 
|         |    101 	    if (unset(SHFILEEXPANSION)) | 
|         |    102 		filesub((char **)getaddrdata(node), | 
|         |    103 			flags & (PF_TYPESET|PF_ASSIGN)); | 
|         |    104 	} else if (!(flags & PF_SINGLE) && !keep) | 
|         |    105 	    uremnode(list, node); | 
|         |    106 	if (errflag) { | 
|         |    107 	    unqueue_signals(); | 
|         |    108 	    return; | 
|         |    109 	} | 
|         |    110     } | 
|         |    111     unqueue_signals(); | 
|         |    112 } | 
|         |    113  | 
|         |    114 /**/ | 
|         |    115 static LinkNode | 
|         |    116 stringsubst(LinkList list, LinkNode node, int ssub, int asssub) | 
|         |    117 { | 
|         |    118     int qt; | 
|         |    119     char *str3 = (char *)getdata(node); | 
|         |    120     char *str  = str3, c; | 
|         |    121  | 
|         |    122     while (!errflag && (c = *str)) { | 
|         |    123 	if ((qt = c == Qstring) || c == String) { | 
|         |    124 	    if ((c = str[1]) == Inpar) { | 
|         |    125 		if (!qt) | 
|         |    126 		    mult_isarr = 1; | 
|         |    127 		str++; | 
|         |    128 		goto comsub; | 
|         |    129 	    } else if (c == Inbrack) { | 
|         |    130 		/* $[...] */ | 
|         |    131 		char *str2 = str; | 
|         |    132 		str2++; | 
|         |    133 		if (skipparens(Inbrack, Outbrack, &str2)) { | 
|         |    134 		    zerr("closing bracket missing", NULL, 0); | 
|         |    135 		    return NULL; | 
|         |    136 		} | 
|         |    137 		str2[-1] = *str = '\0'; | 
|         |    138 		str = arithsubst(str + 2, &str3, str2); | 
|         |    139 		setdata(node, (void *) str3); | 
|         |    140 		continue; | 
|         |    141 	    } else if (c == Snull) { | 
|         |    142 		str = getkeystring(str, NULL, 4, NULL); | 
|         |    143 		continue; | 
|         |    144 	    } else { | 
|         |    145 		node = paramsubst(list, node, &str, qt, ssub); | 
|         |    146 		if (errflag || !node) | 
|         |    147 		    return NULL; | 
|         |    148 		str3 = (char *)getdata(node); | 
|         |    149 		continue; | 
|         |    150 	    } | 
|         |    151 	} else if ((qt = c == Qtick) || (c == Tick ? (mult_isarr = 1) : 0)) | 
|         |    152 	  comsub: { | 
|         |    153 	    LinkList pl; | 
|         |    154 	    char *s, *str2 = str; | 
|         |    155 	    char endchar; | 
|         |    156 	    int l1, l2; | 
|         |    157  | 
|         |    158 	    if (c == Inpar) { | 
|         |    159 		endchar = Outpar; | 
|         |    160 		str[-1] = '\0'; | 
|         |    161 #ifdef DEBUG | 
|         |    162 		if (skipparens(Inpar, Outpar, &str)) | 
|         |    163 		    dputs("BUG: parse error in command substitution"); | 
|         |    164 #else | 
|         |    165 		skipparens(Inpar, Outpar, &str); | 
|         |    166 #endif | 
|         |    167 		str--; | 
|         |    168 	    } else { | 
|         |    169 		endchar = c; | 
|         |    170 		*str = '\0'; | 
|         |    171  | 
|         |    172 		while (*++str != endchar) | 
|         |    173 		    DPUTS(!*str, "BUG: parse error in command substitution"); | 
|         |    174 	    } | 
|         |    175 	    *str++ = '\0'; | 
|         |    176 	    if (endchar == Outpar && str2[1] == '(' && str[-2] == ')') { | 
|         |    177 		/* Math substitution of the form $((...)) */ | 
|         |    178 		str[-2] = '\0'; | 
|         |    179 		str = arithsubst(str2 + 2, &str3, str); | 
|         |    180 		setdata(node, (void *) str3); | 
|         |    181 		continue; | 
|         |    182 	    } | 
|         |    183  | 
|         |    184 	    /* It is a command substitution, which will be parsed again   * | 
|         |    185 	     * by the lexer, so we untokenize it first, but we cannot use * | 
|         |    186 	     * untokenize() since in the case of `...` some Bnulls should * | 
|         |    187 	     * be left unchanged.  Note that the lexer doesn't tokenize   * | 
|         |    188 	     * the body of a command substitution so if there are some    * | 
|         |    189 	     * tokens here they are from a ${(e)~...} substitution.       */ | 
|         |    190 	    for (str = str2; (c = *++str); ) | 
|         |    191 		if (itok(c) && c != Nularg && | 
|         |    192 		    !(endchar != Outpar && c == Bnull && | 
|         |    193 		      (str[1] == '$' || str[1] == '\\' || str[1] == '`' || | 
|         |    194 		       (qt && str[1] == '"')))) | 
|         |    195 		    *str = ztokens[c - Pound]; | 
|         |    196 	    str++; | 
|         |    197 	    if (!(pl = getoutput(str2 + 1, qt || ssub))) { | 
|         |    198 		zerr("parse error in command substitution", NULL, 0); | 
|         |    199 		return NULL; | 
|         |    200 	    } | 
|         |    201 	    if (endchar == Outpar) | 
|         |    202 		str2--; | 
|         |    203 	    if (!(s = (char *) ugetnode(pl))) { | 
|         |    204 		str = strcpy(str2, str); | 
|         |    205 		continue; | 
|         |    206 	    } | 
|         |    207 	    if (!qt && ssub && isset(GLOBSUBST)) | 
|         |    208 		shtokenize(s); | 
|         |    209 	    l1 = str2 - str3; | 
|         |    210 	    l2 = strlen(s); | 
|         |    211 	    if (nonempty(pl)) { | 
|         |    212 		LinkNode n = lastnode(pl); | 
|         |    213 		str2 = (char *) hcalloc(l1 + l2 + 1); | 
|         |    214 		strcpy(str2, str3); | 
|         |    215 		strcpy(str2 + l1, s); | 
|         |    216 		setdata(node, str2); | 
|         |    217 		insertlinklist(pl, node, list); | 
|         |    218 		s = (char *) getdata(node = n); | 
|         |    219 		l1 = 0; | 
|         |    220 		l2 = strlen(s); | 
|         |    221 	    } | 
|         |    222 	    str2 = (char *) hcalloc(l1 + l2 + strlen(str) + 1); | 
|         |    223 	    if (l1) | 
|         |    224 		strcpy(str2, str3); | 
|         |    225 	    strcpy(str2 + l1, s); | 
|         |    226 	    str = strcpy(str2 + l1 + l2, str); | 
|         |    227 	    str3 = str2; | 
|         |    228 	    setdata(node, str3); | 
|         |    229 	    continue; | 
|         |    230 	} else if (asssub && ((c == '=') || c == Equals) && str != str3) { | 
|         |    231 	    /* | 
|         |    232 	     * We are in a normal argument which looks like an assignment | 
|         |    233 	     * and is to be treated like one, with no word splitting. | 
|         |    234 	     */ | 
|         |    235 	    ssub = 1; | 
|         |    236 	} | 
|         |    237 	str++; | 
|         |    238     } | 
|         |    239     return errflag ? NULL : node; | 
|         |    240 } | 
|         |    241  | 
|         |    242 /* | 
|         |    243  * Simplified version of the prefork/singsub processing where | 
|         |    244  * we only do substitutions appropriate to quoting.  Currently | 
|         |    245  * this means only the expansions in $'....'.  This is used | 
|         |    246  * for the end tag for here documents.  As we are not doing | 
|         |    247  * `...` expansions, we just use those for quoting.  However, | 
|         |    248  * they stay in the text.  This is weird, but that's not | 
|         |    249  * my fault. | 
|         |    250  * | 
|         |    251  * The remnulargs() makes this consistent with the other forms | 
|         |    252  * of substitution, indicating that quotes have been fully | 
|         |    253  * processed. | 
|         |    254  */ | 
|         |    255  | 
|         |    256 /**/ | 
|         |    257 void | 
|         |    258 quotesubst(char *str) | 
|         |    259 { | 
|         |    260     char *s = str; | 
|         |    261  | 
|         |    262     while (*s) { | 
|         |    263 	if (*s == String && s[1] == Snull) { | 
|         |    264 	    s = getkeystring(s, NULL, 4, NULL); | 
|         |    265 	} else { | 
|         |    266 	    s++; | 
|         |    267 	} | 
|         |    268     } | 
|         |    269     remnulargs(str); | 
|         |    270 } | 
|         |    271  | 
|         |    272 /**/ | 
|         |    273 mod_export void | 
|         |    274 globlist(LinkList list, int nountok) | 
|         |    275 { | 
|         |    276     LinkNode node, next; | 
|         |    277  | 
|         |    278     badcshglob = 0; | 
|         |    279     for (node = firstnode(list); !errflag && node; node = next) { | 
|         |    280 	next = nextnode(node); | 
|         |    281 	zglob(list, node, nountok); | 
|         |    282     } | 
|         |    283     if (badcshglob == 1) | 
|         |    284 	zerr("no match", NULL, 0); | 
|         |    285 } | 
|         |    286  | 
|         |    287 /* perform substitution on a single word */ | 
|         |    288  | 
|         |    289 /**/ | 
|         |    290 mod_export void | 
|         |    291 singsub(char **s) | 
|         |    292 { | 
|         |    293     int omi = mult_isarr; | 
|         |    294     local_list1(foo); | 
|         |    295  | 
|         |    296     init_list1(foo, *s); | 
|         |    297  | 
|         |    298     prefork(&foo, PF_SINGLE); | 
|         |    299     mult_isarr = omi; | 
|         |    300     if (errflag) | 
|         |    301 	return; | 
|         |    302     *s = (char *) ugetnode(&foo); | 
|         |    303     DPUTS(nonempty(&foo), "BUG: singsub() produced more than one word!"); | 
|         |    304 } | 
|         |    305  | 
|         |    306 /* Perform substitution on a single word. Unlike with singsub, the      * | 
|         |    307  * result can have more than one word. A single word result is stored   * | 
|         |    308  * in *s and *isarr is set to zero; otherwise *isarr is set to 1 and    * | 
|         |    309  * the result is stored in *a. If `a' is zero a multiple word result is * | 
|         |    310  * joined using sep or the IFS parameter if sep is zero and the result  * | 
|         |    311  * is returned in *s.  The return value is true iff the expansion       * | 
|         |    312  * resulted in an empty list.                                           * | 
|         |    313  * The mult_isarr variable is used by paramsubst() to tell if it yields * | 
|         |    314  * an array.                                                            */ | 
|         |    315  | 
|         |    316 /**/ | 
|         |    317 static int mult_isarr; | 
|         |    318  | 
|         |    319 /**/ | 
|         |    320 static int | 
|         |    321 multsub(char **s, char ***a, int *isarr, UNUSED(char *sep)) | 
|         |    322 { | 
|         |    323     int l, omi = mult_isarr; | 
|         |    324     char **r, **p; | 
|         |    325     local_list1(foo); | 
|         |    326 #ifdef __SYMBIAN32__ | 
|         |    327 	sep=sep; | 
|         |    328 #endif | 
|         |    329     mult_isarr = 0; | 
|         |    330     init_list1(foo, *s); | 
|         |    331     prefork(&foo, 0); | 
|         |    332     if (errflag) { | 
|         |    333 	if (isarr) | 
|         |    334 	    *isarr = 0; | 
|         |    335 	mult_isarr = omi; | 
|         |    336 	return 0; | 
|         |    337     } | 
|         |    338     if ((l = countlinknodes(&foo))) { | 
|         |    339 	p = r = hcalloc((l + 1) * sizeof(char*)); | 
|         |    340 	while (nonempty(&foo)) | 
|         |    341 	    *p++ = (char *)ugetnode(&foo); | 
|         |    342 	*p = NULL; | 
|         |    343 	/* | 
|         |    344 	 * This is the most obscure way of deciding whether a value is | 
|         |    345 	 * an array it would be possible to imagine.  It seems to result | 
|         |    346 	 * partly because we don't pass down the qt and ssub flags from | 
|         |    347 	 * paramsubst() through prefork() properly, partly because we | 
|         |    348 	 * don't tidy up to get back the return type from multsub we | 
|         |    349 	 * need properly.  The crux of neatening this up is to get rid | 
|         |    350 	 * of the following test. | 
|         |    351 	 */ | 
|         |    352 	if (a && mult_isarr) { | 
|         |    353 	    *a = r; | 
|         |    354 	    *isarr = SCANPM_MATCHMANY; | 
|         |    355 	    mult_isarr = omi; | 
|         |    356 	    return 0; | 
|         |    357 	} | 
|         |    358 	*s = sepjoin(r, NULL, 1); | 
|         |    359 	mult_isarr = omi; | 
|         |    360 	if (isarr) | 
|         |    361 	    *isarr = 0; | 
|         |    362 	return 0; | 
|         |    363     } | 
|         |    364     if (l) | 
|         |    365 	*s = (char *) ugetnode(&foo); | 
|         |    366     else | 
|         |    367 	*s = dupstring(""); | 
|         |    368     if (isarr) | 
|         |    369 	*isarr = 0; | 
|         |    370     mult_isarr = omi; | 
|         |    371     return !l; | 
|         |    372 } | 
|         |    373  | 
|         |    374 /* | 
|         |    375  * ~, = subs: assign & PF_TYPESET => typeset or magic equals | 
|         |    376  *            assign & PF_ASSIGN => normal assignment | 
|         |    377  */ | 
|         |    378  | 
|         |    379 /**/ | 
|         |    380 mod_export void | 
|         |    381 filesub(char **namptr, int assign) | 
|         |    382 { | 
|         |    383     char *eql = NULL, *sub = NULL, *str, *ptr; | 
|         |    384     int len; | 
|         |    385  | 
|         |    386     filesubstr(namptr, assign); | 
|         |    387  | 
|         |    388     if (!assign) | 
|         |    389 	return; | 
|         |    390  | 
|         |    391     if (assign & PF_TYPESET) { | 
|         |    392 	if ((*namptr)[1] && (eql = sub = strchr(*namptr + 1, Equals))) { | 
|         |    393 	    str = sub + 1; | 
|         |    394 	    if ((sub[1] == Tilde || sub[1] == Equals) && filesubstr(&str, assign)) { | 
|         |    395 		sub[1] = '\0'; | 
|         |    396 		*namptr = dyncat(*namptr, str); | 
|         |    397 	    } | 
|         |    398 	} else | 
|         |    399 	    return; | 
|         |    400     } | 
|         |    401  | 
|         |    402     ptr = *namptr; | 
|         |    403     while ((sub = strchr(ptr, ':'))) { | 
|         |    404 	str = sub + 1; | 
|         |    405 	len = sub - *namptr; | 
|         |    406 	if (sub > eql && | 
|         |    407 	    (sub[1] == Tilde || sub[1] == Equals) && | 
|         |    408 	    filesubstr(&str, assign)) { | 
|         |    409 	    sub[1] = '\0'; | 
|         |    410 	    *namptr = dyncat(*namptr, str); | 
|         |    411 	} | 
|         |    412 	ptr = *namptr + len + 1; | 
|         |    413     } | 
|         |    414 } | 
|         |    415  | 
|         |    416 /**/ | 
|         |    417 mod_export int | 
|         |    418 filesubstr(char **namptr, int assign) | 
|         |    419 { | 
|         |    420 #define isend(c) ( !(c) || (c)=='/' || (c)==Inpar || (assign && (c)==':') ) | 
|         |    421 #define isend2(c) ( !(c) || (c)==Inpar || (assign && (c)==':') ) | 
|         |    422     char *str = *namptr; | 
|         |    423  | 
|         |    424     if (*str == Tilde && str[1] != '=' && str[1] != Equals) { | 
|         |    425 	char *ptr; | 
|         |    426 	int val; | 
|         |    427  | 
|         |    428 	val = zstrtol(str + 1, &ptr, 10); | 
|         |    429 	if (isend(str[1])) {   /* ~ */ | 
|         |    430 	    *namptr = dyncat(home, str + 1); | 
|         |    431 	    return 1; | 
|         |    432 	} else if (str[1] == '+' && isend(str[2])) {   /* ~+ */ | 
|         |    433 	    *namptr = dyncat(pwd, str + 2); | 
|         |    434 	    return 1; | 
|         |    435 	} else if (str[1] == '-' && isend(str[2])) {   /* ~- */ | 
|         |    436 	    char *tmp; | 
|         |    437 	    *namptr = dyncat((tmp = oldpwd) ? tmp : pwd, str + 2); | 
|         |    438 	    return 1; | 
|         |    439 	} else if (!inblank(str[1]) && isend(*ptr) && | 
|         |    440 		   (!idigit(str[1]) || (ptr - str < 4))) { | 
|         |    441 	    char *ds; | 
|         |    442  | 
|         |    443 	    if (val < 0) | 
|         |    444 		val = -val; | 
|         |    445 	    ds = dstackent(str[1], val); | 
|         |    446 	    if (!ds) | 
|         |    447 		return 0; | 
|         |    448 	    *namptr = dyncat(ds, ptr); | 
|         |    449 	    return 1; | 
|         |    450 	} else if (iuser(str[1])) {   /* ~foo */ | 
|         |    451 	    char *ptr, *hom, save; | 
|         |    452  | 
|         |    453 	    for (ptr = ++str; *ptr && iuser(*ptr); ptr++); | 
|         |    454 	    save = *ptr; | 
|         |    455 	    if (!isend(save)) | 
|         |    456 		return 0; | 
|         |    457 	    *ptr = 0; | 
|         |    458 	    if (!(hom = getnameddir(str))) { | 
|         |    459 		if (isset(NOMATCH)) | 
|         |    460 		    zerr("no such user or named directory: %s", str, 0); | 
|         |    461 		*ptr = save; | 
|         |    462 		return 0; | 
|         |    463 	    } | 
|         |    464 	    *ptr = save; | 
|         |    465 	    *namptr = dyncat(hom, ptr); | 
|         |    466 	    return 1; | 
|         |    467 	} | 
|         |    468     } else if (*str == Equals && isset(EQUALS) && str[1]) {   /* =foo */ | 
|         |    469 	char sav, *pp, *cnam; | 
|         |    470  | 
|         |    471 	for (pp = str + 1; !isend2(*pp); pp++); | 
|         |    472 	sav = *pp; | 
|         |    473 	*pp = 0; | 
|         |    474 	if (!(cnam = findcmd(str + 1, 1))) { | 
|         |    475 	    if (isset(NOMATCH)) | 
|         |    476 		zerr("%s not found", str + 1, 0); | 
|         |    477 	    return 0; | 
|         |    478 	} | 
|         |    479 	*namptr = dupstring(cnam); | 
|         |    480 	if (sav) { | 
|         |    481 	    *pp = sav; | 
|         |    482 	    *namptr = dyncat(*namptr, pp); | 
|         |    483 	} | 
|         |    484 	return 1; | 
|         |    485     } | 
|         |    486     return 0; | 
|         |    487 #undef isend | 
|         |    488 #undef isend2 | 
|         |    489 } | 
|         |    490  | 
|         |    491 /**/ | 
|         |    492 static char * | 
|         |    493 strcatsub(char **d, char *pb, char *pe, char *src, int l, char *s, int glbsub, | 
|         |    494 	  int copied) | 
|         |    495 { | 
|         |    496     char *dest; | 
|         |    497     int pl = pe - pb; | 
|         |    498  | 
|         |    499     if (!pl && (!s || !*s)) { | 
|         |    500 	*d = dest = (copied ? src : dupstring(src)); | 
|         |    501 	if (glbsub) | 
|         |    502 	    shtokenize(dest); | 
|         |    503     } else { | 
|         |    504 	*d = dest = hcalloc(pl + l + (s ? strlen(s) : 0) + 1); | 
|         |    505 	strncpy(dest, pb, pl); | 
|         |    506 	dest += pl; | 
|         |    507 	strcpy(dest, src); | 
|         |    508 	if (glbsub) | 
|         |    509 	    shtokenize(dest); | 
|         |    510 	dest += l; | 
|         |    511 	if (s) | 
|         |    512 	    strcpy(dest, s); | 
|         |    513     } | 
|         |    514     return dest; | 
|         |    515 } | 
|         |    516  | 
|         |    517 typedef int (*CompareFn) _((const void *, const void *)); | 
|         |    518  | 
|         |    519 /**/ | 
|         |    520 int | 
|         |    521 strpcmp(const void *a, const void *b) | 
|         |    522 { | 
|         |    523 #ifdef HAVE_STRCOLL | 
|         |    524     return strcoll(*(char **)a, *(char **)b); | 
|         |    525 #else | 
|         |    526     return strcmp(*(char **)a, *(char **)b); | 
|         |    527 #endif | 
|         |    528 } | 
|         |    529  | 
|         |    530 /**/ | 
|         |    531 int | 
|         |    532 invstrpcmp(const void *a, const void *b) | 
|         |    533 { | 
|         |    534 #ifdef HAVE_STRCOLL | 
|         |    535     return -strcoll(*(char **)a, *(char **)b); | 
|         |    536 #else | 
|         |    537     return -strcmp(*(char **)a, *(char **)b); | 
|         |    538 #endif | 
|         |    539 } | 
|         |    540  | 
|         |    541 /**/ | 
|         |    542 int | 
|         |    543 cstrpcmp(const void *a, const void *b) | 
|         |    544 { | 
|         |    545 #ifdef HAVE_STRCOLL | 
|         |    546     VARARR(char, c, strlen(*(char **) a) + 1); | 
|         |    547     VARARR(char, d, strlen(*(char **) b) + 1); | 
|         |    548     char *s, *t; | 
|         |    549     int   cmp; | 
|         |    550  | 
|         |    551     for (s = *(char **) a, t = c; (*t++ = tulower(*s++));); | 
|         |    552     for (s = *(char **) b, t = d; (*t++ = tulower(*s++));); | 
|         |    553  | 
|         |    554     cmp = strcoll(c, d); | 
|         |    555  | 
|         |    556     return cmp; | 
|         |    557 #else | 
|         |    558     char *c = *(char **)a, *d = *(char **)b; | 
|         |    559  | 
|         |    560     for (; *c && tulower(*c) == tulower(*d); c++, d++); | 
|         |    561  | 
|         |    562     return (int)STOUC(tulower(*c)) - (int)STOUC(tulower(*d)); | 
|         |    563 #endif | 
|         |    564 } | 
|         |    565  | 
|         |    566 /**/ | 
|         |    567 int | 
|         |    568 invcstrpcmp(const void *a, const void *b) | 
|         |    569 { | 
|         |    570 #ifdef HAVE_STRCOLL | 
|         |    571     VARARR(char, c, strlen(*(char **) a) + 1); | 
|         |    572     VARARR(char, d, strlen(*(char **) b) + 1); | 
|         |    573     char *s, *t; | 
|         |    574     int   cmp; | 
|         |    575  | 
|         |    576     for (s = *(char **) a, t = c; (*t++ = tulower(*s++));); | 
|         |    577     for (s = *(char **) b, t = d; (*t++ = tulower(*s++));); | 
|         |    578  | 
|         |    579     cmp = strcoll(c, d); | 
|         |    580  | 
|         |    581     return -cmp; | 
|         |    582 #else | 
|         |    583     char *c = *(char **)a, *d = *(char **)b; | 
|         |    584  | 
|         |    585     for (; *c && tulower(*c) == tulower(*d); c++, d++); | 
|         |    586  | 
|         |    587     return (int)STOUC(tulower(*d)) - (int)STOUC(tulower(*c)); | 
|         |    588 #endif | 
|         |    589 } | 
|         |    590  | 
|         |    591 /**/ | 
|         |    592 int | 
|         |    593 nstrpcmp(const void *a, const void *b) | 
|         |    594 { | 
|         |    595     char *c = *(char **)a, *d = *(char **)b; | 
|         |    596     int cmp; | 
|         |    597  | 
|         |    598 #ifdef HAVE_STRCOLL | 
|         |    599     cmp = strcoll(c, d); | 
|         |    600 #endif | 
|         |    601     for (; *c == *d && *c; c++, d++); | 
|         |    602 #ifndef HAVE_STRCOLL | 
|         |    603     cmp = (int)STOUC(*c) - (int)STOUC(*d); | 
|         |    604 #endif | 
|         |    605     if (idigit(*c) || idigit(*d)) { | 
|         |    606 	for (; c > *(char **)a && idigit(c[-1]); c--, d--); | 
|         |    607 	if (idigit(*c) && idigit(*d)) { | 
|         |    608 	    while (*c == '0') | 
|         |    609 		c++; | 
|         |    610 	    while (*d == '0') | 
|         |    611 		d++; | 
|         |    612 	    for (; idigit(*c) && *c == *d; c++, d++); | 
|         |    613 	    if (idigit(*c) || idigit(*d)) { | 
|         |    614 		cmp = (int)STOUC(*c) - (int)STOUC(*d); | 
|         |    615 		while (idigit(*c) && idigit(*d)) | 
|         |    616 		    c++, d++; | 
|         |    617 		if (idigit(*c) && !idigit(*d)) | 
|         |    618 		    return 1; | 
|         |    619 		if (idigit(*d) && !idigit(*c)) | 
|         |    620 		    return -1; | 
|         |    621 	    } | 
|         |    622 	} | 
|         |    623     } | 
|         |    624     return cmp; | 
|         |    625 } | 
|         |    626  | 
|         |    627 /**/ | 
|         |    628 int | 
|         |    629 invnstrpcmp(const void *a, const void *b) | 
|         |    630 { | 
|         |    631     return -nstrpcmp(a, b); | 
|         |    632 } | 
|         |    633  | 
|         |    634 /**/ | 
|         |    635 int | 
|         |    636 instrpcmp(const void *a, const void *b) | 
|         |    637 { | 
|         |    638     VARARR(char, c, strlen(*(char **) a) + 1); | 
|         |    639     VARARR(char, d, strlen(*(char **) b) + 1); | 
|         |    640     char **e = (char **)&c; | 
|         |    641     char **f = (char **)&d; | 
|         |    642     char *s, *t; | 
|         |    643  | 
|         |    644     for (s = *(char **) a, t = c; (*t++ = tulower(*s++));); | 
|         |    645     for (s = *(char **) b, t = d; (*t++ = tulower(*s++));); | 
|         |    646  | 
|         |    647     return nstrpcmp(&e, &f); | 
|         |    648 } | 
|         |    649  | 
|         |    650 /**/ | 
|         |    651 int | 
|         |    652 invinstrpcmp(const void *a, const void *b) | 
|         |    653 { | 
|         |    654     return -instrpcmp(a, b); | 
|         |    655 } | 
|         |    656  | 
|         |    657 /**/ | 
|         |    658 static char * | 
|         |    659 dopadding(char *str, int prenum, int postnum, char *preone, char *postone, char *premul, char *postmul) | 
|         |    660 { | 
|         |    661     char def[3], *ret, *t, *r; | 
|         |    662     int ls, ls2, lpreone, lpostone, lpremul, lpostmul, lr, f, m, c, cc; | 
|         |    663  | 
|         |    664     def[0] = *ifs ? *ifs : ' '; | 
|         |    665     def[1] = *ifs == Meta ? ifs[1] ^ 32 : '\0'; | 
|         |    666     def[2] = '\0'; | 
|         |    667     if (preone && !*preone) | 
|         |    668 	preone = def; | 
|         |    669     if (postone && !*postone) | 
|         |    670 	postone = def; | 
|         |    671     if (!premul || !*premul) | 
|         |    672 	premul = def; | 
|         |    673     if (!postmul || !*postmul) | 
|         |    674 	postmul = def; | 
|         |    675  | 
|         |    676     ls = strlen(str); | 
|         |    677     lpreone = preone ? strlen(preone) : 0; | 
|         |    678     lpostone = postone ? strlen(postone) : 0; | 
|         |    679     lpremul = strlen(premul); | 
|         |    680     lpostmul = strlen(postmul); | 
|         |    681  | 
|         |    682     lr = prenum + postnum; | 
|         |    683  | 
|         |    684     if (lr == ls) | 
|         |    685 	return str; | 
|         |    686  | 
|         |    687     r = ret = (char *)zhalloc(lr + 1); | 
|         |    688  | 
|         |    689     if (prenum) { | 
|         |    690 	if (postnum) { | 
|         |    691 	    ls2 = ls / 2; | 
|         |    692  | 
|         |    693 	    f = prenum - ls2; | 
|         |    694 	    if (f <= 0) | 
|         |    695 		for (str -= f, c = prenum; c--; *r++ = *str++); | 
|         |    696 	    else { | 
|         |    697 		if (f <= lpreone) | 
|         |    698 		    for (c = f, t = preone + lpreone - f; c--; *r++ = *t++); | 
|         |    699 		else { | 
|         |    700 		    f -= lpreone; | 
|         |    701 		    if ((m = f % lpremul)) | 
|         |    702 			for (c = m, t = premul + lpremul - m; c--; *r++ = *t++); | 
|         |    703 		    for (cc = f / lpremul; cc--;) | 
|         |    704 			for (c = lpremul, t = premul; c--; *r++ = *t++); | 
|         |    705 		    for (c = lpreone; c--; *r++ = *preone++); | 
|         |    706 		} | 
|         |    707 		for (c = ls2; c--; *r++ = *str++); | 
|         |    708 	    } | 
|         |    709 	    ls2 = ls - ls2; | 
|         |    710 	    f = postnum - ls2; | 
|         |    711 	    if (f <= 0) | 
|         |    712 		for (c = postnum; c--; *r++ = *str++); | 
|         |    713 	    else { | 
|         |    714 		for (c = ls2; c--; *r++ = *str++); | 
|         |    715 		if (f <= lpostone) | 
|         |    716 		    for (c = f; c--; *r++ = *postone++); | 
|         |    717 		else { | 
|         |    718 		    f -= lpostone; | 
|         |    719 		    for (c = lpostone; c--; *r++ = *postone++); | 
|         |    720 		    for (cc = f / lpostmul; cc--;) | 
|         |    721 			for (c = lpostmul, t = postmul; c--; *r++ = *t++); | 
|         |    722 		    if ((m = f % lpostmul)) | 
|         |    723 			for (; m--; *r++ = *postmul++); | 
|         |    724 		} | 
|         |    725 	    } | 
|         |    726 	} else { | 
|         |    727 	    f = prenum - ls; | 
|         |    728 	    if (f <= 0) | 
|         |    729 		for (c = prenum, str -= f; c--; *r++ = *str++); | 
|         |    730 	    else { | 
|         |    731 		if (f <= lpreone) | 
|         |    732 		    for (c = f, t = preone + lpreone - f; c--; *r++ = *t++); | 
|         |    733 		else { | 
|         |    734 		    f -= lpreone; | 
|         |    735 		    if ((m = f % lpremul)) | 
|         |    736 			for (c = m, t = premul + lpremul - m; c--; *r++ = *t++); | 
|         |    737 		    for (cc = f / lpremul; cc--;) | 
|         |    738 			for (c = lpremul, t = premul; c--; *r++ = *t++); | 
|         |    739 		    for (c = lpreone; c--; *r++ = *preone++); | 
|         |    740 		} | 
|         |    741 		for (c = ls; c--; *r++ = *str++); | 
|         |    742 	    } | 
|         |    743 	} | 
|         |    744     } else if (postnum) { | 
|         |    745 	f = postnum - ls; | 
|         |    746 	if (f <= 0) | 
|         |    747 	    for (c = postnum; c--; *r++ = *str++); | 
|         |    748 	else { | 
|         |    749 	    for (c = ls; c--; *r++ = *str++); | 
|         |    750 	    if (f <= lpostone) | 
|         |    751 		for (c = f; c--; *r++ = *postone++); | 
|         |    752 	    else { | 
|         |    753 		f -= lpostone; | 
|         |    754 		for (c = lpostone; c--; *r++ = *postone++); | 
|         |    755 		for (cc = f / lpostmul; cc--;) | 
|         |    756 		    for (c = lpostmul, t = postmul; c--; *r++ = *t++); | 
|         |    757 		if ((m = f % lpostmul)) | 
|         |    758 		    for (; m--; *r++ = *postmul++); | 
|         |    759 	    } | 
|         |    760 	} | 
|         |    761     } | 
|         |    762     *r = '\0'; | 
|         |    763  | 
|         |    764     return ret; | 
|         |    765 } | 
|         |    766  | 
|         |    767 /**/ | 
|         |    768 char * | 
|         |    769 get_strarg(char *s) | 
|         |    770 { | 
|         |    771     char t = *s++; | 
|         |    772  | 
|         |    773     if (!t) | 
|         |    774 	return s - 1; | 
|         |    775  | 
|         |    776     switch (t) { | 
|         |    777     case '(': | 
|         |    778 	t = ')'; | 
|         |    779 	break; | 
|         |    780     case '[': | 
|         |    781 	t = ']'; | 
|         |    782 	break; | 
|         |    783     case '{': | 
|         |    784 	t = '}'; | 
|         |    785 	break; | 
|         |    786     case '<': | 
|         |    787 	t = '>'; | 
|         |    788 	break; | 
|         |    789     case Inpar: | 
|         |    790 	t = Outpar; | 
|         |    791 	break; | 
|         |    792     case Inang: | 
|         |    793 	t = Outang; | 
|         |    794 	break; | 
|         |    795     case Inbrace: | 
|         |    796 	t = Outbrace; | 
|         |    797 	break; | 
|         |    798     case Inbrack: | 
|         |    799 	t = Outbrack; | 
|         |    800 	break; | 
|         |    801     } | 
|         |    802  | 
|         |    803     while (*s && *s != t) | 
|         |    804 	s++; | 
|         |    805  | 
|         |    806     return s; | 
|         |    807 } | 
|         |    808  | 
|         |    809 /**/ | 
|         |    810 static int | 
|         |    811 get_intarg(char **s) | 
|         |    812 { | 
|         |    813     char *t = get_strarg(*s + 1); | 
|         |    814     char *p, sav; | 
|         |    815     zlong ret; | 
|         |    816  | 
|         |    817     if (!*t) | 
|         |    818 	return -1; | 
|         |    819     sav = *t; | 
|         |    820     *t = '\0'; | 
|         |    821     p = dupstring(*s + 2); | 
|         |    822     *s = t; | 
|         |    823     *t = sav; | 
|         |    824     if (parsestr(p)) | 
|         |    825 	return -1; | 
|         |    826     singsub(&p); | 
|         |    827     if (errflag) | 
|         |    828 	return -1; | 
|         |    829     ret = mathevali(p); | 
|         |    830     if (errflag) | 
|         |    831 	return -1; | 
|         |    832     if (ret < 0) | 
|         |    833 	ret = -ret; | 
|         |    834     return ret < 0 ? -ret : ret; | 
|         |    835 } | 
|         |    836  | 
|         |    837 /* Parsing for the (e) flag. */ | 
|         |    838  | 
|         |    839 static int | 
|         |    840 subst_parse_str(char **sp, int single, int err) | 
|         |    841 { | 
|         |    842     char *s; | 
|         |    843  | 
|         |    844     *sp = s = dupstring(*sp); | 
|         |    845  | 
|         |    846     if (!(err ? parsestr(s) : parsestrnoerr(s))) { | 
|         |    847 	if (!single) { | 
|         |    848             int qt = 0; | 
|         |    849  | 
|         |    850 	    for (; *s; s++) | 
|         |    851 		if (!qt) { | 
|         |    852 		    if (*s == Qstring) | 
|         |    853 			*s = String; | 
|         |    854 		    else if (*s == Qtick) | 
|         |    855 			*s = Tick; | 
|         |    856                 } else if (*s == Dnull) | 
|         |    857                     qt = !qt; | 
|         |    858 	} | 
|         |    859 	return 0; | 
|         |    860     } | 
|         |    861     return 1; | 
|         |    862 } | 
|         |    863  | 
|         |    864 /* parameter substitution */ | 
|         |    865  | 
|         |    866 #define	isstring(c) ((c) == '$' || (char)(c) == String || (char)(c) == Qstring) | 
|         |    867 #define isbrack(c)  ((c) == '[' || (char)(c) == Inbrack) | 
|         |    868  | 
|         |    869 /* | 
|         |    870  * Given a linked list l with node n, perform parameter substitution | 
|         |    871  * starting from *str.  Return the node with the substitutuion performed | 
|         |    872  * or NULL if it failed. | 
|         |    873  * | 
|         |    874  * If qt is true, the `$' was quoted.  TODO: why can't we just look | 
|         |    875  * to see if the first character was String or Qstring? | 
|         |    876  * | 
|         |    877  * If ssub is true, we are being called via singsubst(), which means | 
|         |    878  * the result will be a single word.  TODO: can we generate the | 
|         |    879  * single word at the end?  TODO: if not, or maybe in any case, | 
|         |    880  * can we pass down the ssub flag from prefork with the other flags | 
|         |    881  * instead of pushing it into different arguments?  (How exactly | 
|         |    882  * to qt and ssub differ?  Are both necessary, if so is there some | 
|         |    883  * better way of separating the two?) | 
|         |    884  */ | 
|         |    885  | 
|         |    886 /**/ | 
|         |    887 LinkNode | 
|         |    888 paramsubst(LinkList l, LinkNode n, char **str, int qt, int ssub) | 
|         |    889 { | 
|         |    890     char *aptr = *str, c, cc; | 
|         |    891     char *s = aptr, *fstr, *idbeg, *idend, *ostr = (char *) getdata(n); | 
|         |    892     int colf;			/* != 0 means we found a colon after the name */ | 
|         |    893     /* | 
|         |    894      * There are far too many flags.  They need to be grouped | 
|         |    895      * together into some structure which ties them to where they | 
|         |    896      * came from. | 
|         |    897      * | 
|         |    898      * Some flags have a an obscure relationship to their effect which | 
|         |    899      * depends on incrementing them to particular values in particular | 
|         |    900      * ways. | 
|         |    901      */ | 
|         |    902     /* | 
|         |    903      * Whether the value is an array (in aval) or not (in val).  There's | 
|         |    904      * a movement from storing the value in the stuff read from the | 
|         |    905      * parameter (the value v) to storing them in val and aval. | 
|         |    906      * However, sometimes you find v reappearing temporarily. | 
|         |    907      * | 
|         |    908      * The values -1 and 2 are special to isarr.  It looks like 2 is | 
|         |    909      * some kind of an internal flag to do with whether the array's been | 
|         |    910      * copied, in which case I don't know why we don't use the copied | 
|         |    911      * flag, but they do both occur close together so they presumably | 
|         |    912      * have different effects.  The value -1 is isued to force us to | 
|         |    913      * keep an empty array.  It's tested in the YUK chunk (I mean the | 
|         |    914      * one explicitly marked as such). | 
|         |    915      */ | 
|         |    916     int isarr = 0; | 
|         |    917     /* | 
|         |    918      * This is just the setting of the option except we need to | 
|         |    919      * take account of ^ and ^^. | 
|         |    920      */ | 
|         |    921     int plan9 = isset(RCEXPANDPARAM); | 
|         |    922     /* | 
|         |    923      * Likwise, but with ~ and ~~.  Also, we turn it off later | 
|         |    924      * on if qt is passed down. | 
|         |    925      */ | 
|         |    926     int globsubst = isset(GLOBSUBST); | 
|         |    927     /* | 
|         |    928      * Indicates ${#pm}, massaged by whichlen which is set by | 
|         |    929      * the (c), (w), and (W) flags to indicate how we take the length. | 
|         |    930      */ | 
|         |    931     int getlen = 0; | 
|         |    932     int whichlen = 0; | 
|         |    933     /* | 
|         |    934      * Indicates ${+pm}: a simple boolean for once. | 
|         |    935      */ | 
|         |    936     int chkset = 0; | 
|         |    937     /* | 
|         |    938      * Indicates we have tried to get a value in v but that was | 
|         |    939      * unset.  I don't quite understand why (v == NULL) isn't | 
|         |    940      * good enough, but there are places where we seem to need | 
|         |    941      * to second guess whether a value is a real value or not. | 
|         |    942      */ | 
|         |    943     int vunset = 0; | 
|         |    944     /* | 
|         |    945      * Indicates (t) flag, i.e. print out types.  The code for | 
|         |    946      * this actually isn't too horrifically inbred compared with | 
|         |    947      * that for (P). | 
|         |    948      */ | 
|         |    949     int wantt = 0; | 
|         |    950     /* | 
|         |    951      * Indicates spliting a string into an array.  There aren't | 
|         |    952      * actually that many special cases for this --- which may | 
|         |    953      * be why it doesn't work properly; we split in some cases | 
|         |    954      * where we shouldn't, in particular on the multsubs for | 
|         |    955      * handling embedded values for ${...=...} and the like. | 
|         |    956      */ | 
|         |    957     int spbreak = isset(SHWORDSPLIT) && !ssub && !qt; | 
|         |    958     /* Scalar and array value, see isarr above */ | 
|         |    959     char *val = NULL, **aval = NULL; | 
|         |    960     /* | 
|         |    961      * Padding based on setting in parameter rather than substitution | 
|         |    962      * flags.  This is only used locally. | 
|         |    963      */ | 
|         |    964     unsigned int fwidth = 0; | 
|         |    965     /* | 
|         |    966      * vbuf and v are both used to retrieve parameter values; this | 
|         |    967      * is a kludge, we pass down vbuf and it may or may not return v. | 
|         |    968      */ | 
|         |    969     struct value vbuf; | 
|         |    970     Value v = NULL; | 
|         |    971     /* | 
|         |    972      * This expressive name refers to the set of flags which | 
|         |    973      * is applied to matching for #, %, / and their doubled variants: | 
|         |    974      * (M), (R), (B), (E), (N), (S). | 
|         |    975      */ | 
|         |    976     int flags = 0; | 
|         |    977     /* Value from (I) flag, used for ditto. */ | 
|         |    978     int flnum = 0; | 
|         |    979     /* | 
|         |    980      * sortit is an obscure combination of the settings for (o), (O), | 
|         |    981      * (i) and (n). casind is (i) and numord is (n); these are | 
|         |    982      * separate so we can have fun doing the obscure combinatorics later. | 
|         |    983      * indord is the (a) flag, which for consistency doesn't get | 
|         |    984      * combined into sortit. | 
|         |    985      */ | 
|         |    986     int sortit = 0, casind = 0, numord = 0, indord = 0; | 
|         |    987     /* (u): straightforward. */ | 
|         |    988     int unique = 0; | 
|         |    989     /* combination of (L), (U) and (C) flags. */ | 
|         |    990     int casmod = 0; | 
|         |    991     /* | 
|         |    992      * quotemod says we are doing either (q) (positive), (Q) (negative) | 
|         |    993      * or not (0).  quotetype counts the q's for the first case. | 
|         |    994      * quoterr is simply (X) but gets passed around a lot because the | 
|         |    995      * combination (eX) needs it. | 
|         |    996      */ | 
|         |    997     int quotemod = 0, quotetype = 0, quoteerr = 0; | 
|         |    998     /* | 
|         |    999      * (V) flag: fairly straightforward, except that as with so | 
|         |   1000      * many flags it's not easy to decide where to put it in the order. | 
|         |   1001      */ | 
|         |   1002     int visiblemod = 0; | 
|         |   1003     /* | 
|         |   1004      * The (z) flag, nothing to do with SH_WORD_SPLIT which is tied | 
|         |   1005      * spbreak, see above; fairly straighforward in use but c.f. | 
|         |   1006      * the comment for visiblemod. | 
|         |   1007      */ | 
|         |   1008     int shsplit = 0; | 
|         |   1009     /* | 
|         |   1010      * The separator from (j) and (s) respectively, or (F) and (f) | 
|         |   1011      * respectively (hardwired to "\n" in that case).  Slightly | 
|         |   1012      * confusingly also used for ${#pm}, thought that's at least | 
|         |   1013      * documented in the manual | 
|         |   1014      */ | 
|         |   1015     char *sep = NULL, *spsep = NULL; | 
|         |   1016     /* | 
|         |   1017      * Padding strings.  The left and right padding strings which | 
|         |   1018      * are repeated, then the ones which only occur once, for | 
|         |   1019      * the (l) and (r) flags. | 
|         |   1020      */ | 
|         |   1021     char *premul = NULL, *postmul = NULL, *preone = NULL, *postone = NULL; | 
|         |   1022     /* Replacement string for /orig/repl and //orig/repl */ | 
|         |   1023     char *replstr = NULL; | 
|         |   1024     /* The numbers for (l) and (r) */ | 
|         |   1025     zlong prenum = 0, postnum = 0; | 
|         |   1026     /* | 
|         |   1027      * Whether the value has been copied.  Optimisation:  if we | 
|         |   1028      * are modifying an expression, we only need to copy it the | 
|         |   1029      * first time, and if we don't modify it we can just use the | 
|         |   1030      * value from the parameter or input. | 
|         |   1031      */ | 
|         |   1032     int copied = 0; | 
|         |   1033     /* | 
|         |   1034      * The (A) flag for array assignment, with consequences for | 
|         |   1035      * splitting and joining; (AA) gives arrasg == 2 for associative | 
|         |   1036      * arrays. | 
|         |   1037      */ | 
|         |   1038     int arrasg = 0; | 
|         |   1039     /* | 
|         |   1040      * The (e) flag.  As we need to do extra work not quite | 
|         |   1041      * at the end, the effect of this is kludged in in several places. | 
|         |   1042      */ | 
|         |   1043     int eval = 0; | 
|         |   1044     /* | 
|         |   1045      * The (P) flag.  This interacts a bit obscurely with whether | 
|         |   1046      * or not we are dealing with a sub expression (subexp). | 
|         |   1047      */ | 
|         |   1048     int aspar = 0; | 
|         |   1049     /* | 
|         |   1050      * The (%) flag, c.f. visiblemod again. | 
|         |   1051      */	 | 
|         |   1052     int presc = 0; | 
|         |   1053     /* | 
|         |   1054      * The (@) flag; interacts obscurely with qt and isarr. | 
|         |   1055      * This is one of the things that decides whether multsub | 
|         |   1056      * will produce an array, but in an extremely indirect fashion. | 
|         |   1057      */ | 
|         |   1058     int nojoin = 0; | 
|         |   1059     /* | 
|         |   1060      * != 0 means ${...}, otherwise $...  What works without braces | 
|         |   1061      * is largely a historical artefact (everything works with braces, | 
|         |   1062      * I sincerely hope). | 
|         |   1063      */ | 
|         |   1064     char inbrace = 0; | 
|         |   1065     /* | 
|         |   1066      * Use for the (k) flag.  Goes down into the parameter code, | 
|         |   1067      * sometimes. | 
|         |   1068      */ | 
|         |   1069     char hkeys = 0; | 
|         |   1070     /* | 
|         |   1071      * Used for the (v) flag, ditto.  Not quite sure why they're | 
|         |   1072      * separate, but the tradition seems to be that things only | 
|         |   1073      * get combined when that makes the result more obscure rather | 
|         |   1074      * than less. | 
|         |   1075      */ | 
|         |   1076     char hvals = 0; | 
|         |   1077     /* | 
|         |   1078      * Whether we had to evaluate a subexpression, i.e. an | 
|         |   1079      * internal ${...} or $(...) or plain $pm.  We almost don't | 
|         |   1080      * need to remember this (which would be neater), but the (P) | 
|         |   1081      * flag means the subexp and !subexp code is obscurely combined, | 
|         |   1082      * and the argument passing to fetchvalue has another kludge. | 
|         |   1083      */ | 
|         |   1084     int subexp; | 
|         |   1085  | 
|         |   1086     *s++ = '\0'; | 
|         |   1087     /* | 
|         |   1088      * Nothing to do unless the character following the $ is | 
|         |   1089      * something we recognise. | 
|         |   1090      * | 
|         |   1091      * Shouldn't this be a table or something?  We test for all | 
|         |   1092      * these later on, too. | 
|         |   1093      */ | 
|         |   1094     if (!ialnum(c = *s) && c != '#' && c != Pound && c != '-' && | 
|         |   1095 	c != '!' && c != '$' && c != String && c != Qstring && | 
|         |   1096 	c != '?' && c != Quest && c != '_' && | 
|         |   1097 	c != '*' && c != Star && c != '@' && c != '{' && | 
|         |   1098 	c != Inbrace && c != '=' && c != Equals && c != Hat && | 
|         |   1099 	c != '^' && c != '~' && c != Tilde && c != '+') { | 
|         |   1100 	s[-1] = '$'; | 
|         |   1101 	*str = s; | 
|         |   1102 	return n; | 
|         |   1103     } | 
|         |   1104     DPUTS(c == '{', "BUG: inbrace == '{' in paramsubst()"); | 
|         |   1105     /* | 
|         |   1106      * Extra processing if there is an opening brace: mostly | 
|         |   1107      * flags in parentheses, but also one ksh hack. | 
|         |   1108      */ | 
|         |   1109     if (c == Inbrace) { | 
|         |   1110 	inbrace = 1; | 
|         |   1111 	s++; | 
|         |   1112 	/* | 
|         |   1113 	 * In ksh emulation a leading `!' is a special flag working | 
|         |   1114 	 * sort of like our (k). | 
|         |   1115 	 * TODO: this is one of very few cases tied directly to | 
|         |   1116 	 * the emulation mode rather than an option.  Since ksh | 
|         |   1117 	 * doesn't have parameter flags it might be neater to | 
|         |   1118 	 * handle this with the ^, =, ~ stuff, below. | 
|         |   1119 	 */ | 
|         |   1120 	if ((c = *s) == '!' && s[1] != Outbrace && emulation == EMULATE_KSH) { | 
|         |   1121 	    hkeys = SCANPM_WANTKEYS; | 
|         |   1122 	    s++; | 
|         |   1123 	} else if (c == '(' || c == Inpar) { | 
|         |   1124 	    char *t, sav; | 
|         |   1125 	    int tt = 0; | 
|         |   1126 	    zlong num; | 
|         |   1127 	    /* | 
|         |   1128 	     * The (p) flag is (uniquely) only remembered within | 
|         |   1129 	     * this block.  It says we do print-style handling | 
|         |   1130 	     * on the values for flags, but only on those. | 
|         |   1131 	     * This explains the ghastly macro, but why can't it | 
|         |   1132 	     * be a function?  UNTOK_AND_ESCAPE is defined | 
|         |   1133 	     * so that the argument must be an lvalue. | 
|         |   1134 	     */ | 
|         |   1135 	    int escapes = 0; | 
|         |   1136 	    int klen; | 
|         |   1137 #define UNTOK(C)  (itok(C) ? ztokens[(C) - Pound] : (C)) | 
|         |   1138 #define UNTOK_AND_ESCAPE(X) {\ | 
|         |   1139 		untokenize(X = dupstring(s + 1));\ | 
|         |   1140 		if (escapes) {\ | 
|         |   1141 		    X = getkeystring(X, &klen, 3, NULL);\ | 
|         |   1142 		    X = metafy(X, klen, META_HREALLOC);\ | 
|         |   1143 		}\ | 
|         |   1144 	    } | 
|         |   1145  | 
|         |   1146 	    for (s++; (c = *s) != ')' && c != Outpar; s++, tt = 0) { | 
|         |   1147 		switch (c) { | 
|         |   1148 		case ')': | 
|         |   1149 		case Outpar: | 
|         |   1150 		    break; | 
|         |   1151 		case 'A': | 
|         |   1152 		    ++arrasg; | 
|         |   1153 		    break; | 
|         |   1154 		case '@': | 
|         |   1155 		    nojoin = 1; | 
|         |   1156 		    break; | 
|         |   1157 		case 'M': | 
|         |   1158 		    flags |= SUB_MATCH; | 
|         |   1159 		    break; | 
|         |   1160 		case 'R': | 
|         |   1161 		    flags |= SUB_REST; | 
|         |   1162 		    break; | 
|         |   1163 		case 'B': | 
|         |   1164 		    flags |= SUB_BIND; | 
|         |   1165 		    break; | 
|         |   1166 		case 'E': | 
|         |   1167 		    flags |= SUB_EIND; | 
|         |   1168 		    break; | 
|         |   1169 		case 'N': | 
|         |   1170 		    flags |= SUB_LEN; | 
|         |   1171 		    break; | 
|         |   1172 		case 'S': | 
|         |   1173 		    flags |= SUB_SUBSTR; | 
|         |   1174 		    break; | 
|         |   1175 		case 'I': | 
|         |   1176 		    flnum = get_intarg(&s); | 
|         |   1177 		    if (flnum < 0) | 
|         |   1178 			goto flagerr; | 
|         |   1179 		    break; | 
|         |   1180  | 
|         |   1181 		case 'L': | 
|         |   1182 		    casmod = 2; | 
|         |   1183 		    break; | 
|         |   1184 		case 'U': | 
|         |   1185 		    casmod = 1; | 
|         |   1186 		    break; | 
|         |   1187 		case 'C': | 
|         |   1188 		    casmod = 3; | 
|         |   1189 		    break; | 
|         |   1190  | 
|         |   1191 		case 'o': | 
|         |   1192 		    sortit = 1; | 
|         |   1193 		    break; | 
|         |   1194 		case 'O': | 
|         |   1195 		    sortit = 2; | 
|         |   1196 		    break; | 
|         |   1197 		case 'i': | 
|         |   1198 		    casind = 1; | 
|         |   1199 		    break; | 
|         |   1200 		case 'n': | 
|         |   1201 		    numord = 1; | 
|         |   1202 		    break; | 
|         |   1203 		case 'a': | 
|         |   1204 		    indord = 1; | 
|         |   1205 		    break; | 
|         |   1206  | 
|         |   1207 		case 'V': | 
|         |   1208 		    visiblemod++; | 
|         |   1209 		    break; | 
|         |   1210  | 
|         |   1211 		case 'q': | 
|         |   1212 		    quotemod++, quotetype++; | 
|         |   1213 		    break; | 
|         |   1214 		case 'Q': | 
|         |   1215 		    quotemod--; | 
|         |   1216 		    break; | 
|         |   1217 		case 'X': | 
|         |   1218 		    quoteerr = 1; | 
|         |   1219 		    break; | 
|         |   1220  | 
|         |   1221 		case 'e': | 
|         |   1222 		    eval = 1; | 
|         |   1223 		    break; | 
|         |   1224 		case 'P': | 
|         |   1225 		    aspar = 1; | 
|         |   1226 		    break; | 
|         |   1227  | 
|         |   1228 		case 'c': | 
|         |   1229 		    whichlen = 1; | 
|         |   1230 		    break; | 
|         |   1231 		case 'w': | 
|         |   1232 		    whichlen = 2; | 
|         |   1233 		    break; | 
|         |   1234 		case 'W': | 
|         |   1235 		    whichlen = 3; | 
|         |   1236 		    break; | 
|         |   1237  | 
|         |   1238 		case 'f': | 
|         |   1239 		    spsep = "\n"; | 
|         |   1240 		    break; | 
|         |   1241 		case 'F': | 
|         |   1242 		    sep = "\n"; | 
|         |   1243 		    break; | 
|         |   1244  | 
|         |   1245 		case 's': | 
|         |   1246 		    tt = 1; | 
|         |   1247 		/* fall through */ | 
|         |   1248 		case 'j': | 
|         |   1249 		    t = get_strarg(++s); | 
|         |   1250 		    if (*t) { | 
|         |   1251 			sav = *t; | 
|         |   1252 			*t = '\0'; | 
|         |   1253 			if (tt) | 
|         |   1254 			    UNTOK_AND_ESCAPE(spsep) | 
|         |   1255 			else | 
|         |   1256 			    UNTOK_AND_ESCAPE(sep) | 
|         |   1257 			*t = sav; | 
|         |   1258 			s = t; | 
|         |   1259 		    } else | 
|         |   1260 			goto flagerr; | 
|         |   1261 		    break; | 
|         |   1262  | 
|         |   1263 		case 'l': | 
|         |   1264 		    tt = 1; | 
|         |   1265 		/* fall through */ | 
|         |   1266 		case 'r': | 
|         |   1267 		    sav = s[1]; | 
|         |   1268 		    num = get_intarg(&s); | 
|         |   1269 		    if (num < 0) | 
|         |   1270 			goto flagerr; | 
|         |   1271 		    if (tt) | 
|         |   1272 			prenum = num; | 
|         |   1273 		    else | 
|         |   1274 			postnum = num; | 
|         |   1275 		    if (UNTOK(s[1]) != UNTOK(sav)) | 
|         |   1276 			break; | 
|         |   1277 		    t = get_strarg(++s); | 
|         |   1278 		    if (!*t) | 
|         |   1279 			goto flagerr; | 
|         |   1280 		    sav = *t; | 
|         |   1281 		    *t = '\0'; | 
|         |   1282 		    if (tt) | 
|         |   1283 			UNTOK_AND_ESCAPE(premul) | 
|         |   1284 		    else | 
|         |   1285 			UNTOK_AND_ESCAPE(postmul) | 
|         |   1286 		    *t = sav; | 
|         |   1287 		    sav = *s; | 
|         |   1288 		    s = t + 1; | 
|         |   1289 		    if (UNTOK(*s) != UNTOK(sav)) { | 
|         |   1290 			s--; | 
|         |   1291 			break; | 
|         |   1292 		    } | 
|         |   1293 		    t = get_strarg(s); | 
|         |   1294 		    if (!*t) | 
|         |   1295 			goto flagerr; | 
|         |   1296 		    sav = *t; | 
|         |   1297 		    *t = '\0'; | 
|         |   1298 		    if (tt) | 
|         |   1299 			UNTOK_AND_ESCAPE(preone) | 
|         |   1300 		    else | 
|         |   1301 			UNTOK_AND_ESCAPE(postone) | 
|         |   1302 		    *t = sav; | 
|         |   1303 		    s = t; | 
|         |   1304 		    break; | 
|         |   1305  | 
|         |   1306 		case 'p': | 
|         |   1307 		    escapes = 1; | 
|         |   1308 		    break; | 
|         |   1309  | 
|         |   1310 		case 'k': | 
|         |   1311 		    hkeys = SCANPM_WANTKEYS; | 
|         |   1312 		    break; | 
|         |   1313 		case 'v': | 
|         |   1314 		    hvals = SCANPM_WANTVALS; | 
|         |   1315 		    break; | 
|         |   1316  | 
|         |   1317 		case 't': | 
|         |   1318 		    wantt = 1; | 
|         |   1319 		    break; | 
|         |   1320  | 
|         |   1321 		case '%': | 
|         |   1322 		    presc++; | 
|         |   1323 		    break; | 
|         |   1324  | 
|         |   1325 		case 'z': | 
|         |   1326 		    shsplit = 1; | 
|         |   1327 		    break; | 
|         |   1328  | 
|         |   1329 		case 'u': | 
|         |   1330 		    unique = 1; | 
|         |   1331 		    break; | 
|         |   1332  | 
|         |   1333 		default: | 
|         |   1334 		  flagerr: | 
|         |   1335 		    zerr("error in flags", NULL, 0); | 
|         |   1336 		    return NULL; | 
|         |   1337 		} | 
|         |   1338 	    } | 
|         |   1339 	    s++; | 
|         |   1340 	} | 
|         |   1341     } | 
|         |   1342     /* Sort is done by indexing on sortit-1: | 
|         |   1343      *   bit 1: ascending (o)/descending (O) | 
|         |   1344      *   bit 2: case sensitive/independent (i) | 
|         |   1345      *   bit 3: strict order/numeric (n) | 
|         |   1346      * unless indord (a) is set set, in which case only test for | 
|         |   1347      * descending by assuming only (O) is possible (not verified). | 
|         |   1348      */ | 
|         |   1349     if (sortit) | 
|         |   1350 	sortit += (casind << 1) + (numord << 2); | 
|         |   1351  | 
|         |   1352     /* | 
|         |   1353      * premul, postmul specify the padding character to be used | 
|         |   1354      * multiple times with the (l) and (r) flags respectively. | 
|         |   1355      */ | 
|         |   1356     if (!premul) | 
|         |   1357 	premul = " "; | 
|         |   1358     if (!postmul) | 
|         |   1359 	postmul = " "; | 
|         |   1360  | 
|         |   1361     /* | 
|         |   1362      * Look for special unparenthesised flags. | 
|         |   1363      * TODO: could make these able to appear inside parentheses, too, | 
|         |   1364      * i.e. ${(^)...} etc. | 
|         |   1365      */ | 
|         |   1366     for (;;) { | 
|         |   1367 	if ((c = *s) == '^' || c == Hat) { | 
|         |   1368 	    /* RC_EXPAND_PARAM on or off (doubled )*/ | 
|         |   1369 	    if ((c = *++s) == '^' || c == Hat) { | 
|         |   1370 		plan9 = 0; | 
|         |   1371 		s++; | 
|         |   1372 	    } else | 
|         |   1373 		plan9 = 1; | 
|         |   1374 	} else if ((c = *s) == '=' || c == Equals) { | 
|         |   1375 	    /* SH_WORD_SPLIT on or off (doubled). spbreak = 2 means force */ | 
|         |   1376 	    if ((c = *++s) == '=' || c == Equals) { | 
|         |   1377 		spbreak = 0; | 
|         |   1378 		s++; | 
|         |   1379 	    } else | 
|         |   1380 		spbreak = 2; | 
|         |   1381 	} else if ((c == '#' || c == Pound) && | 
|         |   1382 		   (iident(cc = s[1]) | 
|         |   1383 		    || cc == '*' || cc == Star || cc == '@' | 
|         |   1384 		    || cc == '-' || (cc == ':' && s[2] == '-') | 
|         |   1385 		    || (isstring(cc) && (s[2] == Inbrace || s[2] == Inpar)))) { | 
|         |   1386 	    getlen = 1 + whichlen, s++; | 
|         |   1387 	    /* | 
|         |   1388 	     * Return the length of the parameter. | 
|         |   1389 	     * getlen can be more than 1 to indicate characters (2), | 
|         |   1390 	     * words ignoring multiple delimiters (3), words taking | 
|         |   1391 	     * account of multiple delimiters.  delimiter is in | 
|         |   1392 	     * spsep, NULL means $IFS. | 
|         |   1393 	     */ | 
|         |   1394 	} else if (c == '~' || c == Tilde) { | 
|         |   1395 	    /* GLOB_SUBST on or off (doubled) */ | 
|         |   1396 	    if ((c = *++s) == '~' || c == Tilde) { | 
|         |   1397 		globsubst = 0; | 
|         |   1398 		s++; | 
|         |   1399 	    } else | 
|         |   1400 		globsubst = 1; | 
|         |   1401 	} else if (c == '+') { | 
|         |   1402 	    /* | 
|         |   1403 	     * Return whether indicated parameter is set.  | 
|         |   1404 	     * Try to handle this when parameter is named | 
|         |   1405 	     * by (P) (second part of test). | 
|         |   1406 	     */ | 
|         |   1407 	    if (iident(s[1]) || (aspar && isstring(s[1]) && | 
|         |   1408 				 (s[2] == Inbrace || s[2] == Inpar))) | 
|         |   1409 		chkset = 1, s++; | 
|         |   1410 	    else if (!inbrace) { | 
|         |   1411 		/* Special case for `$+' on its own --- leave unmodified */ | 
|         |   1412 		*aptr = '$'; | 
|         |   1413 		*str = aptr + 1; | 
|         |   1414 		return n; | 
|         |   1415 	    } else { | 
|         |   1416 		zerr("bad substitution", NULL, 0); | 
|         |   1417 		return NULL; | 
|         |   1418 	    } | 
|         |   1419 	} else if (inbrace && INULL(*s)) { | 
|         |   1420 	    /* | 
|         |   1421 	     * Handles things like ${(f)"$(<file)"} by skipping  | 
|         |   1422 	     * the double quotes.  We don't need to know what was | 
|         |   1423 	     * actually there; the presence of a String or Qstring | 
|         |   1424 	     * is good enough. | 
|         |   1425 	     */ | 
|         |   1426 	    s++; | 
|         |   1427 	} else | 
|         |   1428 	    break; | 
|         |   1429     } | 
|         |   1430     /* Don't activate special pattern characters if inside quotes */ | 
|         |   1431     globsubst = globsubst && !qt; | 
|         |   1432  | 
|         |   1433     /* | 
|         |   1434      * At this point, we usually expect a parameter name. | 
|         |   1435      * However, there may be a nested ${...} or $(...). | 
|         |   1436      * These say that the parameter itself is somewhere inside, | 
|         |   1437      * or that there isn't a parameter and we will get the values | 
|         |   1438      * from a command substitution itself.  In either case, | 
|         |   1439      * the current instance of paramsubst() doesn't fetch a value, | 
|         |   1440      * it just operates on what gets passed up. | 
|         |   1441      * (The first ought to have been {...}, reserving ${...} | 
|         |   1442      * for substituting a value at that point, but it's too late now.) | 
|         |   1443      */ | 
|         |   1444     idbeg = s; | 
|         |   1445     if ((subexp = (inbrace && s[-1] && isstring(*s) && | 
|         |   1446 		   (s[1] == Inbrace || s[1] == Inpar)))) { | 
|         |   1447 	int sav; | 
|         |   1448 	int quoted = *s == Qstring; | 
|         |   1449  | 
|         |   1450 	val = s++; | 
|         |   1451 	skipparens(*s, *s == Inpar ? Outpar : Outbrace, &s); | 
|         |   1452 	sav = *s; | 
|         |   1453 	*s = 0; | 
|         |   1454 	/* | 
|         |   1455 	 * This handles arrays.  TODO: this is not the most obscure call to | 
|         |   1456 	 * multsub() (see below) but even so it would be nicer to pass down | 
|         |   1457 	 * and back the arrayness more rationally.  In that case, we should | 
|         |   1458 	 * remove the aspar test and extract a value from an array, if | 
|         |   1459 	 * necessary, when we handle (P) lower down. | 
|         |   1460 	 */ | 
|         |   1461 	if (multsub(&val, (aspar ? NULL : &aval), &isarr, NULL) && quoted) { | 
|         |   1462 	    /* Empty quoted string --- treat as null string, not elided */ | 
|         |   1463 	    isarr = -1; | 
|         |   1464 	    aval = (char **) hcalloc(sizeof(char *)); | 
|         |   1465 	    aspar = 0; | 
|         |   1466 	} else if (aspar) | 
|         |   1467 	    idbeg = val; | 
|         |   1468 	*s = sav; | 
|         |   1469 	/* | 
|         |   1470 	 * This tests for the second double quote in an expression | 
|         |   1471 	 * like ${(f)"$(<file)"}, compare above. | 
|         |   1472 	 */ | 
|         |   1473 	while (INULL(*s)) | 
|         |   1474 	    s++; | 
|         |   1475 	v = (Value) NULL; | 
|         |   1476     } else if (aspar) { | 
|         |   1477 	/* | 
|         |   1478 	 * No subexpression, but in any case the value is going | 
|         |   1479 	 * to give us the name of a parameter on which we do | 
|         |   1480 	 * our remaining processing.  In other words, this | 
|         |   1481 	 * makes ${(P)param} work like ${(P)${param}}.  (Probably | 
|         |   1482 	 * better looked at, this is the basic code for ${(P)param} | 
|         |   1483 	 * and it's been kludged into the subexp code because no | 
|         |   1484 	 * opportunity for a kludge has been neglected.) | 
|         |   1485 	 */ | 
|         |   1486 	if ((v = fetchvalue(&vbuf, &s, 1, (qt ? SCANPM_DQUOTED : 0)))) { | 
|         |   1487 	    val = idbeg = getstrvalue(v); | 
|         |   1488 	    subexp = 1; | 
|         |   1489 	} else | 
|         |   1490 	    vunset = 1; | 
|         |   1491     } | 
|         |   1492     /* | 
|         |   1493      * We need to retrieve a value either if we haven't already | 
|         |   1494      * got it from a subexpression, or if the processing so | 
|         |   1495      * far has just yielded us a parameter name to be processed | 
|         |   1496      * with (P). | 
|         |   1497      */ | 
|         |   1498     if (!subexp || aspar) { | 
|         |   1499 	char *ov = val; | 
|         |   1500  | 
|         |   1501 	/* | 
|         |   1502 	 * Second argument: decide whether to use the subexpression or | 
|         |   1503 	 *   the string next on the line as the parameter name. | 
|         |   1504 	 * Third argument:  decide how processing for brackets | 
|         |   1505 	 *   1 means full processing | 
|         |   1506 	 *   -1 appears to mean something along the lines of | 
|         |   1507 	 *     only handle single digits and don't handle brackets. | 
|         |   1508 	 *     I *think* (but it's really only a guess) that this | 
|         |   1509 	 *     is used by the test below the wantt handling, so | 
|         |   1510 	 *     that in certain cases we handle brackets there. | 
|         |   1511 	 *   0 would apparently mean something like we know we | 
|         |   1512 	 *     should have the name of a scalar and we get cross | 
|         |   1513 	 *     if there's anything present which disagrees with that | 
|         |   1514 	 * but you will search fetchvalue() in vain for comments on this. | 
|         |   1515 	 * Fourth argument gives flags to do with keys, values, quoting, | 
|         |   1516 	 * assigning depending on context and parameter flags. | 
|         |   1517 	 * | 
|         |   1518 	 * This is the last mention of subexp, so presumably this | 
|         |   1519 	 * is what the code which makes sure subexp is set if aspar (the | 
|         |   1520 	 * (P) flag) is set.  I *think* what's going on here is the | 
|         |   1521 	 * second argument is for both input and output: with | 
|         |   1522 	 * subexp, we only want the input effect, whereas normally | 
|         |   1523 	 * we let fetchvalue set the main string pointer s to | 
|         |   1524 	 * the end of the bit it's fetched. | 
|         |   1525 	 */ | 
|         |   1526 	if (!(v = fetchvalue(&vbuf, (subexp ? &ov : &s), | 
|         |   1527 			     (wantt ? -1 : | 
|         |   1528 			      ((unset(KSHARRAYS) || inbrace) ? 1 : -1)), | 
|         |   1529 			     hkeys|hvals| | 
|         |   1530 			     (arrasg ? SCANPM_ASSIGNING : 0)| | 
|         |   1531 			     (qt ? SCANPM_DQUOTED : 0))) || | 
|         |   1532 	    (v->pm && (v->pm->flags & PM_UNSET))) | 
|         |   1533 	    vunset = 1; | 
|         |   1534  | 
|         |   1535 	if (wantt) { | 
|         |   1536 	    /* | 
|         |   1537 	     * Handle the (t) flag: value now becomes the type | 
|         |   1538 	     * information for the parameter. | 
|         |   1539 	     */ | 
|         |   1540 	    if (v && v->pm && !(v->pm->flags & PM_UNSET)) { | 
|         |   1541 		int f = v->pm->flags; | 
|         |   1542  | 
|         |   1543 		switch (PM_TYPE(f)) { | 
|         |   1544 		case PM_SCALAR:  val = "scalar"; break; | 
|         |   1545 		case PM_ARRAY:   val = "array"; break; | 
|         |   1546 		case PM_INTEGER: val = "integer"; break; | 
|         |   1547 		case PM_EFLOAT: | 
|         |   1548 		case PM_FFLOAT:  val = "float"; break; | 
|         |   1549 		case PM_HASHED:  val = "association"; break; | 
|         |   1550 		} | 
|         |   1551 		val = dupstring(val); | 
|         |   1552 		if (v->pm->level) | 
|         |   1553 		    val = dyncat(val, "-local"); | 
|         |   1554 		if (f & PM_LEFT) | 
|         |   1555 		    val = dyncat(val, "-left"); | 
|         |   1556 		if (f & PM_RIGHT_B) | 
|         |   1557 		    val = dyncat(val, "-right_blanks"); | 
|         |   1558 		if (f & PM_RIGHT_Z) | 
|         |   1559 		    val = dyncat(val, "-right_zeros"); | 
|         |   1560 		if (f & PM_LOWER) | 
|         |   1561 		    val = dyncat(val, "-lower"); | 
|         |   1562 		if (f & PM_UPPER) | 
|         |   1563 		    val = dyncat(val, "-upper"); | 
|         |   1564 		if (f & PM_READONLY) | 
|         |   1565 		    val = dyncat(val, "-readonly"); | 
|         |   1566 		if (f & PM_TAGGED) | 
|         |   1567 		    val = dyncat(val, "-tag"); | 
|         |   1568 		if (f & PM_EXPORTED) | 
|         |   1569 		    val = dyncat(val, "-export"); | 
|         |   1570 		if (f & PM_UNIQUE) | 
|         |   1571 		    val = dyncat(val, "-unique"); | 
|         |   1572 		if (f & PM_HIDE) | 
|         |   1573 		    val = dyncat(val, "-hide"); | 
|         |   1574 		if (f & PM_HIDE) | 
|         |   1575 		    val = dyncat(val, "-hideval"); | 
|         |   1576 		if (f & PM_SPECIAL) | 
|         |   1577 		    val = dyncat(val, "-special"); | 
|         |   1578 		vunset = 0; | 
|         |   1579 	    } else | 
|         |   1580 		val = dupstring(""); | 
|         |   1581  | 
|         |   1582 	    v = NULL; | 
|         |   1583 	    isarr = 0; | 
|         |   1584 	} | 
|         |   1585     } | 
|         |   1586     /* | 
|         |   1587      * We get in here two ways; either we need to convert v into | 
|         |   1588      * the local value system, or we need to get rid of brackets | 
|         |   1589      * even if there isn't a v. | 
|         |   1590      */ | 
|         |   1591     while (v || ((inbrace || (unset(KSHARRAYS) && vunset)) && isbrack(*s))) { | 
|         |   1592 	if (!v) { | 
|         |   1593 	    /* | 
|         |   1594 	     * Index applied to non-existent parameter; we may or may | 
|         |   1595 	     * not have a value to index, however.  Create a temporary | 
|         |   1596 	     * empty parameter as a trick, and index on that.  This | 
|         |   1597 	     * usually happens the second time around the loop when | 
|         |   1598 	     * we've used up the original parameter value and want to | 
|         |   1599 	     * apply a subscript to what's left.  However, it's also | 
|         |   1600 	     * possible it's got something to do with some of that murky | 
|         |   1601 	     * passing of -1's as the third argument to fetchvalue() to | 
|         |   1602 	     * inhibit bracket parsing at that stage. | 
|         |   1603 	     */ | 
|         |   1604 	    Param pm; | 
|         |   1605 	    char *os = s; | 
|         |   1606  | 
|         |   1607 	    if (!isbrack(*s)) | 
|         |   1608 		break; | 
|         |   1609 	    if (vunset) { | 
|         |   1610 		val = dupstring(""); | 
|         |   1611 		isarr = 0; | 
|         |   1612 	    } | 
|         |   1613 	    pm = createparam(nulstring, isarr ? PM_ARRAY : PM_SCALAR); | 
|         |   1614 	    DPUTS(!pm, "BUG: parameter not created"); | 
|         |   1615 	    if (isarr) | 
|         |   1616 		pm->u.arr = aval; | 
|         |   1617 	    else | 
|         |   1618 		pm->u.str = val; | 
|         |   1619 	    v = (Value) hcalloc(sizeof *v); | 
|         |   1620 	    v->isarr = isarr; | 
|         |   1621 	    v->pm = pm; | 
|         |   1622 	    v->end = -1; | 
|         |   1623 	    if (getindex(&s, v, qt) || s == os) | 
|         |   1624 		break; | 
|         |   1625 	} | 
|         |   1626 	/* | 
|         |   1627 	 * This is where we extract a value (we know now we have | 
|         |   1628 	 * one) into the local parameters for a scalar (val) or | 
|         |   1629 	 * array (aval) value.  TODO: move val and aval into | 
|         |   1630 	 * a structure with a discriminator.  Hope we can make | 
|         |   1631 	 * more things array values at this point and dearrayify later. | 
|         |   1632 	 * v->isarr tells us whether the stuff form down below looks | 
|         |   1633 	 * like an array.  Unlike multsub() this is probably clean | 
|         |   1634 	 * enough to keep, although possibly the parameter passing | 
|         |   1635 	 * needs reorganising. | 
|         |   1636 	 * | 
|         |   1637 	 * I think we get to discard the existing value of isarr | 
|         |   1638 	 * here because it's already been taken account of, either | 
|         |   1639 	 * in the subexp stuff or immediately above. | 
|         |   1640 	 */ | 
|         |   1641 	if ((isarr = v->isarr)) { | 
|         |   1642 	    /* No way to get here with v->inv != 0, so getvaluearr() * | 
|         |   1643 	     * is called by getarrvalue(); needn't test PM_HASHED.   */ | 
|         |   1644 	    if (v->isarr == SCANPM_WANTINDEX) { | 
|         |   1645 		isarr = v->isarr = 0; | 
|         |   1646 		val = dupstring(v->pm->nam); | 
|         |   1647 	    } else | 
|         |   1648 		aval = getarrvalue(v); | 
|         |   1649 	} else { | 
|         |   1650 	    /* Value retrieved from parameter/subexpression is scalar */ | 
|         |   1651 	    if (v->pm->flags & PM_ARRAY) { | 
|         |   1652 		/* | 
|         |   1653 		 * Although the value is a scalar, the parameter | 
|         |   1654 		 * itself is an array.  Presumably this is due to | 
|         |   1655 		 * being quoted, or doing single substitution or something, | 
|         |   1656 		 * TODO: we're about to do some definitely stringy | 
|         |   1657 		 * stuff, so something like this bit is probably | 
|         |   1658 		 * necessary.  However, I'd like to leave any | 
|         |   1659 		 * necessary joining of arrays until this point | 
|         |   1660 		 * to avoid the multsub() horror. | 
|         |   1661 		 */ | 
|         |   1662 		int tmplen = arrlen(v->pm->gsu.a->getfn(v->pm)); | 
|         |   1663  | 
|         |   1664 		if (v->start < 0) | 
|         |   1665 		    v->start += tmplen + v->inv; | 
|         |   1666 		if (!v->inv && (v->start >= tmplen || v->start < 0)) | 
|         |   1667 		    vunset = 1; | 
|         |   1668 	    } | 
|         |   1669 	    if (!vunset) { | 
|         |   1670 		/* | 
|         |   1671 		 * There really is a value.  Apply any necessary | 
|         |   1672 		 * padding or case transformation.  Note these | 
|         |   1673 		 * are the per-parameter transformations specified | 
|         |   1674 		 * with typeset, not the per-substitution ones set | 
|         |   1675 		 * by flags.  TODO: maybe therefore this would | 
|         |   1676 		 * be more consistent if moved into getstrvalue()? | 
|         |   1677 		 * Bet that's easier said than done. | 
|         |   1678 		 */ | 
|         |   1679 		val = getstrvalue(v); | 
|         |   1680 		fwidth = v->pm->width ? v->pm->width : (int)strlen(val); | 
|         |   1681 		switch (v->pm->flags & (PM_LEFT | PM_RIGHT_B | PM_RIGHT_Z)) { | 
|         |   1682 		    char *t; | 
|         |   1683 		    unsigned int t0; | 
|         |   1684  | 
|         |   1685 		case PM_LEFT: | 
|         |   1686 		case PM_LEFT | PM_RIGHT_Z: | 
|         |   1687 		    t = val; | 
|         |   1688 		    if (v->pm->flags & PM_RIGHT_Z) | 
|         |   1689 			while (*t == '0') | 
|         |   1690 			    t++; | 
|         |   1691 		    else | 
|         |   1692 			while (iblank(*t)) | 
|         |   1693 			    t++; | 
|         |   1694 		    val = (char *) hcalloc(fwidth + 1); | 
|         |   1695 		    val[fwidth] = '\0'; | 
|         |   1696 		    if ((t0 = strlen(t)) > fwidth) | 
|         |   1697 			t0 = fwidth; | 
|         |   1698 		    memset(val, ' ', fwidth); | 
|         |   1699 		    strncpy(val, t, t0); | 
|         |   1700 		    break; | 
|         |   1701 		case PM_RIGHT_B: | 
|         |   1702 		case PM_RIGHT_Z: | 
|         |   1703 		case PM_RIGHT_Z | PM_RIGHT_B: | 
|         |   1704 		    { | 
|         |   1705 			int zero = 1; | 
|         |   1706  | 
|         |   1707 			if (strlen(val) < fwidth) { | 
|         |   1708 			    char *valprefend = val; | 
|         |   1709 			    if (v->pm->flags & PM_RIGHT_Z) { | 
|         |   1710 				/* | 
|         |   1711 				 * This is a documented feature: when deciding | 
|         |   1712 				 * whether to pad with zeroes, ignore | 
|         |   1713 				 * leading blanks already in the value; | 
|         |   1714 				 * only look for numbers after that. | 
|         |   1715 				 * Not sure how useful this really is. | 
|         |   1716 				 * It's certainly confusing to code around. | 
|         |   1717 				 */ | 
|         |   1718 				for (t = val; iblank(*t); t++) | 
|         |   1719 				    ; | 
|         |   1720 				/* | 
|         |   1721 				 * Allow padding after initial minus | 
|         |   1722 				 * for numeric variables. | 
|         |   1723 				 */ | 
|         |   1724 				if ((v->pm->flags & | 
|         |   1725 				     (PM_INTEGER|PM_EFLOAT|PM_FFLOAT)) && | 
|         |   1726 				    *t == '-') | 
|         |   1727 				    t++; | 
|         |   1728 				/* | 
|         |   1729 				 * Allow padding after initial 0x or | 
|         |   1730 				 * base# for integer variables. | 
|         |   1731 				 */ | 
|         |   1732 				if (v->pm->flags & PM_INTEGER) { | 
|         |   1733 				    if (isset(CBASES) && | 
|         |   1734 					t[0] == '0' && t[1] == 'x') | 
|         |   1735 					t += 2; | 
|         |   1736 				    else if ((valprefend = strchr(t, '#'))) | 
|         |   1737 					t = valprefend + 1; | 
|         |   1738 				} | 
|         |   1739 				valprefend = t; | 
|         |   1740 				if (!*t) | 
|         |   1741 				    zero = 0; | 
|         |   1742 				else if (v->pm->flags & | 
|         |   1743 					 (PM_INTEGER|PM_EFLOAT|PM_FFLOAT)) { | 
|         |   1744 				    /* zero always OK */ | 
|         |   1745 				} else if (!idigit(*t)) | 
|         |   1746 				    zero = 0; | 
|         |   1747 			    } | 
|         |   1748 			    t = (char *) hcalloc(fwidth + 1); | 
|         |   1749 			    memset(t, (((v->pm->flags & PM_RIGHT_B) || !zero) ? | 
|         |   1750 				       ' ' : '0'), fwidth); | 
|         |   1751 			    /* | 
|         |   1752 			     * How can the following trigger?  We | 
|         |   1753 			     * haven't altered val or fwidth since | 
|         |   1754 			     * the last time we tested this. | 
|         |   1755 			     */ | 
|         |   1756 			    if ((t0 = strlen(val)) > fwidth) | 
|         |   1757 				t0 = fwidth; | 
|         |   1758 			    /* | 
|         |   1759 			     * Copy - or 0x or base# before any padding | 
|         |   1760 			     * zeroes. | 
|         |   1761 			     */ | 
|         |   1762 			    if (zero && val != valprefend) { | 
|         |   1763 				int preflen = valprefend - val; | 
|         |   1764 				memcpy(t, val, preflen); | 
|         |   1765 				strcpy(t + (fwidth - t0) + preflen, | 
|         |   1766 				       valprefend); | 
|         |   1767 			    } else | 
|         |   1768 				strcpy(t + (fwidth - t0), val); | 
|         |   1769 			    val = t; | 
|         |   1770 			} else { | 
|         |   1771 			    t = (char *) hcalloc(fwidth + 1); | 
|         |   1772 			    t[fwidth] = '\0'; | 
|         |   1773 			    strncpy(t, val + strlen(val) - fwidth, fwidth); | 
|         |   1774 			    val = t; | 
|         |   1775 			} | 
|         |   1776 		    } | 
|         |   1777 		    break; | 
|         |   1778 		} | 
|         |   1779 		switch (v->pm->flags & (PM_LOWER | PM_UPPER)) { | 
|         |   1780 		    char *t; | 
|         |   1781  | 
|         |   1782 		case PM_LOWER: | 
|         |   1783 		    t = val; | 
|         |   1784 		    for (; (c = *t); t++) | 
|         |   1785 			*t = tulower(c); | 
|         |   1786 		    break; | 
|         |   1787 		case PM_UPPER: | 
|         |   1788 		    t = val; | 
|         |   1789 		    for (; (c = *t); t++) | 
|         |   1790 			*t = tuupper(c); | 
|         |   1791 		    break; | 
|         |   1792 		} | 
|         |   1793 	    } | 
|         |   1794 	} | 
|         |   1795 	/* | 
|         |   1796 	 * Finished with the original parameter and its indices; | 
|         |   1797 	 * carry on looping to see if we need to do more indexing. | 
|         |   1798 	 * This means we final get rid of v in favour of val and | 
|         |   1799 	 * aval.  We could do with somehow encapsulating the bit | 
|         |   1800 	 * where we need v. | 
|         |   1801 	 */ | 
|         |   1802 	v = NULL; | 
|         |   1803 	if (!inbrace) | 
|         |   1804 	    break; | 
|         |   1805     } | 
|         |   1806     /* | 
|         |   1807      * We're now past the name or subexpression; the only things | 
|         |   1808      * which can happen now are a closing brace, one of the standard | 
|         |   1809      * parameter postmodifiers, or a history-style colon-modifier. | 
|         |   1810      * | 
|         |   1811      * Again, this duplicates tests for characters we're about to | 
|         |   1812      * examine properly later on. | 
|         |   1813      */ | 
|         |   1814     if (inbrace && | 
|         |   1815 	(c = *s) != '-' && c != '+' && c != ':' && c != '%'  && c != '/' && | 
|         |   1816 	c != '=' && c != Equals && | 
|         |   1817 	c != '#' && c != Pound && | 
|         |   1818 	c != '?' && c != Quest && | 
|         |   1819 	c != '}' && c != Outbrace) { | 
|         |   1820 	zerr("bad substitution", NULL, 0); | 
|         |   1821 	return NULL; | 
|         |   1822     } | 
|         |   1823     /* | 
|         |   1824      * Join arrays up if we're in quotes and there isn't some | 
|         |   1825      * override such as (@). | 
|         |   1826      * TODO: hmm, if we're called as part of some recursive | 
|         |   1827      * substitution do we want to delay this until we get back to | 
|         |   1828      * the top level?  Or is if there's a qt (i.e. this parameter | 
|         |   1829      * substitution is in quotes) always good enough?  Potentially | 
|         |   1830      * we may be OK by now --- all potential `@'s and subexpressions | 
|         |   1831      * have been handled, including any [@] index which comes up | 
|         |   1832      * by virture of v->isarr being set to SCANPM_ISVAR_AT which | 
|         |   1833      * is now in isarr. | 
|         |   1834      * | 
|         |   1835      * However, if we are replacing multsub() with something that | 
|         |   1836      * doesn't mangle arrays, we may need to delay this step until after | 
|         |   1837      * the foo:- or foo:= or whatever that causes that.  Note the value | 
|         |   1838      * (string or array) at this point is irrelevant if we are going to | 
|         |   1839      * be doing that.  This would mean // and stuff get applied | 
|         |   1840      * arraywise even if quoted.  That's probably wrong, so maybe | 
|         |   1841      * this just stays. | 
|         |   1842      * | 
|         |   1843      * We do a separate stage of dearrayification in the YUK chunk, | 
|         |   1844      * I think mostly because of the way we make array or scalar | 
|         |   1845      * values appear to the caller. | 
|         |   1846      */ | 
|         |   1847     if (isarr) { | 
|         |   1848 	if (nojoin) | 
|         |   1849 	    isarr = -1; | 
|         |   1850 	if (qt && !getlen && isarr > 0) { | 
|         |   1851 	    val = sepjoin(aval, sep, 1); | 
|         |   1852 	    isarr = 0; | 
|         |   1853 	} | 
|         |   1854     } | 
|         |   1855  | 
|         |   1856     idend = s; | 
|         |   1857     if (inbrace) { | 
|         |   1858 	/* | 
|         |   1859 	 * This is to match a closing double quote in case | 
|         |   1860 	 * we didn't have a subexpression, e.g. ${"foo"}. | 
|         |   1861 	 * This form is pointless, but logically it ought to work. | 
|         |   1862 	 */ | 
|         |   1863 	while (INULL(*s)) | 
|         |   1864 	    s++; | 
|         |   1865     } | 
|         |   1866     /* | 
|         |   1867      * We don't yet know whether a `:' introduces a history-style | 
|         |   1868      * colon modifier or qualifies something like ${...:=...}. | 
|         |   1869      * But if we remember the colon here it's easy to check later. | 
|         |   1870      */ | 
|         |   1871     if ((colf = *s == ':')) | 
|         |   1872 	s++; | 
|         |   1873  | 
|         |   1874  | 
|         |   1875     /* fstr is to be the text following the substitution.  If we have * | 
|         |   1876      * braces, we look for it here, else we infer it later on.        */ | 
|         |   1877     fstr = s; | 
|         |   1878     if (inbrace) { | 
|         |   1879 	int bct; | 
|         |   1880 	for (bct = 1; (c = *fstr); fstr++) { | 
|         |   1881 	    if (c == Inbrace) | 
|         |   1882 		bct++; | 
|         |   1883 	    else if (c == Outbrace && !--bct) | 
|         |   1884 		break; | 
|         |   1885 	} | 
|         |   1886  | 
|         |   1887 	if (bct) { | 
|         |   1888 	noclosebrace: | 
|         |   1889 	    zerr("closing brace expected", NULL, 0); | 
|         |   1890 	    return NULL; | 
|         |   1891 	} | 
|         |   1892 	if (c) | 
|         |   1893 	    *fstr++ = '\0'; | 
|         |   1894     } | 
|         |   1895  | 
|         |   1896     /* Check for ${..?..} or ${..=..} or one of those. * | 
|         |   1897      * Only works if the name is in braces.            */ | 
|         |   1898  | 
|         |   1899     if (inbrace && ((c = *s) == '-' || | 
|         |   1900 		    c == '+' || | 
|         |   1901 		    c == ':' ||	/* i.e. a doubled colon */ | 
|         |   1902 		    c == '=' || c == Equals || | 
|         |   1903 		    c == '%' || | 
|         |   1904 		    c == '#' || c == Pound || | 
|         |   1905 		    c == '?' || c == Quest || | 
|         |   1906 		    c == '/')) { | 
|         |   1907  | 
|         |   1908 	/* | 
|         |   1909 	 * Default index is 1 if no (I) or (I) gave zero.   But | 
|         |   1910 	 * why don't we set the default explicitly at the start | 
|         |   1911 	 * and massage any passed index where we set flnum anyway? | 
|         |   1912 	 */ | 
|         |   1913 	if (!flnum) | 
|         |   1914 	    flnum++; | 
|         |   1915 	if (c == '%') | 
|         |   1916 	    flags |= SUB_END; | 
|         |   1917  | 
|         |   1918 	/* Check for ${..%%..} or ${..##..} */ | 
|         |   1919 	if ((c == '%' || c == '#' || c == Pound) && c == s[1]) { | 
|         |   1920 	    s++; | 
|         |   1921 	    /* we have %%, not %, or ##, not # */ | 
|         |   1922 	    flags |= SUB_LONG; | 
|         |   1923 	} | 
|         |   1924 	s++; | 
|         |   1925 	if (s[-1] == '/') { | 
|         |   1926 	    char *ptr; | 
|         |   1927 	    /* | 
|         |   1928 	     * previous flags are irrelevant, except for (S) which | 
|         |   1929 	     * indicates shortest substring; else look for longest. | 
|         |   1930 	     */ | 
|         |   1931 	    flags = (flags & SUB_SUBSTR) ? 0 : SUB_LONG; | 
|         |   1932 	    if ((c = *s) == '/') { | 
|         |   1933 		/* doubled, so replace all occurrences */ | 
|         |   1934 		flags |= SUB_GLOBAL; | 
|         |   1935 		c = *++s; | 
|         |   1936 	    } | 
|         |   1937 	    /* Check for anchored substitution */ | 
|         |   1938 	    if (c == '%') { | 
|         |   1939 		/* anchor at tail */ | 
|         |   1940 		flags |= SUB_END; | 
|         |   1941 		s++; | 
|         |   1942 	    } else if (c == '#' || c == Pound) { | 
|         |   1943 		/* anchor at head: this is the `normal' case in getmatch */ | 
|         |   1944 		s++; | 
|         |   1945 	    } else | 
|         |   1946 		flags |= SUB_SUBSTR; | 
|         |   1947 	    /* | 
|         |   1948 	     * Find the / marking the end of the search pattern. | 
|         |   1949 	     * If there isn't one, we're just going to delete that, | 
|         |   1950 	     * i.e. replace it with an empty string. | 
|         |   1951 	     * | 
|         |   1952 	     * We used to use double backslashes to quote slashes, | 
|         |   1953 	     * but actually that was buggy and using a single backslash | 
|         |   1954 	     * is easier and more obvious. | 
|         |   1955 	     */ | 
|         |   1956 	    for (ptr = s; (c = *ptr) && c != '/'; ptr++) | 
|         |   1957 	    { | 
|         |   1958 		if ((c == Bnull || c == '\\') && ptr[1]) | 
|         |   1959 		{ | 
|         |   1960 		    if (ptr[1] == '/') | 
|         |   1961 			chuck(ptr); | 
|         |   1962 		    else | 
|         |   1963 			ptr++; | 
|         |   1964 		} | 
|         |   1965 	    } | 
|         |   1966 	    replstr = (*ptr && ptr[1]) ? ptr+1 : ""; | 
|         |   1967 	    *ptr = '\0'; | 
|         |   1968 	} | 
|         |   1969  | 
|         |   1970 	/* See if this was ${...:-...}, ${...:=...}, etc. */ | 
|         |   1971 	if (colf) | 
|         |   1972 	    flags |= SUB_ALL; | 
|         |   1973 	/* | 
|         |   1974 	 * With no special flags, i.e. just a # or % or whatever, | 
|         |   1975 	 * the matched portion is removed and we keep the rest. | 
|         |   1976 	 * We also want the rest when we're doing a substitution. | 
|         |   1977 	 */ | 
|         |   1978 	if (!(flags & (SUB_MATCH|SUB_REST|SUB_BIND|SUB_EIND|SUB_LEN))) | 
|         |   1979 	    flags |= SUB_REST; | 
|         |   1980  | 
|         |   1981 	if (colf && !vunset) | 
|         |   1982 	    vunset = (isarr) ? !*aval : !*val || (*val == Nularg && !val[1]); | 
|         |   1983  | 
|         |   1984 	switch (s[-1]) { | 
|         |   1985 	case '+': | 
|         |   1986 	    if (vunset) { | 
|         |   1987 		val = dupstring(""); | 
|         |   1988 		copied = 1; | 
|         |   1989 		isarr = 0; | 
|         |   1990 		break; | 
|         |   1991 	    } | 
|         |   1992 	    vunset = 1; | 
|         |   1993 	/* Fall Through! */ | 
|         |   1994 	case '-': | 
|         |   1995 	    if (vunset) { | 
|         |   1996 		val = dupstring(s); | 
|         |   1997 		/* | 
|         |   1998 		 * This is not good enough for sh emulation!  Sh would | 
|         |   1999 		 * split unquoted substrings, yet not split quoted ones | 
|         |   2000 		 * (except according to $@ rules); but this leaves the | 
|         |   2001 		 * unquoted substrings unsplit, and other code below | 
|         |   2002 		 * for spbreak splits even within the quoted substrings. | 
|         |   2003 		 * | 
|         |   2004 		 * TODO: I think multsub needs to be told enough to | 
|         |   2005 		 * decide about splitting with spbreak at this point | 
|         |   2006 		 * (and equally in the `=' handler below).  Then | 
|         |   2007 		 * we can turn off spbreak to avoid the join & split | 
|         |   2008 		 * nastiness later. | 
|         |   2009 		 * | 
|         |   2010 		 * What we really want to do is make this look as | 
|         |   2011 		 * if it were the result of an assignment from | 
|         |   2012 		 * the same value, taking account of quoting. | 
|         |   2013 		 */ | 
|         |   2014 		multsub(&val, (aspar ? NULL : &aval), &isarr, NULL); | 
|         |   2015 		copied = 1; | 
|         |   2016 	    } | 
|         |   2017 	    break; | 
|         |   2018 	case ':': | 
|         |   2019 	    /* this must be `::=', unconditional assignment */ | 
|         |   2020 	    if (*s != '=' && *s != Equals) | 
|         |   2021 		goto noclosebrace; | 
|         |   2022 	    vunset = 1; | 
|         |   2023 	    s++; | 
|         |   2024 	    /* Fall through */ | 
|         |   2025 	case '=': | 
|         |   2026 	case Equals: | 
|         |   2027 	    if (vunset) { | 
|         |   2028 		char sav = *idend; | 
|         |   2029 		int l; | 
|         |   2030  | 
|         |   2031 		*idend = '\0'; | 
|         |   2032 		val = dupstring(s); | 
|         |   2033 		isarr = 0; | 
|         |   2034 		/* | 
|         |   2035 		 * TODO: this is one of those places where I don't | 
|         |   2036 		 * think we want to do the joining until later on. | 
|         |   2037 		 * We also need to handle spbreak and spsep at this | 
|         |   2038 		 * point and unset them. | 
|         |   2039 		 */ | 
|         |   2040 		if (spsep || spbreak || !arrasg) | 
|         |   2041 		    multsub(&val, NULL, NULL, sep); | 
|         |   2042 		else | 
|         |   2043 		    multsub(&val, &aval, &isarr, NULL); | 
|         |   2044 		if (arrasg) { | 
|         |   2045 		    /* | 
|         |   2046 		     * This is an array assignment in a context | 
|         |   2047 		     * where we have no syntactic way of finding | 
|         |   2048 		     * out what an array element is.  So we just guess. | 
|         |   2049 		     */ | 
|         |   2050 		    char *arr[2], **t, **a, **p; | 
|         |   2051 		    if (spsep || spbreak) { | 
|         |   2052 			aval = sepsplit(val, spsep, 0, 1); | 
|         |   2053 			isarr = 2; | 
|         |   2054 			l = arrlen(aval); | 
|         |   2055 			if (l && !*(aval[l-1])) | 
|         |   2056 			    l--; | 
|         |   2057 			if (l && !**aval) | 
|         |   2058 			    l--, t = aval + 1; | 
|         |   2059 			else | 
|         |   2060 			    t = aval; | 
|         |   2061 		    } else if (!isarr) { | 
|         |   2062 			if (!*val && arrasg > 1) { | 
|         |   2063 			    arr[0] = NULL; | 
|         |   2064 			    l = 0; | 
|         |   2065 			} else { | 
|         |   2066 			    arr[0] = val; | 
|         |   2067 			    arr[1] = NULL; | 
|         |   2068 			    l = 1; | 
|         |   2069 			} | 
|         |   2070 			t = aval = arr; | 
|         |   2071 		    } else | 
|         |   2072 			l = arrlen(aval), t = aval; | 
|         |   2073 		    p = a = zalloc(sizeof(char *) * (l + 1)); | 
|         |   2074 		    while (l--) { | 
|         |   2075 			untokenize(*t); | 
|         |   2076 			*p++ = ztrdup(*t++); | 
|         |   2077 		    } | 
|         |   2078 		    *p++ = NULL; | 
|         |   2079 		    if (arrasg > 1) { | 
|         |   2080 			Param pm = sethparam(idbeg, a); | 
|         |   2081 			if (pm) | 
|         |   2082 			    aval = paramvalarr(pm->gsu.h->getfn(pm), hkeys|hvals); | 
|         |   2083 		    } else | 
|         |   2084 			setaparam(idbeg, a); | 
|         |   2085 		} else { | 
|         |   2086 		    untokenize(val); | 
|         |   2087 		    setsparam(idbeg, ztrdup(val)); | 
|         |   2088 		} | 
|         |   2089 		*idend = sav; | 
|         |   2090 		copied = 1; | 
|         |   2091 		if (isarr) { | 
|         |   2092 		  if (nojoin) | 
|         |   2093 		    isarr = -1; | 
|         |   2094 		  if (qt && !getlen && isarr > 0 && !spsep && spbreak < 2) { | 
|         |   2095 		    val = sepjoin(aval, sep, 1); | 
|         |   2096 		    isarr = 0; | 
|         |   2097 		  } | 
|         |   2098 		  sep = spsep = NULL; | 
|         |   2099 		  spbreak = 0; | 
|         |   2100 		} | 
|         |   2101 	    } | 
|         |   2102 	    break; | 
|         |   2103 	case '?': | 
|         |   2104 	case Quest: | 
|         |   2105 	    if (vunset) { | 
|         |   2106 		char *msg; | 
|         |   2107  | 
|         |   2108 		*idend = '\0'; | 
|         |   2109 		msg = tricat(idbeg, ": ", *s ? s : "parameter not set"); | 
|         |   2110 		zerr("%s", msg, 0); | 
|         |   2111 		zsfree(msg); | 
|         |   2112 		if (!interact) | 
|         |   2113 		    exit(1); | 
|         |   2114 		return NULL; | 
|         |   2115 	    } | 
|         |   2116 	    break; | 
|         |   2117 	case '%': | 
|         |   2118 	case '#': | 
|         |   2119 	case Pound: | 
|         |   2120 	case '/': | 
|         |   2121             /* This once was executed only `if (qt) ...'. But with that | 
|         |   2122              * patterns in a expansion resulting from a ${(e)...} aren't | 
|         |   2123              * tokenized even though this function thinks they are (it thinks | 
|         |   2124              * they are because subst_parse_str() turns Qstring tokens | 
|         |   2125              * into String tokens and for unquoted parameter expansions the | 
|         |   2126              * lexer normally does tokenize patterns inside parameter | 
|         |   2127              * expansions). */ | 
|         |   2128             { | 
|         |   2129 		int one = noerrs, oef = errflag, haserr; | 
|         |   2130  | 
|         |   2131 		if (!quoteerr) | 
|         |   2132 		    noerrs = 1; | 
|         |   2133 		haserr = parse_subst_string(s); | 
|         |   2134 		noerrs = one; | 
|         |   2135 		if (!quoteerr) { | 
|         |   2136 		    errflag = oef; | 
|         |   2137 		    if (haserr) | 
|         |   2138 			shtokenize(s); | 
|         |   2139 		} else if (haserr || errflag) { | 
|         |   2140 		    zerr("parse error in ${...%c...} substitution", | 
|         |   2141 			 NULL, s[-1]); | 
|         |   2142 		    return NULL; | 
|         |   2143 		} | 
|         |   2144 	    } | 
|         |   2145 	    { | 
|         |   2146 #if 0 | 
|         |   2147 		/* | 
|         |   2148 		 * This allows # and % to be at the start of | 
|         |   2149 		 * a parameter in the substitution, which is | 
|         |   2150 		 * a bit nasty, and can be done (although | 
|         |   2151 		 * less efficiently) with anchors. | 
|         |   2152 		 */ | 
|         |   2153  | 
|         |   2154 		char t = s[-1]; | 
|         |   2155  | 
|         |   2156 		singsub(&s); | 
|         |   2157  | 
|         |   2158 		if (t == '/' && (flags & SUB_SUBSTR)) { | 
|         |   2159 		    if ((c = *s) == '#' || c == '%') { | 
|         |   2160 			flags &= ~SUB_SUBSTR; | 
|         |   2161 			if (c == '%') | 
|         |   2162 			    flags |= SUB_END; | 
|         |   2163 			s++; | 
|         |   2164 		    } else if (c == '\\') { | 
|         |   2165 			s++; | 
|         |   2166 		    } | 
|         |   2167 		} | 
|         |   2168 #else | 
|         |   2169 		singsub(&s); | 
|         |   2170 #endif | 
|         |   2171 	    } | 
|         |   2172  | 
|         |   2173 	    /* | 
|         |   2174 	     * Either loop over an array doing replacements or | 
|         |   2175 	     * do the replacment on a string. | 
|         |   2176 	     */ | 
|         |   2177 	    if (!vunset && isarr) { | 
|         |   2178 		getmatcharr(&aval, s, flags, flnum, replstr); | 
|         |   2179 		copied = 1; | 
|         |   2180 	    } else { | 
|         |   2181 		if (vunset) | 
|         |   2182 		    val = dupstring(""); | 
|         |   2183 		getmatch(&val, s, flags, flnum, replstr); | 
|         |   2184 		copied = 1; | 
|         |   2185 	    } | 
|         |   2186 	    break; | 
|         |   2187 	} | 
|         |   2188     } else {			/* no ${...=...} or anything, but possible modifiers. */ | 
|         |   2189 	/* | 
|         |   2190 	 * Handler ${+...}.  TODO: strange, why do we handle this only | 
|         |   2191 	 * if there isn't a trailing modifier?  Why don't we do this | 
|         |   2192 	 * e.g. when we hanlder the ${(t)...} flag? | 
|         |   2193 	 */ | 
|         |   2194 	if (chkset) { | 
|         |   2195 	    val = dupstring(vunset ? "0" : "1"); | 
|         |   2196 	    isarr = 0; | 
|         |   2197 	} else if (vunset) { | 
|         |   2198 	    if (unset(UNSET)) { | 
|         |   2199 		*idend = '\0'; | 
|         |   2200 		zerr("%s: parameter not set", idbeg, 0); | 
|         |   2201 		return NULL; | 
|         |   2202 	    } | 
|         |   2203 	    val = dupstring(""); | 
|         |   2204 	} | 
|         |   2205 	if (colf) { | 
|         |   2206 	    /* | 
|         |   2207 	     * History style colon modifiers.  May need to apply | 
|         |   2208 	     * on multiple elements of an array. | 
|         |   2209 	     */ | 
|         |   2210 	    s--; | 
|         |   2211 	    if (unset(KSHARRAYS) || inbrace) { | 
|         |   2212 		if (!isarr) | 
|         |   2213 		    modify(&val, &s); | 
|         |   2214 		else { | 
|         |   2215 		    char *ss; | 
|         |   2216 		    char **ap = aval; | 
|         |   2217 		    char **pp = aval = (char **) hcalloc(sizeof(char *) * | 
|         |   2218 							 (arrlen(aval) + 1)); | 
|         |   2219  | 
|         |   2220 		    while ((*pp = *ap++)) { | 
|         |   2221 			ss = s; | 
|         |   2222 			modify(pp++, &ss); | 
|         |   2223 		    } | 
|         |   2224 		    if (pp == aval) { | 
|         |   2225 			char *t = ""; | 
|         |   2226 			ss = s; | 
|         |   2227 			modify(&t, &ss); | 
|         |   2228 		    } | 
|         |   2229 		    s = ss; | 
|         |   2230 		} | 
|         |   2231 		copied = 1; | 
|         |   2232 		if (inbrace && *s) { | 
|         |   2233 		    if (*s == ':' && !imeta(s[1])) | 
|         |   2234 			zerr("unrecognized modifier `%c'", NULL, s[1]); | 
|         |   2235 		    else | 
|         |   2236 			zerr("unrecognized modifier", NULL, 0); | 
|         |   2237 		    return NULL; | 
|         |   2238 		} | 
|         |   2239 	    } | 
|         |   2240 	} | 
|         |   2241 	if (!inbrace) | 
|         |   2242 	    fstr = s; | 
|         |   2243     } | 
|         |   2244     if (errflag) | 
|         |   2245 	return NULL; | 
|         |   2246     /* | 
|         |   2247      * This handles taking a length with ${#foo} and variations. | 
|         |   2248      * TODO: again. one might naively have thought this had the | 
|         |   2249      * same sort of effect as the ${(t)...} flag and the ${+...} | 
|         |   2250      * test, although in this case we do need the value rather | 
|         |   2251      * the the parameter, so maybe it's a bit different. | 
|         |   2252      */ | 
|         |   2253     if (getlen) { | 
|         |   2254 	long len = 0; | 
|         |   2255 	char buf[14]; | 
|         |   2256  | 
|         |   2257 	if (isarr) { | 
|         |   2258 	    char **ctr; | 
|         |   2259 	    int sl = sep ? ztrlen(sep) : 1; | 
|         |   2260  | 
|         |   2261 	    if (getlen == 1) | 
|         |   2262 		for (ctr = aval; *ctr; ctr++, len++); | 
|         |   2263 	    else if (getlen == 2) { | 
|         |   2264 		if (*aval) | 
|         |   2265 		    for (len = -sl, ctr = aval; | 
|         |   2266 			 len += sl + ztrlen(*ctr), *++ctr;); | 
|         |   2267 	    } | 
|         |   2268 	    else | 
|         |   2269 		for (ctr = aval; | 
|         |   2270 		     *ctr; | 
|         |   2271 		     len += wordcount(*ctr, spsep, getlen > 3), ctr++); | 
|         |   2272 	} else { | 
|         |   2273 	    if (getlen < 3) | 
|         |   2274 		len = ztrlen(val); | 
|         |   2275 	    else | 
|         |   2276 		len = wordcount(val, spsep, getlen > 3); | 
|         |   2277 	} | 
|         |   2278  | 
|         |   2279 	sprintf(buf, "%ld", len); | 
|         |   2280 	val = dupstring(buf); | 
|         |   2281 	isarr = 0; | 
|         |   2282     } | 
|         |   2283     /* | 
|         |   2284      * I think this mult_isarr stuff here is used to pass back | 
|         |   2285      * the setting of whether we are an array to multsub, and | 
|         |   2286      * thence to the top-level paramsubst().  The way the | 
|         |   2287      * setting is passed back is completely obscure, however. | 
|         |   2288      * It's presumably at this point because we try to remember | 
|         |   2289      * whether the value was `really' an array before massaging | 
|         |   2290      * some special cases. | 
|         |   2291      * | 
|         |   2292      * TODO: YUK.  This is not the right place to turn arrays into | 
|         |   2293      * scalars; we should pass back as an array, and let the calling | 
|         |   2294      * code decide how to deal with it.  This is almost certainly | 
|         |   2295      * a lot harder than it sounds.  Do we really need to handle | 
|         |   2296      * one-element arrays as scalars at this point?  Couldn't | 
|         |   2297      * we just test for it later rather than having a multiple-valued | 
|         |   2298      * wave-function for isarr? | 
|         |   2299      */ | 
|         |   2300     mult_isarr = isarr; | 
|         |   2301     if (isarr > 0 && !plan9 && (!aval || !aval[0])) { | 
|         |   2302 	val = dupstring(""); | 
|         |   2303 	isarr = 0; | 
|         |   2304     } else if (isarr && aval && aval[0] && !aval[1]) { | 
|         |   2305 	/* treat a one-element array as a scalar for purposes of   * | 
|         |   2306 	 * concatenation with surrounding text (some${param}thing) * | 
|         |   2307 	 * and rc_expand_param handling.  Note: mult_isarr (above) * | 
|         |   2308 	 * propagates the true array type from nested expansions.  */ | 
|         |   2309 	val = aval[0]; | 
|         |   2310 	isarr = 0; | 
|         |   2311     } | 
|         |   2312     /* ssub is true when we are called from singsub (via prefork). | 
|         |   2313      * It means that we must join arrays and should not split words. */ | 
|         |   2314     /* | 
|         |   2315      * TODO: this is what is screwing up the use of SH_WORD_SPLIT | 
|         |   2316      * after `:-' etc.  If we fix multsub(), we might get away | 
|         |   2317      * with simply unsetting the appropriate flags when they | 
|         |   2318      * get handled. | 
|         |   2319      */ | 
|         |   2320     if (ssub || spbreak || spsep || sep) { | 
|         |   2321 	if (isarr) | 
|         |   2322 	    val = sepjoin(aval, sep, 1), isarr = 0; | 
|         |   2323 	if (!ssub && (spbreak || spsep)) { | 
|         |   2324 	    aval = sepsplit(val, spsep, 0, 1); | 
|         |   2325 	    if (!aval || !aval[0]) | 
|         |   2326 		val = dupstring(""); | 
|         |   2327 	    else if (!aval[1]) | 
|         |   2328 		val = aval[0]; | 
|         |   2329 	    else | 
|         |   2330 		isarr = 2; | 
|         |   2331 	} | 
|         |   2332 	mult_isarr = isarr; | 
|         |   2333     } | 
|         |   2334     /* | 
|         |   2335      * Perform case modififications. | 
|         |   2336      */ | 
|         |   2337     if (casmod) { | 
|         |   2338 	if (isarr) { | 
|         |   2339 	    char **ap; | 
|         |   2340  | 
|         |   2341 	    if (!copied) | 
|         |   2342 		aval = arrdup(aval), copied = 1; | 
|         |   2343 	    ap = aval; | 
|         |   2344  | 
|         |   2345 	    if (casmod == 1) | 
|         |   2346 		for (; *ap; ap++) | 
|         |   2347 		    makeuppercase(ap); | 
|         |   2348 	    else if (casmod == 2) | 
|         |   2349 		for (; *ap; ap++) | 
|         |   2350 		    makelowercase(ap); | 
|         |   2351 	    else | 
|         |   2352 		for (; *ap; ap++) | 
|         |   2353 		    makecapitals(ap); | 
|         |   2354  | 
|         |   2355 	} else { | 
|         |   2356 	    if (!copied) | 
|         |   2357 		val = dupstring(val), copied = 1; | 
|         |   2358 	    if (casmod == 1) | 
|         |   2359 		makeuppercase(&val); | 
|         |   2360 	    else if (casmod == 2) | 
|         |   2361 		makelowercase(&val); | 
|         |   2362 	    else | 
|         |   2363 		makecapitals(&val); | 
|         |   2364 	} | 
|         |   2365     } | 
|         |   2366     /* | 
|         |   2367      * Perform prompt-style modifications. | 
|         |   2368      */ | 
|         |   2369     if (presc) { | 
|         |   2370 	int ops = opts[PROMPTSUBST], opb = opts[PROMPTBANG]; | 
|         |   2371 	int opp = opts[PROMPTPERCENT], len; | 
|         |   2372  | 
|         |   2373 	if (presc < 2) { | 
|         |   2374 	    opts[PROMPTPERCENT] = 1; | 
|         |   2375 	    opts[PROMPTSUBST] = opts[PROMPTBANG] = 0; | 
|         |   2376 	} | 
|         |   2377 	/* | 
|         |   2378 	 * TODO:  It would be really quite nice to abstract the | 
|         |   2379 	 * isarr and !issarr code into a function which gets | 
|         |   2380 	 * passed a pointer to a function with the effect of | 
|         |   2381 	 * the promptexpand bit.  Then we could use this for | 
|         |   2382 	 * a lot of stuff and bury val/aval/isarr inside a structure | 
|         |   2383 	 * which gets passed to it. | 
|         |   2384 	 */ | 
|         |   2385 	if (isarr) { | 
|         |   2386 	    char **ap; | 
|         |   2387  | 
|         |   2388 	    if (!copied) | 
|         |   2389 		aval = arrdup(aval), copied = 1; | 
|         |   2390 	    ap = aval; | 
|         |   2391 	    for (; *ap; ap++) { | 
|         |   2392 		char *tmps; | 
|         |   2393 		unmetafy(*ap, &len); | 
|         |   2394 		untokenize(*ap); | 
|         |   2395 		tmps = unmetafy(promptexpand(metafy(*ap, len, META_NOALLOC), | 
|         |   2396 					     0, NULL, NULL), &len); | 
|         |   2397 		*ap = dupstring(tmps); | 
|         |   2398 		free(tmps); | 
|         |   2399 	    } | 
|         |   2400 	} else { | 
|         |   2401 	    char *tmps; | 
|         |   2402 	    if (!copied) | 
|         |   2403 		val = dupstring(val), copied = 1; | 
|         |   2404 	    unmetafy(val, &len); | 
|         |   2405 	    untokenize(val); | 
|         |   2406 	    tmps = unmetafy(promptexpand(metafy(val, len, META_NOALLOC), | 
|         |   2407 					0, NULL, NULL), &len); | 
|         |   2408 	    val = dupstring(tmps); | 
|         |   2409 	    free(tmps); | 
|         |   2410 	} | 
|         |   2411 	opts[PROMPTSUBST] = ops; | 
|         |   2412 	opts[PROMPTBANG] = opb; | 
|         |   2413 	opts[PROMPTPERCENT] = opp; | 
|         |   2414     } | 
|         |   2415     /* | 
|         |   2416      * One of the possible set of quotes to apply, depending on | 
|         |   2417      * the repetitions of the (q) flag. | 
|         |   2418      */ | 
|         |   2419     if (quotemod) { | 
|         |   2420 	if (--quotetype > 3) | 
|         |   2421 	    quotetype = 3; | 
|         |   2422 	if (isarr) { | 
|         |   2423 	    char **ap; | 
|         |   2424  | 
|         |   2425 	    if (!copied) | 
|         |   2426 		aval = arrdup(aval), copied = 1; | 
|         |   2427 	    ap = aval; | 
|         |   2428  | 
|         |   2429 	    if (quotemod > 0) { | 
|         |   2430 		if (quotetype) { | 
|         |   2431 		    int sl; | 
|         |   2432 		    char *tmp; | 
|         |   2433  | 
|         |   2434 		    for (; *ap; ap++) { | 
|         |   2435 			int pre = quotetype != 3 ? 1 : 2; | 
|         |   2436 			tmp = bslashquote(*ap, NULL, quotetype); | 
|         |   2437 			sl = strlen(tmp); | 
|         |   2438 			*ap = (char *) zhalloc(pre + sl + 2); | 
|         |   2439 			strcpy((*ap) + pre, tmp); | 
|         |   2440 			ap[0][pre - 1] = ap[0][pre + sl] = (quotetype != 2 ? '\'' : '"'); | 
|         |   2441 			ap[0][pre + sl + 1] = '\0'; | 
|         |   2442 			if (quotetype == 3) | 
|         |   2443 			  ap[0][0] = '$'; | 
|         |   2444 		    } | 
|         |   2445 		} else | 
|         |   2446 		    for (; *ap; ap++) | 
|         |   2447 			*ap = bslashquote(*ap, NULL, 0); | 
|         |   2448 	    } else { | 
|         |   2449 		int one = noerrs, oef = errflag, haserr = 0; | 
|         |   2450  | 
|         |   2451 		if (!quoteerr) | 
|         |   2452 		    noerrs = 1; | 
|         |   2453 		for (; *ap; ap++) { | 
|         |   2454 		    haserr |= parse_subst_string(*ap); | 
|         |   2455 		    remnulargs(*ap); | 
|         |   2456 		    untokenize(*ap); | 
|         |   2457 		} | 
|         |   2458 		noerrs = one; | 
|         |   2459 		if (!quoteerr) | 
|         |   2460 		    errflag = oef; | 
|         |   2461 		else if (haserr || errflag) { | 
|         |   2462 		    zerr("parse error in parameter value", NULL, 0); | 
|         |   2463 		    return NULL; | 
|         |   2464 		} | 
|         |   2465 	    } | 
|         |   2466 	} else { | 
|         |   2467 	    if (!copied) | 
|         |   2468 		val = dupstring(val), copied = 1; | 
|         |   2469 	    if (quotemod > 0) { | 
|         |   2470 		if (quotetype) { | 
|         |   2471 		    int pre = quotetype != 3 ? 1 : 2; | 
|         |   2472 		    int sl; | 
|         |   2473 		    char *tmp; | 
|         |   2474 		    tmp = bslashquote(val, NULL, quotetype); | 
|         |   2475 		    sl = strlen(tmp); | 
|         |   2476 		    val = (char *) zhalloc(pre + sl + 2); | 
|         |   2477 		    strcpy(val + pre, tmp); | 
|         |   2478 		    val[pre - 1] = val[pre + sl] = (quotetype != 2 ? '\'' : '"'); | 
|         |   2479 		    val[pre + sl + 1] = '\0'; | 
|         |   2480 		    if (quotetype == 3) | 
|         |   2481 		      val[0] = '$'; | 
|         |   2482 		} else | 
|         |   2483 		    val = bslashquote(val, NULL, 0); | 
|         |   2484 	    } else { | 
|         |   2485 		int one = noerrs, oef = errflag, haserr; | 
|         |   2486  | 
|         |   2487 		if (!quoteerr) | 
|         |   2488 		    noerrs = 1; | 
|         |   2489 		haserr = parse_subst_string(val); | 
|         |   2490 		noerrs = one; | 
|         |   2491 		if (!quoteerr) | 
|         |   2492 		    errflag = oef; | 
|         |   2493 		else if (haserr || errflag) { | 
|         |   2494 		    zerr("parse error in parameter value", NULL, 0); | 
|         |   2495 		    return NULL; | 
|         |   2496 		} | 
|         |   2497 		remnulargs(val); | 
|         |   2498 		untokenize(val); | 
|         |   2499 	    } | 
|         |   2500 	} | 
|         |   2501     } | 
|         |   2502     /* | 
|         |   2503      * Transform special characters in the string to make them | 
|         |   2504      * printable. | 
|         |   2505      */ | 
|         |   2506     if (visiblemod) { | 
|         |   2507 	if (isarr) { | 
|         |   2508 	    char **ap; | 
|         |   2509 	    if (!copied) | 
|         |   2510 		aval = arrdup(aval), copied = 1; | 
|         |   2511 	    for (ap = aval; *ap; ap++) | 
|         |   2512 		*ap = nicedupstring(*ap); | 
|         |   2513 	} else { | 
|         |   2514 	    if (!copied) | 
|         |   2515 		val = dupstring(val), copied = 1; | 
|         |   2516 	    val = nicedupstring(val); | 
|         |   2517 	} | 
|         |   2518     } | 
|         |   2519     /* | 
|         |   2520      * Nothing particularly to do with SH_WORD_SPLIT --- this | 
|         |   2521      * performs lexical splitting on a string as specified by | 
|         |   2522      * the (z) flag. | 
|         |   2523      */ | 
|         |   2524     if (shsplit) { | 
|         |   2525 	LinkList list = NULL; | 
|         |   2526  | 
|         |   2527 	if (isarr) { | 
|         |   2528 	    char **ap; | 
|         |   2529 	    for (ap = aval; *ap; ap++) | 
|         |   2530 		list = bufferwords(list, *ap, NULL); | 
|         |   2531 	    isarr = 0; | 
|         |   2532 	} else | 
|         |   2533 	    list = bufferwords(NULL, val, NULL); | 
|         |   2534  | 
|         |   2535 	if (!list || !firstnode(list)) | 
|         |   2536 	    val = dupstring(""); | 
|         |   2537 	else if (!nextnode(firstnode(list))) | 
|         |   2538 	    val = getdata(firstnode(list)); | 
|         |   2539 	else { | 
|         |   2540 	    char **ap; | 
|         |   2541 	    LinkNode node; | 
|         |   2542  | 
|         |   2543 	    aval = ap = (char **) zhalloc((countlinknodes(list) + 1) * | 
|         |   2544 					  sizeof(char *)); | 
|         |   2545 	    for (node = firstnode(list); node; incnode(node)) | 
|         |   2546 		*ap++ = (char *) getdata(node); | 
|         |   2547 	    *ap = NULL; | 
|         |   2548 	    mult_isarr = isarr = 2; | 
|         |   2549 	} | 
|         |   2550 	copied = 1; | 
|         |   2551     } | 
|         |   2552     /* | 
|         |   2553      * TODO: hmm.  At this point we have to be on our toes about | 
|         |   2554      * whether we're putting stuff into a line or not, i.e. | 
|         |   2555      * we don't want to do this from a recursive call; this is | 
|         |   2556      * probably part of the point of the mult_isarr monkey business. | 
|         |   2557      * Rather than passing back flags in a non-trivial way, maybe | 
|         |   2558      * we could decide on the basis of flags passed down to us. | 
|         |   2559      * | 
|         |   2560      * This is the ideal place to do any last-minute conversion from | 
|         |   2561      * array to strings.  However, given all the transformations we've | 
|         |   2562      * already done, probably if it's going to be done it will already | 
|         |   2563      * have been.  (I'd really like to keep everying in aval or | 
|         |   2564      * equivalent and only locally decide if we need to treat it | 
|         |   2565      * as a scalar.) | 
|         |   2566      */ | 
|         |   2567     if (isarr) { | 
|         |   2568 	char *x; | 
|         |   2569 	char *y; | 
|         |   2570 	int xlen; | 
|         |   2571 	int i; | 
|         |   2572 	LinkNode on = n; | 
|         |   2573  | 
|         |   2574 	/* Handle the (u) flag; we need this before the next test */ | 
|         |   2575 	if (unique) { | 
|         |   2576 	    if(!copied) | 
|         |   2577 		aval = arrdup(aval); | 
|         |   2578  | 
|         |   2579 	    i = arrlen(aval); | 
|         |   2580 	    if (i > 1) | 
|         |   2581 		zhuniqarray(aval); | 
|         |   2582 	} | 
|         |   2583 	if ((!aval[0] || !aval[1]) && !plan9) { | 
|         |   2584 	    /* | 
|         |   2585 	     * Empty array or single element.  Currently you only | 
|         |   2586 	     * get a single element array at this point from the | 
|         |   2587 	     * unique expansion above. but we can potentially | 
|         |   2588 	     * have other reasons. | 
|         |   2589 	     * | 
|         |   2590 	     * The following test removes the markers | 
|         |   2591 	     * from surrounding double quotes, but I don't know why | 
|         |   2592 	     * that's necessary. | 
|         |   2593 	     */ | 
|         |   2594 	    int vallen; | 
|         |   2595 	    if (aptr > (char *) getdata(n) && | 
|         |   2596 		aptr[-1] == Dnull && *fstr == Dnull) | 
|         |   2597 		*--aptr = '\0', fstr++; | 
|         |   2598 	    vallen = aval[0] ? strlen(aval[0]) : 0; | 
|         |   2599 	    y = (char *) hcalloc((aptr - ostr) + vallen + strlen(fstr) + 1); | 
|         |   2600 	    strcpy(y, ostr); | 
|         |   2601 	    *str = y + (aptr - ostr); | 
|         |   2602 	    if (vallen) | 
|         |   2603 	    { | 
|         |   2604 		strcpy(*str, aval[0]); | 
|         |   2605 		*str += vallen; | 
|         |   2606 	    } | 
|         |   2607 	    strcpy(*str, fstr); | 
|         |   2608 	    setdata(n, y); | 
|         |   2609 	    return n; | 
|         |   2610 	} | 
|         |   2611 	/* Handle (o) and (O) and their variants */ | 
|         |   2612 	if (sortit) { | 
|         |   2613 	    if (!copied) | 
|         |   2614 		aval = arrdup(aval); | 
|         |   2615 	    if (indord) { | 
|         |   2616 		if (sortit & 2) { | 
|         |   2617 		    char *copy; | 
|         |   2618 		    char **end = aval + arrlen(aval) - 1, **start = aval; | 
|         |   2619  | 
|         |   2620 		    /* reverse the array */ | 
|         |   2621 		    while (start < end) { | 
|         |   2622 			copy = *end; | 
|         |   2623 			*end-- = *start; | 
|         |   2624 			*start++ = copy; | 
|         |   2625 		    } | 
|         |   2626 		} | 
|         |   2627 	    } else { | 
|         |   2628 		static CompareFn sortfn[] = { | 
|         |   2629 		    strpcmp, invstrpcmp, cstrpcmp, invcstrpcmp, | 
|         |   2630 		    nstrpcmp, invnstrpcmp, instrpcmp, invinstrpcmp | 
|         |   2631 		}; | 
|         |   2632  | 
|         |   2633 		i = arrlen(aval); | 
|         |   2634 		if (i && (*aval[i-1] || --i)) | 
|         |   2635 		    qsort(aval, i, sizeof(char *), sortfn[sortit-1]); | 
|         |   2636 	    } | 
|         |   2637 	} | 
|         |   2638 	if (plan9) { | 
|         |   2639 	    /* Handle RC_EXPAND_PARAM */ | 
|         |   2640 	    LinkNode tn; | 
|         |   2641 	    local_list1(tl); | 
|         |   2642  | 
|         |   2643 	    *--fstr = Marker; | 
|         |   2644 	    init_list1(tl, fstr); | 
|         |   2645 	    if (!eval && !stringsubst(&tl, firstnode(&tl), ssub, 0)) | 
|         |   2646 		return NULL; | 
|         |   2647 	    *str = aptr; | 
|         |   2648 	    tn = firstnode(&tl); | 
|         |   2649 	    while ((x = *aval++)) { | 
|         |   2650 		if (prenum || postnum) | 
|         |   2651 		    x = dopadding(x, prenum, postnum, preone, postone, | 
|         |   2652 				  premul, postmul); | 
|         |   2653 		if (eval && subst_parse_str(&x, (qt && !nojoin), quoteerr)) | 
|         |   2654 		    return NULL; | 
|         |   2655 		xlen = strlen(x); | 
|         |   2656 		for (tn = firstnode(&tl); | 
|         |   2657 		     tn && *(y = (char *) getdata(tn)) == Marker; | 
|         |   2658 		     incnode(tn)) { | 
|         |   2659 		    strcatsub(&y, ostr, aptr, x, xlen, y + 1, globsubst, | 
|         |   2660 			      copied); | 
|         |   2661 		    if (qt && !*y && isarr != 2) | 
|         |   2662 			y = dupstring(nulstring); | 
|         |   2663 		    if (plan9) | 
|         |   2664 			setdata(n, (void *) y), plan9 = 0; | 
|         |   2665 		    else | 
|         |   2666 			insertlinknode(l, n, (void *) y), incnode(n); | 
|         |   2667 		} | 
|         |   2668 	    } | 
|         |   2669 	    for (; tn; incnode(tn)) { | 
|         |   2670 		y = (char *) getdata(tn); | 
|         |   2671 		if (*y == Marker) | 
|         |   2672 		    continue; | 
|         |   2673 		if (qt && !*y && isarr != 2) | 
|         |   2674 		    y = dupstring(nulstring); | 
|         |   2675 		if (plan9) | 
|         |   2676 		    setdata(n, (void *) y), plan9 = 0; | 
|         |   2677 		else | 
|         |   2678 		    insertlinknode(l, n, (void *) y), incnode(n); | 
|         |   2679 	    } | 
|         |   2680 	    if (plan9) { | 
|         |   2681 		uremnode(l, n); | 
|         |   2682 		return n; | 
|         |   2683 	    } | 
|         |   2684 	} else { | 
|         |   2685 	    /* | 
|         |   2686 	     * Not RC_EXPAND_PARAM: simply join the first and | 
|         |   2687 	     * last values. | 
|         |   2688 	     * TODO: how about removing the restriction that | 
|         |   2689 	     * aval[1] is non-NULL to promote consistency?, or | 
|         |   2690 	     * simply changing the test so that we drop into | 
|         |   2691 	     * the scalar branch, instead of tricking isarr? | 
|         |   2692 	     */ | 
|         |   2693 	    x = aval[0]; | 
|         |   2694 	    if (prenum || postnum) | 
|         |   2695 		x = dopadding(x, prenum, postnum, preone, postone, | 
|         |   2696 			      premul, postmul); | 
|         |   2697 	    if (eval && subst_parse_str(&x, (qt && !nojoin), quoteerr)) | 
|         |   2698 		return NULL; | 
|         |   2699 	    xlen = strlen(x); | 
|         |   2700 	    strcatsub(&y, ostr, aptr, x, xlen, NULL, globsubst, copied); | 
|         |   2701 	    if (qt && !*y && isarr != 2) | 
|         |   2702 		y = dupstring(nulstring); | 
|         |   2703 	    setdata(n, (void *) y); | 
|         |   2704  | 
|         |   2705 	    i = 1; | 
|         |   2706 	    /* aval[1] is non-null here */ | 
|         |   2707 	    while (aval[i + 1]) { | 
|         |   2708 		x = aval[i++]; | 
|         |   2709 		if (prenum || postnum) | 
|         |   2710 		    x = dopadding(x, prenum, postnum, preone, postone, | 
|         |   2711 				  premul, postmul); | 
|         |   2712 		if (eval && subst_parse_str(&x, (qt && !nojoin), quoteerr)) | 
|         |   2713 		    return NULL; | 
|         |   2714 		if (qt && !*x && isarr != 2) | 
|         |   2715 		    y = dupstring(nulstring); | 
|         |   2716 		else { | 
|         |   2717 		    y = dupstring(x); | 
|         |   2718 		    if (globsubst) | 
|         |   2719 			shtokenize(y); | 
|         |   2720 		} | 
|         |   2721 		insertlinknode(l, n, (void *) y), incnode(n); | 
|         |   2722 	    } | 
|         |   2723  | 
|         |   2724 	    x = aval[i]; | 
|         |   2725 	    if (prenum || postnum) | 
|         |   2726 		x = dopadding(x, prenum, postnum, preone, postone, | 
|         |   2727 			      premul, postmul); | 
|         |   2728 	    if (eval && subst_parse_str(&x, (qt && !nojoin), quoteerr)) | 
|         |   2729 		return NULL; | 
|         |   2730 	    xlen = strlen(x); | 
|         |   2731 	    *str = strcatsub(&y, aptr, aptr, x, xlen, fstr, globsubst, copied); | 
|         |   2732 	    if (qt && !*y && isarr != 2) | 
|         |   2733 		y = dupstring(nulstring); | 
|         |   2734 	    insertlinknode(l, n, (void *) y), incnode(n); | 
|         |   2735 	} | 
|         |   2736 	if (eval) | 
|         |   2737 	    n = on; | 
|         |   2738     } else { | 
|         |   2739 	/* | 
|         |   2740 	 * Scalar value.  Handle last minute transformations | 
|         |   2741 	 * such as left- or right-padding and the (e) flag to | 
|         |   2742 	 * revaluate the result. | 
|         |   2743 	 */ | 
|         |   2744 	int xlen; | 
|         |   2745 	char *x; | 
|         |   2746 	char *y; | 
|         |   2747  | 
|         |   2748 	x = val; | 
|         |   2749 	if (prenum || postnum) | 
|         |   2750 	    x = dopadding(x, prenum, postnum, preone, postone, | 
|         |   2751 			  premul, postmul); | 
|         |   2752 	if (eval && subst_parse_str(&x, (qt && !nojoin), quoteerr)) | 
|         |   2753 	    return NULL; | 
|         |   2754 	xlen = strlen(x); | 
|         |   2755 	*str = strcatsub(&y, ostr, aptr, x, xlen, fstr, globsubst, copied); | 
|         |   2756 	if (qt && !*y) | 
|         |   2757 	    y = dupstring(nulstring); | 
|         |   2758 	setdata(n, (void *) y); | 
|         |   2759     } | 
|         |   2760     if (eval) | 
|         |   2761 	*str = (char *) getdata(n); | 
|         |   2762  | 
|         |   2763     return n; | 
|         |   2764 } | 
|         |   2765  | 
|         |   2766 /* | 
|         |   2767  * Arithmetic substitution: `a' is the string to be evaluated, `bptr' | 
|         |   2768  * points to the beginning of the string containing it.  The tail of | 
|         |   2769  * the string is given by `rest'. *bptr is modified with the substituted | 
|         |   2770  * string. The function returns a pointer to the tail in the substituted | 
|         |   2771  * string. | 
|         |   2772  */ | 
|         |   2773  | 
|         |   2774 /**/ | 
|         |   2775 static char * | 
|         |   2776 arithsubst(char *a, char **bptr, char *rest) | 
|         |   2777 { | 
|         |   2778     char *s = *bptr, *t; | 
|         |   2779     char buf[BDIGBUFSIZE], *b = buf; | 
|         |   2780     mnumber v; | 
|         |   2781  | 
|         |   2782     singsub(&a); | 
|         |   2783     v = matheval(a); | 
|         |   2784     if ((v.type & MN_FLOAT) && !outputradix) | 
|         |   2785 	b = convfloat(v.u.d, 0, 0, NULL); | 
|         |   2786     else { | 
|         |   2787 	if (v.type & MN_FLOAT) | 
|         |   2788 	    v.u.l = (zlong) v.u.d; | 
|         |   2789 	convbase(buf, v.u.l, outputradix); | 
|         |   2790     } | 
|         |   2791     t = *bptr = (char *) hcalloc(strlen(*bptr) + strlen(b) +  | 
|         |   2792 				 strlen(rest) + 1); | 
|         |   2793     t--; | 
|         |   2794     while ((*++t = *s++)); | 
|         |   2795     t--; | 
|         |   2796     while ((*++t = *b++)); | 
|         |   2797     strcat(t, rest); | 
|         |   2798     return t; | 
|         |   2799 } | 
|         |   2800  | 
|         |   2801 /**/ | 
|         |   2802 void | 
|         |   2803 modify(char **str, char **ptr) | 
|         |   2804 { | 
|         |   2805     char *ptr1, *ptr2, *ptr3, del, *lptr, c, *test, *sep, *t, *tt, tc, *e; | 
|         |   2806     char *copy, *all, *tmp, sav; | 
|         |   2807     int gbal, wall, rec, al, nl; | 
|         |   2808  | 
|         |   2809     test = NULL; | 
|         |   2810  | 
|         |   2811     if (**ptr == ':') | 
|         |   2812 	*str = dupstring(*str); | 
|         |   2813  | 
|         |   2814     while (**ptr == ':') { | 
|         |   2815 	lptr = *ptr; | 
|         |   2816 	(*ptr)++; | 
|         |   2817 	wall = gbal = 0; | 
|         |   2818 	rec = 1; | 
|         |   2819 	c = '\0'; | 
|         |   2820 	sep = NULL; | 
|         |   2821  | 
|         |   2822 	for (; !c && **ptr;) { | 
|         |   2823 	    switch (**ptr) { | 
|         |   2824 	    case 'h': | 
|         |   2825 	    case 'r': | 
|         |   2826 	    case 'e': | 
|         |   2827 	    case 't': | 
|         |   2828 	    case 'l': | 
|         |   2829 	    case 'u': | 
|         |   2830 	    case 'q': | 
|         |   2831 	    case 'Q': | 
|         |   2832 		c = **ptr; | 
|         |   2833 		break; | 
|         |   2834  | 
|         |   2835 	    case 's': | 
|         |   2836 		c = **ptr; | 
|         |   2837 		(*ptr)++; | 
|         |   2838 		ptr1 = *ptr; | 
|         |   2839 		del = *ptr1++; | 
|         |   2840 		for (ptr2 = ptr1; *ptr2 != del && *ptr2; ptr2++); | 
|         |   2841 		if (!*ptr2) { | 
|         |   2842 		    zerr("bad substitution", NULL, 0); | 
|         |   2843 		    return; | 
|         |   2844 		} | 
|         |   2845 		*ptr2++ = '\0'; | 
|         |   2846 		for (ptr3 = ptr2; *ptr3 != del && *ptr3; ptr3++); | 
|         |   2847 		if ((sav = *ptr3)) | 
|         |   2848 		    *ptr3++ = '\0'; | 
|         |   2849 		if (*ptr1) { | 
|         |   2850 		    zsfree(hsubl); | 
|         |   2851 		    hsubl = ztrdup(ptr1); | 
|         |   2852  		} | 
|         |   2853 		if (!hsubl) { | 
|         |   2854 		    zerr("no previous substitution", NULL, 0); | 
|         |   2855 		    return; | 
|         |   2856 		} | 
|         |   2857 		zsfree(hsubr); | 
|         |   2858 		for (tt = hsubl; *tt; tt++) | 
|         |   2859 		    if (INULL(*tt)) | 
|         |   2860 			chuck(tt--); | 
|         |   2861 		untokenize(hsubl); | 
|         |   2862 		for (tt = hsubr = ztrdup(ptr2); *tt; tt++) | 
|         |   2863 		    if (INULL(*tt)) | 
|         |   2864 			chuck(tt--); | 
|         |   2865 		ptr2[-1] = del; | 
|         |   2866 		if (sav) | 
|         |   2867 		    ptr3[-1] = sav; | 
|         |   2868 		*ptr = ptr3 - 1; | 
|         |   2869 		break; | 
|         |   2870  | 
|         |   2871 	    case '&': | 
|         |   2872 		c = 's'; | 
|         |   2873 		break; | 
|         |   2874  | 
|         |   2875 	    case 'g': | 
|         |   2876 		(*ptr)++; | 
|         |   2877 		gbal = 1; | 
|         |   2878 		break; | 
|         |   2879  | 
|         |   2880 	    case 'w': | 
|         |   2881 		wall = 1; | 
|         |   2882 		(*ptr)++; | 
|         |   2883 		break; | 
|         |   2884 	    case 'W': | 
|         |   2885 		wall = 1; | 
|         |   2886 		(*ptr)++; | 
|         |   2887 		ptr1 = get_strarg(ptr2 = *ptr); | 
|         |   2888 		if ((sav = *ptr1)) | 
|         |   2889 		    *ptr1 = '\0'; | 
|         |   2890 		sep = dupstring(ptr2 + 1); | 
|         |   2891 		if (sav) | 
|         |   2892 		    *ptr1 = sav; | 
|         |   2893 		*ptr = ptr1 + 1; | 
|         |   2894 		c = '\0'; | 
|         |   2895 		break; | 
|         |   2896  | 
|         |   2897 	    case 'f': | 
|         |   2898 		rec = -1; | 
|         |   2899 		(*ptr)++; | 
|         |   2900 		break; | 
|         |   2901 	    case 'F': | 
|         |   2902 		rec = get_intarg(ptr); | 
|         |   2903 		(*ptr)++; | 
|         |   2904 		break; | 
|         |   2905 	    default: | 
|         |   2906 		*ptr = lptr; | 
|         |   2907 		return; | 
|         |   2908 	    } | 
|         |   2909 	} | 
|         |   2910 	(*ptr)++; | 
|         |   2911 	if (!c) { | 
|         |   2912 	    *ptr = lptr; | 
|         |   2913 	    return; | 
|         |   2914 	} | 
|         |   2915 	if (rec < 0) | 
|         |   2916 	    test = dupstring(*str); | 
|         |   2917  | 
|         |   2918 	while (rec--) { | 
|         |   2919 	    if (wall) { | 
|         |   2920 		al = 0; | 
|         |   2921 		all = NULL; | 
|         |   2922 		for (t = e = *str; (tt = findword(&e, sep));) { | 
|         |   2923 		    tc = *e; | 
|         |   2924 		    *e = '\0'; | 
|         |   2925 		    copy = dupstring(tt); | 
|         |   2926 		    *e = tc; | 
|         |   2927 		    switch (c) { | 
|         |   2928 		    case 'h': | 
|         |   2929 			remtpath(©); | 
|         |   2930 			break; | 
|         |   2931 		    case 'r': | 
|         |   2932 			remtext(©); | 
|         |   2933 			break; | 
|         |   2934 		    case 'e': | 
|         |   2935 			rembutext(©); | 
|         |   2936 			break; | 
|         |   2937 		    case 't': | 
|         |   2938 			remlpaths(©); | 
|         |   2939 			break; | 
|         |   2940 		    case 'l': | 
|         |   2941 			downcase(©); | 
|         |   2942 			break; | 
|         |   2943 		    case 'u': | 
|         |   2944 			upcase(©); | 
|         |   2945 			break; | 
|         |   2946 		    case 's': | 
|         |   2947 			if (hsubl && hsubr) | 
|         |   2948 			    subst(©, hsubl, hsubr, gbal); | 
|         |   2949 			break; | 
|         |   2950 		    case 'q': | 
|         |   2951 			copy = bslashquote(copy, NULL, 0); | 
|         |   2952 			break; | 
|         |   2953 		    case 'Q': | 
|         |   2954 			{ | 
|         |   2955 			    int one = noerrs, oef = errflag; | 
|         |   2956  | 
|         |   2957 			    noerrs = 1; | 
|         |   2958 			    parse_subst_string(copy); | 
|         |   2959 			    noerrs = one; | 
|         |   2960 			    errflag = oef; | 
|         |   2961 			    remnulargs(copy); | 
|         |   2962 			    untokenize(copy); | 
|         |   2963 			} | 
|         |   2964 			break; | 
|         |   2965 		    } | 
|         |   2966 		    tc = *tt; | 
|         |   2967 		    *tt = '\0'; | 
|         |   2968 		    nl = al + strlen(t) + strlen(copy); | 
|         |   2969 		    ptr1 = tmp = (char *)zhalloc(nl + 1); | 
|         |   2970 		    if (all) | 
|         |   2971 			for (ptr2 = all; *ptr2;) | 
|         |   2972 			    *ptr1++ = *ptr2++; | 
|         |   2973 		    for (ptr2 = t; *ptr2;) | 
|         |   2974 			*ptr1++ = *ptr2++; | 
|         |   2975 		    *tt = tc; | 
|         |   2976 		    for (ptr2 = copy; *ptr2;) | 
|         |   2977 			*ptr1++ = *ptr2++; | 
|         |   2978 		    *ptr1 = '\0'; | 
|         |   2979 		    al = nl; | 
|         |   2980 		    all = tmp; | 
|         |   2981 		    t = e; | 
|         |   2982 		} | 
|         |   2983 		*str = all; | 
|         |   2984  | 
|         |   2985 	    } else { | 
|         |   2986 		switch (c) { | 
|         |   2987 		case 'h': | 
|         |   2988 		    remtpath(str); | 
|         |   2989 		    break; | 
|         |   2990 		case 'r': | 
|         |   2991 		    remtext(str); | 
|         |   2992 		    break; | 
|         |   2993 		case 'e': | 
|         |   2994 		    rembutext(str); | 
|         |   2995 		    break; | 
|         |   2996 		case 't': | 
|         |   2997 		    remlpaths(str); | 
|         |   2998 		    break; | 
|         |   2999 		case 'l': | 
|         |   3000 		    downcase(str); | 
|         |   3001 		    break; | 
|         |   3002 		case 'u': | 
|         |   3003 		    upcase(str); | 
|         |   3004 		    break; | 
|         |   3005 		case 's': | 
|         |   3006 		    if (hsubl && hsubr) { | 
|         |   3007 			char *oldstr = *str; | 
|         |   3008  | 
|         |   3009 			subst(str, hsubl, hsubr, gbal); | 
|         |   3010 			if (*str != oldstr) { | 
|         |   3011 			    *str = dupstring(oldstr = *str); | 
|         |   3012 			    zsfree(oldstr); | 
|         |   3013 			} | 
|         |   3014 		    } | 
|         |   3015 		    break; | 
|         |   3016 		case 'q': | 
|         |   3017 		    *str = bslashquote(*str, NULL, 0); | 
|         |   3018 		    break; | 
|         |   3019 		case 'Q': | 
|         |   3020 		    { | 
|         |   3021 			int one = noerrs, oef = errflag; | 
|         |   3022  | 
|         |   3023 			noerrs = 1; | 
|         |   3024 			parse_subst_string(*str); | 
|         |   3025 			noerrs = one; | 
|         |   3026 			errflag = oef; | 
|         |   3027 			remnulargs(*str); | 
|         |   3028 			untokenize(*str); | 
|         |   3029 		    } | 
|         |   3030 		    break; | 
|         |   3031 		} | 
|         |   3032 	    } | 
|         |   3033 	    if (rec < 0) { | 
|         |   3034 		if (!strcmp(test, *str)) | 
|         |   3035 		    rec = 0; | 
|         |   3036 		else | 
|         |   3037 		    test = dupstring(*str); | 
|         |   3038 	    } | 
|         |   3039 	} | 
|         |   3040     } | 
|         |   3041 } | 
|         |   3042  | 
|         |   3043 /* get a directory stack entry */ | 
|         |   3044  | 
|         |   3045 /**/ | 
|         |   3046 static char * | 
|         |   3047 dstackent(char ch, int val) | 
|         |   3048 { | 
|         |   3049     int backwards; | 
|         |   3050     LinkNode end=(LinkNode)dirstack, n; | 
|         |   3051  | 
|         |   3052     backwards = ch == (isset(PUSHDMINUS) ? '+' : '-'); | 
|         |   3053     if(!backwards && !val--) | 
|         |   3054 	return pwd; | 
|         |   3055     if (backwards) | 
|         |   3056 	for (n=lastnode(dirstack); n != end && val; val--, n=prevnode(n)); | 
|         |   3057     else | 
|         |   3058 	for (end=NULL, n=firstnode(dirstack); n && val; val--, n=nextnode(n)); | 
|         |   3059     if (n == end) { | 
|         |   3060 	if (backwards && !val) | 
|         |   3061 	    return pwd; | 
|         |   3062 	if (isset(NOMATCH)) | 
|         |   3063 	    zerr("not enough directory stack entries.", NULL, 0); | 
|         |   3064 	return NULL; | 
|         |   3065     } | 
|         |   3066     return (char *)getdata(n); | 
|         |   3067 } |