|
|
1.1 ! root 1: /* ! 2: * sh/exec3.c ! 3: * Bourne shell. ! 4: * Builtin commands and shell functions. ! 5: */ ! 6: ! 7: #include "sh.h" ! 8: #include <sys/times.h> ! 9: #include <sys/const.h> /* HZ defined here */ ! 10: ! 11: #define HOUR (60L*60L*HZ) ! 12: #define MINUTE (60L*HZ) ! 13: #define SECOND HZ ! 14: ! 15: NODE *copy_node(); ! 16: char *cd(); ! 17: ! 18: extern s_colon(); ! 19: extern s_dot(); ! 20: extern s_break(); ! 21: #define s_continue s_break ! 22: extern s_cd(); ! 23: extern s_dirs(); ! 24: extern s_eval(); ! 25: extern s_exec(); ! 26: extern s_exit(); ! 27: extern s_export(); ! 28: extern s_login(); ! 29: #define s_newgrp s_login ! 30: extern s_popd(); ! 31: extern s_pushd(); ! 32: extern s_read(); ! 33: #define s_readonly s_export ! 34: extern s_set(); ! 35: extern s_shift(); ! 36: extern s_times(); ! 37: extern s_trap(); ! 38: extern s_umask(); ! 39: extern s_wait(); ! 40: #define SNULL ((int (*)())0) ! 41: ! 42: /* Built-in functions. */ ! 43: typedef struct { ! 44: int i_hash; ! 45: char *i_name; ! 46: int (*i_func)(); ! 47: } INLINE; ! 48: ! 49: INLINE inls[] = { ! 50: 0, ":", s_colon, ! 51: 0, ".", s_dot, ! 52: 0, "break", s_break, ! 53: 0, "continue", s_continue, ! 54: 0, "cd", s_cd, ! 55: 0, "dirs", s_dirs, ! 56: 0, "eval", s_eval, ! 57: 0, "exec", s_exec, ! 58: 0, "exit", s_exit, ! 59: 0, "export", s_export, ! 60: 0, "login", s_login, ! 61: 0, "newgrp", s_newgrp, ! 62: 0, "popd", s_popd, ! 63: 0, "pushd", s_pushd, ! 64: 0, "read", s_read, ! 65: 0, "readonly", s_readonly, ! 66: 0, "set", s_set, ! 67: 0, "shift", s_shift, ! 68: 0, "times", s_times, ! 69: 0, "trap", s_trap, ! 70: 0, "umask", s_umask, ! 71: 0, "wait", s_wait, ! 72: 0, NULL, SNULL ! 73: }; ! 74: ! 75: inline() ! 76: { ! 77: register int (*s_func)(); ! 78: register INLINE *ip; ! 79: register int ahash; ! 80: ! 81: if (inls[0].i_hash==0) ! 82: for (ip=inls; ip->i_name!=NULL; ip++) ! 83: ip->i_hash = ihash(ip->i_name); ! 84: if (nargv[0] == NULL) ! 85: return 0; ! 86: ahash = ihash(nargv[0]); ! 87: for (ip=inls; ip->i_name!=NULL; ip++) ! 88: if (ip->i_hash==ahash && strcmp(nargv[0], ip->i_name)==0) ! 89: break; ! 90: if ((s_func=ip->i_func) == SNULL) ! 91: return 0; ! 92: /* ! 93: * Process exec specially, because it has unique semantics for ! 94: * redirection (among other things). Redirection of builtins is done ! 95: * using the "undo" facility because builtins must execute in the ! 96: * top-level environment. The original code here permitted a small ! 97: * subset of builtins to be redirected, but executed them in a ! 98: * subshell, giving bogus semantics (eg, it permitted "export" to be ! 99: * redirected, but in a subshell it had no effect). ! 100: */ ! 101: if (s_func == s_exec) ! 102: slret = (* s_func) (); ! 103: else { ! 104: REDIR_UNDO * undo = NULL; ! 105: ! 106: if (redirect (niovp, & undo) < 0) ! 107: slret = 1; ! 108: else ! 109: slret = (* s_func) (); ! 110: ! 111: /* ! 112: * NB: The rationale for the following kludge is not clear, ! 113: * but with the ability to properly redirect builtins and ! 114: * execute the in the top-level context, it no longer works. ! 115: * It could be added back in, but since it conflicts with ! 116: * POSIX.2 anyway, why bother. ! 117: */ ! 118: #if 0 ! 119: if (s_func == s_eval) ! 120: slret = (*s_func)(); ! 121: else { ! 122: /* Kludge stderr output to stdout. */ ! 123: dup2(1, 2); ! 124: close(1); ! 125: slret = (*s_func)(); ! 126: } ! 127: #endif ! 128: ! 129: redirundo (& undo); ! 130: } ! 131: return 1; ! 132: } ! 133: ! 134: ihash(cp) ! 135: register char *cp; ! 136: { ! 137: register int i; ! 138: for (i=0; *cp; i+=*cp++); ! 139: return i; ! 140: } ! 141: ! 142: ! 143: /* ! 144: * Actual builtin functions. ! 145: */ ! 146: s_colon() ! 147: { ! 148: return 0; ! 149: } ! 150: ! 151: s_dot() ! 152: { ! 153: if (nargc==2) { ! 154: ffind(NULL); ! 155: if (ffind(vpath, nargv[1], 4)) ! 156: return session(SFILE, duplstr(strt, 0)); ! 157: else { ! 158: ecantfind(nargv[1]); ! 159: return 1; ! 160: } ! 161: } else if (nargc==1) ! 162: return 0; ! 163: syntax(); ! 164: return 1; ! 165: } ! 166: ! 167: s_break() ! 168: { ! 169: register CON *cp; ! 170: register int t; ! 171: register int n; ! 172: int ret; ! 173: ! 174: ret = nargv[0][0]=='b' ? 2 : 1; ! 175: n = nargc>1 ? atoi(nargv[1]) : 1; ! 176: for (cp = sesp->s_con; cp; cp = cp->c_next) { ! 177: t = cp->c_node->n_type; ! 178: if ((t==NWHILE || t==NFOR || t==NUNTIL) && --n == 0) { ! 179: sesp->s_con = cp; ! 180: longjmp(cp->c_envl, ret); ! 181: break; ! 182: } ! 183: freebuf(cp->c_bpp); ! 184: } ! 185: printe("%s out of bounds", ret==1 ? "Continue" : "Break"); ! 186: } ! 187: ! 188: /* s_continue is overlaid with s_break */ ! 189: ! 190: s_cd() ! 191: { ! 192: register char *dir; ! 193: ! 194: if ((dir = cd((nargc<2) ? vhome : nargv[1])) == NULL) ! 195: return -1; /* cd failed */ ! 196: if (dstack[dstkp] != NULL) ! 197: sfree(dstack[dstkp]); ! 198: dstack[dstkp] = duplstr(dir, 1); /* update dir stack */ ! 199: return 0; ! 200: } ! 201: ! 202: s_dirs() ! 203: { ! 204: register int i; ! 205: ! 206: for (i = dstkp; i >= 0; i--) ! 207: printf (stdout, "%s ", dstack[i]); ! 208: fputc('\n', stderr); ! 209: } ! 210: ! 211: s_eval() ! 212: { ! 213: if (nargc>1) ! 214: return session(SARGV, ++nargv); ! 215: else ! 216: return 0; ! 217: } ! 218: ! 219: s_exec() ! 220: { ! 221: if (redirect (niovp, NULL) < 0) { ! 222: if (nargc>1) { ! 223: exit(1); ! 224: NOTREACHED; ! 225: } ! 226: return 1; ! 227: } ! 228: if (nargc==1) ! 229: return 0; ! 230: if (no1flag) { ! 231: cleanup_shell_fns (); ! 232: unlink_temp (capture_temp ()); ! 233: } ! 234: dflttrp(ICMD); ! 235: ++nargv; ! 236: --nargc; ! 237: nenvp = envlvar(nenvp); ! 238: flexec(); ! 239: exit(1); ! 240: NOTREACHED; ! 241: } ! 242: ! 243: s_exit() ! 244: { ! 245: if (nargc > 1) ! 246: slret = atoi(nargv[1]); ! 247: reset(RUEXITS); ! 248: NOTREACHED; ! 249: } ! 250: ! 251: s_export() ! 252: { ! 253: register int flag; ! 254: register char **varv; ! 255: ! 256: flag = nargv[0][0]=='e' ? VEXP : VRDO; ! 257: if (nargc < 2) ! 258: tellvar(flag); ! 259: else ! 260: for (varv=++nargv; *varv; ) ! 261: if (namevar(*varv)) ! 262: flagvar(*varv++, flag); ! 263: else ! 264: eillvar(*varv++); ! 265: return 0; ! 266: } ! 267: ! 268: s_login() ! 269: { ! 270: register char *cmd; ! 271: ! 272: cmd = nargv[0][0]=='l' ? "/bin/login" : "/bin/newgrp"; ! 273: execve(cmd, nargv, envlvar(nenvp)); ! 274: ecantfind(cmd); ! 275: return 1; ! 276: } ! 277: ! 278: /* s_newgrp is overlaid with s_login */ ! 279: ! 280: s_popd() ! 281: { ! 282: register int i, j, n, ret; ! 283: ! 284: if (nargc == 1) ! 285: return popd(); ! 286: /* ! 287: * Kludge to pop one or more specific dir stack elements. ! 288: * Do args backwards so e.g. "popd 2 3 4" works as expected. ! 289: * Internal indices [0, dstkp] are user indices [dstkp, 0]. ! 290: */ ! 291: for (ret = 0, i = nargc-1; i > 0; i--) { ! 292: if ((n = atoi(nargv[i])) == 0) ! 293: ret |= popd(); ! 294: else if (n < 0 || n > dstkp) { ! 295: printe("Illegal arg: %d", n); ! 296: ret = -1; ! 297: continue; ! 298: } else { ! 299: j = dstkp - n; ! 300: if (dstack[j] != NULL) ! 301: sfree(dstack[j]); ! 302: for ( ; j < dstkp; j++) ! 303: dstack[j] = dstack[j+1]; ! 304: --dstkp; ! 305: } ! 306: } ! 307: return ret; ! 308: } ! 309: ! 310: s_pushd() ! 311: { ! 312: register char *dir; ! 313: register int i, ret; ! 314: ! 315: if (nargc == 1) { ! 316: /* Exchange top two stack elements. */ ! 317: if (dstkp == 0) ! 318: return 1; /* only one element on stack */ ! 319: dir = dstack[dstkp-1]; ! 320: dstack[dstkp-1] = dstack[dstkp]; ! 321: dstack[dstkp] = dir; /* exchange top two */ ! 322: return ((cd(dir) == NULL) ? -1 : 0); /* and cd accordingly */ ! 323: } ! 324: /* Push one or more directories to stack. */ ! 325: for (ret = 0, i = 1; i < nargc; i++) ! 326: ret |= pushd(nargv[i]); ! 327: return ret; ! 328: } ! 329: ! 330: /* ! 331: * NB: For s_read (), wrap up the temporary-space global bullshit. Later we ! 332: * can add parameters to this stuff to get the effect of string streams. ! 333: */ ! 334: ! 335: #define temp_string_begin() ((void) (strp = strt)) ! 336: #define temp_string_max() STRSIZE ! 337: #define temp_string_add(c) \ ! 338: (strp < strt + temp_string_max () ? (void) (* strp ++ = c) : \ ! 339: (void) etoolong ()) ! 340: #define temp_string_end() (strt) ! 341: #define temp_string_end_copy() (duplstr (temp_string_end (), 1)) ! 342: #define temp_string_temp_copy() (duplstr (temp_string_end (), 0)) ! 343: #define temp_mark() (0) ! 344: #define temp_release(x) ((void) x) ! 345: ! 346: typedef int temp_mark_type; ! 347: ! 348: #define ARGS(x) x ! 349: void temp_string_begin ARGS (()) { ! 350: temp_string_begin (); ! 351: } ! 352: int temp_string_max ARGS (()) { ! 353: return temp_string_max (); ! 354: } ! 355: void temp_string_add ARGS ((c)) int c; { ! 356: temp_string_add (c); ! 357: } ! 358: char * temp_string_end ARGS (()) { ! 359: return temp_string_end (); ! 360: } ! 361: char * temp_string_end_copy ARGS (()) { ! 362: return temp_string_end_copy (); ! 363: } ! 364: char * temp_string_temp_copy ARGS (()) { ! 365: return temp_string_temp_copy (); ! 366: } ! 367: temp_mark_type temp_mark ARGS (()) { ! 368: return temp_mark (); ! 369: } ! 370: void temp_release ARGS ((m)) temp_mark_type m; { ! 371: temp_release (m); ! 372: } ! 373: ! 374: /* ! 375: * NB: Originally, this code used yylex () to break the input up into words. ! 376: * This was a bad idea, because this caused the IFS variable to have no ! 377: * useful effect. Now we just read using <stdio.h> functions, because the ! 378: * extra machinery for session-management doesn't seem to buy anything. ! 379: */ ! 380: ! 381: s_read() ! 382: { ! 383: char ** argp = nargv + 1; ! 384: char ** arg_end = argp + (nargc - 1); ! 385: char * delimiters; ! 386: int ch; ! 387: ! 388: while (argp < arg_end) ! 389: if (! namevar (* argp ++)) ! 390: eillvar (argp - 1); ! 391: ! 392: delimiters = vifs == NULL ? " \t" : vifs; ! 393: ! 394: argp = nargv + 1; ! 395: while (argp < arg_end) { ! 396: temp_mark_type mark; ! 397: enum { ! 398: EAT_WS, ! 399: WORD ! 400: } state = EAT_WS; ! 401: ! 402: mark = temp_mark (); ! 403: temp_string_begin (); ! 404: ! 405: if (argp + 1 == arg_end) ! 406: delimiters = ""; ! 407: ! 408: while ((ch = getc (stdin)) != EOF && ch != '\n') { ! 409: ! 410: if (strchr (delimiters, ch) != NULL) { ! 411: ! 412: if (state == EAT_WS) ! 413: continue; ! 414: break; ! 415: } ! 416: ! 417: temp_string_add (ch); ! 418: state = WORD; ! 419: } ! 420: temp_string_add (0); ! 421: ! 422: assnvar (* argp ++, temp_string_temp_copy ()); ! 423: temp_release (mark); ! 424: ! 425: if (ch == EOF || ch == '\n') ! 426: break; ! 427: } ! 428: ! 429: while (argp < arg_end) ! 430: assnvar (* argp ++, ""); ! 431: ! 432: return ch == EOF; ! 433: } ! 434: ! 435: ! 436: /* s_readonly overlaid with s_export */ ! 437: ! 438: s_set() ! 439: { ! 440: if (nargc < 2) { ! 441: tellvar(0); ! 442: return 0; ! 443: } ! 444: return set(nargc, nargv, 0); ! 445: } ! 446: ! 447: s_shift() ! 448: { ! 449: register int n; ! 450: ! 451: n = nargc > 1 ? atoi(nargv[1]) : 1; ! 452: while (n > 0 && sargc > 0) { ! 453: n -= 1; ! 454: sargc -= 1; ! 455: sargp += 1; ! 456: } ! 457: return n!=0; ! 458: } ! 459: ! 460: s_times() ! 461: { ! 462: #if _I386 ! 463: #define tb_cutime tms_cutime ! 464: #define tb_cstime tms_cstime ! 465: struct tms tb; ! 466: #else ! 467: struct tbuffer tb; ! 468: ! 469: #endif ! 470: ! 471: times(&tb); ! 472: ptime(tb.tb_cutime); ! 473: ptime(tb.tb_cstime); ! 474: puts ("\n"); ! 475: return 0; ! 476: } ! 477: ! 478: s_trap() ! 479: { ! 480: register char **vp; ! 481: register char *cp; ! 482: register int err; ! 483: ! 484: err = 0; ! 485: if (nargc==1) ! 486: return telltrp(); ! 487: vp = ++nargv; ! 488: cp = *vp; ! 489: if (class(cp[0], MDIGI) ! 490: && (cp[1]=='\0' || (class(cp[1], MDIGI) && cp[2]=='\0'))) ! 491: cp = NULL; ! 492: else ! 493: ++vp; ! 494: while (*vp) { ! 495: if (class(vp[0][0], MDIGI)) ! 496: err |= setstrp(atoi(*vp++), cp); ! 497: else { ! 498: printe("Bad trap: %s", *vp++); ! 499: err |= 1; ! 500: } ! 501: } ! 502: return err; ! 503: } ! 504: ! 505: s_umask() ! 506: { ! 507: if (nargc < 2) ! 508: printf ("%03o\n", ufmask); ! 509: else ! 510: umask(ufmask = atoi(nargv[1])); ! 511: return 0; ! 512: } ! 513: ! 514: s_wait() ! 515: { ! 516: register int f; ! 517: ! 518: f = (nargc > 1) ? atoi(nargv[1]) : 0; ! 519: if (f > 0) ! 520: f = -f; ! 521: waitc(f); ! 522: return slret; ! 523: } ! 524: ! 525: /* ! 526: * Change to given directory. ! 527: * Update global variable CWD accordingly. ! 528: * Return NULL if bad, otherwise full pathname of the directory. ! 529: */ ! 530: char * ! 531: cd(dir) register char *dir; ! 532: { ! 533: if (chdir(dir) < 0) { ! 534: printe("%s: bad directory", dir); ! 535: return NULL; ! 536: } ! 537: if (*dir != '/') { ! 538: /* ! 539: * Find an absolute pathname for the dstack and $CWD. ! 540: * The directory now in dstack[dstkp] is "." if _getwd() failed ! 541: * for any reason (e.g., the user lacks search permission ! 542: * down the path to "/", or "." was rm'ed by another process). ! 543: * Avoid _getwd() in this case, it can undo the chdir() above. ! 544: */ ! 545: if ((strcmp(dstack[dstkp], ".") == 0) ! 546: || ((dir = _getwd()) == NULL)) ! 547: return NULL; ! 548: } ! 549: assnvar("CWD", dir); ! 550: return dir; ! 551: } ! 552: ! 553: /* ! 554: * Pop the directory stack and change to the previous stacked directory. ! 555: */ ! 556: popd() ! 557: { ! 558: if (dstkp == 0) { ! 559: printe("Directory stack underflow"); ! 560: return -1; ! 561: } ! 562: if (dstack[dstkp] != NULL) ! 563: sfree(dstack[dstkp]); ! 564: return (cd(dstack[--dstkp]) == NULL ? -1 : 0); ! 565: } ! 566: ! 567: /* ! 568: * Change to given directory and add it to the directory stack. ! 569: */ ! 570: pushd(dir) register char *dir; ! 571: { ! 572: if ((dir = cd(dir)) == NULL) ! 573: return -1; /* cd failed */ ! 574: if (++dstkp >= DSTACKN) { ! 575: --dstkp; ! 576: printe("Directory stack overflow"); ! 577: return -1; ! 578: } ! 579: dstack[dstkp] = duplstr(dir, 1); ! 580: return 0; ! 581: } ! 582: ! 583: /* ! 584: * The set command. This is also called from `main' to set ! 585: * options from the command line. In this case `flag' is ! 586: * set. ! 587: */ ! 588: set(argc, argv, flag) ! 589: register char *argv[]; ! 590: { ! 591: int n; ! 592: register char *cp; ! 593: ! 594: if (flag) { ! 595: cflag = 0; ! 596: iflag = 0; ! 597: sflag = 0; ! 598: } ! 599: n = 0; ! 600: if (argc > 0) ! 601: n = 1; ! 602: if (argc>1 && argv[1][0]=='-') { ! 603: register char *fp; ! 604: ! 605: n++; ! 606: for (cp = &argv[1][1]; *cp; cp++) { ! 607: if ((fp=index(shfnams, *cp)) == NULL ! 608: || (fp+=shflags-shfnams) == NULL ! 609: || (fp != &lgnflag && fp > &xflag && flag == 0)) ! 610: printe("-%c: Bad option", *cp); ! 611: else if (fp != &lgnflag) ! 612: *fp = *cp; ! 613: } ! 614: if (cp == &argv[1][1]) { ! 615: vflag = 0; ! 616: xflag = 0; ! 617: } ! 618: if (flag == 0 && argc == 2) ! 619: return errflag; ! 620: } ! 621: if (errflag) ! 622: return 1; ! 623: if (sargv != NULL) ! 624: vfree(sargv); ! 625: sargv = vdupl(argv); ! 626: sargc = argc - n; ! 627: sargp = sargv + n; ! 628: return 0; ! 629: } ! 630: ! 631: /* ! 632: * print the time as XmX.Xs ! 633: * as fixed by Randall. ! 634: */ ! 635: ptime(t) ! 636: long t; ! 637: { ! 638: register int ticks, tenths, seconds; ! 639: ! 640: printf ("%ldm", t/MINUTE); ! 641: ticks = t%MINUTE; ! 642: seconds = ticks/SECOND; ! 643: tenths = (ticks%SECOND + SECOND/20)/(SECOND/10); ! 644: if (tenths == 10) { ! 645: tenths = 0; ! 646: seconds++; ! 647: } ! 648: printf ("%d.%ds ", seconds, tenths); ! 649: } ! 650: ! 651: /* User-defined shell functions. */ ! 652: ! 653: /* ! 654: * Lookup a shell function name. ! 655: * The hashing is probably irrelevant. ! 656: */ ! 657: SHFUNC * ! 658: lookup_sh_fn(name) char *name; ! 659: { ! 660: register SHFUNC *fnp; ! 661: register int ahash; ! 662: ! 663: ahash = ihash(name); ! 664: for (fnp=sh_fnp; fnp != NULL; fnp = fnp->fn_link) ! 665: if (fnp->fn_hash==ahash && strcmp(name, fnp->fn_name)==0) ! 666: return fnp; ! 667: return NULL; ! 668: } ! 669: ! 670: ! 671: /* ! 672: * When a subshell is created, the functions are available in the subshell ! 673: * but we don't want to lose the here-documents. ! 674: */ ! 675: ! 676: void subshell_shell_fns () ! 677: { ! 678: SHFUNC * scan; ! 679: ! 680: scan = sh_fnp; ! 681: ! 682: while (scan != NULL) { ! 683: forget_temp (scan->fn_temp); ! 684: scan->fn_temp = NULL; ! 685: scan = scan->fn_link; ! 686: } ! 687: } ! 688: ! 689: ! 690: /* ! 691: * Unset a shell function, freeing the function body and detaching any ! 692: * temporary files. ! 693: */ ! 694: ! 695: void cleanup_shell_fn (fnp) ! 696: SHFUNC * fnp; ! 697: { ! 698: free_node (fnp->fn_body); ! 699: unlink_temp (fnp->fn_temp); ! 700: } ! 701: ! 702: ! 703: /* ! 704: * Before final exit, clean up all shell functions. Freeing the memory of ! 705: * the function bodies is a waste of time here, so we leave that alone. ! 706: */ ! 707: ! 708: void cleanup_shell_fns () ! 709: { ! 710: SHFUNC * scan; ! 711: SHFUNC * next; ! 712: ! 713: for (scan = sh_fnp ; scan != NULL ; scan = next) { ! 714: next = scan->fn_link; ! 715: unlink_temp (scan->fn_temp); ! 716: #if 0 ! 717: cleanup_shell_fn (scan); ! 718: sfree (scan->fn_name); ! 719: sfree (scan); ! 720: #endif ! 721: } ! 722: ! 723: sh_fnp = NULL; ! 724: } ! 725: ! 726: ! 727: /* ! 728: * Define a shell function. ! 729: */ ! 730: def_shell_fn(np) register NODE *np; ! 731: { ! 732: register char *name; ! 733: register SHFUNC *fnp; ! 734: ! 735: name = np->n_strp; ! 736: if ((fnp = lookup_sh_fn(name)) != NULL) ! 737: cleanup_shell_fn (fnp); /* redeclared, free old body */ ! 738: else { ! 739: fnp = salloc(sizeof *fnp); /* allocate new function */ ! 740: fnp->fn_link = sh_fnp; /* add it to list */ ! 741: sh_fnp = fnp; ! 742: fnp->fn_hash = ihash(name); /* and set member info */ ! 743: fnp->fn_name = duplstr(name, 1); ! 744: } ! 745: fnp->fn_temp = capture_temp (); ! 746: fnp->fn_body = copy_node(np->n_next); /* and copy function body */ ! 747: } ! 748: ! 749: /* ! 750: * Look for a shell function, execute it if found. ! 751: */ ! 752: int ! 753: sh_fn() ! 754: { ! 755: register SHFUNC *fnp; ! 756: CON *ocon; ! 757: int oargc; ! 758: char *oarg0; ! 759: char **oargv, **oargp; ! 760: ! 761: if (nargv[0] == NULL) ! 762: return 0; ! 763: if ((fnp = lookup_sh_fn(nargv[0])) == NULL) ! 764: return 0; ! 765: ! 766: /* Set up sargc, sarg0, sargv, sargp here for $1 etc. to work. */ ! 767: oarg0 = sarg0; ! 768: oargc = sargc; ! 769: oargv = sargv; ! 770: oargp = sargp; ! 771: sarg0 = nargv[0]; ! 772: sargc = nargc - 1; ! 773: sargp = sargv = vdupl(nargv+1); ! 774: ocon = sesp->s_con; ! 775: sesp->s_con = NULL; ! 776: ! 777: ++in_sh_fn; ! 778: slret = command(fnp->fn_body); /* execute it */ ! 779: --in_sh_fn; ! 780: ret_done = 0; ! 781: vfree(sargv); ! 782: ! 783: sesp->s_con = ocon; ! 784: sarg0 = oarg0; ! 785: sargc = oargc; ! 786: sargv = oargv; ! 787: sargp = oargp; ! 788: return 1; ! 789: } ! 790: ! 791: /* ! 792: * Recursively allocate a fresh copy of a NODE. ! 793: * Examines type to decide if node uses strp or auxp. ! 794: * Watch out for nodes which contain loops: NFOR2, NWHILE, NUNTIL. ! 795: */ ! 796: NODE * ! 797: copy_node(np) NODE *np; ! 798: { ! 799: register NODE *newnp; ! 800: int flag; ! 801: ! 802: #if 0 ! 803: printf("copy_node(%x)", np); ! 804: if (np != NULL) ! 805: printf(" type=%d", np->n_type); ! 806: printf("\n"); ! 807: #endif ! 808: if (np == NULL) ! 809: return NULL; ! 810: flag = 0; ! 811: newnp = salloc(sizeof *np); /* allocate new NODE */ ! 812: newnp->n_type = np->n_type; ! 813: switch(np->n_type) { ! 814: ! 815: /* The following cases use the strp member. */ ! 816: case NRET: ! 817: case NFOR: ! 818: case NARGS: ! 819: case NASSG: ! 820: case NCASE: ! 821: case NCASE3: ! 822: case NIORS: ! 823: case NFUNC: ! 824: newnp->n_strp = duplstr(np->n_strp, 1); ! 825: break; ! 826: ! 827: /* The following cases use the auxp member. */ ! 828: case NWHILE: ! 829: case NUNTIL: ! 830: case NFOR2: ! 831: flag++; ! 832: np->n_next->n_next = NULL; /* zap the loop for recursion */ ! 833: /* fall through... */ ! 834: case NNULL: ! 835: case NCOMS: ! 836: case NCTRL: ! 837: case NBRAC: ! 838: case NPARN: ! 839: case NIF: ! 840: case NELSE: ! 841: case NCASE2: ! 842: case NLIST: ! 843: case NANDF: ! 844: case NORF: ! 845: case NBACK: ! 846: case NPIPE: ! 847: newnp->n_auxp = copy_node(np->n_auxp); ! 848: break; ! 849: ! 850: case NRPIPE: ! 851: case NWPIPE: ! 852: default: ! 853: /* ??? */ ! 854: printf("type=%d\n", np->n_type); ! 855: panic(9); ! 856: } ! 857: newnp->n_next = copy_node(np->n_next); ! 858: if (flag) ! 859: newnp->n_next->n_next = newnp; /* restore loop */ ! 860: return newnp; ! 861: } ! 862: ! 863: /* ! 864: * Undo the above. ! 865: */ ! 866: free_node(np) register NODE *np; ! 867: { ! 868: if (np == NULL) ! 869: return; ! 870: switch(np->n_type) { ! 871: ! 872: /* strp */ ! 873: case NRET: ! 874: case NFOR: ! 875: case NARGS: ! 876: case NASSG: ! 877: case NCASE: ! 878: case NCASE3: ! 879: case NIORS: ! 880: case NFUNC: ! 881: sfree(np->n_strp); ! 882: break; ! 883: ! 884: /* auxp */ ! 885: case NWHILE: ! 886: case NUNTIL: ! 887: case NFOR2: ! 888: np->n_next->n_next = NULL; /* zap the loop for recursion */ ! 889: /* fall through... */ ! 890: case NNULL: ! 891: case NCOMS: ! 892: case NCTRL: ! 893: case NBRAC: ! 894: case NPARN: ! 895: case NIF: ! 896: case NELSE: ! 897: case NCASE2: ! 898: case NLIST: ! 899: case NANDF: ! 900: case NORF: ! 901: case NBACK: ! 902: case NPIPE: ! 903: free_node(np->n_auxp); ! 904: break; ! 905: ! 906: case NRPIPE: ! 907: case NWPIPE: ! 908: default: ! 909: /* ??? */ ! 910: printf("type=%d\n", np->n_type); ! 911: panic(10); ! 912: } ! 913: free_node(np->n_next); ! 914: sfree(np); ! 915: } ! 916: ! 917: /* end of sh/exec3.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.