/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** 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, see .
*/
/****************************************************************************\
wtime Neal Kettler
\****************************************************************************/
#include
#include "wtime.h"
static char *DAYS[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"};
static char *FULLDAYS[]={"Sunday","Monday","Tuesday","Wednesday","Thursday",
"Friday","Saturday"};
static char *MONTHS[]={"Jan","Feb","Mar","Apr","May","Jun","Jul",
"Aug","Sep","Oct","Nov","Dec"};
static char *FULLMONTHS[]={"January","February","March","April","May","June",
"July","August","September","October","November","December"};
Wtime::Wtime(void)
{
Update();
}
Wtime::Wtime( Wtime &other )
{
sign=other.sign;
sec=other.sec;
usec=other.usec;
}
Wtime::Wtime( uint32 other )
{
sign=POSITIVE;
sec=other;
usec=0;
}
Wtime::~Wtime()
{
}
void Wtime::Update(void)
{
sign=POSITIVE;
#ifdef _WINDOWS
struct _timeb wintime;
_ftime(&wintime);
sec=wintime.time;
usec=(wintime.millitm)*1000;
#endif
#ifndef _WINDOWS
struct timeval unixtime;
struct timezone unixtzone;
gettimeofday(&unixtime,&unixtzone);
sec=unixtime.tv_sec;
usec=unixtime.tv_usec;
#endif
}
// Parses a date string that's in modified RFC 1123 format
// Can have a +minutes after the normal time
// eg: Thu, 20 Jun 1996 17:33:49 +100
// Returns true if successfully parsed, false otherwise
bit8 Wtime::ParseDate(char *in)
{
int i;
uint32 minOffset;
struct tm t;
char *ptr=in;
while ((!isgraph(*ptr))&&(*ptr!=0)) ptr++; // skip to start of string
if (*ptr==0) return(FALSE);
t.tm_wday=-1;
for (i=0; i<7; i++) // parse day of week
if (strncmp(ptr,DAYS[i],strlen(DAYS[i]))==0)
t.tm_wday=i;
if (t.tm_wday==-1)
return(FALSE);
while ((!isdigit(*ptr))&&(*ptr!=0)) ptr++; // skip to day of month
if (*ptr==0) return(FALSE);
t.tm_mday=atoi(ptr);
while ((!isalpha(*ptr))&&(*ptr!=0)) ptr++; // skip to month
if (*ptr==0) return(FALSE);
t.tm_mon=-1;
for (i=0; i<12; i++) // match month
if (strncmp(ptr,MONTHS[i],strlen(MONTHS[i]))==0) t.tm_mon=i;
if (t.tm_mon==-1) return(FALSE);
while ((!isdigit(*ptr))&&(*ptr!=0)) ptr++;
if (*ptr==0) return(FALSE);
t.tm_year=atoi(ptr);
if (t.tm_year<70) // if they specify a 2 digit year, we'll be nice
t.tm_year+=2000;
else if (t.tm_year<100)
t.tm_year+=1900;
if (t.tm_year>2200) // I doubt my code will be around for another 203 years
return(FALSE);
while ((isdigit(*ptr))&&(*ptr!=0)) ptr++; // skip to end of year
if (*ptr==0) return(FALSE);
while ((!isgraph(*ptr))&&(*ptr!=0)) ptr++; // skip to start of time
if (*ptr==0) return(FALSE);
t.tm_hour=atoi(ptr);
while ((*ptr!=':')&&(*ptr!=0)) ptr++;
ptr++; // skip past colon
if (*ptr==0) return(FALSE);
t.tm_min=atoi(ptr);
while ((*ptr!=':')&&(*ptr!=0)) ptr++;
ptr++; // skip past colon
if (*ptr==0) return(FALSE);
t.tm_sec=atoi(ptr);
t.tm_year%=100; // 1996 is stored as 96, not 1996
t.tm_isdst=-1; // daylight savings info isn't available
sec=(uint32)(mktime(&t));
if ((sint32)sec==-1)
return(FALSE);
// The next part of the time is OPTIONAL (+minutes)
// first skip past the seconds
while ((isdigit(*ptr))&&(*ptr!=0)) ptr++;
if (*ptr==0) return(TRUE);
// skip past any spaces
while ((isspace(*ptr))&&(*ptr!=0)) ptr++;
if (*ptr!='+')
{
//printf("\nNOPE ptr was '%s'\n",ptr);
return(TRUE);
}
ptr++;
if (*ptr==0)
{
//printf("\nPTR WAS 0\n");
return(TRUE);
}
minOffset=atol(ptr);
//printf("\n\nAdding %d minutes!\n\n",minOffset);
sec+=minOffset*60; // add the minutes as seconds
return(TRUE);
}
// This takes the standard Microsoft time formatting string
// make sure the out string is big enough
// An example format would be "mm/dd/yy hh:mm:ss"
bit8 Wtime::FormatTime(char *out, char *format)
{
int lastWasH=0;
out[0]=0;
char *ptr=format;
if (*ptr=='"') ptr++; // skip past open quote if exists
while (*ptr!=0)
{
if (lastWasH>0)
lastWasH--;
if (isspace(*ptr))
{
if (lastWasH==1) lastWasH=2;
sprintf(out+strlen(out),"%c",*ptr);
ptr+=1;
}
else if (strncmp(ptr,"\"",1)==0)
{
break;
}
else if (strncmp(ptr,":",1)==0)
{
if (lastWasH==1) lastWasH=2;
sprintf(out+strlen(out),":");
ptr+=1;
}
else if (strncmp(ptr,"/",1)==0)
{
sprintf(out+strlen(out),"/");
ptr+=1;
}
else if (strncmp(ptr,"c",1)==0)
{
sprintf(out+strlen(out),"%ld/%ld/%02ld %ld:%02ld:%02ld",GetMonth(),
GetMDay(),GetYear()%100,GetHour(),GetMinute(),GetSecond());
ptr+=1;
}
else if (strncmp(ptr,"dddddd",6)==0)
{
sprintf(out+strlen(out),"%s %02ld, %ld",FULLMONTHS[GetMonth()-1],
GetMDay(),GetYear());
ptr+=6;
}
else if (strncmp(ptr,"ddddd",5)==0)
{
sprintf(out+strlen(out),"%ld/%ld/%02ld",GetMonth(),GetMDay(),
GetYear()%100);
ptr+=5;
}
else if (strncmp(ptr,"dddd",4)==0)
{
sprintf(out+strlen(out),"%s",FULLDAYS[GetWDay()-1]);
ptr+=4;
}
else if (strncmp(ptr,"ddd",3)==0)
{
sprintf(out+strlen(out),"%s",DAYS[GetWDay()-1]);
ptr+=3;
}
else if (strncmp(ptr,"dd",2)==0)
{
sprintf(out+strlen(out),"%02ld",GetMDay());
ptr+=2;
}
else if (strncmp(ptr,"d",1)==0)
{
sprintf(out+strlen(out),"%ld",GetMDay());
ptr+=1;
}
else if (strncmp(ptr,"ww",2)==0)
{
sprintf(out+strlen(out),"%02ld",GetYWeek());
ptr+=2;
}
else if (strncmp(ptr,"w",1)==0)
{
sprintf(out+strlen(out),"%ld",GetWDay());
ptr+=1;
}
else if (strncmp(ptr,"mmmm",4)==0)
{
sprintf(out+strlen(out),"%s",FULLMONTHS[GetMonth()-1]);
ptr+=4;
}
else if (strncmp(ptr,"mmm",3)==0)
{
sprintf(out+strlen(out),"%s",MONTHS[GetMonth()-1]);
ptr+=3;
}
else if (strncmp(ptr,"mm",2)==0)
{
if (lastWasH==1)
sprintf(out+strlen(out),"%02ld",GetMinute());
else
sprintf(out+strlen(out),"%02ld",GetMonth());
ptr+=2;
}
else if (strncmp(ptr,"m",1)==0)
{
if (lastWasH==1)
sprintf(out+strlen(out),"%ld",GetMinute());
else
sprintf(out+strlen(out),"%ld",GetMonth());
ptr+=1;
}
else if (strncmp(ptr,"q",1)==0)
{
sprintf(out+strlen(out),"%ld",((GetMonth()-1)/4)+1); // GetQuarter
ptr+=1;
}
else if (strncmp(ptr,"yyyy",4)==0)
{
sprintf(out+strlen(out),"%ld",GetYear());
ptr+=4;
}
else if (strncmp(ptr,"yy",2)==0)
{
sprintf(out+strlen(out),"%02ld",GetYear()%100);
ptr+=2;
}
else if (strncmp(ptr,"y",1)==0)
{
sprintf(out+strlen(out),"%ld",GetYDay());
ptr+=1;
}
else if (strncmp(ptr,"hh",2)==0)
{
sprintf(out+strlen(out),"%02ld",GetHour());
lastWasH=2; // needs to be 1 after top of loop decs it
ptr+=2;
}
else if (strncmp(ptr,"h",1)==0)
{
sprintf(out+strlen(out),"%ld",GetHour());
lastWasH=2; // needs to be 1 after top of loop decs it
ptr+=1;
}
else if (strncmp(ptr,"nn",2)==0)
{
sprintf(out+strlen(out),"%02ld",GetMinute());
ptr+=2;
}
else if (strncmp(ptr,"n",1)==0)
{
sprintf(out+strlen(out),"%ld",GetMinute());
ptr+=1;
}
else if (strncmp(ptr,"ss",2)==0)
{
sprintf(out+strlen(out),"%02ld",GetSecond());
ptr+=2;
}
else if (strncmp(ptr,"s",1)==0)
{
sprintf(out+strlen(out),"%ld",GetSecond());
ptr+=1;
}
else if (strncmp(ptr,"ttttt",5)==0)
{
sprintf(out+strlen(out),"%ld:%02ld:%02ld",GetHour(),GetMinute(),
GetSecond());
ptr+=5;
}
// todo
// AM/PM am/pm A/P a/p AMPM
else // an unknown char, move to next
ptr++;
}
return(TRUE);
}
// In addition to PrintTime & PrintDate there is the 'Print' function
// which prints both in RFC 1123 format
void Wtime::PrintTime(FILE *out) const
{
char string[80];
PrintTime(string);
fprintf(out,"%s",string);
}
void Wtime::PrintTime(char *out) const
{
sprintf(out," %02lu:%02lu:%02lu",GetHour(),GetMinute(),GetSecond());
}
void Wtime::PrintDate(FILE *out) const
{
char string[80];
PrintDate(string);
fprintf(out,"%s",string);
}
void Wtime::PrintDate(char *out) const
{
sprintf(out,"%s, %lu %s %lu",DAYS[GetWDay()-1],GetMDay(),MONTHS[GetMonth()-1],
GetYear());
}
uint32 Wtime::GetSec(void) const
{
return(sec);
}
uint32 Wtime::GetUsec(void) const
{
return(usec);
}
void Wtime::SetSec(uint32 newsec)
{
sec=newsec;
}
void Wtime::SetUsec(uint32 newusec)
{
usec=newusec;
}
void Wtime::Set(uint32 newsec, uint32 newusec)
{
sec=newsec;
usec=newusec;
}
// Get a timeval ptr from a Wtime class
struct timeval *Wtime::GetTimeval(void)
{
static struct timeval tv;
tv.tv_sec=sec;
tv.tv_usec=usec;
return(&tv);
}
// Get a timeval ptr from a Wtime class
void Wtime::GetTimevalMT(struct timeval &tv)
{
tv.tv_sec=sec;
tv.tv_usec=usec;
}
uint32 Wtime::GetSecond(void) const
{
struct tm *tptr;
#ifndef _WINDOWS
struct tm t;
tptr=localtime_r((time_t *)&sec,&t);
#else
tptr=localtime((time_t *)&sec);
#endif
return(tptr->tm_sec);
}
uint32 Wtime::GetMinute(void) const
{
struct tm *tptr;
#ifndef _WINDOWS
struct tm t;
tptr=localtime_r((time_t *)&sec,&t);
#else
tptr=localtime((time_t *)&sec);
#endif
return(tptr->tm_min);
}
uint32 Wtime::GetHour(void) const
{
struct tm *tptr;
#ifndef _WINDOWS
struct tm t;
tptr=localtime_r((time_t *)&sec,&t);
#else
tptr=localtime((time_t *)&sec);
#endif
return(tptr->tm_hour);
}
uint32 Wtime::GetMDay(void) const
{
struct tm *tptr;
#ifndef _WINDOWS
struct tm t;
tptr=localtime_r((time_t *)&sec,&t);
#else
tptr=localtime((time_t *)&sec);
#endif
return(tptr->tm_mday);
}
uint32 Wtime::GetWDay(void) const
{
struct tm *tptr;
#ifndef _WINDOWS
struct tm t;
tptr=localtime_r((time_t *)&sec,&t);
#else
tptr=localtime((time_t *)&sec);
#endif
return(tptr->tm_wday+1);
}
uint32 Wtime::GetYDay(void) const
{
struct tm *tptr;
#ifndef _WINDOWS
struct tm t;
tptr=localtime_r((time_t *)&sec,&t);
#else
tptr=localtime((time_t *)&sec);
#endif
return(tptr->tm_yday+1);
}
uint32 Wtime::GetYWeek(void) const
{
uint32 yweek;
uint32 yday=GetYDay();
uint32 wday=GetWDay();
//phase holds the first weekday of the year. If (Jan 1 = Sun) phase = 0
sint32 phase=((wday-yday)%7);
if (phase<0) phase+=7;
yweek=((yday+phase-1)/7)+1;
return(yweek);
}
uint32 Wtime::GetMonth(void) const
{
struct tm *tptr;
#ifndef _WINDOWS
struct tm t;
tptr=localtime_r((time_t *)&sec,&t);
#else
tptr=localtime((time_t *)&sec);
#endif
return(tptr->tm_mon+1);
}
uint32 Wtime::GetYear(void) const
{
struct tm *tptr;
#ifndef _WINDOWS
struct tm t;
tptr=localtime_r((time_t *)&sec,&t);
#else
tptr=localtime((time_t *)&sec);
#endif
if ((tptr->tm_year)>=70)
return((tptr->tm_year)+1900);
else
return((tptr->tm_year)+2000);
}
bit8 Wtime::GetSign(void) const
{
return(sign);
}
// 1 = *this > other
//-1 = *this < other
// 0 = *this == other
int Wtime::Compare(const Wtime &other) const
{
if ((sec==other.sec)&&(usec==other.usec))
return(0); // equal
else if (sec>other.sec)
return(1);
else if (secother.usec)
return(1);
else
return(-1);
}
bit8 Wtime::operator == ( const Wtime &other ) const
{
bit8 retval=Compare(other);
if (retval==0)
return(TRUE);
else
return(FALSE);
}
bit8 Wtime::operator != ( const Wtime &other ) const
{
bit8 retval=Compare(other);
if (retval==0)
return(FALSE);
else
return(TRUE);
}
bit8 Wtime::operator < ( const Wtime &other ) const
{
int retval=Compare(other);
if (retval==-1)
return(TRUE);
else
return(FALSE);
}
bit8 Wtime::operator > ( const Wtime &other ) const
{
int retval=Compare(other);
if (retval==1)
return(TRUE);
else
return(FALSE);
}
bit8 Wtime::operator <= ( const Wtime &other ) const
{
int retval=Compare(other);
if ((retval==-1)||(retval==0))
return(TRUE);
else
return(FALSE);
}
bit8 Wtime::operator >= ( const Wtime &other ) const
{
int retval=Compare(other);
if ((retval==1)||(retval==0))
return(TRUE);
else
return(FALSE);
}
// None of the operators pay attention to sign
// only the functions that begin with 'Signed'
void Wtime::SignedAdd(const Wtime &other)
{
Wtime temp;
if ((sign==POSITIVE)&&(other.sign==POSITIVE))
{
*this+=other;
sign=POSITIVE;
}
else if ((sign==POSITIVE)&&(other.sign==NEGATIVE))
{
if (*this>other)
{
*this-=other;
sign=POSITIVE;
}
else
{
temp=other;
temp-=*this;
*this=temp;
sign=NEGATIVE;
}
}
else if ((sign==NEGATIVE)&&(other.sign==POSITIVE))
{
if (*thisother)
{
*this-=other;
sign=POSITIVE;
}
else
{
temp=other;
temp-=*this;
*this=temp;
sign=NEGATIVE;
}
}
else if ((sign==NEGATIVE)&&(other.sign==NEGATIVE))
{
if (*this1000000)
{
sec++;
usec-=1000000;
}
return *this;
}
Wtime &Wtime::operator -= (const Wtime &other)
{
sint32 temp;
if (Compare(other)==-1)
{
sec=0; // can't handle negative time
usec=0;
return *this;
}
sec-=other.sec;
temp=(sint32)usec;
temp-=(sint32)other.usec;
if (temp<0)
{
sec--;
temp+=1000000;
}
usec=temp;
return *this;
}
Wtime Wtime::operator - (Wtime &other)
{
Wtime temp(*this);
temp-=other;
return(temp);
}
Wtime Wtime::operator + (Wtime &other)
{
Wtime temp(*this);
temp+=other;
return(temp);
}
Wtime &Wtime::operator = (const Wtime &other)
{
sign=other.sign;
sec=other.sec;
usec=other.usec;
return *this;
}
Wtime &Wtime::operator += (const uint32 other)
{
sec+=other;
return *this;
}
Wtime &Wtime::operator -= (const uint32 other)
{
sec-=other;
return *this;
}
Wtime Wtime::operator - (uint32 other)
{
Wtime temp(*this);
temp-=other;
return(temp);
}
Wtime Wtime::operator + (uint32 other)
{
Wtime temp(*this);
temp+=other;
return(temp);
}
Wtime &Wtime::operator = (const uint32 other)
{
sign=POSITIVE;
sec=other;
usec=0;
return *this;
}