/* ** OSSP tai - Time Handling ** Copyright (c) 2002-2003 Ralf S. Engelschall ** Copyright (c) 2002-2003 The OSSP Project ** Copyright (c) 2002-2003 Cable & Wireless Deutschland ** ** 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 #include #include #include #include #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; }