scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | README | LICENSE

commit 5615aa3df1812d66a73f58b645f38c7cd4c40122
parent ca137e7b328a2a441075de9b9b178086464bbbce
Author: Naveen Narayanan <zerous@simple-cc.org>
Date:   Tue, 13 Oct 2020 20:11:07 +0200

libc: Implement tzset in time

Supported format: stdoffset[dst[offset]],start,end

This implementation of tzset supports Julian and Gregorian formats for
the start and end dates. The default time when daylight savings time
starts and ends is 02:00:00 AM.

Thanks k0ga for the parser!

Diffstat:
Msrc/libc/arch/posix/_tzone.c | 254+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Msrc/libc/libc.h | 10+++++++++-
Msrc/libc/time/Makefile | 6++++++
Asrc/libc/time/gentz.awk | 9+++++++++
Msrc/libc/time/localtime.c | 52++++++++++++++++++++++++++++++++++++++++++++--------
Msrc/libc/time/mktime.c | 8+-------
Asrc/libc/time/timezone.lst | 332+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 638 insertions(+), 33 deletions(-)

diff --git a/src/libc/arch/posix/_tzone.c b/src/libc/arch/posix/_tzone.c @@ -1,27 +1,247 @@ #include <stdlib.h> +#include <string.h> #include <time.h> + #include "../../libc.h" -struct tzone * -_tzone(struct tm *tm) +#define TOKENSIZ 10 + +enum { + EOS, + NUM, + STR, +}; + +enum { + GREGORIAN, + JULIAN, +}; + +static char st[TOKENSIZ], ds[TOKENSIZ], tokstr[TOKENSIZ]; +static int tok; + +char *_tzname[2] = { st, ds }; +time_t _tzstdoff, _tzdstoff; +time_t _tzstart, _tzend; +int _tzjulian; + +static int +next(char *str) +{ + int n, t; + static char *s; + + if (str) + s = str; + + switch (*s) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + n = strspn(s, "0123456789"); + t = NUM; + break; + case '+': + case '-': + case ':': + case ',': + n = 1; + t = *s; + break; + case '\0': + n = 0; + t = EOS; + break; + default: + n = strcspn(s, "+-0123456789"); + t = STR; + break; + } + + if (n >= TOKENSIZ-1) + return -1; + memcpy(tokstr, s, n); + tokstr[n] = '\0'; + s += n; + + return tok = t; +} + +static int +accept(int c) +{ + if (tok != c) + return 0; + return next(NULL); +} + +static int +num(int max) +{ + int n; + + if (tok == EOS) + return 0; + if (tok != NUM) + return -1; + n = atoi(tokstr); + if (n < 0 || n > max) + return -1; + return n; +} + +static long +offset(void) +{ + int sign = 1; + int n; + long off; + + if (tok == EOS) + return -1; + + switch (tok) { + case '+': + sign = -1; + case '-': + next(NULL); + break; + default: + return -1; + } + + if ((n = num(24)) < 0) + return -1; + off = n * SECHOUR; + next(NULL); + if (tok == EOS) + goto ret; + + if (!accept(':')) + return -1; + if ((n = num(60)) < 0) + return -1; + off += n * SECMIN; + next(NULL); + if (tok == EOS) + goto ret; + + if (!accept(':')) + return -1; + if ((n = num(60)) < 0) + return -1; + off += n; + next(NULL); + + ret: + return sign * off; +} + +static int +std(void) +{ + time_t off; + + if (tok != STR) + return 0; + strcpy(st, tokstr); + next(NULL); + + if ((off = offset()) == -1) + return 0; + _tzstdoff = off; + + return 1; +} + +static int +dst(void) +{ + time_t off; + + if (tok != STR) + return 0; + strcpy(ds, tokstr); + next(NULL); + + if ((off = offset()) == -1) + _tzdstoff = off; + else + _tzdstoff = _tzstdoff + SECHOUR; + + return 1; +} + +static int +yday(void) { - static struct tzone tz; - static int first = 1; + int type, n; - if (!first) - return &tz; + if (tok == STR && !strcmp(tokstr, "J")) + type = JULIAN; + else if (tok == NUM) + type = GREGORIAN; + else + return -1; - tz.name = getenv("TZ"); - if (!tz.name || *tz.name == '\0') { - tz.name = NULL; - tz.gmtoff = 0; - tz.isdst = 0; - } else { - /* TODO: parse TZ string */ - tz.gmtoff = 0; - tz.isdst = 0; + switch (type) { + case JULIAN: + next(NULL); + n = num(365); + next(NULL); + if (n == 0) + return -1; + _tzjulian = 1; + break; + case GREGORIAN: + n = num(365); + next(NULL); + break; } - first = 0; - return &tz; + return n; +} + +static int +rule(void) +{ + if (tok == EOS) + return 0; + if (!accept(',')) + return 0; + if ((_tzstart = yday()) == -1) + return 0; + if (!accept(',')) + return 0; + if ((_tzend = yday()) == -1) + return 0; +} + +void +_tzset(void) +{ + char *tz = getenv("TZ"); + int i; + + _tzstdoff = _tzdstoff = (time_t) -1; + _tzstart = _tzend = (time_t) -1; + _tzjulian = 0; + + if (!tz) + return; + next(tz); + + if (!std()) + return; + if (!dst()) + return; + if (!rule()) + return; } diff --git a/src/libc/libc.h b/src/libc/libc.h @@ -24,12 +24,20 @@ struct tzone { struct tm; -extern struct tzone *_tzone(struct tm *tm); +extern void _tzset(void); extern int _daysyear(int year); extern int _newyear(int year); extern void *_getheap(void); extern int _dtoi(char); +#ifdef _TIME_H +extern char *_tzname[2]; +extern time_t _tzstdoff, _tzdstoff; +extern time_t _tzstart, _tzend; +extern int _tzjulian; +extern struct tzone tzones[]; +#endif + #ifdef stdin extern int _flsbuf(FILE *fp); extern int _allocbuf(FILE *fp); diff --git a/src/libc/time/Makefile b/src/libc/time/Makefile @@ -12,12 +12,18 @@ OBJS =\ localtime.$O\ mktime.$O\ strftime.$O\ + tz.$O\ all: $(LIBC) $(LIBC): $(OBJS) $(MKLST) +$(OBJS): tz.c + +tz.c: timezone.lst + awk -f gentz.awk $< >$@ + dep: inc-dep include deps.mk diff --git a/src/libc/time/gentz.awk b/src/libc/time/gentz.awk @@ -0,0 +1,9 @@ +BEGIN { print "#include \"../libc.h\"\nstruct tzone tzones[] = {" } +{ + split($2,a,":") + min = a[1] * 60 + min = min + a[2] + sec = min * 60 + printf "\t{\"%s\", %d},\n", $1, sec +} +END { print "\t{0,\t0}\n};\n" } diff --git a/src/libc/time/localtime.c b/src/libc/time/localtime.c @@ -1,22 +1,58 @@ +#include <string.h> #include <time.h> #include "../libc.h" #undef localtime +static time_t +gmtoff(char *tz) +{ + for (struct tzone *t = tzones; t->name; t++) + if (!strcmp(t->name, tz)) + return t->gmtoff; + return 0; +} + struct tm * localtime(const time_t *timep) { - struct tzone *tz; struct tm *tm; - time_t t = *timep; + time_t t; + int yday; + static int first = 1; + + t = *timep; + tm = gmtime(&t); + yday = tm->tm_yday; + + if (first) { + _tzset(); + if (_tzstdoff == -1) + _tzstdoff = gmtoff(_tzname[0]); + if (_tzdstoff == -1) + _tzdstoff = gmtoff(_tzname[1]); + } + first = 0; + + tm->tm_gmtoff = _tzstdoff; + tm->tm_zone = _tzname[0]; + tm->tm_isdst = 0; + + if (_tzjulian && + ((yday + 1) < 60) || + (FEBDAYS(tm->tm_year) < 29)) + yday++; + + if (yday >= _tzstart && + yday <= _tzend && + tm->tm_hour >= 2) { + tm->tm_gmtoff = _tzdstoff; + tm->tm_zone = _tzname[1]; + tm->tm_isdst = 1; + } - tz = _tzone(gmtime(timep)); - t += tz->gmtoff * 60; - t += tz->isdst * 60; + t += tm->tm_gmtoff; tm = gmtime(&t); - tm->tm_zone = tz->name; - tm->tm_isdst = tz->isdst; - tm->tm_gmtoff = tz->gmtoff; return tm; } diff --git a/src/libc/time/mktime.c b/src/libc/time/mktime.c @@ -109,13 +109,7 @@ mktime(struct tm *tm) aux = localtime(&t); - dst = 0; - if (tm->tm_isdst == 0 && aux->tm_isdst == 1) - dst = -SECHOUR; - else if (tm->tm_isdst == 1 && aux->tm_isdst == 0) - dst = +SECHOUR; - - t += aux->tm_gmtoff + dst; + t += aux->tm_gmtoff; return t; } diff --git a/src/libc/time/timezone.lst b/src/libc/time/timezone.lst @@ -0,0 +1,332 @@ +ACDT +10:30 +ACST +09:30 +ACT -05 +ACT +09 +ACWST +08:45 +ADT -03 +AEDT +11 +AEST +10 +AFT +04:30 +AKDT -08 +AKST -09 +ALMT +06 +AMST -03 +AMT -04 +AMT +04 +ANAT +12 +AQTT +05 +ART -03 +AST +03 +AST -04 +AWST +08 +AZOST +00 +AZOT -01 +AZT +04 +BDT +08 +BIOT +06 +BIT -12 +BOT -04 +BRST -02 +BRT -03 +BST +06 +BST +11 +BST +01 +BTT +06 +CAT +02 +CCT +06:30 +CDT -05 +CDT -04 +CEST +02 +CET +01 +CHADT +13:45 +CHAST +12:45 +CHOT +08 +CHOST +09 +CHST +10 +CHUT +10 +CIST -08 +CIT +08 +CKT -10 +CLST -03 +CLT -04 +COST -04 +COT -05 +CST -06 +CST +08 +CST -05 +CT +08 +CVT -01 +CWST +08:45 +CXT +07 +DAVT +07 +DDUT +10 +DFT +01 +EASST -05 +EAST -06 +EAT +03 +ECT -04 +ECT -05 +EDT -04 +EEST +03 +EET +02 +EGST +00 +EGT -01 +EIT +09 +EST -05 +FET +03 +vFJT +12 +FKST -03 +FKT -04 +FNT -02 +GALT -06 +GAMT -09 +GET +04 +GFT -03 +GILT +12 +GIT -09 +GMT +00 +GST -02 +GST +04 +GYT -04 +HDT -09 +HAEC +02 +HST -10 +HKT +08 +HMT +05 +HOVST +08 +HOVT +07 +ICT +07 +IDLW -12 +IDT +03 +IOT +03 +IRDT +04:30 +IRKT +08 +IRST +03:30 +IST +05:30 +IST +01 +IST +02 +JST +09 +KALT +02 +KGT +06 +KOST +11 +KRAT +07 +KST +09 +LHST +10:30 +LHST +11 +LINT +14 +MAGT +12 +MART -09:30 +MAWT +05 +MDT -06 +MET +01 +MEST +02 +MHT +12 +MIST +11 +MIT -09:30 +MMT +06:30 +MSK +03 +MST +08 +MST -07 +MUT +04 +MVT +05 +MYT +08 +NCT +11 +NDT -02:30 +NFT +11 +NOVT +07 +NPT +05:45 +NST -03:30 +NT -03:30 +NUT -11 +NZDT +13 +NZST +12 +OMST +06 +ORAT +05 +PDT -07 +PET -05 +PETT +12 +PGT +10 +PHOT +13 +PHT +08 +PKT +05 +PMDT -02 +PMST -03 +PONT +11 +PST -08 +PST +08 +PYST -03 +PYT -04 +RET +04 +ROTT -03 +SAKT +11 +SAMT +04 +SAST +02 +SBT +11 +SCT +04 +SDT -10 +SGT +08 +SLST +05:30 +SRET +11 +SRT -03 +SST -11 +SST +08 +SYOT +03 +TAHT -10 +THA +07 +TFT +05 +TJT +05 +TKT +13 +TLT +09 +TMT +05 +TRT +03 +TOT +13 +TVT +12 +ULAST +09 +ULAT +08 +UTC +00 +UYST -02 +UYT -03 +UZT +05 +VET -04 +VLAT +10 +VOLT +04 +VOST +06 +VUT +11 +WAKT +12 +WAST +02 +WAT +01 +WEST +01 +WET +00 +WIT +07 +WGST -02 +WGT -03 +WST +08 +YAKT +09 +YEKT +12 +FKST -03 +FKT -04 +FNT -02 +GALT -06 +GAMT -09 +GET +04 +GFT -03 +GILT +12 +GIT -09 +GMT +00 +GST -02 +GST +04 +GYT -04 +HDT -09 +HAEC +02 +HST -10 +HKT +08 +HMT +05 +HOVST +08 +HOVT +07 +ICT +07 +IDLW -12 +IDT +03 +IOT +03 +IRDT +04:30 +IRKT +08 +IRST +03:30 +IST +05:30 +IST +01 +IST +02 +JST +09 +KALT +02 +KGT +06 +KOST +11 +KRAT +07 +KST +09 +LHST +10:30 +LHST +11 +LINT +14 +MAGT +12 +MART -09:30 +MAWT +05 +MDT -06 +MET +01 +MEST +02 +MHT +12 +MIST +11 +MIT -09:30 +MMT +06:30 +MSK +03 +MST +08 +MST -07 +MUT +04 +MVT +05 +MYT +08 +NCT +11 +NDT -02:30 +NFT +11 +NOVT +07 +NPT +05:45 +NST -03:30 +NT -03:30 +NUT -11 +NZDT +13 +NZST +12 +OMST +06 +ORAT +05 +PDT -07 +PET -05 +PETT +12 +PGT +10 +PHOT +13 +PHT +08 +PKT +05 +PMDT -02 +PMST -03 +PONT +11 +PST -08 +PST +08 +PYST -03 +PYT -04 +RET +04 +ROTT -03 +SAKT +11 +SAMT +04 +SAST +02 +SBT +11 +SCT +04 +SDT -10 +SGT +08 +SLST +05:30 +SRET +11 +SRT -03 +SST -11 +SST +08 +SYOT +03 +TAHT -10 +THA +07 +TFT +05 +TJT +05 +TKT +13 +TLT +09 +TMT +05 +TRT +03 +TOT +13 +TVT +12 +ULAST +09 +ULAT +08 +UYST -02 +UYT -03 +UZT +05 +VET -04 +VLAT +10 +VOLT +04 +VOST +06 +VUT +11 +WAKT +12 +WAST +02 +WAT +01 +WEST +01 +WET +00 +WIT +07 +WGST -02 +WGT -03 +WST +08 +YAKT +09 +YEKT +05