17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier * built-in Bourne commands
37dd7cddfSDavid du Colombier */
47dd7cddfSDavid du Colombier
57dd7cddfSDavid du Colombier #include "sh.h"
67dd7cddfSDavid du Colombier #include "ksh_stat.h" /* umask() */
77dd7cddfSDavid du Colombier #include "ksh_time.h"
87dd7cddfSDavid du Colombier #include "ksh_times.h"
97dd7cddfSDavid du Colombier
107dd7cddfSDavid du Colombier static char *clocktos ARGS((clock_t t));
117dd7cddfSDavid du Colombier
127dd7cddfSDavid du Colombier
137dd7cddfSDavid du Colombier /* :, false and true */
147dd7cddfSDavid du Colombier int
c_label(wp)157dd7cddfSDavid du Colombier c_label(wp)
167dd7cddfSDavid du Colombier char **wp;
177dd7cddfSDavid du Colombier {
187dd7cddfSDavid du Colombier return wp[0][0] == 'f' ? 1 : 0;
197dd7cddfSDavid du Colombier }
207dd7cddfSDavid du Colombier
217dd7cddfSDavid du Colombier int
c_shift(wp)227dd7cddfSDavid du Colombier c_shift(wp)
237dd7cddfSDavid du Colombier char **wp;
247dd7cddfSDavid du Colombier {
257dd7cddfSDavid du Colombier register struct block *l = e->loc;
267dd7cddfSDavid du Colombier register int n;
277dd7cddfSDavid du Colombier long val;
287dd7cddfSDavid du Colombier char *arg;
297dd7cddfSDavid du Colombier
307dd7cddfSDavid du Colombier if (ksh_getopt(wp, &builtin_opt, null) == '?')
317dd7cddfSDavid du Colombier return 1;
327dd7cddfSDavid du Colombier arg = wp[builtin_opt.optind];
337dd7cddfSDavid du Colombier
347dd7cddfSDavid du Colombier if (arg) {
357dd7cddfSDavid du Colombier evaluate(arg, &val, KSH_UNWIND_ERROR);
367dd7cddfSDavid du Colombier n = val;
377dd7cddfSDavid du Colombier } else
387dd7cddfSDavid du Colombier n = 1;
397dd7cddfSDavid du Colombier if (n < 0) {
407dd7cddfSDavid du Colombier bi_errorf("%s: bad number", arg);
417dd7cddfSDavid du Colombier return (1);
427dd7cddfSDavid du Colombier }
437dd7cddfSDavid du Colombier if (l->argc < n) {
447dd7cddfSDavid du Colombier bi_errorf("nothing to shift");
457dd7cddfSDavid du Colombier return (1);
467dd7cddfSDavid du Colombier }
477dd7cddfSDavid du Colombier l->argv[n] = l->argv[0];
487dd7cddfSDavid du Colombier l->argv += n;
497dd7cddfSDavid du Colombier l->argc -= n;
507dd7cddfSDavid du Colombier return 0;
517dd7cddfSDavid du Colombier }
527dd7cddfSDavid du Colombier
537dd7cddfSDavid du Colombier int
c_umask(wp)547dd7cddfSDavid du Colombier c_umask(wp)
557dd7cddfSDavid du Colombier char **wp;
567dd7cddfSDavid du Colombier {
577dd7cddfSDavid du Colombier register int i;
587dd7cddfSDavid du Colombier register char *cp;
597dd7cddfSDavid du Colombier int symbolic = 0;
607dd7cddfSDavid du Colombier int old_umask;
617dd7cddfSDavid du Colombier int optc;
627dd7cddfSDavid du Colombier
637dd7cddfSDavid du Colombier while ((optc = ksh_getopt(wp, &builtin_opt, "S")) != EOF)
647dd7cddfSDavid du Colombier switch (optc) {
657dd7cddfSDavid du Colombier case 'S':
667dd7cddfSDavid du Colombier symbolic = 1;
677dd7cddfSDavid du Colombier break;
687dd7cddfSDavid du Colombier case '?':
697dd7cddfSDavid du Colombier return 1;
707dd7cddfSDavid du Colombier }
717dd7cddfSDavid du Colombier cp = wp[builtin_opt.optind];
727dd7cddfSDavid du Colombier if (cp == NULL) {
737dd7cddfSDavid du Colombier old_umask = umask(0);
747dd7cddfSDavid du Colombier umask(old_umask);
757dd7cddfSDavid du Colombier if (symbolic) {
767dd7cddfSDavid du Colombier char buf[18];
777dd7cddfSDavid du Colombier int j;
787dd7cddfSDavid du Colombier
797dd7cddfSDavid du Colombier old_umask = ~old_umask;
807dd7cddfSDavid du Colombier cp = buf;
817dd7cddfSDavid du Colombier for (i = 0; i < 3; i++) {
827dd7cddfSDavid du Colombier *cp++ = "ugo"[i];
837dd7cddfSDavid du Colombier *cp++ = '=';
847dd7cddfSDavid du Colombier for (j = 0; j < 3; j++)
857dd7cddfSDavid du Colombier if (old_umask & (1 << (8 - (3*i + j))))
867dd7cddfSDavid du Colombier *cp++ = "rwx"[j];
877dd7cddfSDavid du Colombier *cp++ = ',';
887dd7cddfSDavid du Colombier }
897dd7cddfSDavid du Colombier cp[-1] = '\0';
907dd7cddfSDavid du Colombier shprintf("%s\n", buf);
917dd7cddfSDavid du Colombier } else
927dd7cddfSDavid du Colombier shprintf("%#3.3o\n", old_umask);
937dd7cddfSDavid du Colombier } else {
947dd7cddfSDavid du Colombier int new_umask;
957dd7cddfSDavid du Colombier
967dd7cddfSDavid du Colombier if (digit(*cp)) {
977dd7cddfSDavid du Colombier for (new_umask = 0; *cp >= '0' && *cp <= '7'; cp++)
987dd7cddfSDavid du Colombier new_umask = new_umask * 8 + (*cp - '0');
997dd7cddfSDavid du Colombier if (*cp) {
1007dd7cddfSDavid du Colombier bi_errorf("bad number");
1017dd7cddfSDavid du Colombier return 1;
1027dd7cddfSDavid du Colombier }
1037dd7cddfSDavid du Colombier } else {
1047dd7cddfSDavid du Colombier /* symbolic format */
1057dd7cddfSDavid du Colombier int positions, new_val;
1067dd7cddfSDavid du Colombier char op;
1077dd7cddfSDavid du Colombier
1087dd7cddfSDavid du Colombier old_umask = umask(0);
1097dd7cddfSDavid du Colombier umask(old_umask); /* in case of error */
1107dd7cddfSDavid du Colombier old_umask = ~old_umask;
1117dd7cddfSDavid du Colombier new_umask = old_umask;
1127dd7cddfSDavid du Colombier positions = 0;
1137dd7cddfSDavid du Colombier while (*cp) {
1147dd7cddfSDavid du Colombier while (*cp && strchr("augo", *cp))
1157dd7cddfSDavid du Colombier switch (*cp++) {
1167dd7cddfSDavid du Colombier case 'a': positions |= 0111; break;
1177dd7cddfSDavid du Colombier case 'u': positions |= 0100; break;
1187dd7cddfSDavid du Colombier case 'g': positions |= 0010; break;
1197dd7cddfSDavid du Colombier case 'o': positions |= 0001; break;
1207dd7cddfSDavid du Colombier }
1217dd7cddfSDavid du Colombier if (!positions)
1227dd7cddfSDavid du Colombier positions = 0111; /* default is a */
1237dd7cddfSDavid du Colombier if (!strchr("=+-", op = *cp))
1247dd7cddfSDavid du Colombier break;
1257dd7cddfSDavid du Colombier cp++;
1267dd7cddfSDavid du Colombier new_val = 0;
1277dd7cddfSDavid du Colombier while (*cp && strchr("rwxugoXs", *cp))
1287dd7cddfSDavid du Colombier switch (*cp++) {
1297dd7cddfSDavid du Colombier case 'r': new_val |= 04; break;
1307dd7cddfSDavid du Colombier case 'w': new_val |= 02; break;
1317dd7cddfSDavid du Colombier case 'x': new_val |= 01; break;
1327dd7cddfSDavid du Colombier case 'u': new_val |= old_umask >> 6;
1337dd7cddfSDavid du Colombier break;
1347dd7cddfSDavid du Colombier case 'g': new_val |= old_umask >> 3;
1357dd7cddfSDavid du Colombier break;
1367dd7cddfSDavid du Colombier case 'o': new_val |= old_umask >> 0;
1377dd7cddfSDavid du Colombier break;
1387dd7cddfSDavid du Colombier case 'X': if (old_umask & 0111)
1397dd7cddfSDavid du Colombier new_val |= 01;
1407dd7cddfSDavid du Colombier break;
1417dd7cddfSDavid du Colombier case 's': /* ignored */
1427dd7cddfSDavid du Colombier break;
1437dd7cddfSDavid du Colombier }
1447dd7cddfSDavid du Colombier new_val = (new_val & 07) * positions;
1457dd7cddfSDavid du Colombier switch (op) {
1467dd7cddfSDavid du Colombier case '-':
1477dd7cddfSDavid du Colombier new_umask &= ~new_val;
1487dd7cddfSDavid du Colombier break;
1497dd7cddfSDavid du Colombier case '=':
1507dd7cddfSDavid du Colombier new_umask = new_val
1517dd7cddfSDavid du Colombier | (new_umask & ~(positions * 07));
1527dd7cddfSDavid du Colombier break;
1537dd7cddfSDavid du Colombier case '+':
1547dd7cddfSDavid du Colombier new_umask |= new_val;
1557dd7cddfSDavid du Colombier }
1567dd7cddfSDavid du Colombier if (*cp == ',') {
1577dd7cddfSDavid du Colombier positions = 0;
1587dd7cddfSDavid du Colombier cp++;
1597dd7cddfSDavid du Colombier } else if (!strchr("=+-", *cp))
1607dd7cddfSDavid du Colombier break;
1617dd7cddfSDavid du Colombier }
1627dd7cddfSDavid du Colombier if (*cp) {
1637dd7cddfSDavid du Colombier bi_errorf("bad mask");
1647dd7cddfSDavid du Colombier return 1;
1657dd7cddfSDavid du Colombier }
1667dd7cddfSDavid du Colombier new_umask = ~new_umask;
1677dd7cddfSDavid du Colombier }
1687dd7cddfSDavid du Colombier umask(new_umask);
1697dd7cddfSDavid du Colombier }
1707dd7cddfSDavid du Colombier return 0;
1717dd7cddfSDavid du Colombier }
1727dd7cddfSDavid du Colombier
1737dd7cddfSDavid du Colombier int
c_dot(wp)1747dd7cddfSDavid du Colombier c_dot(wp)
1757dd7cddfSDavid du Colombier char **wp;
1767dd7cddfSDavid du Colombier {
1777dd7cddfSDavid du Colombier char *file, *cp;
1787dd7cddfSDavid du Colombier char **argv;
1797dd7cddfSDavid du Colombier int argc;
1807dd7cddfSDavid du Colombier int i;
1817dd7cddfSDavid du Colombier int err;
1827dd7cddfSDavid du Colombier
1837dd7cddfSDavid du Colombier if (ksh_getopt(wp, &builtin_opt, null) == '?')
1847dd7cddfSDavid du Colombier return 1;
1857dd7cddfSDavid du Colombier
1867dd7cddfSDavid du Colombier if ((cp = wp[builtin_opt.optind]) == NULL)
1877dd7cddfSDavid du Colombier return 0;
1887dd7cddfSDavid du Colombier file = search(cp, path, R_OK, &err);
1897dd7cddfSDavid du Colombier if (file == NULL) {
1907dd7cddfSDavid du Colombier bi_errorf("%s: %s", cp, err ? strerror(err) : "not found");
1917dd7cddfSDavid du Colombier return 1;
1927dd7cddfSDavid du Colombier }
1937dd7cddfSDavid du Colombier
1947dd7cddfSDavid du Colombier /* Set positional parameters? */
1957dd7cddfSDavid du Colombier if (wp[builtin_opt.optind + 1]) {
1967dd7cddfSDavid du Colombier argv = wp + builtin_opt.optind;
1977dd7cddfSDavid du Colombier argv[0] = e->loc->argv[0]; /* preserve $0 */
1987dd7cddfSDavid du Colombier for (argc = 0; argv[argc + 1]; argc++)
1997dd7cddfSDavid du Colombier ;
2007dd7cddfSDavid du Colombier } else {
2017dd7cddfSDavid du Colombier argc = 0;
2027dd7cddfSDavid du Colombier argv = (char **) 0;
2037dd7cddfSDavid du Colombier }
2047dd7cddfSDavid du Colombier i = include(file, argc, argv, 0);
2057dd7cddfSDavid du Colombier if (i < 0) { /* should not happen */
2067dd7cddfSDavid du Colombier bi_errorf("%s: %s", cp, strerror(errno));
2077dd7cddfSDavid du Colombier return 1;
2087dd7cddfSDavid du Colombier }
2097dd7cddfSDavid du Colombier return i;
2107dd7cddfSDavid du Colombier }
2117dd7cddfSDavid du Colombier
2127dd7cddfSDavid du Colombier int
c_wait(wp)2137dd7cddfSDavid du Colombier c_wait(wp)
2147dd7cddfSDavid du Colombier char **wp;
2157dd7cddfSDavid du Colombier {
2167dd7cddfSDavid du Colombier int UNINITIALIZED(rv);
2177dd7cddfSDavid du Colombier int sig;
2187dd7cddfSDavid du Colombier
2197dd7cddfSDavid du Colombier if (ksh_getopt(wp, &builtin_opt, null) == '?')
2207dd7cddfSDavid du Colombier return 1;
2217dd7cddfSDavid du Colombier wp += builtin_opt.optind;
2227dd7cddfSDavid du Colombier if (*wp == (char *) 0) {
2237dd7cddfSDavid du Colombier while (waitfor((char *) 0, &sig) >= 0)
2247dd7cddfSDavid du Colombier ;
2257dd7cddfSDavid du Colombier rv = sig;
2267dd7cddfSDavid du Colombier } else {
2277dd7cddfSDavid du Colombier for (; *wp; wp++)
2287dd7cddfSDavid du Colombier rv = waitfor(*wp, &sig);
2297dd7cddfSDavid du Colombier if (rv < 0)
2307dd7cddfSDavid du Colombier rv = sig ? sig : 127; /* magic exit code: bad job-id */
2317dd7cddfSDavid du Colombier }
2327dd7cddfSDavid du Colombier return rv;
2337dd7cddfSDavid du Colombier }
2347dd7cddfSDavid du Colombier
2357dd7cddfSDavid du Colombier int
c_read(wp)2367dd7cddfSDavid du Colombier c_read(wp)
2377dd7cddfSDavid du Colombier char **wp;
2387dd7cddfSDavid du Colombier {
2397dd7cddfSDavid du Colombier register int c = 0;
2407dd7cddfSDavid du Colombier int expand = 1, history = 0;
2417dd7cddfSDavid du Colombier int expanding;
2427dd7cddfSDavid du Colombier int ecode = 0;
2437dd7cddfSDavid du Colombier register char *cp;
2447dd7cddfSDavid du Colombier int fd = 0;
2457dd7cddfSDavid du Colombier struct shf *shf;
2467dd7cddfSDavid du Colombier int optc;
2477dd7cddfSDavid du Colombier const char *emsg;
2487dd7cddfSDavid du Colombier XString cs, xs;
2497dd7cddfSDavid du Colombier struct tbl *vp;
2507dd7cddfSDavid du Colombier char UNINITIALIZED(*xp);
2517dd7cddfSDavid du Colombier
2527dd7cddfSDavid du Colombier while ((optc = ksh_getopt(wp, &builtin_opt, "prsu,")) != EOF)
2537dd7cddfSDavid du Colombier switch (optc) {
2547dd7cddfSDavid du Colombier #ifdef KSH
2557dd7cddfSDavid du Colombier case 'p':
2567dd7cddfSDavid du Colombier if ((fd = coproc_getfd(R_OK, &emsg)) < 0) {
2577dd7cddfSDavid du Colombier bi_errorf("-p: %s", emsg);
2587dd7cddfSDavid du Colombier return 1;
2597dd7cddfSDavid du Colombier }
2607dd7cddfSDavid du Colombier break;
2617dd7cddfSDavid du Colombier #endif /* KSH */
2627dd7cddfSDavid du Colombier case 'r':
2637dd7cddfSDavid du Colombier expand = 0;
2647dd7cddfSDavid du Colombier break;
2657dd7cddfSDavid du Colombier case 's':
2667dd7cddfSDavid du Colombier history = 1;
2677dd7cddfSDavid du Colombier break;
2687dd7cddfSDavid du Colombier case 'u':
2697dd7cddfSDavid du Colombier if (!*(cp = builtin_opt.optarg))
2707dd7cddfSDavid du Colombier fd = 0;
2717dd7cddfSDavid du Colombier else if ((fd = check_fd(cp, R_OK, &emsg)) < 0) {
2727dd7cddfSDavid du Colombier bi_errorf("-u: %s: %s", cp, emsg);
2737dd7cddfSDavid du Colombier return 1;
2747dd7cddfSDavid du Colombier }
2757dd7cddfSDavid du Colombier break;
2767dd7cddfSDavid du Colombier case '?':
2777dd7cddfSDavid du Colombier return 1;
2787dd7cddfSDavid du Colombier }
2797dd7cddfSDavid du Colombier wp += builtin_opt.optind;
2807dd7cddfSDavid du Colombier
2817dd7cddfSDavid du Colombier if (*wp == NULL)
2827dd7cddfSDavid du Colombier *--wp = "REPLY";
2837dd7cddfSDavid du Colombier
2847dd7cddfSDavid du Colombier /* Since we can't necessarily seek backwards on non-regular files,
2857dd7cddfSDavid du Colombier * don't buffer them so we can't read too much.
2867dd7cddfSDavid du Colombier */
2877dd7cddfSDavid du Colombier shf = shf_reopen(fd, SHF_RD | SHF_INTERRUPT | can_seek(fd), shl_spare);
2887dd7cddfSDavid du Colombier
2897dd7cddfSDavid du Colombier if ((cp = strchr(*wp, '?')) != NULL) {
2907dd7cddfSDavid du Colombier *cp = 0;
2917dd7cddfSDavid du Colombier if (isatty(fd)) {
2927dd7cddfSDavid du Colombier /* at&t ksh says it prints prompt on fd if it's open
2937dd7cddfSDavid du Colombier * for writing and is a tty, but it doesn't do it
2947dd7cddfSDavid du Colombier * (it also doesn't check the interactive flag,
2957dd7cddfSDavid du Colombier * as is indicated in the Kornshell book).
2967dd7cddfSDavid du Colombier */
2977dd7cddfSDavid du Colombier shellf("%s", cp+1);
2987dd7cddfSDavid du Colombier }
2997dd7cddfSDavid du Colombier }
3007dd7cddfSDavid du Colombier
3017dd7cddfSDavid du Colombier #ifdef KSH
3027dd7cddfSDavid du Colombier /* If we are reading from the co-process for the first time,
3037dd7cddfSDavid du Colombier * make sure the other side of the pipe is closed first. This allows
3047dd7cddfSDavid du Colombier * the detection of eof.
3057dd7cddfSDavid du Colombier *
3067dd7cddfSDavid du Colombier * This is not compatiable with at&t ksh... the fd is kept so another
3077dd7cddfSDavid du Colombier * coproc can be started with same ouput, however, this means eof
3087dd7cddfSDavid du Colombier * can't be detected... This is why it is closed here.
3097dd7cddfSDavid du Colombier * If this call is removed, remove the eof check below, too.
3107dd7cddfSDavid du Colombier * coproc_readw_close(fd);
3117dd7cddfSDavid du Colombier */
3127dd7cddfSDavid du Colombier #endif /* KSH */
3137dd7cddfSDavid du Colombier
3147dd7cddfSDavid du Colombier if (history)
3157dd7cddfSDavid du Colombier Xinit(xs, xp, 128, ATEMP);
3167dd7cddfSDavid du Colombier expanding = 0;
3177dd7cddfSDavid du Colombier Xinit(cs, cp, 128, ATEMP);
3187dd7cddfSDavid du Colombier for (; *wp != NULL; wp++) {
3197dd7cddfSDavid du Colombier for (cp = Xstring(cs, cp); ; ) {
3207dd7cddfSDavid du Colombier if (c == '\n' || c == EOF)
3217dd7cddfSDavid du Colombier break;
3227dd7cddfSDavid du Colombier while (1) {
3237dd7cddfSDavid du Colombier c = shf_getc(shf);
3247dd7cddfSDavid du Colombier if (c == '\0'
3257dd7cddfSDavid du Colombier #ifdef OS2
3267dd7cddfSDavid du Colombier || c == '\r'
3277dd7cddfSDavid du Colombier #endif /* OS2 */
3287dd7cddfSDavid du Colombier )
3297dd7cddfSDavid du Colombier continue;
3307dd7cddfSDavid du Colombier if (c == EOF && shf_error(shf)
3317dd7cddfSDavid du Colombier && shf_errno(shf) == EINTR)
3327dd7cddfSDavid du Colombier {
3337dd7cddfSDavid du Colombier /* Was the offending signal one that
3347dd7cddfSDavid du Colombier * would normally kill a process?
3357dd7cddfSDavid du Colombier * If so, pretend the read was killed.
3367dd7cddfSDavid du Colombier */
3377dd7cddfSDavid du Colombier ecode = fatal_trap_check();
3387dd7cddfSDavid du Colombier
3397dd7cddfSDavid du Colombier /* non fatal (eg, CHLD), carry on */
3407dd7cddfSDavid du Colombier if (!ecode) {
3417dd7cddfSDavid du Colombier shf_clearerr(shf);
3427dd7cddfSDavid du Colombier continue;
3437dd7cddfSDavid du Colombier }
3447dd7cddfSDavid du Colombier }
3457dd7cddfSDavid du Colombier break;
3467dd7cddfSDavid du Colombier }
3477dd7cddfSDavid du Colombier if (history) {
3487dd7cddfSDavid du Colombier Xcheck(xs, xp);
3497dd7cddfSDavid du Colombier Xput(xs, xp, c);
3507dd7cddfSDavid du Colombier }
3517dd7cddfSDavid du Colombier Xcheck(cs, cp);
3527dd7cddfSDavid du Colombier if (expanding) {
3537dd7cddfSDavid du Colombier expanding = 0;
3547dd7cddfSDavid du Colombier if (c == '\n') {
3557dd7cddfSDavid du Colombier c = 0;
3567dd7cddfSDavid du Colombier if (Flag(FTALKING_I) && isatty(fd)) {
3577dd7cddfSDavid du Colombier /* set prompt in case this is
3587dd7cddfSDavid du Colombier * called from .profile or $ENV
3597dd7cddfSDavid du Colombier */
3607dd7cddfSDavid du Colombier set_prompt(PS2, (Source *) 0);
3617dd7cddfSDavid du Colombier pprompt(prompt, 0);
3627dd7cddfSDavid du Colombier }
3637dd7cddfSDavid du Colombier } else if (c != EOF)
3647dd7cddfSDavid du Colombier Xput(cs, cp, c);
3657dd7cddfSDavid du Colombier continue;
3667dd7cddfSDavid du Colombier }
3677dd7cddfSDavid du Colombier if (expand && c == '\\') {
3687dd7cddfSDavid du Colombier expanding = 1;
3697dd7cddfSDavid du Colombier continue;
3707dd7cddfSDavid du Colombier }
3717dd7cddfSDavid du Colombier if (c == '\n' || c == EOF)
3727dd7cddfSDavid du Colombier break;
3737dd7cddfSDavid du Colombier if (ctype(c, C_IFS)) {
3747dd7cddfSDavid du Colombier if (Xlength(cs, cp) == 0 && ctype(c, C_IFSWS))
3757dd7cddfSDavid du Colombier continue;
3767dd7cddfSDavid du Colombier if (wp[1])
3777dd7cddfSDavid du Colombier break;
3787dd7cddfSDavid du Colombier }
3797dd7cddfSDavid du Colombier Xput(cs, cp, c);
3807dd7cddfSDavid du Colombier }
3817dd7cddfSDavid du Colombier /* strip trailing IFS white space from last variable */
3827dd7cddfSDavid du Colombier if (!wp[1])
3837dd7cddfSDavid du Colombier while (Xlength(cs, cp) && ctype(cp[-1], C_IFS)
3847dd7cddfSDavid du Colombier && ctype(cp[-1], C_IFSWS))
3857dd7cddfSDavid du Colombier cp--;
3867dd7cddfSDavid du Colombier Xput(cs, cp, '\0');
3877dd7cddfSDavid du Colombier vp = global(*wp);
3887dd7cddfSDavid du Colombier /* Must be done before setting export. */
3897dd7cddfSDavid du Colombier if (vp->flag & RDONLY) {
3907dd7cddfSDavid du Colombier shf_flush(shf);
3917dd7cddfSDavid du Colombier bi_errorf("%s is read only", *wp);
3927dd7cddfSDavid du Colombier return 1;
3937dd7cddfSDavid du Colombier }
3947dd7cddfSDavid du Colombier if (Flag(FEXPORT))
3957dd7cddfSDavid du Colombier typeset(*wp, EXPORT, 0, 0, 0);
3967dd7cddfSDavid du Colombier if (!setstr(vp, Xstring(cs, cp), KSH_RETURN_ERROR)) {
3977dd7cddfSDavid du Colombier shf_flush(shf);
3987dd7cddfSDavid du Colombier return 1;
3997dd7cddfSDavid du Colombier }
4007dd7cddfSDavid du Colombier }
4017dd7cddfSDavid du Colombier
4027dd7cddfSDavid du Colombier shf_flush(shf);
4037dd7cddfSDavid du Colombier if (history) {
4047dd7cddfSDavid du Colombier Xput(xs, xp, '\0');
4057dd7cddfSDavid du Colombier source->line++;
4067dd7cddfSDavid du Colombier histsave(source->line, Xstring(xs, xp), 1);
4077dd7cddfSDavid du Colombier Xfree(xs, xp);
4087dd7cddfSDavid du Colombier }
4097dd7cddfSDavid du Colombier #ifdef KSH
4107dd7cddfSDavid du Colombier /* if this is the co-process fd, close the file descriptor
4117dd7cddfSDavid du Colombier * (can get eof if and only if all processes are have died, ie,
4127dd7cddfSDavid du Colombier * coproc.njobs is 0 and the pipe is closed).
4137dd7cddfSDavid du Colombier */
4147dd7cddfSDavid du Colombier if (c == EOF && !ecode)
4157dd7cddfSDavid du Colombier coproc_read_close(fd);
4167dd7cddfSDavid du Colombier #endif /* KSH */
4177dd7cddfSDavid du Colombier
4187dd7cddfSDavid du Colombier return ecode ? ecode : c == EOF;
4197dd7cddfSDavid du Colombier }
4207dd7cddfSDavid du Colombier
4217dd7cddfSDavid du Colombier int
c_eval(wp)4227dd7cddfSDavid du Colombier c_eval(wp)
4237dd7cddfSDavid du Colombier char **wp;
4247dd7cddfSDavid du Colombier {
4257dd7cddfSDavid du Colombier register struct source *s;
4267dd7cddfSDavid du Colombier
4277dd7cddfSDavid du Colombier if (ksh_getopt(wp, &builtin_opt, null) == '?')
4287dd7cddfSDavid du Colombier return 1;
4297dd7cddfSDavid du Colombier s = pushs(SWORDS, ATEMP);
4307dd7cddfSDavid du Colombier s->u.strv = wp + builtin_opt.optind;
4317dd7cddfSDavid du Colombier if (!Flag(FPOSIX)) {
4327dd7cddfSDavid du Colombier /*
4337dd7cddfSDavid du Colombier * Handle case where the command is empty due to failed
4347dd7cddfSDavid du Colombier * command substitution, eg, eval "$(false)".
4357dd7cddfSDavid du Colombier * In this case, shell() will not set/change exstat (because
4367dd7cddfSDavid du Colombier * compiled tree is empty), so will use this value.
4377dd7cddfSDavid du Colombier * subst_exstat is cleared in execute(), so should be 0 if
4387dd7cddfSDavid du Colombier * there were no substitutions.
4397dd7cddfSDavid du Colombier *
4407dd7cddfSDavid du Colombier * A strict reading of POSIX says we don't do this (though
4417dd7cddfSDavid du Colombier * it is traditionally done). [from 1003.2-1992]
4427dd7cddfSDavid du Colombier * 3.9.1: Simple Commands
4437dd7cddfSDavid du Colombier * ... If there is a command name, execution shall
4447dd7cddfSDavid du Colombier * continue as described in 3.9.1.1. If there
4457dd7cddfSDavid du Colombier * is no command name, but the command contained a command
4467dd7cddfSDavid du Colombier * substitution, the command shall complete with the exit
4477dd7cddfSDavid du Colombier * status of the last command substitution
4487dd7cddfSDavid du Colombier * 3.9.1.1: Command Search and Execution
4497dd7cddfSDavid du Colombier * ...(1)...(a) If the command name matches the name of
4507dd7cddfSDavid du Colombier * a special built-in utility, that special built-in
4517dd7cddfSDavid du Colombier * utility shall be invoked.
4527dd7cddfSDavid du Colombier * 3.14.5: Eval
4537dd7cddfSDavid du Colombier * ... If there are no arguments, or only null arguments,
4547dd7cddfSDavid du Colombier * eval shall return an exit status of zero.
4557dd7cddfSDavid du Colombier */
4567dd7cddfSDavid du Colombier exstat = subst_exstat;
4577dd7cddfSDavid du Colombier }
4587dd7cddfSDavid du Colombier
4597dd7cddfSDavid du Colombier return shell(s, FALSE);
4607dd7cddfSDavid du Colombier }
4617dd7cddfSDavid du Colombier
4627dd7cddfSDavid du Colombier int
c_trap(wp)4637dd7cddfSDavid du Colombier c_trap(wp)
4647dd7cddfSDavid du Colombier char **wp;
4657dd7cddfSDavid du Colombier {
4667dd7cddfSDavid du Colombier int i;
4677dd7cddfSDavid du Colombier char *s;
4687dd7cddfSDavid du Colombier register Trap *p;
4697dd7cddfSDavid du Colombier
4707dd7cddfSDavid du Colombier if (ksh_getopt(wp, &builtin_opt, null) == '?')
4717dd7cddfSDavid du Colombier return 1;
4727dd7cddfSDavid du Colombier wp += builtin_opt.optind;
4737dd7cddfSDavid du Colombier
4747dd7cddfSDavid du Colombier if (*wp == NULL) {
4757dd7cddfSDavid du Colombier int anydfl = 0;
4767dd7cddfSDavid du Colombier
4777dd7cddfSDavid du Colombier for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++) {
4787dd7cddfSDavid du Colombier if (p->trap == NULL)
4797dd7cddfSDavid du Colombier anydfl = 1;
4807dd7cddfSDavid du Colombier else {
4817dd7cddfSDavid du Colombier shprintf("trap -- ");
4827dd7cddfSDavid du Colombier print_value_quoted(p->trap);
4837dd7cddfSDavid du Colombier shprintf(" %s\n", p->name);
4847dd7cddfSDavid du Colombier }
4857dd7cddfSDavid du Colombier }
4867dd7cddfSDavid du Colombier #if 0 /* this is ugly and not clear POSIX needs it */
4877dd7cddfSDavid du Colombier /* POSIX may need this so output of trap can be saved and
4887dd7cddfSDavid du Colombier * used to restore trap conditions
4897dd7cddfSDavid du Colombier */
4907dd7cddfSDavid du Colombier if (anydfl) {
4917dd7cddfSDavid du Colombier shprintf("trap -- -");
4927dd7cddfSDavid du Colombier for (p = sigtraps, i = SIGNALS+1; --i >= 0; p++)
4937dd7cddfSDavid du Colombier if (p->trap == NULL && p->name)
4947dd7cddfSDavid du Colombier shprintf(" %s", p->name);
4957dd7cddfSDavid du Colombier shprintf(newline);
4967dd7cddfSDavid du Colombier }
4977dd7cddfSDavid du Colombier #endif
4987dd7cddfSDavid du Colombier return 0;
4997dd7cddfSDavid du Colombier }
5007dd7cddfSDavid du Colombier
5017dd7cddfSDavid du Colombier /*
5027dd7cddfSDavid du Colombier * Use case sensitive lookup for first arg so the
5037dd7cddfSDavid du Colombier * command 'exit' isn't confused with the pseudo-signal
5047dd7cddfSDavid du Colombier * 'EXIT'.
5057dd7cddfSDavid du Colombier */
5067dd7cddfSDavid du Colombier s = (gettrap(*wp, FALSE) == NULL) ? *wp++ : NULL; /* get command */
5077dd7cddfSDavid du Colombier if (s != NULL && s[0] == '-' && s[1] == '\0')
5087dd7cddfSDavid du Colombier s = NULL;
5097dd7cddfSDavid du Colombier
5107dd7cddfSDavid du Colombier /* set/clear traps */
5117dd7cddfSDavid du Colombier while (*wp != NULL) {
5127dd7cddfSDavid du Colombier p = gettrap(*wp++, TRUE);
5137dd7cddfSDavid du Colombier if (p == NULL) {
5147dd7cddfSDavid du Colombier bi_errorf("bad signal %s", wp[-1]);
5157dd7cddfSDavid du Colombier return 1;
5167dd7cddfSDavid du Colombier }
5177dd7cddfSDavid du Colombier settrap(p, s);
5187dd7cddfSDavid du Colombier }
5197dd7cddfSDavid du Colombier return 0;
5207dd7cddfSDavid du Colombier }
5217dd7cddfSDavid du Colombier
5227dd7cddfSDavid du Colombier int
c_exitreturn(wp)5237dd7cddfSDavid du Colombier c_exitreturn(wp)
5247dd7cddfSDavid du Colombier char **wp;
5257dd7cddfSDavid du Colombier {
5267dd7cddfSDavid du Colombier int how = LEXIT;
5277dd7cddfSDavid du Colombier int n;
5287dd7cddfSDavid du Colombier char *arg;
5297dd7cddfSDavid du Colombier
5307dd7cddfSDavid du Colombier if (ksh_getopt(wp, &builtin_opt, null) == '?')
5317dd7cddfSDavid du Colombier return 1;
5327dd7cddfSDavid du Colombier arg = wp[builtin_opt.optind];
5337dd7cddfSDavid du Colombier
5347dd7cddfSDavid du Colombier if (arg) {
5357dd7cddfSDavid du Colombier if (!getn(arg, &n)) {
5367dd7cddfSDavid du Colombier exstat = 1;
5377dd7cddfSDavid du Colombier warningf(TRUE, "%s: bad number", arg);
5387dd7cddfSDavid du Colombier } else
5397dd7cddfSDavid du Colombier exstat = n;
5407dd7cddfSDavid du Colombier }
5417dd7cddfSDavid du Colombier if (wp[0][0] == 'r') { /* return */
5427dd7cddfSDavid du Colombier struct env *ep;
5437dd7cddfSDavid du Colombier
5447dd7cddfSDavid du Colombier /* need to tell if this is exit or return so trap exit will
5457dd7cddfSDavid du Colombier * work right (POSIX)
5467dd7cddfSDavid du Colombier */
5477dd7cddfSDavid du Colombier for (ep = e; ep; ep = ep->oenv)
5487dd7cddfSDavid du Colombier if (STOP_RETURN(ep->type)) {
5497dd7cddfSDavid du Colombier how = LRETURN;
5507dd7cddfSDavid du Colombier break;
5517dd7cddfSDavid du Colombier }
5527dd7cddfSDavid du Colombier }
5537dd7cddfSDavid du Colombier
5547dd7cddfSDavid du Colombier if (how == LEXIT && !really_exit && j_stopped_running()) {
5557dd7cddfSDavid du Colombier really_exit = 1;
5567dd7cddfSDavid du Colombier how = LSHELL;
5577dd7cddfSDavid du Colombier }
5587dd7cddfSDavid du Colombier
5597dd7cddfSDavid du Colombier quitenv(); /* get rid of any i/o redirections */
5607dd7cddfSDavid du Colombier unwind(how);
5617dd7cddfSDavid du Colombier /*NOTREACHED*/
5627dd7cddfSDavid du Colombier return 0;
5637dd7cddfSDavid du Colombier }
5647dd7cddfSDavid du Colombier
5657dd7cddfSDavid du Colombier int
c_brkcont(wp)5667dd7cddfSDavid du Colombier c_brkcont(wp)
5677dd7cddfSDavid du Colombier char **wp;
5687dd7cddfSDavid du Colombier {
5697dd7cddfSDavid du Colombier int n, quit;
5707dd7cddfSDavid du Colombier struct env *ep, *last_ep = (struct env *) 0;
5717dd7cddfSDavid du Colombier char *arg;
5727dd7cddfSDavid du Colombier
5737dd7cddfSDavid du Colombier if (ksh_getopt(wp, &builtin_opt, null) == '?')
5747dd7cddfSDavid du Colombier return 1;
5757dd7cddfSDavid du Colombier arg = wp[builtin_opt.optind];
5767dd7cddfSDavid du Colombier
5777dd7cddfSDavid du Colombier if (!arg)
5787dd7cddfSDavid du Colombier n = 1;
5797dd7cddfSDavid du Colombier else if (!bi_getn(arg, &n))
5807dd7cddfSDavid du Colombier return 1;
5817dd7cddfSDavid du Colombier quit = n;
5827dd7cddfSDavid du Colombier if (quit <= 0) {
5837dd7cddfSDavid du Colombier /* at&t ksh does this for non-interactive shells only - weird */
5847dd7cddfSDavid du Colombier bi_errorf("%s: bad value", arg);
5857dd7cddfSDavid du Colombier return 1;
5867dd7cddfSDavid du Colombier }
5877dd7cddfSDavid du Colombier
5887dd7cddfSDavid du Colombier /* Stop at E_NONE, E_PARSE, E_FUNC, or E_INCL */
5897dd7cddfSDavid du Colombier for (ep = e; ep && !STOP_BRKCONT(ep->type); ep = ep->oenv)
5907dd7cddfSDavid du Colombier if (ep->type == E_LOOP) {
5917dd7cddfSDavid du Colombier if (--quit == 0)
5927dd7cddfSDavid du Colombier break;
5937dd7cddfSDavid du Colombier ep->flags |= EF_BRKCONT_PASS;
5947dd7cddfSDavid du Colombier last_ep = ep;
5957dd7cddfSDavid du Colombier }
5967dd7cddfSDavid du Colombier
5977dd7cddfSDavid du Colombier if (quit) {
5987dd7cddfSDavid du Colombier /* at&t ksh doesn't print a message - just does what it
5997dd7cddfSDavid du Colombier * can. We print a message 'cause it helps in debugging
6007dd7cddfSDavid du Colombier * scripts, but don't generate an error (ie, keep going).
6017dd7cddfSDavid du Colombier */
6027dd7cddfSDavid du Colombier if (n == quit) {
6037dd7cddfSDavid du Colombier warningf(TRUE, "%s: cannot %s", wp[0], wp[0]);
6047dd7cddfSDavid du Colombier return 0;
6057dd7cddfSDavid du Colombier }
6067dd7cddfSDavid du Colombier /* POSIX says if n is too big, the last enclosing loop
6077dd7cddfSDavid du Colombier * shall be used. Doesn't say to print an error but we
6087dd7cddfSDavid du Colombier * do anyway 'cause the user messed up.
6097dd7cddfSDavid du Colombier */
6107dd7cddfSDavid du Colombier last_ep->flags &= ~EF_BRKCONT_PASS;
6117dd7cddfSDavid du Colombier warningf(TRUE, "%s: can only %s %d level(s)",
6127dd7cddfSDavid du Colombier wp[0], wp[0], n - quit);
6137dd7cddfSDavid du Colombier }
6147dd7cddfSDavid du Colombier
6157dd7cddfSDavid du Colombier unwind(*wp[0] == 'b' ? LBREAK : LCONTIN);
6167dd7cddfSDavid du Colombier /*NOTREACHED*/
617*027288c8SDavid du Colombier return 0;
6187dd7cddfSDavid du Colombier }
6197dd7cddfSDavid du Colombier
6207dd7cddfSDavid du Colombier int
c_set(wp)6217dd7cddfSDavid du Colombier c_set(wp)
6227dd7cddfSDavid du Colombier char **wp;
6237dd7cddfSDavid du Colombier {
6247dd7cddfSDavid du Colombier int argi, setargs;
6257dd7cddfSDavid du Colombier struct block *l = e->loc;
6267dd7cddfSDavid du Colombier register char **owp = wp;
6277dd7cddfSDavid du Colombier
6287dd7cddfSDavid du Colombier if (wp[1] == NULL) {
6297dd7cddfSDavid du Colombier static const char *const args [] = { "set", "-", NULL };
6307dd7cddfSDavid du Colombier return c_typeset((char **) args);
6317dd7cddfSDavid du Colombier }
6327dd7cddfSDavid du Colombier
6337dd7cddfSDavid du Colombier argi = parse_args(wp, OF_SET, &setargs);
6347dd7cddfSDavid du Colombier if (argi < 0)
6357dd7cddfSDavid du Colombier return 1;
6367dd7cddfSDavid du Colombier /* set $# and $* */
6377dd7cddfSDavid du Colombier if (setargs) {
6387dd7cddfSDavid du Colombier owp = wp += argi - 1;
6397dd7cddfSDavid du Colombier wp[0] = l->argv[0]; /* save $0 */
6407dd7cddfSDavid du Colombier while (*++wp != NULL)
6417dd7cddfSDavid du Colombier *wp = str_save(*wp, &l->area);
6427dd7cddfSDavid du Colombier l->argc = wp - owp - 1;
6437dd7cddfSDavid du Colombier l->argv = (char **) alloc(sizeofN(char *, l->argc+2), &l->area);
6447dd7cddfSDavid du Colombier for (wp = l->argv; (*wp++ = *owp++) != NULL; )
6457dd7cddfSDavid du Colombier ;
6467dd7cddfSDavid du Colombier }
6477dd7cddfSDavid du Colombier /* POSIX says set exit status is 0, but old scripts that use
6487dd7cddfSDavid du Colombier * getopt(1), use the construct: set -- `getopt ab:c "$@"`
6497dd7cddfSDavid du Colombier * which assumes the exit value set will be that of the ``
6507dd7cddfSDavid du Colombier * (subst_exstat is cleared in execute() so that it will be 0
6517dd7cddfSDavid du Colombier * if there are no command substitutions).
6527dd7cddfSDavid du Colombier */
6537dd7cddfSDavid du Colombier return Flag(FPOSIX) ? 0 : subst_exstat;
6547dd7cddfSDavid du Colombier }
6557dd7cddfSDavid du Colombier
6567dd7cddfSDavid du Colombier int
c_unset(wp)6577dd7cddfSDavid du Colombier c_unset(wp)
6587dd7cddfSDavid du Colombier char **wp;
6597dd7cddfSDavid du Colombier {
6607dd7cddfSDavid du Colombier register char *id;
6617dd7cddfSDavid du Colombier int optc, unset_var = 1;
6627dd7cddfSDavid du Colombier int ret = 0;
6637dd7cddfSDavid du Colombier
6647dd7cddfSDavid du Colombier while ((optc = ksh_getopt(wp, &builtin_opt, "fv")) != EOF)
6657dd7cddfSDavid du Colombier switch (optc) {
6667dd7cddfSDavid du Colombier case 'f':
6677dd7cddfSDavid du Colombier unset_var = 0;
6687dd7cddfSDavid du Colombier break;
6697dd7cddfSDavid du Colombier case 'v':
6707dd7cddfSDavid du Colombier unset_var = 1;
6717dd7cddfSDavid du Colombier break;
6727dd7cddfSDavid du Colombier case '?':
6737dd7cddfSDavid du Colombier return 1;
6747dd7cddfSDavid du Colombier }
6757dd7cddfSDavid du Colombier wp += builtin_opt.optind;
6767dd7cddfSDavid du Colombier for (; (id = *wp) != NULL; wp++)
6777dd7cddfSDavid du Colombier if (unset_var) { /* unset variable */
6787dd7cddfSDavid du Colombier struct tbl *vp = global(id);
6797dd7cddfSDavid du Colombier
6807dd7cddfSDavid du Colombier if (!(vp->flag & ISSET))
6817dd7cddfSDavid du Colombier ret = 1;
6827dd7cddfSDavid du Colombier if ((vp->flag&RDONLY)) {
6837dd7cddfSDavid du Colombier bi_errorf("%s is read only", vp->name);
6847dd7cddfSDavid du Colombier return 1;
6857dd7cddfSDavid du Colombier }
6867dd7cddfSDavid du Colombier unset(vp, strchr(id, '[') ? 1 : 0);
6877dd7cddfSDavid du Colombier } else { /* unset function */
6887dd7cddfSDavid du Colombier if (define(id, (struct op *) NULL))
6897dd7cddfSDavid du Colombier ret = 1;
6907dd7cddfSDavid du Colombier }
6917dd7cddfSDavid du Colombier return ret;
6927dd7cddfSDavid du Colombier }
6937dd7cddfSDavid du Colombier
6947dd7cddfSDavid du Colombier int
c_times(wp)6957dd7cddfSDavid du Colombier c_times(wp)
6967dd7cddfSDavid du Colombier char **wp;
6977dd7cddfSDavid du Colombier {
6987dd7cddfSDavid du Colombier struct tms all;
6997dd7cddfSDavid du Colombier
7007dd7cddfSDavid du Colombier (void) ksh_times(&all);
7017dd7cddfSDavid du Colombier shprintf("Shell: %8ss user ", clocktos(all.tms_utime));
7027dd7cddfSDavid du Colombier shprintf("%8ss system\n", clocktos(all.tms_stime));
7037dd7cddfSDavid du Colombier shprintf("Kids: %8ss user ", clocktos(all.tms_cutime));
7047dd7cddfSDavid du Colombier shprintf("%8ss system\n", clocktos(all.tms_cstime));
7057dd7cddfSDavid du Colombier
7067dd7cddfSDavid du Colombier return 0;
7077dd7cddfSDavid du Colombier }
7087dd7cddfSDavid du Colombier
7097dd7cddfSDavid du Colombier /*
7107dd7cddfSDavid du Colombier * time pipeline (really a statement, not a built-in command)
7117dd7cddfSDavid du Colombier */
7127dd7cddfSDavid du Colombier int
timex(t,f)7137dd7cddfSDavid du Colombier timex(t, f)
7147dd7cddfSDavid du Colombier struct op *t;
7157dd7cddfSDavid du Colombier int f;
7167dd7cddfSDavid du Colombier {
7177dd7cddfSDavid du Colombier #define TF_NOARGS BIT(0)
7187dd7cddfSDavid du Colombier #define TF_NOREAL BIT(1) /* don't report real time */
7197dd7cddfSDavid du Colombier #define TF_POSIX BIT(2) /* report in posix format */
7207dd7cddfSDavid du Colombier int rv = 0;
7217dd7cddfSDavid du Colombier struct tms t0, t1, tms;
7227dd7cddfSDavid du Colombier clock_t t0t, t1t = 0;
7237dd7cddfSDavid du Colombier int tf = 0;
7247dd7cddfSDavid du Colombier extern clock_t j_usrtime, j_systime; /* computed by j_wait */
7257dd7cddfSDavid du Colombier char opts[1];
7267dd7cddfSDavid du Colombier
7277dd7cddfSDavid du Colombier t0t = ksh_times(&t0);
7287dd7cddfSDavid du Colombier if (t->left) {
7297dd7cddfSDavid du Colombier /*
7307dd7cddfSDavid du Colombier * Two ways of getting cpu usage of a command: just use t0
7317dd7cddfSDavid du Colombier * and t1 (which will get cpu usage from other jobs that
7327dd7cddfSDavid du Colombier * finish while we are executing t->left), or get the
7337dd7cddfSDavid du Colombier * cpu usage of t->left. at&t ksh does the former, while
7347dd7cddfSDavid du Colombier * pdksh tries to do the later (the j_usrtime hack doesn't
7357dd7cddfSDavid du Colombier * really work as it only counts the last job).
7367dd7cddfSDavid du Colombier */
7377dd7cddfSDavid du Colombier j_usrtime = j_systime = 0;
7387dd7cddfSDavid du Colombier if (t->left->type == TCOM)
7397dd7cddfSDavid du Colombier t->left->str = opts;
7407dd7cddfSDavid du Colombier opts[0] = 0;
7417dd7cddfSDavid du Colombier rv = execute(t->left, f | XTIME);
7427dd7cddfSDavid du Colombier tf |= opts[0];
7437dd7cddfSDavid du Colombier t1t = ksh_times(&t1);
7447dd7cddfSDavid du Colombier } else
7457dd7cddfSDavid du Colombier tf = TF_NOARGS;
7467dd7cddfSDavid du Colombier
7477dd7cddfSDavid du Colombier if (tf & TF_NOARGS) { /* ksh93 - report shell times (shell+kids) */
7487dd7cddfSDavid du Colombier tf |= TF_NOREAL;
7497dd7cddfSDavid du Colombier tms.tms_utime = t0.tms_utime + t0.tms_cutime;
7507dd7cddfSDavid du Colombier tms.tms_stime = t0.tms_stime + t0.tms_cstime;
7517dd7cddfSDavid du Colombier } else {
7527dd7cddfSDavid du Colombier tms.tms_utime = t1.tms_utime - t0.tms_utime + j_usrtime;
7537dd7cddfSDavid du Colombier tms.tms_stime = t1.tms_stime - t0.tms_stime + j_systime;
7547dd7cddfSDavid du Colombier }
7557dd7cddfSDavid du Colombier
7567dd7cddfSDavid du Colombier if (!(tf & TF_NOREAL))
7577dd7cddfSDavid du Colombier shf_fprintf(shl_out,
7587dd7cddfSDavid du Colombier tf & TF_POSIX ? "real %8s\n" : "%8ss real ",
7597dd7cddfSDavid du Colombier clocktos(t1t - t0t));
7607dd7cddfSDavid du Colombier shf_fprintf(shl_out, tf & TF_POSIX ? "user %8s\n" : "%8ss user ",
7617dd7cddfSDavid du Colombier clocktos(tms.tms_utime));
7627dd7cddfSDavid du Colombier shf_fprintf(shl_out, tf & TF_POSIX ? "sys %8s\n" : "%8ss system\n",
7637dd7cddfSDavid du Colombier clocktos(tms.tms_stime));
7647dd7cddfSDavid du Colombier shf_flush(shl_out);
7657dd7cddfSDavid du Colombier
7667dd7cddfSDavid du Colombier return rv;
7677dd7cddfSDavid du Colombier }
7687dd7cddfSDavid du Colombier
7697dd7cddfSDavid du Colombier void
timex_hook(t,app)7707dd7cddfSDavid du Colombier timex_hook(t, app)
7717dd7cddfSDavid du Colombier struct op *t;
7727dd7cddfSDavid du Colombier char ** volatile *app;
7737dd7cddfSDavid du Colombier {
7747dd7cddfSDavid du Colombier char **wp = *app;
7757dd7cddfSDavid du Colombier int optc;
7767dd7cddfSDavid du Colombier int i, j;
7777dd7cddfSDavid du Colombier Getopt opt;
7787dd7cddfSDavid du Colombier
7797dd7cddfSDavid du Colombier ksh_getopt_reset(&opt, 0);
7807dd7cddfSDavid du Colombier opt.optind = 0; /* start at the start */
7817dd7cddfSDavid du Colombier while ((optc = ksh_getopt(wp, &opt, ":p")) != EOF)
7827dd7cddfSDavid du Colombier switch (optc) {
7837dd7cddfSDavid du Colombier case 'p':
7847dd7cddfSDavid du Colombier t->str[0] |= TF_POSIX;
7857dd7cddfSDavid du Colombier break;
7867dd7cddfSDavid du Colombier case '?':
7877dd7cddfSDavid du Colombier errorf("time: -%s unknown option", opt.optarg);
7887dd7cddfSDavid du Colombier case ':':
7897dd7cddfSDavid du Colombier errorf("time: -%s requires an argument",
7907dd7cddfSDavid du Colombier opt.optarg);
7917dd7cddfSDavid du Colombier }
7927dd7cddfSDavid du Colombier /* Copy command words down over options. */
7937dd7cddfSDavid du Colombier if (opt.optind != 0) {
7947dd7cddfSDavid du Colombier for (i = 0; i < opt.optind; i++)
7957dd7cddfSDavid du Colombier afree(wp[i], ATEMP);
7967dd7cddfSDavid du Colombier for (i = 0, j = opt.optind; (wp[i] = wp[j]); i++, j++)
7977dd7cddfSDavid du Colombier ;
7987dd7cddfSDavid du Colombier }
7997dd7cddfSDavid du Colombier if (!wp[0])
8007dd7cddfSDavid du Colombier t->str[0] |= TF_NOARGS;
8017dd7cddfSDavid du Colombier *app = wp;
8027dd7cddfSDavid du Colombier }
8037dd7cddfSDavid du Colombier
8047dd7cddfSDavid du Colombier static char *
clocktos(t)8057dd7cddfSDavid du Colombier clocktos(t)
8067dd7cddfSDavid du Colombier clock_t t;
8077dd7cddfSDavid du Colombier {
8087dd7cddfSDavid du Colombier static char temp[22]; /* enough for 64 bit clock_t */
8097dd7cddfSDavid du Colombier register int i;
8107dd7cddfSDavid du Colombier register char *cp = temp + sizeof(temp);
8117dd7cddfSDavid du Colombier
8127dd7cddfSDavid du Colombier /* note: posix says must use max precision, ie, if clk_tck is
8137dd7cddfSDavid du Colombier * 1000, must print 3 places after decimal (if non-zero, else 1).
8147dd7cddfSDavid du Colombier */
8157dd7cddfSDavid du Colombier if (CLK_TCK != 100) /* convert to 1/100'ths */
8167dd7cddfSDavid du Colombier t = (t < 1000000000/CLK_TCK) ?
8177dd7cddfSDavid du Colombier (t * 100) / CLK_TCK : (t / CLK_TCK) * 100;
8187dd7cddfSDavid du Colombier
8197dd7cddfSDavid du Colombier *--cp = '\0';
8207dd7cddfSDavid du Colombier for (i = -2; i <= 0 || t > 0; i++) {
8217dd7cddfSDavid du Colombier if (i == 0)
8227dd7cddfSDavid du Colombier *--cp = '.';
8237dd7cddfSDavid du Colombier *--cp = '0' + (char)(t%10);
8247dd7cddfSDavid du Colombier t /= 10;
8257dd7cddfSDavid du Colombier }
8267dd7cddfSDavid du Colombier return cp;
8277dd7cddfSDavid du Colombier }
8287dd7cddfSDavid du Colombier
8297dd7cddfSDavid du Colombier /* exec with no args - args case is taken care of in comexec() */
8307dd7cddfSDavid du Colombier int
c_exec(wp)8317dd7cddfSDavid du Colombier c_exec(wp)
8327dd7cddfSDavid du Colombier char ** wp;
8337dd7cddfSDavid du Colombier {
8347dd7cddfSDavid du Colombier int i;
8357dd7cddfSDavid du Colombier
8367dd7cddfSDavid du Colombier /* make sure redirects stay in place */
8377dd7cddfSDavid du Colombier if (e->savefd != NULL) {
8387dd7cddfSDavid du Colombier for (i = 0; i < NUFILE; i++) {
8397dd7cddfSDavid du Colombier if (e->savefd[i] > 0)
8407dd7cddfSDavid du Colombier close(e->savefd[i]);
8417dd7cddfSDavid du Colombier /*
8427dd7cddfSDavid du Colombier * For ksh keep anything > 2 private,
8437dd7cddfSDavid du Colombier * for sh, let them be (POSIX says what
8447dd7cddfSDavid du Colombier * happens is unspecified and the bourne shell
8457dd7cddfSDavid du Colombier * keeps them open).
8467dd7cddfSDavid du Colombier */
8477dd7cddfSDavid du Colombier #ifdef KSH
8487dd7cddfSDavid du Colombier if (i > 2 && e->savefd[i])
8497dd7cddfSDavid du Colombier fd_clexec(i);
8507dd7cddfSDavid du Colombier #endif /* KSH */
8517dd7cddfSDavid du Colombier }
8527dd7cddfSDavid du Colombier e->savefd = NULL;
8537dd7cddfSDavid du Colombier }
8547dd7cddfSDavid du Colombier return 0;
8557dd7cddfSDavid du Colombier }
8567dd7cddfSDavid du Colombier
8577dd7cddfSDavid du Colombier /* dummy function, special case in comexec() */
8587dd7cddfSDavid du Colombier int
c_builtin(wp)8597dd7cddfSDavid du Colombier c_builtin(wp)
8607dd7cddfSDavid du Colombier char ** wp;
8617dd7cddfSDavid du Colombier {
8627dd7cddfSDavid du Colombier return 0;
8637dd7cddfSDavid du Colombier }
8647dd7cddfSDavid du Colombier
8657dd7cddfSDavid du Colombier extern int c_test ARGS((char **wp)); /* in c_test.c */
8667dd7cddfSDavid du Colombier extern int c_ulimit ARGS((char **wp)); /* in c_ulimit.c */
8677dd7cddfSDavid du Colombier
8687dd7cddfSDavid du Colombier /* A leading = means assignments before command are kept;
8697dd7cddfSDavid du Colombier * a leading * means a POSIX special builtin;
8707dd7cddfSDavid du Colombier * a leading + means a POSIX regular builtin
8717dd7cddfSDavid du Colombier * (* and + should not be combined).
8727dd7cddfSDavid du Colombier */
8737dd7cddfSDavid du Colombier const struct builtin shbuiltins [] = {
8747dd7cddfSDavid du Colombier {"*=.", c_dot},
8757dd7cddfSDavid du Colombier {"*=:", c_label},
8767dd7cddfSDavid du Colombier {"[", c_test},
8777dd7cddfSDavid du Colombier {"*=break", c_brkcont},
8787dd7cddfSDavid du Colombier {"=builtin", c_builtin},
8797dd7cddfSDavid du Colombier {"*=continue", c_brkcont},
8807dd7cddfSDavid du Colombier {"*=eval", c_eval},
8817dd7cddfSDavid du Colombier {"*=exec", c_exec},
8827dd7cddfSDavid du Colombier {"*=exit", c_exitreturn},
8837dd7cddfSDavid du Colombier {"+false", c_label},
8847dd7cddfSDavid du Colombier {"*=return", c_exitreturn},
8857dd7cddfSDavid du Colombier {"*=set", c_set},
8867dd7cddfSDavid du Colombier {"*=shift", c_shift},
8877dd7cddfSDavid du Colombier {"=times", c_times},
8887dd7cddfSDavid du Colombier {"*=trap", c_trap},
8897dd7cddfSDavid du Colombier {"+=wait", c_wait},
8907dd7cddfSDavid du Colombier {"+read", c_read},
8917dd7cddfSDavid du Colombier {"test", c_test},
8927dd7cddfSDavid du Colombier {"+true", c_label},
8937dd7cddfSDavid du Colombier {"ulimit", c_ulimit},
8947dd7cddfSDavid du Colombier {"+umask", c_umask},
8957dd7cddfSDavid du Colombier {"*=unset", c_unset},
8967dd7cddfSDavid du Colombier #ifdef OS2
8977dd7cddfSDavid du Colombier /* In OS2, the first line of a file can be "extproc name", which
8987dd7cddfSDavid du Colombier * tells the command interpreter (cmd.exe) to use name to execute
8997dd7cddfSDavid du Colombier * the file. For this to be useful, ksh must ignore commands
9007dd7cddfSDavid du Colombier * starting with extproc and this does the trick...
9017dd7cddfSDavid du Colombier */
9027dd7cddfSDavid du Colombier {"extproc", c_label},
9037dd7cddfSDavid du Colombier #endif /* OS2 */
9047dd7cddfSDavid du Colombier {NULL, NULL}
9057dd7cddfSDavid du Colombier };
906