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