URI:
       tzoneinfo.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tzoneinfo.c (3065B)
       ---
            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 MIT license used in the rest of the distribution.
           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         if(zonefile==nil) {
          122                 if ((tmp=getenv("timezone"))!=nil) {
          123                         tzdata = readtzfile(tmp);
          124                         free(tmp);
          125                         goto havedata;
          126                 }
          127                 zonefile = "/etc/localtime";
          128         }
          129         tzdata = readtzfile(zonefile);
          130         if (tzdata==nil)
          131                 return;
          132 
          133 havedata:
          134         if (strncmp("TZif", (char*)tzdata, 4)!=0)
          135                 goto errfree;
          136 
          137         if (parsehead()==-1) {
          138         errfree:
          139                 free(tzdata);
          140                 tzdata = nil;
          141                 z.timecnt = 0;
          142                 return;
          143         }
          144 }
          145 
          146 static
          147 tlong
          148 gett4(uchar *p)
          149 {
          150         long l;
          151 
          152         l = get4(p);
          153         if (l<0)
          154                 return 0;
          155         return l;
          156 }
          157 int
          158 zonetinfo(Tinfo *ti, int i)
          159 {
          160         if (tzdata==nil)
          161                 readtimezone();
          162         if (i<0 || i>=z.timecnt)
          163                 return -1;
          164         ti->t = gett4(z.ptime + 4*i);
          165         ttinfo(ti, i);
          166         return i;
          167 }
          168 
          169 int
          170 zonelookuptinfo(Tinfo *ti, tlong t)
          171 {
          172         uchar *p;
          173         int        i;
          174         tlong        oldtt, tt;
          175 
          176         if (tzdata==nil)
          177                 readtimezone();
          178         oldtt = 0;
          179         p = z.ptime;
          180         for (i=0; i<z.timecnt; i++) {
          181                 tt = gett4(p);
          182                 if (t<tt)
          183                         break;
          184                 oldtt = tt;
          185                 p += 4;
          186         }
          187         if (i>0) {
          188                 ttinfo(ti, i-1);
          189                 ti->t = oldtt;
          190 //                fprint(2, "t:%ld off:%d dflag:%d %s\n", (long)ti->t, ti->tzoff, ti->dlflag, ti->zone);
          191                 return i-1;
          192         }
          193         return -1;
          194 }
          195 
          196 void
          197 zonedump(int fd)
          198 {
          199         int        i;
          200         uchar *p;
          201         tlong t;
          202         Tinfo ti;
          203 
          204         if (tzdata==nil)
          205                 readtimezone();
          206         p = z.ptime;
          207         for (i=0; i<z.timecnt; i++) {
          208                 t = gett4(p);
          209                 ttinfo(&ti, i);
          210                 fprint(fd, "%ld\t%d\t%d\t%s\n", (long)t, ti.tzoff, ti.dlflag, ti.zone);
          211                 p += 4;
          212         }
          213 }