add a sleep builtin that can deal with fractions too
This commit is contained in:
		
							
								
								
									
										57
									
								
								funcs.c
									
									
									
									
									
								
							
							
						
						
									
										57
									
								
								funcs.c
									
									
									
									
									
								
							| @@ -26,7 +26,19 @@ | |||||||
|  |  | ||||||
| #include "sh.h" | #include "sh.h" | ||||||
|  |  | ||||||
| __RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.168 2011/01/30 01:35:58 tg Exp $"); | #if HAVE_SELECT | ||||||
|  | #if HAVE_SYS_BSDTYPES_H | ||||||
|  | #include <sys/bsdtypes.h> | ||||||
|  | #endif | ||||||
|  | #if HAVE_SYS_SELECT_H | ||||||
|  | #include <sys/select.h> | ||||||
|  | #endif | ||||||
|  | #if HAVE_BSTRING_H | ||||||
|  | #include <bstring.h> | ||||||
|  | #endif | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | __RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.169 2011/02/11 00:41:34 tg Exp $"); | ||||||
|  |  | ||||||
| #if HAVE_KILLPG | #if HAVE_KILLPG | ||||||
| /* | /* | ||||||
| @@ -112,6 +124,9 @@ const struct builtin mkshbuiltins[] = { | |||||||
| #endif | #endif | ||||||
| 	{"realpath", c_realpath}, | 	{"realpath", c_realpath}, | ||||||
| 	{"rename", c_rename}, | 	{"rename", c_rename}, | ||||||
|  | #if HAVE_SELECT | ||||||
|  | 	{"sleep", c_sleep}, | ||||||
|  | #endif | ||||||
| 	{NULL, (int (*)(const char **))NULL} | 	{NULL, (int (*)(const char **))NULL} | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -3647,3 +3662,43 @@ c_cat(const char **wp) | |||||||
| 	free(buf); | 	free(buf); | ||||||
| 	return (rv); | 	return (rv); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #if HAVE_SELECT | ||||||
|  | int | ||||||
|  | c_sleep(const char **wp) | ||||||
|  | { | ||||||
|  | 	struct timeval tv; | ||||||
|  | 	int rv = 1; | ||||||
|  |  | ||||||
|  | 	/* skip argv[0] */ | ||||||
|  | 	++wp; | ||||||
|  | 	if (wp[0] && !strcmp(wp[0], "--")) | ||||||
|  | 		/* skip "--" (options separator) */ | ||||||
|  | 		++wp; | ||||||
|  |  | ||||||
|  | 	if (!wp[0] || wp[1]) | ||||||
|  | 		bi_errorf(T_synerr); | ||||||
|  | 	else if (parse_usec(wp[0], &tv)) | ||||||
|  | 		bi_errorf("%s: %s '%s'", T_synerr, strerror(errno), wp[0]); | ||||||
|  | 	else { | ||||||
|  | #ifndef MKSH_NOPROSPECTOFWORK | ||||||
|  | 		sigset_t omask; | ||||||
|  |  | ||||||
|  | 		/* block SIGCHLD from interrupting us, though */ | ||||||
|  | 		sigprocmask(SIG_BLOCK, &sm_sigchld, &omask); | ||||||
|  | #endif | ||||||
|  | 		if (select(0, NULL, NULL, NULL, &tv) == 0 || errno == EINTR) | ||||||
|  | 			/* | ||||||
|  | 			 * strictly speaking only for SIGALRM, but the | ||||||
|  | 			 * execution may be interrupted by other signals | ||||||
|  | 			 */ | ||||||
|  | 			rv = 0; | ||||||
|  | 		else | ||||||
|  | 			bi_errorf("%s: %s", T_select, strerror(errno)); | ||||||
|  | #ifndef MKSH_NOPROSPECTOFWORK | ||||||
|  | 		sigprocmask(SIG_BLOCK, &omask, NULL); | ||||||
|  | #endif | ||||||
|  | 	} | ||||||
|  | 	return (rv); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|   | |||||||
							
								
								
									
										11
									
								
								mksh.1
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								mksh.1
									
									
									
									
									
								
							| @@ -1,4 +1,4 @@ | |||||||
