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