1/*
2 * sleep -- sleep for fractions of a second
3 *
4 * usage: sleep seconds[.fraction]
5 */
6#include "config.h"
7
8#include "bashtypes.h"
9
10#if defined (TIME_WITH_SYS_TIME)
11#  include <sys/time.h>
12#  include <time.h>
13#else
14#  if defined (HAVE_SYS_TIME_H)
15#    include <sys/time.h>
16#  else
17#    include <time.h>
18#  endif
19#endif
20
21#if defined (HAVE_UNISTD_H)
22#include <unistd.h>
23#endif
24
25#include <stdio.h>
26#include "chartypes.h"
27
28#include "shell.h"
29#include "builtins.h"
30
31#define RETURN(x) \
32	do { \
33		if (sp) *sp = sec; \
34		if (usp) *usp = usec; \
35		return (x); \
36	} while (0)
37
38#if defined (HAVE_TIMEVAL) && defined (HAVE_SELECT)
39static int
40fsleep(sec, usec)
41long	sec, usec;
42{
43	struct timeval tv;
44
45	tv.tv_sec = sec;
46	tv.tv_usec = usec;
47
48	return select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv);
49}
50#else /* !HAVE_TIMEVAL || !HAVE_SELECT */
51static int
52fsleep(sec, usec)
53long	sec, usec;
54{
55	if (usec >= 500000)	/* round */
56		sec++;
57	return (sleep(sec));
58}
59#endif /* !HAVE_TIMEVAL || !HAVE_SELECT */
60
61/*
62 * An incredibly simplistic floating point converter.
63 */
64static int multiplier[7] = { 1, 100000, 10000, 1000, 100, 10, 1 };
65
66static int
67convert(s, sp, usp)
68char	*s;
69long	*sp, *usp;
70{
71	int n;
72	long sec, usec;
73	char	*p;
74
75	sec = usec = 0;
76
77#define DECIMAL	'.'
78
79	for (p = s; p && *p; p++) {
80		if (*p == DECIMAL)		/* decimal point */
81			break;
82		if (DIGIT(*p) == 0)
83			RETURN(0);
84		sec = (sec * 10) + (*p - '0');
85	}
86
87	if (*p == 0)
88		RETURN(1);
89
90	if (*p == DECIMAL)
91		p++;
92
93	/* Look for up to six digits past a decimal point. */
94	for (n = 0; n < 6 && p[n]; n++) {
95		if (DIGIT(p[n]) == 0)
96			RETURN(0);
97		usec = (usec * 10) + (p[n] - '0');
98	}
99
100	/* Now convert to millionths */
101	usec *= multiplier[n];
102
103	if (n == 6 && p[6] >= '5' && p[6] <= '9')
104		usec++;			/* round up 1 */
105
106	RETURN(1);
107}
108
109int
110sleep_builtin (list)
111WORD_LIST	*list;
112{
113	long	sec, usec;
114
115	if (list == 0) {
116		builtin_usage();
117		return(EX_USAGE);
118	}
119
120	if (*list->word->word == '-' || list->next) {
121		builtin_usage ();
122		return (EX_USAGE);
123	}
124
125    	if (convert(list->word->word, &sec, &usec)) {
126		fsleep(sec, usec);
127		return(EXECUTION_SUCCESS);
128    	}
129
130	builtin_error("%s: bad sleep interval", list->word->word);
131	return (EXECUTION_FAILURE);
132}
133
134static char *sleep_doc[] = {
135	"sleep suspends execution for a minimum of SECONDS[.FRACTION] seconds.",
136	(char *)NULL
137};
138
139struct builtin sleep_struct = {
140	"sleep",
141	sleep_builtin,
142	BUILTIN_ENABLED,
143	sleep_doc,
144	"sleep seconds[.fraction]",
145	0
146};
147