Commit Diff


commit - 1cccddd6b3fb4a90641b8d05dc0bed618380074c
commit + f35a04866f298aa4b0fa6846da0c0187751ce9b2
blob - 0782d099feacdb1a59f797fa707967543f57c28a
blob + c5e115690a1855c9e2530eb95074c96739aade14
--- src/lib9/ctime.c
+++ 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';
+}
+
blob - 8509bb484c5e56af4e36bc768fb8b393c634125d (mode 644)
blob + /dev/null
--- 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;
-}
-
blob - 782dd274169a6e375b368e9cee31b2c77929cef6
blob + 4bbd0f8b57a3cf4a5dd4214962fd60a833e7b5a0
--- src/lib9/mkfile
+++ 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
blob - f90bf771b67e5a0b18c94065c930368dd3f9c236
blob + 0af154de255fc97f12a8adbb1a9e8198338efaad
--- src/lib9/opentemp.c
+++ 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;
 }
-
blob - /dev/null
blob + 5edf439d1a5a882081b293f64a78aa71d1a1a61e (mode 644)
--- /dev/null
+++ 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;
+}
blob - /dev/null
blob + f49d8120c68c64f6365b769737d2ea968f0e1b3b (mode 644)
--- /dev/null
+++ 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;
+	}
+}
blob - /dev/null
blob + 55e60df9f1f3558a65169463a895278dab698fda (mode 644)
--- /dev/null
+++ 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);
+