stime.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  1. /* Copyright (C) 1995,1996,1997,1998, 1999, 2000, 2002 Free Software Foundation, Inc.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation; either version 2, or (at your option)
  6. * any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this software; see the file COPYING. If not, write to
  15. * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. * Boston, MA 02111-1307 USA
  17. *
  18. * As a special exception, the Free Software Foundation gives permission
  19. * for additional uses of the text contained in its release of GUILE.
  20. *
  21. * The exception is that, if you link the GUILE library with other files
  22. * to produce an executable, this does not by itself cause the
  23. * resulting executable to be covered by the GNU General Public License.
  24. * Your use of that executable is in no way restricted on account of
  25. * linking the GUILE library code into it.
  26. *
  27. * This exception does not however invalidate any other reasons why
  28. * the executable file might be covered by the GNU General Public License.
  29. *
  30. * This exception applies only to the code released by the
  31. * Free Software Foundation under the name GUILE. If you copy
  32. * code from other Free Software Foundation releases into a copy of
  33. * GUILE, as the General Public License permits, the exception does
  34. * not apply to the code that you add in this way. To avoid misleading
  35. * anyone as to the status of such modified files, you must delete
  36. * this exception notice from them.
  37. *
  38. * If you write modifications of your own for GUILE, it is your choice
  39. * whether to permit this exception to apply to your modifications.
  40. * If you do not wish that, delete this exception notice. */
  41. #include <stdio.h>
  42. #include "libguile/_scm.h"
  43. #include "libguile/feature.h"
  44. #include "libguile/strings.h"
  45. #include "libguile/vectors.h"
  46. #include "libguile/validate.h"
  47. #include "libguile/stime.h"
  48. #ifdef HAVE_UNISTD_H
  49. #include <unistd.h>
  50. #endif
  51. # ifdef HAVE_SYS_TYPES_H
  52. # include <sys/types.h>
  53. # endif
  54. # ifdef TIME_WITH_SYS_TIME
  55. # include <sys/time.h>
  56. # include <time.h>
  57. # else
  58. # ifdef HAVE_SYS_TIME_H
  59. # include <sys/time.h>
  60. # else
  61. # ifdef HAVE_TIME_H
  62. # include <time.h>
  63. # endif
  64. # endif
  65. # endif
  66. #ifdef HAVE_SYS_TIMES_H
  67. # include <sys/times.h>
  68. #endif
  69. #ifdef HAVE_SYS_TIMEB_H
  70. # include <sys/timeb.h>
  71. #endif
  72. #ifndef tzname /* For SGI. */
  73. extern char *tzname[]; /* RS6000 and others reject char **tzname. */
  74. #endif
  75. #ifdef MISSING_STRPTIME_DECL
  76. extern char *strptime ();
  77. #endif
  78. /* This should be figured out by autoconf. */
  79. #if ! defined(CLKTCK) && defined(CLK_TCK)
  80. # define CLKTCK CLK_TCK
  81. #endif
  82. #if ! defined(CLKTCK) && defined(CLOCKS_PER_SEC)
  83. # define CLKTCK CLOCKS_PER_SEC
  84. #endif
  85. #if ! defined(CLKTCK)
  86. # define CLKTCK 60
  87. #endif
  88. #ifdef __STDC__
  89. # define timet time_t
  90. #else
  91. # define timet long
  92. #endif
  93. #ifdef HAVE_TIMES
  94. static
  95. long mytime()
  96. {
  97. struct tms time_buffer;
  98. times(&time_buffer);
  99. return time_buffer.tms_utime + time_buffer.tms_stime;
  100. }
  101. #else
  102. # ifdef LACK_CLOCK
  103. # define mytime() ((time((timet*)0) - scm_your_base) * CLKTCK)
  104. # else
  105. # define mytime clock
  106. # endif
  107. #endif
  108. extern int errno;
  109. #ifdef HAVE_FTIME
  110. struct timeb scm_your_base = {0};
  111. #else
  112. timet scm_your_base = 0;
  113. #endif
  114. SCM_DEFINE (scm_get_internal_real_time, "get-internal-real-time", 0, 0, 0,
  115. (),
  116. "Returns the number of time units since the interpreter was started.")
  117. #define FUNC_NAME s_scm_get_internal_real_time
  118. {
  119. #ifdef HAVE_FTIME
  120. struct timeb time_buffer;
  121. SCM tmp;
  122. ftime (&time_buffer);
  123. time_buffer.time -= scm_your_base.time;
  124. tmp = scm_long2num (time_buffer.millitm - scm_your_base.millitm);
  125. tmp = scm_sum (tmp,
  126. scm_product (SCM_MAKINUM (1000),
  127. SCM_MAKINUM (time_buffer.time)));
  128. return scm_quotient (scm_product (tmp, SCM_MAKINUM (CLKTCK)),
  129. SCM_MAKINUM (1000));
  130. #else
  131. return scm_long2num((time((timet*)0) - scm_your_base) * (int)CLKTCK);
  132. #endif /* HAVE_FTIME */
  133. }
  134. #undef FUNC_NAME
  135. #ifdef HAVE_TIMES
  136. SCM_DEFINE (scm_times, "times", 0, 0, 0,
  137. (void),
  138. "Returns an object with information about real and processor time.\n"
  139. "The following procedures accept such an object as an argument and\n"
  140. "return a selected component:\n\n"
  141. "@table @code\n"
  142. "@item tms:clock\n"
  143. "The current real time, expressed as time units relative to an\n"
  144. "arbitrary base.\n"
  145. "@item tms:utime\n"
  146. "The CPU time units used by the calling process.\n"
  147. "@item tms:stime\n"
  148. "The CPU time units used by the system on behalf of the calling process.\n"
  149. "@item tms:cutime\n"
  150. "The CPU time units used by terminated child processes of the calling\n"
  151. "process, whose status has been collected (e.g., using @code{waitpid}).\n"
  152. "@item tms:cstime\n"
  153. "Similarly, the CPU times units used by the system on behalf of \n"
  154. "terminated child processes.\n"
  155. "@end table")
  156. #define FUNC_NAME s_scm_times
  157. {
  158. struct tms t;
  159. clock_t rv;
  160. SCM result = scm_make_vector (SCM_MAKINUM(5), SCM_UNDEFINED);
  161. rv = times (&t);
  162. if (rv == -1)
  163. SCM_SYSERROR;
  164. SCM_VELTS (result)[0] = scm_long2num (rv);
  165. SCM_VELTS (result)[1] = scm_long2num (t.tms_utime);
  166. SCM_VELTS (result)[2] = scm_long2num (t.tms_stime);
  167. SCM_VELTS (result)[3] = scm_long2num (t.tms_cutime);
  168. SCM_VELTS (result)[4] = scm_long2num (t.tms_cstime);
  169. return result;
  170. }
  171. #undef FUNC_NAME
  172. #endif /* HAVE_TIMES */
  173. static long scm_my_base = 0;
  174. SCM_DEFINE (scm_get_internal_run_time, "get-internal-run-time", 0, 0, 0,
  175. (void),
  176. "Returns the number of time units of processor time used by the interpreter.\n"
  177. "Both \"system\" and \"user\" time are included but subprocesses are not.")
  178. #define FUNC_NAME s_scm_get_internal_run_time
  179. {
  180. return scm_long2num(mytime()-scm_my_base);
  181. }
  182. #undef FUNC_NAME
  183. SCM_DEFINE (scm_current_time, "current-time", 0, 0, 0,
  184. (void),
  185. "Returns the number of seconds since 1970-01-01 00:00:00 UTC, excludingleap seconds.")
  186. #define FUNC_NAME s_scm_current_time
  187. {
  188. timet timv;
  189. SCM_DEFER_INTS;
  190. if ((timv = time (0)) == -1)
  191. SCM_SYSERROR;
  192. SCM_ALLOW_INTS;
  193. return scm_long2num((long) timv);
  194. }
  195. #undef FUNC_NAME
  196. SCM_DEFINE (scm_gettimeofday, "gettimeofday", 0, 0, 0,
  197. (void),
  198. "Returns a pair containing the number of seconds and microseconds since\n"
  199. "1970-01-01 00:00:00 UTC, excluding leap seconds. Note: whether true\n"
  200. "microsecond resolution is available depends on the operating system.")
  201. #define FUNC_NAME s_scm_gettimeofday
  202. {
  203. #ifdef HAVE_GETTIMEOFDAY
  204. struct timeval time;
  205. SCM_DEFER_INTS;
  206. if (gettimeofday (&time, NULL) == -1)
  207. SCM_SYSERROR;
  208. SCM_ALLOW_INTS;
  209. return scm_cons (scm_long2num ((long) time.tv_sec),
  210. scm_long2num ((long) time.tv_usec));
  211. #else
  212. # ifdef HAVE_FTIME
  213. struct timeb time;
  214. ftime(&time);
  215. return scm_cons (scm_long2num ((long) time.time),
  216. SCM_MAKINUM (time.millitm * 1000));
  217. # else
  218. timet timv;
  219. SCM_DEFER_INTS;
  220. if ((timv = time (0)) == -1)
  221. SCM_SYSERROR;
  222. SCM_ALLOW_INTS;
  223. return scm_cons (scm_long2num (timv), SCM_MAKINUM (0));
  224. # endif
  225. #endif
  226. }
  227. #undef FUNC_NAME
  228. static SCM
  229. filltime (struct tm *bd_time, int zoff, char *zname)
  230. {
  231. SCM result = scm_make_vector (SCM_MAKINUM(11), SCM_UNDEFINED);
  232. SCM_VELTS (result)[0] = SCM_MAKINUM (bd_time->tm_sec);
  233. SCM_VELTS (result)[1] = SCM_MAKINUM (bd_time->tm_min);
  234. SCM_VELTS (result)[2] = SCM_MAKINUM (bd_time->tm_hour);
  235. SCM_VELTS (result)[3] = SCM_MAKINUM (bd_time->tm_mday);
  236. SCM_VELTS (result)[4] = SCM_MAKINUM (bd_time->tm_mon);
  237. SCM_VELTS (result)[5] = SCM_MAKINUM (bd_time->tm_year);
  238. SCM_VELTS (result)[6] = SCM_MAKINUM (bd_time->tm_wday);
  239. SCM_VELTS (result)[7] = SCM_MAKINUM (bd_time->tm_yday);
  240. SCM_VELTS (result)[8] = SCM_MAKINUM (bd_time->tm_isdst);
  241. SCM_VELTS (result)[9] = SCM_MAKINUM (zoff);
  242. SCM_VELTS (result)[10] = zname ? scm_makfrom0str (zname) : SCM_BOOL_F;
  243. return result;
  244. }
  245. static char tzvar[3] = "TZ";
  246. extern char ** environ;
  247. /* if zone is set, create a temporary environment with only a TZ
  248. string. other threads or interrupt handlers shouldn't be allowed
  249. to run until the corresponding restorezone is called. hence the use
  250. of a static variable for tmpenv is no big deal. */
  251. static char **
  252. setzone (SCM zone, int pos, const char *subr)
  253. {
  254. char **oldenv = 0;
  255. if (!SCM_UNBNDP (zone))
  256. {
  257. static char *tmpenv[2];
  258. char *buf;
  259. SCM_ASSERT (SCM_ROSTRINGP (zone), zone, pos, subr);
  260. SCM_COERCE_SUBSTR (zone);
  261. buf = scm_must_malloc (SCM_LENGTH (zone) + sizeof (tzvar) + 1,
  262. subr);
  263. sprintf (buf, "%s=%s", tzvar, SCM_ROCHARS (zone));
  264. oldenv = environ;
  265. tmpenv[0] = buf;
  266. tmpenv[1] = 0;
  267. environ = tmpenv;
  268. }
  269. return oldenv;
  270. }
  271. static void
  272. restorezone (SCM zone, char **oldenv, const char *subr)
  273. {
  274. if (!SCM_UNBNDP (zone))
  275. {
  276. scm_must_free (environ[0]);
  277. environ = oldenv;
  278. #ifdef HAVE_TZSET
  279. /* for the possible benefit of user code linked with libguile. */
  280. tzset();
  281. #endif
  282. }
  283. }
  284. SCM_DEFINE (scm_localtime, "localtime", 1, 1, 0,
  285. (SCM time, SCM zone),
  286. "Returns an object representing the broken down components of @var{time},\n"
  287. "an integer like the one returned by @code{current-time}. The time zone\n"
  288. "for the calculation is optionally specified by @var{zone} (a string),\n"
  289. "otherwise the @code{TZ} environment variable or the system default is\n"
  290. "used.")
  291. #define FUNC_NAME s_scm_localtime
  292. {
  293. timet itime;
  294. struct tm *ltptr, lt, *utc;
  295. SCM result;
  296. int zoff;
  297. char *zname = 0;
  298. char **oldenv;
  299. int err;
  300. itime = SCM_NUM2LONG (1,time);
  301. /* deferring interupts is essential since a) setzone may install a temporary
  302. environment b) localtime uses a static buffer. */
  303. SCM_DEFER_INTS;
  304. oldenv = setzone (zone, SCM_ARG2, FUNC_NAME);
  305. #ifdef LOCALTIME_CACHE
  306. tzset ();
  307. #endif
  308. ltptr = localtime (&itime);
  309. err = errno;
  310. if (ltptr)
  311. {
  312. const char *ptr;
  313. /* copy zone name before calling gmtime or restoring zone. */
  314. #if defined (HAVE_TM_ZONE)
  315. ptr = ltptr->tm_zone;
  316. #elif defined (HAVE_TZNAME)
  317. ptr = tzname[ (ltptr->tm_isdst == 1) ? 1 : 0 ];
  318. #else
  319. ptr = "";
  320. #endif
  321. zname = SCM_MUST_MALLOC (strlen (ptr) + 1);
  322. strcpy (zname, ptr);
  323. }
  324. /* the struct is copied in case localtime and gmtime share a buffer. */
  325. if (ltptr)
  326. lt = *ltptr;
  327. utc = gmtime (&itime);
  328. if (utc == NULL)
  329. err = errno;
  330. restorezone (zone, oldenv, FUNC_NAME);
  331. /* delayed until zone has been restored. */
  332. errno = err;
  333. if (utc == NULL || ltptr == NULL)
  334. SCM_SYSERROR;
  335. /* calculate timezone offset in seconds west of UTC. */
  336. zoff = (utc->tm_hour - lt.tm_hour) * 3600 + (utc->tm_min - lt.tm_min) * 60
  337. + utc->tm_sec - lt.tm_sec;
  338. if (utc->tm_year < lt.tm_year)
  339. zoff -= 24 * 60 * 60;
  340. else if (utc->tm_year > lt.tm_year)
  341. zoff += 24 * 60 * 60;
  342. else if (utc->tm_yday < lt.tm_yday)
  343. zoff -= 24 * 60 * 60;
  344. else if (utc->tm_yday > lt.tm_yday)
  345. zoff += 24 * 60 * 60;
  346. result = filltime (&lt, zoff, zname);
  347. SCM_ALLOW_INTS;
  348. scm_must_free (zname);
  349. return result;
  350. }
  351. #undef FUNC_NAME
  352. SCM_DEFINE (scm_gmtime, "gmtime", 1, 0, 0,
  353. (SCM time),
  354. "Returns an object representing the broken down components of @var{time},\n"
  355. "an integer like the one returned by @code{current-time}. The values\n"
  356. "are calculated for UTC.")
  357. #define FUNC_NAME s_scm_gmtime
  358. {
  359. timet itime;
  360. struct tm *bd_time;
  361. SCM result;
  362. itime = SCM_NUM2LONG (1,time);
  363. SCM_DEFER_INTS;
  364. bd_time = gmtime (&itime);
  365. if (bd_time == NULL)
  366. SCM_SYSERROR;
  367. result = filltime (bd_time, 0, "GMT");
  368. SCM_ALLOW_INTS;
  369. return result;
  370. }
  371. #undef FUNC_NAME
  372. /* copy time components from a Scheme object to a struct tm. */
  373. static void
  374. bdtime2c (SCM sbd_time, struct tm *lt, int pos, const char *subr)
  375. {
  376. SCM *velts;
  377. int i;
  378. SCM_ASSERT (SCM_VECTORP (sbd_time)
  379. && SCM_LENGTH (sbd_time) == 11,
  380. sbd_time, pos, subr);
  381. velts = SCM_VELTS (sbd_time);
  382. for (i = 0; i < 10; i++)
  383. {
  384. SCM_ASSERT (SCM_INUMP (velts[i]), sbd_time, pos, subr);
  385. }
  386. SCM_ASSERT (SCM_FALSEP (velts[10]) || SCM_STRINGP (velts[10]),
  387. sbd_time, pos, subr);
  388. lt->tm_sec = SCM_INUM (velts[0]);
  389. lt->tm_min = SCM_INUM (velts[1]);
  390. lt->tm_hour = SCM_INUM (velts[2]);
  391. lt->tm_mday = SCM_INUM (velts[3]);
  392. lt->tm_mon = SCM_INUM (velts[4]);
  393. lt->tm_year = SCM_INUM (velts[5]);
  394. lt->tm_wday = SCM_INUM (velts[6]);
  395. lt->tm_yday = SCM_INUM (velts[7]);
  396. lt->tm_isdst = SCM_INUM (velts[8]);
  397. #ifdef HAVE_TM_ZONE
  398. lt->tm_gmtoff = SCM_INUM (velts[9]);
  399. if (SCM_FALSEP (velts[10]))
  400. lt->tm_zone = NULL;
  401. else
  402. lt->tm_zone = SCM_CHARS (velts[10]);
  403. #endif
  404. }
  405. SCM_DEFINE (scm_mktime, "mktime", 1, 1, 0,
  406. (SCM sbd_time, SCM zone),
  407. "@var{bd-time} is an object representing broken down time and @code{zone}\n"
  408. "is an optional time zone specifier (otherwise the TZ environment variable\n"
  409. "or the system default is used).\n\n"
  410. "Returns a pair: the CAR is a corresponding\n"
  411. "integer time value like that returned\n"
  412. "by @code{current-time}; the CDR is a broken down time object, similar to\n"
  413. "as @var{bd-time} but with normalized values.")
  414. #define FUNC_NAME s_scm_mktime
  415. {
  416. timet itime;
  417. struct tm lt, *utc;
  418. SCM result;
  419. int zoff;
  420. char *zname = 0;
  421. char **oldenv;
  422. int err;
  423. bdtime2c (sbd_time, &lt, SCM_ARG1, FUNC_NAME);
  424. SCM_DEFER_INTS;
  425. oldenv = setzone (zone, SCM_ARG2, FUNC_NAME);
  426. #ifdef LOCALTIME_CACHE
  427. tzset ();
  428. #endif
  429. itime = mktime (&lt);
  430. err = errno;
  431. if (itime != -1)
  432. {
  433. const char *ptr;
  434. /* copy zone name before calling gmtime or restoring the zone. */
  435. #if defined (HAVE_TM_ZONE)
  436. ptr = lt.tm_zone;
  437. #elif defined (HAVE_TZNAME)
  438. ptr = tzname[ (lt.tm_isdst == 1) ? 1 : 0 ];
  439. #else
  440. ptr = "";
  441. #endif
  442. zname = SCM_MUST_MALLOC (strlen (ptr) + 1);
  443. strcpy (zname, ptr);
  444. }
  445. /* get timezone offset in seconds west of UTC. */
  446. utc = gmtime (&itime);
  447. if (utc == NULL)
  448. err = errno;
  449. restorezone (zone, oldenv, FUNC_NAME);
  450. /* delayed until zone has been restored. */
  451. errno = err;
  452. if (utc == NULL || itime == -1)
  453. SCM_SYSERROR;
  454. zoff = (utc->tm_hour - lt.tm_hour) * 3600 + (utc->tm_min - lt.tm_min) * 60
  455. + utc->tm_sec - lt.tm_sec;
  456. if (utc->tm_year < lt.tm_year)
  457. zoff -= 24 * 60 * 60;
  458. else if (utc->tm_year > lt.tm_year)
  459. zoff += 24 * 60 * 60;
  460. else if (utc->tm_yday < lt.tm_yday)
  461. zoff -= 24 * 60 * 60;
  462. else if (utc->tm_yday > lt.tm_yday)
  463. zoff += 24 * 60 * 60;
  464. result = scm_cons (scm_long2num ((long) itime),
  465. filltime (&lt, zoff, zname));
  466. SCM_ALLOW_INTS;
  467. scm_must_free (zname);
  468. return result;
  469. }
  470. #undef FUNC_NAME
  471. #ifdef HAVE_TZSET
  472. SCM_DEFINE (scm_tzset, "tzset", 0, 0, 0,
  473. (void),
  474. "Initialize the timezone from the TZ environment variable\n"
  475. "or the system default. It's not usually necessary to call this procedure\n"
  476. "since it's done automatically by other procedures that depend on the\n"
  477. "timezone.")
  478. #define FUNC_NAME s_scm_tzset
  479. {
  480. tzset();
  481. return SCM_UNSPECIFIED;
  482. }
  483. #undef FUNC_NAME
  484. #endif /* HAVE_TZSET */
  485. SCM_DEFINE (scm_strftime, "strftime", 2, 0, 0,
  486. (SCM format, SCM stime),
  487. "Formats a time specification @var{time} using @var{template}. @var{time}\n"
  488. "is an object with time components in the form returned by @code{localtime}\n"
  489. "or @code{gmtime}. @var{template} is a string which can include formatting\n"
  490. "specifications introduced by a @code{%} character. The formatting of\n"
  491. "month and day names is dependent on the current locale. The value returned\n"
  492. "is the formatted string.\n"
  493. "@xref{Formatting Date and Time, , , libc, The GNU C Library Reference Manual}.)")
  494. #define FUNC_NAME s_scm_strftime
  495. {
  496. struct tm t;
  497. char *tbuf;
  498. int size = 50;
  499. char *fmt;
  500. int len;
  501. SCM result;
  502. SCM_VALIDATE_ROSTRING (1,format);
  503. bdtime2c (stime, &t, SCM_ARG2, FUNC_NAME);
  504. SCM_COERCE_SUBSTR (format);
  505. fmt = SCM_ROCHARS (format);
  506. len = SCM_ROLENGTH (format);
  507. tbuf = SCM_MUST_MALLOC (size);
  508. {
  509. #if !defined (HAVE_TM_ZONE)
  510. /* it seems the only way to tell non-GNU versions of strftime what
  511. zone to use (for the %Z format) is to set TZ in the
  512. environment. interrupts and thread switching must be deferred
  513. until TZ is restored. */
  514. char **oldenv = NULL;
  515. SCM *velts = SCM_VELTS (stime);
  516. int have_zone = 0;
  517. if (SCM_NFALSEP (velts[10]) && *SCM_CHARS (velts[10]) != 0)
  518. {
  519. /* it's not required that the TZ setting be correct, just that
  520. it has the right name. so try something like TZ=EST0.
  521. using only TZ=EST would be simpler but it doesn't work on
  522. some OSs, e.g., Solaris. */
  523. SCM zone =
  524. scm_string_append (scm_cons (velts[10],
  525. scm_cons (scm_makfrom0str ("0"),
  526. SCM_EOL)));
  527. have_zone = 1;
  528. SCM_DEFER_INTS;
  529. oldenv = setzone (zone, SCM_ARG2, FUNC_NAME);
  530. }
  531. #endif
  532. #ifdef LOCALTIME_CACHE
  533. tzset ();
  534. #endif
  535. while ((len = strftime (tbuf, size, fmt, &t)) == size)
  536. {
  537. scm_must_free (tbuf);
  538. size *= 2;
  539. tbuf = SCM_MUST_MALLOC (size);
  540. }
  541. #if !defined (HAVE_TM_ZONE)
  542. if (have_zone)
  543. {
  544. restorezone (velts[10], oldenv, FUNC_NAME);
  545. SCM_ALLOW_INTS;
  546. }
  547. #endif
  548. }
  549. result = scm_makfromstr (tbuf, len, 0);
  550. scm_must_free (tbuf);
  551. return result;
  552. }
  553. #undef FUNC_NAME
  554. #ifdef HAVE_STRPTIME
  555. SCM_DEFINE (scm_strptime, "strptime", 2, 0, 0,
  556. (SCM format, SCM string),
  557. "Performs the reverse action to @code{strftime}, parsing @var{string}\n"
  558. "according to the specification supplied in @var{template}. The\n"
  559. "interpretation of month and day names is dependent on the current\n"
  560. "locale. The\n"
  561. "value returned is a pair. The CAR has an object with time components \n"
  562. "in the form returned by @code{localtime} or @code{gmtime},\n"
  563. "but the time zone components\n"
  564. "are not usefully set.\n"
  565. "The CDR reports the number of characters from @var{string} which\n"
  566. "vwere used for the conversion.")
  567. #define FUNC_NAME s_scm_strptime
  568. {
  569. struct tm t;
  570. char *fmt, *str, *rest;
  571. SCM_VALIDATE_ROSTRING (1,format);
  572. SCM_VALIDATE_ROSTRING (2,string);
  573. SCM_COERCE_SUBSTR (format);
  574. SCM_COERCE_SUBSTR (string);
  575. fmt = SCM_ROCHARS (format);
  576. str = SCM_ROCHARS (string);
  577. /* initialize the struct tm */
  578. #define tm_init(field) t.field = 0
  579. tm_init (tm_sec);
  580. tm_init (tm_min);
  581. tm_init (tm_hour);
  582. tm_init (tm_mday);
  583. tm_init (tm_mon);
  584. tm_init (tm_year);
  585. tm_init (tm_wday);
  586. tm_init (tm_yday);
  587. #undef tm_init
  588. t.tm_isdst = -1;
  589. SCM_DEFER_INTS;
  590. if ((rest = strptime (str, fmt, &t)) == NULL)
  591. SCM_SYSERROR;
  592. SCM_ALLOW_INTS;
  593. return scm_cons (filltime (&t, 0, NULL), SCM_MAKINUM (rest - str));
  594. }
  595. #undef FUNC_NAME
  596. #endif /* HAVE_STRPTIME */
  597. void
  598. scm_init_stime()
  599. {
  600. scm_sysintern("internal-time-units-per-second",
  601. scm_long2num((long)CLKTCK));
  602. #ifdef HAVE_FTIME
  603. if (!scm_your_base.time) ftime(&scm_your_base);
  604. #else
  605. if (!scm_your_base) time(&scm_your_base);
  606. #endif
  607. if (!scm_my_base) scm_my_base = mytime();
  608. scm_add_feature ("current-time");
  609. #include "libguile/stime.x"
  610. }
  611. /*
  612. Local Variables:
  613. c-file-style: "gnu"
  614. End:
  615. */