This commit was manufactured by cvs2svn to create tag 'release101'.
[python/dscho.git] / Modules / timemodule.c
blob9ba9c7a361f8989d80a0fc9dae983fccc1d26322
1 /***********************************************************
2 Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum,
3 Amsterdam, The Netherlands.
5 All Rights Reserved
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Stichting Mathematisch
12 Centrum or CWI not be used in advertising or publicity pertaining to
13 distribution of the software without specific, written prior permission.
15 STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18 FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 ******************************************************************/
25 /* Time module */
27 #include "allobjects.h"
28 #include "modsupport.h"
29 #include "ceval.h"
31 #include <signal.h>
32 #include <setjmp.h>
34 #ifndef macintosh
35 #include <sys/types.h>
36 #endif
38 #ifdef QUICKWIN
39 #include <io.h>
40 #endif
42 #ifdef HAVE_UNISTD_H
43 #include <unistd.h>
44 #endif
46 #ifdef HAVE_SELECT
47 #include "myselect.h"
48 #else
49 #include "mytime.h"
50 #endif
52 #if HAVE_FTIME
53 #include <sys/timeb.h>
54 #endif
56 /* Forward declarations */
57 static void floatsleep PROTO((double));
58 static double floattime PROTO(());
60 static object *
61 time_time(self, args)
62 object *self;
63 object *args;
65 double secs;
66 if (!getnoarg(args))
67 return NULL;
68 secs = floattime();
69 if (secs == 0.0) {
70 err_errno(IOError);
71 return NULL;
73 return newfloatobject(secs);
76 #ifdef HAVE_CLOCK
78 #ifndef CLOCKS_PER_SEC
79 #define CLOCKS_PER_SEC 1000000
80 #endif
82 static object *
83 time_clock(self, args)
84 object *self;
85 object *args;
87 if (!getnoarg(args))
88 return NULL;
89 return newfloatobject(((double)clock()) / CLOCKS_PER_SEC);
91 #endif /* HAVE_CLOCK */
93 #ifdef SIGINT
94 static jmp_buf sleep_intr;
96 /* ARGSUSED */
97 static void
98 sleep_catcher(sig)
99 int sig; /* Not used but required by interface */
101 longjmp(sleep_intr, 1);
103 #endif /* SIGINT */
105 static object *
106 time_sleep(self, args)
107 object *self;
108 object *args;
110 double secs;
111 #ifdef SIGINT
112 /* We must set the signal handler *after* calling setjmp, to
113 avoid a race condition. Unfortunately some compilers put
114 the sigsave variable in a register. Sometimes auto is
115 enough, sometimes static is needed to avoid this (Microsoft
116 C 7.0). */
117 #ifdef WITH_THREAD
118 auto
119 #else
120 static
121 #endif
122 RETSIGTYPE (*sigsave)() = 0; /* Initialized to shut lint up */
123 #endif /* SIGINT */
124 if (!getargs(args, "d", &secs))
125 return NULL;
126 #ifdef SIGINT
127 BGN_SAVE
128 if (setjmp(sleep_intr)) {
129 RET_SAVE
130 signal(SIGINT, sigsave);
131 err_set(KeyboardInterrupt);
132 return NULL;
134 sigsave = signal(SIGINT, SIG_IGN);
135 if (sigsave != (RETSIGTYPE (*)()) SIG_IGN)
136 signal(SIGINT, sleep_catcher);
137 #endif
138 floatsleep(secs);
139 #ifdef SIGINT
140 END_SAVE
141 signal(SIGINT, sigsave);
142 #endif
143 INCREF(None);
144 return None;
147 static object *
148 time_convert(when, function)
149 time_t when;
150 struct tm * (*function) PROTO((time_t *));
152 struct tm *p = function(&when);
153 return mkvalue("(iiiiiiiii)",
154 p->tm_year + 1900,
155 p->tm_mon + 1, /* Want January == 1 */
156 p->tm_mday,
157 p->tm_hour,
158 p->tm_min,
159 p->tm_sec,
160 (p->tm_wday + 6) % 7, /* Want Monday == 0 */
161 p->tm_yday + 1, /* Want January, 1 == 1 */
162 p->tm_isdst);
165 static object *
166 time_gmtime(self, args)
167 object *self;
168 object *args;
170 double when;
171 if (!getargs(args, "d", &when))
172 return NULL;
173 return time_convert((time_t)when, gmtime);
176 static object *
177 time_localtime(self, args)
178 object *self;
179 object *args;
181 double when;
182 if (!getargs(args, "d", &when))
183 return NULL;
184 return time_convert((time_t)when, localtime);
187 static int
188 gettmarg(args, p)
189 object *args;
190 struct tm *p;
192 if (!getargs(args, "(iiiiiiiii)",
193 &p->tm_year,
194 &p->tm_mon,
195 &p->tm_mday,
196 &p->tm_hour,
197 &p->tm_min,
198 &p->tm_sec,
199 &p->tm_wday,
200 &p->tm_yday,
201 &p->tm_isdst))
202 return 0;
203 if (p->tm_year >= 1900)
204 p->tm_year -= 1900;
205 p->tm_mon--;
206 p->tm_wday = (p->tm_wday + 1) % 7;
207 p->tm_yday--;
208 return 1;
211 static object *
212 time_asctime(self, args)
213 object *self;
214 object *args;
216 struct tm buf;
217 char *p;
218 if (!gettmarg(args, &buf))
219 return NULL;
220 p = asctime(&buf);
221 if (p[24] == '\n')
222 p[24] = '\0';
223 return newstringobject(p);
226 static object *
227 time_ctime(self, args)
228 object *self;
229 object *args;
231 double dt;
232 time_t tt;
233 char *p;
234 if (!getargs(args, "d", &dt))
235 return NULL;
236 tt = dt;
237 p = ctime(&tt);
238 if (p[24] == '\n')
239 p[24] = '\0';
240 return newstringobject(p);
243 static object *
244 time_mktime(self, args)
245 object *self;
246 object *args;
248 struct tm buf;
249 if (!gettmarg(args, &buf))
250 return NULL;
251 return newintobject((long)mktime(&buf));
254 static struct methodlist time_methods[] = {
255 {"time", time_time},
256 #ifdef HAVE_CLOCK
257 {"clock", time_clock},
258 #endif
259 {"sleep", time_sleep},
260 {"gmtime", time_gmtime},
261 {"localtime", time_localtime},
262 {"asctime", time_asctime},
263 {"ctime", time_ctime},
264 {"mktime", time_mktime},
265 {NULL, NULL} /* sentinel */
268 void
269 inittime()
271 object *m, *d;
272 m = initmodule("time", time_methods);
273 d = getmoduledict(m);
274 #ifdef HAVE_TZNAME
275 tzset();
276 dictinsert(d, "timezone", newintobject((long)timezone));
277 #ifdef HAVE_ALTZONE
278 dictinsert(d, "altzone", newintobject((long)altzone));
279 #else
280 dictinsert(d, "altzone", newintobject((long)timezone-3600));
281 #endif
282 dictinsert(d, "daylight", newintobject((long)daylight));
283 dictinsert(d, "tzname", mkvalue("(zz)", tzname[0], tzname[1]));
284 #else /* !HAVE_TZNAME */
285 #if HAVE_TM_ZONE
287 #define YEAR ((time_t)((365 * 24 + 6) * 3600))
288 time_t t;
289 struct tm *p;
290 long winterzone, summerzone;
291 char wintername[10], summername[10];
292 /* XXX This won't work on the southern hemisphere.
293 XXX Anybody got a better idea? */
294 t = (time((time_t *)0) / YEAR) * YEAR;
295 p = localtime(&t);
296 winterzone = -p->tm_gmtoff;
297 strncpy(wintername, p->tm_zone ? p->tm_zone : " ", 9);
298 wintername[9] = '\0';
299 t += YEAR/2;
300 p = localtime(&t);
301 summerzone = -p->tm_gmtoff;
302 strncpy(summername, p->tm_zone ? p->tm_zone : " ", 9);
303 summername[9] = '\0';
304 dictinsert(d, "timezone", newintobject(winterzone));
305 dictinsert(d, "altzone", newintobject(summerzone));
306 dictinsert(d, "daylight",
307 newintobject((long)(winterzone != summerzone)));
308 dictinsert(d, "tzname",
309 mkvalue("(zz)", wintername, summername));
311 #endif /* HAVE_TM_ZONE */
312 #endif /* !HAVE_TZNAME */
316 /* Implement floattime() for various platforms */
318 static double
319 floattime()
321 /* There are three ways to get the time:
322 (1) gettimeofday() -- resolution in microseconds
323 (2) ftime() -- resolution in milliseconds
324 (3) time() -- resolution in seconds
325 In all cases the return value is a float in seconds.
326 Since on some systems (e.g. SCO ODT 3.0) gettimeofday() may
327 fail, so we fall back on ftime() or time().
328 Note: clock resolution does not imply clock accuracy! */
329 #ifdef HAVE_GETTIMEOFDAY
331 struct timeval t;
332 if (gettimeofday(&t, (struct timezone *)NULL) == 0)
333 return (double)t.tv_sec + t.tv_usec*0.000001;
335 #endif /* !HAVE_GETTIMEOFDAY */
337 #ifdef HAVE_FTIME
338 struct timeb t;
339 ftime(&t);
340 return (double)t.time + t.millitm*0.001;
341 #else /* !HAVE_FTIME */
342 time_t secs;
343 time(&secs);
344 return (double)secs;
345 #endif /* !HAVE_FTIME */
350 /* Implement floatsleep() for various platforms */
353 static void
354 floatsleep(secs)
355 double secs;
357 #ifdef HAVE_SELECT
358 struct timeval t;
359 double frac;
360 extern double fmod PROTO((double, double));
361 extern double floor PROTO((double));
362 frac = fmod(secs, 1.0);
363 secs = floor(secs);
364 t.tv_sec = (long)secs;
365 t.tv_usec = (long)(frac*1000000.0);
366 (void) select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t);
367 #else /* !HAVE_SELECT */
368 #ifdef macintosh
369 #define MacTicks (* (long *)0x16A)
370 long deadline;
371 deadline = MacTicks + (long)(secs * 60.0);
372 while (MacTicks < deadline) {
373 if (intrcheck())
374 sleep_catcher(SIGINT);
376 #else /* !macintosh */
377 #ifdef MSDOS
378 struct timeb t1, t2;
379 double frac;
380 extern double fmod PROTO((double, double));
381 extern double floor PROTO((double));
382 if (secs <= 0.0)
383 return;
384 frac = fmod(secs, 1.0);
385 secs = floor(secs);
386 ftime(&t1);
387 t2.time = t1.time + (int)secs;
388 t2.millitm = t1.millitm + (int)(frac*1000.0);
389 while (t2.millitm >= 1000) {
390 t2.time++;
391 t2.millitm -= 1000;
393 for (;;) {
394 #ifdef QUICKWIN
395 _wyield();
396 #endif
397 ftime(&t1);
398 if (t1.time > t2.time ||
399 t1.time == t2.time && t1.millitm >= t2.millitm)
400 break;
402 #else /* !MSDOS */
403 sleep((int)secs);
404 #endif /* !MSDOS */
405 #endif /* !macintosh */
406 #endif /* !HAVE_SELECT */