|
|
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.