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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 */ 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 */ 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 */ 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 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 */ 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 */ 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 */ 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