1
0
mirror of https://frontier.innolan.net/rainlance/amiga-tz.git synced 2025-12-07 14:05:55 +00:00
Files
amiga-tz/localtime.c

236 lines
4.8 KiB
C
Raw Normal View History

#
/*LINTLIBRARY*/
/*
** Should there be any built-in rules other than GMT?
** In particular, should zones such as "EST5" (abbreviation is always "EST",
** GMT offset is always 5 hours) be built in?
*/
#include "tzfile.h"
#include "time.h"
#ifdef OBJECTID
static char sccsid[] = "%W%";
#endif
#ifndef TRUE
#define TRUE 1
#define FALSE 0
#endif
#ifndef MAXPATHLEN
#define MAXPATHLEN 1024
#endif
extern char * asctime();
extern struct tm * gmtime();
extern char * strcpy();
extern char * strcat();
extern char * getenv();
struct state {
struct tzhead h;
long ats[TZ_MAX_TIMES];
unsigned char types[TZ_MAX_TIMES];
struct ttinfo ttis[TZ_MAX_TYPES];
char chars[TZ_MAX_CHARS + 1];
};
static struct state s;
static char isset;
char * tz_abbr; /* set by localtime; available to all */
#define GETSHORT(val, p) { \
register int shortval; \
shortval = *p++; \
shortval = (shortval << 8) | *p++; \
val = shortval; \
}
#define GETLONG(val, p) { \
register long longval; \
longval = *p++; \
longval = (longval << 8) | *p++; \
longval = (longval << 8) | *p++; \
longval = (longval << 8) | *p++; \
val = longval; \
}
static
tzload(tzname, sp)
register char * tzname;
register struct state * sp;
{
register int i;
register int fid;
if (tzname == 0 && (tzname = TZDEFAULT) == 0)
return -1;
{
register char * p;
register int doaccess;
char fullname[MAXPATHLEN];
doaccess = tzname[0] == '/';
if (!doaccess) {
if ((p = TZDIR) == 0)
return -1;
if ((strlen(p) + strlen(tzname) + 1) >= sizeof fullname)
return -1;
(void) strcpy(fullname, p);
(void) strcat(fullname, "/");
(void) strcat(fullname, tzname);
/*
** Set doaccess if '.' (as in "../") shows up in name.
*/
while (*tzname != '\0')
if (*tzname++ == '.')
doaccess = TRUE;
tzname = fullname;
}
if (doaccess && access(tzname, 4) != 0)
return -1;
if ((fid = open(tzname, 0)) == -1)
return -1;
}
{
register unsigned char * p;
unsigned char buf[sizeof s];
p = buf;
i = read(fid, (char *) p, sizeof buf);
if (close(fid) != 0 || i < sizeof sp->h)
return -1;
p += sizeof sp->h.tzh_reserved;
GETSHORT(sp->h.tzh_timecnt, p);
GETSHORT(sp->h.tzh_typecnt, p);
GETSHORT(sp->h.tzh_charcnt, p);
if (sp->h.tzh_timecnt > TZ_MAX_TIMES ||
sp->h.tzh_typecnt == 0 ||
sp->h.tzh_typecnt > TZ_MAX_TYPES ||
sp->h.tzh_charcnt > TZ_MAX_CHARS)
return -1;
if (i < sizeof sp->h.tzh_reserved + 3 * sizeof (short) +
sp->h.tzh_timecnt * (sizeof (long) + sizeof (char)) +
sp->h.tzh_typecnt * (sizeof (long) + 2*sizeof (char)) +
sp->h.tzh_charcnt * sizeof (char))
return -1;
for (i = 0; i < sp->h.tzh_timecnt; ++i)
GETLONG(sp->ats[i], p);
for (i = 0; i < sp->h.tzh_timecnt; ++i)
sp->types[i] = *p++;
for (i = 0; i < sp->h.tzh_typecnt; ++i) {
register struct ttinfo * ttisp;
ttisp = &sp->ttis[i];
GETLONG(ttisp->tt_gmtoff, p);
ttisp->tt_isdst = *p++;
ttisp->tt_abbrind = *p++;
}
for (i = 0; i < sp->h.tzh_charcnt; ++i)
sp->chars[i] = *p++;
sp->chars[sp->h.tzh_charcnt] = '\0'; /* ensure '\0' at end */
}
/*
** Check that all the local time type indices are valid.
*/
for (i = 0; i < sp->h.tzh_timecnt; ++i)
if (sp->types[i] >= sp->h.tzh_typecnt)
return -1;
/*
** Check that all the abbreviation indices are valid.
*/
for (i = 0; i < sp->h.tzh_typecnt; ++i)
if (sp->ttis[i].tt_abbrind >= sp->h.tzh_charcnt)
return -1;
return 0;
}
/*
** settz("") Use built-in GMT.
** settz((char *) 0) Use TZDEFAULT.
** settz(otherwise) Use otherwise.
*/
settz(tzname)
char * tzname;
{
register int answer;
isset = TRUE;
if (tzname != 0 && *tzname == '\0')
answer = 0; /* Use built-in GMT */
else {
if (tzload(tzname, &s) == 0)
return 0;
/*
** If we want to try for local time on errors. . .
if (tzload((char *) 0, &s) == 0)
return -1;
*/
answer = -1;
}
s.h.tzh_timecnt = 0;
s.ttis[0].tt_gmtoff = 0;
s.ttis[0].tt_abbrind = 0;
(void) strcpy(s.chars, "GMT");
return answer;
}
static struct tm *
newsub(timep, sp)
register long * timep;
register struct state * sp;
{
register struct ttinfo * ttisp;
register struct tm * tmp;
register int i;
long t;
t = *timep;
if (sp->h.tzh_timecnt == 0 || t < sp->ats[0])
i = 0;
else {
for (i = 1; i < sp->h.tzh_timecnt; ++i)
if (t < sp->ats[i])
break;
i = sp->types[i - 1];
}
ttisp = &sp->ttis[i];
t += ttisp->tt_gmtoff;
tmp = gmtime(&t);
tmp->tm_isdst = ttisp->tt_isdst;
tz_abbr = &sp->chars[ttisp->tt_abbrind];
return tmp;
}
struct tm *
newlocaltime(timep)
long * timep;
{
if (!isset)
(void) settz(getenv("TZ"));
return newsub(timep, &s);
}
struct tm *
zonetime(timep, zone)
long * timep;
char * zone;
{
struct state st;
return (tzload(zone, &st) == 0) ? newsub(timep, &st) : 0;
}
char *
newctime(timep)
long * timep;
{
return asctime(newlocaltime(timep));
}