timemodule.c revision 234f942aefb779efa6cfb7225e21d16a3f7e80f7
1/***********************************************************
2Copyright 1991, 1992, 1993 by Stichting Mathematisch Centrum,
3Amsterdam, The Netherlands.
4
5                        All Rights Reserved
6
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the names of Stichting Mathematisch
12Centrum or CWI not be used in advertising or publicity pertaining to
13distribution of the software without specific, written prior permission.
14
15STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
23******************************************************************/
24
25/* Time module */
26
27#include "allobjects.h"
28#include "modsupport.h"
29#include "ceval.h"
30
31#include "sigtype.h"
32
33#include <signal.h>
34#include <setjmp.h>
35
36#ifdef BSD_TIME
37#define HAVE_GETTIMEOFDAY
38#include "myselect.h" /* Implies <sys/types.h>, <sys/time.h>, <sys/param.h> */
39#endif
40
41#ifdef macintosh
42#define NO_UNISTD
43#endif
44
45#ifndef NO_UNISTD
46#include <unistd.h>
47#endif
48
49/* What happens here is not trivial.
50   The BSD_TIME code needs <sys/time.h> (for struct timeval).
51   The rest of the code needs only time_t, except some MS-DOS
52   code which needs clock_t as well.
53   Standard C says that time_t is defined in <time.h>, and
54   does not have <sys/types.h>; THINK C agrees (MS-DOS too?).
55   What's worse, in pure 4.3 BSD, older SunOS versions, and
56   probably everything derived from BSD, you can't #include
57   both <time.h> and <sys/time.h> in the same file, since
58   <sys/time.h> includes <time.h> without any protection,
59   and <time.h> contains a typedef, which can't be parsed twice!
60   So on traditional UNIX systems we include <sys/types.h>
61   and <sys/time.h> and hope this implies <time.h> and time_t,
62   while on other systems, including conforming Standard C
63   systems (where 'unix' can't be defined), we rely on <time.h>.
64   Still one problem: BSD_TIME won't work with strict Standard C...
65*/
66
67#ifdef unix
68#include <sys/types.h>
69#include <sys/time.h> /* Implies <time.h> everywhere, as far as I know */
70#else /* !unix */
71#include <time.h>
72#endif /* !unix */
73
74/* XXX This is bogus -- times() is defined in posixmodule.c */
75#ifdef DO_TIMES
76#include <sys/times.h>
77#include <sys/param.h>
78#include <errno.h>
79#endif
80
81#ifdef SYSV
82/* Access timezone stuff */
83#ifdef OLDTZ				/* ANSI prepends underscore to these */
84#define _timezone	timezone	/* seconds to be added to GMT */
85#define _altzone	0		/* _timezone if daylight saving time */
86#define _daylight	0		/* if zero, _altzone is not available*/
87#define _tzname		tzname		/* Name of timezone and altzone */
88#endif
89#ifdef NOALTTZ				/* if system doesn't support alt tz */
90#undef _daylight
91#undef _altzone
92#define _daylight	0
93#define _altzone 	0
94#endif
95#endif /* SYSV */
96
97/* Forward declarations */
98static void floatsleep PROTO((double));
99static long millitimer PROTO((void));
100
101/* Time methods */
102
103static object *
104time_time(self, args)
105	object *self;
106	object *args;
107{
108#ifdef HAVE_GETTIMEOFDAY
109	struct timeval t;
110	struct timezone tz;
111	if (!getnoarg(args))
112		return NULL;
113	if (gettimeofday(&t, &tz) != 0) {
114		err_errno(IOError);
115		return NULL;
116	}
117	return newfloatobject(t.tv_sec*1.0 + t.tv_usec*0.000001);
118#else /* !HAVE_GETTIMEOFDAY */
119	time_t secs;
120	if (!getnoarg(args))
121		return NULL;
122	time(&secs);
123#ifdef macintosh
124/* The Mac epoch is 1904, while UNIX uses 1970; Python prefers 1970 */
125/* Moreover, the Mac returns local time.  This we cannot fix... */
126#define TIMEDIFF ((time_t) \
127	(((1970-1904)*365L + (1970-1904)/4) * 24 * 3600))
128	secs -= TIMEDIFF;
129#endif
130	return newfloatobject((double)secs);
131#endif /* !HAVE_GETTIMEOFDAY */
132}
133
134static jmp_buf sleep_intr;
135
136/* ARGSUSED */
137static void
138sleep_catcher(sig)
139	int sig; /* Not used but required by interface */
140{
141	longjmp(sleep_intr, 1);
142}
143
144static object *
145time_sleep(self, args)
146	object *self;
147	object *args;
148{
149	double secs;
150	SIGTYPE (*sigsave)() = 0; /* Initialized to shut lint up */
151	if (!getargs(args, "d", &secs))
152		return NULL;
153	BGN_SAVE
154	if (setjmp(sleep_intr)) {
155		RET_SAVE
156		signal(SIGINT, sigsave);
157		err_set(KeyboardInterrupt);
158		return NULL;
159	}
160	sigsave = signal(SIGINT, SIG_IGN);
161	if (sigsave != (SIGTYPE (*)()) SIG_IGN)
162		signal(SIGINT, sleep_catcher);
163	floatsleep(secs);
164	END_SAVE
165	signal(SIGINT, sigsave);
166	INCREF(None);
167	return None;
168}
169
170#ifdef macintosh
171#define DO_MILLI
172#endif
173
174#ifdef AMOEBA
175#define DO_MILLI
176extern long sys_milli();
177#define millitimer sys_milli
178#endif /* AMOEBA */
179
180#ifdef BSD_TIME
181#define DO_MILLI
182#endif /* BSD_TIME */
183
184#ifdef TURBO_C
185#define DO_MILLI
186#endif
187
188#ifdef DO_MILLI
189
190static object *
191time_millisleep(self, args)
192	object *self;
193	object *args;
194{
195	long msecs;
196	SIGTYPE (*sigsave)();
197	if (!getlongarg(args, &msecs))
198		return NULL;
199	BGN_SAVE
200	if (setjmp(sleep_intr)) {
201		RET_SAVE
202		signal(SIGINT, sigsave);
203		err_set(KeyboardInterrupt);
204		return NULL;
205	}
206	sigsave = signal(SIGINT, SIG_IGN);
207	if (sigsave != (SIGTYPE (*)()) SIG_IGN)
208		signal(SIGINT, sleep_catcher);
209	floatsleep(msecs / 1000.0);
210	END_SAVE
211	signal(SIGINT, sigsave);
212	INCREF(None);
213	return None;
214}
215
216static object *
217time_millitimer(self, args)
218	object *self;
219	object *args;
220{
221	long msecs;
222	if (!getnoarg(args))
223		return NULL;
224	msecs = millitimer();
225	return newintobject(msecs);
226}
227
228#endif /* DO_MILLI */
229
230#ifdef DO_TIMES
231
232static object *
233time_times(self, args)
234	object *self;
235	object *args;
236{
237	struct tms t;
238	clock_t c;
239	if (!getnoarg(args))
240		return NULL;
241	errno = 0;
242	c = times(&t);
243	if (c == (clock_t) -1) {
244		err_errno(IOError);
245		return NULL;
246	}
247	return mkvalue("(dddd)",
248		       (double)t.tms_utime / HZ,
249		       (double)t.tms_stime / HZ,
250		       (double)t.tms_cutime / HZ,
251		       (double)t.tms_cstime / HZ);
252}
253
254#endif
255
256
257static object *
258time_convert(when, function)
259	time_t when;
260	struct tm * (*function) PROTO((time_t *));
261{
262	struct tm *p = function(&when);
263	return mkvalue("(iiiiiiiii)",
264		       p->tm_year + 1900,
265		       p->tm_mon + 1, /* Want January == 1 */
266		       p->tm_mday,
267		       p->tm_hour,
268		       p->tm_min,
269		       p->tm_sec,
270		       (p->tm_wday + 6) % 7, /* Want Monday == 0 */
271		       p->tm_yday,
272		       p->tm_isdst);
273}
274
275static object *
276time_gmtime(self, args)
277	object *self;
278	object *args;
279{
280	double when;
281	if (!getargs(args, "d", &when))
282		return NULL;
283	return time_convert((time_t)when, gmtime);
284}
285
286static object *
287time_localtime(self, args)
288	object *self;
289	object *args;
290{
291	double when;
292	if (!getargs(args, "d", &when))
293		return NULL;
294	return time_convert((time_t)when, localtime);
295}
296
297/* Some very old systems may not have mktime().  Comment it out then! */
298
299static object *
300time_mktime(self, args)
301	object *self;
302	object *args;
303{
304	struct tm buf;
305	if (!getargs(args, "(iiiiiiiii)",
306		     &buf.tm_year,
307		     &buf.tm_mon,
308		     &buf.tm_mday,
309		     &buf.tm_hour,
310		     &buf.tm_min,
311		     &buf.tm_sec,
312		     &buf.tm_wday,
313		     &buf.tm_yday,
314		     &buf.tm_isdst))
315		return NULL;
316	if (buf.tm_year >= 1900)
317		buf.tm_year -= 1900;
318	buf.tm_mon--;
319	return newintobject((long)mktime(&buf));
320}
321
322static struct methodlist time_methods[] = {
323#ifdef DO_MILLI
324	{"millisleep",	time_millisleep},
325	{"millitimer",	time_millitimer},
326#endif /* DO_MILLI */
327#ifdef DO_TIMES
328	{"times",	time_times},
329#endif
330	{"sleep",	time_sleep},
331	{"time",	time_time},
332	{"gmtime",	time_gmtime},
333	{"localtime",	time_localtime},
334	{"mktime",	time_mktime},
335	{NULL,		NULL}		/* sentinel */
336};
337
338
339void
340inittime()
341{
342	object *m, *d;
343	m = initmodule("time", time_methods);
344	d = getmoduledict(m);
345#ifdef SYSV
346	tzset();
347	dictinsert(d, "timezone", newintobject((long)_timezone));
348	dictinsert(d, "altzone", newintobject((long)_altzone));
349	dictinsert(d, "daylight", newintobject((long)_daylight));
350	dictinsert(d, "tzname", mkvalue("(zz)", _tzname[0], _tzname[1]));
351#else /* !SYSV */
352	{
353#define YEAR ((time_t)((365 * 24 + 6) * 3600))
354		time_t t;
355		struct tm *p;
356		long winterzone, summerzone;
357		char wintername[10], summername[10];
358		t = (time((time_t *)0) / YEAR) * YEAR;
359		p = localtime(&t);
360		winterzone = -p->tm_gmtoff;
361		strncpy(wintername, p->tm_zone ? p->tm_zone : "   ", 9);
362		wintername[9] = '\0';
363		t += YEAR/2;
364		p = localtime(&t);
365		summerzone = -p->tm_gmtoff;
366		strncpy(summername, p->tm_zone ? p->tm_zone : "   ", 9);
367		summername[9] = '\0';
368		dictinsert(d, "timezone", newintobject(winterzone));
369		dictinsert(d, "altzone", newintobject(summerzone));
370		dictinsert(d, "daylight",
371			   newintobject((long)(winterzone != summerzone)));
372		dictinsert(d, "tzname",
373			   mkvalue("(zz)", wintername, summername));
374	}
375#endif /* !SYSV */
376}
377
378
379#ifdef macintosh
380
381#define MacTicks	(* (long *)0x16A)
382
383#ifdef THINK_C_3_0
384sleep(secs)
385	int secs;
386{
387	register long deadline;
388
389	deadline = MacTicks + mecs * 60;
390	while (MacTicks < deadline) {
391		if (intrcheck())
392			sleep_catcher(SIGINT);
393	}
394}
395#endif
396
397static void
398floatsleep(secs)
399	double secs;
400{
401	register long deadline;
402
403	deadline = MacTicks + (long)(secs * 60.0);
404	while (MacTicks < deadline) {
405		if (intrcheck())
406			sleep_catcher(SIGINT);
407	}
408}
409
410static long
411millitimer()
412{
413	return MacTicks * 50 / 3; /* MacTicks * 1000 / 60 */
414}
415
416#endif /* macintosh */
417
418
419#ifdef unix
420
421#ifdef BSD_TIME
422
423static long
424millitimer()
425{
426	struct timeval t;
427	struct timezone tz;
428	if (gettimeofday(&t, &tz) != 0)
429		return -1;
430	return t.tv_sec*1000 + t.tv_usec/1000;
431}
432
433static void
434floatsleep(secs)
435	double secs;
436{
437	struct timeval t;
438	double frac;
439	extern double fmod PROTO((double, double));
440	extern double floor PROTO((double));
441	frac = fmod(secs, 1.0);
442	secs = floor(secs);
443	t.tv_sec = (long)secs;
444	t.tv_usec = (long)(frac*1000000.0);
445	(void) select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t);
446}
447
448#else /* !BSD_TIME */
449
450static void
451floatsleep(secs)
452	double secs;
453{
454	sleep((int)secs);
455}
456
457#endif /* !BSD_TIME */
458
459#endif /* unix */
460
461
462#ifdef TURBO_C /* Maybe also for MS-DOS? */
463
464#ifndef CLOCKS_PER_SEC
465#define CLOCKS_PER_SEC 55	/* 54.945 msec per tick (18.2 HZ clock) */
466#endif
467
468static void
469floatsleep(secs)
470	double secs;
471{
472	delay(long(secs/1000.0));
473}
474
475static long
476millitimer()
477{
478	clock_t ticks;
479
480	ticks = clock();	/* ticks since program start */
481	return ticks * CLOCKS_PER_SEC;/* XXX shouldn't this be different? */
482}
483
484#endif /* TURBO_C */
485