timemodule.c revision dbd9ba6a6c19c3d06f5684b3384a934f740038db
1/***********************************************************
2Copyright (c) 2000, BeOpen.com.
3Copyright (c) 1995-2000, Corporation for National Research Initiatives.
4Copyright (c) 1990-1995, Stichting Mathematisch Centrum.
5All rights reserved.
6
7See the file "Misc/COPYRIGHT" for information on usage and
8redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
9******************************************************************/
10
11/* Time module */
12
13#include "Python.h"
14
15#include <ctype.h>
16
17#ifdef HAVE_SELECT
18#include "mymath.h"
19#endif
20
21#ifdef macintosh
22#include <time.h>
23#include <OSUtils.h>
24#ifdef USE_GUSI2
25/* GUSI, the I/O library which has the time() function and such uses the
26** Mac epoch of 1904. MSL, the C library which has localtime() and so uses
27** the ANSI epoch of 1900.
28*/
29#define GUSI_TO_MSL_EPOCH (4*365*24*60*60)
30#endif /* USE_GUSI2 */
31#else
32#include <sys/types.h>
33#endif
34
35#ifdef QUICKWIN
36#include <io.h>
37#endif
38
39#ifdef HAVE_UNISTD_H
40#include <unistd.h>
41#endif
42
43#if defined(HAVE_SELECT) && !defined(__BEOS__)
44#include "myselect.h"
45#else
46#include "mytime.h"
47#endif
48
49#ifdef HAVE_FTIME
50#include <sys/timeb.h>
51#if !defined(MS_WINDOWS) && !defined(PYOS_OS2)
52extern int ftime();
53#endif /* MS_WINDOWS */
54#endif /* HAVE_FTIME */
55
56#if defined(__WATCOMC__) && !defined(__QNX__)
57#include <i86.h>
58#else
59#ifdef MS_WINDOWS
60#include <windows.h>
61#ifdef MS_WIN16
62/* These overrides not needed for Win32 */
63#define timezone _timezone
64#define tzname _tzname
65#define daylight _daylight
66#define altzone _altzone
67#endif /* MS_WIN16 */
68#endif /* MS_WINDOWS */
69#endif /* !__WATCOMC__ || __QNX__ */
70
71#if defined(MS_WIN32) && !defined(MS_WIN64)
72/* Win32 has better clock replacement
73   XXX Win64 does not yet, but might when the platform matures. */
74#include <largeint.h>
75#undef HAVE_CLOCK /* We have our own version down below */
76#endif /* MS_WIN32 && !MS_WIN64 */
77
78#if defined(PYCC_VACPP)
79#include <sys/time.h>
80#endif
81
82#ifdef __BEOS__
83/* For bigtime_t, snooze(). - [cjh] */
84#include <support/SupportDefs.h>
85#include <kernel/OS.h>
86#ifndef CLOCKS_PER_SEC
87/* C'mon, fix the bloody headers... - [cjh] */
88#define CLOCKS_PER_SEC 1000
89#endif
90#endif
91
92/* Forward declarations */
93static int floatsleep(double);
94static double floattime();
95
96/* For Y2K check */
97static PyObject *moddict;
98
99#ifdef macintosh
100/* Our own timezone. We have enough information to deduce whether
101** DST is on currently, but unfortunately we cannot put it to good
102** use because we don't know the rules (and that is needed to have
103** localtime() return correct tm_isdst values for times other than
104** the current time. So, we cop out and only tell the user the current
105** timezone.
106*/
107static long timezone;
108
109static void
110initmactimezone()
111{
112	MachineLocation	loc;
113	long		delta;
114
115	ReadLocation(&loc);
116
117	if (loc.latitude == 0 && loc.longitude == 0 && loc.u.gmtDelta == 0)
118		return;
119
120	delta = loc.u.gmtDelta & 0x00FFFFFF;
121
122	if (delta & 0x00800000)
123		delta |= 0xFF000000;
124
125	timezone = -delta;
126}
127#endif /* macintosh */
128
129
130static PyObject *
131time_time(self, args)
132	PyObject *self;
133	PyObject *args;
134{
135	double secs;
136	if (!PyArg_NoArgs(args))
137		return NULL;
138	secs = floattime();
139	if (secs == 0.0) {
140		PyErr_SetFromErrno(PyExc_IOError);
141		return NULL;
142	}
143	return PyFloat_FromDouble(secs);
144}
145
146static char time_doc[] =
147"time() -> floating point number\n\
148\n\
149Return the current time in seconds since the Epoch.\n\
150Fractions of a second may be present if the system clock provides them.";
151
152#ifdef HAVE_CLOCK
153
154#ifndef CLOCKS_PER_SEC
155#ifdef CLK_TCK
156#define CLOCKS_PER_SEC CLK_TCK
157#else
158#define CLOCKS_PER_SEC 1000000
159#endif
160#endif
161
162static PyObject *
163time_clock(self, args)
164	PyObject *self;
165	PyObject *args;
166{
167	if (!PyArg_NoArgs(args))
168		return NULL;
169	return PyFloat_FromDouble(((double)clock()) / CLOCKS_PER_SEC);
170}
171#endif /* HAVE_CLOCK */
172
173#if defined(MS_WIN32) && !defined(MS_WIN64)
174/* Due to Mark Hammond */
175static PyObject *
176time_clock(self, args)
177	PyObject *self;
178	PyObject *args;
179{
180	static LARGE_INTEGER ctrStart;
181	static LARGE_INTEGER divisor = {0,0};
182	LARGE_INTEGER now, diff, rem;
183
184	if (!PyArg_NoArgs(args))
185		return NULL;
186
187	if (LargeIntegerEqualToZero(divisor)) {
188		QueryPerformanceCounter(&ctrStart);
189		if (!QueryPerformanceFrequency(&divisor) ||
190		    LargeIntegerEqualToZero(divisor)) {
191				/* Unlikely to happen -
192				   this works on all intel machines at least!
193				   Revert to clock() */
194			return PyFloat_FromDouble(clock());
195		}
196	}
197	QueryPerformanceCounter(&now);
198	diff = LargeIntegerSubtract(now, ctrStart);
199	diff = LargeIntegerDivide(diff, divisor, &rem);
200	/* XXX - we assume both divide results fit in 32 bits.  This is
201	   true on Intels.  First person who can afford a machine that
202	   doesnt deserves to fix it :-)
203	*/
204	return PyFloat_FromDouble((double)diff.LowPart +
205		              ((double)rem.LowPart / (double)divisor.LowPart));
206}
207
208#define HAVE_CLOCK /* So it gets included in the methods */
209#endif /* MS_WIN32 && !MS_WIN64 */
210
211#ifdef HAVE_CLOCK
212static char clock_doc[] =
213"clock() -> floating point number\n\
214\n\
215Return the CPU time or real time since the start of the process or since\n\
216the first call to clock().  This has as much precision as the system records.";
217#endif
218
219static PyObject *
220time_sleep(self, args)
221	PyObject *self;
222	PyObject *args;
223{
224	double secs;
225	if (!PyArg_Parse(args, "d", &secs))
226		return NULL;
227	if (floatsleep(secs) != 0)
228		return NULL;
229	Py_INCREF(Py_None);
230	return Py_None;
231}
232
233static char sleep_doc[] =
234"sleep(seconds)\n\
235\n\
236Delay execution for a given number of seconds.  The argument may be\n\
237a floating point number for subsecond precision.";
238
239static PyObject *
240tmtotuple(p)
241	struct tm *p;
242{
243	return Py_BuildValue("(iiiiiiiii)",
244			     p->tm_year + 1900,
245			     p->tm_mon + 1,	   /* Want January == 1 */
246			     p->tm_mday,
247			     p->tm_hour,
248			     p->tm_min,
249			     p->tm_sec,
250			     (p->tm_wday + 6) % 7, /* Want Monday == 0 */
251			     p->tm_yday + 1,	   /* Want January, 1 == 1 */
252			     p->tm_isdst);
253}
254
255static PyObject *
256time_convert(when, function)
257	time_t when;
258	struct tm * (*function)(const time_t *);
259{
260	struct tm *p;
261	errno = 0;
262#if defined(macintosh) && defined(USE_GUSI204)
263	when = when + GUSI_TO_MSL_EPOCH;
264#endif
265	p = function(&when);
266	if (p == NULL) {
267#ifdef EINVAL
268		if (errno == 0)
269			errno = EINVAL;
270#endif
271		return PyErr_SetFromErrno(PyExc_IOError);
272	}
273	return tmtotuple(p);
274}
275
276static PyObject *
277time_gmtime(self, args)
278	PyObject *self;
279	PyObject *args;
280{
281	double when;
282	if (!PyArg_Parse(args, "d", &when))
283		return NULL;
284	return time_convert((time_t)when, gmtime);
285}
286
287static char gmtime_doc[] =
288"gmtime(seconds) -> tuple\n\
289\n\
290Convert seconds since the Epoch to a time tuple expressing UTC (a.k.a. GMT).";
291
292static PyObject *
293time_localtime(self, args)
294	PyObject *self;
295	PyObject *args;
296{
297	double when;
298	if (!PyArg_Parse(args, "d", &when))
299		return NULL;
300	return time_convert((time_t)when, localtime);
301}
302
303static char localtime_doc[] =
304"localtime(seconds) -> tuple\n\
305Convert seconds since the Epoch to a time tuple expressing local time.";
306
307static int
308gettmarg(args, p)
309	PyObject *args;
310	struct tm *p;
311{
312	int y;
313	memset((ANY *) p, '\0', sizeof(struct tm));
314
315	if (!PyArg_Parse(args, "(iiiiiiiii)",
316			 &y,
317			 &p->tm_mon,
318			 &p->tm_mday,
319			 &p->tm_hour,
320			 &p->tm_min,
321			 &p->tm_sec,
322			 &p->tm_wday,
323			 &p->tm_yday,
324			 &p->tm_isdst))
325		return 0;
326	if (y < 1900) {
327		PyObject *accept = PyDict_GetItemString(moddict,
328							"accept2dyear");
329		if (accept == NULL || !PyInt_Check(accept) ||
330		    PyInt_AsLong(accept) == 0) {
331			PyErr_SetString(PyExc_ValueError,
332					"year >= 1900 required");
333			return 0;
334		}
335		if (69 <= y && y <= 99)
336			y += 1900;
337		else if (0 <= y && y <= 68)
338			y += 2000;
339		else {
340			PyErr_SetString(PyExc_ValueError,
341					"year out of range (00-99, 1900-*)");
342			return 0;
343		}
344	}
345	p->tm_year = y - 1900;
346	p->tm_mon--;
347	p->tm_wday = (p->tm_wday + 1) % 7;
348	p->tm_yday--;
349	return 1;
350}
351
352#ifdef HAVE_STRFTIME
353static PyObject *
354time_strftime(self, args)
355	PyObject *self;
356	PyObject *args;
357{
358	PyObject *tup;
359	struct tm buf;
360	const char *fmt;
361	size_t fmtlen, buflen;
362	char *outbuf = 0;
363	size_t i;
364
365	memset((ANY *) &buf, '\0', sizeof(buf));
366
367	if (!PyArg_ParseTuple(args, "sO:strftime", &fmt, &tup)
368	    || !gettmarg(tup, &buf))
369		return NULL;
370	fmtlen = strlen(fmt);
371
372	/* I hate these functions that presume you know how big the output
373	 * will be ahead of time...
374	 */
375	for (i = 1024; ; i += i) {
376		outbuf = malloc(i);
377		if (outbuf == NULL) {
378			return PyErr_NoMemory();
379		}
380		buflen = strftime(outbuf, i, fmt, &buf);
381		if (buflen > 0 || i >= 256 * fmtlen) {
382			/* If the buffer is 256 times as long as the format,
383			   it's probably not failing for lack of room!
384			   More likely, the format yields an empty result,
385			   e.g. an empty format, or %Z when the timezone
386			   is unknown. */
387			PyObject *ret;
388			ret = PyString_FromStringAndSize(outbuf, buflen);
389			free(outbuf);
390			return ret;
391		}
392		free(outbuf);
393	}
394}
395
396static char strftime_doc[] =
397"strftime(format, tuple) -> string\n\
398\n\
399Convert a time tuple to a string according to a format specification.\n\
400See the library reference manual for formatting codes.";
401#endif /* HAVE_STRFTIME */
402
403#ifdef HAVE_STRPTIME
404
405#if 0
406extern char *strptime(); /* Enable this if it's not declared in <time.h> */
407#endif
408
409static PyObject *
410time_strptime(self, args)
411	PyObject *self;
412	PyObject *args;
413{
414	struct tm tm;
415	char *fmt = "%a %b %d %H:%M:%S %Y";
416	char *buf;
417	char *s;
418
419	if (!PyArg_ParseTuple(args, "s|s:strptime", &buf, &fmt))
420	        return NULL;
421	memset((ANY *) &tm, '\0', sizeof(tm));
422	s = strptime(buf, fmt, &tm);
423	if (s == NULL) {
424		PyErr_SetString(PyExc_ValueError, "format mismatch");
425		return NULL;
426	}
427	while (*s && isspace(*s))
428		s++;
429	if (*s) {
430		PyErr_Format(PyExc_ValueError,
431			     "unconverted data remains: '%.400s'", s);
432		return NULL;
433	}
434	return tmtotuple(&tm);
435}
436
437static char strptime_doc[] =
438"strptime(string, format) -> tuple\n\
439Parse a string to a time tuple according to a format specification.\n\
440See the library reference manual for formatting codes (same as strftime()).";
441#endif /* HAVE_STRPTIME */
442
443static PyObject *
444time_asctime(self, args)
445	PyObject *self;
446	PyObject *args;
447{
448	PyObject *tup;
449	struct tm buf;
450	char *p;
451	if (!PyArg_ParseTuple(args, "O:asctime", &tup))
452		return NULL;
453	if (!gettmarg(tup, &buf))
454		return NULL;
455	p = asctime(&buf);
456	if (p[24] == '\n')
457		p[24] = '\0';
458	return PyString_FromString(p);
459}
460
461static char asctime_doc[] =
462"asctime(tuple) -> string\n\
463\n\
464Convert a time tuple to a string, e.g. 'Sat Jun 06 16:26:11 1998'.";
465
466static PyObject *
467time_ctime(self, args)
468	PyObject *self;
469	PyObject *args;
470{
471	double dt;
472	time_t tt;
473	char *p;
474	if (!PyArg_Parse(args, "d", &dt))
475		return NULL;
476	tt = (time_t)dt;
477#if defined(macintosh) && defined(USE_GUSI204)
478	tt = tt + GUSI_TO_MSL_EPOCH;
479#endif
480	p = ctime(&tt);
481	if (p == NULL) {
482		PyErr_SetString(PyExc_ValueError, "unconvertible time");
483		return NULL;
484	}
485	if (p[24] == '\n')
486		p[24] = '\0';
487	return PyString_FromString(p);
488}
489
490static char ctime_doc[] =
491"ctime(seconds) -> string\n\
492\n\
493Convert a time in seconds since the Epoch to a string in local time.\n\
494This is equivalent to asctime(localtime(seconds)).";
495
496#ifdef HAVE_MKTIME
497static PyObject *
498time_mktime(self, args)
499	PyObject *self;
500	PyObject *args;
501{
502	PyObject *tup;
503	struct tm buf;
504	time_t tt;
505	if (!PyArg_ParseTuple(args, "O:mktime", &tup))
506		return NULL;
507	tt = time(&tt);
508	buf = *localtime(&tt);
509	if (!gettmarg(tup, &buf))
510		return NULL;
511	tt = mktime(&buf);
512	if (tt == (time_t)(-1)) {
513		PyErr_SetString(PyExc_OverflowError,
514                                "mktime argument out of range");
515		return NULL;
516	}
517#if defined(macintosh) && defined(USE_GUSI2)
518	tt = tt - GUSI_TO_MSL_EPOCH;
519#endif
520	return PyFloat_FromDouble((double)tt);
521}
522
523static char mktime_doc[] =
524"mktime(tuple) -> floating point number\n\
525\n\
526Convert a time tuple in local time to seconds since the Epoch.";
527#endif /* HAVE_MKTIME */
528
529static PyMethodDef time_methods[] = {
530	{"time",	time_time, 0, time_doc},
531#ifdef HAVE_CLOCK
532	{"clock",	time_clock, 0, clock_doc},
533#endif
534	{"sleep",	time_sleep, 0, sleep_doc},
535	{"gmtime",	time_gmtime, 0, gmtime_doc},
536	{"localtime",	time_localtime, 0, localtime_doc},
537	{"asctime",	time_asctime, 1, asctime_doc},
538	{"ctime",	time_ctime, 0, ctime_doc},
539#ifdef HAVE_MKTIME
540	{"mktime",	time_mktime, 1, mktime_doc},
541#endif
542#ifdef HAVE_STRFTIME
543	{"strftime",	time_strftime, 1, strftime_doc},
544#endif
545#ifdef HAVE_STRPTIME
546	{"strptime",	time_strptime, 1, strptime_doc},
547#endif
548	{NULL,		NULL}		/* sentinel */
549};
550
551static void
552ins(d, name, v)
553	PyObject *d;
554	char *name;
555	PyObject *v;
556{
557	if (v == NULL)
558		Py_FatalError("Can't initialize time module -- NULL value");
559	if (PyDict_SetItemString(d, name, v) != 0)
560		Py_FatalError(
561		"Can't initialize time module -- PyDict_SetItemString failed");
562	Py_DECREF(v);
563}
564
565static char module_doc[] =
566"This module provides various functions to manipulate time values.\n\
567\n\
568There are two standard representations of time.  One is the number\n\
569of seconds since the Epoch, in UTC (a.k.a. GMT).  It may be an integer\n\
570or a floating point number (to represent fractions of seconds).\n\
571The Epoch is system-defined; on Unix, it is generally January 1st, 1970.\n\
572The actual value can be retrieved by calling gmtime(0).\n\
573\n\
574The other representation is a tuple of 9 integers giving local time.\n\
575The tuple items are:\n\
576  year (four digits, e.g. 1998)\n\
577  month (1-12)\n\
578  day (1-31)\n\
579  hours (0-23)\n\
580  minutes (0-59)\n\
581  seconds (0-59)\n\
582  weekday (0-6, Monday is 0)\n\
583  Julian day (day in the year, 1-366)\n\
584  DST (Daylight Savings Time) flag (-1, 0 or 1)\n\
585If the DST flag is 0, the time is given in the regular time zone;\n\
586if it is 1, the time is given in the DST time zone;\n\
587if it is -1, mktime() should guess based on the date and time.\n\
588\n\
589Variables:\n\
590\n\
591timezone -- difference in seconds between UTC and local standard time\n\
592altzone -- difference in  seconds between UTC and local DST time\n\
593daylight -- whether local time should reflect DST\n\
594tzname -- tuple of (standard time zone name, DST time zone name)\n\
595\n\
596Functions:\n\
597\n\
598time() -- return current time in seconds since the Epoch as a float\n\
599clock() -- return CPU time since process start as a float\n\
600sleep() -- delay for a number of seconds given as a float\n\
601gmtime() -- convert seconds since Epoch to UTC tuple\n\
602localtime() -- convert seconds since Epoch to local time tuple\n\
603asctime() -- convert time tuple to string\n\
604ctime() -- convert time in seconds to string\n\
605mktime() -- convert local time tuple to seconds since Epoch\n\
606strftime() -- convert time tuple to string according to format specification\n\
607strptime() -- parse string to time tuple according to format specification\n\
608";
609
610
611DL_EXPORT(void)
612inittime()
613{
614	PyObject *m, *d;
615	char *p;
616	m = Py_InitModule3("time", time_methods, module_doc);
617	d = PyModule_GetDict(m);
618	/* Accept 2-digit dates unless PYTHONY2K is set and non-empty */
619	p = getenv("PYTHONY2K");
620	ins(d, "accept2dyear", PyInt_FromLong((long) (!p || !*p)));
621	/* Squirrel away the module's dictionary for the y2k check */
622	Py_INCREF(d);
623	moddict = d;
624#if defined(HAVE_TZNAME) && !defined(__GLIBC__)
625	tzset();
626#ifdef PYOS_OS2
627	ins(d, "timezone", PyInt_FromLong((long)_timezone));
628#else /* !PYOS_OS2 */
629	ins(d, "timezone", PyInt_FromLong((long)timezone));
630#endif /* PYOS_OS2 */
631#ifdef HAVE_ALTZONE
632	ins(d, "altzone", PyInt_FromLong((long)altzone));
633#else
634#ifdef PYOS_OS2
635	ins(d, "altzone", PyInt_FromLong((long)_timezone-3600));
636#else /* !PYOS_OS2 */
637	ins(d, "altzone", PyInt_FromLong((long)timezone-3600));
638#endif /* PYOS_OS2 */
639#endif
640	ins(d, "daylight", PyInt_FromLong((long)daylight));
641	ins(d, "tzname", Py_BuildValue("(zz)", tzname[0], tzname[1]));
642#else /* !HAVE_TZNAME || __GLIBC__ */
643#ifdef HAVE_TM_ZONE
644	{
645#define YEAR ((time_t)((365 * 24 + 6) * 3600))
646		time_t t;
647		struct tm *p;
648		long janzone, julyzone;
649		char janname[10], julyname[10];
650		t = (time((time_t *)0) / YEAR) * YEAR;
651		p = localtime(&t);
652		janzone = -p->tm_gmtoff;
653		strncpy(janname, p->tm_zone ? p->tm_zone : "   ", 9);
654		janname[9] = '\0';
655		t += YEAR/2;
656		p = localtime(&t);
657		julyzone = -p->tm_gmtoff;
658		strncpy(julyname, p->tm_zone ? p->tm_zone : "   ", 9);
659		julyname[9] = '\0';
660
661		if( janzone < julyzone ) {
662			/* DST is reversed in the southern hemisphere */
663			ins(d, "timezone", PyInt_FromLong(julyzone));
664			ins(d, "altzone", PyInt_FromLong(janzone));
665			ins(d, "daylight",
666			    PyInt_FromLong((long)(janzone != julyzone)));
667			ins(d, "tzname",
668			    Py_BuildValue("(zz)", julyname, janname));
669		} else {
670			ins(d, "timezone", PyInt_FromLong(janzone));
671			ins(d, "altzone", PyInt_FromLong(julyzone));
672			ins(d, "daylight",
673			    PyInt_FromLong((long)(janzone != julyzone)));
674			ins(d, "tzname",
675			    Py_BuildValue("(zz)", janname, julyname));
676		}
677	}
678#else
679#ifdef macintosh
680	/* The only thing we can obtain is the current timezone
681	** (and whether dst is currently _active_, but that is not what
682	** we're looking for:-( )
683	*/
684	initmactimezone();
685	ins(d, "timezone", PyInt_FromLong(timezone));
686	ins(d, "altzone", PyInt_FromLong(timezone));
687	ins(d, "daylight", PyInt_FromLong((long)0));
688	ins(d, "tzname", Py_BuildValue("(zz)", "", ""));
689#endif /* macintosh */
690#endif /* HAVE_TM_ZONE */
691#endif /* !HAVE_TZNAME || __GLIBC__ */
692	if (PyErr_Occurred())
693		Py_FatalError("Can't initialize time module");
694}
695
696
697/* Implement floattime() for various platforms */
698
699static double
700floattime()
701{
702	/* There are three ways to get the time:
703	  (1) gettimeofday() -- resolution in microseconds
704	  (2) ftime() -- resolution in milliseconds
705	  (3) time() -- resolution in seconds
706	  In all cases the return value is a float in seconds.
707	  Since on some systems (e.g. SCO ODT 3.0) gettimeofday() may
708	  fail, so we fall back on ftime() or time().
709	  Note: clock resolution does not imply clock accuracy! */
710#ifdef HAVE_GETTIMEOFDAY
711	{
712		struct timeval t;
713#ifdef GETTIMEOFDAY_NO_TZ
714		if (gettimeofday(&t) == 0)
715			return (double)t.tv_sec + t.tv_usec*0.000001;
716#else /* !GETTIMEOFDAY_NO_TZ */
717		if (gettimeofday(&t, (struct timezone *)NULL) == 0)
718			return (double)t.tv_sec + t.tv_usec*0.000001;
719#endif /* !GETTIMEOFDAY_NO_TZ */
720	}
721#endif /* !HAVE_GETTIMEOFDAY */
722	{
723#if defined(HAVE_FTIME)
724		struct timeb t;
725		ftime(&t);
726		return (double)t.time + (double)t.millitm * (double)0.001;
727#else /* !HAVE_FTIME */
728		time_t secs;
729		time(&secs);
730		return (double)secs;
731#endif /* !HAVE_FTIME */
732	}
733}
734
735
736/* Implement floatsleep() for various platforms.
737   When interrupted (or when another error occurs), return -1 and
738   set an exception; else return 0. */
739
740static int
741#ifdef MPW
742floatsleep(double secs)
743#else
744	floatsleep(secs)
745	double secs;
746#endif /* MPW */
747{
748/* XXX Should test for MS_WIN32 first! */
749#if defined(HAVE_SELECT) && !defined(__BEOS__)
750	struct timeval t;
751	double frac;
752	frac = fmod(secs, 1.0);
753	secs = floor(secs);
754	t.tv_sec = (long)secs;
755	t.tv_usec = (long)(frac*1000000.0);
756	Py_BEGIN_ALLOW_THREADS
757	if (select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t) != 0) {
758#ifdef EINTR
759		if (errno != EINTR) {
760#else
761		if (1) {
762#endif
763			Py_BLOCK_THREADS
764			PyErr_SetFromErrno(PyExc_IOError);
765			return -1;
766		}
767	}
768	Py_END_ALLOW_THREADS
769#else /* !HAVE_SELECT || __BEOS__ */
770#ifdef macintosh
771#define MacTicks	(* (long *)0x16A)
772	long deadline;
773	deadline = MacTicks + (long)(secs * 60.0);
774	while (MacTicks < deadline) {
775		/* XXX Should call some yielding function here */
776		if (PyErr_CheckSignals())
777			return -1;
778	}
779#else /* !macintosh */
780#if defined(__WATCOMC__) && !defined(__QNX__)
781	/* XXX Can't interrupt this sleep */
782	Py_BEGIN_ALLOW_THREADS
783	delay((int)(secs * 1000 + 0.5));  /* delay() uses milliseconds */
784	Py_END_ALLOW_THREADS
785#else /* !__WATCOMC__ || __QNX__ */
786#ifdef MSDOS
787	struct timeb t1, t2;
788	double frac;
789	extern double fmod(double, double);
790	extern double floor(double);
791	if (secs <= 0.0)
792		return;
793	frac = fmod(secs, 1.0);
794	secs = floor(secs);
795	ftime(&t1);
796	t2.time = t1.time + (int)secs;
797	t2.millitm = t1.millitm + (int)(frac*1000.0);
798	while (t2.millitm >= 1000) {
799		t2.time++;
800		t2.millitm -= 1000;
801	}
802	for (;;) {
803#ifdef QUICKWIN
804		Py_BEGIN_ALLOW_THREADS
805		_wyield();
806		Py_END_ALLOW_THREADS
807#endif
808		if (PyErr_CheckSignals())
809			return -1;
810		ftime(&t1);
811		if (t1.time > t2.time ||
812		    t1.time == t2.time && t1.millitm >= t2.millitm)
813			break;
814	}
815#else /* !MSDOS */
816#ifdef MS_WIN32
817	{
818		double millisecs = secs * 1000.0;
819		if (millisecs > (double)ULONG_MAX) {
820			PyErr_SetString(PyExc_OverflowError, "sleep length is too large");
821			return -1;
822		}
823		/* XXX Can't interrupt this sleep */
824		Py_BEGIN_ALLOW_THREADS
825		Sleep((unsigned long)millisecs);
826		Py_END_ALLOW_THREADS
827	}
828#else /* !MS_WIN32 */
829#ifdef PYOS_OS2
830	/* This Sleep *IS* Interruptable by Exceptions */
831	Py_BEGIN_ALLOW_THREADS
832	if (DosSleep(secs * 1000) != NO_ERROR) {
833		Py_BLOCK_THREADS
834		PyErr_SetFromErrno(PyExc_IOError);
835		return -1;
836	}
837	Py_END_ALLOW_THREADS
838#else /* !PYOS_OS2 */
839#ifdef __BEOS__
840	/* This sleep *CAN BE* interrupted. */
841	{
842		if( secs <= 0.0 ) {
843			return;
844		}
845
846		Py_BEGIN_ALLOW_THREADS
847		/* BeOS snooze() is in microseconds... */
848		if( snooze( (bigtime_t)( secs * 1000.0 * 1000.0 ) ) == B_INTERRUPTED ) {
849			Py_BLOCK_THREADS
850			PyErr_SetFromErrno( PyExc_IOError );
851			return -1;
852		}
853		Py_END_ALLOW_THREADS
854	}
855#else /* !__BEOS__ */
856	/* XXX Can't interrupt this sleep */
857	Py_BEGIN_ALLOW_THREADS
858	sleep((int)secs);
859	Py_END_ALLOW_THREADS
860#endif /* !__BEOS__ */
861#endif /* !PYOS_OS2 */
862#endif /* !MS_WIN32 */
863#endif /* !MSDOS */
864#endif /* !__WATCOMC__ || __QNX__ */
865#endif /* !macintosh */
866#endif /* !HAVE_SELECT */
867	return 0;
868}
869