forsyth20121205-174063a80cc13 years agoHistory
511 lines · 9.2 KB · Brainfuck
RawDownload
implement Daytime;## These routines convert time as follows:## The epoch is 0000 Jan 1 1970 GMT.# The argument time is in microseconds since then.# The local(t) entry returns a reference to an ADT# containing##	seconds (0-59)#	minutes (0-59)#	hours (0-23)#	day of month (1-31)#	month (0-11)#	year-1900#	weekday (0-6, Sun is 0)#	day of the year#	daylight savings flag## The routine gets the daylight savings time from the file /locale/timezone.## text(tvec)# where tvec is produced by local# returns a string that has the time in the form##	Thu Jan 01 00:00:00 GMT 1970n0#	012345678901234567890123456789#	0	  1	    2## time() just reads the time from /dev/time# and then calls localtime, then asctime.## The sign bit of second times will turn on 68 years from the epoch ->2038#include	"sys.m";include	"string.m";include "daytime.m"; S: String;sys: Sys; dmsize := array[] of {	31, 28, 31, 30, 31, 30,	31, 31, 30, 31, 30, 31};ldmsize := array[] of {	31, 29, 31, 30, 31, 30,	31, 31, 30, 31, 30, 31}; Timezone: adt{	stname: string;	dlname: string;	stdiff:	int;	dldiff: int;	dlpairs: array of int;}; timezone: ref Timezone; now(): int{	if(sys == nil)		sys = load Sys Sys->PATH; 	fd := sys->open("/dev/time", sys->OREAD);	if(fd == nil)		return 0;	buf := array[128] of byte;	n := sys->read(fd, buf, len buf);	if(n < 0)		return 0; 	t := (big string buf[0:n]) / big 1000000;	return int t;} time(): string{	t := now();	tm := local(t);	return text(tm);} local(tim: int): ref Tm{	ct: ref Tm; 	if(timezone == nil)		timezone = readtimezone(nil); 	t := tim + timezone.stdiff;	dlflag := 0;	for(i := 0; i+1 < len timezone.dlpairs; i += 2) {		if(t >= timezone.dlpairs[i] && t < timezone.dlpairs[i+1]) {			t = tim + timezone.dldiff;			dlflag++;			break;		}	}	ct = gmt(t);	if(dlflag) {		ct.zone = timezone.dlname;		ct.tzoff = timezone.dldiff;	}	else {		ct.zone = timezone.stname;		ct.tzoff = timezone.stdiff;	}	return ct;} gmt(tim: int): ref Tm{	xtime := ref Tm; 	# break initial number into days	hms := tim % 86400;	day := tim / 86400;	if(hms < 0) {		hms += 86400;		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 + 7340036) % 7; 	# year number	if(day >= 0)		for(d1 = 70; day >= dysize(d1+1900); d1++)			day -= dysize(d1+1900);	else		for (d1 = 70; day < 0; d1--)			day += dysize(d1+1900-1);	xtime.year = d1;	d0 := day;	xtime.yday = d0; 	# generate month	if(dysize(d1+1900) == 366)		dmsz := ldmsize;	else		dmsz = dmsize;	for(d1 = 0; d0 >= dmsz[d1]; d1++)		d0 -= dmsz[d1];	xtime.mday = d0 + 1;	xtime.mon = d1;	xtime.zone = "GMT";	xtime.tzoff = 0;	return xtime;} wkday := array[] of {	"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; weekday := array[] of {	"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; month := array[] of {	"Jan", "Feb", "Mar", "Apr", "May", "Jun",	"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; text(t: ref Tm): string{	if(sys == nil)		sys = load Sys Sys->PATH; 	year := 1900+t.year; 	return sys->sprint("%s %s %.2d %.2d:%.2d:%.2d %s %d",		wkday[t.wday],		month[t.mon],		t.mday,		t.hour,		t.min,		t.sec,		t.zone,		year);} filet(now: int, file: int): string{	if(sys == nil)		sys = load Sys Sys->PATH; 	t := local(file);	if(now - file < 6*30*24*3600)		return sys->sprint("%s %.2d %.2d:%.2d",			month[t.mon], t.mday, t.hour, t.min); 	year := 1900+t.year; 	return sys->sprint("%s %.2d  %d", month[t.mon], t.mday, year);} dysize(y: int): int{	if(y%4 == 0 && (y%100 != 0 || y%400 == 0))		return 366;	return 365;} readtimezone(fname: string): ref Timezone{	if(sys == nil)		sys = load Sys Sys->PATH; 	tz := ref Timezone;	tz.stdiff = 0;	tz.stname = "GMT"; 	s: string;	if(fname == nil){		s = readfile("/env/timezone");		if(s == nil)			s = readfile("/locale/timezone");	}else{		if(fname[0] != '/' && fname[0] != '#')			fname = "/locale/" + fname;		s = readfile(fname);	}	if(s == nil)		return tz;	if(s[0] == '/' || s[0] == '#'){		if(s[len s-1] == '\n')			s = s[0: len s-1];		s = readfile(s);		if(s == nil)			return tz;	}	(n, val) := sys->tokenize(s, "\t \n\r");	if(n < 4)		return tz; 	tz.stname = hd val;	val = tl val;	tz.stdiff = int hd val;	val = tl val;	tz.dlname = hd val;	val = tl val;	tz.dldiff = int hd val;	val = tl val; 	tz.dlpairs = array[n-4] of {* => 0};	for(j := 0; val != nil; val = tl val)		tz.dlpairs[j++] = int hd val;	return tz;} readfile(name: string): string{	fd := sys->open(name, Sys->OREAD);	if(fd == nil)		return nil;	buf := array[2048] of byte;	n := sys->read(fd, buf, len buf);	if(n <= 0)		return nil;	return string buf[0:n];} SEC2MIN:	con 60;SEC2HOUR:	con 60*SEC2MIN;SEC2DAY:	con 24*SEC2HOUR; tm2epoch(tm: ref Tm): int{	secs := 0; 	#	#  seconds per year	#	yr := tm.year + 1900;	if(yr < 1970)		for(i := yr; i < 1970; i++)			secs -= dysize(i) * SEC2DAY;	else		for(i = 1970; i < yr; i++)			secs += dysize(i) * SEC2DAY;	#	#  seconds per month	#	if(dysize(yr) == 366)		dmsz := ldmsize;	else		dmsz = dmsize;	for(i = 0; i < tm.mon; i++)		secs += dmsz[i] * SEC2DAY; 	#	# secs in last month	#	secs += (tm.mday-1) * SEC2DAY; 	#	# hours, minutes, seconds	#	secs += tm.hour * SEC2HOUR;	secs += tm.min * SEC2MIN;	secs += tm.sec; 	#	#  time zone offset includes daylight savings time	#	return secs - tm.tzoff;} # handle three formats (we'll be a bit more tolerant)#  Sun, 06 Nov 1994 08:49:37 TZ  (rfc822+rfc1123)#  Sunday, 06-Nov-94 08:49:37 TZ (rfc850, obsoleted by rfc1036)#  Sun Nov  6 08:49:37 1994	 (ANSI C's asctime() format, assume GMT)## return nil on parsing error#string2tm(date: string): ref Tm{	buf: string;	ok: int;	tm := ref Tm; 	if(S == nil)		S = load String String->PATH; 	# Weekday|Wday	(date, buf) = dateword(date);	tm.wday = strlookup(wkday, buf);	if(tm.wday < 0)		tm.wday = strlookup(weekday, buf);	if(tm.wday < 0)		return nil; 	# Try Mon	odate := date;	(date, buf) = dateword(date);	tm.mon = strlookup(month, buf);	if(tm.mon >= 0) {		# Mon was OK, so asctime() format		# DD		(date, tm.mday) = datenum(date);		if(tm.mday < 1 || tm.mday > 31)			return nil; 		# HH:MM:SS		(ok, date) = hhmmss(date, tm);		if(!ok)			return nil; 		# optional time zone		while(date != nil && date[0] == ' ')			date = date[1:];		if(date != nil && !(date[0] >= '0' && date[0] <= '9')){			for(i := 0; i < len date; i++)				if(date[i] == ' '){					(tm.zone, tm.tzoff) = tzinfo(date[0: i]);					date = date[i:];					break;				}		} 		# YY|YYYY		(nil, tm.year) = datenum(date);		if(tm.year > 1900)			tm.year -= 1900;		if(tm.zone == ""){			tm.zone = "GMT";			tm.tzoff = 0;		}	} else {		# Mon was not OK		date = odate;		# DD Mon YYYY or DD-Mon-(YY|YYYY)		(date, tm.mday) = datenum(date);		if(tm.mday < 1 || tm.mday > 31)			return nil;		(date, buf) = dateword(date);		tm.mon = strlookup(month, buf);		if(tm.mon < 0 || tm.mon >= 12)			return nil;		(date, tm.year) = datenum(date);		if(tm.year > 1900)			tm.year -= 1900; 		# HH:MM:SS		(ok, buf) = hhmmss(date, tm);		if(!ok)			return nil;		(tm.zone, tm.tzoff) = tzinfo(buf);		if(tm.zone == "")			return nil;	} 	return tm;} dateword(date: string): (string, string){	notalnum: con "^A-Za-z0-9"; 	date = S->drop(date, notalnum);	(w, rest) := S->splitl(date, notalnum);	return (rest, w);} datenum(date: string): (string, int){	notdig: con "^0-9"; 	date = S->drop(date, notdig);	(num, rest) := S->splitl(date, notdig);	return (rest, int num);} strlookup(a: array of string, s: string): int{	n := len a;	for(i := 0; i < n; i++) {		if(s == a[i])			return i;	}	return -1;} hhmmss(date: string, tm: ref Tm): (int, string){	err := (0, ""); 	(date, tm.hour) = datenum(date);	if(tm.hour < 0 || tm.hour >= 24)		return err;	(date, tm.min) = datenum(date);	if(tm.min < 0 || tm.min >= 60)		return err;	(date, tm.sec) = datenum(date);	if(tm.sec < 0 || tm.sec >= 60)		return err; 	return (1, date);} tzinfo(tz: string): (string, int){	# strip leading and trailing whitespace	WS: con " \t";	tz = S->drop(tz, WS);	for(n := len tz; n > 0; n--) {		if(S->in(tz[n-1], WS) == 0)			break;	}	if(n < len tz)		tz = tz[:n]; 	# if no timezone, default to GMT	if(tz == nil)		return ("GMT", 0); 	# GMT aliases	case tz {	"GMT" or	"UT" or	"UTC" or	"Z" =>		return ("GMT", 0);	} 	# [+-]hhmm (hours and minutes offset from GMT)	if(len tz == 5 && (tz[0] == '+' || tz[0] == '-')) {		h := int tz[1:3];		m := int tz[3:5];		if(h > 23 || m > 59)			return ("", 0);		tzoff := h*SEC2HOUR + m*SEC2MIN;		if(tz[0] == '-')			tzoff = -tzoff;		return ("GMT", tzoff);	} 	# try continental US timezones	filename: string;	case tz {	"CST" or "CDT" =>		filename = "CST.CDT";	"EST" or "EDT" =>		filename = "EST.EDT";	"MST" or "MDT" =>		filename = "MST.MDT";	"PST" or "PDT" =>		filename = "PST.PDT";

Lines 1–500 of 511.