Commit | Line | Data |
---|---|---|
dbf02a84 WJ |
1 | /* |
2 | * | |
3 | * subst.c - various substitutions | |
4 | * | |
5 | * This file is part of zsh, the Z shell. | |
6 | * | |
7 | * This software is Copyright 1992 by Paul Falstad | |
8 | * | |
9 | * Permission is hereby granted to copy, reproduce, redistribute or otherwise | |
10 | * use this software as long as: there is no monetary profit gained | |
11 | * specifically from the use or reproduction of this software, it is not | |
12 | * sold, rented, traded or otherwise marketed, and this copyright notice is | |
13 | * included prominently in any copy made. | |
14 | * | |
15 | * The author make no claims as to the fitness or correctness of this software | |
16 | * for any use whatsoever, and it is provided as is. Any use of this software | |
17 | * is at the user's own risk. | |
18 | * | |
19 | */ | |
20 | ||
21 | #include "zsh.h" | |
22 | #include <pwd.h> | |
23 | ||
24 | /* do substitutions before fork */ | |
25 | ||
26 | void prefork(list) /**/ | |
27 | Lklist list; | |
28 | { | |
29 | Lknode node = firstnode(list); | |
30 | int qt; | |
31 | ||
32 | while (node) | |
33 | { | |
34 | char *str,*str3; | |
35 | ||
36 | str = str3 = getdata(node); | |
37 | if ((*str == Inang || *str == Outang || *str == Equals) && | |
38 | str[1] == Inpar) | |
39 | { | |
40 | if (*str == Inang) | |
41 | setdata(node,getoutproc(str+2)); /* <(...) */ | |
42 | else if (*str == Equals) | |
43 | setdata(node,getoutputfile(str+2)); /* =(...) */ | |
44 | else | |
45 | setdata(node,getinproc(str+2)); /* >(...) */ | |
46 | if (!getdata(node)) | |
47 | { | |
48 | zerr("parse error in process substitution",NULL,0); | |
49 | return; | |
50 | } | |
51 | } | |
52 | else while (*str) | |
53 | { | |
54 | if ((qt = *str == Qstring) || *str == String) | |
55 | if (str[1] != Inpar) | |
56 | if (str[1] == Inbrack) | |
57 | { | |
58 | arithsubst((vptr*) &str,&str3); /* $[...] */ | |
59 | setdata(node,str3); | |
60 | str = str3; | |
61 | continue; | |
62 | } | |
63 | else | |
64 | { | |
65 | paramsubst(list,node,str,str3,qt); | |
66 | if (errflag) | |
67 | return; | |
68 | str3 = str = getdata(node); | |
69 | continue; | |
70 | } | |
71 | str++; | |
72 | if (errflag) | |
73 | return; | |
74 | } | |
75 | if (*(char *) getdata(node)) | |
76 | remnulargs(getdata(node)); | |
77 | if (unset(IGNOREBRACES)) | |
78 | while (hasbraces(getdata(node))) | |
79 | xpandbraces(list,&node); | |
80 | filesub((char **) getaddrdata(node)); | |
81 | if (errflag) | |
82 | return; | |
83 | incnode(node); | |
84 | } | |
85 | } | |
86 | ||
87 | void postfork(list,doglob) /**/ | |
88 | Lklist list;int doglob; | |
89 | { | |
90 | Lknode node = firstnode(list); | |
91 | int glb = 1; | |
92 | ||
93 | badcshglob = 0; | |
94 | if (isset(NOGLOBOPT) || !doglob) | |
95 | glb = 0; | |
96 | while (node) | |
97 | { | |
98 | char *str3,*str; | |
99 | ||
100 | str = str3 = getdata(node); | |
101 | while (*str) | |
102 | { | |
103 | if (((*str == String || *str == Qstring) && str[1] == Inpar) || | |
104 | *str == Tick || *str == Qtick) | |
105 | { | |
106 | Lknode n = prevnode(node); | |
107 | ||
108 | commsubst(list,node,str,str3, | |
109 | (*str == Qstring || *str == Qtick)); /* `...`,$(...) */ | |
110 | if (errflag) | |
111 | return; | |
112 | str = str3 = getdata(node = nextnode(n)); | |
113 | } | |
114 | str++; | |
115 | } | |
116 | if (glb) | |
117 | { | |
118 | if (haswilds(getdata(node))) | |
119 | glob(list,&node); | |
120 | if (errflag) | |
121 | return; | |
122 | } | |
123 | incnode(node); | |
124 | } | |
125 | if (badcshglob == 1) zerr("no match",NULL,0); | |
126 | } | |
127 | ||
128 | /* perform substitution on a single word */ | |
129 | ||
130 | void singsub(s) /**/ | |
131 | char **s; | |
132 | { | |
133 | Lklist foo; | |
134 | char *t; | |
135 | ||
136 | for (t = *s; *t; t++) | |
137 | if (*t == String) | |
138 | *t = Qstring; | |
139 | else if (*t == Tick) | |
140 | *t = Qtick; | |
141 | foo = newlist(); | |
142 | addnode(foo,*s); | |
143 | prefork(foo); | |
144 | if (errflag) | |
145 | return; | |
146 | postfork(foo,0); | |
147 | if (errflag) | |
148 | return; | |
149 | *s = ugetnode(foo); | |
150 | if (firstnode(foo)) | |
151 | zerr("ambiguous: %s",*s,0); | |
152 | } | |
153 | ||
154 | /* strdup, but returns "Nularg" if this is a null string */ | |
155 | ||
156 | vptr nstrdup(s) /**/ | |
157 | vptr s; | |
158 | { | |
159 | char *t = s; | |
160 | char u[2]; | |
161 | ||
162 | u[0] = Nularg; u[1] = '\0'; | |
163 | if (!*t) | |
164 | return strdup(u); | |
165 | return strdup(t); | |
166 | } | |
167 | ||
168 | char *dynread(stop) /**/ | |
169 | int stop; | |
170 | { | |
171 | int bsiz = 256,ct = 0,c; | |
172 | char *buf = zalloc(bsiz),*ptr; | |
173 | ||
174 | ptr = buf; | |
175 | while ((c = hgetc()) != stop) | |
176 | { | |
177 | *ptr++ = c; | |
178 | if (++ct == bsiz) | |
179 | { | |
180 | buf = realloc(buf,bsiz *= 2); | |
181 | ptr = buf+ct; | |
182 | } | |
183 | } | |
184 | *ptr = 0; | |
185 | return buf; | |
186 | } | |
187 | ||
188 | int filesub(namptr) /**/ | |
189 | char **namptr; | |
190 | { | |
191 | char *str = *namptr,*cnam; | |
192 | ||
193 | if (*str == Tilde && str[1] != '=') | |
194 | { | |
195 | if (str[1] == '+' && (str[2] == '/' || str[2] == '\0')) | |
196 | { | |
197 | char *foo = strdup(pwd); /* ~+ */ | |
198 | ||
199 | str+=2; | |
200 | modify(&foo,&str); | |
201 | *namptr = dyncat(pwd,str); | |
202 | return 1; | |
203 | } | |
204 | else if (str[1] == '-' && (str[2] == '/' || str[2] == '\0')) | |
205 | { | |
206 | char *foo; /* ~- */ | |
207 | ||
208 | if (cnam = oldpwd) | |
209 | foo = cnam; | |
210 | else | |
211 | foo = pwd; | |
212 | str += 2; | |
213 | foo = strdup(foo); | |
214 | modify(&foo,&str); | |
215 | *namptr = dyncat(foo,str); | |
216 | return 1; | |
217 | } | |
218 | if (ialpha(str[1])) /* ~foo */ | |
219 | { | |
220 | char *ptr,*hom; | |
221 | ||
222 | for (ptr = ++str; *ptr && iuser(*ptr); ptr++) | |
223 | if (*ptr == '-') | |
224 | *ptr = '-'; | |
225 | if (*ptr && *ptr != '/') return 0; | |
226 | if (!(hom = gethome(str,ptr-str))) | |
227 | { | |
228 | zerr("user not found: %l",str,ptr-str); | |
229 | errflag = 1; | |
230 | return 0; | |
231 | } | |
232 | modify(&hom,&ptr); | |
233 | *namptr = dyncat(hom,ptr); | |
234 | return 1; | |
235 | } | |
236 | else if (str[1] == '/') /* ~/foo */ | |
237 | { | |
238 | *namptr = dyncat(home,str+1); | |
239 | return 1; | |
240 | } | |
241 | else if (!str[1]) /* ~ by itself */ | |
242 | { | |
243 | *namptr = strdup(home); | |
244 | return 1; | |
245 | } | |
246 | } | |
247 | if (*str == Equals && iuser(str[1]) && unset(NOEQUALS)) | |
248 | { | |
249 | char *ptr,*s,*ds; | |
250 | int val; | |
251 | ||
252 | if (ialpha(str[1])) /* =foo */ | |
253 | { | |
254 | char sav,*pp; | |
255 | ||
256 | for (pp = str+1; *pp && *pp != ':'; pp++); | |
257 | sav = *pp; | |
258 | *pp = '\0'; | |
259 | if (!(cnam = findcmd(str+1))) | |
260 | { | |
261 | zerr("%s not found",str+1,0); | |
262 | errflag = 1; | |
263 | return 0; | |
264 | } | |
265 | *namptr = cnam; | |
266 | if ((*pp = sav) == ':') | |
267 | { | |
268 | modify(namptr,&pp); | |
269 | s = *namptr; | |
270 | *namptr = dyncat(*namptr,pp); | |
271 | } | |
272 | return 1; | |
273 | } | |
274 | if (str[1] == '-') /* =- */ | |
275 | { | |
276 | val = -1; | |
277 | ptr = str+2; | |
278 | } | |
279 | else | |
280 | val = zstrtol(str+1,&ptr,10); /* =# */ | |
281 | ds = dstackent(val); | |
282 | if (!ds) | |
283 | return 1; | |
284 | s = strdup(ds); | |
285 | modify(&s,&ptr); | |
286 | *namptr = dyncat(s,ptr); | |
287 | return 1; | |
288 | } | |
289 | return 0; | |
290 | } | |
291 | ||
292 | /* get a named directory */ | |
293 | ||
294 | char *gethome(user,len) /**/ | |
295 | char *user;int len; | |
296 | { | |
297 | char sav,*str; | |
298 | struct passwd *pw; | |
299 | ||
300 | if (len == 0) | |
301 | return strdup(home); | |
302 | sav = user[len]; | |
303 | user[len] = '\0'; | |
304 | if ((str = getsparamval(user,len)) && *str == '/') | |
305 | { | |
306 | str = strdup(str); | |
307 | adduserdir(user,str); | |
308 | user[len] = sav; | |
309 | return str; | |
310 | } | |
311 | permalloc(); /* fixes iris bug--getpwnam calls strdup! */ | |
312 | pw = getpwnam(user); | |
313 | lastalloc(); | |
314 | if (!pw) { | |
315 | user[len] = sav; | |
316 | return NULL; | |
317 | } | |
318 | str = xsymlink(pw->pw_dir); | |
319 | adduserdir(user,str); | |
320 | user[len] = sav; | |
321 | return str; | |
322 | } | |
323 | ||
324 | /* `...`, $(...) */ | |
325 | ||
326 | void commsubst(l,n,str3,str,qt) /**/ | |
327 | Lklist l;Lknode n;char *str3;char *str;int qt; | |
328 | { | |
329 | char *str2; | |
330 | Lknode where = prevnode(n); | |
331 | Lklist pl; | |
332 | ||
333 | if (*str3 == Tick || *str3 == Qtick) | |
334 | { | |
335 | *str3 = '\0'; | |
336 | for (str2 = ++str3; *str3 != Tick && *str3 != Qtick; str3++); | |
337 | *str3++ = '\0'; | |
338 | } | |
339 | else | |
340 | { | |
341 | *str3++ = '\0'; | |
342 | for (str2 = ++str3; *str3 != Outpar; str3++); | |
343 | *str3++ = '\0'; | |
344 | } | |
345 | uremnode(l,n); | |
346 | if (!(pl = getoutput(str2,qt))) | |
347 | { | |
348 | zerr("parse error in command substitution",NULL,0); | |
349 | errflag = 1; | |
350 | return; | |
351 | } | |
352 | if (full(pl)) | |
353 | { | |
354 | setdata(firstnode(pl),dyncat(str,peekfirst(pl))); | |
355 | setdata(lastnode(pl),dyncat(getdata(lastnode(pl)),str3)); | |
356 | inslist(pl,where,l); | |
357 | } | |
358 | else | |
359 | insnode(l,where,dyncat(str,str3)); | |
360 | } | |
361 | ||
362 | /* parameter substitution */ | |
363 | ||
364 | void paramsubst(l,n,aptr,bptr,qt) /**/ | |
365 | Lklist l;Lknode n;char *aptr;char *bptr;int qt; | |
366 | { | |
367 | char *s = aptr,*u,*idbeg,*idend,*ostr = bptr; | |
368 | int brs; /* != 0 means ${...}, otherwise $... */ | |
369 | int colf; /* != 0 means we found a colon after the name */ | |
370 | int doub = 0; /* != 0 means we have %%, not %, or ##, not # */ | |
371 | int isarr = 0; | |
372 | int wasnularr = 0; | |
373 | int plan9 = isset(RCEXPANDPARAM); | |
374 | int getlen = 0; | |
375 | int vunset = 0; | |
376 | int spbreak = isset(SHWORDSPLIT) && !qt; | |
377 | char *val = NULL,**aval = NULL; | |
378 | int fwidth = 0; | |
379 | Value v; | |
380 | ||
381 | *s++ = '\0'; | |
382 | if (!ialnum(*s) && *s != '#' && *s != Pound && *s != '-' && | |
383 | *s != '!' && *s != '$' && *s != String && *s != Qstring && | |
384 | *s != '?' && *s != Quest && *s != '_' && | |
385 | *s != '*' && *s != Star && *s != '@' && *s != '{' && | |
386 | *s != Inbrace && *s != '=' && *s != Hat && *s != '^') { | |
387 | s[-1] = '$'; | |
388 | return; | |
389 | } | |
390 | if (brs = (*s == '{' || *s == Inbrace)) s++; | |
391 | for (;;) | |
392 | if (*s == '^' || *s == Hat) | |
393 | plan9 ^= 1,s++; | |
394 | else if (*s == '=') | |
395 | spbreak ^= 1,s++; | |
396 | else if ((*s == '#' || *s == Pound) && iident(s[1])) | |
397 | getlen = 1,s++; | |
398 | else | |
399 | break; | |
400 | ||
401 | idbeg = s; | |
402 | if (!(v = getvalue(&s,1))) { | |
403 | vunset = 1; | |
404 | idend = s; | |
405 | } else | |
406 | if (isarr = v->isarr) | |
407 | aval = getarrvalue(v); | |
408 | else { | |
409 | val = getstrvalue(v); | |
410 | fwidth = v->pm->ct; | |
411 | switch (v->pm->flags & (PMFLAG_L | PMFLAG_R | PMFLAG_Z)) { | |
412 | char *t; | |
413 | int t0; | |
414 | ||
415 | case PMFLAG_L: | |
416 | case PMFLAG_L|PMFLAG_Z: | |
417 | t = val; | |
418 | if (v->pm->flags & PMFLAG_Z) | |
419 | while (*t == '0') t++; | |
420 | else | |
421 | while (isep(*t)) t++; | |
422 | val = ncalloc(fwidth+1); | |
423 | val[fwidth] = '\0'; | |
424 | if ((t0 = strlen(t)) > fwidth) | |
425 | t0 = fwidth; | |
426 | memset(val,' ',fwidth); | |
427 | strncpy(val,t,t0); | |
428 | break; | |
429 | case PMFLAG_R: | |
430 | case PMFLAG_Z: | |
431 | case PMFLAG_Z|PMFLAG_R: | |
432 | if (strlen(val) < fwidth) { | |
433 | t = ncalloc(fwidth+1); | |
434 | memset(t,(v->pm->flags & PMFLAG_R) ? ' ' : '0',fwidth); | |
435 | if ((t0 = strlen(val)) > fwidth) | |
436 | t0 = fwidth; | |
437 | strcpy(t+(fwidth-t0),val); | |
438 | val = t; | |
439 | } else { | |
440 | t = ncalloc(fwidth+1); | |
441 | t[fwidth] = '\0'; | |
442 | strncpy(t,val+strlen(val)-fwidth,fwidth); | |
443 | val = t; | |
444 | } | |
445 | break; | |
446 | } | |
447 | switch (v->pm->flags & (PMFLAG_l | PMFLAG_u)) { | |
448 | char *t; | |
449 | ||
450 | case PMFLAG_l: | |
451 | t = val; | |
452 | for (;*t;t++) | |
453 | *t = tulower(*t); | |
454 | break; | |
455 | case PMFLAG_u: | |
456 | t = val; | |
457 | for (;*t;t++) | |
458 | *t = tuupper(*t); | |
459 | break; | |
460 | } | |
461 | } | |
462 | if (colf = *s == ':') s++; | |
463 | ||
464 | /* check for ${..?...} or ${..=..} or one of those. Only works | |
465 | if the name is in braces. */ | |
466 | ||
467 | if (brs && (*s == '-' || *s == '=' || *s == '?' || *s == '+' || *s == '#' || | |
468 | *s == '%' || *s == Quest || *s == Pound)) { | |
469 | if (v && v->isarr && (*s == '%' || *s == '#' || *s == Pound)) { | |
470 | zerr("operator requires a scalar",NULL,0); | |
471 | return; | |
472 | } | |
473 | if (*s == s[1]) { | |
474 | s++; | |
475 | doub = 1; | |
476 | } | |
477 | u = ++s; | |
478 | if (brs) { | |
479 | int bct = 1; | |
480 | ||
481 | for (;;) { | |
482 | if (*s == '{' || *s == Inbrace) | |
483 | bct++; | |
484 | else if (*s == '}' || *s == Outbrace) | |
485 | bct--; | |
486 | if (!bct || !*s) | |
487 | break; | |
488 | s++; | |
489 | } | |
490 | } else { | |
491 | while (*s++); | |
492 | s--; | |
493 | } | |
494 | if (*s) *s++ = '\0'; | |
495 | if (colf && !vunset) | |
496 | vunset = (isarr) ? !*aval : !*val; | |
497 | switch ((int)(unsigned char)u[-1]) { | |
498 | case '-': | |
499 | if (vunset) | |
500 | val = strdup(u), isarr = 0; | |
501 | break; | |
502 | case '=': | |
503 | if (vunset) { | |
504 | char sav = *idend; | |
505 | ||
506 | *idend = '\0'; | |
507 | setsparam(idbeg,ztrdup(val = strdup(u))); | |
508 | *idend = sav; | |
509 | isarr = 0; | |
510 | } | |
511 | break; | |
512 | case '?': | |
513 | case (int)(unsigned char)Quest: | |
514 | if (vunset) { | |
515 | zerr("%s",(*u) ? u : "parameter not set",0); | |
516 | if (!interact) | |
517 | exit(1); | |
518 | return; | |
519 | } | |
520 | break; | |
521 | case '+': | |
522 | if (vunset) | |
523 | val = strdup(""); | |
524 | else | |
525 | val = strdup(u); | |
526 | isarr = 0; | |
527 | break; | |
528 | case '#': | |
529 | case (int)(unsigned char)Pound: | |
530 | if (vunset) | |
531 | val = strdup(""); | |
532 | singsub(&u); | |
533 | getmatch(&val,u,doub); | |
534 | break; | |
535 | case '%': | |
536 | if (vunset) | |
537 | val = strdup(""); | |
538 | singsub(&u); | |
539 | getmatch(&val,u,doub+2); | |
540 | break; | |
541 | } | |
542 | } else { /* no ${...=...} or anything, but possible modifiers. */ | |
543 | if (vunset) { | |
544 | if (isset(NOUNSET)) { | |
545 | zerr("parameter not set",NULL,0); | |
546 | return; | |
547 | } | |
548 | val = strdup(""); | |
549 | } | |
550 | if (colf) { | |
551 | s--; | |
552 | if (!isarr) modify(&val,&s); | |
553 | else { | |
554 | char *ss = s; | |
555 | char **ap = aval; | |
556 | while (*ap) { | |
557 | ss = s; | |
558 | modify(ap,&ss); | |
559 | } | |
560 | } | |
561 | } | |
562 | if (brs) { | |
563 | if (*s != '}' && *s != Outbrace) { | |
564 | zerr("closing brace expected",NULL,0); | |
565 | errflag = 1; | |
566 | return; | |
567 | } | |
568 | s++; | |
569 | } | |
570 | } | |
571 | if (errflag) | |
572 | return; | |
573 | if (getlen) { | |
574 | long len = 0; | |
575 | char buf[14]; | |
576 | ||
577 | if (isarr) { | |
578 | char **ctr; | |
579 | for (ctr = aval; *ctr; ctr++,len++); | |
580 | } else | |
581 | len = strlen(val); | |
582 | sprintf(buf,"%ld",len); | |
583 | val = strdup(buf); | |
584 | isarr = 0; | |
585 | } | |
586 | if (isarr) | |
587 | if (!aval || !aval[0]) { | |
588 | if (isarr < 0) | |
589 | wasnularr = 1; | |
590 | val = strdup(""); | |
591 | isarr = 0; | |
592 | } else if (!aval[1]) { | |
593 | val = aval[0]; | |
594 | isarr = 0; | |
595 | } | |
596 | if (qt) { | |
597 | if (isarr > 0) { | |
598 | val = spacejoin(aval); | |
599 | isarr = 0; | |
600 | } | |
601 | } else if (spbreak) { | |
602 | if (isarr) | |
603 | val = spacejoin(aval); | |
604 | isarr = 1; | |
605 | aval = spacesplit(val); | |
606 | if (!aval || !aval[0]) { | |
607 | val = strdup(""); | |
608 | isarr = 0; | |
609 | } else if (!aval[1]) { | |
610 | val = aval[0]; | |
611 | isarr = 0; | |
612 | } | |
613 | /* if only one member, not really an array */ | |
614 | if (!aval[1]) | |
615 | isarr = 0; | |
616 | } | |
617 | if (isarr) | |
618 | if (plan9) { | |
619 | int dlen; | |
620 | char *y; | |
621 | ||
622 | y = ncalloc((dlen = (char *) aptr-bptr+strlen(s)+1)+strlen(aval[0])); | |
623 | setdata(n,y); | |
624 | strcpy(y,ostr); | |
625 | strcat(y,aval[0]); | |
626 | strcat(y,s); | |
627 | while (*++aval) { | |
628 | char *x = ncalloc(dlen+strlen(*aval)); | |
629 | ||
630 | strcpy(x,ostr); | |
631 | strcat(x,*aval); | |
632 | strcat(x,s); | |
633 | insnode(l,n,x), incnode(n); | |
634 | } | |
635 | } else { | |
636 | char *zz; | |
637 | ||
638 | zz = ncalloc((char *) aptr-(bptr)+strlen(aval[0])+1); | |
639 | setdata(n,zz); | |
640 | strcpy(zz,ostr); | |
641 | strcat(zz,*aval++); | |
642 | while (aval[1]) | |
643 | insnode(l,n,*aval++), incnode(n); | |
644 | zz = ncalloc(strlen(*aval)+strlen(s)+1); | |
645 | strcpy(zz,*aval); | |
646 | strcat(zz,s); | |
647 | insnode(l,n,zz); | |
648 | } | |
649 | else { | |
650 | bptr = ncalloc((char *) aptr-bptr+strlen(val)+strlen(s)+1); | |
651 | setdata(n,bptr); | |
652 | strcpy(bptr,ostr); | |
653 | strcat(bptr,val); | |
654 | strcat(bptr,s); | |
655 | } | |
656 | } | |
657 | ||
658 | /* arithmetic substitution */ | |
659 | ||
660 | void arithsubst(aptr,bptr) /**/ | |
661 | vptr *aptr;char **bptr; | |
662 | { | |
663 | char *s = *aptr,*t,buf[16]; | |
664 | long v; | |
665 | ||
666 | *s = '\0'; | |
667 | for (; *s != Outbrack; s++); | |
668 | *s++ = '\0'; | |
669 | v = matheval((char *) *aptr+2); | |
670 | sprintf(buf,"%ld",v); | |
671 | t = ncalloc(strlen(*bptr)+strlen(buf)+strlen(s)+1); | |
672 | strcpy(t,*bptr); | |
673 | strcat(t,buf); | |
674 | strcat(t,s); | |
675 | *bptr = t; | |
676 | } | |
677 | ||
678 | void modify(str,ptr) /**/ | |
679 | char **str;char **ptr; | |
680 | { | |
681 | char *ptr1,*ptr2,*ptr3,del,*lptr; | |
682 | int gbal; | |
683 | ||
684 | if (**ptr == ':') | |
685 | *str = strdup(*str); | |
686 | while (**ptr == ':') | |
687 | { | |
688 | lptr = *ptr; | |
689 | (*ptr)++; | |
690 | gbal = 0; | |
691 | here: | |
692 | switch(*(*ptr)++) | |
693 | { | |
694 | case 'h': remtpath(str); break; | |
695 | case 'r': remtext(str); break; | |
696 | case 'e': rembutext(str); break; | |
697 | case 't': remlpaths(str); break; | |
698 | case 'l': downcase(str); break; | |
699 | case 'u': upcase(str); break; | |
700 | case 's': | |
701 | if (hsubl) | |
702 | free(hsubl); | |
703 | if (hsubr) | |
704 | free(hsubr); | |
705 | ptr1 = *ptr; | |
706 | del = *ptr1++; | |
707 | for (ptr2 = ptr1; *ptr2 != del && *ptr2; ptr2++); | |
708 | if (!*ptr2) | |
709 | { | |
710 | zerr("bad subtitution",NULL,0); | |
711 | errflag = 1; | |
712 | return; | |
713 | } | |
714 | *ptr2++ = '\0'; | |
715 | for (ptr3 = ptr2; *ptr3 != del && *ptr3; ptr3++); | |
716 | if (*ptr3) | |
717 | *ptr3++ = '\0'; | |
718 | hsubl = ztrdup(ptr1); | |
719 | hsubr = ztrdup(ptr2); | |
720 | *ptr = ptr3; | |
721 | case '&': | |
722 | if (hsubl && hsubr) | |
723 | subst(str,hsubl,hsubr,gbal); | |
724 | break; | |
725 | case 'g': gbal = 1; goto here; | |
726 | default: *ptr = lptr; return; | |
727 | } | |
728 | } | |
729 | } | |
730 | ||
731 | /* get a directory stack entry */ | |
732 | ||
733 | char *dstackent(val) /**/ | |
734 | int val; | |
735 | { | |
736 | Lknode node; | |
737 | ||
738 | if ((val < 0 && !firstnode(dirstack)) || !val--) | |
739 | return pwd; | |
740 | if (val < 0) | |
741 | node = lastnode(dirstack); | |
742 | else | |
743 | for (node = firstnode(dirstack); node && val; val--,incnode(node)); | |
744 | if (!node) | |
745 | { | |
746 | zerr("not enough dir stack entries.",NULL,0); | |
747 | errflag = 1; | |
748 | return NULL; | |
749 | } | |
750 | return getdata(node); | |
751 | } | |
752 | ||
753 | /* make an alias hash table node */ | |
754 | ||
755 | struct alias *mkanode(txt,cmflag) /**/ | |
756 | char *txt;int cmflag; | |
757 | { | |
758 | struct alias *ptr = (Alias) zcalloc(sizeof *ptr); | |
759 | ||
760 | ptr->text = txt; | |
761 | ptr->cmd = cmflag; | |
762 | ptr->inuse = 0; | |
763 | return ptr; | |
764 | } |