📄 rvtm.c
字号:
/***********************************************************************
Filename : rvtm.c
Description: tm functions - Calendar time
************************************************************************
Copyright (c) 2001 RADVISION Inc. and RADVISION Ltd.
************************************************************************
NOTICE:
This document contains information that is confidential and proprietary
to RADVISION Inc. and RADVISION Ltd.. No part of this document may be
reproduced in any form whatsoever without written prior approval by
RADVISION Inc. or RADVISION Ltd..
RADVISION Inc. and RADVISION Ltd. reserve the right to revise this
publication and make changes without obligation to notify any person of
such revisions or changes.
***********************************************************************/
#include "rvtm.h"
#include "rvansi.h"
/* Required OS Specific headers files */
#if (RV_TM_TYPE == RV_TM_VXWORKS)
#include <vxWorks.h>
#include <sysLib.h>
#include <tickLib.h>
#include <limits.h>
#include <wdLib.h>
#elif (RV_TM_TYPE == RV_TM_PSOS)
#include <psos.h>
#include <limits.h>
#elif (RV_TM_TYPE == RV_TM_OSE)
#include <ose.h>
#include <limits.h>
#elif (RV_TM_TYPE == RV_TM_NUCLEUS)
#include <nucleus.h>
#include <target.h>
#include <limits.h>
static char *RvAsctime_r(const struct tm *timeptr, char *result);
static struct tm *RvGmtime_r(time_t t, struct tm *tm);
static struct tm *RvLocaltime_r(time_t t, struct tm *tm);
#elif (RV_TM_TYPE == RV_TM_WINCE)
struct tm * __cdecl localtime(const time_t *);
static char *RvAsctime_r(const struct tm *timeptr, char *result);
static struct tm *RvGmtime_r(time_t t, struct tm *tm);
static struct tm *RvLocaltime_r(time_t t, struct tm *tm);
size_t strftime(char *s, size_t maxs, const char *f, const struct tm *t);
static void strfmt(char *str, const char *fmt, ...);
#endif
/* Special headers required for test code */
#if defined(RV_TEST_CODE)
#include "rvstdio.h"
#if (RV_TM_TYPE == RV_TM_VXWORKS)
#include <ioLib.h>
#endif
#endif
/* Lets make error codes a little easier to type */
#define RvTmErrorCode(_e) RvErrorCode(RV_ERROR_LIBCODE_CCORE, RV_CCORE_MODULE_TM, (_e));
RvStatus RvTmInit(void)
{
return RV_OK;
}
RvStatus RvTmEnd(void)
{
return RV_OK;
}
/* Convert calander time back to seconds since 1970. */
/* The tm structure is also adjusted as per mktime. */
/* Remember that the day of the week ranges 0 to 6 with */
/* 0 being Sunday and the day of the year ranges from 0 */
/* to 365 with 0 being January 1st. */
RvStatus RvTmConvertToTime(RvTm *tm, RvTime *t)
{
time_t secs;
RvStatus result;
#if (RV_TM_TYPE == RV_TM_OSE)
int tmpdst;
#endif
#if defined(RV_NULLCHECK)
if((t == NULL) || (tm == NULL))
return RvTmErrorCode(RV_ERROR_NULLPTR);
#endif
result = RV_OK;
/* We have to adjust nanoseconds ourselves. */
while(tm->nsec < 0) {
tm->tm.tm_sec--;
tm->nsec += RV_TIME_NSECPERSEC;
}
while(tm->nsec >= RV_TIME_NSECPERSEC) {
tm->tm.tm_sec++;
tm->nsec -= RV_TIME_NSECPERSEC;
}
#if (RV_TM_TYPE == RV_TM_OSE)
/* OSE's version of mktime errors if isdst != 0 so */
/* We'll make it happy. */
tmpdst = tm->tm.tm_isdst;
tm->tm.tm_isdst = 0;
#endif
#if (RV_OS_TYPE == RV_OS_TYPE_WINCE)
/* mktime not supported under winCE */
return RvTmErrorCode(RV_ERROR_NOTSUPPORTED);
#else
/* Now send tm structure to mktime. */
secs = mktime(&tm->tm);
#endif
if(secs != (time_t)(-1)) {
RvTimeSetSecs(t, (RvInt32)secs);
RvTimeSetNsecs(t, tm->nsec);
} else result = RvTmErrorCode(RV_ERROR_UNKNOWN);
#if (RV_TM_TYPE == RV_TM_OSE)
tm->tm.tm_isdst = tmpdst; /* Undo the OSE hack. */
#endif
return result;
}
/* Convert wall time to a UTC calendar time */
/* Everyone does gmtime_r slightly differently, so we have to deal with it. */
RVCOREAPI RvStatus RVCALLCONV RvTmConstructUtc(RvTm *tm, const RvTime *t)
{
RvStatus result;
time_t secs;
#if (RV_TM_TYPE == RV_TM_WIN32)
struct tm *tmresult;
#endif
#if defined(RV_NULLCHECK)
if((t == NULL) || (tm == NULL))
return RvTmErrorCode(RV_ERROR_NULLPTR);
#endif
result = RV_OK;
secs = (time_t)RvTimeGetSecs(t);
#if (RV_TM_TYPE == RV_TM_POSIX) ||(RV_TM_TYPE == RV_TM_OSE)
if(gmtime_r(&secs, &tm->tm) == NULL)
result = RvTmErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_TM_TYPE == RV_TM_WIN32)
tmresult = gmtime(&secs);
if(tmresult != NULL) {
memcpy(&tm->tm, tmresult, sizeof(tm->tm));
} else result = RvTmErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_TM_TYPE == RV_TM_VXWORKS)
if(gmtime_r(&secs, &tm->tm) != OK)
result = RvTmErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_TM_TYPE == RV_TM_PSOS)
/* In pSOS, gmtime is declared right but always returns NULL. */
gmtime_r(&secs, &tm->tm);
#endif
#if (RV_TM_TYPE == RV_TM_NUCLEUS) || (RV_TM_TYPE == RV_TM_WINCE)
/* Use our own gmtime since there's no standard one for Nucleus */
if(RvGmtime_r(secs, &tm->tm) == NULL)
result = RvTmErrorCode(RV_ERROR_UNKNOWN);
#endif
if(result == RV_OK) {
tm->tm.tm_isdst = 0; /* Some OS's forget to clear this */
tm->nsec = RvTimeGetNsecs(t);
}
return result;
}
/* Convert wall time to a local calendar time */
/* Everyone does localtime_r slightly differently, so we have to deal with it. */
RvStatus RvTmConstructLocal(RvTm *tm, const RvTime *t)
{
RvStatus result;
time_t secs;
#if (RV_TM_TYPE == RV_TM_WIN32)
struct tm *tmresult;
#endif
#if defined(RV_NULLCHECK)
if((t == NULL) || (tm == NULL))
return RvTmErrorCode(RV_ERROR_NULLPTR);
#endif
result = RV_OK;
secs = (time_t)RvTimeGetSecs(t);
#if (RV_TM_TYPE == RV_TM_POSIX) || (RV_TM_TYPE == RV_TM_OSE) || \
(RV_TM_TYPE == RV_TM_PSOS)
if(localtime_r(&secs, &tm->tm) == NULL)
result = RvTmErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_TM_TYPE == RV_TM_WIN32)
tmresult = localtime(&secs);
if(tmresult != NULL) {
memcpy(&tm->tm, tmresult, sizeof(tm->tm));
} else result = RvTmErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_TM_TYPE == RV_TM_VXWORKS)
if(localtime_r(&secs, &tm->tm) != OK)
result = RvTmErrorCode(RV_ERROR_UNKNOWN);
#endif
#if (RV_TM_TYPE == RV_TM_NUCLEUS) || (RV_TM_TYPE == RV_TM_WINCE)
/* Use our own localtime since there's no standard one for Nucleus */
if(RvLocaltime_r(secs, &tm->tm) == NULL)
result = RvTmErrorCode(RV_ERROR_UNKNOWN);
#endif
if(result == RV_OK)
tm->nsec = RvTimeGetNsecs(t);
return result;
}
/* Convert a calander time to a standard time string. The buffer */
/* pointed to by buf MUST be large enough to handle the string */
/* generated. This should be a minimum of the value defined by */
/* the constant RV_TM_ASCTIME_BUFSIZE. */
RvChar *RvTmAsctime(const RvTm *tm, RvChar *buf, RvSize_t bufsize)
{
RvChar *result;
#if defined(RV_NULLCHECK)
if((tm == NULL) || (buf == NULL))
return NULL;
#endif
#if defined(RV_RANGECHECK)
if(bufsize < RV_TM_ASCTIME_BUFSIZE)
return NULL;
#endif
#if (RV_TM_TYPE == RV_TM_OSE)
result = (RvChar *)asctime_r(&tm->tm, buf, bufsize);
#endif
#if (RV_TM_TYPE == RV_TM_POSIX)
result = (RvChar *)asctime_r(&tm->tm, buf);
#endif
#if (RV_TM_TYPE == RV_TM_PSOS)
#if (RV_OS_VERSION == RV_OS_PSOS_2_0)
result = (RvChar *)asctime_r(&tm->tm, buf, (int)bufsize);
#else
result = (RvChar *)asctime_r(&tm->tm, buf);
#endif /* RV_OS_VERSION == RV_OS_PSOS_2_0 */
#endif
#if (RV_TM_TYPE == RV_TM_WIN32)
result = asctime(&tm->tm);
if(result != NULL)
result = strncpy(buf, result, bufsize);
#endif
#if (RV_TM_TYPE == RV_TM_VXWORKS)
if(asctime_r(&tm->tm, buf, &bufsize) > 0) {
result = buf;
} else result = NULL;
#endif
#if (RV_TM_TYPE == RV_TM_NUCLEUS) || (RV_TM_TYPE == RV_TM_WINCE)
result = RvAsctime_r(&tm->tm, buf); /* use our own since we can't count on libs */
#endif
return result;
}
/* Allow custom formatting of a time string. Only use */
/* standard ANSI formats to insure OS comapatability. */
/* Returns the number of characters in the result string */
/* if successfull, otherwise returns a 0. */
RvSize_t RvTmStrftime(const RvTm *tm, const RvChar *format, RvChar *result, RvSize_t maxsize)
{
#if defined(RV_NULLCHECK)
if((tm == NULL) || (format == NULL) || (result == NULL)) return RvInt32Const(0);
#endif
return strftime(result, maxsize, format, &tm->tm);
}
/* Only use for Nucleus, other OS's have their own libs */
#if (RV_TM_TYPE == RV_TM_NUCLEUS) || (RV_OS_TYPE == RV_OS_TYPE_WINCE)
/**************************************************************************************/
/* This following part of this file contains primitive versions of gmtime_r */
/* and localtime_r (asctime_r is generic). These are for embedded OS's */
/* (ie Nucleus) that don't have these standard reentrant functions. Things */
/* like leap-seconds are not accounted for and no timezone work is done */
/* (localtime = gmtime). Eventually a full set of time functions should be */
/* included to handle it all properly for each OS. */
/* Parts based on the following public domain software: */
/* $FreeBSD: src/lib/libc/stdtime/asctime.c,v 1.8 2001/01/24 13:01:02 deischen Exp $ */
/* $FreeBSD: src/lib/libc/stdtime/localtime.c,v 1.27 2001/02/15 22:17:04 tegge Exp $ */
/* June 5, 1996 by Arthur David Olson (arthur_david_olson@nih.gov). */
#define SECSPERMIN 60
#define MINSPERHOUR 60
#define HOURSPERDAY 24
#define DAYSPERWEEK 7
#define DAYSPERNYEAR 365
#define DAYSPERLYEAR 366
#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)
#define MONSPERYEAR 12
#define TM_SUNDAY 0
#define TM_MONDAY 1
#define TM_TUESDAY 2
#define TM_WEDNESDAY 3
#define TM_THURSDAY 4
#define TM_FRIDAY 5
#define TM_SATURDAY 6
#define TM_JANUARY 0
#define TM_FEBRUARY 1
#define TM_MARCH 2
#define TM_APRIL 3
#define TM_MAY 4
#define TM_JUNE 5
#define TM_JULY 6
#define TM_AUGUST 7
#define TM_SEPTEMBER 8
#define TM_OCTOBER 9
#define TM_NOVEMBER 10
#define TM_DECEMBER 11
#define TM_YEAR_BASE 1900
#define EPOCH_YEAR 1970
#define EPOCH_WDAY TM_THURSDAY
/*
** Accurate only for the past couple of centuries;
** that will probably do.
*/
#define isleap(_y) (((_y) % 4) == 0 && (((_y) % 100) != 0 || ((_y) % 400) == 0))
static const int mon_lengths[2][MONSPERYEAR] = {
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
};
static const int year_lengths[2] = {
DAYSPERNYEAR, DAYSPERLYEAR
};
/*
** A la X3J11, with core dump avoidance.
*/
/* result must be at least 26 characters long */
static char *RvAsctime_r(const struct tm *timeptr, char *result)
{
static const char wday_name[][4] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
static const char mon_name[][4] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
const char *wn;
const char *mn;
int mday, hour, min, sec, year;
if((timeptr->tm_wday < 0) || (timeptr->tm_wday >= DAYSPERWEEK)) {
wn = "???";
} else wn = wday_name[timeptr->tm_wday];
if((timeptr->tm_mon < 0) || (timeptr->tm_mon >= MONSPERYEAR)) {
mn = "???";
} else mn = mon_name[timeptr->tm_mon];
year = TM_YEAR_BASE + timeptr->tm_year;
mday = timeptr->tm_mday;
hour = timeptr->tm_hour;
min = timeptr->tm_min;
sec = timeptr->tm_sec;
/* Add checks to prevent overruns */
if((timeptr->tm_mday < 0) || (timeptr->tm_mday > 99))
mday = 0;
if((timeptr->tm_hour < 0) || (timeptr->tm_hour > 99))
hour = 0;
if((timeptr->tm_min < 0) || (timeptr->tm_min > 99))
min = 0;
if((timeptr->tm_sec < 0) || (timeptr->tm_sec > 99))
sec = 0;
if((year < 0) || (year > 9999))
year = 0;
/*
** The X3J11-suggested format is
** "%.3s %.3s%3d %02.2d:%02.2d:%02.2d %d\n"
** Since the .2 in 02.2d is ignored, we drop it.
*/
RvSprintf(result, "%.3s %.3s%3d %02d:%02d:%02d %d\n", wn, mn,
mday, hour, min, sec, year);
return result;
}
/* Does not account for leap seconds or anything fancy. IEEE spec */
/* even forgot about leap seconds. So we do things the simple way */
/* for now */
static struct tm *RvGmtime_r(time_t t, struct tm *tm)
{
RvUint year, month, days, leapyear;
time_t temp;
temp = t;
tm->tm_sec = temp % SECSPERMIN;
temp = temp/SECSPERMIN;
tm->tm_min = temp % MINSPERHOUR;
temp = temp/MINSPERHOUR;
tm->tm_hour = temp % HOURSPERDAY;
temp = temp / HOURSPERDAY;
tm->tm_wday = (temp + EPOCH_WDAY) % DAYSPERWEEK;
year = EPOCH_YEAR;
for(;;) {
leapyear = isleap(year);
days = year_lengths[leapyear];
if(temp < days) break;
temp -= days;
year++;
}
tm->tm_year = year - TM_YEAR_BASE;
tm->tm_yday = temp;
month = TM_JANUARY;
for(;;) {
days = mon_lengths[leapyear][month];
if(temp < days) break;
temp -= days;
month++;
}
tm->tm_mon = month;
tm->tm_mday = temp + 1;
tm->tm_isdst = 0;
return tm;
}
static struct tm *RvLocaltime_r(time_t t, struct tm *tm)
{
/* To do local time, we should find out time zone offset */
/* and subtract it from the gmtime result along with */
/* any offset for daylight savings time if it is in effect */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -