blob: a1a131c64f4c2eef8dac74016d95d632c8e05c77 [file] [log] [blame]
/*!
\file datetime.c
\brief Native CMPIDateTime implementation.
This is the native CMPIDateTime implementation as used for remote
providers. It reflects the well-defined interface of a regular
CMPIDateTime, however, it works independently from the management broker.
It is part of a native broker implementation that simulates CMPI data
types rather than interacting with the entities in a full-grown CIMOM.
(C) Copyright IBM Corp. 2003
THIS FILE IS PROVIDED UNDER THE TERMS OF THE ECLIPSE PUBLIC LICENSE
("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE
CONSTITUTES RECIPIENTS ACCEPTANCE OF THE AGREEMENT.
You can obtain a current copy of the Eclipse Public License from
http://www.opensource.org/licenses/eclipse-1.0.php
\author Frank Scheffler
$Revision: 1.2 $
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include "cmcidt.h"
#include "cmcift.h"
#include "cmcimacs.h"
#include "native.h"
#ifdef DMALLOC
#include "dmalloc.h"
#endif
//! Native extension of the CMPIDateTime data type.
/*!
This structure stores the information needed to represent time for
CMPI providers.
*/
struct native_datetime {
CMPIDateTime dt; /*!< the inheriting data structure */
char cimDt[26];
};
static struct native_datetime * __new_datetime ( const char *cimDt,
CMPIStatus * );
/****************************************************************************/
//! Releases a previously cloned CMPIDateTime object from memory.
/*!
To achieve this, the object is simply added to the thread-based memory
management to be freed later.
\param dt the object to be released
\return CMPI_RC_OK.
*/
static CMPIStatus __dtft_release ( CMPIDateTime * dt )
{
struct native_datetime * ndt = (struct native_datetime *) dt;
if ( ndt ) {
free ( ndt );
CMReturn ( CMPI_RC_OK );
}
CMReturn ( CMPI_RC_ERR_FAILED );
}
//! Clones an existing CMPIDateTime object.
/*!
The function simply calls __new_datetime() with the data fields
extracted from dt.
\param dt the object to be cloned
\param rc return code pointer
\return a copy of the given CMPIDateTime object that won't be freed
from memory before calling __dtft_release().
*/
static CMPIDateTime * __dtft_clone ( CMPIDateTime * dt, CMPIStatus * rc )
{
struct native_datetime * ndt = (struct native_datetime *) dt;
struct native_datetime * new = __new_datetime ( ndt->cimDt, rc );
return (CMPIDateTime *) new;
}
static CMPIUint64 chars2bin(const char *string, CMPIStatus * rc)
{
CMPIUint64 msecs,secs;
CMPIBoolean interval;
char *str;
str = strdup(string);
interval = (str[21] == ':');
// 0000000000111111111122222
// 0123456789012345678901234
// yyyymmddhhmmss mmmmmmsutc
// 20050503104354.000000:000
str[21] = 0;
msecs = strtoull(str+15,NULL,10);
str[14] = 0;
secs = strtoull(str+12,NULL,10);
str[12] = 0;
secs += strtoull(str+10,NULL,10) * 60ULL;
str[10] = 0;
secs += strtoull(str+8,NULL,10) * 60ULL * 60ULL;
str[8] = 0;
if (interval) {
secs += strtoull(str,NULL,10) * 60ULL * 60ULL * 24ULL;
msecs=msecs+(secs*1000000ULL);
}
else {
struct tm tmp;
memset(&tmp, 0, sizeof(struct tm));
tzset();
tmp.tm_gmtoff = timezone;
tmp.tm_isdst = daylight;
tmp.tm_mday = atoi(str + 6);
str[6] = 0;
tmp.tm_mon = atoi(str + 4) - 1;
str[4] = 0;
tmp.tm_year = atoi(str) - 1900;
msecs=msecs+(secs*1000000ULL);
msecs += (CMPIUint64) mktime(&tmp) * 1000000ULL;
}
free(str);
return msecs;
}
static void bin2chars(CMPIUint64 msecs, CMPIBoolean interval, CMPIStatus * rc, char *str_time)
{
time_t secs = msecs / 1000000ULL;
unsigned long usecs = msecs % 1000000ULL;
if (interval) {
unsigned long long useconds, seconds, mins, hrs, days;
seconds= msecs / 1000000ULL;
useconds = msecs % 1000000ULL;
mins = seconds / 60ULL;
seconds %= 60ULL;
hrs = mins / 60ULL;
mins %= 60ULL;
days = hrs / 24ULL;
hrs %= 24ULL;
sprintf(str_time, "%8.8llu%2.2llu%2.2llu%2.2llu.%6.6llu:000",
days, hrs, mins, seconds, useconds);
}
else {
struct tm tm_time;
char us_utc_time[11];
if ( localtime_r ( &secs, &tm_time ) == NULL ) {
CMSetStatus(rc, CMPI_RC_ERR_FAILED);
return;
}
tzset ();
snprintf ( us_utc_time, 11, "%6.6ld%+4.3ld",
usecs, ( daylight != 0 ) * 60 - timezone / 60 );
strftime ( str_time, 26, "%Y%m%d%H%M%S.", &tm_time );
strcat ( str_time, us_utc_time );
}
}
//! Extracts the binary time from the encapsulated CMPIDateTime object.
/*!
\param dt the native CMPIDateTime to be extracted.
\param rc return code pointer
\return an amount of microseconds.
*/
static CMPIUint64 __dtft_getBinaryFormat ( CMPIDateTime * dt,
CMPIStatus * rc )
{
struct native_datetime * ndt = (struct native_datetime *) dt;
CMSetStatus ( rc, CMPI_RC_OK );
return chars2bin(ndt->cimDt,rc);
}
//! Gives back a string representation of the time object.
/*!
\param dt the native CMPIDateTime to be converted.
\param rc return code pointer
\return a string that has one of the following formats:
- yyyymmddhhmmss.mmmmmmsutc (for absolute times)
- ddddddddhhmmss.mmmmmm:000 (for time intervals)
*/
static CMPIString * __dtft_getStringFormat ( CMPIDateTime * dt,
CMPIStatus * rc )
{
struct native_datetime * ndt = (struct native_datetime *) dt;
CMSetStatus ( rc, CMPI_RC_OK );
return native_new_CMPIString(ndt->cimDt, rc);
}
//! States, whether the time object represents an interval.
/*!
\param dt the native CMPIDateTime to be checked.
\param rc return code pointer
\return zero, if it is an absolute time, non-zero for intervals.
*/
static CMPIBoolean __dtft_isInterval ( CMPIDateTime * dt, CMPIStatus * rc )
{
struct native_datetime * ndt = (struct native_datetime *) dt;
CMSetStatus ( rc, CMPI_RC_OK );
return ndt->cimDt[21] == ':' ? 1 : 0;
}
//! Creates a new native_datetime object.
/*!
The newly allocated object's function table is initialized to point
to the native functions in this file.
\param mm_add TOOL_MM_ADD for a regular object, TOOL_MM_NO_ADD for
cloned ones
\param msecs the binary time to be stored
\param interval the interval flag to be stored
\param rc return code pointer
\return a fully initialized native_datetime object pointer.
*/
static struct native_datetime * __new_datetime ( const char *cimDt,
CMPIStatus * rc )
{
static const CMPIDateTimeFT dtft = {
NATIVE_FT_VERSION,
__dtft_release,
__dtft_clone,
__dtft_getBinaryFormat,
__dtft_getStringFormat,
__dtft_isInterval
};
static const CMPIDateTime dt = {
"CMPIDateTime",
(CMPIDateTimeFT *)&dtft
};
struct native_datetime * ndt = (struct native_datetime *)
calloc ( 1, sizeof ( struct native_datetime ) );
ndt->dt = dt;
strcpy(ndt->cimDt, cimDt);
CMSetStatus ( rc, CMPI_RC_OK );
return ndt;
}
//! Creates a native CMPIDateTime representing the current time.
/*!
This function calculates the current time and stores it within
a new native_datetime object.
\param rc return code pointer
\return a pointer to a native CMPIDateTime.
*/
CMPIDateTime * native_new_CMPIDateTime ( CMPIStatus * rc )
{
struct timeval tv;
struct timezone tz;
CMPIUint64 msecs;
char cimDt[26];
gettimeofday ( &tv, &tz );
msecs = (CMPIUint64) 1000000 * (CMPIUint64) tv.tv_sec
+ (CMPIUint64) tv.tv_usec;
bin2chars(msecs, 0, rc, cimDt);
return (CMPIDateTime *) __new_datetime ( cimDt, rc );
}
//! Creates a native CMPIDateTime given a fixed binary time.
/*!
This calls is simply passed on to __new_datetime().
\param time fixed time-stamp in microseconds
\param interval states, if the time-stamp is to be treated as interval
\param rc return code pointer
\return a pointer to a native CMPIDateTime.
\sa __dtft_getBinaryFormat()
*/
CMPIDateTime * native_new_CMPIDateTime_fromBinary ( CMPIUint64 time,
CMPIBoolean interval,
CMPIStatus * rc )
{
char cimDt[26];
bin2chars(time, interval, rc, cimDt);
return (CMPIDateTime *) __new_datetime(cimDt, rc);
}
//! Creates a native CMPIDateTime given a fixed time in string representation.
/*!
This function assumes the given string to have one of the following formats:
- for absolute times: yyyymmddhhmmss.mmmmmmsutc
- for time intervals: ddddddddhhmmss.mmmmmm:000
\param string the time to be converted into internal representation
\param rc return code pointer
\return a pointer to a native CMPIDateTime.
\sa __dtft_getStringFormat()
*/
CMPIDateTime * native_new_CMPIDateTime_fromChars ( const char * string,
CMPIStatus * rc )
{
if (string == NULL || strlen(string)!=25 ||
(string[21]!='-' && string[21]!='+' && string[21]!=':')) {
CMSetStatus(rc, CMPI_RC_ERR_INVALID_PARAMETER);
return NULL;
}
return (CMPIDateTime *) __new_datetime(string, rc);
}
/****************************************************************************/
/*** Local Variables: ***/
/*** mode: C ***/
/*** c-basic-offset: 8 ***/
/*** End: ***/