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