plan9port/src/lib9/zoneinfo.c
Russ Cox 88a87fadae all: update for new MIT license
On March 23, 2021, Nokia transferred the copyrights in the Plan 9 software
to the Plan 9 Foundation, which relicensed them under the MIT license.

This commit updates the Plan 9 from User Space license to reflect the
new base license. The vast majority of the contributions beyond the
base Plan 9 set were by me, many of them explicitly under an MIT license.
Those are all under the new MIT license now as well.

The port of mk to Unix was taken from Inferno via Vita Nuova and had
been made available under GPL, but Vita Nuova has relicensed Inferno
under the MIT license as well, to match the new Plan 9 license.

Michael Teichgraber contributed src/lib9/zoneinfo.c explicitly under
the Lucent Public License but has agreed to change the contribution
to the MIT license now used in the rest of the distribution.

There remain a few exceptions, most notably fonts.
See the root LICENSE file for full details.

The only mention of the Lucent Public License in the whole tree now
is in the LICENSE file, explaining the history.
2021-03-23 20:59:23 -04:00

213 lines
3 KiB
C

#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 MIT license used in the rest of the distribution.
*/
#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;
if(zonefile==nil) {
if ((tmp=getenv("timezone"))!=nil) {
tzdata = readtzfile(tmp);
free(tmp);
goto havedata;
}
zonefile = "/etc/localtime";
}
tzdata = readtzfile(zonefile);
if (tzdata==nil)
return;
havedata:
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;
}
}