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