zoneinfo.c - 9base - revived minimalist port of Plan 9 userland to Unix
 (HTM) git clone git://git.suckless.org/9base
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       zoneinfo.c (3092B)
       ---
            1 #include <u.h>
            2 #include <libc.h>
            3 
            4 /*
            5  * Access local time entries of zoneinfo files.
            6  * Formats 0 and 2 are supported, and 4-byte timestamps
            7  * 
            8  * Copyright © 2008 M. Teichgräber
            9  * Contributed under the terms of the Lucent Public License 1.02.
           10  */
           11 #include "zoneinfo.h"
           12 
           13 static
           14 struct Zoneinfo
           15 {
           16         int        timecnt;                /* # of transition times */
           17         int        typecnt;                /* # of local time types */
           18         int        charcnt;                /* # of characters of time zone abbreviation strings */
           19 
           20         uchar *ptime;
           21         uchar *ptype;
           22         uchar *ptt;
           23         uchar *pzone;
           24 } z;
           25 
           26 static uchar *tzdata;
           27 
           28 static
           29 uchar*
           30 readtzfile(char *file)
           31 {
           32         uchar *p;
           33         int fd;
           34         Dir *d;
           35 
           36         fd = open(file, OREAD);
           37         if (fd<0)
           38                 return nil;
           39         d = dirfstat(fd);
           40         if (d==nil)
           41                 return nil;
           42         p = malloc(d->length);
           43         if (p!=nil)
           44                 readn(fd, p, d->length);
           45         free(d);
           46         close(fd);
           47         return p;
           48 }
           49 static char *zonefile;
           50 void
           51 tzfile(char *f)
           52 {
           53         if (tzdata!=nil) {
           54                 free(tzdata);
           55                 tzdata = nil;
           56         }
           57         z.timecnt = 0;
           58         zonefile = f;
           59 }
           60 
           61 static
           62 long
           63 get4(uchar *p)
           64 {
           65         return (p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3];
           66 }
           67 
           68 enum {
           69         TTinfosz        = 4+1+1,
           70 };
           71 
           72 static
           73 int
           74 parsehead(void)
           75 {
           76         uchar *p;
           77         int        ver;
           78 
           79         ver = tzdata[4];
           80         if (ver!=0)
           81         if (ver!='2')
           82                 return -1;
           83 
           84         p = tzdata + 4 + 1 + 15;
           85 
           86         z.timecnt = get4(p+3*4);
           87         z.typecnt = get4(p+4*4);
           88         if (z.typecnt==0)
           89                 return -1;
           90         z.charcnt = get4(p+5*4);
           91         z.ptime = p+6*4;
           92         z.ptype = z.ptime + z.timecnt*4;
           93         z.ptt = z.ptype + z.timecnt;
           94         z.pzone = z.ptt + z.typecnt*TTinfosz;
           95         return 0;
           96 }
           97 
           98 static
           99 void
          100 ttinfo(Tinfo *ti, int tti)
          101 {
          102         uchar *p;
          103         int        i;
          104 
          105         i = z.ptype[tti];
          106         assert(i<z.typecnt);
          107         p = z.ptt + i*TTinfosz;
          108         ti->tzoff = get4(p);
          109         ti->dlflag = p[4];
          110         assert(p[5]<z.charcnt);
          111         ti->zone = (char*)z.pzone + p[5];
          112 }
          113 
          114 static
          115 void
          116 readtimezone(void)
          117 {
          118         char *tmp;
          119 
          120         z.timecnt = 0;
          121         switch (zonefile==nil) {
          122         default:
          123                 if ((tmp=getenv("timezone"))!=nil) {
          124                         tzdata = readtzfile(tmp);
          125                         free(tmp);
          126                         break;
          127                 }
          128                 zonefile = "/etc/localtime";
          129                 /* fall through */
          130         case 0:
          131                 tzdata = readtzfile(zonefile);
          132         }
          133         if (tzdata==nil)
          134                 return;
          135 
          136         if (strncmp("TZif", (char*)tzdata, 4)!=0)
          137                 goto errfree;
          138 
          139         if (parsehead()==-1) {
          140         errfree:
          141                 free(tzdata);
          142                 tzdata = nil;
          143                 z.timecnt = 0;
          144                 return;
          145         }
          146 }
          147 
          148 static
          149 tlong
          150 gett4(uchar *p)
          151 {
          152         long l;
          153 
          154         l = get4(p);
          155         if (l<0)
          156                 return 0;
          157         return l;
          158 }
          159 int
          160 zonetinfo(Tinfo *ti, int i)
          161 {
          162         if (tzdata==nil)
          163                 readtimezone();
          164         if (i<0 || i>=z.timecnt)
          165                 return -1;
          166         ti->t = gett4(z.ptime + 4*i);
          167         ttinfo(ti, i);
          168         return i;
          169 }
          170 
          171 int
          172 zonelookuptinfo(Tinfo *ti, tlong t)
          173 {
          174         uchar *p;
          175         int        i;
          176         tlong        oldtt, tt;
          177 
          178         if (tzdata==nil)
          179                 readtimezone();
          180         oldtt = 0;
          181         p = z.ptime;
          182         for (i=0; i<z.timecnt; i++) {
          183                 tt = gett4(p);
          184                 if (t<tt)
          185                         break;
          186                 oldtt = tt;
          187                 p += 4;
          188         }
          189         if (i>0) {
          190                 ttinfo(ti, i-1);
          191                 ti->t = oldtt;
          192 //                fprint(2, "t:%ld off:%d dflag:%d %s\n", (long)ti->t, ti->tzoff, ti->dlflag, ti->zone);
          193                 return i-1;
          194         }
          195         return -1;
          196 }
          197 
          198 void
          199 zonedump(int fd)
          200 {
          201         int        i;
          202         uchar *p;
          203         tlong t;
          204         Tinfo ti;
          205 
          206         if (tzdata==nil)
          207                 readtimezone();
          208         p = z.ptime;
          209         for (i=0; i<z.timecnt; i++) {
          210                 t = gett4(p);
          211                 ttinfo(&ti, i);
          212                 fprint(fd, "%ld\t%d\t%d\t%s\n", (long)t, ti.tzoff, ti.dlflag, ti.zone);
          213                 p += 4;
          214         }
          215 }