xref: /plan9/sys/src/ape/cmd/pdksh/c_sh.c (revision 027288c8a8763d34db13dc89d8bcd6514dbc2163)
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