add a sleep builtin that can deal with fractions too

This commit is contained in:
tg 2011-02-11 00:41:38 +00:00
parent 4e626ecc30
commit cc8caf2cf9
4 changed files with 131 additions and 10 deletions

57
funcs.c
View File

@ -26,7 +26,19 @@
#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
/*
@ -112,6 +124,9 @@ const struct builtin mkshbuiltins[] = {
#endif
{"realpath", c_realpath},
{"rename", c_rename},
#if HAVE_SELECT
{"sleep", c_sleep},
#endif
{NULL, (int (*)(const char **))NULL}
};
@ -3647,3 +3662,43 @@ c_cat(const char **wp)
free(buf);
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
View File

@ -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 $
.\"-
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
@ -72,7 +72,7 @@
.\" with -mandoc, it might implement .Mx itself, but we want to
.\" 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
.\"
@ -2805,7 +2805,7 @@ regular commands
.Ic \&[ , chdir , bind , cat ,
.Ic echo , let , mknod , print ,
.Ic printf , pwd , realpath , rename ,
.Ic test , ulimit , whence
.Ic sleep , test , ulimit , whence
.Pp
In the future, the additional
.Nm
@ -4047,6 +4047,11 @@ etc.
.Ar number
defaults to 1.
.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 ...
Like
.Ic \&. Po Do dot Dc Pc ,

7
sh.h
View File

@ -154,7 +154,7 @@
#endif
#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
#define MKSH_VERSION "R39 2011/02/09"
@ -626,6 +626,7 @@ EXTERN const char T_oomem[] I__("can't allocate %lu data bytes");
#else
EXTERN const char T_synerr[] I__("syntax error");
#endif
EXTERN const char T_select[] I__("select");
EXTERN const char T_r_fc_e_[] I__("r=fc -e -");
#define T_fc_e_ (T_r_fc_e_ + 2) /* "fc -e -" */
#define Tn_fc_e_ 7 /* strlen(T_fc_e_) */
@ -794,7 +795,7 @@ struct coproc {
EXTERN struct coproc coproc;
#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;
#endif
@ -1526,6 +1527,7 @@ int c_mknod(const char **);
int c_realpath(const char **);
int c_rename(const char **);
int c_cat(const char **);
int c_sleep(const char **);
/* histrap.c */
void init_histvec(void);
void hist_init(Source *);
@ -1703,6 +1705,7 @@ int shf_vfprintf(struct shf *, const char *, va_list)
/* syn.c */
void initkeywords(void);
struct op *compile(Source *);
bool parse_usec(const char *, struct timeval *);
/* tree.c */
int fptreef(struct shf *, int, const char *, ...);
char *snptreef(char *, int, const char *, ...);

66
syn.c
View File

@ -1,7 +1,7 @@
/* $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>
*
* Provided that these terms and disclaimer and all copyright notices
@ -22,7 +22,7 @@
#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 {
int start_token; /* token than began nesting (eg, FOR) */
@ -405,7 +405,7 @@ get_command(int cf)
t = newtp((c == FOR) ? TFOR : TSELECT);
musthave(LWORD, ARRAYVAR);
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");
strdupx(t->str, ident, ATEMP);
nesting_push(&old_nesting, c);
@ -736,7 +736,7 @@ const struct tokeninfo {
{ "case", CASE, true },
{ "esac", ESAC, true },
{ "for", FOR, true },
{ "select", SELECT, true },
{ T_select, SELECT, true },
{ "while", WHILE, true },
{ "until", UNTIL, true },
{ "do", DO, true },
@ -1005,3 +1005,61 @@ dbtestp_error(Test_env *te, int offset, const char *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