|
|
1.1 root 1: /*
2: * built-in Bourne commands
3: */
4:
5: static char *RCSid = "$Header: c_sh.c,v 3.1 88/11/03 09:14:31 egisin Exp $";
6:
7: #include <stddef.h>
8: #include <stdlib.h>
9: #include <stdio.h>
10: #include <string.h>
11: #include <errno.h>
12: #include <signal.h>
13: #include <setjmp.h>
14: #include <sys/times.h>
15: #include <unistd.h> /* getcwd */
16: #include "sh.h"
17: #include "lex.h"
18: #include "tree.h"
19: #include "table.h"
20:
21: static void putvlist();
22: static char *clocktos();
23:
24: int
25: c_label(wp)
26: char **wp;
27: {
28: return 0;
29: }
30:
31: /* todo: add symlink hacks */
32: int
33: c_cd(wp)
34: register char **wp;
35: {
36: static char path[PATH];
37: register char *cp;
38: register struct tbl *vp;
39:
40: if ((cp = wp[1]) == NULL && (cp = strval(global("HOME"))) == NULL)
41: errorf("no home directory");
42: if (strcmp(cp, "-") == 0) {
43: cp = strval(global("OLDPWD"));
44: shellf("%s\n", cp);
45: }
46: if (chdir(cp) < 0)
47: errorf("%s: bad directory\n", cp);
48: flushcom(0);
49:
50: /* maintain $PWD and $OLDPWD */
51: vp = global("PWD");
52: cp = strval(vp);
53: if (cp != null)
54: setstr(global("OLDPWD"), cp);
55: cp = getcwd(path, (size_t)PATH);
56: if (cp == NULL)
57: unset(vp);
58: else
59: setstr(vp, cp);
60:
61: return 0;
62: }
63:
64: int
65: c_shift(wp)
66: register char **wp;
67: {
68: register struct block *l = e.loc;
69: register int n;
70:
71: n = wp[1] ? evaluate(wp[1]) : 1;
72: if (l->argc < n) {
73: errorf("nothing to shift\n");
74: return (1);
75: }
76: l->argv[n] = l->argv[0];
77: l->argv += n;
78: l->argc -= n;
79: return 0;
80: }
81:
82: int
83: c_umask(wp)
84: register char **wp;
85: {
86: register int i;
87: register char *cp;
88:
89: if ((cp = wp[1]) == NULL) {
90: i = umask(0);
91: umask(i);
92: printf("%03o\n", i); /* should this be shell output? */
93: } else {
94: for (i = 0; *cp>='0' && *cp<='7'; cp++)
95: i = i*8 + (*cp-'0');
96: umask(i);
97: }
98: return 0;
99: }
100:
101: int
102: c_dot(wp)
103: char **wp;
104: {
105: char *file, *cp;
106:
107: if ((cp = wp[1]) == NULL)
108: return 0;
109: file = search(cp, path, 0);
110: if (file == NULL)
111: errorf("%s: not found\n", cp);
112: if (include(file))
113: return exstat;
114: return -1;
115: }
116:
117: int
118: c_wait(wp)
119: char **wp;
120: {
121: register char *cp;
122:
123: wp++;
124: cp = *wp;
125: if (cp == NULL)
126: cp = "%";
127: /* todo: print status ? */
128: return waitfor(j_lookup(cp));
129: }
130:
131: int
132: c_read(wp)
133: register char **wp;
134: {
135: register int c = 0;
136: FILE *f = stdin;
137: int expand = 1;
138: register char *cp;
139:
140: for (wp++; (cp = *wp) != NULL && *cp++ == '-'; wp++) {
141: while (*cp) switch (*cp++) {
142: case 'e':
143: expand = 1;
144: break;
145: case 'r':
146: expand = 0;
147: break;
148: case 'u':
149: if (!digit(*cp) || (f = shf[*cp++-'0']) == NULL)
150: errorf("bad -u argument\n");
151: break;
152: }
153: }
154:
155: if (*wp == NULL)
156: errorf("missing name\n");
157: if ((cp = strchr(*wp, '?')) != NULL) {
158: *cp = 0;
159: if (flag[FTALKING]) {
160: shellf("%s ", cp+1);
161: fflush(shlout);
162: }
163: }
164:
165: for (; *wp != NULL; wp++) {
166: for (cp = line; cp <= line+LINE; ) {
167: if (c == '\n')
168: break;
169: c = getc(f);
170: if (c == EOF)
171: return 1;
172: if (expand && c == '\\') {
173: c = getc(f);
174: if (c == '\n')
175: c = 0;
176: else
177: *cp++ = c;
178: continue;
179: }
180: if (c == '\n' || wp[1] && ctype(c, C_IFS))
181: break;
182: *cp++ = c;
183: }
184: *cp = 0;
185: setstr(global(*wp), line);
186: }
187: return 0;
188: }
189:
190: int
191: c_eval(wp)
192: register char **wp;
193: {
194: register struct source *s;
195:
196: s = pushs(SWORDS);
197: s->u.strv = wp+1;
198: return shell(s);
199: }
200:
201: void setsig ARGS((struct trap *p, handler_t f));
202:
203: int
204: c_trap(wp)
205: register char **wp;
206: {
207: int i;
208: char *s;
209: register struct trap *p;
210:
211: wp++;
212: if (*wp == NULL) {
213: for (p = sigtraps, i = SIGNALS; --i >= 0; p++) {
214: if (p->trap != NULL)
215: shellf("%s: %s\n", p->name, p->trap);
216: }
217: return 0;
218: }
219:
220: s = (gettrap(*wp) == NULL) ? *wp++ : NULL; /* get command */
221: if (s != NULL && s[0] == '-' && s[1] == '\0')
222: s = NULL;
223:
224: /* set/clear traps */
225: while (*wp != NULL) {
226: p = gettrap(*wp++);
227: if (p == NULL)
228: errorf("trap: bad signal %s\n", wp[-1]);
229: if (p->trap != NULL)
230: afree((Void*)p->trap, APERM);
231: p->trap = NULL;
232: if (s != NULL) {
233: if (strlen(s) != 0) {
234: p->trap = strsave(s, APERM);
235: setsig(p, trapsig);
236: } else
237: setsig(p, (handler_t)SIG_IGN);
238: } else
239: /* todo: restore to orginal value */
240: setsig(p,
241: (p->signal==SIGINT || p->signal==SIGQUIT) && flag[FTALKING]
242: ? (handler_t)SIG_IGN : (handler_t)SIG_DFL);
243: }
244: return 0;
245: }
246:
247: void
248: setsig(p, f)
249: register struct trap *p;
250: void (*f)();
251: {
252: if (p->signal == 0)
253: return;
254: if (signal(p->signal, SIG_IGN) != SIG_IGN || p->ourtrap) {
255: p->ourtrap = 1;
256: signal(p->signal, f);
257: }
258: }
259:
260: int
261: c_return(wp)
262: char **wp;
263: {
264: wp++;
265: if (*wp != NULL)
266: exstat = getn(*wp);
267: quitenv(); /* pop E_TCOM */
268: while (e.type == E_LOOP || e.type == E_EXEC)
269: quitenv();
270: if (e.type == E_FUNC)
271: longjmp(e.jbuf, 1);
272: leave(exstat);
273: }
274:
275: int
276: c_brkcont(wp)
277: register char **wp;
278: {
279: int quit;
280:
281: quit = wp[1] == NULL ? 1 : getn(wp[1]);
282: quitenv(); /* pop E_TCOM */
283: while (e.type == E_LOOP || e.type == E_EXEC) {
284: if (e.type == E_LOOP && --quit <= 0)
285: longjmp(e.jbuf, (*wp[0] == 'b') ? LBREAK : LCONTIN);
286: quitenv();
287: }
288: errorf("cannot %s\n", wp[0]);
289: }
290:
291: int
292: c_exit(wp)
293: char **wp;
294: {
295: register char *cp;
296:
297: e.oenv = NULL;
298: if ((cp = wp[1]) != NULL)
299: exstat = getn(cp);
300: #if JOBS
301: if (flag[FMONITOR] && j_stopped()) /* todo: only once */
302: errorf("There are stopped jobs\n");
303: #endif
304: leave(exstat);
305: }
306:
307: int
308: c_exro(wp)
309: register char **wp;
310: {
311: int flag = (**wp == 'e') ? EXPORT : RDONLY;
312:
313: if (*++wp != NULL) {
314: for (; *wp != NULL; wp++)
315: if (typeset(*wp, flag, 0) == NULL)
316: errorf("%s: bad identifier\n", *wp);
317: } else
318: putvlist(flag);
319: return 0;
320: }
321:
322: static void
323: putvlist(flag)
324: register int flag;
325: {
326: struct block *l = e.loc;
327: register struct tbl *vp, **p;
328:
329: flag |= ISSET;
330: for (l = e.loc; l != NULL; l = l->next)
331: for (p = tsort(&l->vars); (vp = *p++) != NULL; )
332: if ((vp->flag&flag) == flag) {
333: if (vp->flag & EXPORT)
334: printf("export ");
335: if (vp->flag & RDONLY)
336: printf("readonly ");
337: printf("%s\n", vp->name);
338: }
339: }
340:
341: int
342: c_set(wp)
343: register char **wp;
344: {
345: struct block *l = e.loc;
346: register struct tbl *vp, **p;
347: register char **owp = wp;
348: register char *cp;
349: int old_fmonitor = flag[FMONITOR];
350:
351: if ((cp = *++wp) == NULL) {
352: static char * Const args [] = {"set", "-", NULL};
353: extern int c_typeset ARGS((char **args));
354: return c_typeset(args);
355: }
356:
357: for (; (cp = *wp) != NULL && (*cp == '-' || *cp == '+');) {
358: int i, n = *cp++ == '-'; /* set or clear flag */
359: wp++;
360: if (*cp == '\0') {
361: if (n)
362: flag[FXTRACE] = flag[FVERBOSE] = 0;
363: break;
364: }
365: if (*cp == '-')
366: goto setargs;
367: for (; *cp != '\0'; cp++)
368: if (*cp == 'o') {
369: if (*wp == NULL) {
370: printoptions();
371: return 0;
372: }
373: i = option(*wp++);
374: if (i == 0)
375: shellf("%s: unknown option\n", *--wp);
376: flag[i] = n;
377: } else if (*cp>='a' && *cp<='z')
378: flag[FLAG(*cp)] = n;
379: else
380: errorf("%c: bad flag\n", *cp);
381: if (flag[FTALKING])
382: flag[FERREXIT] = 0;
383: }
384:
385: #if JOBS
386: if (old_fmonitor != flag[FMONITOR])
387: j_change();
388: #endif
389:
390: /* set $# and $* */
391: if (*wp != NULL) {
392: setargs:
393: owp = --wp;
394: wp[0] = l->argv[0]; /* save $0 */
395: while (*++wp != NULL)
396: *wp = strsave(*wp, &l->area);
397: l->argc = wp - owp - 1;
398: l->argv = (char **) alloc(sizeofN(char *, l->argc+2), &l->area);
399: for (wp = l->argv; (*wp++ = *owp++) != NULL; )
400: ;
401: resetopts();
402: }
403: return 0;
404: }
405:
406: int
407: c_unset(wp)
408: register char **wp;
409: {
410: register char *id;
411: int flagf = 0;
412:
413: for (wp++; (id = *wp) != NULL && *id == '-'; wp++)
414: if (*++id == 'f')
415: flagf++;
416: for (; (id = *wp) != NULL; wp++)
417: if (!flagf) { /* unset variable */
418: unset(local(id));
419: } else { /* unset function */
420: register struct tbl *tp;
421: tp = tsearch(&e.loc->funs, id, hash(id));
422: if (tp != NULL)
423: define(tp, (struct op *)NULL);
424: }
425: return 0;
426: }
427:
428: int
429: c_ulimit(wp)
430: register char **wp;
431: {
432: extern int do_ulimit();
433:
434: return do_ulimit(wp[1], wp[2]);
435: }
436:
437: int
438: c_times(wp)
439: char **wp;
440: {
441: struct tms all;
442:
443: (void) times(&all);
444: printf("Shell: ");
445: printf("%8s user ", clocktos(all.tms_utime));
446: printf("%8s system\n", clocktos(all.tms_stime));
447: printf("Kids: ");
448: printf("%8s user ", clocktos(all.tms_cutime));
449: printf("%8s system\n", clocktos(all.tms_cstime));
450:
451: return 0;
452: }
453:
454: /*
455: * time pipeline (really a statement, not a built-in comman)
456: */
457: int
458: timex(t, f)
459: struct op *t;
460: int f;
461: {
462: int rv;
463: struct tms t0, t1;
464: clock_t t0t, t1t, time();
465: extern clock_t j_utime, j_stime; /* computed by j_wait */
466:
467: j_utime = j_stime = 0;
468: #if COHERENT
469: t0t = time((clock_t)NULL);
470: (void)times(&t0);
471: #else
472: t0t = times(&t0);
473: #endif
474: rv = execute(t->left, f);
475: #if COHERENT
476: t1t = time((clock_t)NULL);
477: (void)times(&t1);
478: #else
479: t1t = times(&t1);
480: #endif
481: shellf("%8s real ", clocktos((t1t - t0t) * 100));
482: shellf("%8s user ",
483: clocktos(t1.tms_utime - t0.tms_utime + j_utime));
484: shellf("%8s system ",
485: clocktos(t1.tms_stime - t0.tms_stime + j_stime));
486: shellf("\n");
487:
488: return rv;
489: }
490:
491: static char *
492: clocktos(t)
493: clock_t t;
494: {
495: static char temp[20];
496: register int i;
497: register char *cp = temp + sizeof(temp);
498:
499: #if !COHERENT
500: #if CLK_TCK != 100 /* convert to 1/100'ths */
501: t = (t < 1000000000/CLK_TCK) ?
502: (t * 100) / CLK_TCK : (t / CLK_TCK) * 100;
503: #endif
504: #endif
505: *--cp = '\0';
506: *--cp = 's';
507: for (i = -2; i <= 0 || t > 0; i++) {
508: if (i == 0)
509: *--cp = '.';
510: *--cp = '0' + (char)(t%10);
511: t /= 10;
512: }
513: return cp;
514: }
515:
516: /* dummy function, special case in comexec() */
517: int
518: c_exec(wp)
519: char ** wp;
520: {
521: return 0;
522: }
523:
524: /* dummy function, special case in comexec() */
525: int
526: c_builtin(wp)
527: char ** wp;
528: {
529: return 0;
530: }
531:
532: extern int c_test(); /* in test.c */
533:
534: Const struct builtin shbuiltins [] = {
535: {"=:", c_label},
536: {"=.", c_dot},
537: {"[", c_test},
538: {"=cd", c_cd},
539: {"builtin", c_builtin},
540: {"=exec", c_exec},
541: {"=shift", c_shift},
542: {"wait", c_wait},
543: {"read", c_read},
544: {"=eval", c_eval},
545: {"trap", c_trap},
546: {"break", c_brkcont},
547: {"continue", c_brkcont},
548: {"exit", c_exit},
549: {"=export", c_exro},
550: {"=readonly", c_exro},
551: {"=return", c_return},
552: {"=set", c_set},
553: {"=unset", c_unset},
554: {"umask", c_umask},
555: {"test", c_test},
556: {"times", c_times},
557: {"ulimit", c_ulimit},
558: {NULL, NULL}
559: };
560:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.