Fred Gleason d1125fc6a9 2020-01-02 Fred Gleason <fredg@paravelsystems.com>
* Fixed a bug in the 'rivwebcapi' validate_tm() function that caused
	dates containing '29 February' to always fail regardless of leap-year
	validity.
2020-01-02 15:55:02 -05:00

351 lines
9.3 KiB
C

/* rd_common.c
*
* Common Utility Functions for the Rivendell Access Library
*
* (C) Copyright 2015-2019 Fred Gleason <fredg@paravelsystems.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "rd_common.h"
unsigned RD_ReadBool(const char *val)
{
if((strcasecmp(val,"true")==0)||(strcasecmp(val,"yes")==0)||
(strcasecmp(val,"on")==0)) {
return 1;
}
else {
return 0;
}
}
/*******************************************************************
* RD_Cnv_DTString_to_tm
* Take a DateTime String and converts to a tm struct.
* Assumes a Z means Zulu (GMT) Always returns localtime
* in tm struct pointer. Returns null tm on invalid date length
*******************************************************************/
struct tm RD_Cnv_DTString_to_tm( const char *datein)
{
struct tm datetimetm = {0};
struct tm *tmptr;
time_t rawtime;
time_t newrawtime;
char theyear[5];
char themonth[3];
char theday[3];
char thehr[3];
char themin[3];
char thesec[3];
char plusminusz[2];
char offsethr[3];
char offsetmin[3];
double offsetfromutc = 0;
int offhr = 0;
int offmin = 0;
int val;
tmptr = &datetimetm;
if ((strlen(datein) < 19) || // INVALID DATE
(strlen(datein) > 26) )
return datetimetm;
strlcpy(theyear,datein,4);
strlcpy(themonth,datein+5,2);
strlcpy(theday,datein+8,2);
strlcpy(thehr,datein+11,2);
strlcpy(themin,datein+14,2);
strlcpy(thesec,datein+17,2);
if (strlen(datein) > 19)
{
strlcpy(plusminusz,datein+19,1);
if ( (( strcmp(plusminusz,"+"))==0) ||
(( strcmp(plusminusz,"-"))==0) )
{
strlcpy(offsethr,datein+20,2);
strlcpy(offsetmin,datein+23,2);
}
}
val = atoi(theyear) - 1900;
tmptr->tm_year = val;
val = atoi(themonth) - 1;
tmptr->tm_mon = val;
tmptr->tm_mday = atoi(theday);
tmptr->tm_hour = atoi(thehr);
tmptr->tm_min = atoi(themin);
tmptr->tm_sec = atoi(thesec);
/* This is to fix if Windows Assumes apply DST */
#ifdef _WIN32
tmptr->tm_isdst = -1;
#endif
rawtime = mktime (tmptr);
newrawtime = rawtime;
if ((strcmp(plusminusz,"Z")) != 0)
{
if (strlen(datein)==25)
{
offhr = atoi(offsethr);
offmin = atoi(offsetmin);
}
if ((strcmp(plusminusz,"-"))== 0)
{
newrawtime = rawtime + ((offhr * 3600) +
(offmin * 60));
}
else
{
newrawtime = rawtime - ((offhr * 3600) -
(offmin * 60));
}
}
// Get the local offset from UTC
offsetfromutc = get_local_offset();
newrawtime += offsetfromutc;
#ifdef _WIN32
tmptr = localtime(&newrawtime);
#else
localtime_r(&newrawtime,tmptr);
#endif
return datetimetm;
}
/****************************************************************
* strlcpy
* Copies a strng buffer into a string buffer with size bufsiz
* Returns size_t length copied. Null Terminates Automatically
*****************************************************************/
size_t strlcpy(char * dest, const char* src, size_t bufsize)
{
size_t srclen = strlen(src);
size_t len;
if (bufsize == 0)
return bufsize;
len = (bufsize < srclen) ? bufsize : srclen;
memcpy(dest,src,len);
dest[len]='\0';
return len;
}
/****************************************************************
* RD_Cnv_tm_to_DTString
* Copies tm struct values into a date string. Returns
* size_t length copied. Returns 0 if invalid tm struct.
*****************************************************************/
size_t RD_Cnv_tm_to_DTString(struct tm *tmptr,char * dest)
{
char theyear[5];
char themonth[3];
char theday[3];
char thehr[3];
char themin[3];
char thesec[3];
char plusminus[3];
char minus[2] = "-";
char colon_sep[4] = ":";
char T_sep[2] = "T";
char offsethr[3];
char offsetmin[3];
double offsetfromutc;
int offhr = 0;
int offmin = 0;
int val;
int leap = 0;
if (!validate_tm(tmptr))
{
dest[0]=0;
return 0;
}
offsetfromutc = get_local_offset();
if (offsetfromutc > 0)
strlcpy(plusminus,"%2b",3);
else
strlcpy(plusminus,"-",1);
offhr = (int) (offsetfromutc / 3600);
double hold_min;
double divby = 3600;
hold_min = fmod(offsetfromutc,divby);
offmin = (int) (hold_min / 60);
sprintf(offsethr,"%02d",abs(offhr));
sprintf(offsetmin,"%02d",abs(offmin));
val = tmptr->tm_year + 1900;
sprintf(theyear,"%d",val);
val = tmptr->tm_mon + 1;
sprintf(themonth,"%02d",val);
sprintf(theday,"%02d",tmptr->tm_mday);
sprintf(thehr,"%02d",tmptr->tm_hour);
sprintf(themin,"%02d",tmptr->tm_min);
sprintf(thesec,"%02d",tmptr->tm_sec);
strlcpy(dest,theyear,4);
strcat(dest, minus);
strcat(dest,themonth);
strcat(dest, minus);
strcat(dest,theday);
strcat(dest,T_sep);
strcat(dest,thehr);
strcat(dest,colon_sep);
strcat(dest,themin);
strcat(dest,colon_sep);
strcat(dest,thesec);
strcat(dest,plusminus);
strcat(dest,offsethr);
strcat(dest,colon_sep);
strcat(dest,offsetmin);
return strlen(dest);
}
/****************************************************************
* validate tm
* Validates a tm struct YYYY-MM-DD hh:mm:ss
* Returns 1 if successful 0 if error
****************************************************************/
int validate_tm (struct tm *tmptr)
{
int monthdays[12]={31,28,31,30,31,30,31,31,30,31,30,31};
int val;
int leap = 0;
val = tmptr->tm_year + 1900;
if ((val < 1900) || (val > 9999) )
return 0;
if ( (tmptr->tm_mon < 0) ||
(tmptr->tm_mon > 11))
return 0;
if ((tmptr->tm_mday == 29 ) && (tmptr->tm_mon == 1))
{
if ( (val % 400) == 0 )
leap = 1;
else if ((val %100) == 0)
leap = 0;
else if ((val % 4) == 0)
leap = 1;
else
leap = 0;
if (leap)
monthdays[1]=29;
else
return 0;
}
if ( (tmptr->tm_mday > monthdays[tmptr->tm_mon]) ||
(tmptr->tm_mday <=0) )
return 0;
if ( (tmptr->tm_sec > 61) ||
(tmptr->tm_sec < 0))
return 0;
if ( (tmptr->tm_min > 59) ||
(tmptr->tm_min < 0))
return 0;
if ( (tmptr->tm_hour > 23) ||
(tmptr->tm_hour < 0))
return 0;
return 1;
}
/****************************************************************
* get_local_offset
* returns local UTC Offset
* Returns 1 if successful 0 if error
****************************************************************/
double get_local_offset()
{
time_t currtime;
struct tm * timeinfo;
time( &currtime );
timeinfo = gmtime (&currtime);
time_t utc = mktime (timeinfo);
timeinfo = localtime(&currtime);
time_t local = mktime(timeinfo);
double offsetfromutc = difftime(local,utc);
#ifdef _WIN32
if (timeinfo->tm_isdst)
offsetfromutc += 3600;
#endif
return offsetfromutc;
}
/****************************************************************
* RD_Cnv_TString_to_msec
* Converts a relative-to-midnight start time string ("HH:MM:SS.ZZZ")
* and returns it as milliseconds after midnight, or -1 if
* the conversion fails.
*****************************************************************/
int RD_Cnv_TString_to_msec(const char *str)
{
int hour;
int minute;
int second;
int tenth;
if(strlen(str)<10) {
return -1;
}
if(sscanf(str,"%02d",&hour)!=1) {
return -1;
}
if((hour<0)||(hour>23)) {
return -1;
}
if(sscanf(str+3,"%02d",&minute)!=1) {
return -1;
}
if((minute<0)||(minute>59)) {
return -1;
}
if(sscanf(str+6,"%02d",&second)!=1) {
return -1;
}
if((second<0)||(second>59)) {
return -1;
}
if(sscanf(str+9,"%1d",&tenth)!=1) {
return -1;
}
if((tenth<0)||(tenth>9)) {
return -1;
}
return 3600000*hour+60000*minute+1000*second+100*tenth;
}
/****************************************************************
* RD_Cnv_msec_to_TString
* Converts a milliseconds after midnight integer to
* time string ("HH:MM:SS.ZZZ"), returning the length
* of the string.
*****************************************************************/
size_t RD_Cnv_msec_to_TString(char *str, size_t len,int msec)
{
int hour;
int minute;
int second;
int tenth;
if(msec<0) {
str[len]=0;
return 0;
}
hour=msec/3600000;
minute=(msec-3600000*hour)/60000;
second=(msec-3600000*hour-60000*minute)/1000;
tenth=(msec-3600000*hour-60000*minute-1000*second)/100;
snprintf(str,len,"%02d:%02d:%02d.%1d",hour,minute,second,tenth);
return strlen(str);
}