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