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