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