diff options
author | cinap_lenrek <cinap_lenrek@felloff.net> | 2020-06-15 00:12:57 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@felloff.net> | 2020-06-15 00:12:57 +0200 |
commit | febe84af755d8b6941c6e59c1b350f889c4fccb0 (patch) | |
tree | 45cb13daa2c1ef116613a7e461e0c59fda1d5bd6 /sys/src/libc | |
parent | 8b3efcfc4e3b38eab3f0ff503e573c072ff890f5 (diff) |
libc: revert date change again. this is getting ridicuoulus.
this breaks the sample from the seconds manpage, and overall
produces funky results. this needs alot more testing.
term% seconds '23 may 2011'
seconds: tmparse: invalid date 23 may 2011 near 'may 2011'
term% seconds '2019-01-01 00:00:00'
-118370073600
Diffstat (limited to 'sys/src/libc')
-rw-r--r-- | sys/src/libc/9sys/ctime.c | 269 | ||||
-rw-r--r-- | sys/src/libc/9sys/tm2sec.c | 197 | ||||
-rw-r--r-- | sys/src/libc/port/date.c | 859 | ||||
-rw-r--r-- | sys/src/libc/port/mkfile | 1 |
4 files changed, 447 insertions, 879 deletions
diff --git a/sys/src/libc/9sys/ctime.c b/sys/src/libc/9sys/ctime.c index 4b7c9b2e2..11340ea41 100644 --- a/sys/src/libc/9sys/ctime.c +++ b/sys/src/libc/9sys/ctime.c @@ -33,34 +33,269 @@ #include <u.h> #include <libc.h> +static char dmsize[12] = +{ + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +/* + * The following table is used for 1974 and 1975 and + * gives the day number of the first day after the Sunday of the + * change. + */ + +static int dysize(int); +static void ct_numb(char*, int); + +#define TZSIZE 150 +static void readtimezone(void); +static int rd_name(char**, char*); +static int rd_long(char**, long*); +static +struct +{ + char stname[4]; + char dlname[4]; + long stdiff; + long dldiff; + long dlpairs[TZSIZE]; +} timezone; + +char* +ctime(long t) +{ + return asctime(localtime(t)); +} + Tm* localtime(long tim) { - static Tm tm; - Tzone *tz; - - /* No error checking: the API doesn't allow it. */ - tz = tmgetzone("local"); - tmtime(&tm, tim, tz); - return &tm; + Tm *ct; + long t, *p; + int dlflag; + if(timezone.stname[0] == 0) + readtimezone(); + t = tim + timezone.stdiff; + dlflag = 0; + for(p = timezone.dlpairs; *p; p += 2) + if(t >= p[0]) + if(t < p[1]) { + t = tim + timezone.dldiff; + dlflag++; + break; + } + ct = gmtime(t); + if(dlflag){ + strcpy(ct->zone, timezone.dlname); + ct->tzoff = timezone.dldiff; + } else { + strcpy(ct->zone, timezone.stname); + ct->tzoff = timezone.stdiff; + } + return ct; } Tm* -gmtime(long abs) +gmtime(long tim) { - static Tm tm; - return tmtime(&tm, abs, nil); + int d0, d1; + long hms, day; + static Tm xtime; + + /* + * break initial number into days + */ + hms = tim % 86400L; + day = tim / 86400L; + if(hms < 0) { + hms += 86400L; + day -= 1; + } + + /* + * generate hours:minutes:seconds + */ + xtime.sec = hms % 60; + d1 = hms / 60; + xtime.min = d1 % 60; + d1 /= 60; + xtime.hour = d1; + + /* + * day is the day number. + * generate day of the week. + * The addend is 4 mod 7 (1/1/1970 was Thursday) + */ + + xtime.wday = (day + 7340036L) % 7; + + /* + * year number + */ + if(day >= 0) + for(d1 = 1970; day >= dysize(d1); d1++) + day -= dysize(d1); + else + for (d1 = 1970; day < 0; d1--) + day += dysize(d1-1); + xtime.year = d1-1900; + xtime.yday = d0 = day; + + /* + * generate month + */ + + if(dysize(d1) == 366) + dmsize[1] = 29; + for(d1 = 0; d0 >= dmsize[d1]; d1++) + d0 -= dmsize[d1]; + dmsize[1] = 28; + xtime.mday = d0 + 1; + xtime.mon = d1; + strcpy(xtime.zone, "GMT"); + return &xtime; } char* -ctime(long abs) +asctime(Tm *t) +{ + char *ncp; + static char cbuf[30]; + + strcpy(cbuf, "Thu Jan 01 00:00:00 GMT 1970\n"); + ncp = &"SunMonTueWedThuFriSat"[t->wday*3]; + cbuf[0] = *ncp++; + cbuf[1] = *ncp++; + cbuf[2] = *ncp; + ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[t->mon*3]; + cbuf[4] = *ncp++; + cbuf[5] = *ncp++; + cbuf[6] = *ncp; + ct_numb(cbuf+8, t->mday); + ct_numb(cbuf+11, t->hour+100); + ct_numb(cbuf+14, t->min+100); + ct_numb(cbuf+17, t->sec+100); + ncp = t->zone; + cbuf[20] = *ncp++; + cbuf[21] = *ncp++; + cbuf[22] = *ncp; + ct_numb(cbuf+24, (t->year+1900) / 100 + 100); + ct_numb(cbuf+26, t->year+100); + return cbuf; +} + +static +dysize(int y) +{ + + if(y%4 == 0 && (y%100 != 0 || y%400 == 0)) + return 366; + return 365; +} + +static +void +ct_numb(char *cp, int n) +{ + + cp[0] = ' '; + if(n >= 10) + cp[0] = (n/10)%10 + '0'; + cp[1] = n%10 + '0'; +} + +static +void +readtimezone(void) +{ + char buf[TZSIZE*11+30], *p; + int i; + + memset(buf, 0, sizeof(buf)); + i = open("/env/timezone", 0); + if(i < 0) + goto error; + if(read(i, buf, sizeof(buf)) >= sizeof(buf)){ + close(i); + goto error; + } + close(i); + p = buf; + if(rd_name(&p, timezone.stname)) + goto error; + if(rd_long(&p, &timezone.stdiff)) + goto error; + if(rd_name(&p, timezone.dlname)) + goto error; + if(rd_long(&p, &timezone.dldiff)) + goto error; + for(i=0; i<TZSIZE; i++) { + if(rd_long(&p, &timezone.dlpairs[i])) + goto error; + if(timezone.dlpairs[i] == 0) + return; + } + +error: + timezone.stdiff = 0; + strcpy(timezone.stname, "GMT"); + timezone.dlpairs[0] = 0; +} + +static +rd_name(char **f, char *p) +{ + int c, i; + + for(;;) { + c = *(*f)++; + if(c != ' ' && c != '\n') + break; + } + for(i=0; i<3; i++) { + if(c == ' ' || c == '\n') + return 1; + *p++ = c; + c = *(*f)++; + } + if(c != ' ' && c != '\n') + return 1; + *p = 0; + return 0; +} + +static +rd_long(char **f, long *p) { - Tzone *tz; - Tm tm; + int c, s; + long l; - /* No error checking: the API doesn't allow it. */ - tz = tmgetzone("local"); - tmtime(&tm, abs, tz); - return asctime(&tm); + s = 0; + for(;;) { + c = *(*f)++; + if(c == '-') { + s++; + continue; + } + if(c != ' ' && c != '\n') + break; + } + if(c == 0) { + *p = 0; + return 0; + } + l = 0; + for(;;) { + if(c == ' ' || c == '\n') + break; + if(c < '0' || c > '9') + return 1; + l = l*10 + c-'0'; + c = *(*f)++; + } + if(s) + l = -l; + *p = l; + return 0; } diff --git a/sys/src/libc/9sys/tm2sec.c b/sys/src/libc/9sys/tm2sec.c index 96d4c3d61..20bebd0c8 100644 --- a/sys/src/libc/9sys/tm2sec.c +++ b/sys/src/libc/9sys/tm2sec.c @@ -1,9 +1,202 @@ #include <u.h> #include <libc.h> +#define TZSIZE 150 +static void readtimezone(void); +static int rd_name(char**, char*); +static int rd_long(char**, long*); +static +struct +{ + char stname[4]; + char dlname[4]; + long stdiff; + long dldiff; + long dlpairs[TZSIZE]; +} timezone; + +#define SEC2MIN 60L +#define SEC2HOUR (60L*SEC2MIN) +#define SEC2DAY (24L*SEC2HOUR) + +/* + * days per month plus days/year + */ +static int dmsize[] = +{ + 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; +static int ldmsize[] = +{ + 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +/* + * return the days/month for the given year + */ +static int * +yrsize(int y) +{ + if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0)) + return ldmsize; + else + return dmsize; +} + +/* + * compute seconds since Jan 1 1970 GMT + * and convert to our timezone. + */ long tm2sec(Tm *tm) { - tmnorm(tm); - return tm->abs; + long secs, *p; + int i, yday, year, *d2m; + + if(strcmp(tm->zone, "GMT") != 0 && timezone.stname[0] == 0) + readtimezone(); + secs = 0; + + /* + * seconds per year + */ + year = tm->year + 1900; + for(i = 1970; i < year; i++){ + d2m = yrsize(i); + secs += d2m[0] * SEC2DAY; + } + + /* + * if mday is set, use mon and mday to compute yday + */ + if(tm->mday){ + yday = 0; + d2m = yrsize(year); + for(i=0; i<tm->mon; i++) + yday += d2m[i+1]; + yday += tm->mday-1; + }else{ + yday = tm->yday; + } + secs += yday * SEC2DAY; + + /* + * hours, minutes, seconds + */ + secs += tm->hour * SEC2HOUR; + secs += tm->min * SEC2MIN; + secs += tm->sec; + + /* + * Only handles zones mentioned in /env/timezone, + * but things get too ambiguous otherwise. + */ + if(strcmp(tm->zone, timezone.stname) == 0) + secs -= timezone.stdiff; + else if(strcmp(tm->zone, timezone.dlname) == 0) + secs -= timezone.dldiff; + else if(tm->zone[0] == 0){ + secs -= timezone.dldiff; + for(p = timezone.dlpairs; *p; p += 2) + if(secs >= p[0] && secs < p[1]) + break; + if(*p == 0){ + secs += timezone.dldiff; + secs -= timezone.stdiff; + } + } + return secs; +} + +static +void +readtimezone(void) +{ + char buf[TZSIZE*11+30], *p; + int i; + + memset(buf, 0, sizeof(buf)); + i = open("/env/timezone", 0); + if(i < 0) + goto error; + if(read(i, buf, sizeof(buf)) >= sizeof(buf)) + goto error; + close(i); + p = buf; + if(rd_name(&p, timezone.stname)) + goto error; + if(rd_long(&p, &timezone.stdiff)) + goto error; + if(rd_name(&p, timezone.dlname)) + goto error; + if(rd_long(&p, &timezone.dldiff)) + goto error; + for(i=0; i<TZSIZE; i++) { + if(rd_long(&p, &timezone.dlpairs[i])) + goto error; + if(timezone.dlpairs[i] == 0) + return; + } + +error: + timezone.stdiff = 0; + strcpy(timezone.stname, "GMT"); + timezone.dlpairs[0] = 0; +} + +static int +rd_name(char **f, char *p) +{ + int c, i; + + for(;;) { + c = *(*f)++; + if(c != ' ' && c != '\n') + break; + } + for(i=0; i<3; i++) { + if(c == ' ' || c == '\n') + return 1; + *p++ = c; + c = *(*f)++; + } + if(c != ' ' && c != '\n') + return 1; + *p = 0; + return 0; +} + +static int +rd_long(char **f, long *p) +{ + int c, s; + long l; + + s = 0; + for(;;) { + c = *(*f)++; + if(c == '-') { + s++; + continue; + } + if(c != ' ' && c != '\n') + break; + } + if(c == 0) { + *p = 0; + return 0; + } + l = 0; + for(;;) { + if(c == ' ' || c == '\n') + break; + if(c < '0' || c > '9') + return 1; + l = l*10 + c-'0'; + c = *(*f)++; + } + if(s) + l = -l; + *p = l; + return 0; } diff --git a/sys/src/libc/port/date.c b/sys/src/libc/port/date.c deleted file mode 100644 index 0afc4e4fc..000000000 --- a/sys/src/libc/port/date.c +++ /dev/null @@ -1,859 +0,0 @@ -#include <u.h> -#include <libc.h> - -typedef struct Tzabbrev Tzabbrev; -typedef struct Tzoffpair Tzoffpair; - -#define Ctimefmt "W MMM _D hh:mm:ss ZZZ YYYY\n" -enum { - Tzsize = 150, - Nsec = 1000*1000*1000, - Daysec = (vlong)24*3600, - Days400y = 365*400 + 4*25 - 3, - Days4y = 365*4 + 1, -}; - -enum { - Cend, - Cspace, - Cnum, - Cletter, - Cpunct, -}; - -struct Tzone { - char tzname[16]; - char stname[4]; - char dlname[4]; - long stdiff; - long dldiff; - long dlpairs[Tzsize]; -}; - -static QLock zlock; -static int nzones; -static Tzone **zones; -static int mdays[] = { - 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 -}; -static char *wday[] = { - "Sunday","Monday","Tuesday", - "Wednesday","Thursday","Friday", - "Saturday", nil, -}; -static char *month[] = { - "January", "February", "March", - "April", "May", "June", "July", - "August", "September", "October", - "November", "December", nil -}; - -struct Tzabbrev { - char *abbr; - char *name; -}; - -struct Tzoffpair { - char *abbr; - int off; -}; - -/* Obsolete time zone names. Hardcoded to match RFC5322 */ -static Tzabbrev tzabbrev[] = { - {"UT", "GMT"}, {"GMT", "GMT"}, {"UTC", "GMT"}, - {"EST", "US_Eastern"}, {"EDT", "US_Eastern"}, - {"CST", "US_Central"}, {"CDT", "US_Central"}, - {"MST", "US_Mountain"}, {"MDT", "US_Mountain"}, - {"PST", "US_Pacific"}, {"PDT", "US_Pacific"}, - {nil}, -}; - -/* Military timezone names */ -static Tzoffpair milabbrev[] = { - {"A", -1*3600}, {"B", -2*3600}, {"C", -3*3600}, - {"D", -4*3600}, {"E", -5*3600}, {"F", -6*3600}, - {"G", -7*3600}, {"H", -8*3600}, {"I", -9*3600}, - {"K", -10*3600}, {"L", -11*3600}, {"M", -12*3600}, - {"N", +1*3600}, {"O", +2*3600}, {"P", +3*3600}, - {"Q", +4*3600}, {"R", +5*3600}, {"S", +6*3600}, - {"T", +7*3600}, {"U", +8*3600}, {"V", +9*3600}, - {"W", +10*3600}, {"X", +11*3600}, {"Y", +12*3600}, - {"Z", 0}, {nil, 0} -}; - -static int -isleap(int y) -{ - return y % 4 == 0 && (y % 100 != 0 || y % 400 == 0); -} - -static int -rdname(char **f, char *p) -{ - int c, i; - - while((c = *(*f)++) != 0) - if(c != ' ' && c != '\n') - break; - for(i=0; i<3; i++) { - if(c == ' ' || c == '\n') - return 1; - *p++ = c; - c = *(*f)++; - } - if(c != ' ' && c != '\n') - return 1; - *p = 0; - return 0; -} - -static int -rdlong(char **f, long *p) -{ - int c, s; - long l; - - s = 0; - while((c = *(*f)++) != 0){ - if(c == '-') - s++; - else if(c != ' ' && c != '\n') - break; - } - if(c == 0) { - *p = 0; - return 0; - } - l = 0; - for(;;) { - if(c == ' ' || c == '\n') - break; - if(c < '0' || c > '9') - return 1; - l = l*10 + c-'0'; - c = *(*f)++; - } - if(s) - l = -l; - *p = l; - return 0; -} - -static int -loadzone(Tzone *tz, char *name) -{ - char buf[Tzsize*11+30], path[128], *p; - int i, f, r; - - if(strcmp(name, "local") == 0) - snprint(path, sizeof(path), "/env/timezone"); - else - snprint(path, sizeof(path), "/adm/timezone/%s", name); - memset(buf, 0, sizeof(buf)); - if((f = open(path, 0)) == -1) - return -1; - r = read(f, buf, sizeof(buf)); - close(f); - if(r == sizeof(buf) || r == -1) - return -1; - p = buf; - if(rdname(&p, tz->stname)) - return -1; - if(rdlong(&p, &tz->stdiff)) - return -1; - if(rdname(&p, tz->dlname)) - return -1; - if(rdlong(&p, &tz->dldiff)) - return -1; - for(i=0; i < Tzsize; i++) { - if(rdlong(&p, &tz->dlpairs[i])) - return -1; - if(tz->dlpairs[i] == 0) - return 0; - } - return -1; -} - -Tzone* -tmgetzone(char *tzname) -{ - Tzone *tz, **newzones; - int i; - - if(tzname == nil) - tzname = "GMT"; - qlock(&zlock); - for(i = 0; i < nzones; i++){ - tz = zones[i]; - if(strcmp(tz->stname, tzname) == 0) - goto found; - if(strcmp(tz->dlname, tzname) == 0) - goto found; - if(strcmp(tz->tzname, tzname) == 0) - goto found; - } - - tz = malloc(sizeof(Tzone)); - if(tz == nil) - goto error; - newzones = realloc(zones, (nzones + 1) * sizeof(Tzone*)); - if(newzones == nil) - goto error; - if(loadzone(tz, tzname) != 0) - goto error; - if(snprint(tz->tzname, sizeof(tz->tzname), tzname) >= sizeof(tz->tzname)){ - werrstr("timezone name too long"); - return nil; - } - zones = newzones; - zones[nzones] = tz; - nzones++; -found: - qunlock(&zlock); - return tz; -error: - free(tz); - qunlock(&zlock); - return nil; -} - -static void -getzoneoff(Tzone *tz, vlong abs, Tm *tm) -{ - long dl, *p; - dl = 0; - if(tz == nil){ - snprint(tm->zone, sizeof(tm->zone), "GMT"); - tm->tzoff = 0; - return; - } - for(p = tz->dlpairs; *p; p += 2) - if(abs >= p[0] && abs < p[1]) - dl = 1; - if(dl){ - snprint(tm->zone, sizeof(tm->zone), tz->dlname); - tm->tzoff = tz->dldiff; - }else{ - snprint(tm->zone, sizeof(tm->zone), tz->stname); - tm->tzoff = tz->stdiff; - } -} - -static Tm* -tmfill(Tm *tm, vlong abs, vlong nsec) -{ - vlong zrel, j, y, m, d, t, e; - int i; - - tm->abs = abs; - zrel = abs + tm->tzoff; - t = zrel % Daysec; - e = zrel / Daysec; - if(t < 0){ - t += Daysec; - e -= 1; - } - - t += nsec/Nsec; - tm->sec = t % 60; - t /= 60; - tm->min = t % 60; - t /= 60; - tm->hour = t; - tm->wday = (e + 4) % 7; - - /* - * Split up year, month, day. - * - * Implemented according to "Algorithm 199, - * conversions between calendar date and - * Julian day number", Robert G. Tantzen, - * Air Force Missile Development - * Center, Holloman AFB, New Mex. - * - * Lots of magic. - */ - j = (zrel + 2440588 * Daysec) / (Daysec) - 1721119; - y = (4 * j - 1) / Days400y; - j = 4 * j - 1 - Days400y * y; - d = j / 4; - j = (4 * d + 3) / Days4y; - d = 4 * d + 3 - Days4y * j; - d = (d + 4) / 4 ; - m = (5 * d - 3) / 153; - d = 5 * d - 3 - 153 * m; - d = (d + 5) / 5; - y = 100 * y + j; - - if(m < 10) - m += 3; - else{ - m -= 9; - y++; - } - - /* there's no year 0 */ - if(y <= 0) - y--; - /* and if j negative, the day and month are also negative */ - if(m < 0) - m += 12; - if(d < 0) - d += mdays[m - 1]; - - tm->yday = d; - for(i = 0; i < m - 1; i++) - tm->yday += mdays[i]; - if(m > 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) - tm->yday++; - tm->year = y - 1900; - tm->mon = m - 1; - tm->mday = d; - tm->nsec = nsec%Nsec; - return tm; -} - - -Tm* -tmtime(Tm *tm, vlong abs, Tzone *tz) -{ - return tmtimens(tm, abs, 0, tz); -} - -Tm* -tmtimens(Tm *tm, vlong abs, int ns, Tzone *tz) -{ - tm->tz = tz; - getzoneoff(tz, abs, tm); - return tmfill(tm, abs, ns); -} - -Tm* -tmnow(Tm *tm, Tzone *tz) -{ - vlong ns; - - ns = nsec(); - return tmtimens(tm, nsec()/Nsec, ns%Nsec, tz); -} - -Tm* -tmnorm(Tm *tm) -{ - vlong c, yadj, j, abs, y, m, d; - - if(tm->mon > 1){ - m = tm->mon - 2; - y = tm->year + 1900; - }else{ - m = tm->mon + 10; - y = tm->year - 1901; - } - d = tm->mday; - c = y / 100; - yadj = y - 100 * c; - j = (c * Days400y / 4 + - Days4y * yadj / 4 + - (153 * m + 2)/5 + d - - 719469); - abs = j * Daysec; - abs += tm->hour * 3600; - abs += tm->min * 60; - abs += tm->sec; - abs -= tm->tzoff; - return tmfill(tm, abs, tm->nsec); -} - -static int -τconv(Fmt *f) -{ - int depth, n, w, h, m, c0, sgn, pad, off; - char *p, *am; - Tmfmt tf; - Tm *tm; - - n = 0; - tf = va_arg(f->args, Tmfmt); - tm = tf.tm; - p = tf.fmt; - if(p == nil) - p = Ctimefmt; - while(*p){ - w = 1; - pad = 0; - while(*p == '_'){ - pad++; - p++; - } - c0 = *p++; - while(c0 && *p == c0){ - w++; - p++; - } - pad += w; - switch(c0){ - case 0: - break; - case 'Y': - switch(w){ - case 1: n += fmtprint(f, "%*d", pad, tm->year + 1900); break; - case 2: n += fmtprint(f, "%*d", pad, tm->year % 100); break; - case 4: n += fmtprint(f, "%*d", pad, tm->year + 1900); break; - default: goto badfmt; - } - break; - case 'M': - switch(w){ - case 1: n += fmtprint(f, "%*d", pad, tm->mon + 1); break; - case 2: n += fmtprint(f, "%*s%02d", pad-2, "", tm->mon + 1); break; - case 3: n += fmtprint(f, "%*.3s", pad, month[tm->mon]); break; - case 4: n += fmtprint(f, "%*s", pad, month[tm->mon]); break; - default: goto badfmt; - } - break; - case 'D': - switch(w){ - case 1: n += fmtprint(f, "%*d", pad, tm->mday); break; - case 2: n += fmtprint(f, "%*s%02d", pad-2, "", tm->mday); break; - default: goto badfmt; - } - break; - case 'W': - switch(w){ - case 1: n += fmtprint(f, "%*.3s", pad, wday[tm->wday]); break; - case 2: n += fmtprint(f, "%*s", pad, wday[tm->wday]); break; - default: goto badfmt; - } - break; - case 'H': - switch(w){ - case 1: n += fmtprint(f, "%*d", pad, tm->hour % 12); break; - case 2: n += fmtprint(f, "%*s%02d", pad-2, "", tm->hour % 12); break; - default: goto badfmt; - } - break; - case 'h': - switch(w){ - case 1: n += fmtprint(f, "%*d", pad, tm->hour); break; - case 2: n += fmtprint(f, "%*s%02d", pad-2, "", tm->hour); break; - default: goto badfmt; - } - break; - case 'm': - switch(w){ - case 1: n += fmtprint(f, "%*d", pad, tm->min); break; - case 2: n += fmtprint(f, "%*s%02d", pad-2, "", tm->min); break; - default: goto badfmt; - } - break; - case 's': - switch(w){ - case 1: n += fmtprint(f, "%*d", pad, tm->sec); break; - case 2: n += fmtprint(f, "%*s%02d", pad-2, "", tm->sec); break; - default: goto badfmt; - } - break; - case 'z': - if(w != 1) - goto badfmt; - case 'Z': - sgn = (tm->tzoff < 0) ? '-' : '+'; - off = (tm->tzoff < 0) ? -tm->tzoff : tm->tzoff; - h = off/3600; - m = (off/60)%60; - if(w < 3 && pad < 5) - pad = 5; - switch(w){ - case 1: n += fmtprint(f, "%*s%c%02d%02d", pad-5, "", sgn, h, m); break; - case 2: n += fmtprint(f, "%*s%c%02d:%02d", pad-5, "", sgn, h, m); break; - case 3: n += fmtprint(f, "%*s", pad, tm->zone); break; - } - break; - case 'A': - case 'a': - if(w != 1) - goto badfmt; - if(c0 == 'a') - am = (tm->hour < 12) ? "am" : "pm"; - else - am = (tm->hour < 12) ? "AM" : "PM"; - n += fmtprint(f, "%*s", pad, am); - break; - case '[': - depth = 1; - while(*p){ - if(*p == '[') - depth++; - if(*p == ']') - depth--; - if(*p == '\\') - p++; - if(depth == 0) - break; - fmtrune(f, *p++); - } - if(*p++ != ']') - goto badfmt; - break; - default: - n += fmtrune(f, c0); - break; - } - } - return n; -badfmt: - werrstr("garbled format %s", tf.fmt); - return -1; -} - -static int -getnum(char **ps, int maxw, int *ok) -{ - char *s, *e; - int n; - - n = 0; - e = *ps + maxw; - for(s = *ps; s != e && *s >= '0' && *s <= '9'; s++){ - n *= 10; - n += *s - '0'; - } - *ok = s != *ps; - *ps = s; - return n; -} - -static int -lookup(char **s, char **tab, int len, int *ok) -{ - int nc, i; - - *ok = 0; - for(i = 0; *tab; tab++){ - nc = (len != -1) ? len : strlen(*tab); - if(cistrncmp(*s, *tab, nc) == 0){ - *s += nc; - *ok = 1; - return i; - } - i++; - } - *ok = 0; - return -1; -} - -Tm* -tmparse(Tm *tm, char *fmt, char *str, Tzone *tz) -{ - int depth, w, c0, zs, z0, z1, ampm, zoned, sloppy, tzo, ok; - char *s, *p, *q; - Tzone *zparsed; - Tzabbrev *a; - Tzoffpair *m; - - p = fmt; - s = str; - tzo = 0; - ampm = -1; - zoned = 0; - zparsed = nil; - sloppy = 0; - /* Default all fields */ - tmtime(tm, 0, nil); - if(*p == '~'){ - sloppy = 1; - p++; - } - while(*p){ - w = 1; - c0 = *p++; - if(c0 == '?'){ - w = -1; - c0 = *p++; - } - while(*p == c0){ - if(w != -1) w++; - p++; - } - ok = 1; - switch(c0){ - case 'Y': - switch(w){ - case -1: - tm->year = getnum(&s, 4, &ok); - if(tm->year > 100) tm->year -= 1900; - break; - case 1: tm->year = getnum(&s, 4, &ok) - 1900; break; - case 2: tm->year = getnum(&s, 2, &ok); break; - case 3: - case 4: tm->year = getnum(&s, 4, &ok) - 1900; break; - default: goto badfmt; - } - break; - case 'M': - switch(w){ - case -1: - tm->mon = getnum(&s, 2, &ok) - 1; - if(!ok) tm->mon = lookup(&s, month, -1, &ok); - if(!ok) tm->mon = lookup(&s, month, 3, &ok); - break; - case 1: - case 2: tm->mon = getnum(&s, 2, &ok) - 1; break; - case 3: tm->mon = lookup(&s, month, 3, &ok); break; - case 4: tm->mon = lookup(&s, month, -1, &ok); break; - default: goto badfmt; - } - break; - case 'D': - switch(w){ - case -1: - case 1: - case 2: tm->mday = getnum(&s, 2, &ok); break; - default: goto badfmt; - } - break; - case 'W': - switch(w){ - case -1: - tm->wday = lookup(&s, wday, -1, &ok); - if(!ok) tm->wday = lookup(&s, wday, 3, &ok); - break; - case 1: tm->wday = lookup(&s, wday, 3, &ok); break; - case 2: tm->wday = lookup(&s, wday, -1, &ok); break; - default: goto badfmt; - } - break; - case 'h': - switch(w){ - case -1: - case 1: - case 2: tm->hour = getnum(&s, 2, &ok); break; - default: goto badfmt; - } - break; - case 'm': - switch(w){ - case -1: - case 1: - case 2: tm->min = getnum(&s, 2, &ok); break; - default: goto badfmt; - } - break; - case 's': - switch(w){ - case -1: - case 1: - case 2: tm->sec = getnum(&s, 2, &ok); break; - default: goto badfmt; - } - break; - case 'z': - if(w != 1) - goto badfmt; - case 'Z': - zs = 0; - zoned = 1; - switch(*s++){ - case '+': zs = 1; break; - case '-': zs = -1; break; - default: s--; break; - } - switch(w){ - case -1: - case 3: - for(a = tzabbrev; a->abbr; a++) - if(strncmp(s, a->abbr, strlen(a->abbr)) == 0) - break; - if(a->abbr != nil){ - s += strlen(a->abbr); - zparsed = tmgetzone(a->name); - if(zparsed == nil){ - werrstr("unloadable zone %s (%s)", a->abbr, a->name); - return nil; - } - break; - } - for(m = milabbrev; m->abbr != nil; m++) - if(strncmp(s, m->abbr, strlen(m->abbr)) == 0) - break; - if(m->abbr != nil){ - snprint(tm->zone, sizeof(tm->zone), "%s", m->abbr); - tzo = m->off; - break; - } - /* fall through */ - case 1: - /* offset: [+-]hhmm */ - q = s; - z0 = getnum(&s, 4, &ok); - if(s - q == 4){ - z1 = z0 % 100; - if(z0/100 > 13 || z1 >= 60) - goto baddate; - tzo = zs*(3600*z0/100 + 60*z1); - snprint(tm->zone, sizeof(tm->zone), "%c%02d%02d", zs<0?'-':'+', z0/100, z1); - break; - } - if(w != -1) - goto baddate; - s = q; - /* fall through */ - case 2: - /* offset: [+-]hh:mm */ - z0 = getnum(&s, 2, &ok); - if(*s++ != ':') - goto baddate; - z1 = getnum(&s, 2, &ok); - if(z1 > 60) - goto baddate; - tzo = zs*(3600*z0 + 60*z1); - snprint(tm->zone, sizeof(tm->zone), "%c%d02:%02d", zs<0?'-':'+', z0, z1); - break; - } - break; - case 'A': - case 'a': - if(cistrncmp(s, "am", 2) == 0) - ampm = 0; - else if(cistrncmp(s, "pm", 2) == 0) - ampm = 1; - else - goto baddate; - break; - case '[': - depth = 1; - while(*p){ - if(*p == '[') - depth++; - if(*p == ']') - depth--; - if(*p == '\\') - p++; - if(depth == 0) - break; - if(*s == 0) - goto baddate; - if(*s++ != *p++) - goto baddate; - } - if(*p != ']') - goto badfmt; - p++; - break; - case ',': - case ' ': - case '\t': - if(*s != ' ' && *s != '\t' && *s != ',') - goto baddate; - while(*p == ' ' || *p == '\t' || *p == ',') - p++; - while(*s == ' ' || *s == '\t' || *s == ',') - s++; - break; - default: - if(*s == 0) - goto baddate; - if(*s++ != c0) - goto baddate; - break; - } - if(!ok) - goto baddate; - } - - if(!sloppy && ampm != -1 && tm->hour > 12) - goto baddate; - if(ampm == 1) - tm->hour += 12; - /* - * If we're allowing sloppy date ranges, - * we'll normalize out of range values. - */ - if(!sloppy){ - if(tm->yday < 0 && tm->yday > 365 + isleap(tm->year + 1900)) - goto baddate; - if(tm->wday < 0 && tm->wday > 6) - goto baddate; - if(tm->mon < 0 || tm->mon > 11) - goto baddate; - if(tm->mday < 0 || tm->mday > mdays[tm->mon]) - goto baddate; - if(tm->hour < 0 || tm->hour > 24) - goto baddate; - if(tm->min < 0 || tm->min > 59) - goto baddate; - if(tm->sec < 0 || tm->sec > 60) - goto baddate; - if(tm->nsec < 0 || tm->nsec > Nsec) - goto baddate; - } - - /* - * Normalizing gives us the local time, - * but because we havnen't applied the - * timezone, we think we're GMT. So, we - * need to shift backwards. Then, we move - * the "GMT that was local" back to local - * time. - */ - tmnorm(tm); - tm->tzoff = tzo; - if(!zoned) - getzoneoff(tz, tm->abs, tm); - else if(zparsed != nil) - getzoneoff(zparsed, tm->abs, tm); - tm->abs -= tm->tzoff; - if(tz != nil || !zoned) - tmtime(tm, tm->abs, tz); - return tm; -baddate: - werrstr("invalid date %s near '%s'", str, s); - return nil; -badfmt: - werrstr("garbled format %s near '%s'", fmt, p); - return nil; -} - -Tmfmt -tmfmt(Tm *d, char *fmt) -{ - return (Tmfmt){fmt, d}; -} - -void -tmfmtinstall(void) -{ - fmtinstall(L'τ', τconv); -} - -/* These legacy functions need access to τconv */ -static char* -dotmfmt(Fmt *f, ...) -{ - static char buf[30]; - va_list ap; - - va_start(ap, f); - f->runes = 0; - f->start = buf; - f->to = buf; - f->stop = buf + sizeof(buf) - 1; - f->flush = nil; - f->farg = nil; - f->nfmt = 0; - f->args = ap; - τconv(f); - va_end(ap); - buf[sizeof(buf) - 1] = 0; - return buf; -} - -char* -asctime(Tm* tm) -{ - Tmfmt tf; - Fmt f; - - tf = tmfmt(tm, nil); - return dotmfmt(&f, tf); -} diff --git a/sys/src/libc/port/mkfile b/sys/src/libc/port/mkfile index 11aec6989..402990422 100644 --- a/sys/src/libc/port/mkfile +++ b/sys/src/libc/port/mkfile @@ -20,7 +20,6 @@ CFILES=\ cleanname.c\ crypt.c\ ctype.c\ - date.c\ encodefmt.c\ execl.c\ exits.c\ |