744 lines
14 KiB
C
744 lines
14 KiB
C
/*
|
|
** This file is in the public domain.
|
|
*/
|
|
|
|
#include "amiga.h"
|
|
#include "private.h"
|
|
#include <dos/var.h>
|
|
#include <devices/timer.h>
|
|
#include <libraries/locale.h>
|
|
#include <utility/date.h>
|
|
|
|
/* Amiga convert functions */
|
|
void Amiga2Tm(ULONG seconds, struct tm *tm);
|
|
ULONG Tm2Amiga(struct tm *tm);
|
|
ULONG Unix2Amiga(time_t t);
|
|
time_t Amiga2Unix(ULONG t);
|
|
void Tm2DateStamp(struct tm *tm, struct DateStamp *date);
|
|
void DateStamp2Tm(struct DateStamp *date, struct tm *tm);
|
|
void Unix2DateStamp(time_t *time, struct DateStamp *date);
|
|
void DateStamp2Unix(struct DateStamp *date, time_t *time);
|
|
void Tm2Date(struct tm *tm, struct ClockData *date);
|
|
void Date2Tm(struct ClockData *date, struct tm *tm);
|
|
void Date2Unix(struct ClockData *date, time_t *time);
|
|
void Unix2Date(time_t *time, struct ClockData *date);
|
|
|
|
static struct timerequest *TimeRequest;
|
|
static struct MsgPort *TimerPort;
|
|
|
|
const struct lc_time_T C_time_locale = {
|
|
{"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
|
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"},
|
|
{"January", "February", "March", "April", "May", "June",
|
|
"July", "August", "September", "October", "November", "December"},
|
|
{"Sun", "Mon", "Tue", "Wed",
|
|
"Thu", "Fri", "Sat"},
|
|
{"Sunday", "Monday", "Tuesday", "Wednesday",
|
|
"Thursday", "Friday", "Saturday"},
|
|
|
|
/* X_fmt */
|
|
"%H:%M:%S",
|
|
|
|
/*
|
|
** x_fmt
|
|
** C99 requires this format.
|
|
** Using just numbers (as here) makes Quakers happier;
|
|
** it's also compatible with SVR4.
|
|
*/
|
|
"%m/%d/%y",
|
|
|
|
/*
|
|
** c_fmt
|
|
** C99 requires this format.
|
|
** Previously this code used "%D %X", but we now conform to C99.
|
|
** Note that
|
|
** "%a %b %d %H:%M:%S %Y"
|
|
** is used by Solaris 2.3.
|
|
*/
|
|
"%a %b %e %T %Y",
|
|
|
|
/* t_fmt_ampm */
|
|
"TODO",
|
|
|
|
/* am */
|
|
"AM",
|
|
|
|
/* pm */
|
|
"PM",
|
|
|
|
/* am_pm */
|
|
{ "TODOAM", "TODOPM"},
|
|
|
|
/* date_fmt */
|
|
"%a %b %e %H:%M:%S %Z %Y"};
|
|
|
|
static int
|
|
CreateTimer()
|
|
{
|
|
int error;
|
|
|
|
TimerPort = CreateMsgPort();
|
|
if (TimerPort == NULL)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
TimeRequest = (struct timerequest *)CreateIORequest(
|
|
TimerPort,
|
|
sizeof(struct timerequest));
|
|
|
|
if (TimeRequest == NULL)
|
|
{
|
|
DeleteMsgPort(TimerPort);
|
|
return 2;
|
|
}
|
|
|
|
error = OpenDevice(
|
|
(STRPTR)TIMERNAME,
|
|
UNIT_MICROHZ,
|
|
(struct IORequest *)TimeRequest,
|
|
0);
|
|
|
|
if (error != 0)
|
|
{
|
|
DeleteIORequest((struct IORequest *)TimeRequest);
|
|
DeleteMsgPort(TimerPort);
|
|
return 3;
|
|
}
|
|
|
|
TimerBase = (struct Device *)TimeRequest->tr_node.io_Device;
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
DeleteTimer()
|
|
{
|
|
TimerBase = NULL;
|
|
|
|
if (TimeRequest != NULL)
|
|
{
|
|
if (!CheckIO((struct IORequest *)TimeRequest))
|
|
{
|
|
WaitIO((struct IORequest *)TimeRequest);
|
|
}
|
|
|
|
CloseDevice((struct IORequest *)TimeRequest);
|
|
DeleteIORequest((struct IORequest *)TimeRequest);
|
|
|
|
TimeRequest = NULL;
|
|
}
|
|
|
|
if (TimerPort != NULL)
|
|
{
|
|
DeleteMsgPort(TimerPort);
|
|
TimerPort = NULL;
|
|
}
|
|
}
|
|
|
|
int gmtoffset(time_t locale_time)
|
|
{
|
|
struct tm tm;
|
|
time_t time = locale_time;
|
|
localtime_r(&time, &tm);
|
|
return tm.tm_gmtoff;
|
|
}
|
|
|
|
int gettimeofday(struct timeval *tv, void *tz)
|
|
{
|
|
long zone;
|
|
|
|
if (tv == NULL)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if (TimerSemaphore != NULL)
|
|
{
|
|
ObtainSemaphore(TimerSemaphore);
|
|
}
|
|
|
|
if (CreateTimer() != 0)
|
|
{
|
|
if (TimerSemaphore != NULL)
|
|
{
|
|
ReleaseSemaphore(TimerSemaphore);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
zone = gmtoffset(tv->tv_secs);
|
|
|
|
TimeRequest->tr_node.io_Command = TR_GETSYSTIME;
|
|
DoIO((struct IORequest *)TimeRequest);
|
|
tv->tv_secs = (long)TimeRequest->tr_time.tv_secs + EPOCH_OFFSET + zone;
|
|
tv->tv_micro = TimeRequest->tr_time.tv_micro;
|
|
|
|
DeleteTimer();
|
|
|
|
if (TimerSemaphore != NULL)
|
|
{
|
|
ReleaseSemaphore(TimerSemaphore);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int settimeofday(const struct timeval *tv, void *tz)
|
|
{
|
|
long zone;
|
|
|
|
if (tv == NULL)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if (TimerSemaphore != NULL)
|
|
{
|
|
ObtainSemaphore(TimerSemaphore);
|
|
}
|
|
|
|
if (CreateTimer() != 0)
|
|
{
|
|
if (TimerSemaphore != NULL)
|
|
{
|
|
ReleaseSemaphore(TimerSemaphore);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
zone = gmtoffset(tv->tv_secs);
|
|
|
|
TimeRequest->tr_node.io_Command = TR_SETSYSTIME;
|
|
TimeRequest->tr_time.tv_secs = (long)tv->tv_secs - EPOCH_OFFSET - zone;
|
|
TimeRequest->tr_time.tv_micro = tv->tv_micro;
|
|
DoIO((struct IORequest *)TimeRequest);
|
|
|
|
DeleteTimer();
|
|
|
|
if (TimerSemaphore != NULL)
|
|
{
|
|
ReleaseSemaphore(TimerSemaphore);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int getsystime(struct timeval *tv)
|
|
{
|
|
if (tv == NULL)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if (TimerSemaphore != NULL)
|
|
{
|
|
ObtainSemaphore(TimerSemaphore);
|
|
}
|
|
|
|
if (CreateTimer() != 0)
|
|
{
|
|
if (TimerSemaphore != NULL)
|
|
{
|
|
ReleaseSemaphore(TimerSemaphore);
|
|
}
|
|
|
|
tv->tv_secs = 0;
|
|
tv->tv_micro = 0;
|
|
return -1;
|
|
}
|
|
|
|
#ifdef AROS
|
|
TimeRequest->tr_node.io_Command = TR_GETSYSTIME;
|
|
DoIO((struct IORequest *)TimeRequest);
|
|
tv->tv_secs = TimeRequest->tr_time.tv_secs;
|
|
tv->tv_micro = 0;
|
|
#else
|
|
{
|
|
struct timeval tv1;
|
|
GetSysTime(&tv1);
|
|
*tv = tv1;
|
|
}
|
|
#endif
|
|
|
|
DeleteTimer();
|
|
|
|
if (TimerSemaphore != NULL)
|
|
{
|
|
ReleaseSemaphore(TimerSemaphore);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int setsystime(struct timeval *tv)
|
|
{
|
|
if (tv == NULL)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if (TimerSemaphore != NULL)
|
|
{
|
|
ObtainSemaphore(TimerSemaphore);
|
|
}
|
|
|
|
if (CreateTimer() != 0)
|
|
{
|
|
if (TimerSemaphore != NULL)
|
|
{
|
|
ReleaseSemaphore(TimerSemaphore);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
TimeRequest->tr_node.io_Command = TR_SETSYSTIME;
|
|
TimeRequest->tr_time.tv_secs = (long)tv->tv_secs;
|
|
TimeRequest->tr_time.tv_micro = tv->tv_micro;
|
|
DoIO((struct IORequest *)TimeRequest);
|
|
|
|
DeleteTimer();
|
|
|
|
if (TimerSemaphore != NULL)
|
|
{
|
|
ReleaseSemaphore(TimerSemaphore);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if defined(__AROS__)
|
|
int *__stdc_geterrnoptr(void)
|
|
{
|
|
return &errno;
|
|
}
|
|
#endif
|
|
|
|
int daylight_c(void)
|
|
{
|
|
return daylight;
|
|
}
|
|
|
|
long Timezone_c(void)
|
|
{
|
|
return Timezone;
|
|
}
|
|
|
|
long altzone_c(void)
|
|
{
|
|
return altzone;
|
|
}
|
|
|
|
char **tzname_c(void)
|
|
{
|
|
return (char **)tzname;
|
|
}
|
|
|
|
/*
|
|
struct lc_time_T *_current_locale()
|
|
{
|
|
return (struct lc_time_T *)&C_time_locale;
|
|
}
|
|
|
|
size_t
|
|
_strftime(const Timezone_t sp, char *const s, const size_t maxsize,
|
|
const char *const format, const struct tm *const t, struct lc_time_T *loc);
|
|
|
|
size_t
|
|
strftime_lz(const Timezone_t sp, char *const s, const size_t maxsize,
|
|
const char *const format, const struct tm *const t, locale_t locale)
|
|
{
|
|
size_t res;
|
|
struct lc_time_T *l = openlc(locale);
|
|
|
|
res = _strftime(sp, s, maxsize, format, t, l);
|
|
|
|
closelc(l);
|
|
return res;
|
|
}
|
|
*/
|
|
|
|
struct lc_time_T *openlc(locale_t locale)
|
|
{
|
|
int i, j;
|
|
struct lc_time_T *l = (struct lc_time_T *)AllocMem(
|
|
sizeof(struct lc_time_T),
|
|
MEMF_ANY | MEMF_CLEAR);
|
|
|
|
struct Locale *loc = locale;
|
|
|
|
if (!loc)
|
|
{
|
|
loc = OpenLocale(NULL);
|
|
}
|
|
|
|
l->X_fmt = (const char *)loc->loc_TimeFormat;
|
|
l->x_fmt = (const char *)loc->loc_ShortDateFormat;
|
|
l->c_fmt = (const char *)loc->loc_DateTimeFormat;
|
|
l->am = (const char *)GetLocaleStr(loc, AM_STR);
|
|
l->pm = (const char *)GetLocaleStr(loc, PM_STR);
|
|
l->date_fmt = "%a %b %e %H:%M:%S %Z %Y";
|
|
|
|
j = 0;
|
|
for (i = 1; i < 8; i++)
|
|
{
|
|
l->weekday[j++] = (const char *)GetLocaleStr(loc, i);
|
|
}
|
|
|
|
j = 0;
|
|
for (i = 8; i < 15; i++)
|
|
{
|
|
l->wday[j++] = (const char *)GetLocaleStr(loc, i);
|
|
}
|
|
|
|
j = 0;
|
|
for (i = 15; i < 27; i++)
|
|
{
|
|
l->month[j++] = (const char *)GetLocaleStr(loc, i);
|
|
}
|
|
|
|
j = 0;
|
|
for (i = 27; i < 39; i++)
|
|
{
|
|
l->mon[j++] = (const char *)GetLocaleStr(loc, i);
|
|
}
|
|
|
|
l->locale = loc;
|
|
|
|
return l;
|
|
}
|
|
|
|
void closelc(struct lc_time_T *lc)
|
|
{
|
|
if (lc->locale)
|
|
{
|
|
CloseLocale(lc->locale);
|
|
}
|
|
|
|
FreeMem(lc, sizeof(struct lc_time_T));
|
|
}
|
|
|
|
/* Similar to intuition.library CurrentTime */
|
|
void CurrentTimeGmt(ULONG *seconds, ULONG *micros)
|
|
{
|
|
ULONG sec, mic;
|
|
CurrentTime(&sec, &mic);
|
|
*seconds = sec + (daylight ? altzone : Timezone);
|
|
*micros = mic;
|
|
}
|
|
|
|
struct tm *AmigaLocalTime(ULONG *seconds, struct tm *tm)
|
|
{
|
|
time_t time;
|
|
if (tm == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (seconds == NULL)
|
|
{
|
|
/* Amiga Epoch time */
|
|
Date2Tm(NULL, tm);
|
|
return tm;
|
|
}
|
|
|
|
time = Amiga2Unix(*seconds);
|
|
localtime_r(&time, tm);
|
|
return tm;
|
|
}
|
|
|
|
struct tm *AmigaLocalTimeZ(ULONG *seconds, struct tm *tm, const Timezone_t tz)
|
|
{
|
|
time_t time;
|
|
if (tm == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if (seconds == NULL)
|
|
{
|
|
/* Amiga Epoch time */
|
|
Date2Tm(NULL, tm);
|
|
return tm;
|
|
}
|
|
|
|
time = Amiga2Unix(*seconds);
|
|
localtime_rz(tz, &time, tm);
|
|
return tm;
|
|
}
|
|
|
|
/* Similar to locale.library FormatDate */
|
|
void FormatDateTm(char *const s, const char *format, struct tm *tm,
|
|
char *buffer, long maxsize)
|
|
{
|
|
strftime(s, maxsize, format, tm);
|
|
}
|
|
|
|
/* Similar to locale.library ParseDate */
|
|
int ParseDateTm(struct Locale *locale, const char *format, struct tm *tm,
|
|
const char *string)
|
|
{
|
|
// TODO
|
|
return 0;
|
|
}
|
|
|
|
/* Similar to utility.library Amiga2Date.
|
|
Fills in a tm structure with the date and time calculated
|
|
from a ULONG containing the number of seconds from 01-Jan-1978
|
|
to the date. */
|
|
void Amiga2Tm(ULONG seconds, struct tm *tm)
|
|
{
|
|
struct tm tmp;
|
|
time_t t;
|
|
if (tm == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
t = seconds + EPOCH_OFFSET;
|
|
localtime_r(&t, &tmp);
|
|
t = seconds + EPOCH_OFFSET - tmp.tm_gmtoff;
|
|
localtime_r(&t, tm);
|
|
}
|
|
|
|
/* Similar to utility.library Date2Amiga.
|
|
Calculates the number of seconds from 01-Jan-1978 to the date
|
|
specified in the tm structure. */
|
|
ULONG Tm2Amiga(struct tm *tm)
|
|
{
|
|
time_t time;
|
|
if (tm == NULL)
|
|
{
|
|
/* Amiga Epoch time */
|
|
return 0;
|
|
}
|
|
|
|
time = timelocal(tm);
|
|
return time - EPOCH_OFFSET;
|
|
}
|
|
|
|
/* Convert between Unix Time Epoch and Amiga Time Epoch */
|
|
ULONG Unix2Amiga(time_t t)
|
|
{
|
|
return t - EPOCH_OFFSET;
|
|
}
|
|
|
|
time_t Amiga2Unix(ULONG t)
|
|
{
|
|
return t + EPOCH_OFFSET;
|
|
}
|
|
|
|
/* Convert to and from DateStamp */
|
|
void Tm2DateStamp(struct tm *tm, struct DateStamp *date)
|
|
{
|
|
time_t time;
|
|
struct tm tmp = *tm;
|
|
|
|
if (date == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (tm == NULL)
|
|
{
|
|
/* UNIX Epoch time */
|
|
time = 0;
|
|
}
|
|
else
|
|
{
|
|
time = mktime(&tmp);
|
|
}
|
|
|
|
Unix2DateStamp(&time, date);
|
|
}
|
|
|
|
void DateStamp2Tm(struct DateStamp *date, struct tm *tm)
|
|
{
|
|
time_t time;
|
|
if (tm == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (date == NULL)
|
|
{
|
|
Date2Tm(NULL, tm);
|
|
return;
|
|
}
|
|
|
|
DateStamp2Unix(date, &time);
|
|
gmtime_r(&time, tm);
|
|
}
|
|
|
|
void Unix2DateStamp(time_t *time, struct DateStamp *date)
|
|
{
|
|
long t, d, m, q;
|
|
if (date == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (time == NULL)
|
|
{
|
|
/* Amiga Epoch time */
|
|
date->ds_Days = 0;
|
|
date->ds_Minute = 0;
|
|
date->ds_Tick = 0;
|
|
return;
|
|
}
|
|
|
|
t = *time - EPOCH_OFFSET;
|
|
d = t / SECONDSPERDAY;
|
|
m = (t - SECONDSPERDAY * d) / 60;
|
|
q = (t - SECONDSPERDAY * d - m * 60) * 60; // TODO: Ticks = 50
|
|
|
|
date->ds_Days = d;
|
|
date->ds_Minute = m;
|
|
date->ds_Tick = q;
|
|
}
|
|
|
|
void DateStamp2Unix(struct DateStamp *date, time_t *time)
|
|
{
|
|
if (time == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (date == NULL)
|
|
{
|
|
/* Amiga Epoch time */
|
|
*time = EPOCH_OFFSET;
|
|
return;
|
|
}
|
|
|
|
*time = date->ds_Days * SECONDSPERDAY +
|
|
date->ds_Minute * 60 +
|
|
date->ds_Tick / 60 +
|
|
EPOCH_OFFSET;
|
|
}
|
|
|
|
/* Convert from tm to ClockData */
|
|
void Tm2Date(struct tm *tm, struct ClockData *date)
|
|
{
|
|
if (date == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (tm == NULL)
|
|
{
|
|
/* UNIX Epoch time */
|
|
date->sec = 0;
|
|
date->min = 0;
|
|
date->hour = 0;
|
|
date->mday = 1;
|
|
date->month = 1;
|
|
date->year = EPOCH_YEAR;
|
|
date->wday = EPOCH_WDAY;
|
|
return;
|
|
}
|
|
|
|
date->sec = (UWORD)tm->tm_sec;
|
|
date->min = (UWORD)tm->tm_min;
|
|
date->hour = (UWORD)tm->tm_hour;
|
|
date->mday = (UWORD)tm->tm_mday;
|
|
date->month = (UWORD)tm->tm_mon + 1;
|
|
date->year = (UWORD)tm->tm_year + TM_YEAR_BASE + EPOCH_OFFSET_YEAR;
|
|
date->wday = (UWORD)tm->tm_wday;
|
|
|
|
/* tm allow seconds in interval [0-61] */
|
|
if (date->sec > 59)
|
|
{
|
|
date->sec = 59;
|
|
}
|
|
}
|
|
|
|
/* Convert from ClockData to tm */
|
|
void Date2Tm(struct ClockData *date, struct tm *tm)
|
|
{
|
|
if (tm == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (date == NULL)
|
|
{
|
|
/* Amiga Epoch time */
|
|
tm->tm_sec = 0;
|
|
tm->tm_min = 0;
|
|
tm->tm_hour = 0;
|
|
tm->tm_mday = 1;
|
|
tm->tm_mon = 0;
|
|
tm->tm_year = EPOCH_YEAR + EPOCH_OFFSET_YEAR - TM_YEAR_BASE;
|
|
mktime(tm);
|
|
return;
|
|
}
|
|
|
|
tm->tm_sec = (int)date->sec;
|
|
tm->tm_min = (int)date->min;
|
|
tm->tm_hour = (int)date->hour;
|
|
tm->tm_mday = (int)date->mday;
|
|
tm->tm_mon = (int)date->month - 1;
|
|
tm->tm_year = (int)date->year - TM_YEAR_BASE - EPOCH_OFFSET_YEAR;
|
|
tm->tm_wday = (int)date->wday;
|
|
mktime(tm);
|
|
}
|
|
|
|
void Date2Unix(struct ClockData *date, time_t *time)
|
|
{
|
|
struct tm tm;
|
|
if (time == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (date == NULL)
|
|
{
|
|
/* UNIX Epoch time */
|
|
*time = 0;
|
|
return;
|
|
}
|
|
|
|
Date2Tm(date, &tm);
|
|
mktime(&tm);
|
|
}
|
|
|
|
void Unix2Date(time_t *time, struct ClockData *date)
|
|
{
|
|
struct tm tm;
|
|
time_t t;
|
|
if (date == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (time == NULL)
|
|
{
|
|
/* UNIX Epoch time */
|
|
Tm2Date(NULL, date);
|
|
return;
|
|
}
|
|
|
|
t = *time;
|
|
gmtime_r(&t, &tm);
|
|
Tm2Date(&tm, date);
|
|
}
|
|
|
|
#undef time
|
|
#undef time_t
|
|
|
|
time_t
|
|
time(time_t *x)
|
|
{
|
|
time_t tloc;
|
|
ULONG sec, mic;
|
|
CurrentTime(&sec, &mic);
|
|
tloc = (time_t)(sec);
|
|
|
|
if (x)
|
|
{
|
|
*x = tloc;
|
|
}
|
|
|
|
return tloc;
|
|
}
|