rktio: add date & time
This commit is contained in:
parent
c006e951f4
commit
636b1637b4
|
@ -24,6 +24,7 @@ OBJS = rktio_fs.@LTO@ \
|
|||
rktio_envvars.@LTO@ \
|
||||
rktio_fs_change.@LTO@ \
|
||||
rktio_flock.@LTO@ \
|
||||
rktio_time.@LTO@ \
|
||||
rktio_error.@LTO@ \
|
||||
rktio_hash.@LTO@ \
|
||||
rktio_wide.@LTO@ \
|
||||
|
@ -72,6 +73,9 @@ rktio_fs_change.@LTO@: $(srcdir)/rktio_fs_change.c $(RKTIO_HEADERS)
|
|||
rktio_flock.@LTO@: $(srcdir)/rktio_flock.c $(RKTIO_HEADERS)
|
||||
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_flock.@LTO@ -c $(srcdir)/rktio_flock.c
|
||||
|
||||
rktio_time.@LTO@: $(srcdir)/rktio_time.c $(RKTIO_HEADERS)
|
||||
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_time.@LTO@ -c $(srcdir)/rktio_time.c
|
||||
|
||||
rktio_error.@LTO@: $(srcdir)/rktio_error.c $(RKTIO_HEADERS)
|
||||
$(CC) $(CFLAGS) -I$(srcdir) -I. -o rktio_error.@LTO@ -c $(srcdir)/rktio_error.c
|
||||
|
||||
|
|
|
@ -435,6 +435,20 @@ static rktio_fd_t *connect_loop(rktio_t *rktio, rktio_addrinfo_t *addr, rktio_ad
|
|||
return fd;
|
||||
}
|
||||
|
||||
static char *month_name(rktio_t *rktio, int month)
|
||||
{
|
||||
static char *months[] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "NOV", "DEC"};
|
||||
check_valid((month >= 1) && (month <= 12));
|
||||
return months[month-1];
|
||||
}
|
||||
|
||||
static char *week_day_name(rktio_t *rktio, int dow)
|
||||
{
|
||||
static char *days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
|
||||
check_valid((dow >= 0) && (dow <= 6));
|
||||
return days[dow-1];
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
rktio_t *rktio;
|
||||
|
@ -897,6 +911,7 @@ int main(int argc, char **argv)
|
|||
char *path = "test1";
|
||||
rktio_fs_change_t *fc;
|
||||
rktio_poll_set_t *ps;
|
||||
double start;
|
||||
|
||||
if (verbose)
|
||||
printf("fs change\n");
|
||||
|
@ -910,9 +925,10 @@ int main(int argc, char **argv)
|
|||
check_valid(ps);
|
||||
rktio_poll_add_fs_change(rktio, fc, ps);
|
||||
|
||||
start = rktio_get_inexact_milliseconds();
|
||||
rktio_sleep(rktio, 0.1, ps, NULL);
|
||||
rktio_poll_set_close(rktio, ps);
|
||||
/* FIXME: check that at least 0.1 seconds have passed */
|
||||
check_valid(rktio_get_inexact_milliseconds() - start > 0.1);
|
||||
|
||||
ps = rktio_make_poll_set(rktio);
|
||||
check_valid(ps);
|
||||
|
@ -1005,6 +1021,35 @@ int main(int argc, char **argv)
|
|||
rktio_close(rktio, fd);
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
printf("time and date\n");
|
||||
|
||||
{
|
||||
intptr_t now;
|
||||
rktio_date_t *today;
|
||||
int gmt;
|
||||
|
||||
now = rktio_get_seconds(rktio);
|
||||
|
||||
for (gmt = 0; gmt <= 1; gmt++) {
|
||||
today = rktio_seconds_to_date(rktio, now, 5000, gmt);
|
||||
check_valid(today);
|
||||
|
||||
printf("%2.2d:%2.2d:%2.2d %s(%+d/%+d%s) on %s %d-%s-%ld [day %d of year]\n",
|
||||
today->hour, today->minute, today->second,
|
||||
today->zone_name ? today->zone_name : "",
|
||||
today->zone_offset, today->zone_offset / (60 * 60),
|
||||
(today->is_dst ? ";DST" : ""),
|
||||
week_day_name(rktio, today->day_of_week),
|
||||
today->day, month_name(rktio, today->month), today->year,
|
||||
today->day_of_year);
|
||||
|
||||
if (today->zone_name)
|
||||
free(today->zone_name);
|
||||
free(today);
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose)
|
||||
printf("done\n");
|
||||
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
#include "rktio_config.h"
|
||||
|
||||
/* A rktio_t value represents an instance of the Racket I/O system.
|
||||
Every rktio_...() function takes it as the first argument, except
|
||||
for rktio_init(), rktio_signal_received_at(), and rktio_free(). */
|
||||
Almost every rktio_...() function takes it as the first argument. */
|
||||
typedef struct rktio_t rktio_t;
|
||||
|
||||
rktio_t *rktio_init(void);
|
||||
|
@ -386,6 +385,28 @@ rktio_signal_handle_t *rktio_get_signal_handle(rktio_t *rktio);
|
|||
void rktio_signal_received_at(rktio_signal_handle_t *h);
|
||||
void rktio_signal_received(rktio_t *rktio);
|
||||
|
||||
/*************************************************/
|
||||
/* Time and date */
|
||||
|
||||
typedef struct rktio_date_t {
|
||||
int nanosecond, second, minute, hour, day, month;
|
||||
intptr_t year;
|
||||
int day_of_week;
|
||||
int day_of_year;
|
||||
int is_dst;
|
||||
int zone_offset;
|
||||
char *zone_name; /* can be NULL */
|
||||
} rktio_date_t;
|
||||
|
||||
intptr_t rktio_get_milliseconds(void);
|
||||
double rktio_get_inexact_milliseconds(void);
|
||||
|
||||
intptr_t rktio_get_process_milliseconds(rktio_t *rktio);
|
||||
intptr_t scheme_get_process_children_milliseconds(rktio_t *rktio);
|
||||
|
||||
intptr_t rktio_get_seconds(rktio_t *rktio);
|
||||
rktio_date_t *rktio_seconds_to_date(rktio_t *rktio, intptr_t seconds, intptr_t nanoseconds, int get_gmt);
|
||||
|
||||
/*************************************************/
|
||||
/* Errors */
|
||||
|
||||
|
@ -418,6 +439,7 @@ enum {
|
|||
RKTIO_ERROR_INFO_TRY_AGAIN, /* for UDP */
|
||||
RKTIO_ERROR_TRY_AGAIN, /* for UDP */
|
||||
RKTIO_ERROR_TRY_AGAIN_WITH_IPV4, /* for TCP listen */
|
||||
RKTIO_ERROR_TIME_OUT_OF_RANGE,
|
||||
};
|
||||
|
||||
/* GAI error sub-codes */
|
||||
|
|
|
@ -37,4 +37,4 @@ typedef unsigned long uintptr_t;
|
|||
#undef RKTIO_STATIC_FDSET_SIZE
|
||||
|
||||
/* In case you want to use fcntl for file locks */
|
||||
#undef USE_FCNTL_AND_FORK_FOR_FILE_LOCKS
|
||||
#undef RKTIO_USE_FCNTL_AND_FORK_FOR_FILE_LOCKS
|
||||
|
|
|
@ -45,9 +45,11 @@ int rktio_get_last_error_kind(rktio_t *rktio)
|
|||
const char *rktio_get_error_string(rktio_t *rktio, int kind, int errid)
|
||||
{
|
||||
const char *s = NULL;
|
||||
if (kind == RKTIO_ERROR_KIND_POSIX)
|
||||
if (kind == RKTIO_ERROR_KIND_POSIX) {
|
||||
#ifndef NO_STRERROR_AVAILABLE
|
||||
s = strerror(errid);
|
||||
else if (kind == RKTIO_ERROR_KIND_GAI)
|
||||
#endif
|
||||
} else if (kind == RKTIO_ERROR_KIND_GAI)
|
||||
s = rktio_gai_strerror(errid);
|
||||
if (s) return s;
|
||||
return "???";
|
||||
|
|
|
@ -308,7 +308,7 @@ void rktio_reliably_close(intptr_t s) {
|
|||
int rktio_close(rktio_t *rktio, rktio_fd_t *rfd)
|
||||
{
|
||||
#ifdef RKTIO_SYSTEM_UNIX
|
||||
# ifdef USE_FCNTL_AND_FORK_FOR_FILE_LOCKS
|
||||
# ifdef RKTIO_USE_FCNTL_AND_FORK_FOR_FILE_LOCKS
|
||||
if (!(rfd->modes & RKTIO_OPEN_SOCKET))
|
||||
rktio_release_lockf(rktio, rfd->fd);
|
||||
# endif
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if defined(RKTIO_SYSTEM_UNIX) && !defined(USE_FCNTL_AND_FORK_FOR_FILE_LOCKS)
|
||||
#if defined(RKTIO_SYSTEM_UNIX) && !defined(RKTIO_USE_FCNTL_AND_FORK_FOR_FILE_LOCKS)
|
||||
# define USE_FLOCK_FOR_FILE_LOCKS
|
||||
#endif
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
|||
#include <sys/file.h>
|
||||
#endif
|
||||
|
||||
#if defined(USE_FCNTL_AND_FORK_FOR_FILE_LOCKS)
|
||||
#if defined(RKTIO_USE_FCNTL_AND_FORK_FOR_FILE_LOCKS)
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
typedef struct pair_t { int car, cdr; } pair_t;
|
||||
|
@ -39,7 +39,7 @@ int rktio_file_lock_try(rktio_t *rktio, rktio_fd_t *rfd, int excl)
|
|||
get_posix_error();
|
||||
return RKTIO_LOCK_ERROR;
|
||||
}
|
||||
# elif defined(USE_FCNTL_AND_FORK_FOR_FILE_LOCKS)
|
||||
# elif defined(RKTIO_USE_FCNTL_AND_FORK_FOR_FILE_LOCKS)
|
||||
/* An lockf() is cancelled if *any* file descriptor to the same file
|
||||
is closed within the same process. We avoid that problem by forking
|
||||
a new process whose only job is to use lockf(). */
|
||||
|
@ -194,7 +194,7 @@ int rktio_file_lock_try(rktio_t *rktio, rktio_fd_t *rfd, int excl)
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_FCNTL_AND_FORK_FOR_FILE_LOCKS
|
||||
#ifdef RKTIO_USE_FCNTL_AND_FORK_FOR_FILE_LOCKS
|
||||
void rktio_release_lockf(rktio_t *rktio, int fd)
|
||||
{
|
||||
if (rktio->locked_fd_process_map) {
|
||||
|
@ -227,7 +227,7 @@ int rktio_file_unlock(rktio_t *rktio, rktio_fd_t *rfd)
|
|||
} while ((ok == -1) && (errno == EINTR));
|
||||
ok = !ok;
|
||||
if (!ok) get_posix_error();
|
||||
# elif defined(USE_FCNTL_AND_FORK_FOR_FILE_LOCKS)
|
||||
# elif defined(RKTIO_USE_FCNTL_AND_FORK_FOR_FILE_LOCKS)
|
||||
rktio_release_lockf(rktio, fd);
|
||||
ok = 1;
|
||||
# else
|
||||
|
|
|
@ -33,10 +33,6 @@
|
|||
# define BIG_OFF_T_IZE(n) n
|
||||
#endif
|
||||
|
||||
#if defined(__linux__)
|
||||
# define DIRENT_NO_NAMLEN
|
||||
#endif
|
||||
|
||||
#if defined(RKTIO_SYSTEM_UNIX) && !defined(NO_UNIX_USERS)
|
||||
static int have_user_ids = 0;
|
||||
static uid_t uid;
|
||||
|
|
|
@ -36,27 +36,6 @@ typedef struct sockaddr_in rktio_unspec_address;
|
|||
#define REGISTER_SOCKET(s) /**/
|
||||
#define UNREGISTER_SOCKET(s) /**/
|
||||
|
||||
# if defined(__linux__) || defined(OS_X)
|
||||
/* RKTIO_TCP_LISTEN_IPV6_ONLY_SOCKOPT uses IPV6_V6ONLY for IPv6
|
||||
listeners when the same listener has an IPv4 address, which means
|
||||
that the IpV6 listener accepts only IPv6 connections. This is used
|
||||
with Linux, for example, because a port cannot have both an IPv4
|
||||
and IPv6 listener if the IPv6 one doesn't use IPV6_V6ONLY. (The
|
||||
two listeners might be for different interfaces, in which case
|
||||
IPV6_V6ONLY is not necessary, but we must err on the side of being
|
||||
too restrictive. If IPV6_V6ONLY is not #defined or if setting the
|
||||
option doesn't work, then the IPv6 addresses are silently ignored
|
||||
when creating the listener (but only where there is at least once
|
||||
IPv4 address). */
|
||||
# define RKTIO_TCP_LISTEN_IPV6_ONLY_SOCKOPT
|
||||
# endif
|
||||
|
||||
#if defined(sun)
|
||||
/* USE_NULL_TO_DISCONNECT_UDP calls connect() with NULL instead of
|
||||
an AF_UNSPEC address to disconnect a UDP socket. */
|
||||
# define USE_NULL_TO_DISCONNECT_UDP
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef CANT_SET_SOCKET_BUFSIZE
|
||||
|
|
373
racket/src/rktio/rktio_platform.h
Normal file
373
racket/src/rktio/rktio_platform.h
Normal file
|
@ -0,0 +1,373 @@
|
|||
/************** SunOS/Solaris ****************/
|
||||
|
||||
#if defined(sun)
|
||||
|
||||
# include "uconfig.h"
|
||||
|
||||
# define USE_EXPLICT_FP_FORM_CHECK
|
||||
|
||||
# include <errno.h>
|
||||
# ifdef ECHRNG
|
||||
/* Solaris */
|
||||
# define DIRENT_NO_NAMLEN
|
||||
# define NO_USLEEP
|
||||
# define USE_ULIMIT
|
||||
# define SOME_FDS_ARE_NOT_SELECTABLE
|
||||
# define RKTIO_USE_FCNTL_AND_FORK_FOR_FILE_LOCKS
|
||||
# define USE_TIMEZONE_AND_ALTZONE_VAR
|
||||
# define USE_TZNAME_VAR
|
||||
# define USE_NULL_TO_DISCONNECT_UDP
|
||||
# else
|
||||
/* SunOS4 */
|
||||
# define USE_TM_GMTOFF_FIELD
|
||||
# define USE_TM_ZONE_FIELD
|
||||
# define NO_STRERROR_AVAILABLE
|
||||
# define USE_FNDELAY_O_NONBLOCK
|
||||
# endif
|
||||
|
||||
# ifdef _POSIX_PTHREAD_SEMANTICS
|
||||
# define SUBPROCESS_USE_FORK1
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
/************** RS6000/AIX ****************/
|
||||
|
||||
# if defined(_IBMR2)
|
||||
|
||||
# define SELECT_INCLUDE
|
||||
|
||||
# define USE_TIMEZONE_VAR_W_DLS
|
||||
# define USE_TZNAME_VAR
|
||||
|
||||
#endif
|
||||
|
||||
/************** Linux ****************/
|
||||
|
||||
#if defined(__linux__)
|
||||
|
||||
# define DIRENT_NO_NAMLEN
|
||||
|
||||
# define SIGSET_NEEDS_REINSTALL
|
||||
|
||||
# define USE_TIMEZONE_VAR_W_DLS
|
||||
# define USE_TZNAME_VAR
|
||||
|
||||
# define RKTIO_TCP_LISTEN_IPV6_ONLY_SOCKOPT
|
||||
|
||||
# ifdef __ANDROID__
|
||||
# define PROTOENT_IS_INT IPPROTO_TCP
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
/********************* NetBSD ***********************/
|
||||
|
||||
#if defined(__NetBSD__)
|
||||
|
||||
# define USE_TM_GMTOFF_FIELD
|
||||
# define USE_TM_ZONE_FIELD
|
||||
|
||||
#endif
|
||||
|
||||
/************** OpenBSD ****************/
|
||||
/* Thanks to Bengt Kleberg */
|
||||
|
||||
#if defined(__OpenBSD__)
|
||||
|
||||
# define USE_TM_GMTOFF_FIELD
|
||||
# define USE_TM_ZONE_FIELD
|
||||
|
||||
#endif
|
||||
|
||||
/************** FreeBSD ****************/
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
|
||||
# define USE_TM_GMTOFF_FIELD
|
||||
# define USE_TM_ZONE_FIELD
|
||||
# define MAX_VALID_DATE_SECONDS_BITS 51
|
||||
|
||||
#endif
|
||||
|
||||
/************** SGI/IRIX ****************/
|
||||
|
||||
#if (defined(mips) || defined(__mips)) \
|
||||
&& !(defined(ultrix) || defined(__ultrix) || defined(__linux__) || defined(__OpenBSD__))
|
||||
|
||||
# define DIRENT_NO_NAMLEN
|
||||
|
||||
# define BSTRING_INCLUDE
|
||||
|
||||
# define NO_USLEEP
|
||||
|
||||
# define USE_TIMEZONE_AND_ALTZONE_VAR
|
||||
# define USE_TZNAME_VAR
|
||||
|
||||
#endif
|
||||
|
||||
/************** Ultrix ****************/
|
||||
|
||||
#if defined(ultrix) || defined(__ultrix)
|
||||
|
||||
# define DIRENT_NO_NAMLEN
|
||||
|
||||
# define NO_USLEEP
|
||||
|
||||
#endif
|
||||
|
||||
/************** ALPHA/OSF1 ****************/
|
||||
|
||||
# if (defined(__alpha) || defined(__alpha__)) \
|
||||
&& !defined(__linux__) && !defined(__NetBSD__) && !defined(__OpenBSD__)
|
||||
|
||||
# define USE_FNDELAY_O_NONBLOCK
|
||||
|
||||
#endif
|
||||
|
||||
/************** HP/UX with cc or gcc ****************/
|
||||
|
||||
#if defined(__hpux)
|
||||
|
||||
# define SOME_FDS_ARE_NOT_SELECTABLE
|
||||
|
||||
# define USE_SYSCALL_GETRUSAGE
|
||||
|
||||
# define USE_ULIMIT
|
||||
|
||||
# define USE_TIMEZONE_VAR_W_DLS
|
||||
# define USE_TZNAME_VAR
|
||||
|
||||
#endif
|
||||
|
||||
/************** x86/SCO Unix with gcc ****************/
|
||||
/* Contributed by Atanas Ivanov <nasko@noac.bg> */
|
||||
|
||||
#if defined(_M_XENIX) && defined(_M_SYSV)
|
||||
|
||||
# define DIRENT_NO_NAMLEN
|
||||
|
||||
#endif
|
||||
|
||||
/****************** Windows with MSVC or MinGW *****************/
|
||||
|
||||
#if (defined(__BORLANDC__) \
|
||||
|| ((defined(_MSC_VER) || defined(__MINGW32__)) \
|
||||
&& (defined(__WIN32__) || defined(WIN32) || defined(_WIN32))))
|
||||
|
||||
# if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
# define NO_READDIR
|
||||
# define USE_FINDFIRST
|
||||
# define MKDIR_NO_MODE_FLAG
|
||||
# endif
|
||||
# if defined(__BORLANDC__)
|
||||
# define DIRENT_NO_NAMLEN
|
||||
# define MKDIR_NO_MODE_FLAG
|
||||
# endif
|
||||
|
||||
#endif
|
||||
|
||||
/******************** Windows with Cygwin ******************/
|
||||
|
||||
#if defined(__CYGWIN32__)
|
||||
|
||||
# define RKTIO_BINARY O_BINARY
|
||||
|
||||
# define DIRENT_NO_NAMLEN
|
||||
|
||||
# define SIGCHILD_DOESNT_INTERRUPT_SELECT
|
||||
# define SIGSET_NEEDS_REINSTALL
|
||||
|
||||
# define CANT_SET_SOCKET_BUFSIZE
|
||||
# define NO_NEED_FOR_BEGINTHREAD
|
||||
# define USE_CREATE_PIPE
|
||||
|
||||
# define USE_PLAIN_TIME
|
||||
# define USE_TOD_FOR_TIMEZONE
|
||||
|
||||
#endif
|
||||
|
||||
/************** MacOS and Darwin ****************/
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
|
||||
# define RKTIO_TCP_LISTEN_IPV6_ONLY_SOCKOPT
|
||||
|
||||
# define USE_TM_GMTOFF_FIELD
|
||||
# define USE_TM_ZONE_FIELD
|
||||
|
||||
# define UDP_DISCONNECT_EADRNOTAVAIL_OK
|
||||
|
||||
# endif
|
||||
|
||||
/************ QNX *************/
|
||||
|
||||
#if defined(__QNX__)
|
||||
|
||||
# define SIGSET_NEEDS_REINSTALL
|
||||
|
||||
# define BROKEN_READLINK_NUL_TERMINATOR
|
||||
|
||||
#endif
|
||||
|
||||
/************ Dragonfly *************/
|
||||
|
||||
#if defined(__DragonFly__)
|
||||
|
||||
# define USE_TM_GMTOFF_FIELD
|
||||
# define USE_TM_ZONE_FIELD
|
||||
# define MAX_VALID_DATE_SECONDS_BITS 51
|
||||
|
||||
#endif
|
||||
|
||||
/***************************************************/
|
||||
|
||||
/***** CONFIGURATION FLAG DESCRPTIONS ******/
|
||||
|
||||
/*********************/
|
||||
/* Date and time */
|
||||
/*********************/
|
||||
|
||||
/* DONT_USE_GETRUSAGE uses clock() for timing info. */
|
||||
|
||||
/* USE_SYSCALL_GETRUSAGE uses syscall() to implement getrusage() for
|
||||
timing info. Used with USE_GETRUSAGE. */
|
||||
|
||||
/* CLOCKS_PER_SEC relates the values returned by clock() to
|
||||
real seconds. (The difference between two clock() calls is
|
||||
divided by this number.) Usually, this is defined in <time.h>;
|
||||
it defaults to 1000000 */
|
||||
|
||||
/* USE_PLAIN_TIME uses time. */
|
||||
|
||||
/* CLOCK_IS_USER_TIME uses the system time for user milliseconds. */
|
||||
|
||||
/* USER_TIME_IS_CLOCK uses the user time for system milliseconds. */
|
||||
|
||||
/* MAX_VALID_DATE_SECONDS_BITS sets a maximum number of bits for
|
||||
seconds to pass to localtime() ro gmtime(). */
|
||||
|
||||
/* MIN_VALID_DATE_SECONDS sets a minimum vald time in seconds. */
|
||||
|
||||
/* USE_TIMEZONE_VAR gets timezone offset from a timezone global.
|
||||
USE_TOD_FOR_TIMEZONE gets timezone offset via gettimeofday.
|
||||
USE_TIMEZONE_VAR_W_DLS is similar, but adds 1 hour when daylight
|
||||
savings is in effect.
|
||||
USE_TIMEZONE_AND_ALTZONE_VAR is similar, but uses altzone when
|
||||
daylight savings is in effect.
|
||||
USE_TM_GMTOFF_FIELD gets timezone offset from the tm_gmtoff field
|
||||
of the tm struct. */
|
||||
|
||||
/* USE_TZNAME_VAR gets the timezone name from a tzname global.
|
||||
USE_TM_ZONE_FIELD gets the timezone name from a tm_zone field
|
||||
of the tm struct. */
|
||||
|
||||
/*******************/
|
||||
/* Filesystem */
|
||||
/*******************/
|
||||
|
||||
/* NO_STAT_PROC means that there is no stat() function. */
|
||||
|
||||
/* NO_MKDIR means that there is no mkdir() function. */
|
||||
|
||||
/* BROKEN_READLINK_NUL_TERMINATOR means that readlink() may
|
||||
report a length that includes trailing NUL terminators,
|
||||
which should be stripped away. */
|
||||
|
||||
/* USE_GETDISK uses getdisk() and setdisk() to implement the
|
||||
filesystem-root-list primitive under DOS. */
|
||||
|
||||
/* NO_READDIR means that there is no opendir() and readdir() for
|
||||
implementing directory-list. */
|
||||
|
||||
/* DIRENT_NO_NAMLEN specifies that dirent entries do not have a
|
||||
d_namlen field; this is used only when NO_READDIR is not
|
||||
specified. */
|
||||
|
||||
/* MKDIR_NO_MODE_FLAG specifies that mkdir() takes only one argument,
|
||||
instead of a directory name and mode flags. */
|
||||
|
||||
/***********************/
|
||||
/* File descriptors */
|
||||
/***********************/
|
||||
|
||||
/* RKTIO_USE_FCNTL_AND_FORK_FOR_FILE_LOCKS means that fnctl() and fork()
|
||||
should be used to implement file locking instead of flock(). */
|
||||
|
||||
/* SUBPROCESS_USE_FORK1 uses fork1() instead of fork(). */
|
||||
|
||||
/* USE_FNDELAY_O_NONBLOCK uses FNDELAY instead of O_NONBLOCK for
|
||||
fcntl on Unix TCP sockets. */
|
||||
|
||||
/* SOME_FDS_ARE_NOT_SELECTABLE indicates that select() doesn't work
|
||||
for reading on all kinds of file descriptors. Such FDs must never
|
||||
be able to go from no-char-ready to char-ready while Racket is
|
||||
sleeping. */
|
||||
|
||||
/* USE_TRANSITIONAL_64_FILE_OPS uses fseeko64, lseek64, stat64, etc.
|
||||
for file operations involving sizes (that can require 64-bit
|
||||
arithmetic). The `configure` script normally finds this one. */
|
||||
|
||||
/* USE_ULIMIT uses ulimit instead of getdtablesize. */
|
||||
|
||||
/* CANT_SET_SOCKET_BUFSIZE turns off setting the buffer size for
|
||||
Unix TCP sockets. */
|
||||
|
||||
/* USE_NULL_TO_DISCONNECT_UDP calls connect() with NULL instead of
|
||||
an AF_UNSPEC address to disconnect a UDP socket. */
|
||||
|
||||
/* UDP_DISCONNECT_EADRNOTAVAIL_OK means that a disconnecting call
|
||||
to connect() might return EADDRNOTAVAIL instead of
|
||||
EAFNOSUPPORT. */
|
||||
|
||||
/* MZ_BINARY is combined with other flags in all calls to open();
|
||||
it can be defined to O_BINARY in Cygwin, for example. */
|
||||
|
||||
/* MZ_TCP_LISTEN_IPV6_ONLY_SOCKOPT uses IPV6_V6ONLY for IPv6
|
||||
listeners when the same listener has an IPv4 address, which means
|
||||
that the IpV6 listener accepts only IPv6 connections. This is used
|
||||
with Linux, for example, because a port cannot have both an IPv4
|
||||
and IPv6 listener if the IPv6 one doesn't use IPV6_V6ONLY. (The
|
||||
two listeners might be for different interfaces, in which case
|
||||
IPV6_V6ONLY is not necessary, but we must err on the side of being
|
||||
too restrictive. If IPV6_V6ONLY is not #defined or if setting the
|
||||
option doesn't work, then the IPv6 addresses are silently ignored
|
||||
when creating the listener (but only where there is at least once
|
||||
IPv4 address). */
|
||||
|
||||
/***********************/
|
||||
/* Signals */
|
||||
/***********************/
|
||||
|
||||
/* SIGSET_NEEDS_REINSTALL reinstalls a signal handler when it
|
||||
is called to handle a signal. The expected semantics of sigset()
|
||||
(when this flags is not defined) is that a signal handler is NOT
|
||||
reset to SIG_DFL after a handler is called to handle a signal. */
|
||||
|
||||
/* USE_CREATE_PIPE uses CreatePipe() instead of _pipe() for Windows. */
|
||||
|
||||
/* SIGCHILD_DOESNT_INTERRUPT_SELECT indicates that the SIGCHILD
|
||||
signal, sent when a child OS process dies, does not interrupt
|
||||
select(). This flag is needed for Cygwin B20. */
|
||||
|
||||
/***********************/
|
||||
/* Miscellaneous */
|
||||
/***********************/
|
||||
|
||||
/* DIR_INCLUDE if there's a <dir.h> file (mainly for Windows). */
|
||||
|
||||
/* DIRECT_INCLUDE if there's a <direct.h> file (mainly for Windows). */
|
||||
|
||||
/* IO_INCLUDE if there's a <io.h> file (mainly for Windows). */
|
||||
|
||||
/* SELECT_INCLUDE if there's a <sys/select.h> file (mainly for Unix). */
|
||||
|
||||
/* BSTRING_INCLUDE if there's a <bstring.h> file (mainly for Unix). */
|
||||
|
||||
/* NO_SLEEP means that there is no sleep() function. Used only in
|
||||
standalone Racket. */
|
||||
|
||||
/* NO_USLEEP means that there is no usleep() function. Used only in
|
||||
standalone Racket. Used only if NO_SLEEP is undefined. */
|
||||
|
||||
/* NO_STRERROR_AVAILABLE means that strerror() is not available. */
|
|
@ -2,6 +2,8 @@
|
|||
# define OS_X
|
||||
#endif
|
||||
|
||||
#include "rktio_platform.h"
|
||||
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
# include <winsock2.h>
|
||||
# include <windows.h>
|
||||
|
@ -84,7 +86,7 @@ struct rktio_t {
|
|||
wchar_t *wide_buffer;
|
||||
#endif
|
||||
|
||||
#ifdef USE_FCNTL_AND_FORK_FOR_FILE_LOCKS
|
||||
#ifdef RKTIO_USE_FCNTL_AND_FORK_FOR_FILE_LOCKS
|
||||
struct rktio_hash_t *locked_fd_process_map;
|
||||
#endif
|
||||
};
|
||||
|
@ -250,10 +252,10 @@ void rktio_set_windows_error(rktio_t *rktio, int errid);
|
|||
# define set_windows_error(errid) rktio_set_windows_error(rktio, errid)
|
||||
#endif
|
||||
|
||||
#if defined(USE_FCNTL_O_NONBLOCK)
|
||||
# define RKTIO_NONBLOCKING O_NONBLOCK
|
||||
#else
|
||||
#if defined(USE_FNDELAY_O_NONBLOCK)
|
||||
# define RKTIO_NONBLOCKING FNDELAY
|
||||
#else
|
||||
# define RKTIO_NONBLOCKING O_NONBLOCK
|
||||
#endif
|
||||
|
||||
#ifndef RKTIO_BINARY
|
||||
|
@ -277,6 +279,19 @@ void rktio_winsock_done(rktio_t *rktio);
|
|||
#endif
|
||||
void rktio_init_wide(rktio_t *rktio);
|
||||
|
||||
#ifdef USE_FCNTL_AND_FORK_FOR_FILE_LOCKS
|
||||
#ifdef RKTIO_USE_FCNTL_AND_FORK_FOR_FILE_LOCKS
|
||||
void rktio_release_lockf(rktio_t *rktio, int fd);
|
||||
#endif
|
||||
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
# ifdef _MSC_VER
|
||||
typedef _int64 rktio_int64_t;
|
||||
typedef unsigned _int64 rktio_uint64_t;
|
||||
# else
|
||||
typedef __int64 rktio_int64_t;
|
||||
typedef unsigned __int64 rktio_uint64_t;
|
||||
# endif
|
||||
#else
|
||||
typedef long long rktio_int64_t;
|
||||
typedef unsigned long long rktio_uint64_t;
|
||||
#endif
|
||||
|
|
|
@ -752,10 +752,10 @@ static void collect_process_time(rktio_t *rktio, DWORD w, rktio_process_t *sp)
|
|||
if ((w != STILL_ACTIVE) && !sp->got_time) {
|
||||
FILETIME cr, ex, kr, us;
|
||||
if (GetProcessTimes(sp->handle, &cr, &ex, &kr, &us)) {
|
||||
__int64 v;
|
||||
rktio_int64_t v;
|
||||
uintptr_t msecs;
|
||||
v = ((((__int64)kr.dwHighDateTime << 32) + kr.dwLowDateTime)
|
||||
+ (((__int64)us.dwHighDateTime << 32) + us.dwLowDateTime));
|
||||
v = ((((rktio_int64_t)kr.dwHighDateTime << 32) + kr.dwLowDateTime)
|
||||
+ (((rktio_int64_t)us.dwHighDateTime << 32) + us.dwLowDateTime));
|
||||
msecs = (uintptr_t)(v / 10000);
|
||||
|
||||
rktio->process_children_msecs += msecs;
|
||||
|
|
484
racket/src/rktio/rktio_time.c
Normal file
484
racket/src/rktio/rktio_time.c
Normal file
|
@ -0,0 +1,484 @@
|
|||
#include "rktio.h"
|
||||
#include "rktio_private.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#if !defined(DONT_USE_GETRUSAGE) && defined(RKTIO_SYSTEM_UNIX)
|
||||
# define USE_GETRUSAGE
|
||||
#endif
|
||||
|
||||
#ifdef RKTIO_SYSTEM_UNIX
|
||||
# include <time.h>
|
||||
# include <sys/time.h>
|
||||
# ifdef USE_GETRUSAGE
|
||||
# include <sys/types.h>
|
||||
# include <sys/time.h>
|
||||
# include <sys/resource.h>
|
||||
# include <errno.h>
|
||||
# endif /* USE_GETRUSAGE */
|
||||
# ifdef USE_SYSCALL_GETRUSAGE
|
||||
# include <sys/syscall.h>
|
||||
# define getrusage(a, b) syscall(SYS_GETRUSAGE, a, b)
|
||||
# define USE_GETRUSAGE
|
||||
# endif /* USE_SYSCALL_GETRUSAGE */
|
||||
# if !defined(USE_GETRUSAGE) && !defined(USER_TIME_IS_CLOCK)
|
||||
# include <sys/times.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
typedef BOOL (WINAPI*GetTimeZoneInformationForYearProc_t)(USHORT wYear, void* pdtzi, LPTIME_ZONE_INFORMATION ptzi);
|
||||
static GetTimeZoneInformationForYearProc_t GetTimeZoneInformationForYearProc;
|
||||
|
||||
typedef BOOL (WINAPI*SystemTimeToTzSpecificLocalTimeExProc_t)(void *lpTimeZoneInformation,
|
||||
const SYSTEMTIME *lpUniversalTime,
|
||||
LPSYSTEMTIME lpLocalTime);
|
||||
static SystemTimeToTzSpecificLocalTimeExProc_t SystemTimeToTzSpecificLocalTimeExProc;
|
||||
#endif
|
||||
|
||||
/*========================================================================*/
|
||||
/* Time */
|
||||
/*========================================================================*/
|
||||
|
||||
#ifndef CLOCKS_PER_SEC
|
||||
#define CLOCKS_PER_SEC 1000000
|
||||
#endif
|
||||
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
/* Number of milliseconds from 1601 to 1970: */
|
||||
# define MSEC_OFFSET 11644473600000
|
||||
|
||||
rktio_int64_t get_hectonanoseconds_as_longlong()
|
||||
/* this function can be called from any OS thread */
|
||||
{
|
||||
FILETIME ft;
|
||||
rktio_int64_t v;
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
v = ((rktio_int64_t)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
|
||||
v -= ((rktio_int64_t)MSEC_OFFSET * 10000);
|
||||
return v;
|
||||
}
|
||||
#endif
|
||||
|
||||
intptr_t rktio_get_milliseconds(void)
|
||||
/* this function can be called from any OS thread */
|
||||
{
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
return (intptr_t)(get_hectonanoseconds_as_longlong() / (rktio_int64_t)10000);
|
||||
#else
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
return now.tv_sec * 1000 + now.tv_usec / 1000;
|
||||
#endif
|
||||
}
|
||||
|
||||
double rktio_get_inexact_milliseconds(void)
|
||||
/* this function can be called from any OS thread */
|
||||
{
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
rktio_int64_t v;
|
||||
v = get_hectonanoseconds_as_longlong();
|
||||
return (double)(v / 10000) + (((double)(v % 10000)) / 10000.0);
|
||||
#else
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
return (double)now.tv_sec * 1000.0 + (double)now.tv_usec / 1000;
|
||||
#endif
|
||||
}
|
||||
|
||||
intptr_t rktio_get_process_milliseconds(rktio_t *rktio)
|
||||
{
|
||||
#ifdef USER_TIME_IS_CLOCK
|
||||
return scheme_get_milliseconds();
|
||||
#else
|
||||
# ifdef USE_GETRUSAGE
|
||||
struct rusage use;
|
||||
intptr_t s, u;
|
||||
|
||||
do {
|
||||
if (!getrusage(RUSAGE_SELF, &use))
|
||||
break;
|
||||
} while (errno == EINTR);
|
||||
|
||||
s = use.ru_utime.tv_sec + use.ru_stime.tv_sec;
|
||||
u = use.ru_utime.tv_usec + use.ru_stime.tv_usec;
|
||||
|
||||
return s * 1000 + u / 1000;
|
||||
# else
|
||||
# ifdef RKTIO_SYSTEM_WINDOWS
|
||||
{
|
||||
FILETIME cr, ex, kr, us;
|
||||
if (GetProcessTimes(GetCurrentProcess(), &cr, &ex, &kr, &us)) {
|
||||
rktio_int64_t v;
|
||||
v = ((((rktio_int64_t)kr.dwHighDateTime << 32) + kr.dwLowDateTime)
|
||||
+ (((rktio_int64_t)us.dwHighDateTime << 32) + us.dwLowDateTime));
|
||||
return (uintptr_t)(v / 10000);
|
||||
} else
|
||||
return 0; /* anything better to do? */
|
||||
}
|
||||
# else
|
||||
return clock() * 1000 / CLOCKS_PER_SEC;
|
||||
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
intptr_t scheme_get_process_children_milliseconds(rktio_t *rktio)
|
||||
{
|
||||
#ifdef USER_TIME_IS_CLOCK
|
||||
return 0;
|
||||
#else
|
||||
# ifdef USE_GETRUSAGE
|
||||
struct rusage use;
|
||||
intptr_t s, u;
|
||||
|
||||
do {
|
||||
if (!getrusage(RUSAGE_CHILDREN, &use))
|
||||
break;
|
||||
} while (errno == EINTR);
|
||||
|
||||
s = use.ru_utime.tv_sec + use.ru_stime.tv_sec;
|
||||
u = use.ru_utime.tv_usec + use.ru_stime.tv_usec;
|
||||
|
||||
return (s * 1000 + u / 1000);
|
||||
# else
|
||||
# ifdef RKTIO_SYSTEM_WINDOWS
|
||||
return rktio->process_children_msecs;
|
||||
# else
|
||||
clock_t t;
|
||||
times(&t);
|
||||
return (t.tms_cutime + t.tms_cstime) * 1000 / CLK_TCK;
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
intptr_t rktio_get_seconds(rktio_t *rktio)
|
||||
{
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
return (intptr_t)(get_hectonanoseconds_as_longlong() / (rktio_int64_t)10000000);
|
||||
#else
|
||||
# ifdef USE_PLAIN_TIME
|
||||
time_t now;
|
||||
now = time(NULL);
|
||||
return now;
|
||||
# else
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
return now.tv_sec;
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
|
||||
/*========================================================================*/
|
||||
/* Date */
|
||||
/*========================================================================*/
|
||||
|
||||
#if defined(RKTIO_SYSTEM_WINDOWS)
|
||||
/* Assuming not a leap year (and adjusted elsewhere): */
|
||||
static int month_offsets[13] = { 0, 31, 59, 90,
|
||||
120, 151, 181, 212,
|
||||
243, 273, 304, 334,
|
||||
365};
|
||||
|
||||
# define dtxCOMP(f) if (a->f < b->f) return 1; if (a->f > b->f) return 0;
|
||||
|
||||
static int is_start_day_before(SYSTEMTIME *a, SYSTEMTIME *b)
|
||||
{
|
||||
dtxCOMP(wYear);
|
||||
|
||||
/* When comparing DST boundaries, we expect to get here,
|
||||
because wYear will be 0 to mean "every year". */
|
||||
|
||||
dtxCOMP(wMonth);
|
||||
|
||||
/* When comparing DST boundaries, it's unlikely that we'll get here,
|
||||
because that would mean that StdT and DST start in the same month. */
|
||||
|
||||
dtxCOMP(wDay); /* for DST boundaires, this is a week number */
|
||||
dtxCOMP(wDayOfWeek);
|
||||
dtxCOMP(wHour);
|
||||
dtxCOMP(wMinute);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int is_day_before(SYSTEMTIME *a, SYSTEMTIME *b)
|
||||
/* a is a date, and b is a DST boundary spec */
|
||||
{
|
||||
int dos, doc;
|
||||
|
||||
if (b->wYear) {
|
||||
dtxCOMP(wYear);
|
||||
}
|
||||
|
||||
dtxCOMP(wMonth);
|
||||
|
||||
/* "Date" of a Sunday this month, 0 to 6: */
|
||||
dos = ((a->wDay - a->wDayOfWeek) + 7) % 7;
|
||||
/* Date of first b->wDayOfWeek this month, 1 to 7: */
|
||||
doc = (dos + b->wDayOfWeek) % 7;
|
||||
if (doc == 0) doc = 7;
|
||||
/* Date of change this year: */
|
||||
doc = doc + ((b->wDay - 1) * 7);
|
||||
if (doc > (month_offsets[b->wMonth] - month_offsets[b->wMonth-1]))
|
||||
doc -= 7;
|
||||
/* Above assumes that a time change doesn't occur on a leap day! */
|
||||
|
||||
if (a->wDay < doc)
|
||||
return 1;
|
||||
if (a->wDay > doc)
|
||||
return 0;
|
||||
|
||||
dtxCOMP(wHour);
|
||||
dtxCOMP(wMinute);
|
||||
|
||||
return 0;
|
||||
}
|
||||
# undef dtxCOMP
|
||||
#endif
|
||||
|
||||
#if defined(OS_X) && defined(__x86_64__)
|
||||
/* work around a bug in localtime() in 10.6.8 */
|
||||
# include <sys/param.h>
|
||||
# include <sys/sysctl.h>
|
||||
static int VALID_TIME_RANGE(intptr_t lnow)
|
||||
{
|
||||
/* Fits in 32 bits? */
|
||||
int ilnow = (int)lnow;
|
||||
if (lnow == (intptr_t)ilnow)
|
||||
return 1;
|
||||
|
||||
/* 10.7 or later? */
|
||||
{
|
||||
int a[2];
|
||||
size_t len;
|
||||
char *vers;
|
||||
|
||||
a[0] = CTL_KERN;
|
||||
a[1] = KERN_OSRELEASE;
|
||||
sysctl(a, 2, NULL, &len, NULL, 0);
|
||||
vers = malloc(len * sizeof(char));
|
||||
sysctl(a, 2, vers, &len, NULL, 0);
|
||||
|
||||
if ((vers[0] == '1') && (vers[1] == '0') && (vers[2] == '.')) {
|
||||
/* localtime() in 10.6.x (= 10.x at the kernel layer) doesn't seem
|
||||
to work right with negative numbers that don't fit into 32 bits */
|
||||
free(vers);
|
||||
return 0;
|
||||
}
|
||||
free(vers);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
#else
|
||||
|
||||
# ifdef MIN_VALID_DATE_SECONDS
|
||||
# define VALID_TIME_RANGE_MIN(x) ((x) >= MIN_VALID_DATE_SECONDS)
|
||||
# else
|
||||
# define VALID_TIME_RANGE_MIN(x) 1
|
||||
# endif
|
||||
|
||||
# if defined(MAX_VALID_DATE_SECONDS_BITS) && defined(SIXTY_FOUR_BIT_INTEGERS)
|
||||
# define VALID_TIME_RANGE_BITS(x) (((x) >= 0) \
|
||||
? ((x) == ((x) & (((intptr_t)1 << MAX_VALID_DATE_SECONDS_BITS) - 1))) \
|
||||
: ((-(x)) == ((-(x)) & (((intptr_t)1 << MAX_VALID_DATE_SECONDS_BITS) - 1))))
|
||||
# else
|
||||
# define VALID_TIME_RANGE_BITS(x) 1
|
||||
# endif
|
||||
|
||||
# define VALID_TIME_RANGE(x) (VALID_TIME_RANGE_MIN(x) && VALID_TIME_RANGE_BITS(x))
|
||||
|
||||
#endif
|
||||
|
||||
rktio_date_t *rktio_seconds_to_date(rktio_t *rktio, intptr_t seconds, intptr_t nanoseconds, int get_gmt)
|
||||
{
|
||||
intptr_t lnow;
|
||||
int hour, min, sec, month, day, wday, yday, dst;
|
||||
intptr_t year;
|
||||
long tzoffset;
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
# define CHECK_TIME_T uintptr_t
|
||||
SYSTEMTIME localTime;
|
||||
#else
|
||||
# define CHECK_TIME_T time_t
|
||||
struct tm *localTime;
|
||||
#endif
|
||||
CHECK_TIME_T now;
|
||||
char *tzn;
|
||||
rktio_date_t *result;
|
||||
|
||||
lnow = seconds;
|
||||
|
||||
if ((((intptr_t)(now = (CHECK_TIME_T)lnow)) == lnow)
|
||||
&& VALID_TIME_RANGE(lnow)) {
|
||||
int success;
|
||||
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
{
|
||||
rktio_uint64_t tmpC;
|
||||
tmpC = ((rktio_uint64_t)lnow * 10000000);
|
||||
if ((rktio_int64_t)tmpC / 10000000 != lnow) {
|
||||
/* overflow */
|
||||
success = 0;
|
||||
} else {
|
||||
rktio_int64_t nsC;
|
||||
FILETIME ft;
|
||||
nsC = tmpC + ((rktio_uint64_t)MSEC_OFFSET * 10000);
|
||||
if (nsC < (rktio_int64_t)tmpC) {
|
||||
/* overflow */
|
||||
success = 0;
|
||||
} else {
|
||||
ft.dwLowDateTime = nsC & (rktio_int64_t)0xFFFFFFFF;
|
||||
ft.dwHighDateTime = nsC >> 32;
|
||||
success = FileTimeToSystemTime(&ft, &localTime);
|
||||
if (success && !get_gmt) {
|
||||
SYSTEMTIME t2 = localTime;
|
||||
if (SystemTimeToTzSpecificLocalTimeExProc)
|
||||
success = SystemTimeToTzSpecificLocalTimeExProc(NULL, &t2, &localTime);
|
||||
else
|
||||
success = SystemTimeToTzSpecificLocalTime(NULL, &t2, &localTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (get_gmt)
|
||||
localTime = gmtime(&now);
|
||||
else
|
||||
localTime = localtime(&now);
|
||||
success = !!localTime;
|
||||
#endif
|
||||
|
||||
if (success) {
|
||||
#ifdef RKTIO_SYSTEM_WINDOWS
|
||||
|
||||
hour = localTime.wHour;
|
||||
min = localTime.wMinute;
|
||||
sec = localTime.wSecond;
|
||||
|
||||
month = localTime.wMonth;
|
||||
day = localTime.wDay;
|
||||
year = localTime.wYear;
|
||||
|
||||
wday = localTime.wDayOfWeek;
|
||||
yday = month_offsets[localTime.wMonth-1] + day-1;
|
||||
/* leap-year adjustment: */
|
||||
if ((month > 2)
|
||||
&& ((year % 4) == 0)
|
||||
&& (((year % 100) != 0) || ((year % 400) == 0)))
|
||||
yday++;
|
||||
|
||||
dst = 0;
|
||||
if (get_gmt) {
|
||||
tzoffset = 0;
|
||||
tzn = "UTC";
|
||||
} else {
|
||||
TIME_ZONE_INFORMATION tz;
|
||||
if (GetTimeZoneInformationForYearProc)
|
||||
GetTimeZoneInformationForYearProc(localTime.wYear, NULL, &tz);
|
||||
else
|
||||
(void)GetTimeZoneInformation(&tz);
|
||||
if (tz.StandardDate.wMonth) {
|
||||
if (is_start_day_before(&tz.DaylightDate, &tz.StandardDate)) {
|
||||
/* northern hemisphere */
|
||||
dst = (!is_day_before(&localTime, &tz.DaylightDate)
|
||||
&& is_day_before(&localTime, &tz.StandardDate));
|
||||
} else {
|
||||
/* southern hemisphere */
|
||||
dst = (is_day_before(&localTime, &tz.StandardDate)
|
||||
|| !is_day_before(&localTime, &tz.DaylightDate));
|
||||
}
|
||||
}
|
||||
if (dst) {
|
||||
tzoffset = (tz.Bias + tz.DaylightBias) * -60;
|
||||
tzn = NARROW_PATH_copy(tz.DaylightName);
|
||||
} else {
|
||||
tzoffset = (tz.Bias + tz.StandardBias) * -60;
|
||||
tzn = NARROW_PATH_copy(tz.StandardName);
|
||||
}
|
||||
}
|
||||
#else
|
||||
hour = localTime->tm_hour;
|
||||
min = localTime->tm_min;
|
||||
sec = localTime->tm_sec;
|
||||
|
||||
month = localTime->tm_mon + 1;
|
||||
day = localTime->tm_mday;
|
||||
year = (uintptr_t)localTime->tm_year + 1900;
|
||||
|
||||
wday = localTime->tm_wday;
|
||||
yday = localTime->tm_yday;
|
||||
|
||||
if (get_gmt)
|
||||
dst = 0;
|
||||
else
|
||||
dst = localTime->tm_isdst;
|
||||
|
||||
tzoffset = 0;
|
||||
if (!get_gmt) {
|
||||
# ifdef USE_TIMEZONE_VAR
|
||||
tzoffset = -MSC_IZE(timezone);
|
||||
# endif
|
||||
# ifdef USE_TOD_FOR_TIMEZONE
|
||||
{
|
||||
struct timezone xtz;
|
||||
struct timeval xtv;
|
||||
gettimeofday(&xtv, &xtz);
|
||||
tzoffset = -(xtz.tz_minuteswest * 60);
|
||||
}
|
||||
# endif
|
||||
# ifdef USE_TIMEZONE_VAR_W_DLS
|
||||
tzoffset = -(MSCBOR_IZE(timezone) - (dst ? 3600 : 0));
|
||||
# endif
|
||||
# ifdef USE_TIMEZONE_AND_ALTZONE_VAR
|
||||
if (dst)
|
||||
tzoffset = -altzone;
|
||||
else
|
||||
tzoffset = -timezone;
|
||||
# endif
|
||||
# ifdef USE_TM_GMTOFF_FIELD
|
||||
tzoffset = localTime->tm_gmtoff;
|
||||
# endif
|
||||
# ifdef USE_TZNAME_VAR
|
||||
tzn = MSC_IZE(tzname)[localTime->tm_isdst];
|
||||
# elif defined(USE_TM_ZONE_FIELD)
|
||||
tzn = localTime->tm_zone;
|
||||
# else
|
||||
tzn = NULL;
|
||||
# endif
|
||||
} else
|
||||
tzn = "UTC";
|
||||
|
||||
#endif
|
||||
|
||||
if (!tzn)
|
||||
tzn = "?";
|
||||
|
||||
result = malloc(sizeof(rktio_date_t));
|
||||
|
||||
result->nanosecond = nanoseconds;
|
||||
result->second = sec;
|
||||
result->minute = min;
|
||||
result->hour = hour;
|
||||
result->day = day;
|
||||
result->month = month;
|
||||
result->year = year;
|
||||
result->day_of_week = wday;
|
||||
result->day_of_year = yday;
|
||||
result->is_dst = (dst ? 1 : 0);
|
||||
result->zone_offset = tzoffset;
|
||||
if (tzn)
|
||||
result->zone_name = strdup(tzn);
|
||||
else
|
||||
result->zone_name = NULL;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
set_racket_error(RKTIO_ERROR_TIME_OUT_OF_RANGE);
|
||||
return NULL;
|
||||
}
|
Loading…
Reference in New Issue
Block a user