aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lib9/ctime.c157
-rw-r--r--src/lib9/date.c100
-rw-r--r--src/lib9/mkfile4
-rw-r--r--src/lib9/opentemp.c16
-rw-r--r--src/lib9/tm2sec.c110
-rw-r--r--src/lib9/zoneinfo.c215
-rw-r--r--src/lib9/zoneinfo.h19
7 files changed, 498 insertions, 123 deletions
diff --git a/src/lib9/ctime.c b/src/lib9/ctime.c
index 0782d099..c5e11569 100644
--- a/src/lib9/ctime.c
+++ b/src/lib9/ctime.c
@@ -1,21 +1,135 @@
+/*
+ * This routine converts time as follows.
+ * The epoch is 0000 Jan 1 1970 GMT.
+ * The argument time is in seconds since then.
+ * The localtime(t) entry returns a pointer to an array
+ * containing
+ *
+ * seconds (0-59)
+ * minutes (0-59)
+ * hours (0-23)
+ * day of month (1-31)
+ * month (0-11)
+ * year-1970
+ * weekday (0-6, Sun is 0)
+ * day of the year
+ * daylight savings flag
+ *
+ * The routine gets the daylight savings time from the environment.
+ *
+ * asctime(tvec))
+ * where tvec is produced by localtime
+ * returns a ptr to a character string
+ * that has the ascii time in the form
+ *
+ * \\
+ * Thu Jan 01 00:00:00 GMT 1970n0
+ * 012345678901234567890123456789
+ * 0 1 2
+ *
+ * ctime(t) just calls localtime, then asctime.
+ */
+
#include <u.h>
#include <libc.h>
-static
-void
-ct_numb(char *cp, int n)
+#include "zoneinfo.h"
+
+static char dmsize[12] =
{
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
- cp[0] = ' ';
- if(n >= 10)
- cp[0] = (n/10)%10 + '0';
- cp[1] = n%10 + '0';
+#define dysize ctimedysize
+static int dysize(int);
+static void ct_numb(char*, int);
+
+char*
+ctime(long t)
+{
+ return asctime(localtime(t));
+}
+
+Tm*
+localtime(long tim)
+{
+ Tinfo ti;
+ Tm *ct;
+
+ if (zonelookuptinfo(&ti, tim)!=-1) {
+ ct = gmtime(tim+ti.tzoff);
+ strncpy(ct->zone, ti.zone, sizeof ct->zone);
+ ct->zone[sizeof ct->zone-1] = 0;
+ ct->tzoff = ti.tzoff;
+ return ct;
+ }
+ return gmtime(tim);
+}
+
+Tm*
+gmtime(long tim)
+{
+ 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*
asctime(Tm *t)
{
- int i;
char *ncp;
static char cbuf[30];
@@ -33,12 +147,6 @@ asctime(Tm *t)
ct_numb(cbuf+14, t->min+100);
ct_numb(cbuf+17, t->sec+100);
ncp = t->zone;
- for(i=0; i<3; i++)
- if(ncp[i] == 0)
- break;
- for(; i<3; i++)
- ncp[i] = '?';
- ncp = t->zone;
cbuf[20] = *ncp++;
cbuf[21] = *ncp++;
cbuf[22] = *ncp;
@@ -50,9 +158,24 @@ asctime(Tm *t)
return cbuf;
}
-char*
-ctime(long t)
+static
+int
+dysize(int y)
{
- return asctime(localtime(t));
+
+ 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';
}
diff --git a/src/lib9/date.c b/src/lib9/date.c
deleted file mode 100644
index 8509bb48..00000000
--- a/src/lib9/date.c
+++ /dev/null
@@ -1,100 +0,0 @@
-#define NOPLAN9DEFINES
-#include <u.h>
-#include <libc.h>
-#include <stdlib.h> /* setenv etc. */
-#include <time.h>
-
-static int
-dotz(time_t t, char *tzone)
-{
- struct tm *gtm;
- struct tm tm;
-
- strftime(tzone, 32, "%Z", localtime(&t));
- tm = *localtime(&t); /* set local time zone field */
- gtm = gmtime(&t);
- tm.tm_sec = gtm->tm_sec;
- tm.tm_min = gtm->tm_min;
- tm.tm_hour = gtm->tm_hour;
- tm.tm_mday = gtm->tm_mday;
- tm.tm_mon = gtm->tm_mon;
- tm.tm_year = gtm->tm_year;
- tm.tm_wday = gtm->tm_wday;
- return t - mktime(&tm);
-}
-
-static void
-tm2Tm(struct tm *tm, Tm *bigtm, int tzoff, char *zone)
-{
- memset(bigtm, 0, sizeof *bigtm);
- bigtm->sec = tm->tm_sec;
- bigtm->min = tm->tm_min;
- bigtm->hour = tm->tm_hour;
- bigtm->mday = tm->tm_mday;
- bigtm->mon = tm->tm_mon;
- bigtm->year = tm->tm_year;
- bigtm->wday = tm->tm_wday;
- bigtm->tzoff = tzoff;
- strncpy(bigtm->zone, zone, 3);
- bigtm->zone[3] = 0;
-}
-
-static void
-Tm2tm(Tm *bigtm, struct tm *tm)
-{
- /* initialize with current time to get local time zone! (tm_isdst) */
- time_t t;
- time(&t);
- *tm = *localtime(&t);
-
- tm->tm_sec = bigtm->sec;
- tm->tm_min = bigtm->min;
- tm->tm_hour = bigtm->hour;
- tm->tm_mday = bigtm->mday;
- tm->tm_mon = bigtm->mon;
- tm->tm_year = bigtm->year;
- tm->tm_wday = bigtm->wday;
-}
-
-Tm*
-p9gmtime(long x)
-{
- time_t t;
- struct tm tm;
- static Tm bigtm;
-
- t = (time_t)x;
- tm = *gmtime(&t);
- tm2Tm(&tm, &bigtm, 0, "GMT");
- return &bigtm;
-}
-
-Tm*
-p9localtime(long x)
-{
- time_t t;
- struct tm tm;
- static Tm bigtm;
- char tzone[32];
-
- t = (time_t)x;
- tm = *localtime(&t);
- tm2Tm(&tm, &bigtm, dotz(t, tzone), tzone);
- return &bigtm;
-}
-
-long
-p9tm2sec(Tm *bigtm)
-{
- time_t t;
- struct tm tm;
- char tzone[32];
-
- Tm2tm(bigtm, &tm);
- t = mktime(&tm);
- if(strcmp(bigtm->zone, "GMT") == 0 || strcmp(bigtm->zone, "UCT") == 0){
- t += dotz(t, tzone);
- }
- return t;
-}
-
diff --git a/src/lib9/mkfile b/src/lib9/mkfile
index 782dd274..4bbd0f8b 100644
--- a/src/lib9/mkfile
+++ b/src/lib9/mkfile
@@ -88,7 +88,6 @@ LIB9OFILES=\
create.$O\
crypt.$O\
ctime.$O\
- date.$O\
dial.$O\
dirfstat.$O\
dirfwstat.$O\
@@ -149,6 +148,7 @@ LIB9OFILES=\
syslog.$O\
sysname.$O\
time.$O\
+ tm2sec.$O\
tokenize.$O\
truerand.$O\
u16.$O\
@@ -158,6 +158,7 @@ LIB9OFILES=\
wait.$O\
waitpid.$O\
write.$O\
+ zoneinfo.$O\
OFILES=\
$LIB9OFILES\
@@ -193,3 +194,4 @@ testgoogfmt: testfltfmt.$O googfmt.$O $XLIB
testgoogprint: testprint.$O googfmt.$O $XLIB
$LD -o $target testprint.$O googfmt.$O
+ctime.$O tm2sec.$O zoneinfo.$O: zoneinfo.h
diff --git a/src/lib9/opentemp.c b/src/lib9/opentemp.c
index f90bf771..0af154de 100644
--- a/src/lib9/opentemp.c
+++ b/src/lib9/opentemp.c
@@ -2,14 +2,20 @@
#include <libc.h>
int
-opentemp(char *template)
+opentemp(char *template, int mode)
{
- int fd;
+ int fd, fd1;
fd = mkstemp(template);
if(fd < 0)
return -1;
- remove(template);
- return fd;
+ /* reopen for mode */
+ fd1 = open(template, mode);
+ if(fd1 < 0){
+ close(fd);
+ remove(template);
+ return -1;
+ }
+ close(fd);
+ return fd1;
}
-
diff --git a/src/lib9/tm2sec.c b/src/lib9/tm2sec.c
new file mode 100644
index 00000000..5edf439d
--- /dev/null
+++ b/src/lib9/tm2sec.c
@@ -0,0 +1,110 @@
+#include <u.h>
+#include <libc.h>
+
+#include "zoneinfo.h"
+
+#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)
+{
+ Tinfo ti0, ti1, *ti;
+ long secs;
+ int i, yday, year, *d2m;
+
+ 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;
+
+ /*
+ * Assume the local time zone if zone is not GMT
+ */
+ if(strcmp(tm->zone, "GMT") != 0) {
+ i = zonelookuptinfo(&ti0, secs);
+ ti = &ti0;
+ if (i != -1)
+ if (ti->tzoff!=0) {
+ /*
+ * to what local time period `secs' belongs?
+ */
+ if (ti->tzoff>0) {
+ /*
+ * east of GMT; check previous local time transition
+ */
+ if (ti->t+ti->tzoff > secs)
+ if (zonetinfo(&ti1, i-1)!=-1)
+ ti = &ti1;
+ } else
+ /*
+ * west of GMT; check next local time transition
+ */
+ if (zonetinfo(&ti1, i+1))
+ if (ti1.t+ti->tzoff < secs)
+ ti = &ti1;
+// fprint(2, "tt: %ld+%d %ld\n", (long)ti->t, ti->tzoff, (long)secs);
+ secs -= ti->tzoff;
+ }
+ }
+
+ if(secs < 0)
+ secs = 0;
+ return secs;
+}
diff --git a/src/lib9/zoneinfo.c b/src/lib9/zoneinfo.c
new file mode 100644
index 00000000..f49d8120
--- /dev/null
+++ b/src/lib9/zoneinfo.c
@@ -0,0 +1,215 @@
+#include <u.h>
+#include <libc.h>
+
+/*
+ * Access local time entries of zoneinfo files.
+ * Formats 0 and 2 are supported, and 4-byte timestamps
+ *
+ * Copyright © 2008 M. Teichgräber
+ * Contributed under the terms of the Lucent Public License 1.02.
+ */
+#include "zoneinfo.h"
+
+static
+struct Zoneinfo
+{
+ int timecnt; /* # of transition times */
+ int typecnt; /* # of local time types */
+ int charcnt; /* # of characters of time zone abbreviation strings */
+
+ uchar *ptime;
+ uchar *ptype;
+ uchar *ptt;
+ uchar *pzone;
+} z;
+
+static uchar *tzdata;
+
+static
+uchar*
+readtzfile(char *file)
+{
+ uchar *p;
+ int fd;
+ Dir *d;
+
+ fd = open(file, OREAD);
+ if (fd<0)
+ return nil;
+ d = dirfstat(fd);
+ if (d==nil)
+ return nil;
+ p = malloc(d->length);
+ if (p!=nil)
+ readn(fd, p, d->length);
+ free(d);
+ close(fd);
+ return p;
+}
+static char *zonefile;
+void
+tzfile(char *f)
+{
+ if (tzdata!=nil) {
+ free(tzdata);
+ tzdata = nil;
+ }
+ z.timecnt = 0;
+ zonefile = f;
+}
+
+static
+long
+get4(uchar *p)
+{
+ return (p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3];
+}
+
+enum {
+ TTinfosz = 4+1+1,
+};
+
+static
+int
+parsehead(void)
+{
+ uchar *p;
+ int ver;
+
+ ver = tzdata[4];
+ if (ver!=0)
+ if (ver!='2')
+ return -1;
+
+ p = tzdata + 4 + 1 + 15;
+
+ z.timecnt = get4(p+3*4);
+ z.typecnt = get4(p+4*4);
+ if (z.typecnt==0)
+ return -1;
+ z.charcnt = get4(p+5*4);
+ z.ptime = p+6*4;
+ z.ptype = z.ptime + z.timecnt*4;
+ z.ptt = z.ptype + z.timecnt;
+ z.pzone = z.ptt + z.typecnt*TTinfosz;
+ return 0;
+}
+
+static
+void
+ttinfo(Tinfo *ti, int tti)
+{
+ uchar *p;
+ int i;
+
+ i = z.ptype[tti];
+ assert(i<z.typecnt);
+ p = z.ptt + i*TTinfosz;
+ ti->tzoff = get4(p);
+ ti->dlflag = p[4];
+ assert(p[5]<z.charcnt);
+ ti->zone = (char*)z.pzone + p[5];
+}
+
+static
+void
+readtimezone(void)
+{
+ char *tmp;
+
+ z.timecnt = 0;
+ switch (zonefile==nil) {
+ default:
+ if ((tmp=getenv("timezone"))!=nil) {
+ tzdata = readtzfile(tmp);
+ free(tmp);
+ break;
+ }
+ zonefile = "/etc/localtime";
+ /* fall through */
+ case 0:
+ tzdata = readtzfile(zonefile);
+ }
+ if (tzdata==nil)
+ return;
+
+ if (strncmp("TZif", (char*)tzdata, 4)!=0)
+ goto errfree;
+
+ if (parsehead()==-1) {
+ errfree:
+ free(tzdata);
+ tzdata = nil;
+ z.timecnt = 0;
+ return;
+ }
+}
+
+static
+tlong
+gett4(uchar *p)
+{
+ long l;
+
+ l = get4(p);
+ if (l<0)
+ return 0;
+ return l;
+}
+int
+zonetinfo(Tinfo *ti, int i)
+{
+ if (tzdata==nil)
+ readtimezone();
+ if (i<0 || i>=z.timecnt)
+ return -1;
+ ti->t = gett4(z.ptime + 4*i);
+ ttinfo(ti, i);
+ return i;
+}
+
+int
+zonelookuptinfo(Tinfo *ti, tlong t)
+{
+ uchar *p;
+ int i;
+ tlong oldtt, tt;
+
+ if (tzdata==nil)
+ readtimezone();
+ oldtt = 0;
+ p = z.ptime;
+ for (i=0; i<z.timecnt; i++) {
+ tt = gett4(p);
+ if (t<tt)
+ break;
+ oldtt = tt;
+ p += 4;
+ }
+ if (i>0) {
+ ttinfo(ti, i-1);
+ ti->t = oldtt;
+// fprint(2, "t:%ld off:%d dflag:%d %s\n", (long)ti->t, ti->tzoff, ti->dlflag, ti->zone);
+ return i-1;
+ }
+ return -1;
+}
+
+void
+zonedump(int fd)
+{
+ int i;
+ uchar *p;
+ tlong t;
+ Tinfo ti;
+
+ if (tzdata==nil)
+ readtimezone();
+ p = z.ptime;
+ for (i=0; i<z.timecnt; i++) {
+ t = gett4(p);
+ ttinfo(&ti, i);
+ fprint(fd, "%ld\t%d\t%d\t%s\n", (long)t, ti.tzoff, ti.dlflag, ti.zone);
+ p += 4;
+ }
+}
diff --git a/src/lib9/zoneinfo.h b/src/lib9/zoneinfo.h
new file mode 100644
index 00000000..55e60df9
--- /dev/null
+++ b/src/lib9/zoneinfo.h
@@ -0,0 +1,19 @@
+#define zonetinfo _p9zonetinfo
+#define zonedump _p9zonedump
+#define zonelookuptinfo _p9zonelookuptinfo
+
+typedef long tlong;
+
+typedef
+struct Tinfo
+{
+ long t;
+ int tzoff;
+ int dlflag;
+ char *zone;
+} Tinfo;
+
+extern int zonelookuptinfo(Tinfo*, tlong);
+extern int zonetinfo(Tinfo*, int);
+extern void zonedump(int fd);
+