1/* 2 * parse.c - parser 3 * 4 * This file is part of zsh, the Z shell. 5 * 6 * Copyright (c) 1992-1997 Paul Falstad 7 * All rights reserved. 8 * 9 * Permission is hereby granted, without written agreement and without 10 * license or royalty fees, to use, copy, modify, and distribute this 11 * software and to distribute modified versions of this software for any 12 * purpose, provided that the above copyright notice and the following 13 * two paragraphs appear in all copies of this software. 14 * 15 * In no event shall Paul Falstad or the Zsh Development Group be liable 16 * to any party for direct, indirect, special, incidental, or consequential 17 * damages arising out of the use of this software and its documentation, 18 * even if Paul Falstad and the Zsh Development Group have been advised of 19 * the possibility of such damage. 20 * 21 * Paul Falstad and the Zsh Development Group specifically disclaim any 22 * warranties, including, but not limited to, the implied warranties of 23 * merchantability and fitness for a particular purpose. The software 24 * provided hereunder is on an "as is" basis, and Paul Falstad and the 25 * Zsh Development Group have no obligation to provide maintenance, 26 * support, updates, enhancements, or modifications. 27 * 28 */ 29 30#include "zsh.mdh" 31#include "parse.pro" 32 33/* != 0 if we are about to read a command word */ 34 35/**/ 36mod_export int incmdpos; 37 38/**/ 39int aliasspaceflag; 40 41/* != 0 if we are in the middle of a [[ ... ]] */ 42 43/**/ 44mod_export int incond; 45 46/* != 0 if we are after a redirection (for ctxtlex only) */ 47 48/**/ 49mod_export int inredir; 50 51/* != 0 if we are about to read a case pattern */ 52 53/**/ 54int incasepat; 55 56/* != 0 if we just read a newline */ 57 58/**/ 59int isnewlin; 60 61/* != 0 if we are after a for keyword */ 62 63/**/ 64int infor; 65 66/* list of here-documents */ 67 68/**/ 69struct heredocs *hdocs; 70 71 72#define YYERROR(O) { tok = LEXERR; ecused = (O); return 0; } 73#define YYERRORV(O) { tok = LEXERR; ecused = (O); return; } 74#define COND_ERROR(X,Y) do { \ 75 zwarn(X,Y); \ 76 herrflush(); \ 77 if (noerrs != 2) \ 78 errflag = 1; \ 79 YYERROR(ecused) \ 80} while(0) 81 82 83/* 84 * Word code. 85 * 86 * The parser now produces word code, reducing memory consumption compared 87 * to the nested structs we had before. 88 * 89 * Word code layout: 90 * 91 * WC_END 92 * - end of program code 93 * 94 * WC_LIST 95 * - data contains type (sync, ...) 96 * - followed by code for this list 97 * - if not (type & Z_END), followed by next WC_LIST 98 * 99 * WC_SUBLIST 100 * - data contains type (&&, ||, END) and flags (coprog, not) 101 * - followed by code for sublist 102 * - if not (type == END), followed by next WC_SUBLIST 103 * 104 * WC_PIPE 105 * - data contains type (end, mid) and LINENO 106 * - if not (type == END), followed by offset to next WC_PIPE 107 * - followed by command 108 * - if not (type == END), followed by next WC_PIPE 109 * 110 * WC_REDIR 111 * - must precede command-code (or WC_ASSIGN) 112 * - data contains type (<, >, ...) 113 * - followed by fd1 and name from struct redir 114 * - for the extended form {var}>... where the fd is assigned 115 * to var, there is an extra item to contain var 116 * 117 * WC_ASSIGN 118 * - data contains type (scalar, array) and number of array-elements 119 * - followed by name and value 120 * 121 * WC_SIMPLE 122 * - data contains the number of arguments (plus command) 123 * - followed by strings 124 * 125 * WC_SUBSH 126 * - data unused 127 * - followed by list 128 * 129 * WC_CURSH 130 * - data unused 131 * - followed by list 132 * 133 * WC_TIMED 134 * - data contains type (followed by pipe or not) 135 * - if (type == PIPE), followed by pipe 136 * 137 * WC_FUNCDEF 138 * - data contains offset to after body 139 * - followed by number of names 140 * - followed by names 141 * - followed by offset to first string 142 * - followed by length of string table 143 * - followed by number of patterns for body 144 * - followed by codes for body 145 * - followed by strings for body 146 * 147 * WC_FOR 148 * - data contains type (list, ...) and offset to after body 149 * - if (type == COND), followed by init, cond, advance expressions 150 * - else if (type == PPARAM), followed by param name 151 * - else if (type == LIST), followed by param name, num strings, strings 152 * - followed by body 153 * 154 * WC_SELECT 155 * - data contains type (list, ...) and offset to after body 156 * - if (type == PPARAM), followed by param name 157 * - else if (type == LIST), followed by param name, num strings, strings 158 * - followed by body 159 * 160 * WC_WHILE 161 * - data contains type (while, until) and offset to after body 162 * - followed by condition 163 * - followed by body 164 * 165 * WC_REPEAT 166 * - data contains offset to after body 167 * - followed by number-string 168 * - followed by body 169 * 170 * WC_CASE 171 * - first CASE is always of type HEAD, data contains offset to esac 172 * - after that CASEs of type OR (;;), AND (;&) and TESTAND (;|), 173 * data is offset to next case 174 * - each OR/AND/TESTAND case is followed by pattern, pattern-number, list 175 * 176 * WC_IF 177 * - first IF is of type HEAD, data contains offset to fi 178 * - after that IFs of type IF, ELIF, ELSE, data is offset to next 179 * - each non-HEAD is followed by condition (only IF, ELIF) and body 180 * 181 * WC_COND 182 * - data contains type 183 * - if (type == AND/OR), data contains offset to after this one, 184 * followed by two CONDs 185 * - else if (type == NOT), followed by COND 186 * - else if (type == MOD), followed by name and strings 187 * - else if (type == MODI), followed by name, left, right 188 * - else if (type == STR[N]EQ), followed by left, right, pattern-number 189 * - else if (has two args) followed by left, right 190 * - else followed by string 191 * 192 * WC_ARITH 193 * - followed by string (there's only one) 194 * 195 * WC_AUTOFN 196 * - only used by the autoload builtin 197 * 198 * Lists and sublists may also be simplified, indicated by the presence 199 * of the Z_SIMPLE or WC_SUBLIST_SIMPLE flags. In this case they are only 200 * followed by a slot containing the line number, not by a WC_SUBLIST or 201 * WC_PIPE, respectively. The real advantage of simplified lists and 202 * sublists is that they can be executed faster, see exec.c. In the 203 * parser, the test if a list can be simplified is done quite simply 204 * by passing a int* around which gets set to non-zero if the thing 205 * just parsed is `complex', i.e. may need to be run by forking or 206 * some such. 207 * 208 * In each of the above, strings are encoded as one word code. For empty 209 * strings this is the bit pattern 11x, the lowest bit is non-zero if the 210 * string contains tokens and zero otherwise (this is true for the other 211 * ways to encode strings, too). For short strings (one to three 212 * characters), this is the marker 01x with the 24 bits above that 213 * containing the characters. Longer strings are encoded as the offset 214 * into the strs character array stored in the eprog struct shifted by 215 * two and ored with the bit pattern 0x. 216 * The ecstrcode() function that adds the code for a string uses a simple 217 * binary tree of strings already added so that long strings are encoded 218 * only once. 219 * 220 * Note also that in the eprog struct the pattern, code, and string 221 * arrays all point to the same memory block. 222 * 223 * 224 * To make things even faster in future versions, we could not only 225 * test if the strings contain tokens, but instead what kind of 226 * expansions need to be done on strings. In the execution code we 227 * could then use these flags for a specialized version of prefork() 228 * to avoid a lot of string parsing and some more string duplication. 229 */ 230 231/**/ 232int eclen, ecused, ecnpats; 233/**/ 234Wordcode ecbuf; 235/**/ 236Eccstr ecstrs; 237/**/ 238int ecsoffs, ecssub, ecnfunc; 239 240#define EC_INIT_SIZE 256 241#define EC_DOUBLE_THRESHOLD 32768 242#define EC_INCREMENT 1024 243 244 245/* Adjust pointers in here-doc structs. */ 246 247static void 248ecadjusthere(int p, int d) 249{ 250 struct heredocs *h; 251 252 for (h = hdocs; h; h = h->next) 253 if (h->pc >= p) 254 h->pc += d; 255} 256 257/* Insert n free code-slots at position p. */ 258 259static void 260ecispace(int p, int n) 261{ 262 int m; 263 264 if ((eclen - ecused) < n) { 265 int a = (eclen < EC_DOUBLE_THRESHOLD ? eclen : EC_INCREMENT); 266 267 if (n > a) a = n; 268 269 ecbuf = (Wordcode) zrealloc((char *) ecbuf, (eclen + a) * sizeof(wordcode)); 270 eclen += a; 271 } 272 if ((m = ecused - p) > 0) 273 memmove(ecbuf + p + n, ecbuf + p, m * sizeof(wordcode)); 274 ecused += n; 275 ecadjusthere(p, n); 276} 277 278/* Add one wordcode. */ 279 280static int 281ecadd(wordcode c) 282{ 283 if ((eclen - ecused) < 1) { 284 int a = (eclen < EC_DOUBLE_THRESHOLD ? eclen : EC_INCREMENT); 285 286 ecbuf = (Wordcode) zrealloc((char *) ecbuf, (eclen + a) * sizeof(wordcode)); 287 eclen += a; 288 } 289 ecbuf[ecused] = c; 290 ecused++; 291 292 return ecused - 1; 293} 294 295/* Delete a wordcode. */ 296 297static void 298ecdel(int p) 299{ 300 int n = ecused - p - 1; 301 302 if (n > 0) 303 memmove(ecbuf + p, ecbuf + p + 1, n * sizeof(wordcode)); 304 ecused--; 305 ecadjusthere(p, -1); 306} 307 308/* Build the wordcode for a string. */ 309 310static wordcode 311ecstrcode(char *s) 312{ 313 int l, t = has_token(s); 314 315 if ((l = strlen(s) + 1) && l <= 4) { 316 wordcode c = (t ? 3 : 2); 317 switch (l) { 318 case 4: c |= ((wordcode) STOUC(s[2])) << 19; 319 case 3: c |= ((wordcode) STOUC(s[1])) << 11; 320 case 2: c |= ((wordcode) STOUC(s[0])) << 3; break; 321 case 1: c = (t ? 7 : 6); break; 322 } 323 return c; 324 } else { 325 Eccstr p, *pp; 326 int cmp; 327 328 for (pp = &ecstrs; (p = *pp); ) { 329 if (!(cmp = p->nfunc - ecnfunc) && !(cmp = strcmp(p->str, s))) 330 return p->offs; 331 pp = (cmp < 0 ? &(p->left) : &(p->right)); 332 } 333 p = *pp = (Eccstr) zhalloc(sizeof(*p)); 334 p->left = p->right = 0; 335 p->offs = ((ecsoffs - ecssub) << 2) | (t ? 1 : 0); 336 p->aoffs = ecsoffs; 337 p->str = s; 338 p->nfunc = ecnfunc; 339 ecsoffs += l; 340 341 return p->offs; 342 } 343} 344 345#define ecstr(S) ecadd(ecstrcode(S)) 346 347#define par_save_list(C) \ 348 do { \ 349 int eu = ecused; \ 350 par_list(C); \ 351 if (eu == ecused) ecadd(WCB_END()); \ 352 } while (0) 353#define par_save_list1(C) \ 354 do { \ 355 int eu = ecused; \ 356 par_list1(C); \ 357 if (eu == ecused) ecadd(WCB_END()); \ 358 } while (0) 359 360 361/* Initialise wordcode buffer. */ 362 363static void 364init_parse(void) 365{ 366 if (ecbuf) zfree(ecbuf, eclen); 367 368 ecbuf = (Wordcode) zalloc((eclen = EC_INIT_SIZE) * sizeof(wordcode)); 369 ecused = 0; 370 ecstrs = NULL; 371 ecsoffs = ecnpats = 0; 372 ecssub = 0; 373 ecnfunc = 0; 374} 375 376/* Build eprog. */ 377 378static void 379copy_ecstr(Eccstr s, char *p) 380{ 381 while (s) { 382 memcpy(p + s->aoffs, s->str, strlen(s->str) + 1); 383 copy_ecstr(s->left, p); 384 s = s->right; 385 } 386} 387 388static Eprog 389bld_eprog(void) 390{ 391 Eprog ret; 392 int l; 393 394 ecadd(WCB_END()); 395 396 ret = (Eprog) zhalloc(sizeof(*ret)); 397 ret->len = ((ecnpats * sizeof(Patprog)) + 398 (ecused * sizeof(wordcode)) + 399 ecsoffs); 400 ret->npats = ecnpats; 401 ret->nref = -1; /* Eprog is on the heap */ 402 ret->pats = (Patprog *) zhalloc(ret->len); 403 ret->prog = (Wordcode) (ret->pats + ecnpats); 404 ret->strs = (char *) (ret->prog + ecused); 405 ret->shf = NULL; 406 ret->flags = EF_HEAP; 407 ret->dump = NULL; 408 for (l = 0; l < ecnpats; l++) 409 ret->pats[l] = dummy_patprog1; 410 memcpy(ret->prog, ecbuf, ecused * sizeof(wordcode)); 411 copy_ecstr(ecstrs, ret->strs); 412 413 zfree(ecbuf, eclen); 414 ecbuf = NULL; 415 416 return ret; 417} 418 419/**/ 420mod_export int 421empty_eprog(Eprog p) 422{ 423 return (!p || !p->prog || *p->prog == WCB_END()); 424} 425 426static void 427clear_hdocs() 428{ 429 struct heredocs *p, *n; 430 431 for (p = hdocs; p; p = n) { 432 n = p->next; 433 zfree(p, sizeof(struct heredocs)); 434 } 435 hdocs = NULL; 436} 437 438/* 439 * event : ENDINPUT 440 * | SEPER 441 * | sublist [ SEPER | AMPER | AMPERBANG ] 442 */ 443 444/**/ 445Eprog 446parse_event(void) 447{ 448 tok = ENDINPUT; 449 incmdpos = 1; 450 aliasspaceflag = 0; 451 zshlex(); 452 init_parse(); 453 454 if (!par_event()) { 455 clear_hdocs(); 456 return NULL; 457 } 458 return bld_eprog(); 459} 460 461/**/ 462static int 463par_event(void) 464{ 465 int r = 0, p, c = 0; 466 467 while (tok == SEPER) { 468 if (isnewlin > 0) 469 return 0; 470 zshlex(); 471 } 472 if (tok == ENDINPUT) 473 return 0; 474 475 p = ecadd(0); 476 477 if (par_sublist(&c)) { 478 if (tok == ENDINPUT) { 479 set_list_code(p, Z_SYNC, c); 480 r = 1; 481 } else if (tok == SEPER) { 482 set_list_code(p, Z_SYNC, c); 483 if (isnewlin <= 0) 484 zshlex(); 485 r = 1; 486 } else if (tok == AMPER) { 487 set_list_code(p, Z_ASYNC, c); 488 zshlex(); 489 r = 1; 490 } else if (tok == AMPERBANG) { 491 set_list_code(p, (Z_ASYNC | Z_DISOWN), c); 492 zshlex(); 493 r = 1; 494 } 495 } 496 if (!r) { 497 tok = LEXERR; 498 if (errflag) { 499 yyerror(0); 500 ecused--; 501 return 0; 502 } 503 yyerror(1); 504 herrflush(); 505 if (noerrs != 2) 506 errflag = 1; 507 ecused--; 508 return 0; 509 } else { 510 int oec = ecused; 511 512 if (!par_event()) { 513 ecused = oec; 514 ecbuf[p] |= wc_bdata(Z_END); 515 } 516 } 517 return 1; 518} 519 520/**/ 521mod_export Eprog 522parse_list(void) 523{ 524 int c = 0; 525 526 tok = ENDINPUT; 527 incmdpos = 1; 528 zshlex(); 529 init_parse(); 530 par_list(&c); 531 if (tok != ENDINPUT) { 532 clear_hdocs(); 533 tok = LEXERR; 534 yyerror(0); 535 return NULL; 536 } 537 return bld_eprog(); 538} 539 540/* 541 * This entry point is only used for bin_test, our attempt to 542 * provide compatibility with /bin/[ and /bin/test. Hence 543 * at this point condlex should always be set to testlex. 544 */ 545 546/**/ 547mod_export Eprog 548parse_cond(void) 549{ 550 init_parse(); 551 552 if (!par_cond()) { 553 clear_hdocs(); 554 return NULL; 555 } 556 return bld_eprog(); 557} 558 559/* This adds a list wordcode. The important bit about this is that it also 560 * tries to optimise this to a Z_SIMPLE list code. */ 561 562/**/ 563static void 564set_list_code(int p, int type, int complex) 565{ 566 if (!complex && (type == Z_SYNC || type == (Z_SYNC | Z_END)) && 567 WC_SUBLIST_TYPE(ecbuf[p + 1]) == WC_SUBLIST_END) { 568 int ispipe = !(WC_SUBLIST_FLAGS(ecbuf[p + 1]) & WC_SUBLIST_SIMPLE); 569 ecbuf[p] = WCB_LIST((type | Z_SIMPLE), ecused - 2 - p); 570 ecdel(p + 1); 571 if (ispipe) 572 ecbuf[p + 1] = WC_PIPE_LINENO(ecbuf[p + 1]); 573 } else 574 ecbuf[p] = WCB_LIST(type, 0); 575} 576 577/* The same for sublists. */ 578 579/**/ 580static void 581set_sublist_code(int p, int type, int flags, int skip, int complex) 582{ 583 if (complex) 584 ecbuf[p] = WCB_SUBLIST(type, flags, skip); 585 else { 586 ecbuf[p] = WCB_SUBLIST(type, (flags | WC_SUBLIST_SIMPLE), skip); 587 ecbuf[p + 1] = WC_PIPE_LINENO(ecbuf[p + 1]); 588 } 589} 590 591/* 592 * list : { SEPER } [ sublist [ { SEPER | AMPER | AMPERBANG } list ] ] 593 */ 594 595/**/ 596static int 597par_list(int *complex) 598{ 599 int p, lp = -1, c; 600 601 rec: 602 603 while (tok == SEPER) 604 zshlex(); 605 606 p = ecadd(0); 607 c = 0; 608 609 if (par_sublist(&c)) { 610 *complex |= c; 611 if (tok == SEPER || tok == AMPER || tok == AMPERBANG) { 612 if (tok != SEPER) 613 *complex = 1; 614 set_list_code(p, ((tok == SEPER) ? Z_SYNC : 615 (tok == AMPER) ? Z_ASYNC : 616 (Z_ASYNC | Z_DISOWN)), c); 617 incmdpos = 1; 618 do { 619 zshlex(); 620 } while (tok == SEPER); 621 lp = p; 622 goto rec; 623 } else 624 set_list_code(p, (Z_SYNC | Z_END), c); 625 return 1; 626 } else { 627 ecused--; 628 if (lp >= 0) { 629 ecbuf[lp] |= wc_bdata(Z_END); 630 return 1; 631 } 632 return 0; 633 } 634} 635 636/**/ 637static int 638par_list1(int *complex) 639{ 640 int p = ecadd(0), c = 0; 641 642 if (par_sublist(&c)) { 643 set_list_code(p, (Z_SYNC | Z_END), c); 644 *complex |= c; 645 return 1; 646 } else { 647 ecused--; 648 return 0; 649 } 650} 651 652/* 653 * sublist : sublist2 [ ( DBAR | DAMPER ) { SEPER } sublist ] 654 */ 655 656/**/ 657static int 658par_sublist(int *complex) 659{ 660 int f, p, c = 0; 661 662 p = ecadd(0); 663 664 if ((f = par_sublist2(&c)) != -1) { 665 int e = ecused; 666 667 *complex |= c; 668 if (tok == DBAR || tok == DAMPER) { 669 enum lextok qtok = tok; 670 int sl; 671 672 cmdpush(tok == DBAR ? CS_CMDOR : CS_CMDAND); 673 zshlex(); 674 while (tok == SEPER) 675 zshlex(); 676 sl = par_sublist(complex); 677 set_sublist_code(p, (sl ? (qtok == DBAR ? 678 WC_SUBLIST_OR : WC_SUBLIST_AND) : 679 WC_SUBLIST_END), 680 f, (e - 1 - p), c); 681 cmdpop(); 682 } else 683 set_sublist_code(p, WC_SUBLIST_END, f, (e - 1 - p), c); 684 return 1; 685 } else { 686 ecused--; 687 return 0; 688 } 689} 690 691/* 692 * sublist2 : [ COPROC | BANG ] pline 693 */ 694 695/**/ 696static int 697par_sublist2(int *complex) 698{ 699 int f = 0; 700 701 if (tok == COPROC) { 702 *complex = 1; 703 f |= WC_SUBLIST_COPROC; 704 zshlex(); 705 } else if (tok == BANG) { 706 *complex = 1; 707 f |= WC_SUBLIST_NOT; 708 zshlex(); 709 } 710 if (!par_pline(complex) && !f) 711 return -1; 712 713 return f; 714} 715 716/* 717 * pline : cmd [ ( BAR | BARAMP ) { SEPER } pline ] 718 */ 719 720/**/ 721static int 722par_pline(int *complex) 723{ 724 int p; 725 zlong line = toklineno; 726 727 p = ecadd(0); 728 729 if (!par_cmd(complex)) { 730 ecused--; 731 return 0; 732 } 733 if (tok == BAR) { 734 *complex = 1; 735 cmdpush(CS_PIPE); 736 zshlex(); 737 while (tok == SEPER) 738 zshlex(); 739 ecbuf[p] = WCB_PIPE(WC_PIPE_MID, (line >= 0 ? line + 1 : 0)); 740 ecispace(p + 1, 1); 741 ecbuf[p + 1] = ecused - 1 - p; 742 if (!par_pline(complex)) { 743 tok = LEXERR; 744 } 745 cmdpop(); 746 return 1; 747 } else if (tok == BARAMP) { 748 int r; 749 750 for (r = p + 1; wc_code(ecbuf[r]) == WC_REDIR; 751 r += WC_REDIR_WORDS(ecbuf[r])); 752 753 ecispace(r, 3); 754 ecbuf[r] = WCB_REDIR(REDIR_MERGEOUT); 755 ecbuf[r + 1] = 2; 756 ecbuf[r + 2] = ecstrcode("1"); 757 758 *complex = 1; 759 cmdpush(CS_ERRPIPE); 760 zshlex(); 761 while (tok == SEPER) 762 zshlex(); 763 ecbuf[p] = WCB_PIPE(WC_PIPE_MID, (line >= 0 ? line + 1 : 0)); 764 ecispace(p + 1, 1); 765 ecbuf[p + 1] = ecused - 1 - p; 766 if (!par_pline(complex)) { 767 tok = LEXERR; 768 } 769 cmdpop(); 770 return 1; 771 } else { 772 ecbuf[p] = WCB_PIPE(WC_PIPE_END, (line >= 0 ? line + 1 : 0)); 773 return 1; 774 } 775} 776 777/* 778 * cmd : { redir } ( for | case | if | while | repeat | 779 * subsh | funcdef | time | dinbrack | dinpar | simple ) { redir } 780 */ 781 782/**/ 783static int 784par_cmd(int *complex) 785{ 786 int r, nr = 0; 787 788 r = ecused; 789 790 if (IS_REDIROP(tok)) { 791 *complex = 1; 792 while (IS_REDIROP(tok)) { 793 nr += par_redir(&r, NULL); 794 } 795 } 796 switch (tok) { 797 case FOR: 798 cmdpush(CS_FOR); 799 par_for(complex); 800 cmdpop(); 801 break; 802 case FOREACH: 803 cmdpush(CS_FOREACH); 804 par_for(complex); 805 cmdpop(); 806 break; 807 case SELECT: 808 *complex = 1; 809 cmdpush(CS_SELECT); 810 par_for(complex); 811 cmdpop(); 812 break; 813 case CASE: 814 cmdpush(CS_CASE); 815 par_case(complex); 816 cmdpop(); 817 break; 818 case IF: 819 par_if(complex); 820 break; 821 case WHILE: 822 cmdpush(CS_WHILE); 823 par_while(complex); 824 cmdpop(); 825 break; 826 case UNTIL: 827 cmdpush(CS_UNTIL); 828 par_while(complex); 829 cmdpop(); 830 break; 831 case REPEAT: 832 cmdpush(CS_REPEAT); 833 par_repeat(complex); 834 cmdpop(); 835 break; 836 case INPAR: 837 *complex = 1; 838 cmdpush(CS_SUBSH); 839 par_subsh(complex); 840 cmdpop(); 841 break; 842 case INBRACE: 843 cmdpush(CS_CURSH); 844 par_subsh(complex); 845 cmdpop(); 846 break; 847 case FUNC: 848 cmdpush(CS_FUNCDEF); 849 par_funcdef(complex); 850 cmdpop(); 851 break; 852 case DINBRACK: 853 cmdpush(CS_COND); 854 par_dinbrack(); 855 cmdpop(); 856 break; 857 case DINPAR: 858 ecadd(WCB_ARITH()); 859 ecstr(tokstr); 860 zshlex(); 861 break; 862 case TIME: 863 { 864 static int inpartime = 0; 865 866 if (!inpartime) { 867 *complex = 1; 868 inpartime = 1; 869 par_time(); 870 inpartime = 0; 871 break; 872 } 873 } 874 tok = STRING; 875 /* fall through */ 876 default: 877 { 878 int sr; 879 880 if (!(sr = par_simple(complex, nr))) { 881 if (!nr) 882 return 0; 883 } else { 884 /* Take account of redirections */ 885 if (sr > 1) { 886 *complex = 1; 887 r += sr - 1; 888 } 889 } 890 } 891 break; 892 } 893 if (IS_REDIROP(tok)) { 894 *complex = 1; 895 while (IS_REDIROP(tok)) 896 (void)par_redir(&r, NULL); 897 } 898 incmdpos = 1; 899 incasepat = 0; 900 incond = 0; 901 return 1; 902} 903 904/* 905 * for : ( FOR DINPAR expr SEMI expr SEMI expr DOUTPAR | 906 * ( FOR[EACH] | SELECT ) name ( "in" wordlist | INPAR wordlist OUTPAR ) ) 907 * { SEPER } ( DO list DONE | INBRACE list OUTBRACE | list ZEND | list1 ) 908 */ 909 910/**/ 911static void 912par_for(int *complex) 913{ 914 int oecused = ecused, csh = (tok == FOREACH), p, sel = (tok == SELECT); 915 int type; 916 917 p = ecadd(0); 918 919 incmdpos = 0; 920 infor = tok == FOR ? 2 : 0; 921 zshlex(); 922 if (tok == DINPAR) { 923 zshlex(); 924 if (tok != DINPAR) 925 YYERRORV(oecused); 926 ecstr(tokstr); 927 zshlex(); 928 if (tok != DINPAR) 929 YYERRORV(oecused); 930 ecstr(tokstr); 931 zshlex(); 932 if (tok != DOUTPAR) 933 YYERRORV(oecused); 934 ecstr(tokstr); 935 infor = 0; 936 incmdpos = 1; 937 zshlex(); 938 type = WC_FOR_COND; 939 } else { 940 int np = 0, n, posix_in, ona = noaliases, onc = nocorrect; 941 infor = 0; 942 if (tok != STRING || !isident(tokstr)) 943 YYERRORV(oecused); 944 if (!sel) 945 np = ecadd(0); 946 n = 0; 947 incmdpos = 1; 948 noaliases = nocorrect = 1; 949 for (;;) { 950 n++; 951 ecstr(tokstr); 952 zshlex(); 953 if (tok != STRING || !strcmp(tokstr, "in") || sel) 954 break; 955 if (!isident(tokstr) || errflag) 956 { 957 noaliases = ona; 958 nocorrect = onc; 959 YYERRORV(oecused); 960 } 961 } 962 noaliases = ona; 963 nocorrect = onc; 964 if (!sel) 965 ecbuf[np] = n; 966 posix_in = isnewlin; 967 while (isnewlin) 968 zshlex(); 969 if (tok == STRING && !strcmp(tokstr, "in")) { 970 incmdpos = 0; 971 zshlex(); 972 np = ecadd(0); 973 n = par_wordlist(); 974 if (tok != SEPER) 975 YYERRORV(oecused); 976 ecbuf[np] = n; 977 type = (sel ? WC_SELECT_LIST : WC_FOR_LIST); 978 } else if (!posix_in && tok == INPAR) { 979 incmdpos = 0; 980 zshlex(); 981 np = ecadd(0); 982 n = par_nl_wordlist(); 983 if (tok != OUTPAR) 984 YYERRORV(oecused); 985 ecbuf[np] = n; 986 incmdpos = 1; 987 zshlex(); 988 type = (sel ? WC_SELECT_LIST : WC_FOR_LIST); 989 } else 990 type = (sel ? WC_SELECT_PPARAM : WC_FOR_PPARAM); 991 } 992 incmdpos = 1; 993 while (tok == SEPER) 994 zshlex(); 995 if (tok == DOLOOP) { 996 zshlex(); 997 par_save_list(complex); 998 if (tok != DONE) 999 YYERRORV(oecused); 1000 zshlex(); 1001 } else if (tok == INBRACE) { 1002 zshlex(); 1003 par_save_list(complex); 1004 if (tok != OUTBRACE) 1005 YYERRORV(oecused); 1006 zshlex(); 1007 } else if (csh || isset(CSHJUNKIELOOPS)) { 1008 par_save_list(complex); 1009 if (tok != ZEND) 1010 YYERRORV(oecused); 1011 zshlex(); 1012 } else if (unset(SHORTLOOPS)) { 1013 YYERRORV(oecused); 1014 } else 1015 par_save_list1(complex); 1016 1017 ecbuf[p] = (sel ? 1018 WCB_SELECT(type, ecused - 1 - p) : 1019 WCB_FOR(type, ecused - 1 - p)); 1020} 1021 1022/* 1023 * case : CASE STRING { SEPER } ( "in" | INBRACE ) 1024 { { SEPER } STRING { BAR STRING } OUTPAR 1025 list [ DSEMI | SEMIAMP | SEMIBAR ] } 1026 { SEPER } ( "esac" | OUTBRACE ) 1027 */ 1028 1029/**/ 1030static void 1031par_case(int *complex) 1032{ 1033 int oecused = ecused, brflag, p, pp, n = 1, type; 1034 int ona, onc; 1035 1036 p = ecadd(0); 1037 1038 incmdpos = 0; 1039 zshlex(); 1040 if (tok != STRING) 1041 YYERRORV(oecused); 1042 ecstr(tokstr); 1043 1044 incmdpos = 1; 1045 ona = noaliases; 1046 onc = nocorrect; 1047 noaliases = nocorrect = 1; 1048 zshlex(); 1049 while (tok == SEPER) 1050 zshlex(); 1051 if (!(tok == STRING && !strcmp(tokstr, "in")) && tok != INBRACE) 1052 { 1053 noaliases = ona; 1054 nocorrect = onc; 1055 YYERRORV(oecused); 1056 } 1057 brflag = (tok == INBRACE); 1058 incasepat = 1; 1059 incmdpos = 0; 1060 noaliases = ona; 1061 nocorrect = onc; 1062 zshlex(); 1063 1064 for (;;) { 1065 char *str; 1066 1067 while (tok == SEPER) 1068 zshlex(); 1069 if (tok == OUTBRACE) 1070 break; 1071 if (tok == INPAR) 1072 zshlex(); 1073 if (tok != STRING) 1074 YYERRORV(oecused); 1075 if (!strcmp(tokstr, "esac")) 1076 break; 1077 str = dupstring(tokstr); 1078 incasepat = 0; 1079 incmdpos = 1; 1080 type = WC_CASE_OR; 1081 for (;;) { 1082 zshlex(); 1083 if (tok == OUTPAR) { 1084 incasepat = 0; 1085 incmdpos = 1; 1086 zshlex(); 1087 break; 1088 } else if (tok == BAR) { 1089 char *str2; 1090 int sl = strlen(str); 1091 1092 incasepat = 1; 1093 incmdpos = 0; 1094 str2 = hcalloc(sl + 2); 1095 strcpy(str2, str); 1096 str2[sl] = Bar; 1097 str2[sl+1] = '\0'; 1098 str = str2; 1099 } else { 1100 int sl = strlen(str); 1101 1102 if (!sl || str[sl - 1] != Bar) { 1103 /* POSIX allows (foo*) patterns */ 1104 int pct; 1105 char *s; 1106 1107 for (s = str, pct = 0; *s; s++) { 1108 if (*s == Inpar) 1109 pct++; 1110 if (!pct) 1111 break; 1112 if (pct == 1) { 1113 if (*s == Bar || *s == Inpar) 1114 while (iblank(s[1])) 1115 chuck(s+1); 1116 if (*s == Bar || *s == Outpar) 1117 while (iblank(s[-1]) && 1118 (s < str + 1 || s[-2] != Meta)) 1119 chuck(--s); 1120 } 1121 if (*s == Outpar) 1122 pct--; 1123 } 1124 if (*s || pct || s == str) 1125 YYERRORV(oecused); 1126 /* Simplify pattern by removing surrounding (...) */ 1127 sl = strlen(str); 1128 DPUTS(*str != Inpar || str[sl - 1] != Outpar, 1129 "BUG: strange case pattern"); 1130 str[sl - 1] = '\0'; 1131 chuck(str); 1132 break; 1133 } else { 1134 char *str2; 1135 1136 if (tok != STRING) 1137 YYERRORV(oecused); 1138 str2 = hcalloc(sl + strlen(tokstr) + 1); 1139 strcpy(str2, str); 1140 strcpy(str2 + sl, tokstr); 1141 str = str2; 1142 } 1143 } 1144 } 1145 pp = ecadd(0); 1146 ecstr(str); 1147 ecadd(ecnpats++); 1148 par_save_list(complex); 1149 n++; 1150 if (tok == SEMIAMP) 1151 type = WC_CASE_AND; 1152 else if (tok == SEMIBAR) 1153 type = WC_CASE_TESTAND; 1154 ecbuf[pp] = WCB_CASE(type, ecused - 1 - pp); 1155 if ((tok == ESAC && !brflag) || (tok == OUTBRACE && brflag)) 1156 break; 1157 if (tok != DSEMI && tok != SEMIAMP && tok != SEMIBAR) 1158 YYERRORV(oecused); 1159 incasepat = 1; 1160 incmdpos = 0; 1161 zshlex(); 1162 } 1163 incmdpos = 1; 1164 zshlex(); 1165 1166 ecbuf[p] = WCB_CASE(WC_CASE_HEAD, ecused - 1 - p); 1167} 1168 1169/* 1170 * if : { ( IF | ELIF ) { SEPER } ( INPAR list OUTPAR | list ) 1171 { SEPER } ( THEN list | INBRACE list OUTBRACE | list1 ) } 1172 [ FI | ELSE list FI | ELSE { SEPER } INBRACE list OUTBRACE ] 1173 (you get the idea...?) 1174 */ 1175 1176/**/ 1177static void 1178par_if(int *complex) 1179{ 1180 int oecused = ecused, p, pp, type, usebrace = 0; 1181 enum lextok xtok; 1182 unsigned char nc; 1183 1184 p = ecadd(0); 1185 1186 for (;;) { 1187 xtok = tok; 1188 cmdpush(xtok == IF ? CS_IF : CS_ELIF); 1189 zshlex(); 1190 if (xtok == FI) 1191 break; 1192 if (xtok == ELSE) 1193 break; 1194 while (tok == SEPER) 1195 zshlex(); 1196 if (!(xtok == IF || xtok == ELIF)) { 1197 cmdpop(); 1198 YYERRORV(oecused); 1199 } 1200 pp = ecadd(0); 1201 type = (xtok == IF ? WC_IF_IF : WC_IF_ELIF); 1202 par_save_list(complex); 1203 incmdpos = 1; 1204 if (tok == ENDINPUT) { 1205 cmdpop(); 1206 YYERRORV(oecused); 1207 } 1208 while (tok == SEPER) 1209 zshlex(); 1210 xtok = FI; 1211 nc = cmdstack[cmdsp - 1] == CS_IF ? CS_IFTHEN : CS_ELIFTHEN; 1212 if (tok == THEN) { 1213 usebrace = 0; 1214 cmdpop(); 1215 cmdpush(nc); 1216 zshlex(); 1217 par_save_list(complex); 1218 ecbuf[pp] = WCB_IF(type, ecused - 1 - pp); 1219 incmdpos = 1; 1220 cmdpop(); 1221 } else if (tok == INBRACE) { 1222 usebrace = 1; 1223 cmdpop(); 1224 cmdpush(nc); 1225 zshlex(); 1226 par_save_list(complex); 1227 if (tok != OUTBRACE) { 1228 cmdpop(); 1229 YYERRORV(oecused); 1230 } 1231 ecbuf[pp] = WCB_IF(type, ecused - 1 - pp); 1232 zshlex(); 1233 incmdpos = 1; 1234 if (tok == SEPER) 1235 break; 1236 cmdpop(); 1237 } else if (unset(SHORTLOOPS)) { 1238 cmdpop(); 1239 YYERRORV(oecused); 1240 } else { 1241 cmdpop(); 1242 cmdpush(nc); 1243 par_save_list1(complex); 1244 ecbuf[pp] = WCB_IF(type, ecused - 1 - pp); 1245 incmdpos = 1; 1246 break; 1247 } 1248 } 1249 cmdpop(); 1250 if (xtok == ELSE) { 1251 pp = ecadd(0); 1252 cmdpush(CS_ELSE); 1253 while (tok == SEPER) 1254 zshlex(); 1255 if (tok == INBRACE && usebrace) { 1256 zshlex(); 1257 par_save_list(complex); 1258 if (tok != OUTBRACE) { 1259 cmdpop(); 1260 YYERRORV(oecused); 1261 } 1262 } else { 1263 par_save_list(complex); 1264 if (tok != FI) { 1265 cmdpop(); 1266 YYERRORV(oecused); 1267 } 1268 } 1269 ecbuf[pp] = WCB_IF(WC_IF_ELSE, ecused - 1 - pp); 1270 zshlex(); 1271 cmdpop(); 1272 } 1273 ecbuf[p] = WCB_IF(WC_IF_HEAD, ecused - 1 - p); 1274} 1275 1276/* 1277 * while : ( WHILE | UNTIL ) ( INPAR list OUTPAR | list ) { SEPER } 1278 ( DO list DONE | INBRACE list OUTBRACE | list ZEND ) 1279 */ 1280 1281/**/ 1282static void 1283par_while(int *complex) 1284{ 1285 int oecused = ecused, p; 1286 int type = (tok == UNTIL ? WC_WHILE_UNTIL : WC_WHILE_WHILE); 1287 1288 p = ecadd(0); 1289 zshlex(); 1290 par_save_list(complex); 1291 incmdpos = 1; 1292 while (tok == SEPER) 1293 zshlex(); 1294 if (tok == DOLOOP) { 1295 zshlex(); 1296 par_save_list(complex); 1297 if (tok != DONE) 1298 YYERRORV(oecused); 1299 zshlex(); 1300 } else if (tok == INBRACE) { 1301 zshlex(); 1302 par_save_list(complex); 1303 if (tok != OUTBRACE) 1304 YYERRORV(oecused); 1305 zshlex(); 1306 } else if (isset(CSHJUNKIELOOPS)) { 1307 par_save_list(complex); 1308 if (tok != ZEND) 1309 YYERRORV(oecused); 1310 zshlex(); 1311 } else 1312 YYERRORV(oecused); 1313 1314 ecbuf[p] = WCB_WHILE(type, ecused - 1 - p); 1315} 1316 1317/* 1318 * repeat : REPEAT STRING { SEPER } ( DO list DONE | list1 ) 1319 */ 1320 1321/**/ 1322static void 1323par_repeat(int *complex) 1324{ 1325 int oecused = ecused, p; 1326 1327 p = ecadd(0); 1328 1329 incmdpos = 0; 1330 zshlex(); 1331 if (tok != STRING) 1332 YYERRORV(oecused); 1333 ecstr(tokstr); 1334 incmdpos = 1; 1335 zshlex(); 1336 while (tok == SEPER) 1337 zshlex(); 1338 if (tok == DOLOOP) { 1339 zshlex(); 1340 par_save_list(complex); 1341 if (tok != DONE) 1342 YYERRORV(oecused); 1343 zshlex(); 1344 } else if (tok == INBRACE) { 1345 zshlex(); 1346 par_save_list(complex); 1347 if (tok != OUTBRACE) 1348 YYERRORV(oecused); 1349 zshlex(); 1350 } else if (isset(CSHJUNKIELOOPS)) { 1351 par_save_list(complex); 1352 if (tok != ZEND) 1353 YYERRORV(oecused); 1354 zshlex(); 1355 } else if (unset(SHORTLOOPS)) { 1356 YYERRORV(oecused); 1357 } else 1358 par_save_list1(complex); 1359 1360 ecbuf[p] = WCB_REPEAT(ecused - 1 - p); 1361} 1362 1363/* 1364 * subsh : INPAR list OUTPAR | 1365 * INBRACE list OUTBRACE [ "always" INBRACE list OUTBRACE ] 1366 */ 1367 1368/**/ 1369static void 1370par_subsh(int *complex) 1371{ 1372 enum lextok otok = tok; 1373 int oecused = ecused, p, pp; 1374 1375 p = ecadd(0); 1376 /* Extra word only needed for always block */ 1377 pp = ecadd(0); 1378 zshlex(); 1379 par_list(complex); 1380 ecadd(WCB_END()); 1381 if (tok != ((otok == INPAR) ? OUTPAR : OUTBRACE)) 1382 YYERRORV(oecused); 1383 incmdpos = 1; 1384 zshlex(); 1385 1386 /* Optional always block. No intervening SEPERs allowed. */ 1387 if (otok == INBRACE && tok == STRING && !strcmp(tokstr, "always")) { 1388 ecbuf[pp] = WCB_TRY(ecused - 1 - pp); 1389 incmdpos = 1; 1390 do { 1391 zshlex(); 1392 } while (tok == SEPER); 1393 1394 if (tok != INBRACE) 1395 YYERRORV(oecused); 1396 cmdpop(); 1397 cmdpush(CS_ALWAYS); 1398 1399 zshlex(); 1400 par_save_list(complex); 1401 while (tok == SEPER) 1402 zshlex(); 1403 1404 incmdpos = 1; 1405 1406 if (tok != OUTBRACE) 1407 YYERRORV(oecused); 1408 zshlex(); 1409 ecbuf[p] = WCB_TRY(ecused - 1 - p); 1410 } else { 1411 ecbuf[p] = (otok == INPAR ? WCB_SUBSH(ecused - 1 - p) : 1412 WCB_CURSH(ecused - 1 - p)); 1413 } 1414} 1415 1416/* 1417 * funcdef : FUNCTION wordlist [ INOUTPAR ] { SEPER } 1418 * ( list1 | INBRACE list OUTBRACE ) 1419 */ 1420 1421/**/ 1422static void 1423par_funcdef(int *complex) 1424{ 1425 int oecused = ecused, num = 0, onp, p, c = 0; 1426 int so, oecssub = ecssub; 1427 zlong oldlineno = lineno; 1428 1429 lineno = 0; 1430 nocorrect = 1; 1431 incmdpos = 0; 1432 zshlex(); 1433 1434 p = ecadd(0); 1435 ecadd(0); 1436 1437 incmdpos = 1; 1438 while (tok == STRING) { 1439 if (*tokstr == Inbrace && !tokstr[1]) { 1440 tok = INBRACE; 1441 break; 1442 } 1443 ecstr(tokstr); 1444 num++; 1445 zshlex(); 1446 } 1447 ecadd(0); 1448 ecadd(0); 1449 ecadd(0); 1450 1451 nocorrect = 0; 1452 if (tok == INOUTPAR) 1453 zshlex(); 1454 while (tok == SEPER) 1455 zshlex(); 1456 1457 ecnfunc++; 1458 ecssub = so = ecsoffs; 1459 onp = ecnpats; 1460 ecnpats = 0; 1461 1462 if (tok == INBRACE) { 1463 zshlex(); 1464 par_list(&c); 1465 if (tok != OUTBRACE) { 1466 lineno += oldlineno; 1467 ecnpats = onp; 1468 ecssub = oecssub; 1469 YYERRORV(oecused); 1470 } 1471 if (num == 0) { 1472 /* Anonymous function, possibly with arguments */ 1473 incmdpos = 0; 1474 *complex = 1; 1475 } 1476 zshlex(); 1477 } else if (unset(SHORTLOOPS)) { 1478 lineno += oldlineno; 1479 ecnpats = onp; 1480 ecssub = oecssub; 1481 YYERRORV(oecused); 1482 } else 1483 par_list1(&c); 1484 1485 ecadd(WCB_END()); 1486 ecbuf[p + num + 2] = so - oecssub; 1487 ecbuf[p + num + 3] = ecsoffs - so; 1488 ecbuf[p + num + 4] = ecnpats; 1489 ecbuf[p + 1] = num; 1490 1491 ecnpats = onp; 1492 ecssub = oecssub; 1493 ecnfunc++; 1494 1495 ecbuf[p] = WCB_FUNCDEF(ecused - 1 - p); 1496 1497 if (num == 0) { 1498 /* Unnamed function */ 1499 int parg = ecadd(0); 1500 ecadd(0); 1501 while (tok == STRING) { 1502 ecstr(tokstr); 1503 num++; 1504 zshlex(); 1505 } 1506 ecbuf[parg] = ecused - parg; /*?*/ 1507 ecbuf[parg+1] = num; 1508 } 1509 lineno += oldlineno; 1510} 1511 1512/* 1513 * time : TIME sublist2 1514 */ 1515 1516/**/ 1517static void 1518par_time(void) 1519{ 1520 int p, f, c = 0; 1521 1522 zshlex(); 1523 1524 p = ecadd(0); 1525 ecadd(0); 1526 if ((f = par_sublist2(&c)) < 0) { 1527 ecused--; 1528 ecbuf[p] = WCB_TIMED(WC_TIMED_EMPTY); 1529 } else { 1530 ecbuf[p] = WCB_TIMED(WC_TIMED_PIPE); 1531 set_sublist_code(p + 1, WC_SUBLIST_END, f, ecused - 2 - p, c); 1532 } 1533} 1534 1535/* 1536 * dinbrack : DINBRACK cond DOUTBRACK 1537 */ 1538 1539/**/ 1540static void 1541par_dinbrack(void) 1542{ 1543 int oecused = ecused; 1544 1545 incond = 1; 1546 incmdpos = 0; 1547 zshlex(); 1548 par_cond(); 1549 if (tok != DOUTBRACK) 1550 YYERRORV(oecused); 1551 incond = 0; 1552 incmdpos = 1; 1553 zshlex(); 1554} 1555 1556/* 1557 * simple : { COMMAND | EXEC | NOGLOB | NOCORRECT | DASH } 1558 { STRING | ENVSTRING | ENVARRAY wordlist OUTPAR | redir } 1559 [ INOUTPAR { SEPER } ( list1 | INBRACE list OUTBRACE ) ] 1560 * 1561 * Returns 0 if no code, else 1 plus the number of code words 1562 * used up by redirections. 1563 */ 1564 1565/**/ 1566static int 1567par_simple(int *complex, int nr) 1568{ 1569 int oecused = ecused, isnull = 1, r, argc = 0, p, isfunc = 0, sr = 0; 1570 int c = *complex, nrediradd, assignments = 0; 1571 1572 r = ecused; 1573 for (;;) { 1574 if (tok == NOCORRECT) { 1575 *complex = c = 1; 1576 nocorrect = 1; 1577 } else if (tok == ENVSTRING) { 1578 char *p, *name, *str; 1579 1580 name = tokstr; 1581 for (p = tokstr; *p && *p != Inbrack && *p != '=' && *p != '+'; 1582 p++); 1583 if (*p == Inbrack) skipparens(Inbrack, Outbrack, &p); 1584 if (*p == '+') { 1585 *p++ = '\0'; 1586 ecadd(WCB_ASSIGN(WC_ASSIGN_SCALAR, WC_ASSIGN_INC, 0)); 1587 } else 1588 ecadd(WCB_ASSIGN(WC_ASSIGN_SCALAR, WC_ASSIGN_NEW, 0)); 1589 1590 if (*p == '=') { 1591 *p = '\0'; 1592 str = p + 1; 1593 } else 1594 equalsplit(tokstr, &str); 1595 for (p = str; *p; p++) { 1596 /* 1597 * We can't treat this as "simple" if it contains 1598 * expansions that require process subsitution, since then 1599 * we need process handling. 1600 */ 1601 if (p[1] == Inpar && 1602 (*p == Equals || *p == Inang || *p == OutangProc)) { 1603 *complex = 1; 1604 break; 1605 } 1606 } 1607 ecstr(name); 1608 ecstr(str); 1609 isnull = 0; 1610 assignments = 1; 1611 } else if (tok == ENVARRAY) { 1612 int oldcmdpos = incmdpos, n, type2; 1613 1614 /* 1615 * We consider array setting complex because it can 1616 * contain process substitutions, which need a valid job. 1617 */ 1618 *complex = c = 1; 1619 p = ecadd(0); 1620 incmdpos = 0; 1621 if ((type2 = strlen(tokstr) - 1) && tokstr[type2] == '+') { 1622 tokstr[type2] = '\0'; 1623 type2 = WC_ASSIGN_INC; 1624 } else 1625 type2 = WC_ASSIGN_NEW; 1626 ecstr(tokstr); 1627 cmdpush(CS_ARRAY); 1628 zshlex(); 1629 n = par_nl_wordlist(); 1630 ecbuf[p] = WCB_ASSIGN(WC_ASSIGN_ARRAY, type2, n); 1631 cmdpop(); 1632 if (tok != OUTPAR) 1633 YYERROR(oecused); 1634 incmdpos = oldcmdpos; 1635 isnull = 0; 1636 assignments = 1; 1637 } else 1638 break; 1639 zshlex(); 1640 } 1641 if (tok == AMPER || tok == AMPERBANG) 1642 YYERROR(oecused); 1643 1644 p = ecadd(WCB_SIMPLE(0)); 1645 1646 for (;;) { 1647 if (tok == STRING) { 1648 int redir_var = 0; 1649 1650 *complex = 1; 1651 incmdpos = 0; 1652 1653 if (!isset(IGNOREBRACES) && *tokstr == Inbrace) 1654 { 1655 char *eptr = tokstr + strlen(tokstr) - 1; 1656 char *ptr = eptr; 1657 1658 if (*ptr == Outbrace && ptr > tokstr + 1) 1659 { 1660 if (itype_end(tokstr+1, IIDENT, 0) >= ptr - 1) 1661 { 1662 char *toksave = tokstr; 1663 char *idstring = dupstrpfx(tokstr+1, eptr-tokstr-1); 1664 redir_var = 1; 1665 zshlex(); 1666 1667 if (IS_REDIROP(tok) && tokfd == -1) 1668 { 1669 *complex = c = 1; 1670 nrediradd = par_redir(&r, idstring); 1671 p += nrediradd; 1672 sr += nrediradd; 1673 } 1674 else 1675 { 1676 ecstr(toksave); 1677 argc++; 1678 } 1679 } 1680 } 1681 } 1682 1683 if (!redir_var) 1684 { 1685 ecstr(tokstr); 1686 argc++; 1687 zshlex(); 1688 } 1689 } else if (IS_REDIROP(tok)) { 1690 *complex = c = 1; 1691 nrediradd = par_redir(&r, NULL); 1692 p += nrediradd; 1693 sr += nrediradd; 1694 } else if (tok == INOUTPAR) { 1695 zlong oldlineno = lineno; 1696 int onp, so, oecssub = ecssub; 1697 1698 /* Error if too many function definitions at once */ 1699 if (!isset(MULTIFUNCDEF) && argc > 1) 1700 YYERROR(oecused); 1701 /* Error if preceding assignments */ 1702 if (assignments) 1703 YYERROR(oecused); 1704 1705 *complex = c; 1706 lineno = 0; 1707 incmdpos = 1; 1708 cmdpush(CS_FUNCDEF); 1709 zshlex(); 1710 while (tok == SEPER) 1711 zshlex(); 1712 1713 ecispace(p + 1, 1); 1714 ecbuf[p + 1] = argc; 1715 ecadd(0); 1716 ecadd(0); 1717 ecadd(0); 1718 1719 ecnfunc++; 1720 ecssub = so = ecsoffs; 1721 onp = ecnpats; 1722 ecnpats = 0; 1723 1724 if (tok == INBRACE) { 1725 int c = 0; 1726 1727 zshlex(); 1728 par_list(&c); 1729 if (tok != OUTBRACE) { 1730 cmdpop(); 1731 lineno += oldlineno; 1732 ecnpats = onp; 1733 ecssub = oecssub; 1734 YYERROR(oecused); 1735 } 1736 if (argc == 0) { 1737 /* Anonymous function, possibly with arguments */ 1738 incmdpos = 0; 1739 *complex = 1; 1740 } 1741 zshlex(); 1742 } else { 1743 int ll, sl, c = 0; 1744 1745 ll = ecadd(0); 1746 sl = ecadd(0); 1747 (void)ecadd(WCB_PIPE(WC_PIPE_END, 0)); 1748 1749 if (!par_cmd(&c)) { 1750 cmdpop(); 1751 YYERROR(oecused); 1752 } 1753 1754 set_sublist_code(sl, WC_SUBLIST_END, 0, ecused - 1 - sl, c); 1755 set_list_code(ll, (Z_SYNC | Z_END), c); 1756 } 1757 cmdpop(); 1758 1759 ecadd(WCB_END()); 1760 ecbuf[p + argc + 2] = so - oecssub; 1761 ecbuf[p + argc + 3] = ecsoffs - so; 1762 ecbuf[p + argc + 4] = ecnpats; 1763 1764 ecnpats = onp; 1765 ecssub = oecssub; 1766 ecnfunc++; 1767 1768 ecbuf[p] = WCB_FUNCDEF(ecused - 1 - p); 1769 1770 if (argc == 0) { 1771 /* Unnamed function */ 1772 int parg = ecadd(0); 1773 ecadd(0); 1774 while (tok == STRING) { 1775 ecstr(tokstr); 1776 argc++; 1777 zshlex(); 1778 } 1779 ecbuf[parg] = ecused - parg; /*?*/ 1780 ecbuf[parg+1] = argc; 1781 } 1782 lineno += oldlineno; 1783 1784 isfunc = 1; 1785 isnull = 0; 1786 break; 1787 } else 1788 break; 1789 isnull = 0; 1790 } 1791 if (isnull && !(sr + nr)) { 1792 ecused = p; 1793 return 0; 1794 } 1795 incmdpos = 1; 1796 1797 if (!isfunc) 1798 ecbuf[p] = WCB_SIMPLE(argc); 1799 1800 return sr + 1; 1801} 1802 1803/* 1804 * redir : ( OUTANG | ... | TRINANG ) STRING 1805 * 1806 * Return number of code words required for redirection 1807 */ 1808 1809static int redirtab[TRINANG - OUTANG + 1] = { 1810 REDIR_WRITE, 1811 REDIR_WRITENOW, 1812 REDIR_APP, 1813 REDIR_APPNOW, 1814 REDIR_READ, 1815 REDIR_READWRITE, 1816 REDIR_HEREDOC, 1817 REDIR_HEREDOCDASH, 1818 REDIR_MERGEIN, 1819 REDIR_MERGEOUT, 1820 REDIR_ERRWRITE, 1821 REDIR_ERRWRITENOW, 1822 REDIR_ERRAPP, 1823 REDIR_ERRAPPNOW, 1824 REDIR_HERESTR, 1825}; 1826 1827/**/ 1828static int 1829par_redir(int *rp, char *idstring) 1830{ 1831 int r = *rp, type, fd1, oldcmdpos, oldnc, ncodes; 1832 char *name; 1833 1834 oldcmdpos = incmdpos; 1835 incmdpos = 0; 1836 oldnc = nocorrect; 1837 if (tok != INANG && tok != INOUTANG) 1838 nocorrect = 1; 1839 type = redirtab[tok - OUTANG]; 1840 fd1 = tokfd; 1841 zshlex(); 1842 if (tok != STRING && tok != ENVSTRING) 1843 YYERROR(ecused); 1844 incmdpos = oldcmdpos; 1845 nocorrect = oldnc; 1846 1847 /* assign default fd */ 1848 if (fd1 == -1) 1849 fd1 = IS_READFD(type) ? 0 : 1; 1850 1851 name = tokstr; 1852 1853 switch (type) { 1854 case REDIR_HEREDOC: 1855 case REDIR_HEREDOCDASH: { 1856 /* <<[-] name */ 1857 struct heredocs **hd; 1858 int htype = type; 1859 1860 /* 1861 * Add two here for the string to remember the HERE 1862 * terminator in raw and munged form. 1863 */ 1864 if (idstring) 1865 { 1866 type |= REDIR_VARID_MASK; 1867 ncodes = 6; 1868 } 1869 else 1870 ncodes = 5; 1871 1872 /* If we ever to change the number of codes, we have to change 1873 * the definition of WC_REDIR_WORDS. */ 1874 ecispace(r, ncodes); 1875 *rp = r + ncodes; 1876 ecbuf[r] = WCB_REDIR(type); 1877 ecbuf[r + 1] = fd1; 1878 1879 /* 1880 * r + 2: the HERE string we recover 1881 * r + 3: the HERE document terminator, raw 1882 * r + 4: the HERE document terminator, munged 1883 */ 1884 if (idstring) 1885 ecbuf[r + 5] = ecstrcode(idstring); 1886 1887 for (hd = &hdocs; *hd; hd = &(*hd)->next) 1888 ; 1889 *hd = zalloc(sizeof(struct heredocs)); 1890 (*hd)->next = NULL; 1891 (*hd)->type = htype; 1892 (*hd)->pc = r; 1893 (*hd)->str = tokstr; 1894 1895 zshlex(); 1896 return ncodes; 1897 } 1898 case REDIR_WRITE: 1899 case REDIR_WRITENOW: 1900 if (tokstr[0] == OutangProc && tokstr[1] == Inpar) 1901 /* > >(...) */ 1902 type = REDIR_OUTPIPE; 1903 else if (tokstr[0] == Inang && tokstr[1] == Inpar) 1904 YYERROR(ecused); 1905 break; 1906 case REDIR_READ: 1907 if (tokstr[0] == Inang && tokstr[1] == Inpar) 1908 /* < <(...) */ 1909 type = REDIR_INPIPE; 1910 else if (tokstr[0] == OutangProc && tokstr[1] == Inpar) 1911 YYERROR(ecused); 1912 break; 1913 case REDIR_READWRITE: 1914 if ((tokstr[0] == Inang || tokstr[0] == OutangProc) && 1915 tokstr[1] == Inpar) 1916 type = tokstr[0] == Inang ? REDIR_INPIPE : REDIR_OUTPIPE; 1917 break; 1918 } 1919 zshlex(); 1920 1921 /* If we ever to change the number of codes, we have to change 1922 * the definition of WC_REDIR_WORDS. */ 1923 if (idstring) 1924 { 1925 type |= REDIR_VARID_MASK; 1926 ncodes = 4; 1927 } 1928 else 1929 ncodes = 3; 1930 1931 ecispace(r, ncodes); 1932 *rp = r + ncodes; 1933 ecbuf[r] = WCB_REDIR(type); 1934 ecbuf[r + 1] = fd1; 1935 ecbuf[r + 2] = ecstrcode(name); 1936 if (idstring) 1937 ecbuf[r + 3] = ecstrcode(idstring); 1938 1939 return ncodes; 1940} 1941 1942/**/ 1943void 1944setheredoc(int pc, int type, char *str, char *termstr, char *munged_termstr) 1945{ 1946 ecbuf[pc] = WCB_REDIR(type | REDIR_FROM_HEREDOC_MASK); 1947 ecbuf[pc + 2] = ecstrcode(str); 1948 ecbuf[pc + 3] = ecstrcode(termstr); 1949 ecbuf[pc + 4] = ecstrcode(munged_termstr); 1950} 1951 1952/* 1953 * wordlist : { STRING } 1954 */ 1955 1956/**/ 1957static int 1958par_wordlist(void) 1959{ 1960 int num = 0; 1961 while (tok == STRING) { 1962 ecstr(tokstr); 1963 num++; 1964 zshlex(); 1965 } 1966 return num; 1967} 1968 1969/* 1970 * nl_wordlist : { STRING | SEPER } 1971 */ 1972 1973/**/ 1974static int 1975par_nl_wordlist(void) 1976{ 1977 int num = 0; 1978 1979 while (tok == STRING || tok == SEPER) { 1980 if (tok != SEPER) { 1981 ecstr(tokstr); 1982 num++; 1983 } 1984 zshlex(); 1985 } 1986 return num; 1987} 1988 1989/* 1990 * condlex is zshlex for normal parsing, but is altered to allow 1991 * the test builtin to use par_cond. 1992 */ 1993 1994/**/ 1995void (*condlex) _((void)) = zshlex; 1996 1997/* 1998 * cond : cond_1 { SEPER } [ DBAR { SEPER } cond ] 1999 */ 2000 2001/**/ 2002static int 2003par_cond(void) 2004{ 2005 int p = ecused, r; 2006 2007 r = par_cond_1(); 2008 while (tok == SEPER) 2009 condlex(); 2010 if (tok == DBAR) { 2011 condlex(); 2012 while (tok == SEPER) 2013 condlex(); 2014 ecispace(p, 1); 2015 par_cond(); 2016 ecbuf[p] = WCB_COND(COND_OR, ecused - 1 - p); 2017 return 1; 2018 } 2019 return r; 2020} 2021 2022/* 2023 * cond_1 : cond_2 { SEPER } [ DAMPER { SEPER } cond_1 ] 2024 */ 2025 2026/**/ 2027static int 2028par_cond_1(void) 2029{ 2030 int r, p = ecused; 2031 2032 r = par_cond_2(); 2033 while (tok == SEPER) 2034 condlex(); 2035 if (tok == DAMPER) { 2036 condlex(); 2037 while (tok == SEPER) 2038 condlex(); 2039 ecispace(p, 1); 2040 par_cond_1(); 2041 ecbuf[p] = WCB_COND(COND_AND, ecused - 1 - p); 2042 return 1; 2043 } 2044 return r; 2045} 2046 2047/* 2048 * cond_2 : BANG cond_2 2049 | INPAR { SEPER } cond_2 { SEPER } OUTPAR 2050 | STRING STRING STRING 2051 | STRING STRING 2052 | STRING ( INANG | OUTANG ) STRING 2053 */ 2054 2055/**/ 2056static int 2057par_cond_2(void) 2058{ 2059 char *s1, *s2, *s3; 2060 int dble = 0; 2061 2062 if (condlex == testlex) { 2063 /* See the description of test in POSIX 1003.2 */ 2064 if (tok == NULLTOK) 2065 /* no arguments: false */ 2066 return par_cond_double(dupstring("-n"), dupstring("")); 2067 if (!*testargs) { 2068 /* one argument: [ foo ] is equivalent to [ -n foo ] */ 2069 s1 = tokstr; 2070 condlex(); 2071 return par_cond_double(dupstring("-n"), s1); 2072 } 2073 if (testargs[1]) { 2074 /* three arguments: if the second argument is a binary operator, * 2075 * perform that binary test on the first and the third argument */ 2076 if (!strcmp(*testargs, "=") || 2077 !strcmp(*testargs, "==") || 2078 !strcmp(*testargs, "!=") || 2079 (**testargs == '-' && get_cond_num(*testargs + 1) >= 0)) { 2080 s1 = tokstr; 2081 condlex(); 2082 s2 = tokstr; 2083 condlex(); 2084 s3 = tokstr; 2085 condlex(); 2086 return par_cond_triple(s1, s2, s3); 2087 } 2088 } 2089 } 2090 if (tok == BANG) { 2091 /* 2092 * In "test" compatibility mode, "! -a ..." and "! -o ..." 2093 * are treated as "[string] [and] ..." and "[string] [or] ...". 2094 */ 2095 if (!(condlex == testlex && *testargs && 2096 (!strcmp(*testargs, "-a") || !strcmp(*testargs, "-o")))) 2097 { 2098 condlex(); 2099 ecadd(WCB_COND(COND_NOT, 0)); 2100 return par_cond_2(); 2101 } 2102 } 2103 if (tok == INPAR) { 2104 int r; 2105 2106 condlex(); 2107 while (tok == SEPER) 2108 condlex(); 2109 r = par_cond(); 2110 while (tok == SEPER) 2111 condlex(); 2112 if (tok != OUTPAR) 2113 YYERROR(ecused); 2114 condlex(); 2115 return r; 2116 } 2117 if (tok != STRING) { 2118 if (tok && tok != LEXERR && condlex == testlex) { 2119 s1 = tokstr; 2120 condlex(); 2121 return par_cond_double("-n", s1); 2122 } else 2123 YYERROR(ecused); 2124 } 2125 s1 = tokstr; 2126 if (condlex == testlex) 2127 dble = (*s1 == '-' && strspn(s1+1, "abcdefghknoprstuwxzLONGS") == 1 2128 && !s1[2]); 2129 condlex(); 2130 if (tok == INANG || tok == OUTANG) { 2131 enum lextok xtok = tok; 2132 condlex(); 2133 if (tok != STRING) 2134 YYERROR(ecused); 2135 s3 = tokstr; 2136 condlex(); 2137 ecadd(WCB_COND((xtok == INANG ? COND_STRLT : COND_STRGTR), 0)); 2138 ecstr(s1); 2139 ecstr(s3); 2140 return 1; 2141 } 2142 if (tok != STRING) { 2143 if (tok != LEXERR && condlex == testlex) { 2144 if (!dble) 2145 return par_cond_double("-n", s1); 2146 else if (!strcmp(s1, "-t")) 2147 return par_cond_double(s1, "1"); 2148 } else 2149 YYERROR(ecused); 2150 } 2151 s2 = tokstr; 2152 incond++; /* parentheses do globbing */ 2153 condlex(); 2154 incond--; /* parentheses do grouping */ 2155 if (tok == STRING && !dble) { 2156 s3 = tokstr; 2157 condlex(); 2158 if (tok == STRING) { 2159 LinkList l = newlinklist(); 2160 2161 addlinknode(l, s2); 2162 addlinknode(l, s3); 2163 2164 while (tok == STRING) { 2165 addlinknode(l, tokstr); 2166 condlex(); 2167 } 2168 return par_cond_multi(s1, l); 2169 } else 2170 return par_cond_triple(s1, s2, s3); 2171 } else 2172 return par_cond_double(s1, s2); 2173} 2174 2175/**/ 2176static int 2177par_cond_double(char *a, char *b) 2178{ 2179 if (a[0] != '-' || !a[1]) 2180 COND_ERROR("parse error: condition expected: %s", a); 2181 else if (!a[2] && strspn(a+1, "abcdefgknoprstuwxzhLONGS") == 1) { 2182 ecadd(WCB_COND(a[1], 0)); 2183 ecstr(b); 2184 } else { 2185 ecadd(WCB_COND(COND_MOD, 1)); 2186 ecstr(a); 2187 ecstr(b); 2188 } 2189 return 1; 2190} 2191 2192/**/ 2193static int 2194get_cond_num(char *tst) 2195{ 2196 static char *condstrs[] = 2197 { 2198 "nt", "ot", "ef", "eq", "ne", "lt", "gt", "le", "ge", NULL 2199 }; 2200 int t0; 2201 2202 for (t0 = 0; condstrs[t0]; t0++) 2203 if (!strcmp(condstrs[t0], tst)) 2204 return t0; 2205 return -1; 2206} 2207 2208/**/ 2209static int 2210par_cond_triple(char *a, char *b, char *c) 2211{ 2212 int t0; 2213 2214 if ((b[0] == Equals || b[0] == '=') && 2215 (!b[1] || ((b[1] == Equals || b[1] == '=') && !b[2]))) { 2216 ecadd(WCB_COND(COND_STREQ, 0)); 2217 ecstr(a); 2218 ecstr(c); 2219 ecadd(ecnpats++); 2220 } else if (b[0] == '!' && (b[1] == Equals || b[1] == '=') && !b[2]) { 2221 ecadd(WCB_COND(COND_STRNEQ, 0)); 2222 ecstr(a); 2223 ecstr(c); 2224 ecadd(ecnpats++); 2225 } else if ((b[0] == Equals || b[0] == '=') && 2226 (b[1] == '~' || b[1] == Tilde) && !b[2]) { 2227 /* We become an implicit COND_MODI but do not provide the first 2228 * item, it's skipped */ 2229 ecadd(WCB_COND(COND_REGEX, 0)); 2230 ecstr(a); 2231 ecstr(c); 2232 } else if (b[0] == '-') { 2233 if ((t0 = get_cond_num(b + 1)) > -1) { 2234 ecadd(WCB_COND(t0 + COND_NT, 0)); 2235 ecstr(a); 2236 ecstr(c); 2237 } else { 2238 ecadd(WCB_COND(COND_MODI, 0)); 2239 ecstr(b); 2240 ecstr(a); 2241 ecstr(c); 2242 } 2243 } else if (a[0] == '-' && a[1]) { 2244 ecadd(WCB_COND(COND_MOD, 2)); 2245 ecstr(a); 2246 ecstr(b); 2247 ecstr(c); 2248 } else 2249 COND_ERROR("condition expected: %s", b); 2250 2251 return 1; 2252} 2253 2254/**/ 2255static int 2256par_cond_multi(char *a, LinkList l) 2257{ 2258 if (a[0] != '-' || !a[1]) 2259 COND_ERROR("condition expected: %s", a); 2260 else { 2261 LinkNode n; 2262 2263 ecadd(WCB_COND(COND_MOD, countlinknodes(l))); 2264 ecstr(a); 2265 for (n = firstnode(l); n; incnode(n)) 2266 ecstr((char *) getdata(n)); 2267 } 2268 return 1; 2269} 2270 2271/**/ 2272static void 2273yyerror(int noerr) 2274{ 2275 int t0; 2276 char *t; 2277 2278 if ((t = dupstring(zshlextext))) 2279 untokenize(t); 2280 2281 for (t0 = 0; t0 != 20; t0++) 2282 if (!t || !t[t0] || t[t0] == '\n') 2283 break; 2284 if (!(histdone & HISTFLAG_NOEXEC)) { 2285 if (t0 == 20) 2286 zwarn("parse error near `%l...'", t, 20); 2287 else if (t0) 2288 zwarn("parse error near `%l'", t, t0); 2289 else 2290 zwarn("parse error"); 2291 } 2292 if (!noerr && noerrs != 2) 2293 errflag = 1; 2294} 2295 2296/* 2297 * Duplicate a programme list, on the heap if heap is 1, else 2298 * in permanent storage. 2299 * 2300 * Be careful in case p is the Eprog for a function which will 2301 * later be autoloaded. The shf element of the returned Eprog 2302 * must be set appropriately by the caller. (Normally we create 2303 * the Eprog in this case by using mkautofn.) 2304 */ 2305 2306/**/ 2307mod_export Eprog 2308dupeprog(Eprog p, int heap) 2309{ 2310 Eprog r; 2311 int i; 2312 Patprog *pp; 2313 2314 if (p == &dummy_eprog) 2315 return p; 2316 2317 r = (heap ? (Eprog) zhalloc(sizeof(*r)) : (Eprog) zalloc(sizeof(*r))); 2318 r->flags = (heap ? EF_HEAP : EF_REAL) | (p->flags & EF_RUN); 2319 r->dump = NULL; 2320 r->len = p->len; 2321 r->npats = p->npats; 2322 /* 2323 * If Eprog is on the heap, reference count is not valid. 2324 * Otherwise, initialise reference count to 1 so that a freeeprog() 2325 * will delete it if it is not in use. 2326 */ 2327 r->nref = heap ? -1 : 1; 2328 pp = r->pats = (heap ? (Patprog *) hcalloc(r->len) : 2329 (Patprog *) zshcalloc(r->len)); 2330 r->prog = (Wordcode) (r->pats + r->npats); 2331 r->strs = ((char *) r->prog) + (p->strs - ((char *) p->prog)); 2332 memcpy(r->prog, p->prog, r->len - (p->npats * sizeof(Patprog))); 2333 r->shf = NULL; 2334 2335 for (i = r->npats; i--; pp++) 2336 *pp = dummy_patprog1; 2337 2338 return r; 2339} 2340 2341 2342/* 2343 * Pair of functions to mark an Eprog as in use, and to delete it 2344 * when it is no longer in use, by means of the reference count in 2345 * then nref element. 2346 * 2347 * If nref is negative, the Eprog is on the heap and is never freed. 2348 */ 2349 2350/* Increase the reference count of an Eprog so it won't be deleted. */ 2351 2352/**/ 2353mod_export void 2354useeprog(Eprog p) 2355{ 2356 if (p && p != &dummy_eprog && p->nref >= 0) 2357 p->nref++; 2358} 2359 2360/* Free an Eprog if we have finished with it */ 2361 2362/**/ 2363mod_export void 2364freeeprog(Eprog p) 2365{ 2366 int i; 2367 Patprog *pp; 2368 2369 if (p && p != &dummy_eprog) { 2370 /* paranoia */ 2371 DPUTS(p->nref > 0 && (p->flags & EF_HEAP), "Heap EPROG has nref > 0"); 2372 DPUTS(p->nref < 0 && !(p->flags & EF_HEAP), "Real EPROG has nref < 0"); 2373 DPUTS(p->nref < -1, "Uninitialised EPROG nref"); 2374#ifdef MAX_FUNCTION_DEPTH 2375 DPUTS(p->nref > MAX_FUNCTION_DEPTH + 10, "Overlarge EPROG nref"); 2376#endif 2377 if (p->nref > 0 && !--p->nref) { 2378 for (i = p->npats, pp = p->pats; i--; pp++) 2379 freepatprog(*pp); 2380 if (p->dump) { 2381 decrdumpcount(p->dump); 2382 zfree(p->pats, p->npats * sizeof(Patprog)); 2383 } else 2384 zfree(p->pats, p->len); 2385 zfree(p, sizeof(*p)); 2386 } 2387 } 2388} 2389 2390/**/ 2391char * 2392ecgetstr(Estate s, int dup, int *tokflag) 2393{ 2394 static char buf[4]; 2395 wordcode c = *s->pc++; 2396 char *r; 2397 2398 if (c == 6 || c == 7) 2399 r = ""; 2400 else if (c & 2) { 2401 buf[0] = (char) ((c >> 3) & 0xff); 2402 buf[1] = (char) ((c >> 11) & 0xff); 2403 buf[2] = (char) ((c >> 19) & 0xff); 2404 buf[3] = '\0'; 2405 r = dupstring(buf); 2406 dup = EC_NODUP; 2407 } else { 2408 r = s->strs + (c >> 2); 2409 } 2410 if (tokflag) 2411 *tokflag = (c & 1); 2412 2413 /*** Since function dump files are mapped read-only, avoiding to 2414 * to duplicate strings when they don't contain tokens may fail 2415 * when one of the many utility functions happens to write to 2416 * one of the strings (without really modifying it). 2417 * If that happens to you and you don't feel like debugging it, 2418 * just change the line below to: 2419 * 2420 * return (dup ? dupstring(r) : r); 2421 */ 2422 2423 return ((dup == EC_DUP || (dup && (c & 1))) ? dupstring(r) : r); 2424} 2425 2426/**/ 2427char * 2428ecrawstr(Eprog p, Wordcode pc, int *tokflag) 2429{ 2430 static char buf[4]; 2431 wordcode c = *pc; 2432 2433 if (c == 6 || c == 7) { 2434 if (tokflag) 2435 *tokflag = (c & 1); 2436 return ""; 2437 } else if (c & 2) { 2438 buf[0] = (char) ((c >> 3) & 0xff); 2439 buf[1] = (char) ((c >> 11) & 0xff); 2440 buf[2] = (char) ((c >> 19) & 0xff); 2441 buf[3] = '\0'; 2442 if (tokflag) 2443 *tokflag = (c & 1); 2444 return buf; 2445 } else { 2446 if (tokflag) 2447 *tokflag = (c & 1); 2448 return p->strs + (c >> 2); 2449 } 2450} 2451 2452/**/ 2453char ** 2454ecgetarr(Estate s, int num, int dup, int *tokflag) 2455{ 2456 char **ret, **rp; 2457 int tf = 0, tmp = 0; 2458 2459 ret = rp = (char **) zhalloc((num + 1) * sizeof(char *)); 2460 2461 while (num--) { 2462 *rp++ = ecgetstr(s, dup, &tmp); 2463 tf |= tmp; 2464 } 2465 *rp = NULL; 2466 if (tokflag) 2467 *tokflag = tf; 2468 2469 return ret; 2470} 2471 2472/**/ 2473LinkList 2474ecgetlist(Estate s, int num, int dup, int *tokflag) 2475{ 2476 if (num) { 2477 LinkList ret; 2478 int i, tf = 0, tmp = 0; 2479 2480 ret = newsizedlist(num); 2481 for (i = 0; i < num; i++) { 2482 setsizednode(ret, i, ecgetstr(s, dup, &tmp)); 2483 tf |= tmp; 2484 } 2485 if (tokflag) 2486 *tokflag = tf; 2487 return ret; 2488 } 2489 if (tokflag) 2490 *tokflag = 0; 2491 return NULL; 2492} 2493 2494/**/ 2495LinkList 2496ecgetredirs(Estate s) 2497{ 2498 LinkList ret = newlinklist(); 2499 wordcode code = *s->pc++; 2500 2501 while (wc_code(code) == WC_REDIR) { 2502 Redir r = (Redir) zhalloc(sizeof(*r)); 2503 2504 r->type = WC_REDIR_TYPE(code); 2505 r->fd1 = *s->pc++; 2506 r->name = ecgetstr(s, EC_DUP, NULL); 2507 if (WC_REDIR_FROM_HEREDOC(code)) { 2508 r->flags = REDIRF_FROM_HEREDOC; 2509 r->here_terminator = ecgetstr(s, EC_DUP, NULL); 2510 r->munged_here_terminator = ecgetstr(s, EC_DUP, NULL); 2511 } else { 2512 r->flags = 0; 2513 r->here_terminator = NULL; 2514 r->munged_here_terminator = NULL; 2515 } 2516 if (WC_REDIR_VARID(code)) 2517 r->varid = ecgetstr(s, EC_DUP, NULL); 2518 else 2519 r->varid = NULL; 2520 2521 addlinknode(ret, r); 2522 2523 code = *s->pc++; 2524 } 2525 s->pc--; 2526 2527 return ret; 2528} 2529 2530/**/ 2531mod_export struct eprog dummy_eprog; 2532 2533static wordcode dummy_eprog_code; 2534 2535/**/ 2536void 2537init_eprog(void) 2538{ 2539 dummy_eprog_code = WCB_END(); 2540 dummy_eprog.len = sizeof(wordcode); 2541 dummy_eprog.prog = &dummy_eprog_code; 2542 dummy_eprog.strs = NULL; 2543} 2544 2545/* Code for function dump files. 2546 * 2547 * Dump files consist of a header and the function bodies (the wordcode 2548 * plus the string table) and that twice: once for the byte-order of the 2549 * host the file was created on and once for the other byte-order. The 2550 * header describes where the beginning of the `other' version is and it 2551 * is up to the shell reading the file to decide which version it needs. 2552 * This is done by checking if the first word is FD_MAGIC (then the 2553 * shell reading the file has the same byte order as the one that created 2554 * the file) or if it is FD_OMAGIC, then the `other' version has to be 2555 * read. 2556 * The header is the magic number, a word containing the flags (if the 2557 * file should be mapped or read and if this header is the `other' one), 2558 * the version string in a field of 40 characters and the descriptions 2559 * for the functions in the dump file. 2560 * 2561 * NOTES: 2562 * - This layout has to be kept; everything after it may be changed. 2563 * - When incompatible changes are made, the FD_MAGIC and FD_OMAGIC 2564 * numbers have to be changed. 2565 * 2566 * Each description consists of a struct fdhead followed by the name, 2567 * aligned to sizeof(wordcode) (i.e. 4 bytes). 2568 */ 2569 2570#include "version.h" 2571 2572#define FD_EXT ".zwc" 2573#define FD_MINMAP 4096 2574 2575#define FD_PRELEN 12 2576#define FD_MAGIC 0x04050607 2577#define FD_OMAGIC 0x07060504 2578 2579#define FDF_MAP 1 2580#define FDF_OTHER 2 2581 2582typedef struct fdhead *FDHead; 2583 2584struct fdhead { 2585 wordcode start; /* offset to function definition */ 2586 wordcode len; /* length of wordcode/strings */ 2587 wordcode npats; /* number of patterns needed */ 2588 wordcode strs; /* offset to strings */ 2589 wordcode hlen; /* header length (incl. name) */ 2590 wordcode flags; /* flags and offset to name tail */ 2591}; 2592 2593#define fdheaderlen(f) (((Wordcode) (f))[FD_PRELEN]) 2594 2595#define fdmagic(f) (((Wordcode) (f))[0]) 2596#define fdsetbyte(f,i,v) \ 2597 ((((unsigned char *) (((Wordcode) (f)) + 1))[i]) = ((unsigned char) (v))) 2598#define fdbyte(f,i) ((wordcode) (((unsigned char *) (((Wordcode) (f)) + 1))[i])) 2599#define fdflags(f) fdbyte(f, 0) 2600#define fdsetflags(f,v) fdsetbyte(f, 0, v) 2601#define fdother(f) (fdbyte(f, 1) + (fdbyte(f, 2) << 8) + (fdbyte(f, 3) << 16)) 2602#define fdsetother(f, o) \ 2603 do { \ 2604 fdsetbyte(f, 1, ((o) & 0xff)); \ 2605 fdsetbyte(f, 2, (((o) >> 8) & 0xff)); \ 2606 fdsetbyte(f, 3, (((o) >> 16) & 0xff)); \ 2607 } while (0) 2608#define fdversion(f) ((char *) ((f) + 2)) 2609 2610#define firstfdhead(f) ((FDHead) (((Wordcode) (f)) + FD_PRELEN)) 2611#define nextfdhead(f) ((FDHead) (((Wordcode) (f)) + (f)->hlen)) 2612 2613#define fdhflags(f) (((FDHead) (f))->flags) 2614#define fdhtail(f) (((FDHead) (f))->flags >> 2) 2615#define fdhbldflags(f,t) ((f) | ((t) << 2)) 2616 2617#define FDHF_KSHLOAD 1 2618#define FDHF_ZSHLOAD 2 2619 2620#define fdname(f) ((char *) (((FDHead) (f)) + 1)) 2621 2622/* This is used when building wordcode files. */ 2623 2624typedef struct wcfunc *WCFunc; 2625 2626struct wcfunc { 2627 char *name; 2628 Eprog prog; 2629 int flags; 2630}; 2631 2632/* Try to find the description for the given function name. */ 2633 2634static FDHead 2635dump_find_func(Wordcode h, char *name) 2636{ 2637 FDHead n, e = (FDHead) (h + fdheaderlen(h)); 2638 2639 for (n = firstfdhead(h); n < e; n = nextfdhead(n)) 2640 if (!strcmp(name, fdname(n) + fdhtail(n))) 2641 return n; 2642 2643 return NULL; 2644} 2645 2646/**/ 2647int 2648bin_zcompile(char *nam, char **args, Options ops, UNUSED(int func)) 2649{ 2650 int map, flags, ret; 2651 char *dump; 2652 2653 if ((OPT_ISSET(ops,'k') && OPT_ISSET(ops,'z')) || 2654 (OPT_ISSET(ops,'R') && OPT_ISSET(ops,'M')) || 2655 (OPT_ISSET(ops,'c') && 2656 (OPT_ISSET(ops,'U') || OPT_ISSET(ops,'k') || OPT_ISSET(ops,'z'))) || 2657 (!(OPT_ISSET(ops,'c') || OPT_ISSET(ops,'a')) && OPT_ISSET(ops,'m'))) { 2658 zwarnnam(nam, "illegal combination of options"); 2659 return 1; 2660 } 2661 if ((OPT_ISSET(ops,'c') || OPT_ISSET(ops,'a')) && isset(KSHAUTOLOAD)) 2662 zwarnnam(nam, "functions will use zsh style autoloading"); 2663 2664 flags = (OPT_ISSET(ops,'k') ? FDHF_KSHLOAD : 2665 (OPT_ISSET(ops,'z') ? FDHF_ZSHLOAD : 0)); 2666 2667 if (OPT_ISSET(ops,'t')) { 2668 Wordcode f; 2669 2670 if (!*args) { 2671 zwarnnam(nam, "too few arguments"); 2672 return 1; 2673 } 2674 if (!(f = load_dump_header(nam, (strsfx(FD_EXT, *args) ? *args : 2675 dyncat(*args, FD_EXT)), 1))) 2676 return 1; 2677 2678 if (args[1]) { 2679 for (args++; *args; args++) 2680 if (!dump_find_func(f, *args)) 2681 return 1; 2682 return 0; 2683 } else { 2684 FDHead h, e = (FDHead) (f + fdheaderlen(f)); 2685 2686 printf("zwc file (%s) for zsh-%s\n", 2687 ((fdflags(f) & FDF_MAP) ? "mapped" : "read"), fdversion(f)); 2688 for (h = firstfdhead(f); h < e; h = nextfdhead(h)) 2689 printf("%s\n", fdname(h)); 2690 return 0; 2691 } 2692 } 2693 if (!*args) { 2694 zwarnnam(nam, "too few arguments"); 2695 return 1; 2696 } 2697 map = (OPT_ISSET(ops,'M') ? 2 : (OPT_ISSET(ops,'R') ? 0 : 1)); 2698 2699 if (!args[1] && !(OPT_ISSET(ops,'c') || OPT_ISSET(ops,'a'))) { 2700 queue_signals(); 2701 ret = build_dump(nam, dyncat(*args, FD_EXT), args, OPT_ISSET(ops,'U'), 2702 map, flags); 2703 unqueue_signals(); 2704 return ret; 2705 } 2706 dump = (strsfx(FD_EXT, *args) ? *args : dyncat(*args, FD_EXT)); 2707 2708 queue_signals(); 2709 ret = ((OPT_ISSET(ops,'c') || OPT_ISSET(ops,'a')) ? 2710 build_cur_dump(nam, dump, args + 1, OPT_ISSET(ops,'m'), map, 2711 (OPT_ISSET(ops,'c') ? 1 : 0) | 2712 (OPT_ISSET(ops,'a') ? 2 : 0)) : 2713 build_dump(nam, dump, args + 1, OPT_ISSET(ops,'U'), map, flags)); 2714 unqueue_signals(); 2715 2716 return ret; 2717} 2718 2719/* Load the header of a dump file. Returns NULL if the file isn't a 2720 * valid dump file. */ 2721 2722/**/ 2723static Wordcode 2724load_dump_header(char *nam, char *name, int err) 2725{ 2726 int fd, v = 1; 2727 wordcode buf[FD_PRELEN + 1]; 2728 2729 if ((fd = open(name, O_RDONLY)) < 0) { 2730 if (err) 2731 zwarnnam(nam, "can't open zwc file: %s", name); 2732 return NULL; 2733 } 2734 if (read(fd, buf, (FD_PRELEN + 1) * sizeof(wordcode)) != 2735 ((FD_PRELEN + 1) * sizeof(wordcode)) || 2736 (v = (fdmagic(buf) != FD_MAGIC && fdmagic(buf) != FD_OMAGIC)) || 2737 strcmp(fdversion(buf), ZSH_VERSION)) { 2738 if (err) { 2739 if (!v) { 2740 zwarnnam(nam, "zwc file has wrong version (zsh-%s): %s", 2741 fdversion(buf), name); 2742 } else 2743 zwarnnam(nam, "invalid zwc file: %s" , name); 2744 } 2745 close(fd); 2746 return NULL; 2747 } else { 2748 int len; 2749 Wordcode head; 2750 2751 if (fdmagic(buf) == FD_MAGIC) { 2752 len = fdheaderlen(buf) * sizeof(wordcode); 2753 head = (Wordcode) zhalloc(len); 2754 } 2755 else { 2756 int o = fdother(buf); 2757 2758 if (lseek(fd, o, 0) == -1 || 2759 read(fd, buf, (FD_PRELEN + 1) * sizeof(wordcode)) != 2760 ((FD_PRELEN + 1) * sizeof(wordcode))) { 2761 zwarnnam(nam, "invalid zwc file: %s" , name); 2762 close(fd); 2763 return NULL; 2764 } 2765 len = fdheaderlen(buf) * sizeof(wordcode); 2766 head = (Wordcode) zhalloc(len); 2767 } 2768 memcpy(head, buf, (FD_PRELEN + 1) * sizeof(wordcode)); 2769 2770 len -= (FD_PRELEN + 1) * sizeof(wordcode); 2771 if (read(fd, head + (FD_PRELEN + 1), len) != len) { 2772 close(fd); 2773 zwarnnam(nam, "invalid zwc file: %s" , name); 2774 return NULL; 2775 } 2776 close(fd); 2777 return head; 2778 } 2779} 2780 2781/* Swap the bytes in a wordcode. */ 2782 2783static void 2784fdswap(Wordcode p, int n) 2785{ 2786 wordcode c; 2787 2788 for (; n--; p++) { 2789 c = *p; 2790 *p = (((c & 0xff) << 24) | 2791 ((c & 0xff00) << 8) | 2792 ((c & 0xff0000) >> 8) | 2793 ((c & 0xff000000) >> 24)); 2794 } 2795} 2796 2797/* Write a dump file. */ 2798 2799static void 2800write_dump(int dfd, LinkList progs, int map, int hlen, int tlen) 2801{ 2802 LinkNode node; 2803 WCFunc wcf; 2804 int other = 0, ohlen, tmp; 2805 wordcode pre[FD_PRELEN]; 2806 char *tail, *n; 2807 struct fdhead head; 2808 Eprog prog; 2809 2810 if (map == 1) 2811 map = (tlen >= FD_MINMAP); 2812 2813 memset(pre, 0, sizeof(wordcode) * FD_PRELEN); 2814 2815 for (ohlen = hlen; ; hlen = ohlen) { 2816 fdmagic(pre) = (other ? FD_OMAGIC : FD_MAGIC); 2817 fdsetflags(pre, ((map ? FDF_MAP : 0) | other)); 2818 fdsetother(pre, tlen); 2819 strcpy(fdversion(pre), ZSH_VERSION); 2820 write_loop(dfd, (char *)pre, FD_PRELEN * sizeof(wordcode)); 2821 2822 for (node = firstnode(progs); node; incnode(node)) { 2823 wcf = (WCFunc) getdata(node); 2824 n = wcf->name; 2825 prog = wcf->prog; 2826 head.start = hlen; 2827 hlen += (prog->len - (prog->npats * sizeof(Patprog)) + 2828 sizeof(wordcode) - 1) / sizeof(wordcode); 2829 head.len = prog->len - (prog->npats * sizeof(Patprog)); 2830 head.npats = prog->npats; 2831 head.strs = prog->strs - ((char *) prog->prog); 2832 head.hlen = (sizeof(struct fdhead) / sizeof(wordcode)) + 2833 (strlen(n) + sizeof(wordcode)) / sizeof(wordcode); 2834 if ((tail = strrchr(n, '/'))) 2835 tail++; 2836 else 2837 tail = n; 2838 head.flags = fdhbldflags(wcf->flags, (tail - n)); 2839 if (other) 2840 fdswap((Wordcode) &head, sizeof(head) / sizeof(wordcode)); 2841 write_loop(dfd, (char *)&head, sizeof(head)); 2842 tmp = strlen(n) + 1; 2843 write_loop(dfd, n, tmp); 2844 if ((tmp &= (sizeof(wordcode) - 1))) 2845 write_loop(dfd, (char *)&head, sizeof(wordcode) - tmp); 2846 } 2847 for (node = firstnode(progs); node; incnode(node)) { 2848 prog = ((WCFunc) getdata(node))->prog; 2849 tmp = (prog->len - (prog->npats * sizeof(Patprog)) + 2850 sizeof(wordcode) - 1) / sizeof(wordcode); 2851 if (other) 2852 fdswap(prog->prog, (((Wordcode) prog->strs) - prog->prog)); 2853 write_loop(dfd, (char *)prog->prog, tmp * sizeof(wordcode)); 2854 } 2855 if (other) 2856 break; 2857 other = FDF_OTHER; 2858 } 2859} 2860 2861/**/ 2862static int 2863build_dump(char *nam, char *dump, char **files, int ali, int map, int flags) 2864{ 2865 int dfd, fd, hlen, tlen, flen, ona = noaliases; 2866 LinkList progs; 2867 char *file; 2868 Eprog prog; 2869 WCFunc wcf; 2870 2871 if (!strsfx(FD_EXT, dump)) 2872 dump = dyncat(dump, FD_EXT); 2873 2874 unlink(dump); 2875 if ((dfd = open(dump, O_WRONLY|O_CREAT, 0444)) < 0) { 2876 zwarnnam(nam, "can't write zwc file: %s", dump); 2877 return 1; 2878 } 2879 progs = newlinklist(); 2880 noaliases = ali; 2881 2882 for (hlen = FD_PRELEN, tlen = 0; *files; files++) { 2883 if (!strcmp(*files, "-k")) { 2884 flags = (flags & ~(FDHF_KSHLOAD | FDHF_ZSHLOAD)) | FDHF_KSHLOAD; 2885 continue; 2886 } else if (!strcmp(*files, "-z")) { 2887 flags = (flags & ~(FDHF_KSHLOAD | FDHF_ZSHLOAD)) | FDHF_ZSHLOAD; 2888 continue; 2889 } 2890 if ((fd = open(*files, O_RDONLY)) < 0 || 2891 (flen = lseek(fd, 0, 2)) == -1) { 2892 if (fd >= 0) 2893 close(fd); 2894 close(dfd); 2895 zwarnnam(nam, "can't open file: %s", *files); 2896 noaliases = ona; 2897 unlink(dump); 2898 return 1; 2899 } 2900 file = (char *) zalloc(flen + 1); 2901 file[flen] = '\0'; 2902 lseek(fd, 0, 0); 2903 if (read(fd, file, flen) != flen) { 2904 close(fd); 2905 close(dfd); 2906 zfree(file, flen); 2907 zwarnnam(nam, "can't read file: %s", *files); 2908 noaliases = ona; 2909 unlink(dump); 2910 return 1; 2911 } 2912 close(fd); 2913 file = metafy(file, flen, META_REALLOC); 2914 2915 if (!(prog = parse_string(file, 1)) || errflag) { 2916 errflag = 0; 2917 close(dfd); 2918 zfree(file, flen); 2919 zwarnnam(nam, "can't read file: %s", *files); 2920 noaliases = ona; 2921 unlink(dump); 2922 return 1; 2923 } 2924 zfree(file, flen); 2925 2926 wcf = (WCFunc) zhalloc(sizeof(*wcf)); 2927 wcf->name = *files; 2928 wcf->prog = prog; 2929 wcf->flags = ((prog->flags & EF_RUN) ? FDHF_KSHLOAD : flags); 2930 addlinknode(progs, wcf); 2931 2932 flen = (strlen(*files) + sizeof(wordcode)) / sizeof(wordcode); 2933 hlen += (sizeof(struct fdhead) / sizeof(wordcode)) + flen; 2934 2935 tlen += (prog->len - (prog->npats * sizeof(Patprog)) + 2936 sizeof(wordcode) - 1) / sizeof(wordcode); 2937 } 2938 noaliases = ona; 2939 2940 tlen = (tlen + hlen) * sizeof(wordcode); 2941 2942 write_dump(dfd, progs, map, hlen, tlen); 2943 2944 close(dfd); 2945 2946 return 0; 2947} 2948 2949static int 2950cur_add_func(char *nam, Shfunc shf, LinkList names, LinkList progs, 2951 int *hlen, int *tlen, int what) 2952{ 2953 Eprog prog; 2954 WCFunc wcf; 2955 2956 if (shf->node.flags & PM_UNDEFINED) { 2957 int ona = noaliases; 2958 2959 if (!(what & 2)) { 2960 zwarnnam(nam, "function is not loaded: %s", shf->node.nam); 2961 return 1; 2962 } 2963 noaliases = (shf->node.flags & PM_UNALIASED); 2964 if (!(prog = getfpfunc(shf->node.nam, NULL, NULL)) || 2965 prog == &dummy_eprog) { 2966 noaliases = ona; 2967 zwarnnam(nam, "can't load function: %s", shf->node.nam); 2968 return 1; 2969 } 2970 if (prog->dump) 2971 prog = dupeprog(prog, 1); 2972 noaliases = ona; 2973 } else { 2974 if (!(what & 1)) { 2975 zwarnnam(nam, "function is already loaded: %s", shf->node.nam); 2976 return 1; 2977 } 2978 prog = dupeprog(shf->funcdef, 1); 2979 } 2980 wcf = (WCFunc) zhalloc(sizeof(*wcf)); 2981 wcf->name = shf->node.nam; 2982 wcf->prog = prog; 2983 wcf->flags = ((prog->flags & EF_RUN) ? FDHF_KSHLOAD : FDHF_ZSHLOAD); 2984 addlinknode(progs, wcf); 2985 addlinknode(names, shf->node.nam); 2986 2987 *hlen += ((sizeof(struct fdhead) / sizeof(wordcode)) + 2988 ((strlen(shf->node.nam) + sizeof(wordcode)) / sizeof(wordcode))); 2989 *tlen += (prog->len - (prog->npats * sizeof(Patprog)) + 2990 sizeof(wordcode) - 1) / sizeof(wordcode); 2991 2992 return 0; 2993} 2994 2995/**/ 2996static int 2997build_cur_dump(char *nam, char *dump, char **names, int match, int map, 2998 int what) 2999{ 3000 int dfd, hlen, tlen; 3001 LinkList progs, lnames; 3002 Shfunc shf = NULL; 3003 3004 if (!strsfx(FD_EXT, dump)) 3005 dump = dyncat(dump, FD_EXT); 3006 3007 unlink(dump); 3008 if ((dfd = open(dump, O_WRONLY|O_CREAT, 0444)) < 0) { 3009 zwarnnam(nam, "can't write zwc file: %s", dump); 3010 return 1; 3011 } 3012 progs = newlinklist(); 3013 lnames = newlinklist(); 3014 3015 hlen = FD_PRELEN; 3016 tlen = 0; 3017 3018 if (!*names) { 3019 int i; 3020 HashNode hn; 3021 3022 for (i = 0; i < shfunctab->hsize; i++) 3023 for (hn = shfunctab->nodes[i]; hn; hn = hn->next) 3024 if (cur_add_func(nam, (Shfunc) hn, lnames, progs, 3025 &hlen, &tlen, what)) { 3026 errflag = 0; 3027 close(dfd); 3028 unlink(dump); 3029 return 1; 3030 } 3031 } else if (match) { 3032 char *pat; 3033 Patprog pprog; 3034 int i; 3035 HashNode hn; 3036 3037 for (; *names; names++) { 3038 tokenize(pat = dupstring(*names)); 3039 if (!(pprog = patcompile(pat, PAT_STATIC, NULL))) { 3040 zwarnnam(nam, "bad pattern: %s", *names); 3041 close(dfd); 3042 unlink(dump); 3043 return 1; 3044 } 3045 for (i = 0; i < shfunctab->hsize; i++) 3046 for (hn = shfunctab->nodes[i]; hn; hn = hn->next) 3047 if (!linknodebydatum(lnames, hn->nam) && 3048 pattry(pprog, hn->nam) && 3049 cur_add_func(nam, (Shfunc) hn, lnames, progs, 3050 &hlen, &tlen, what)) { 3051 errflag = 0; 3052 close(dfd); 3053 unlink(dump); 3054 return 1; 3055 } 3056 } 3057 } else { 3058 for (; *names; names++) { 3059 if (errflag || 3060 !(shf = (Shfunc) shfunctab->getnode(shfunctab, *names))) { 3061 zwarnnam(nam, "unknown function: %s", *names); 3062 errflag = 0; 3063 close(dfd); 3064 unlink(dump); 3065 return 1; 3066 } 3067 if (cur_add_func(nam, shf, lnames, progs, &hlen, &tlen, what)) { 3068 errflag = 0; 3069 close(dfd); 3070 unlink(dump); 3071 return 1; 3072 } 3073 } 3074 } 3075 if (empty(progs)) { 3076 zwarnnam(nam, "no functions"); 3077 errflag = 0; 3078 close(dfd); 3079 unlink(dump); 3080 return 1; 3081 } 3082 tlen = (tlen + hlen) * sizeof(wordcode); 3083 3084 write_dump(dfd, progs, map, hlen, tlen); 3085 3086 close(dfd); 3087 3088 return 0; 3089} 3090 3091/**/ 3092#if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MMAP) && defined(HAVE_MUNMAP) 3093 3094#include <sys/mman.h> 3095 3096/**/ 3097#if defined(MAP_SHARED) && defined(PROT_READ) 3098 3099/**/ 3100#define USE_MMAP 1 3101 3102/**/ 3103#endif 3104/**/ 3105#endif 3106 3107/**/ 3108#ifdef USE_MMAP 3109 3110/* List of dump files mapped. */ 3111 3112static FuncDump dumps; 3113 3114/**/ 3115static int 3116zwcstat(char *filename, struct stat *buf) 3117{ 3118 if (stat(filename, buf)) { 3119#ifdef HAVE_FSTAT 3120 FuncDump f; 3121 3122 for (f = dumps; f; f = f->next) { 3123 if (!strncmp(filename, f->filename, strlen(f->filename)) && 3124 !fstat(f->fd, buf)) 3125 return 0; 3126 } 3127#endif 3128 return 1; 3129 } else return 0; 3130} 3131 3132/* Load a dump file (i.e. map it). */ 3133 3134static void 3135load_dump_file(char *dump, struct stat *sbuf, int other, int len) 3136{ 3137 FuncDump d; 3138 Wordcode addr; 3139 int fd, off, mlen; 3140 3141 if (other) { 3142 static size_t pgsz = 0; 3143 3144 if (!pgsz) { 3145 3146#ifdef _SC_PAGESIZE 3147 pgsz = sysconf(_SC_PAGESIZE); /* SVR4 */ 3148#else 3149# ifdef _SC_PAGE_SIZE 3150 pgsz = sysconf(_SC_PAGE_SIZE); /* HPUX */ 3151# else 3152 pgsz = getpagesize(); 3153# endif 3154#endif 3155 3156 pgsz--; 3157 } 3158 off = len & ~pgsz; 3159 mlen = len + (len - off); 3160 } else { 3161 off = 0; 3162 mlen = len; 3163 } 3164 if ((fd = open(dump, O_RDONLY)) < 0) 3165 return; 3166 3167 fd = movefd(fd); 3168 if (fd == -1) 3169 return; 3170 3171 if ((addr = (Wordcode) mmap(NULL, mlen, PROT_READ, MAP_SHARED, fd, off)) == 3172 ((Wordcode) -1)) { 3173 close(fd); 3174 return; 3175 } 3176 d = (FuncDump) zalloc(sizeof(*d)); 3177 d->next = dumps; 3178 dumps = d; 3179 d->dev = sbuf->st_dev; 3180 d->ino = sbuf->st_ino; 3181 d->fd = fd; 3182#ifdef FD_CLOEXEC 3183 fcntl(fd, F_SETFD, FD_CLOEXEC); 3184#endif 3185 d->map = addr + (other ? (len - off) / sizeof(wordcode) : 0); 3186 d->addr = addr; 3187 d->len = len; 3188 d->count = 0; 3189 d->filename = ztrdup(dump); 3190} 3191 3192#else 3193 3194#define zwcstat(f, b) (!!stat(f, b)) 3195 3196/**/ 3197#endif 3198 3199/* Try to load a function from one of the possible wordcode files for it. 3200 * The first argument is a element of $fpath, the second one is the name 3201 * of the function searched and the last one is the possible name for the 3202 * uncompiled function file (<path>/<func>). */ 3203 3204/**/ 3205Eprog 3206try_dump_file(char *path, char *name, char *file, int *ksh) 3207{ 3208 Eprog prog; 3209 struct stat std, stc, stn; 3210 int rd, rc, rn; 3211 char *dig, *wc; 3212 3213 if (strsfx(FD_EXT, path)) { 3214 queue_signals(); 3215 prog = check_dump_file(path, NULL, name, ksh); 3216 unqueue_signals(); 3217 return prog; 3218 } 3219 dig = dyncat(path, FD_EXT); 3220 wc = dyncat(file, FD_EXT); 3221 3222 rd = zwcstat(dig, &std); 3223 rc = stat(wc, &stc); 3224 rn = stat(file, &stn); 3225 3226 /* See if there is a digest file for the directory, it is younger than 3227 * both the uncompiled function file and its compiled version (or they 3228 * don't exist) and the digest file contains the definition for the 3229 * function. */ 3230 queue_signals(); 3231 if (!rd && 3232 (rc || std.st_mtime > stc.st_mtime) && 3233 (rn || std.st_mtime > stn.st_mtime) && 3234 (prog = check_dump_file(dig, &std, name, ksh))) { 3235 unqueue_signals(); 3236 return prog; 3237 } 3238 /* No digest file. Now look for the per-function compiled file. */ 3239 if (!rc && 3240 (rn || stc.st_mtime > stn.st_mtime) && 3241 (prog = check_dump_file(wc, &stc, name, ksh))) { 3242 unqueue_signals(); 3243 return prog; 3244 } 3245 /* No compiled file for the function. The caller (getfpfunc() will 3246 * check if the directory contains the uncompiled file for it. */ 3247 unqueue_signals(); 3248 return NULL; 3249} 3250 3251/* Almost the same, but for sourced files. */ 3252 3253/**/ 3254Eprog 3255try_source_file(char *file) 3256{ 3257 Eprog prog; 3258 struct stat stc, stn; 3259 int rc, rn; 3260 char *wc, *tail; 3261 3262 if ((tail = strrchr(file, '/'))) 3263 tail++; 3264 else 3265 tail = file; 3266 3267 if (strsfx(FD_EXT, file)) { 3268 queue_signals(); 3269 prog = check_dump_file(file, NULL, tail, NULL); 3270 unqueue_signals(); 3271 return prog; 3272 } 3273 wc = dyncat(file, FD_EXT); 3274 3275 rc = stat(wc, &stc); 3276 rn = stat(file, &stn); 3277 3278 queue_signals(); 3279 if (!rc && (rn || stc.st_mtime > stn.st_mtime) && 3280 (prog = check_dump_file(wc, &stc, tail, NULL))) { 3281 unqueue_signals(); 3282 return prog; 3283 } 3284 unqueue_signals(); 3285 return NULL; 3286} 3287 3288/* See if `file' names a wordcode dump file and that contains the 3289 * definition for the function `name'. If so, return an eprog for it. */ 3290 3291/**/ 3292static Eprog 3293check_dump_file(char *file, struct stat *sbuf, char *name, int *ksh) 3294{ 3295 int isrec = 0; 3296 Wordcode d; 3297 FDHead h; 3298 FuncDump f; 3299 struct stat lsbuf; 3300 3301 if (!sbuf) { 3302 if (zwcstat(file, &lsbuf)) 3303 return NULL; 3304 sbuf = &lsbuf; 3305 } 3306 3307#ifdef USE_MMAP 3308 3309 rec: 3310 3311#endif 3312 3313 d = NULL; 3314 3315#ifdef USE_MMAP 3316 3317 for (f = dumps; f; f = f->next) 3318 if (f->dev == sbuf->st_dev && f->ino == sbuf->st_ino) { 3319 d = f->map; 3320 break; 3321 } 3322 3323#else 3324 3325 f = NULL; 3326 3327#endif 3328 3329 if (!f && (isrec || !(d = load_dump_header(NULL, file, 0)))) 3330 return NULL; 3331 3332 if ((h = dump_find_func(d, name))) { 3333 /* Found the name. If the file is already mapped, return the eprog, 3334 * otherwise map it and just go up. */ 3335 3336#ifdef USE_MMAP 3337 3338 if (f) { 3339 Eprog prog = (Eprog) zalloc(sizeof(*prog)); 3340 Patprog *pp; 3341 int np; 3342 3343 prog->flags = EF_MAP; 3344 prog->len = h->len; 3345 prog->npats = np = h->npats; 3346 prog->nref = 1; /* allocated from permanent storage */ 3347 prog->pats = pp = (Patprog *) zalloc(np * sizeof(Patprog)); 3348 prog->prog = f->map + h->start; 3349 prog->strs = ((char *) prog->prog) + h->strs; 3350 prog->shf = NULL; 3351 prog->dump = f; 3352 3353 incrdumpcount(f); 3354 3355 while (np--) 3356 *pp++ = dummy_patprog1; 3357 3358 if (ksh) 3359 *ksh = ((fdhflags(h) & FDHF_KSHLOAD) ? 2 : 3360 ((fdhflags(h) & FDHF_ZSHLOAD) ? 0 : 1)); 3361 3362 return prog; 3363 } else if (fdflags(d) & FDF_MAP) { 3364 load_dump_file(file, sbuf, (fdflags(d) & FDF_OTHER), fdother(d)); 3365 isrec = 1; 3366 goto rec; 3367 } else 3368 3369#endif 3370 3371 { 3372 Eprog prog; 3373 Patprog *pp; 3374 int np, fd, po = h->npats * sizeof(Patprog); 3375 3376 if ((fd = open(file, O_RDONLY)) < 0 || 3377 lseek(fd, ((h->start * sizeof(wordcode)) + 3378 ((fdflags(d) & FDF_OTHER) ? fdother(d) : 0)), 0) < 0) { 3379 if (fd >= 0) 3380 close(fd); 3381 return NULL; 3382 } 3383 d = (Wordcode) zalloc(h->len + po); 3384 3385 if (read(fd, ((char *) d) + po, h->len) != (int)h->len) { 3386 close(fd); 3387 zfree(d, h->len); 3388 3389 return NULL; 3390 } 3391 close(fd); 3392 3393 prog = (Eprog) zalloc(sizeof(*prog)); 3394 3395 prog->flags = EF_REAL; 3396 prog->len = h->len + po; 3397 prog->npats = np = h->npats; 3398 prog->nref = 1; /* allocated from permanent storage */ 3399 prog->pats = pp = (Patprog *) d; 3400 prog->prog = (Wordcode) (((char *) d) + po); 3401 prog->strs = ((char *) prog->prog) + h->strs; 3402 prog->shf = NULL; 3403 prog->dump = f; 3404 3405 while (np--) 3406 *pp++ = dummy_patprog1; 3407 3408 if (ksh) 3409 *ksh = ((fdhflags(h) & FDHF_KSHLOAD) ? 2 : 3410 ((fdhflags(h) & FDHF_ZSHLOAD) ? 0 : 1)); 3411 3412 return prog; 3413 } 3414 } 3415 return NULL; 3416} 3417 3418#ifdef USE_MMAP 3419 3420/* Increment the reference counter for a dump file. */ 3421 3422/**/ 3423void 3424incrdumpcount(FuncDump f) 3425{ 3426 f->count++; 3427} 3428 3429/**/ 3430static void 3431freedump(FuncDump f) 3432{ 3433 munmap((void *) f->addr, f->len); 3434 zclose(f->fd); 3435 zsfree(f->filename); 3436 zfree(f, sizeof(*f)); 3437} 3438 3439/* Decrement the reference counter for a dump file. If zero, unmap the file. */ 3440 3441/**/ 3442void 3443decrdumpcount(FuncDump f) 3444{ 3445 f->count--; 3446 if (!f->count) { 3447 FuncDump p, q; 3448 3449 for (q = NULL, p = dumps; p && p != f; q = p, p = p->next); 3450 if (p) { 3451 if (q) 3452 q->next = p->next; 3453 else 3454 dumps = p->next; 3455 freedump(f); 3456 } 3457 } 3458} 3459 3460#ifndef FD_CLOEXEC 3461/**/ 3462mod_export void 3463closedumps(void) 3464{ 3465 while (dumps) { 3466 FuncDump p = dumps->next; 3467 freedump(dumps); 3468 dumps = p; 3469 } 3470} 3471#endif 3472 3473#else 3474 3475void 3476incrdumpcount(FuncDump f) 3477{ 3478} 3479 3480void 3481decrdumpcount(FuncDump f) 3482{ 3483} 3484 3485#ifndef FD_CLOEXEC 3486/**/ 3487mod_export void 3488closedumps(void) 3489{ 3490} 3491#endif 3492 3493#endif 3494 3495/**/ 3496int 3497dump_autoload(char *nam, char *file, int on, Options ops, int func) 3498{ 3499 Wordcode h; 3500 FDHead n, e; 3501 Shfunc shf; 3502 int ret = 0; 3503 3504 if (!strsfx(FD_EXT, file)) 3505 file = dyncat(file, FD_EXT); 3506 3507 if (!(h = load_dump_header(nam, file, 1))) 3508 return 1; 3509 3510 for (n = firstfdhead(h), e = (FDHead) (h + fdheaderlen(h)); n < e; 3511 n = nextfdhead(n)) { 3512 shf = (Shfunc) zshcalloc(sizeof *shf); 3513 shf->node.flags = on; 3514 shf->funcdef = mkautofn(shf); 3515 shf->sticky = NULL; 3516 shfunctab->addnode(shfunctab, ztrdup(fdname(n) + fdhtail(n)), shf); 3517 if (OPT_ISSET(ops,'X') && eval_autoload(shf, shf->node.nam, ops, func)) 3518 ret = 1; 3519 } 3520 return ret; 3521} 3522 3523