1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * David Korn <dgk@research.att.com> *
18 * *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22 * Shell macro expander
23 * expands ~
24 * expands ${...}
25 * expands $(...)
26 * expands $((...))
27 * expands `...`
28 *
29 * David Korn
30 * AT&T Labs
31 *
32 */
33
34 #include "defs.h"
35 #include <fcin.h>
36 #include <pwd.h>
37 #include "name.h"
38 #include "variables.h"
39 #include "shlex.h"
40 #include "io.h"
41 #include "jobs.h"
42 #include "shnodes.h"
43 #include "path.h"
44 #include "national.h"
45 #include "streval.h"
46
47 #undef STR_GROUP
48 #ifndef STR_GROUP
49 # define STR_GROUP 0
50 #endif
51
52 #if !SHOPT_MULTIBYTE
53 #define mbchar(p) (*(unsigned char*)p++)
54 #endif
55
56 static int _c_;
57 typedef struct _mac_
58 {
59 Shell_t *shp; /* pointer to shell interpreter */
60 Sfio_t *sp; /* stream pointer for here-document */
61 struct argnod **arghead; /* address of head of argument list */
62 char *ifsp; /* pointer to IFS value */
63 int fields; /* number of fields */
64 short quoted; /* set when word has quotes */
65 unsigned char ifs; /* first char of IFS */
66 char quote; /* set within double quoted contexts */
67 char lit; /* set within single quotes */
68 char split; /* set when word splittin is possible */
69 char pattern; /* set when file expansion follows */
70 char patfound; /* set if pattern character found */
71 char assign; /* set for assignments */
72 char arith; /* set for ((...)) */
73 char let; /* set when expanding let arguments */
74 char zeros; /* strip leading zeros when set */
75 char arrayok; /* $x[] ok for arrays */
76 char subcopy; /* set when copying subscript */
77 int dotdot; /* set for .. in subscript */
78 void *nvwalk; /* for name space walking*/
79 } Mac_t;
80
81 #undef ESCAPE
82 #define ESCAPE '\\'
83 #define isescchar(s) ((s)>S_QUOTE)
84 #define isqescchar(s) ((s)>=S_QUOTE)
85 #define isbracechar(c) ((c)==RBRACE || (_c_=sh_lexstates[ST_BRACE][c])==S_MOD1 ||_c_==S_MOD2)
86 #define ltos(x) fmtbase((long)(x),0,0)
87
88 /* type of macro expansions */
89 #define M_BRACE 1 /* ${var} */
90 #define M_TREE 2 /* ${var.} */
91 #define M_SIZE 3 /* ${#var} */
92 #define M_VNAME 4 /* ${!var} */
93 #define M_SUBNAME 5 /* ${!var[sub]} */
94 #define M_NAMESCAN 6 /* ${!var*} */
95 #define M_NAMECOUNT 7 /* ${#var*} */
96 #define M_TYPE 8 /* ${@var} */
97
98 static int substring(const char*, const char*, int[], int);
99 static void copyto(Mac_t*, int, int);
100 static void comsubst(Mac_t*, Shnode_t*, int);
101 static int varsub(Mac_t*);
102 static void mac_copy(Mac_t*,const char*, int);
103 static void tilde_expand2(Shell_t*,int);
104 static char *sh_tilde(Shell_t*,const char*);
105 static char *special(Shell_t *,int);
106 static void endfield(Mac_t*,int);
107 static void mac_error(Namval_t*);
108 static char *mac_getstring(char*);
109 static int charlen(const char*,int);
110 #if SHOPT_MULTIBYTE
111 static char *lastchar(const char*,const char*);
112 #endif /* SHOPT_MULTIBYTE */
113
sh_macopen(Shell_t * shp)114 void *sh_macopen(Shell_t *shp)
115 {
116 void *addr = newof(0,Mac_t,1,0);
117 Mac_t *mp = (Mac_t*)addr;
118 mp->shp = shp;
119 return(addr);
120 }
121
122 /*
123 * perform only parameter substitution and catch failures
124 */
sh_mactry(Shell_t * shp,register char * string)125 char *sh_mactry(Shell_t *shp,register char *string)
126 {
127 if(string)
128 {
129 int jmp_val;
130 int savexit = shp->savexit;
131 struct checkpt buff;
132 sh_pushcontext(&buff,SH_JMPSUB);
133 jmp_val = sigsetjmp(buff.buff,0);
134 if(jmp_val == 0)
135 string = sh_mactrim(shp,string,0);
136 sh_popcontext(&buff);
137 shp->savexit = savexit;
138 return(string);
139 }
140 return("");
141 }
142
143 /*
144 * Perform parameter expansion, command substitution, and arithmetic
145 * expansion on <str>.
146 * If <mode> greater than 1 file expansion is performed if the result
147 * yields a single pathname.
148 * If <mode> negative, than expansion rules for assignment are applied.
149 */
sh_mactrim(Shell_t * shp,char * str,register int mode)150 char *sh_mactrim(Shell_t *shp, char *str, register int mode)
151 {
152 register Mac_t *mp = (Mac_t*)shp->mac_context;
153 Stk_t *stkp = shp->stk;
154 Mac_t savemac;
155 savemac = *mp;
156 stkseek(stkp,0);
157 mp->arith = (mode==3);
158 mp->let = 0;
159 shp->argaddr = 0;
160 mp->pattern = (mode==1||mode==2);
161 mp->patfound = 0;
162 mp->assign = 0;
163 if(mode<0)
164 mp->assign = -mode;
165 mp->quoted = mp->lit = mp->split = mp->quote = 0;
166 mp->sp = 0;
167 if(mp->ifsp=nv_getval(sh_scoped(shp,IFSNOD)))
168 mp->ifs = *mp->ifsp;
169 else
170 mp->ifs = ' ';
171 stkseek(stkp,0);
172 fcsopen(str);
173 copyto(mp,0,mp->arith);
174 str = stkfreeze(stkp,1);
175 if(mode==2)
176 {
177 /* expand only if unique */
178 struct argnod *arglist=0;
179 if((mode=path_expand(str,&arglist))==1)
180 str = arglist->argval;
181 else if(mode>1)
182 errormsg(SH_DICT,ERROR_exit(1),e_ambiguous,str);
183 sh_trim(str);
184 }
185 *mp = savemac;
186 return(str);
187 }
188
189 /*
190 * Perform all the expansions on the argument <argp>
191 */
sh_macexpand(Shell_t * shp,register struct argnod * argp,struct argnod ** arghead,int flag)192 int sh_macexpand(Shell_t* shp, register struct argnod *argp, struct argnod **arghead,int flag)
193 {
194 register int flags = argp->argflag;
195 register char *str = argp->argval;
196 register Mac_t *mp = (Mac_t*)shp->mac_context;
197 char **saveargaddr = shp->argaddr;
198 Mac_t savemac;
199 Stk_t *stkp = shp->stk;
200 savemac = *mp;
201 mp->sp = 0;
202 if(mp->ifsp=nv_getval(sh_scoped(shp,IFSNOD)))
203 mp->ifs = *mp->ifsp;
204 else
205 mp->ifs = ' ';
206 if((flag&ARG_OPTIMIZE) && !shp->indebug)
207 shp->argaddr = (char**)&argp->argchn.ap;
208 else
209 shp->argaddr = 0;
210 mp->arghead = arghead;
211 mp->quoted = mp->lit = mp->quote = 0;
212 mp->arith = ((flag&ARG_ARITH)!=0);
213 mp->let = ((flag&ARG_LET)!=0);
214 mp->split = !(flag&ARG_ASSIGN);
215 mp->assign = !mp->split;
216 mp->pattern = mp->split && !(flag&ARG_NOGLOB) && !sh_isoption(SH_NOGLOB);
217 mp->arrayok = mp->arith || (flag&ARG_ARRAYOK);
218 str = argp->argval;
219 fcsopen(str);
220 mp->fields = 0;
221 if(!arghead)
222 {
223 mp->split = 0;
224 mp->pattern = ((flag&ARG_EXP)!=0);
225 stkseek(stkp,0);
226 }
227 else
228 {
229 stkseek(stkp,ARGVAL);
230 *stkptr(stkp,ARGVAL-1) = 0;
231 }
232 mp->patfound = 0;
233 if(mp->pattern)
234 mp->arrayok = 0;
235 copyto(mp,0,mp->arith);
236 if(!arghead)
237 {
238 argp->argchn.cp = stkfreeze(stkp,1);
239 if(shp->argaddr)
240 argp->argflag |= ARG_MAKE;
241 }
242 else
243 {
244 endfield(mp,mp->quoted);
245 flags = mp->fields;
246 if(flags==1 && shp->argaddr)
247 argp->argchn.ap = *arghead;
248 }
249 shp->argaddr = saveargaddr;
250 *mp = savemac;
251 return(flags);
252 }
253
254 /*
255 * Expand here document which is stored in <infile> or <string>
256 * The result is written to <outfile>
257 */
sh_machere(Shell_t * shp,Sfio_t * infile,Sfio_t * outfile,char * string)258 void sh_machere(Shell_t *shp,Sfio_t *infile, Sfio_t *outfile, char *string)
259 {
260 register int c,n;
261 register const char *state = sh_lexstates[ST_QUOTE];
262 register char *cp;
263 register Mac_t *mp = (Mac_t*)shp->mac_context;
264 Lex_t *lp = (Lex_t*)mp->shp->lex_context;
265 Fcin_t save;
266 Mac_t savemac;
267 Stk_t *stkp = shp->stk;
268 savemac = *mp;
269 stkseek(stkp,0);
270 shp->argaddr = 0;
271 mp->sp = outfile;
272 mp->split = mp->assign = mp->pattern = mp->patfound = mp->lit = mp->arith = mp->let = 0;
273 mp->quote = 1;
274 mp->ifsp = nv_getval(sh_scoped(shp,IFSNOD));
275 mp->ifs = ' ';
276 fcsave(&save);
277 if(infile)
278 fcfopen(infile);
279 else
280 fcsopen(string);
281 fcnotify(0,lp);
282 cp = fcseek(0);
283 while(1)
284 {
285 #if SHOPT_MULTIBYTE
286 if(mbwide())
287 {
288 do
289 {
290 ssize_t len;
291 switch(len = mbsize(cp))
292 {
293 case -1: /* illegal multi-byte char */
294 case 0:
295 case 1:
296 n=state[*(unsigned char*)cp++];
297 break;
298 default:
299 /* use state of alpha character */
300 n=state['a'];
301 cp += len;
302 }
303 }
304 while(n == 0);
305 }
306 else
307 #endif /* SHOPT_MULTIBYTE */
308 while((n=state[*(unsigned char*)cp++])==0);
309 if(n==S_NL || n==S_QUOTE || n==S_RBRA)
310 continue;
311 if(c=(cp-1)-fcseek(0))
312 sfwrite(outfile,fcseek(0),c);
313 cp = fcseek(c+1);
314 switch(n)
315 {
316 case S_EOF:
317 if((n=fcfill()) <=0)
318 {
319 /* ignore 0 byte when reading from file */
320 if(n==0 && fcfile())
321 continue;
322 fcrestore(&save);
323 *mp = savemac;
324 return;
325 }
326 cp = fcseek(-1);
327 continue;
328 case S_ESC:
329 fcgetc(c);
330 cp=fcseek(-1);
331 if(c>0)
332 cp++;
333 if(!isescchar(state[c]))
334 sfputc(outfile,ESCAPE);
335 continue;
336 case S_GRAVE:
337 comsubst(mp,(Shnode_t*)0,0);
338 break;
339 case S_DOL:
340 c = fcget();
341 if(c=='.')
342 goto regular;
343 again:
344 switch(n=sh_lexstates[ST_DOL][c])
345 {
346 case S_ALP: case S_SPC1: case S_SPC2:
347 case S_DIG: case S_LBRA:
348 {
349 Fcin_t save2;
350 int offset = stktell(stkp);
351 int offset2;
352 sfputc(stkp,c);
353 if(n==S_LBRA)
354 {
355 c = fcget();
356 fcseek(-1);
357 if(sh_lexstates[ST_NORM][c]==S_BREAK)
358 {
359 comsubst(mp,(Shnode_t*)0,2);
360 break;
361 }
362 sh_lexskip(lp,RBRACE,1,ST_BRACE);
363 }
364 else if(n==S_ALP)
365 {
366 while(fcgetc(c),isaname(c))
367 sfputc(stkp,c);
368 fcseek(-1);
369 }
370 sfputc(stkp,0);
371 offset2 = stktell(stkp);
372 fcsave(&save2);
373 fcsopen(stkptr(stkp,offset));
374 varsub(mp);
375 if(c=stktell(stkp)-offset2)
376 sfwrite(outfile,(char*)stkptr(stkp,offset2),c);
377 fcrestore(&save2);
378 stkseek(stkp,offset);
379 break;
380 }
381 case S_PAR:
382 comsubst(mp,(Shnode_t*)0,1);
383 break;
384 case S_EOF:
385 if((c=fcfill()) > 0)
386 goto again;
387 /* FALL THRU */
388 default:
389 regular:
390 sfputc(outfile,'$');
391 fcseek(-1);
392 break;
393 }
394 }
395 cp = fcseek(0);
396 }
397 }
398
399 /*
400 * expand argument but do not trim pattern characters
401 */
sh_macpat(Shell_t * shp,register struct argnod * arg,int flags)402 char *sh_macpat(Shell_t *shp,register struct argnod *arg, int flags)
403 {
404 register char *sp = arg->argval;
405 if((arg->argflag&ARG_RAW))
406 return(sp);
407 sh_stats(STAT_ARGEXPAND);
408 if(flags&ARG_OPTIMIZE)
409 arg->argchn.ap=0;
410 if(!(sp=arg->argchn.cp))
411 {
412 sh_macexpand(shp,arg,NIL(struct argnod**),flags|ARG_ARRAYOK);
413 sp = arg->argchn.cp;
414 if(!(flags&ARG_OPTIMIZE) || !(arg->argflag&ARG_MAKE))
415 arg->argchn.cp = 0;
416 arg->argflag &= ~ARG_MAKE;
417 }
418 else
419 sh_stats(STAT_ARGHITS);
420 return(sp);
421 }
422
423 /*
424 * Process the characters up to <endch> or end of input string
425 */
copyto(register Mac_t * mp,int endch,int newquote)426 static void copyto(register Mac_t *mp,int endch, int newquote)
427 {
428 register int c,n;
429 register const char *state = sh_lexstates[ST_MACRO];
430 register char *cp,*first;
431 Lex_t *lp = (Lex_t*)mp->shp->lex_context;
432 int tilde = -1;
433 int oldquote = mp->quote;
434 int ansi_c = 0;
435 int paren = 0;
436 int ere = 0;
437 int brace = 0;
438 Sfio_t *sp = mp->sp;
439 Stk_t *stkp = mp->shp->stk;
440 mp->sp = NIL(Sfio_t*);
441 mp->quote = newquote;
442 first = cp = fcseek(0);
443 if(!mp->quote && *cp=='~' && cp[1]!=LPAREN)
444 tilde = stktell(stkp);
445 /* handle // operator specially */
446 if(mp->pattern==2 && *cp=='/')
447 cp++;
448 while(1)
449 {
450 #if SHOPT_MULTIBYTE
451 if(mbwide())
452 {
453 ssize_t len;
454 do
455 {
456 switch(len = mbsize(cp))
457 {
458 case -1: /* illegal multi-byte char */
459 case 0:
460 len = 1;
461 case 1:
462 n = state[*(unsigned char*)cp++];
463 break;
464 default:
465 /* treat as if alpha */
466 cp += len;
467 n=state['a'];
468 }
469 }
470 while(n == 0);
471 c = (cp-len) - first;
472 }
473 else
474 #endif /* SHOPT_MULTIBYTE */
475 {
476 while((n=state[*(unsigned char*)cp++])==0);
477 c = (cp-1) - first;
478 }
479 switch(n)
480 {
481 case S_ESC:
482 if(ansi_c)
483 {
484 /* process ANSI-C escape character */
485 char *addr= --cp;
486 if(c)
487 sfwrite(stkp,first,c);
488 c = chresc(cp,&addr);
489 cp = addr;
490 first = fcseek(cp-first);
491 #if SHOPT_MULTIBYTE
492 if(c > UCHAR_MAX && mbwide())
493 {
494 int i;
495 unsigned char mb[8];
496
497 n = wctomb((char*)mb, c);
498 for(i=0;i<n;i++)
499 sfputc(stkp,mb[i]);
500 }
501 else
502 #endif /* SHOPT_MULTIBYTE */
503 sfputc(stkp,c);
504 if(c==ESCAPE && mp->pattern)
505 sfputc(stkp,ESCAPE);
506 break;
507 }
508 else if(sh_isoption(SH_BRACEEXPAND) && mp->pattern==4 && (*cp==',' || *cp==LBRACE || *cp==RBRACE || *cp=='.'))
509 break;
510 else if(mp->split && endch && !mp->quote && !mp->lit)
511 {
512 if(c)
513 mac_copy(mp,first,c);
514 cp = fcseek(c+2);
515 if(c= cp[-1])
516 {
517 sfputc(stkp,c);
518 if(c==ESCAPE)
519 sfputc(stkp,ESCAPE);
520 }
521 else
522 cp--;
523 first = cp;
524 break;
525 }
526 n = state[*(unsigned char*)cp];
527 if(n==S_ENDCH && *cp!=endch)
528 n = S_PAT;
529 if(mp->pattern)
530 {
531 /* preserve \digit for pattern matching */
532 /* also \alpha for extended patterns */
533 if(!mp->lit && !mp->quote)
534 {
535 if((n==S_DIG || ((paren+ere) && sh_lexstates[ST_DOL][*(unsigned char*)cp]==S_ALP)))
536 break;
537 if(ere && mp->pattern==1 && strchr(".[()*+?{|^$&!",*cp))
538 break;
539 }
540 /* followed by file expansion */
541 if(!mp->lit && (n==S_ESC || (!mp->quote &&
542 (n==S_PAT||n==S_ENDCH||n==S_SLASH||n==S_BRACT||*cp=='-'))))
543 {
544 cp += (n!=S_EOF);
545 if(ere && n==S_ESC && *cp =='\\' && cp[1]=='$')
546 {
547 /* convert \\\$ into \$' */
548 sfwrite(stkp,first,c+1);
549 cp = first = fcseek(c+3);
550 }
551 break;
552 }
553 if(!(ere && *cp=='$') && (mp->lit || (mp->quote && !isqescchar(n) && n!=S_ENDCH)))
554 {
555 /* add \ for file expansion */
556 sfwrite(stkp,first,c+1);
557 first = fcseek(c);
558 break;
559 }
560 }
561 if(mp->lit)
562 break;
563 if(!mp->quote || isqescchar(n) || n==S_ENDCH)
564 {
565 /* eliminate \ */
566 if(c)
567 sfwrite(stkp,first,c);
568 /* check new-line joining */
569 first = fcseek(c+1);
570 }
571 cp += (n!=S_EOF);
572 break;
573 case S_GRAVE: case S_DOL:
574 if(mp->lit)
575 break;
576 if(c)
577 {
578 if(mp->split && !mp->quote && endch)
579 mac_copy(mp,first,c);
580 else
581 sfwrite(stkp,first,c);
582 }
583 first = fcseek(c+1);
584 c = mp->pattern;
585 if(n==S_GRAVE)
586 comsubst(mp,(Shnode_t*)0,0);
587 else if((n= *cp)==0 || !varsub(mp))
588 {
589 if(n=='\'' && !mp->quote)
590 ansi_c = 1;
591 else if(mp->quote || n!='"')
592 sfputc(stkp,'$');
593 }
594 cp = first = fcseek(0);
595 if(*cp)
596 mp->pattern = c;
597 break;
598 case S_ENDCH:
599 if((mp->lit || cp[-1]!=endch || mp->quote!=newquote))
600 goto pattern;
601 if(endch==RBRACE && *cp==LPAREN && mp->pattern && brace)
602 goto pattern;
603 case S_EOF:
604 if(c)
605 {
606 if(mp->split && !mp->quote && !mp->lit && endch)
607 mac_copy(mp,first,c);
608 else
609 sfwrite(stkp,first,c);
610 }
611 c += (n!=S_EOF);
612 first = fcseek(c);
613 if(tilde>=0)
614 tilde_expand2(mp->shp,tilde);
615 goto done;
616 case S_QUOTE:
617 if(mp->lit || mp->arith)
618 break;
619 case S_LIT:
620 if(mp->arith)
621 {
622 if((*cp=='`' || *cp=='[') && cp[1]=='\'')
623 cp +=2;
624 break;
625 }
626 if(n==S_LIT && mp->quote)
627 break;
628 if(c)
629 {
630 if(mp->split && endch && !mp->quote && !mp->lit)
631 mac_copy(mp,first,c);
632 else
633 sfwrite(stkp,first,c);
634 }
635 first = fcseek(c+1);
636 if(n==S_LIT)
637 {
638 if(mp->quote)
639 continue;
640 if(mp->lit)
641 mp->lit = ansi_c = 0;
642 else
643 mp->lit = 1;
644 }
645 else
646 mp->quote = !mp->quote;
647 mp->quoted++;
648 break;
649 case S_BRACT:
650 if(mp->arith || (((mp->assign&1) || endch==RBRACT) &&
651 !(mp->quote || mp->lit)))
652 {
653 int offset=0,oldpat = mp->pattern;
654 int oldarith = mp->arith, oldsub=mp->subcopy;
655 sfwrite(stkp,first,++c);
656 if(mp->assign&1)
657 {
658 if(first[c-2]=='.')
659 offset = stktell(stkp);
660 if(isastchar(*cp) && cp[1]==']')
661 errormsg(SH_DICT,ERROR_exit(1),
662 e_badsubscript,*cp);
663 }
664 first = fcseek(c);
665 mp->pattern = 4;
666 mp->arith = 0;
667 mp->subcopy = 0;
668 copyto(mp,RBRACT,0);
669 mp->subcopy = oldsub;
670 mp->arith = oldarith;
671 mp->pattern = oldpat;
672 sfputc(stkp,RBRACT);
673 if(offset)
674 {
675 cp = stkptr(stkp,stktell(stkp));
676 if(sh_checkid(stkptr(stkp,offset),cp)!=cp)
677 stkseek(stkp,stktell(stkp)-2);
678 }
679 cp = first = fcseek(0);
680 break;
681 }
682 case S_PAT:
683 if(mp->pattern && !(mp->quote || mp->lit))
684 {
685 mp->patfound = mp->pattern;
686 if((n=cp[-1])==LPAREN)
687 {
688 paren++;
689 if((cp-first)>1 && cp[-2]=='~')
690 {
691 char *p = cp;
692 while((c=mbchar(p)) && c!=RPAREN && c!='E');
693 ere = (c=='E'||c=='A');
694 }
695 }
696 else if(n==RPAREN)
697 --paren;
698 }
699 goto pattern;
700 case S_COM:
701 if(mp->pattern==4 && (mp->quote || mp->lit))
702 {
703 if(c)
704 {
705 sfwrite(stkp,first,c);
706 first = fcseek(c);
707 }
708 sfputc(stkp,ESCAPE);
709 }
710 break;
711 case S_BRACE:
712 if(!(mp->quote || mp->lit))
713 {
714 mp->patfound = mp->split && sh_isoption(SH_BRACEEXPAND);
715 brace = 1;
716 }
717 pattern:
718 if(!mp->pattern || !(mp->quote || mp->lit))
719 {
720 /* mark beginning of {a,b} */
721 if(n==S_BRACE && endch==0 && mp->pattern)
722 mp->pattern=4;
723 if(n==S_SLASH && mp->pattern==2)
724 mp->pattern=3;
725 break;
726 }
727 if(mp->pattern==3)
728 break;
729 if(c)
730 sfwrite(stkp,first,c);
731 first = fcseek(c);
732 sfputc(stkp,ESCAPE);
733 break;
734 case S_EQ:
735 if(mp->assign==1)
736 {
737 if(*cp=='~' && !endch && !mp->quote && !mp->lit)
738 tilde = stktell(stkp)+(c+1);
739 mp->assign = 2;
740 }
741 break;
742 case S_SLASH:
743 case S_COLON:
744 if(tilde >=0)
745 {
746 if(c)
747 sfwrite(stkp,first,c);
748 first = fcseek(c);
749 tilde_expand2(mp->shp,tilde);
750 tilde = -1;
751 c=0;
752 }
753 if(n==S_COLON && mp->assign==2 && *cp=='~' && endch==0 && !mp->quote &&!mp->lit)
754 tilde = stktell(stkp)+(c+1);
755 else if(n==S_SLASH && mp->pattern==2)
756 #if 0
757 goto pattern;
758 #else
759 {
760 if(mp->quote || mp->lit)
761 goto pattern;
762 sfwrite(stkp,first,c+1);
763 first = fcseek(c+1);
764 c = stktell(stkp);
765 sh_lexskip(lp,RBRACE,0,ST_NESTED);
766 stkseek(stkp,c);
767 cp = fcseek(-1);
768 sfwrite(stkp,first,cp-first);
769 first=cp;
770 }
771 #endif
772 break;
773 case S_DOT:
774 if(*cp=='.' && mp->subcopy==1)
775 {
776 sfwrite(stkp,first,c);
777 sfputc(stkp,0);
778 mp->dotdot = stktell(stkp);
779 cp = first = fcseek(c+2);
780 }
781 break;
782 }
783 }
784 done:
785 mp->sp = sp;
786 mp->quote = oldquote;
787 }
788
789 /*
790 * copy <str> to stack performing sub-expression substitutions
791 */
mac_substitute(Mac_t * mp,register char * cp,char * str,register int subexp[],int subsize)792 static void mac_substitute(Mac_t *mp, register char *cp,char *str,register int subexp[],int subsize)
793 {
794 register int c,n;
795 register char *first=fcseek(0);
796 char *ptr;
797 Mac_t savemac;
798 Stk_t *stkp = mp->shp->stk;
799 n = stktell(stkp);
800 savemac = *mp;
801 mp->pattern = 3;
802 mp->split = 0;
803 fcsopen(cp);
804 copyto(mp,0,0);
805 sfputc(stkp,0);
806 ptr = cp = strdup(stkptr(stkp,n));
807 stkseek(stkp,n);
808 *mp = savemac;
809 fcsopen(first);
810 first = cp;
811 while(1)
812 {
813 while((c= *cp++) && c!=ESCAPE);
814 if(c==0)
815 break;
816 if((n= *cp++)=='\\' || n==RBRACE || (n>='0' && n<='9' && (n-='0')<subsize))
817 {
818 c = cp-first-2;
819 if(c)
820 mac_copy(mp,first,c);
821 first=cp;
822 if(n=='\\' || n==RBRACE)
823 {
824 first--;
825 continue;
826 }
827 if((c=subexp[2*n])>=0)
828 {
829 if((n=subexp[2*n+1]-c)>0)
830 mac_copy(mp,str+c,n);
831 }
832 }
833 else if(n==0)
834 break;
835 }
836 if(n=cp-first-1)
837 mac_copy(mp,first,n);
838 free(ptr);
839 }
840
841 #if SHOPT_FILESCAN
842 #define MAX_OFFSETS (sizeof(shp->offsets)/sizeof(shp->offsets[0]))
843 #define MAX_ARGN (32*1024)
844
845 /*
846 * compute the arguments $1 ... $n and $# from the current line as needed
847 * save line offsets in the offsets array.
848 */
getdolarg(Shell_t * shp,int n,int * size)849 static char *getdolarg(Shell_t *shp, int n, int *size)
850 {
851 register int c=S_DELIM, d=shp->ifstable['\\'];
852 register unsigned char *first,*last,*cp = (unsigned char*)shp->cur_line;
853 register int m=shp->offsets[0],delim=0;
854 if(m==0)
855 return(0);
856 if(m<0)
857 m = 0;
858 else if(n<=m)
859 m = n-1;
860 else
861 m--;
862 if(m >= MAX_OFFSETS-1)
863 m = MAX_OFFSETS-2;
864 cp += shp->offsets[m+1];
865 n -= m;
866 shp->ifstable['\\'] = 0;
867 shp->ifstable[0] = S_EOF;
868 while(1)
869 {
870 if(c==S_DELIM)
871 while(shp->ifstable[*cp++]==S_SPACE);
872 first = --cp;
873 if(++m < MAX_OFFSETS)
874 shp->offsets[m] = (first-(unsigned char*)shp->cur_line);
875 while((c=shp->ifstable[*cp++])==0);
876 last = cp-1;
877 if(c==S_SPACE)
878 while((c=shp->ifstable[*cp++])==S_SPACE);
879 if(--n==0 || c==S_EOF)
880 {
881 if(last==first && c==S_EOF && (!delim || (m>1)))
882 {
883 n++;
884 m--;
885 }
886 break;
887 }
888 delim = (c==S_DELIM);
889 }
890 shp->ifstable['\\'] = d;
891 if(m > shp->offsets[0])
892 shp->offsets[0] = m;
893 if(n)
894 first = last = 0;
895 if(size)
896 *size = last-first;
897 return((char*)first);
898 }
899 #endif /* SHOPT_FILESCAN */
900
901 /*
902 * get the prefix after name reference resolution
903 */
prefix(Shell_t * shp,char * id)904 static char *prefix(Shell_t *shp, char *id)
905 {
906 Namval_t *np;
907 register char *sub=0, *cp = strchr(id,'.');
908 if(cp)
909 {
910 *cp = 0;
911 np = nv_search(id, shp->var_tree,0);
912 *cp = '.';
913 if(isastchar(cp[1]))
914 cp[1] = 0;
915 if(np && nv_isref(np))
916 {
917 int n;
918 char *sp;
919 shp->argaddr = 0;
920 while(nv_isref(np) && np->nvalue.cp)
921 {
922 sub = nv_refsub(np);
923 np = nv_refnode(np);
924 if(sub)
925 nv_putsub(np,sub,0L);
926 }
927 id = (char*)malloc(strlen(cp)+1+(n=strlen(sp=nv_name(np)))+ (sub?strlen(sub)+3:1));
928 memcpy(id,sp,n);
929 if(sub)
930 {
931 id[n++] = '[';
932 strcpy(&id[n],sub);
933 n+= strlen(sub)+1;
934 id[n-1] = ']';
935 }
936 strcpy(&id[n],cp);
937 return(id);
938 }
939 }
940 return(strdup(id));
941 }
942
943 /*
944 * copy to ']' onto the stack and return offset to it
945 */
subcopy(Mac_t * mp,int flag)946 static int subcopy(Mac_t *mp, int flag)
947 {
948 int split = mp->split;
949 int xpattern = mp->pattern;
950 int loc = stktell(mp->shp->stk);
951 int xarith = mp->arith;
952 int arrayok = mp->arrayok;
953 mp->split = 0;
954 mp->arith = 0;
955 mp->pattern = flag?4:0;
956 mp->arrayok=1;
957 mp->subcopy++;
958 mp->dotdot = 0;
959 copyto(mp,RBRACT,0);
960 mp->subcopy = 0;
961 mp->pattern = xpattern;
962 mp->split = split;
963 mp->arith = xarith;
964 mp->arrayok = arrayok;
965 return(loc);
966 }
967
968 /*
969 * if name is a discipline function, run the function and put the results
970 * on the stack so that ${x.foo} behaves like ${ x.foo;}
971 */
sh_macfun(Shell_t * shp,const char * name,int offset)972 int sh_macfun(Shell_t *shp, const char *name, int offset)
973 {
974 Namval_t *np, *nq;
975 np = nv_bfsearch(name,shp->fun_tree,&nq,(char**)0);
976 if(np)
977 {
978 /* treat ${x.foo} as ${x.foo;} */
979 Shnode_t *tp;
980 char buff[sizeof(struct dolnod)+sizeof(char*)];
981 struct comnod node;
982 struct dolnod *dp = (struct dolnod*)buff;
983 memset(&node,0,sizeof(node));
984 memset(&buff,0,sizeof(buff));
985 tp = (Shnode_t*)&node;
986 tp->com.comarg = (struct argnod*)dp;
987 tp->com.comline = shp->inlineno;
988 dp->dolnum = 1;
989 dp->dolval[0] = strdup(name);
990 stkseek(shp->stk,offset);
991 comsubst((Mac_t*)shp->mac_context,tp,2);
992 free(dp->dolval[0]);
993 return(1);
994 }
995 return(0);
996 }
997
namecount(Mac_t * mp,const char * prefix)998 static int namecount(Mac_t *mp,const char *prefix)
999 {
1000 int count = 0;
1001 mp->nvwalk = nv_diropen((Namval_t*)0,prefix);
1002 while(nv_dirnext(mp->nvwalk))
1003 count++;
1004 nv_dirclose(mp->nvwalk);
1005 return(count);
1006 }
1007
nextname(Mac_t * mp,const char * prefix,int len)1008 static char *nextname(Mac_t *mp,const char *prefix, int len)
1009 {
1010 char *cp;
1011 if(len==0)
1012 {
1013 mp->nvwalk = nv_diropen((Namval_t*)0,prefix);
1014 return((char*)mp->nvwalk);
1015 }
1016 if(!(cp=nv_dirnext(mp->nvwalk)))
1017 nv_dirclose(mp->nvwalk);
1018 return(cp);
1019 }
1020
1021 /*
1022 * This routine handles $param, ${parm}, and ${param op word}
1023 * The input stream is assumed to be a string
1024 */
varsub(Mac_t * mp)1025 static int varsub(Mac_t *mp)
1026 {
1027 register int c;
1028 register int type=0; /* M_xxx */
1029 register char *v,*argp=0;
1030 register Namval_t *np = NIL(Namval_t*);
1031 register int dolg=0, mode=0;
1032 Lex_t *lp = (Lex_t*)mp->shp->lex_context;
1033 Namarr_t *ap=0;
1034 int dolmax=0, vsize= -1, offset= -1, nulflg, replen=0, bysub=0;
1035 char idbuff[3], *id = idbuff, *pattern=0, *repstr, *arrmax=0;
1036 int var=1,addsub=0,oldpat=mp->pattern,idnum=0,flag=0,d;
1037 Stk_t *stkp = mp->shp->stk;
1038 retry1:
1039 mp->zeros = 0;
1040 idbuff[0] = 0;
1041 idbuff[1] = 0;
1042 c = fcget();
1043 switch(isascii(c)?sh_lexstates[ST_DOL][c]:S_ALP)
1044 {
1045 case S_RBRA:
1046 if(type<M_SIZE)
1047 goto nosub;
1048 /* This code handles ${#} */
1049 c = mode;
1050 mode = type = 0;
1051 /* FALL THRU */
1052 case S_SPC1:
1053 if(type==M_BRACE)
1054 {
1055 if(isaletter(mode=fcpeek(0)) || mode=='.')
1056 {
1057 if(c=='#')
1058 type = M_SIZE;
1059 #ifdef SHOPT_TYPEDEF
1060 else if(c=='@')
1061 {
1062 type = M_TYPE;
1063 goto retry1;
1064 }
1065 #endif /* SHOPT_TYPEDEF */
1066 else
1067 type = M_VNAME;
1068 mode = c;
1069 goto retry1;
1070 }
1071 else if(c=='#' && (isadigit(mode)||fcpeek(1)==RBRACE))
1072 {
1073 type = M_SIZE;
1074 mode = c;
1075 goto retry1;
1076 }
1077 }
1078 /* FALL THRU */
1079 case S_SPC2:
1080 var = 0;
1081 *id = c;
1082 v = special(mp->shp,c);
1083 if(isastchar(c))
1084 {
1085 mode = c;
1086 #if SHOPT_FILESCAN
1087 if(mp->shp->cur_line)
1088 {
1089 v = getdolarg(&sh,1,(int*)0);
1090 dolmax = MAX_ARGN;
1091 }
1092 else
1093 #endif /* SHOPT_FILESCAN */
1094 dolmax = mp->shp->st.dolc+1;
1095 dolg = (v!=0);
1096 }
1097 break;
1098 case S_LBRA:
1099 if(type)
1100 goto nosub;
1101 type = M_BRACE;
1102 goto retry1;
1103 case S_PAR:
1104 if(type)
1105 goto nosub;
1106 comsubst(mp,(Shnode_t*)0,1);
1107 return(1);
1108 case S_DIG:
1109 var = 0;
1110 c -= '0';
1111 mp->shp->argaddr = 0;
1112 if(type)
1113 {
1114 register int d;
1115 while((d=fcget()),isadigit(d))
1116 c = 10*c + (d-'0');
1117 fcseek(-1);
1118 }
1119 idnum = c;
1120 if(c==0)
1121 v = special(mp->shp,c);
1122 #if SHOPT_FILESCAN
1123 else if(mp->shp->cur_line)
1124 {
1125 mp->shp->used_pos = 1;
1126 v = getdolarg(&sh,c,&vsize);
1127 }
1128 #endif /* SHOPT_FILESCAN */
1129 else if(c <= mp->shp->st.dolc)
1130 {
1131 mp->shp->used_pos = 1;
1132 v = mp->shp->st.dolv[c];
1133 }
1134 else
1135 v = 0;
1136 break;
1137 case S_ALP:
1138 if(c=='.' && type==0)
1139 goto nosub;
1140 offset = stktell(stkp);
1141 do
1142 {
1143 np = 0;
1144 do
1145 sfputc(stkp,c);
1146 while(((c=fcget()),(!isascii(c)||isaname(c)))||type && c=='.');
1147 while(c==LBRACT && (type||mp->arrayok))
1148 {
1149 mp->shp->argaddr=0;
1150 if((c=fcget(),isastchar(c)) && fcpeek(0)==RBRACT)
1151 {
1152 if(type==M_VNAME)
1153 type = M_SUBNAME;
1154 idbuff[0] = mode = c;
1155 fcget();
1156 c = fcget();
1157 if(c=='.' || c==LBRACT)
1158 {
1159 sfputc(stkp,LBRACT);
1160 sfputc(stkp,mode);
1161 sfputc(stkp,RBRACT);
1162 }
1163 else
1164 flag = NV_ARRAY;
1165 break;
1166 }
1167 else
1168 {
1169 fcseek(-1);
1170 c = stktell(stkp);
1171 sfputc(stkp,LBRACT);
1172 v = stkptr(stkp,subcopy(mp,1));
1173 if(type && mp->dotdot)
1174 {
1175 mode = '@';
1176 v[-1] = 0;
1177 if(type==M_VNAME)
1178 type = M_SUBNAME;
1179 else if(type==M_SIZE)
1180 goto nosub;
1181 }
1182 else
1183 sfputc(stkp,RBRACT);
1184 c = fcget();
1185 if(c==0 && type==M_VNAME)
1186 type = M_SUBNAME;
1187 }
1188 }
1189 }
1190 while(type && c=='.');
1191 if(c==RBRACE && type && fcpeek(-2)=='.')
1192 {
1193 /* ${x.} or ${x..} */
1194 if(fcpeek(-3) == '.')
1195 {
1196 stkseek(stkp,stktell(stkp)-2);
1197 nv_local = 1;
1198 }
1199 else
1200 {
1201 stkseek(stkp,stktell(stkp)-1);
1202 type = M_TREE;
1203 }
1204 }
1205 sfputc(stkp,0);
1206 id=stkptr(stkp,offset);
1207 if(isastchar(c) && type)
1208 {
1209 if(type==M_VNAME || type==M_SIZE)
1210 {
1211 idbuff[0] = mode = c;
1212 if((d=fcpeek(0))==c)
1213 idbuff[1] = fcget();
1214 if(type==M_VNAME)
1215 type = M_NAMESCAN;
1216 else
1217 type = M_NAMECOUNT;
1218 break;
1219 }
1220 goto nosub;
1221 }
1222 flag |= NV_NOASSIGN|NV_VARNAME|NV_NOADD;
1223 if(c=='=' || c=='?' || (c==':' && ((d=fcpeek(0))=='=' || d=='?')))
1224 flag &= ~NV_NOADD;
1225 #if SHOPT_FILESCAN
1226 if(mp->shp->cur_line && *id=='R' && strcmp(id,"REPLY")==0)
1227 {
1228 mp->shp->argaddr=0;
1229 np = REPLYNOD;
1230 }
1231 else
1232 #endif /* SHOPT_FILESCAN */
1233 {
1234 if(mp->shp->argaddr)
1235 flag &= ~NV_NOADD;
1236 np = nv_open(id,mp->shp->var_tree,flag|NV_NOFAIL);
1237 }
1238 if(isastchar(mode))
1239 var = 0;
1240 if((!np || nv_isnull(np)) && type==M_BRACE && c==RBRACE && !(flag&NV_ARRAY) && strchr(id,'.'))
1241 {
1242 if(sh_macfun(mp->shp,id,offset))
1243 {
1244 fcget();
1245 return(1);
1246 }
1247 }
1248 if(np && (flag&NV_NOADD) && nv_isnull(np))
1249 {
1250 if(nv_isattr(np,NV_NOFREE))
1251 nv_offattr(np,NV_NOFREE);
1252 else
1253 np = 0;
1254 }
1255 ap = np?nv_arrayptr(np):0;
1256 if(type)
1257 {
1258 if(mp->dotdot)
1259 {
1260 if(ap)
1261 {
1262 nv_putsub(np,v,ARRAY_SCAN);
1263 v = stkptr(stkp,mp->dotdot);
1264 dolmax =1;
1265 if(array_assoc(ap))
1266 arrmax = strdup(v);
1267 else if((dolmax = (int)sh_arith(v))<0)
1268 dolmax += array_maxindex(np);
1269 if(type==M_SUBNAME)
1270 bysub = 1;
1271 }
1272 else
1273 {
1274 if((int)sh_arith(v))
1275 np = 0;
1276 }
1277 }
1278 else if(ap && (isastchar(mode)||type==M_TREE) && !(ap->nelem&ARRAY_SCAN) && type!=M_SIZE)
1279 nv_putsub(np,NIL(char*),ARRAY_SCAN);
1280 if(!isbracechar(c))
1281 goto nosub;
1282 else
1283 fcseek(-1);
1284 }
1285 else
1286 fcseek(-1);
1287 if(type<=1 && np && nv_isvtree(np) && mp->pattern==1 && !mp->split)
1288 {
1289 int peek=1,cc=fcget();
1290 if(type && cc=='}')
1291 {
1292 cc = fcget();
1293 peek = 2;
1294 }
1295 if(mp->quote && cc=='"')
1296 {
1297 cc = fcget();
1298 peek++;
1299 }
1300 fcseek(-peek);
1301 if(cc==0)
1302 mp->assign = 1;
1303 }
1304 if((type==M_VNAME||type==M_SUBNAME) && mp->shp->argaddr && strcmp(nv_name(np),id))
1305 mp->shp->argaddr = 0;
1306 c = (type>M_BRACE && isastchar(mode));
1307 if(np && (type==M_TREE || !c || !ap))
1308 {
1309 char *savptr;
1310 c = *((unsigned char*)stkptr(stkp,offset-1));
1311 savptr = stkfreeze(stkp,0);
1312 if(type==M_VNAME || (type==M_SUBNAME && ap))
1313 {
1314 type = M_BRACE;
1315 v = nv_name(np);
1316 if(ap && !mp->dotdot && !(ap->nelem&ARRAY_UNDEF))
1317 addsub = 1;
1318 }
1319 #ifdef SHOPT_TYPEDEF
1320 else if(type==M_TYPE)
1321 {
1322 Namval_t *nq = nv_type(np);
1323 type = M_BRACE;
1324 if(nq)
1325 nv_typename(nq,mp->shp->strbuf);
1326 else
1327 nv_attribute(np,mp->shp->strbuf,"typeset",1);
1328 v = sfstruse(mp->shp->strbuf);
1329 }
1330 #endif /* SHOPT_TYPEDEF */
1331 #if SHOPT_FILESCAN
1332 else if(mp->shp->cur_line && np==REPLYNOD)
1333 v = mp->shp->cur_line;
1334 #endif /* SHOPT_FILESCAN */
1335 else if(type==M_TREE)
1336 v = nv_getvtree(np,(Namfun_t*)0);
1337 else
1338 {
1339 if(type && fcpeek(0)=='+')
1340 {
1341 if(ap)
1342 v = nv_arrayisset(np,ap)?(char*)"x":0;
1343 else
1344 v = nv_isnull(np)?0:(char*)"x";
1345 }
1346 else
1347 v = nv_getval(np);
1348 /* special case --- ignore leading zeros */
1349 if( (mp->arith||mp->let) && (np->nvfun || nv_isattr(np,(NV_LJUST|NV_RJUST|NV_ZFILL))) && (offset==0 || !isalnum(c)))
1350 mp->zeros = 1;
1351 }
1352 if(savptr==stakptr(0))
1353 stkseek(stkp,offset);
1354 else
1355 stkset(stkp,savptr,offset);
1356 }
1357 else
1358 {
1359 v = 0;
1360 if(type==M_VNAME)
1361 {
1362 v = id;
1363 type = M_BRACE;
1364 }
1365 else if(type==M_TYPE)
1366 type = M_BRACE;
1367 }
1368 stkseek(stkp,offset);
1369 if(ap)
1370 {
1371 #if SHOPT_OPTIMIZE
1372 if(mp->shp->argaddr)
1373 nv_optimize(np);
1374 #endif
1375 if(isastchar(mode) && array_elem(ap)> !c)
1376 dolg = -1;
1377 else
1378 dolg = 0;
1379 }
1380 break;
1381 case S_EOF:
1382 fcseek(-1);
1383 default:
1384 goto nosub;
1385 }
1386 c = fcget();
1387 if(type>M_TREE)
1388 {
1389 if(c!=RBRACE)
1390 mac_error(np);
1391 if(type==M_NAMESCAN || type==M_NAMECOUNT)
1392 {
1393 mp->shp->last_root = mp->shp->var_tree;
1394 id = prefix(mp->shp,id);
1395 stkseek(stkp,offset);
1396 if(type==M_NAMECOUNT)
1397 {
1398 c = namecount(mp,id);
1399 v = ltos(c);
1400 }
1401 else
1402 {
1403 dolmax = strlen(id);
1404 dolg = -1;
1405 nextname(mp,id,0);
1406 v = nextname(mp,id,dolmax);
1407 }
1408 }
1409 else if(type==M_SUBNAME)
1410 {
1411 if(dolg<0)
1412 {
1413 v = nv_getsub(np);
1414 bysub=1;
1415 }
1416 else if(v)
1417 {
1418 if(!ap || isastchar(mode))
1419 v = "0";
1420 else
1421 v = nv_getsub(np);
1422 }
1423 }
1424 else
1425 {
1426 if(!isastchar(mode))
1427 c = charlen(v,vsize);
1428 else if(dolg>0)
1429 {
1430 #if SHOPT_FILESCAN
1431 if(mp->shp->cur_line)
1432 {
1433 getdolarg(&sh,MAX_ARGN,(int*)0);
1434 c = mp->shp->offsets[0];
1435 }
1436 else
1437 #endif /* SHOPT_FILESCAN */
1438 c = mp->shp->st.dolc;
1439 }
1440 else if(dolg<0)
1441 c = array_elem(ap);
1442 else
1443 c = (v!=0);
1444 dolg = dolmax = 0;
1445 v = ltos(c);
1446 }
1447 c = RBRACE;
1448 }
1449 nulflg = 0;
1450 if(type && c==':')
1451 {
1452 c = fcget();
1453 if(sh_lexstates[ST_BRACE][c]==S_MOD1 && c!='*' && c!= ':')
1454 nulflg=1;
1455 else if(c!='%' && c!='#')
1456 {
1457 fcseek(-1);
1458 c = ':';
1459 }
1460 }
1461 if(type)
1462 {
1463 if(!isbracechar(c))
1464 {
1465 if(!nulflg)
1466 mac_error(np);
1467 fcseek(-1);
1468 c = ':';
1469 }
1470 if(c!=RBRACE)
1471 {
1472 int newops = (c=='#' || c == '%' || c=='/');
1473 offset = stktell(stkp);
1474 if(c=='/' ||c==':' || ((!v || (nulflg && *v==0)) ^ (c=='+'||c=='#'||c=='%')))
1475 {
1476 int newquote = mp->quote;
1477 int split = mp->split;
1478 int quoted = mp->quoted;
1479 int arith = mp->arith;
1480 int zeros = mp->zeros;
1481 int assign = mp->assign;
1482 if(newops)
1483 {
1484 type = fcget();
1485 if(type=='%' || type=='#')
1486 {
1487 int d = fcget();
1488 fcseek(-1);
1489 if(d=='(')
1490 type = 0;
1491 }
1492 fcseek(-1);
1493 mp->pattern = 1+(c=='/');
1494 mp->split = 0;
1495 mp->quoted = 0;
1496 mp->assign &= ~1;
1497 mp->arith = mp->zeros = 0;
1498 newquote = 0;
1499 }
1500 else if(c=='?' || c=='=')
1501 mp->split = mp->pattern = 0;
1502 copyto(mp,RBRACE,newquote);
1503 if(!oldpat)
1504 mp->patfound = 0;
1505 mp->pattern = oldpat;
1506 mp->split = split;
1507 mp->quoted = quoted;
1508 mp->arith = arith;
1509 mp->zeros = zeros;
1510 mp->assign = assign;
1511 /* add null byte */
1512 sfputc(stkp,0);
1513 stkseek(stkp,stktell(stkp)-1);
1514 }
1515 else
1516 {
1517 sh_lexskip(lp,RBRACE,0,(!newops&&mp->quote)?ST_QUOTE:ST_NESTED);
1518 stkseek(stkp,offset);
1519 }
1520 argp=stkptr(stkp,offset);
1521 }
1522 }
1523 else
1524 {
1525 fcseek(-1);
1526 c=0;
1527 }
1528 if(c==':') /* ${name:expr1[:expr2]} */
1529 {
1530 char *ptr;
1531 type = (int)sh_strnum(argp,&ptr,1);
1532 if(isastchar(mode))
1533 {
1534 if(id==idbuff) /* ${@} or ${*} */
1535 {
1536 if(type<0 && (type+= dolmax)<0)
1537 type = 0;
1538 if(type==0)
1539 v = special(mp->shp,dolg=0);
1540 #if SHOPT_FILESCAN
1541 else if(mp->shp->cur_line)
1542 {
1543 v = getdolarg(&sh,dolg=type,&vsize);
1544 if(!v)
1545 dolmax = type;
1546 }
1547 #endif /* SHOPT_FILESCAN */
1548 else if(type < dolmax)
1549 v = mp->shp->st.dolv[dolg=type];
1550 else
1551 v = 0;
1552 }
1553 else if(ap)
1554 {
1555 if(type<0)
1556 {
1557 if(array_assoc(ap))
1558 type = -type;
1559 else
1560 type += array_maxindex(np);
1561 }
1562 if(array_assoc(ap))
1563 {
1564 while(type-- >0 && (v=0,nv_nextsub(np)))
1565 v = nv_getval(np);
1566 }
1567 else if(type > 0)
1568 {
1569 if(nv_putsub(np,NIL(char*),type|ARRAY_SCAN))
1570 v = nv_getval(np);
1571 else
1572 v = 0;
1573 }
1574 }
1575 else if(type>0)
1576 v = 0;
1577 }
1578 else if(v)
1579 {
1580 vsize = charlen(v,vsize);
1581 if(type<0 && (type += vsize)<0)
1582 type = 0;
1583 if(vsize < type)
1584 v = 0;
1585 #if SHOPT_MULTIBYTE
1586 else if(mbwide())
1587 {
1588 mbinit();
1589 while(type-->0)
1590 {
1591 if((c=mbsize(v))<1)
1592 c = 1;
1593 v += c;
1594 }
1595 c = ':';
1596 }
1597 #endif /* SHOPT_MULTIBYTE */
1598 else
1599 v += type;
1600 vsize -= type;
1601 }
1602 if(*ptr==':')
1603 {
1604 if((type = (int)sh_strnum(ptr+1,&ptr,1)) <=0)
1605 v = 0;
1606 else if(isastchar(mode))
1607 {
1608 if(dolg>=0)
1609 {
1610 if(dolg+type < dolmax)
1611 dolmax = dolg+type;
1612 }
1613 else
1614 dolmax = type;
1615 }
1616 else if(type < vsize)
1617 {
1618 #if SHOPT_MULTIBYTE
1619 if(mbwide())
1620 {
1621 char *vp = v;
1622 mbinit();
1623 while(type-->0)
1624 {
1625 if((c=mbsize(vp))<1)
1626 c = 1;
1627 vp += c;
1628 }
1629 type = vp-v;
1630 c = ':';
1631 }
1632 #endif /* SHOPT_MULTIBYTE */
1633 vsize = type;
1634 }
1635 }
1636 if(*ptr)
1637 mac_error(np);
1638 stkseek(stkp,offset);
1639 argp = 0;
1640 }
1641 /* check for substring operations */
1642 else if(c == '#' || c == '%' || c=='/')
1643 {
1644 if(c=='/')
1645 {
1646 if(type=='/' || type=='#' || type=='%')
1647 {
1648 c = type;
1649 type = '/';
1650 argp++;
1651 }
1652 else
1653 type = 0;
1654 }
1655 else
1656 {
1657 if(type==c) /* ## or %% */
1658 argp++;
1659 else
1660 type = 0;
1661 }
1662 pattern = strdup(argp);
1663 if((type=='/' || c=='/') && (repstr = mac_getstring(pattern)))
1664 replen = strlen(repstr);
1665 if(v || c=='/' && offset>=0)
1666 stkseek(stkp,offset);
1667 }
1668 /* check for quoted @ */
1669 if(mode=='@' && mp->quote && !v && c!='-')
1670 mp->quoted-=2;
1671 retry2:
1672 if(v && (!nulflg || *v ) && c!='+')
1673 {
1674 register int d = (mode=='@'?' ':mp->ifs);
1675 int match[2*(MATCH_MAX+1)], nmatch, nmatch_prev, vsize_last;
1676 char *vlast;
1677 while(1)
1678 {
1679 if(!v)
1680 v= "";
1681 if(c=='/' || c=='#' || c== '%')
1682 {
1683 flag = (type || c=='/')?(STR_GROUP|STR_MAXIMAL):STR_GROUP;
1684 if(c!='/')
1685 flag |= STR_LEFT;
1686 nmatch = 0;
1687 while(1)
1688 {
1689 vsize = strlen(v);
1690 nmatch_prev = nmatch;
1691 if(c=='%')
1692 nmatch=substring(v,pattern,match,flag&STR_MAXIMAL);
1693 else
1694 nmatch=strgrpmatch(v,pattern,match,elementsof(match)/2,flag);
1695 if(replen>0)
1696 sh_setmatch(v,vsize,nmatch,match);
1697 if(nmatch)
1698 {
1699 vlast = v;
1700 vsize_last = vsize;
1701 vsize = match[0];
1702 }
1703 else if(c=='#')
1704 vsize = 0;
1705 if(vsize)
1706 mac_copy(mp,v,vsize);
1707 if(nmatch && replen>0 && (match[1] || !nmatch_prev))
1708 mac_substitute(mp,repstr,v,match,nmatch);
1709 if(nmatch==0)
1710 v += vsize;
1711 else
1712 v += match[1];
1713 if(*v && c=='/' && type)
1714 {
1715 /* avoid infinite loop */
1716 if(nmatch && match[1]==0)
1717 {
1718 nmatch = 0;
1719 mac_copy(mp,v,1);
1720 v++;
1721 }
1722 continue;
1723 }
1724 vsize = -1;
1725 break;
1726 }
1727 if(replen==0)
1728 sh_setmatch(vlast,vsize_last,nmatch,match);
1729 }
1730 if(vsize)
1731 mac_copy(mp,v,vsize>0?vsize:strlen(v));
1732 if(addsub)
1733 {
1734 sfprintf(mp->shp->strbuf,"[%s]",nv_getsub(np));
1735 v = sfstruse(mp->shp->strbuf);
1736 mac_copy(mp, v, strlen(v));
1737 }
1738 if(dolg==0 && dolmax==0)
1739 break;
1740 if(mp->dotdot)
1741 {
1742 if(nv_nextsub(np) == 0)
1743 break;
1744 if(bysub)
1745 v = nv_getsub(np);
1746 else
1747 v = nv_getval(np);
1748 if(array_assoc(ap))
1749 {
1750 if(strcmp(bysub?v:nv_getsub(np),arrmax)>0)
1751 break;
1752 }
1753 else
1754 {
1755 if(nv_aindex(np) > dolmax)
1756 break;
1757 }
1758 }
1759 else if(dolg>=0)
1760 {
1761 if(++dolg >= dolmax)
1762 break;
1763 #if SHOPT_FILESCAN
1764 if(mp->shp->cur_line)
1765 {
1766 if(dolmax==MAX_ARGN && isastchar(mode))
1767 break;
1768 if(!(v=getdolarg(&sh,dolg,&vsize)))
1769 {
1770 dolmax = dolg;
1771 break;
1772 }
1773 }
1774 else
1775 #endif /* SHOPT_FILESCAN */
1776 v = mp->shp->st.dolv[dolg];
1777 }
1778 else if(!np)
1779 {
1780 if(!(v = nextname(mp,id,dolmax)))
1781 break;
1782 }
1783 else
1784 {
1785 if(dolmax && --dolmax <=0)
1786 {
1787 nv_putsub(np,NIL(char*),ARRAY_UNDEF);
1788 break;
1789 }
1790 if(ap)
1791 ap->nelem |= ARRAY_SCAN;
1792 if(nv_nextsub(np) == 0)
1793 break;
1794 if(bysub)
1795 v = nv_getsub(np);
1796 else
1797 v = nv_getval(np);
1798 }
1799 if(mp->split && (!mp->quote || mode=='@'))
1800 {
1801 if(!np)
1802 mp->pattern = 0;
1803 endfield(mp,mp->quoted);
1804 mp->pattern = oldpat;
1805 }
1806 else if(d)
1807 {
1808 if(mp->sp)
1809 sfputc(mp->sp,d);
1810 else
1811 sfputc(stkp,d);
1812 }
1813 }
1814 if(arrmax)
1815 free((void*)arrmax);
1816 if(pattern)
1817 free((void*)pattern);
1818 }
1819 else if(argp)
1820 {
1821 if(c=='/' && replen>0 && pattern && strmatch("",pattern))
1822 mac_substitute(mp,repstr,v,0,0);
1823 if(c=='?')
1824 {
1825 if(np)
1826 id = nv_name(np);
1827 else if(idnum)
1828 id = ltos(idnum);
1829 if(*argp)
1830 {
1831 sfputc(stkp,0);
1832 errormsg(SH_DICT,ERROR_exit(1),"%s: %s",id,argp);
1833 }
1834 else if(v)
1835 errormsg(SH_DICT,ERROR_exit(1),e_nullset,id);
1836 else
1837 errormsg(SH_DICT,ERROR_exit(1),e_notset,id);
1838 }
1839 else if(c=='=')
1840 {
1841 if(np)
1842 {
1843 if(mp->shp->subshell)
1844 np = sh_assignok(np,1);
1845 nv_putval(np,argp,0);
1846 v = nv_getval(np);
1847 nulflg = 0;
1848 stkseek(stkp,offset);
1849 goto retry2;
1850 }
1851 else
1852 mac_error(np);
1853 }
1854 }
1855 else if(var && sh_isoption(SH_NOUNSET) && type<=M_TREE && (!np || nv_isnull(np) || (nv_isarray(np) && !np->nvalue.cp)))
1856 {
1857 if(np)
1858 {
1859 if(nv_isarray(np))
1860 {
1861 sfprintf(mp->shp->strbuf,"%s[%s]\0",nv_name(np),nv_getsub(np));
1862 id = sfstruse(mp->shp->strbuf);
1863 }
1864 else
1865 id = nv_name(np);
1866 nv_close(np);
1867 }
1868 errormsg(SH_DICT,ERROR_exit(1),e_notset,id);
1869 }
1870 if(np)
1871 nv_close(np);
1872 return(1);
1873 nosub:
1874 if(type==M_BRACE && sh_lexstates[ST_NORM][c]==S_BREAK)
1875 {
1876 fcseek(-1);
1877 comsubst(mp,(Shnode_t*)0,2);
1878 return(1);
1879 }
1880 if(type)
1881 mac_error(np);
1882 fcseek(-1);
1883 nv_close(np);
1884 return(0);
1885 }
1886
1887 /*
1888 * This routine handles command substitution
1889 * <type> is 0 for older `...` version
1890 */
comsubst(Mac_t * mp,register Shnode_t * t,int type)1891 static void comsubst(Mac_t *mp,register Shnode_t* t, int type)
1892 {
1893 Sfdouble_t num;
1894 register int c;
1895 register char *str;
1896 Sfio_t *sp;
1897 Stk_t *stkp = mp->shp->stk;
1898 Fcin_t save;
1899 struct slnod *saveslp = mp->shp->st.staklist;
1900 struct _mac_ savemac;
1901 int savtop = stktell(stkp);
1902 char lastc, *savptr = stkfreeze(stkp,0);
1903 int was_history = sh_isstate(SH_HISTORY);
1904 int was_verbose = sh_isstate(SH_VERBOSE);
1905 int was_interactive = sh_isstate(SH_INTERACTIVE);
1906 int newlines,bufsize,nextnewlines;
1907 Namval_t *np;
1908 mp->shp->argaddr = 0;
1909 savemac = *mp;
1910 mp->shp->st.staklist=0;
1911 if(type)
1912 {
1913 sp = 0;
1914 fcseek(-1);
1915 if(!t)
1916 t = sh_dolparen((Lex_t*)mp->shp->lex_context);
1917 if(t && t->tre.tretyp==TARITH)
1918 {
1919 fcsave(&save);
1920 if((t->ar.arexpr->argflag&ARG_RAW))
1921 num = arith_exec(t->ar.arcomp);
1922 else
1923 num = sh_arith(sh_mactrim(mp->shp,t->ar.arexpr->argval,3));
1924 out_offset:
1925 stkset(stkp,savptr,savtop);
1926 *mp = savemac;
1927 if((Sflong_t)num!=num)
1928 sfprintf(mp->shp->strbuf,"%.*Lg",LDBL_DIG,num);
1929 else if(num)
1930 sfprintf(mp->shp->strbuf,"%lld",(Sflong_t)num);
1931 else
1932 sfprintf(mp->shp->strbuf,"%Lg",num);
1933 str = sfstruse(mp->shp->strbuf);
1934 mac_copy(mp,str,strlen(str));
1935 mp->shp->st.staklist = saveslp;
1936 fcrestore(&save);
1937 return;
1938 }
1939 }
1940 else
1941 {
1942 while(fcgetc(c)!='`' && c)
1943 {
1944 if(c==ESCAPE)
1945 {
1946 fcgetc(c);
1947 if(!(isescchar(sh_lexstates[ST_QUOTE][c]) ||
1948 (c=='"' && mp->quote)))
1949 sfputc(stkp,ESCAPE);
1950 }
1951 sfputc(stkp,c);
1952 }
1953 c = stktell(stkp);
1954 str=stkfreeze(stkp,1);
1955 /* disable verbose and don't save in history file */
1956 sh_offstate(SH_HISTORY);
1957 sh_offstate(SH_VERBOSE);
1958 if(mp->sp)
1959 sfsync(mp->sp); /* flush before executing command */
1960 sp = sfnew(NIL(Sfio_t*),str,c,-1,SF_STRING|SF_READ);
1961 c = mp->shp->inlineno;
1962 mp->shp->inlineno = error_info.line+mp->shp->st.firstline;
1963 t = (Shnode_t*)sh_parse(mp->shp, sp,SH_EOF|SH_NL);
1964 mp->shp->inlineno = c;
1965 type = 1;
1966 }
1967 #if KSHELL
1968 if(t)
1969 {
1970 fcsave(&save);
1971 sfclose(sp);
1972 if(t->tre.tretyp==0 && !t->com.comarg && !t->com.comset)
1973 {
1974 /* special case $(<file) and $(<#file) */
1975 register int fd;
1976 int r;
1977 struct checkpt buff;
1978 struct ionod *ip=0;
1979 sh_pushcontext(&buff,SH_JMPIO);
1980 if((ip=t->tre.treio) &&
1981 ((ip->iofile&IOLSEEK) || !(ip->iofile&IOUFD)) &&
1982 (r=sigsetjmp(buff.buff,0))==0)
1983 fd = sh_redirect(mp->shp,ip,3);
1984 else
1985 fd = sh_chkopen(e_devnull);
1986 sh_popcontext(&buff);
1987 if(r==0 && ip && (ip->iofile&IOLSEEK))
1988 {
1989 if(sp=mp->shp->sftable[fd])
1990 num = sftell(sp);
1991 else
1992 num = lseek(fd, (off_t)0, SEEK_CUR);
1993 goto out_offset;
1994 }
1995 sp = sfnew(NIL(Sfio_t*),(char*)malloc(IOBSIZE+1),IOBSIZE,fd,SF_READ|SF_MALLOC);
1996 type = 3;
1997 }
1998 else
1999 sp = sh_subshell(t,sh_isstate(SH_ERREXIT),type);
2000 fcrestore(&save);
2001 }
2002 else
2003 sp = sfopen(NIL(Sfio_t*),"","sr");
2004 sh_freeup(mp->shp);
2005 mp->shp->st.staklist = saveslp;
2006 if(was_history)
2007 sh_onstate(SH_HISTORY);
2008 if(was_verbose)
2009 sh_onstate(SH_VERBOSE);
2010 #else
2011 sp = sfpopen(NIL(Sfio_t*),str,"r");
2012 #endif
2013 *mp = savemac;
2014 np = sh_scoped(mp->shp,IFSNOD);
2015 nv_putval(np,mp->ifsp,NV_RDONLY);
2016 mp->ifsp = nv_getval(np);
2017 stkset(stkp,savptr,savtop);
2018 newlines = 0;
2019 lastc = 0;
2020 sfsetbuf(sp,(void*)sp,0);
2021 bufsize = sfvalue(sp);
2022 /* read command substitution output and put on stack or here-doc */
2023 sfpool(sp, NIL(Sfio_t*), SF_WRITE);
2024 sh_offstate(SH_INTERACTIVE);
2025 while((str=(char*)sfreserve(sp,SF_UNBOUND,0)) && (c = sfvalue(sp))>0)
2026 {
2027 #if SHOPT_CRNL
2028 /* eliminate <cr> */
2029 register char *dp;
2030 char *buff = str;
2031 while(c>1 && (*str !='\r'|| str[1]!='\n'))
2032 {
2033 c--;
2034 str++;
2035 }
2036 dp = str;
2037 while(c>1)
2038 {
2039 str++;
2040 c--;
2041 while(c>1 && (*str!='\r' || str[1]!='\n'))
2042 {
2043 c--;
2044 *dp++ = *str++;
2045 }
2046 }
2047 if(c)
2048 *dp++ = *str++;
2049 str = buff;
2050 c = dp-str;
2051 #endif /* SHOPT_CRNL */
2052 /* delay appending trailing new-lines */
2053 for(nextnewlines=0; c-->0 && str[c]=='\n'; nextnewlines++);
2054 if(c < 0)
2055 {
2056 newlines += nextnewlines;
2057 continue;
2058 }
2059 if(newlines >0)
2060 {
2061 if(mp->sp)
2062 sfnputc(mp->sp,'\n',newlines);
2063 else if(!mp->quote && mp->split && mp->shp->ifstable['\n'])
2064 endfield(mp,0);
2065 else
2066 sfnputc(stkp,'\n',newlines);
2067 }
2068 else if(lastc)
2069 {
2070 mac_copy(mp,&lastc,1);
2071 lastc = 0;
2072 }
2073 newlines = nextnewlines;
2074 if(++c < bufsize)
2075 str[c] = 0;
2076 else
2077 {
2078 /* can't write past buffer so save last character */
2079 lastc = str[--c];
2080 str[c] = 0;
2081 }
2082 mac_copy(mp,str,c);
2083 }
2084 if(was_interactive)
2085 sh_onstate(SH_INTERACTIVE);
2086 if(mp->shp->spid)
2087 job_wait(mp->shp->spid);
2088 if(--newlines>0 && mp->shp->ifstable['\n']==S_DELIM)
2089 {
2090 if(mp->sp)
2091 sfnputc(mp->sp,'\n',newlines);
2092 else if(!mp->quote && mp->split)
2093 while(newlines--)
2094 endfield(mp,1);
2095 else
2096 sfnputc(stkp,'\n',newlines);
2097 }
2098 if(lastc)
2099 mac_copy(mp,&lastc,1);
2100 sfclose(sp);
2101 return;
2102 }
2103
2104 /*
2105 * copy <str> onto the stack
2106 */
mac_copy(register Mac_t * mp,register const char * str,register int size)2107 static void mac_copy(register Mac_t *mp,register const char *str, register int size)
2108 {
2109 register char *state;
2110 register const char *cp=str;
2111 register int c,n,nopat,len;
2112 Stk_t *stkp=mp->shp->stk;
2113 nopat = (mp->quote||mp->assign==1||mp->arith);
2114 if(mp->zeros)
2115 {
2116 /* prevent leading 0's from becomming octal constants */
2117 while(size>1 && *str=='0')
2118 str++,size--;
2119 mp->zeros = 0;
2120 cp = str;
2121 }
2122 if(mp->sp)
2123 sfwrite(mp->sp,str,size);
2124 else if(mp->pattern>=2 || (mp->pattern && nopat))
2125 {
2126 state = sh_lexstates[ST_MACRO];
2127 /* insert \ before file expansion characters */
2128 while(size-->0)
2129 {
2130 #if SHOPT_MULTIBYTE
2131 if(mbwide() && (len=mbsize(cp))>1)
2132 {
2133 cp += len;
2134 size -= (len-1);
2135 continue;
2136 }
2137 #endif
2138 c = state[n= *(unsigned char*)cp++];
2139 if(nopat&&(c==S_PAT||c==S_ESC||c==S_BRACT||c==S_ENDCH) && mp->pattern!=3)
2140 c=1;
2141 else if(mp->pattern==4 && (c==S_ESC||c==S_BRACT||c==S_ENDCH || isastchar(n)))
2142 c=1;
2143 else if(mp->pattern==2 && c==S_SLASH)
2144 c=1;
2145 else if(mp->pattern==3 && c==S_ESC && (state[*(unsigned char*)cp]==S_DIG||(*cp==ESCAPE)))
2146 {
2147 if(!(c=mp->quote))
2148 cp++;
2149 }
2150 else
2151 c=0;
2152 if(c)
2153 {
2154 if(c = (cp-1) - str)
2155 sfwrite(stkp,str,c);
2156 sfputc(stkp,ESCAPE);
2157 str = cp-1;
2158 }
2159 }
2160 if(c = cp-str)
2161 sfwrite(stkp,str,c);
2162 }
2163 else if(!mp->quote && mp->split && (mp->ifs||mp->pattern))
2164 {
2165 /* split words at ifs characters */
2166 state = mp->shp->ifstable;
2167 if(mp->pattern)
2168 {
2169 char *sp = "&|()";
2170 while(c = *sp++)
2171 {
2172 if(state[c]==0)
2173 state[c] = S_EPAT;
2174 }
2175 sp = "*?[{";
2176 while(c = *sp++)
2177 {
2178 if(state[c]==0)
2179 state[c] = S_PAT;
2180 }
2181 if(state[ESCAPE]==0)
2182 state[ESCAPE] = S_ESC;
2183 }
2184 while(size-->0)
2185 {
2186 n=state[c= *(unsigned char*)cp++];
2187 #if SHOPT_MULTIBYTE
2188 if(mbwide() && n!=S_MBYTE && (len=mbsize(cp-1))>1)
2189 {
2190 sfwrite(stkp,cp-1, len);
2191 cp += --len;
2192 size -= len;
2193 continue;
2194 }
2195 #endif
2196 if(n==S_ESC || n==S_EPAT)
2197 {
2198 /* don't allow extended patterns in this case */
2199 mp->patfound = mp->pattern;
2200 sfputc(stkp,ESCAPE);
2201 }
2202 else if(n==S_PAT)
2203 mp->patfound = mp->pattern;
2204 else if(n && mp->ifs)
2205 {
2206 #if SHOPT_MULTIBYTE
2207 if(n==S_MBYTE)
2208 {
2209 if(sh_strchr(mp->ifsp,cp-1)<0)
2210 continue;
2211 n = mbsize(cp-1) - 1;
2212 if(n==-2)
2213 n = 0;
2214 cp += n;
2215 size -= n;
2216 n= S_DELIM;
2217 }
2218 #endif /* SHOPT_MULTIBYTE */
2219 if(n==S_SPACE || n==S_NL)
2220 {
2221 while(size>0 && ((n=state[c= *(unsigned char*)cp++])==S_SPACE||n==S_NL))
2222 size--;
2223 #if SHOPT_MULTIBYTE
2224 if(n==S_MBYTE && sh_strchr(mp->ifsp,cp-1)>=0)
2225 {
2226 n = mbsize(cp-1) - 1;
2227 if(n==-2)
2228 n = 0;
2229 cp += n;
2230 size -= n;
2231 n=S_DELIM;
2232 }
2233 else
2234 #endif /* SHOPT_MULTIBYTE */
2235 if(n==S_DELIM)
2236 size--;
2237 }
2238 endfield(mp,n==S_DELIM||mp->quoted);
2239 mp->patfound = 0;
2240 if(n==S_DELIM)
2241 while(size>0 && ((n=state[c= *(unsigned char*)cp++])==S_SPACE||n==S_NL))
2242 size--;
2243 if(size<=0)
2244 break;
2245 cp--;
2246 continue;
2247
2248 }
2249 sfputc(stkp,c);
2250 }
2251 if(mp->pattern)
2252 {
2253 cp = "&|()";
2254 while(c = *cp++)
2255 {
2256 if(state[c]==S_EPAT)
2257 state[c] = 0;
2258 }
2259 cp = "*?[{";
2260 while(c = *cp++)
2261 {
2262 if(state[c]==S_PAT)
2263 state[c] = 0;
2264 }
2265 if(mp->shp->ifstable[ESCAPE]==S_ESC)
2266 mp->shp->ifstable[ESCAPE] = 0;
2267 }
2268 }
2269 else
2270 sfwrite(stkp,str,size);
2271 }
2272
2273 /*
2274 * Terminate field.
2275 * If field is null count field if <split> is non-zero
2276 * Do filename expansion of required
2277 */
endfield(register Mac_t * mp,int split)2278 static void endfield(register Mac_t *mp,int split)
2279 {
2280 register struct argnod *argp;
2281 register int count=0;
2282 Stk_t *stkp = mp->shp->stk;
2283 if(stktell(stkp) > ARGVAL || split)
2284 {
2285 argp = (struct argnod*)stkfreeze(stkp,1);
2286 argp->argnxt.cp = 0;
2287 argp->argflag = 0;
2288 if(mp->patfound)
2289 {
2290 mp->shp->argaddr = 0;
2291 #if SHOPT_BRACEPAT
2292 count = path_generate(argp,mp->arghead);
2293 #else
2294 count = path_expand(argp->argval,mp->arghead);
2295 #endif /* SHOPT_BRACEPAT */
2296 if(count)
2297 mp->fields += count;
2298 else if(split) /* pattern is null string */
2299 *argp->argval = 0;
2300 else /* pattern expands to nothing */
2301 count = -1;
2302 }
2303 if(count==0)
2304 {
2305 argp->argchn.ap = *mp->arghead;
2306 *mp->arghead = argp;
2307 mp->fields++;
2308 }
2309 if(count>=0)
2310 {
2311 (*mp->arghead)->argflag |= ARG_MAKE;
2312 if(mp->assign || sh_isoption(SH_NOGLOB))
2313 argp->argflag |= ARG_RAW|ARG_EXP;
2314 }
2315 stkseek(stkp,ARGVAL);
2316 }
2317 mp->quoted = mp->quote;
2318 }
2319
2320 /*
2321 * Finds the right substring of STRING using the expression PAT
2322 * the longest substring is found when FLAG is set.
2323 */
substring(register const char * string,const char * pat,int match[],int flag)2324 static int substring(register const char *string,const char *pat,int match[], int flag)
2325 {
2326 register const char *sp=string;
2327 register int size,len,nmatch,n;
2328 int smatch[2*(MATCH_MAX+1)];
2329 if(flag)
2330 {
2331 if(n=strgrpmatch(sp,pat,smatch,elementsof(smatch)/2,STR_RIGHT|STR_MAXIMAL))
2332 {
2333 memcpy(match,smatch,n*2*sizeof(smatch[0]));
2334 return(n);
2335 }
2336 return(0);
2337 }
2338 size = len = strlen(sp);
2339 sp += size;
2340 while(sp>=string)
2341 {
2342 #if SHOPT_MULTIBYTE
2343 if(mbwide())
2344 sp = lastchar(string,sp);
2345 #endif /* SHOPT_MULTIBYTE */
2346 if(n=strgrpmatch(sp,pat,smatch,elementsof(smatch)/2,STR_RIGHT|STR_LEFT|STR_MAXIMAL))
2347 {
2348 nmatch = n;
2349 memcpy(match,smatch,n*2*sizeof(smatch[0]));
2350 size = sp-string;
2351 break;
2352 }
2353 sp--;
2354 }
2355 if(size==len)
2356 return(0);
2357 if(nmatch)
2358 {
2359 nmatch *=2;
2360 while(--nmatch>=0)
2361 match[nmatch] += size;
2362 }
2363 return(n);
2364 }
2365
2366 #if SHOPT_MULTIBYTE
lastchar(const char * string,const char * endstring)2367 static char *lastchar(const char *string, const char *endstring)
2368 {
2369 register char *str = (char*)string;
2370 register int c;
2371 mbinit();
2372 while(*str)
2373 {
2374 if((c=mbsize(str))<0)
2375 c = 1;
2376 if(str+c > endstring)
2377 break;
2378 str += c;
2379 }
2380 return(str);
2381 }
2382 #endif /* SHOPT_MULTIBYTE */
charlen(const char * string,int len)2383 static int charlen(const char *string,int len)
2384 {
2385 if(!string)
2386 return(0);
2387 #if SHOPT_MULTIBYTE
2388 if(mbwide())
2389 {
2390 register const char *str = string, *strmax=string+len;
2391 register int n=0;
2392 mbinit();
2393 if(len>0)
2394 {
2395 while(str<strmax && mbchar(str))
2396 n++;
2397 }
2398 else while(mbchar(str))
2399 n++;
2400 return(n);
2401 }
2402 else
2403 #endif /* SHOPT_MULTIBYTE */
2404 {
2405 if(len<0)
2406 return(strlen(string));
2407 return(len);
2408 }
2409 }
2410
2411 /*
2412 * This is the default tilde discipline function
2413 */
sh_btilde(int argc,char * argv[],void * context)2414 static int sh_btilde(int argc, char *argv[], void *context)
2415 {
2416 Shell_t *shp = ((Shbltin_t*)context)->shp;
2417 char *cp = sh_tilde(shp,argv[1]);
2418 NOT_USED(argc);
2419 if(!cp)
2420 cp = argv[1];
2421 sfputr(sfstdout, cp, '\n');
2422 return(0);
2423 }
2424
2425 /*
2426 * <offset> is byte offset for beginning of tilde string
2427 */
tilde_expand2(Shell_t * shp,register int offset)2428 static void tilde_expand2(Shell_t *shp, register int offset)
2429 {
2430 char shtilde[10], *av[3], *ptr=stkfreeze(shp->stk,1);
2431 Sfio_t *iop, *save=sfstdout;
2432 Namval_t *np;
2433 static int beenhere=0;
2434 strcpy(shtilde,".sh.tilde");
2435 np = nv_open(shtilde,shp->fun_tree, NV_VARNAME|NV_NOARRAY|NV_NOASSIGN|NV_NOFAIL);
2436 if(np && !beenhere)
2437 {
2438 beenhere = 1;
2439 sh_addbuiltin(shtilde,sh_btilde,0);
2440 nv_onattr(np,NV_EXPORT);
2441 }
2442 av[0] = ".sh.tilde";
2443 av[1] = &ptr[offset];
2444 av[2] = 0;
2445 iop = sftmp(IOBSIZE+1);;
2446 sfset(iop,SF_READ,0);
2447 sfstdout = iop;
2448 if(np)
2449 sh_fun(np, (Namval_t*)0, av);
2450 else
2451 sh_btilde(2, av, &sh);
2452 sfstdout = save;
2453 stkset(shp->stk,ptr, offset);
2454 sfseek(iop,(Sfoff_t)0,SEEK_SET);
2455 sfset(iop,SF_READ,1);
2456 if(ptr = sfreserve(iop, SF_UNBOUND, -1))
2457 {
2458 Sfoff_t n = sfvalue(iop);
2459 while(ptr[n-1]=='\n')
2460 n--;
2461 if(n==1 && fcpeek(0)=='/' && ptr[n-1])
2462 n--;
2463 if(n)
2464 sfwrite(shp->stk,ptr,n);
2465 }
2466 else
2467 sfputr(shp->stk,av[1],0);
2468 sfclose(iop);
2469 }
2470
2471 /*
2472 * This routine is used to resolve ~ expansion.
2473 * A ~ by itself is replaced with the users login directory.
2474 * A ~- is replaced by the previous working directory in shell.
2475 * A ~+ is replaced by the present working directory in shell.
2476 * If ~name is replaced with login directory of name.
2477 * If string doesn't start with ~ or ~... not found then 0 returned.
2478 */
2479
sh_tilde(Shell_t * shp,register const char * string)2480 static char *sh_tilde(Shell_t *shp,register const char *string)
2481 {
2482 register char *cp;
2483 register int c;
2484 register struct passwd *pw;
2485 register Namval_t *np=0;
2486 static Dt_t *logins_tree;
2487 if(*string++!='~')
2488 return(NIL(char*));
2489 if((c = *string)==0)
2490 {
2491 if(!(cp=nv_getval(sh_scoped(shp,HOME))))
2492 cp = getlogin();
2493 return(cp);
2494 }
2495 if((c=='-' || c=='+') && string[1]==0)
2496 {
2497 if(c=='+')
2498 cp = nv_getval(sh_scoped(shp,PWDNOD));
2499 else
2500 cp = nv_getval(sh_scoped(shp,OLDPWDNOD));
2501 return(cp);
2502 }
2503 if(logins_tree && (np=nv_search(string,logins_tree,0)))
2504 return(nv_getval(np));
2505 if(!(pw = getpwnam(string)))
2506 return(NIL(char*));
2507 if(!logins_tree)
2508 logins_tree = dtopen(&_Nvdisc,Dtbag);
2509 if(np=nv_search(string,logins_tree,NV_ADD))
2510 nv_putval(np, pw->pw_dir,0);
2511 return(pw->pw_dir);
2512 }
2513
2514 /*
2515 * return values for special macros
2516 */
special(Shell_t * shp,register int c)2517 static char *special(Shell_t *shp,register int c)
2518 {
2519 if(c!='$')
2520 shp->argaddr = 0;
2521 switch(c)
2522 {
2523 case '@':
2524 case '*':
2525 return(shp->st.dolc>0?shp->st.dolv[1]:NIL(char*));
2526 case '#':
2527 #if SHOPT_FILESCAN
2528 if(shp->cur_line)
2529 {
2530 getdolarg(shp,MAX_ARGN,(int*)0);
2531 return(ltos(shp->offsets[0]));
2532 }
2533 #endif /* SHOPT_FILESCAN */
2534 return(ltos(shp->st.dolc));
2535 case '!':
2536 if(shp->bckpid)
2537 return(ltos(shp->bckpid));
2538 break;
2539 case '$':
2540 if(nv_isnull(SH_DOLLARNOD))
2541 return(ltos(shp->pid));
2542 return(nv_getval(SH_DOLLARNOD));
2543 case '-':
2544 return(sh_argdolminus(shp->arg_context));
2545 case '?':
2546 return(ltos(shp->savexit));
2547 case 0:
2548 if(sh_isstate(SH_PROFILE) || shp->fn_depth==0 || !shp->st.cmdname)
2549 return(shp->shname);
2550 else
2551 return(shp->st.cmdname);
2552 }
2553 return(NIL(char*));
2554 }
2555
2556 /*
2557 * Handle macro expansion errors
2558 */
mac_error(Namval_t * np)2559 static void mac_error(Namval_t *np)
2560 {
2561 if(np)
2562 nv_close(np);
2563 errormsg(SH_DICT,ERROR_exit(1),e_subst,fcfirst());
2564 }
2565
2566 /*
2567 * Given pattern/string, replace / with 0 and return pointer to string
2568 * \ characters are stripped from string. The \ are stripped in the
2569 * replacement string unless followed by a digit or \.
2570 */
mac_getstring(char * pattern)2571 static char *mac_getstring(char *pattern)
2572 {
2573 register char *cp=pattern, *rep=0, *dp;
2574 register int c;
2575 while(c = *cp++)
2576 {
2577 if(c==ESCAPE && (!rep || (*cp && strchr("&|()[]*?",*cp))))
2578 {
2579 c = *cp++;
2580 }
2581 else if(!rep && c=='/')
2582 {
2583 cp[-1] = 0;
2584 rep = dp = cp;
2585 continue;
2586 }
2587 if(rep)
2588 *dp++ = c;
2589 }
2590 if(rep)
2591 *dp = 0;
2592 return(rep);
2593 }
2594