| .\" $MirOS: src/bin/mksh/mksh.1,v 1.248 2011/02/09 13:08:18 tg Exp $ | .\" $MirOS: src/bin/mksh/mksh.1,v 1.249 2011/02/11 00:41:35 tg Exp $ | ||||||
| .\" $OpenBSD: ksh.1,v 1.138 2010/09/20 07:41:17 jmc Exp $ | .\" $OpenBSD: ksh.1,v 1.138 2010/09/20 07:41:17 jmc Exp $ | ||||||
| .\"- | .\"- | ||||||
| .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, | .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, | ||||||
| @@ -72,7 +72,7 @@ | |||||||
| .\" with -mandoc, it might implement .Mx itself, but we want to | .\" with -mandoc, it might implement .Mx itself, but we want to | ||||||
| .\" use our own definition. And .Dd must come *first*, always. | .\" use our own definition. And .Dd must come *first*, always. | ||||||
| .\" | .\" | ||||||
| .Dd $Mdocdate: February 9 2011 $ | .Dd $Mdocdate: February 11 2011 $ | ||||||
| .\" | .\" | ||||||
| .\" Check which macro package we use | .\" Check which macro package we use | ||||||
| .\" | .\" | ||||||
| @@ -2805,7 +2805,7 @@ regular commands | |||||||
| .Ic \&[ , chdir , bind , cat , | .Ic \&[ , chdir , bind , cat , | ||||||
| .Ic echo , let , mknod , print , | .Ic echo , let , mknod , print , | ||||||
| .Ic printf , pwd , realpath , rename , | .Ic printf , pwd , realpath , rename , | ||||||
| .Ic test , ulimit , whence | .Ic sleep , test , ulimit , whence | ||||||
| .Pp | .Pp | ||||||
| In the future, the additional | In the future, the additional | ||||||
| .Nm | .Nm | ||||||
| @@ -4047,6 +4047,11 @@ etc. | |||||||
| .Ar number | .Ar number | ||||||
| defaults to 1. | defaults to 1. | ||||||
| .Pp | .Pp | ||||||
|  | .It Ic sleep Ar seconds | ||||||
|  | Suspends execution for a minimum of the | ||||||
|  | .Ar seconds | ||||||
|  | specified as positive decimal value with an optional fractional part. | ||||||
|  | Signal delivery may continue execution earlier. | ||||||
| .It Ic source Ar file Op Ar arg ... | .It Ic source Ar file Op Ar arg ... | ||||||
| Like | Like | ||||||
| .Ic \&. Po Do dot Dc Pc , | .Ic \&. Po Do dot Dc Pc , | ||||||
|   | |||||||
							
								
								
									
										7
									
								
								sh.h
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								sh.h
									
									
									
									
									
								
							| @@ -154,7 +154,7 @@ | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #ifdef EXTERN | #ifdef EXTERN | ||||||
| __RCSID("$MirOS: src/bin/mksh/sh.h,v 1.428 2011/02/09 13:08:27 tg Exp $"); | __RCSID("$MirOS: src/bin/mksh/sh.h,v 1.429 2011/02/11 00:41:37 tg Exp $"); | ||||||
| #endif | #endif | ||||||
| #define MKSH_VERSION "R39 2011/02/09" | #define MKSH_VERSION "R39 2011/02/09" | ||||||
|  |  | ||||||
| @@ -626,6 +626,7 @@ EXTERN const char T_oomem[] I__("can't allocate %lu data bytes"); | |||||||
| #else | #else | ||||||
| EXTERN const char T_synerr[] I__("syntax error"); | EXTERN const char T_synerr[] I__("syntax error"); | ||||||
| #endif | #endif | ||||||
|  | EXTERN const char T_select[] I__("select"); | ||||||
| EXTERN const char T_r_fc_e_[] I__("r=fc -e -"); | EXTERN const char T_r_fc_e_[] I__("r=fc -e -"); | ||||||
| #define T_fc_e_		(T_r_fc_e_ + 2)		/* "fc -e -" */ | #define T_fc_e_		(T_r_fc_e_ + 2)		/* "fc -e -" */ | ||||||
| #define Tn_fc_e_	7			/* strlen(T_fc_e_) */ | #define Tn_fc_e_	7			/* strlen(T_fc_e_) */ | ||||||
| @@ -794,7 +795,7 @@ struct coproc { | |||||||
| EXTERN struct coproc coproc; | EXTERN struct coproc coproc; | ||||||
|  |  | ||||||
| #ifndef MKSH_NOPROSPECTOFWORK | #ifndef MKSH_NOPROSPECTOFWORK | ||||||
| /* Used in jobs.c and by coprocess stuff in exec.c */ | /* used in jobs.c and by coprocess stuff in exec.c and select() calls */ | ||||||
| EXTERN sigset_t		sm_default, sm_sigchld; | EXTERN sigset_t		sm_default, sm_sigchld; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| @@ -1526,6 +1527,7 @@ int c_mknod(const char **); | |||||||
| int c_realpath(const char **); | int c_realpath(const char **); | ||||||
| int c_rename(const char **); | int c_rename(const char **); | ||||||
| int c_cat(const char **); | int c_cat(const char **); | ||||||
|  | int c_sleep(const char **); | ||||||
| /* histrap.c */ | /* histrap.c */ | ||||||
| void init_histvec(void); | void init_histvec(void); | ||||||
| void hist_init(Source *); | void hist_init(Source *); | ||||||
| @@ -1703,6 +1705,7 @@ int shf_vfprintf(struct shf *, const char *, va_list) | |||||||
| /* syn.c */ | /* syn.c */ | ||||||
| void initkeywords(void); | void initkeywords(void); | ||||||
| struct op *compile(Source *); | struct op *compile(Source *); | ||||||
|  | bool parse_usec(const char *, struct timeval *); | ||||||
| /* tree.c */ | /* tree.c */ | ||||||
| int fptreef(struct shf *, int, const char *, ...); | int fptreef(struct shf *, int, const char *, ...); | ||||||
| char *snptreef(char *, int, const char *, ...); | char *snptreef(char *, int, const char *, ...); | ||||||
|   | |||||||
							
								
								
									
										66
									
								
								syn.c
									
									
									
									
									
								
							
							
						
						
									
										66
									
								
								syn.c
									
									
									
									
									
								
							| @@ -1,7 +1,7 @@ | |||||||
| /*	$OpenBSD: syn.c,v 1.28 2008/07/23 16:34:38 jaredy Exp $	*/ | /*	$OpenBSD: syn.c,v 1.28 2008/07/23 16:34:38 jaredy Exp $	*/ | ||||||
|  |  | ||||||
| /*- | /*- | ||||||
|  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009 |  * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2011 | ||||||
|  *	Thorsten Glaser <tg@mirbsd.org> |  *	Thorsten Glaser <tg@mirbsd.org> | ||||||
|  * |  * | ||||||
|  * Provided that these terms and disclaimer and all copyright notices |  * Provided that these terms and disclaimer and all copyright notices | ||||||
| @@ -22,7 +22,7 @@ | |||||||
|  |  | ||||||
| #include "sh.h" | #include "sh.h" | ||||||
|  |  | ||||||
| __RCSID("$MirOS: src/bin/mksh/syn.c,v 1.52 2010/09/14 21:26:18 tg Exp $"); | __RCSID("$MirOS: src/bin/mksh/syn.c,v 1.53 2011/02/11 00:41:38 tg Exp $"); | ||||||
|  |  | ||||||
| struct nesting_state { | struct nesting_state { | ||||||
| 	int start_token;	/* token than began nesting (eg, FOR) */ | 	int start_token;	/* token than began nesting (eg, FOR) */ | ||||||
| @@ -405,7 +405,7 @@ get_command(int cf) | |||||||
| 		t = newtp((c == FOR) ? TFOR : TSELECT); | 		t = newtp((c == FOR) ? TFOR : TSELECT); | ||||||
| 		musthave(LWORD, ARRAYVAR); | 		musthave(LWORD, ARRAYVAR); | ||||||
| 		if (!is_wdvarname(yylval.cp, true)) | 		if (!is_wdvarname(yylval.cp, true)) | ||||||
| 			yyerror("%s: %s\n", c == FOR ? "for" : "select", | 			yyerror("%s: %s\n", c == FOR ? "for" : T_select, | ||||||
| 			    "bad identifier"); | 			    "bad identifier"); | ||||||
| 		strdupx(t->str, ident, ATEMP); | 		strdupx(t->str, ident, ATEMP); | ||||||
| 		nesting_push(&old_nesting, c); | 		nesting_push(&old_nesting, c); | ||||||
| @@ -736,7 +736,7 @@ const struct tokeninfo { | |||||||
| 	{ "case",	CASE,	true }, | 	{ "case",	CASE,	true }, | ||||||
| 	{ "esac",	ESAC,	true }, | 	{ "esac",	ESAC,	true }, | ||||||
| 	{ "for",	FOR,	true }, | 	{ "for",	FOR,	true }, | ||||||
| 	{ "select",	SELECT,	true }, | 	{ T_select,	SELECT,	true }, | ||||||
| 	{ "while",	WHILE,	true }, | 	{ "while",	WHILE,	true }, | ||||||
| 	{ "until",	UNTIL,	true }, | 	{ "until",	UNTIL,	true }, | ||||||
| 	{ "do",		DO,	true }, | 	{ "do",		DO,	true }, | ||||||
| @@ -1005,3 +1005,61 @@ dbtestp_error(Test_env *te, int offset, const char *msg) | |||||||
| 	} | 	} | ||||||
| 	syntaxerr(msg); | 	syntaxerr(msg); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | #if HAVE_SELECT | ||||||
|  |  | ||||||
|  | #ifndef EOVERFLOW | ||||||
|  | #ifdef ERANGE | ||||||
|  | #define EOVERFLOW	ERANGE | ||||||
|  | #else | ||||||
|  | #define EOVERFLOW	EINVAL | ||||||
|  | #endif | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | bool | ||||||
|  | parse_usec(const char *s, struct timeval *tv) | ||||||
|  | { | ||||||
|  | 	struct timeval tt; | ||||||
|  | 	int i; | ||||||
|  |  | ||||||
|  | 	tv->tv_sec = 0; | ||||||
|  | 	/* parse integral part */ | ||||||
|  | 	while (ksh_isdigit(*s)) { | ||||||
|  | 		tt.tv_sec = tv->tv_sec * 10 + (*s++ - '0'); | ||||||
|  | 		if (tt.tv_sec / 10 != tv->tv_sec) { | ||||||
|  | 			errno = EOVERFLOW; | ||||||
|  | 			return (true); | ||||||
|  | 		} | ||||||
|  | 		tv->tv_sec = tt.tv_sec; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	tv->tv_usec = 0; | ||||||
|  | 	if (!*s) | ||||||
|  | 		/* no decimal fraction */ | ||||||
|  | 		return (false); | ||||||
|  | 	else if (*s++ != '.') { | ||||||
|  | 		/* junk after integral part */ | ||||||
|  | 		errno = EINVAL; | ||||||
|  | 		return (true); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* parse decimal fraction */ | ||||||
|  | 	i = 100000; | ||||||
|  | 	while (ksh_isdigit(*s)) { | ||||||
|  | 		tv->tv_usec += i * (*s++ - '0'); | ||||||
|  | 		if (i == 1) | ||||||
|  | 			break; | ||||||
|  | 		i /= 10; | ||||||
|  | 	} | ||||||
|  | 	/* check for junk after fractional part */ | ||||||
|  | 	while (ksh_isdigit(*s)) | ||||||
|  | 		++s; | ||||||
|  | 	if (*s) { | ||||||
|  | 		errno = EINVAL; | ||||||
|  | 		return (true); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/* end of input string reached, no errors */ | ||||||
|  | 	return (false); | ||||||
|  | } | ||||||
|  | #endif | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user