ossp-pkg/tai/tai_lib.c
/*
** OSSP tai - Time Handling
** Copyright (c) 2002-2003 Ralf S. Engelschall <rse@engelschall.com>
** Copyright (c) 2002-2003 The OSSP Project <http://www.ossp.org/>
** Copyright (c) 2002-2003 Cable & Wireless Deutschland <http://www.cw.com/de/>
**
** This file is part of OSSP tai, a time handling library
** which can be found at http://www.ossp.org/pkg/lib/tai/.
**
** Permission to use, copy, modify, and distribute this software for
** any purpose with or without fee is hereby granted, provided that
** the above copyright notice and this permission notice appear in all
** copies.
**
** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
** SUCH DAMAGE.
**
** tai_lib.c: API implementation
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <time.h>
#include "tai.h"
#include "tai_p.h"
tai_rc_t tai_create(tai_t **ptai)
{
tai_t *tai;
tai_rc_t rv;
if ((tai = (tai_t *)malloc(sizeof(tai_t))) == NULL)
return TAI_ERR_SYS;
if ((rv = tai_import(tai, TAI_TYPE_TIMET, 0)) != TAI_OK) {
free(tai);
return rv;
}
*ptai = tai;
return TAI_OK;
}
tai_rc_t tai_destroy(tai_t *tai)
{
if (tai == NULL)
return TAI_ERR_ARG;
free(tai);
return TAI_OK;
}
#if 0
static time_t tai_utcoffset(void)
{
time_t tL, tU;
struct tm *tmL, *tmU;
time_t offset;
/* determine local time (UTC based) */
tL = time(NULL); /* theoretically this could be a constant value, too */
/* unpack local time (local time based) */
tmL = localtime(&tL);
/* unpack local time (UTC based) */
tmU = gmtime(&tL);
/* pack UTC-based local time back into local time */
tU = mktime(tmU);
/* local time adjustment for Daylight Saving Time (DST) */
if (tmL->tm_isdst)
tL += (60*60);
/* finally calculate the UTC offset */
offset = (tL - tU);
return offset;
}
#endif
tai_rc_t tai_import(tai_t *tai, tai_type_t type, ...)
{
va_list ap;
if (tai == NULL)
return TAI_ERR_ARG;
va_start(ap, type);
if (type == TAI_TYPE_TIMET) {
/* import from time_t */
#ifdef HAVE_GMTIME_R
struct tm stmbuf;
#endif
struct tm *stm;
time_t t;
t = (time_t)va_arg(ap, long);
#ifdef HAVE_GMTIME_R
stm = gmtime_r(&t, &stmbuf);
#else
stm = gmtime(&t);
#endif
tai->tai_sec = stm->tm_sec;
tai->tai_min = stm->tm_min;
tai->tai_hour = stm->tm_hour;
tai->tai_mday = stm->tm_mday;
tai->tai_mon = stm->tm_mon;
tai->tai_year = stm->tm_year;
tai->tai_wday = stm->tm_wday;
tai->tai_yday = stm->tm_yday;
tai->tai_isdst = stm->tm_isdst;
#ifdef HAVE_TM_GMTOFF
tai->tai_gmtoff = stm->tm_gmtoff; /* implicitly 0 */
#else
tai->tai_gmtoff = 0; /* explicitly 0 */
#endif
}
else if (type == TAI_TYPE_STRUCTTM) {
/* import from struct tm */
struct tm *stm;
stm = (struct tm *)va_arg(ap, void *);
#define TM_ISRANGE(var,field,min,max) \
(var->tm_##field >= (min) && var->tm_##field <= (max))
if (!TM_ISRANGE(stm,sec,0,61) ||
!TM_ISRANGE(stm,min,0,59) ||
!TM_ISRANGE(stm,hour,0,23) ||
!TM_ISRANGE(stm,mday,1,31) ||
!TM_ISRANGE(stm,mon,0,11) ||
!TM_ISRANGE(stm,wday,0,6) ||
!TM_ISRANGE(stm,yday,0,365) ||
!TM_ISRANGE(stm,isdst,0,1))
return TAI_ERR_ARG;
tai->tai_sec = stm->tm_sec;
tai->tai_min = stm->tm_min;
tai->tai_hour = stm->tm_hour;
tai->tai_mday = stm->tm_mday;
tai->tai_mon = stm->tm_mon;
tai->tai_year = stm->tm_year;
tai->tai_wday = stm->tm_wday;
tai->tai_yday = stm->tm_yday;
tai->tai_isdst = stm->tm_isdst;
#ifdef HAVE_TM_GMTOFF
tai->tai_gmtoff = stm->tm_gmtoff;
#else
tai->tai_gmtoff = 0;
#endif
}
else if (type == TAI_TYPE_UNIX) {
/* import from time(3) FIXME */
time_t t = time(NULL);
tai->sec = ui64_n2i((unsigned long)t);
tai->asec = ui64_n2i((unsigned long)0);
tai_tai2cal(tai, 7200);
}
else
return TAI_ERR_IMP; /* FIXME */
va_end(ap);
return TAI_OK;
}
tai_rc_t tai_export(tai_t *tai, tai_type_t type, ...)
{
va_list ap;
if (tai == NULL)
return TAI_ERR_ARG;
va_start(ap, type);
if (type == TAI_TYPE_TIMET) {
time_t *pt;
struct tm stmbuf;
struct tm *stm;
#ifndef HAVE_TIMEGM
time_t t;
#endif
pt = (time_t *)va_arg(ap, void *);
stm = &stmbuf;
stm->tm_sec = tai->tai_sec;
stm->tm_min = tai->tai_min;
stm->tm_hour = tai->tai_hour;
stm->tm_mday = tai->tai_mday;
stm->tm_mon = tai->tai_mon;
stm->tm_year = tai->tai_year;
stm->tm_wday = tai->tai_wday;
stm->tm_yday = tai->tai_yday;
stm->tm_isdst = tai->tai_isdst;
#ifdef HAVE_TM_GMTOFF
stm->tm_gmtoff = tai->tai_gmtoff;
#endif
#ifdef HAVE_TIMEGM
/* non-standard timegm(3) makes our life easy */
*pt = timegm(stm);
#else
/* standard mktime(3) calculated relative to local timezone,
so we have to post-adjust result */
*pt = mktime(stm);
t = 12*60*60*2; /* max offset of 12 hours plus safety */
*pt += (mktime(localtime(&t)) - mktime(gmtime(&t)));
#endif
}
else if (type == TAI_TYPE_STRUCTTM) {
struct tm *stm;
stm = (struct tm *)va_arg(ap, void *);
stm->tm_sec = tai->tai_sec;
stm->tm_min = tai->tai_min;
stm->tm_hour = tai->tai_hour;
stm->tm_mday = tai->tai_mday;
stm->tm_mon = tai->tai_mon;
stm->tm_year = tai->tai_year;
stm->tm_wday = tai->tai_wday;
stm->tm_yday = tai->tai_yday;
stm->tm_isdst = tai->tai_isdst;
#ifdef HAVE_TM_GMTOFF
stm->tm_gmtoff = tai->tai_gmtoff;
#endif
}
else
return TAI_ERR_IMP; /* FIXME */
va_end(ap);
return TAI_OK;
}
tai_rc_t tai_format(tai_t *tai, char *buf_ptr, size_t buf_len, const char *fmt)
{
struct tm stm;
tai_rc_t rv;
if (tai == NULL || buf_ptr == NULL || buf_len == 0 || fmt == NULL)
return TAI_ERR_ARG;
if ((rv = tai_export(tai, TAI_TYPE_STRUCTTM, &stm)) != TAI_OK)
return rv;
if (tai_format_int(buf_ptr, buf_len, fmt, &stm) == 0)
return TAI_ERR_FMT;
return TAI_OK;
}
tai_rc_t tai_parse(tai_t *tai, const char *buf_ptr, size_t buf_len, const char *fmt)
{
struct tm stm;
char *cp;
char *cp2;
tai_rc_t rv;
if (tai == NULL || buf_ptr == NULL || buf_len == 0 || fmt == NULL)
return TAI_ERR_ARG;
if ((cp = malloc(buf_len+1)) == NULL)
return TAI_ERR_SYS;
memmove(cp, buf_ptr, buf_len);
cp[buf_len] = '\0';
memset(&stm, 0, sizeof(struct tm));
cp2 = tai_parse_int(cp, fmt, &stm);
free(cp);
if (cp2 == NULL)
return TAI_ERR_PRS;
if ((rv = tai_import(tai, TAI_TYPE_STRUCTTM, &stm)) != TAI_OK)
return rv;
return TAI_OK;
}
tai_rc_t tai_op(tai_t *tai, tai_op_t op, ...)
{
tai_rc_t rc = TAI_ERR_IMP;
va_list ap;
if (tai == NULL)
return TAI_ERR_ARG;
va_start(ap, op);
if ((op == TAI_OP_NE) || (op == TAI_OP_EQ) || (op == TAI_OP_LT) || (op == TAI_OP_LE) || (op == TAI_OP_GT) || (op == TAI_OP_GE)) {
tai_t *tai1, *tai2;
unsigned long s1, s2;
tai1 = tai;
tai2 = (tai_t *)va_arg(ap, void *);
s1 = tai1->tai_sec + (60 * tai1->tai_min) + (60 * 60 * tai1->tai_hour) + (60 * 60 * 24 * tai1->tai_yday) + (60 * 60 * 24 * 365 * tai1->tai_year) + tai1->tai_gmtoff;
s2 = tai2->tai_sec + (60 * tai2->tai_min) + (60 * 60 * tai2->tai_hour) + (60 * 60 * 24 * tai2->tai_yday) + (60 * 60 * 24 * 365 * tai2->tai_year) + tai2->tai_gmtoff;
switch (op) {
case TAI_OP_NE: rc = (s2 != s1 ? TAI_OK : TAI_FALSE); break;
case TAI_OP_EQ: rc = (s2 == s1 ? TAI_OK : TAI_FALSE); break;
case TAI_OP_LT: rc = (s2 < s1 ? TAI_OK : TAI_FALSE); break;
case TAI_OP_LE: rc = (s2 <= s1 ? TAI_OK : TAI_FALSE); break;
case TAI_OP_GT: rc = (s2 > s1 ? TAI_OK : TAI_FALSE); break;
case TAI_OP_GE: rc = (s2 >= s1 ? TAI_OK : TAI_FALSE); break;
default: break; /* FIXME */
}
}
va_end(ap);
return rc;
}