ref: beab0276a94c684f938ae5ea3d2c29c3dc331386
dir: /lib/date/zoneinfo+posixy.myr/
use std use sys use "types" pkg _zoneinfo = type zifile const findtzoff : (tz : byte[:], tm : std.time -> std.option(date.duration)) const load : (file : byte[:] -> zifile#) const free : (f : zifile# -> void) ;; type zifile = struct time : int32[:] timetype: byte[:] ttinfo : ttinfo[:] abbrev : byte[:] leap : int32[2][:] isstd : byte[:] isgmt : byte[:] ;; type ttinfo = struct gmtoff : int32 isdst : byte abbrind : byte ;; const zonepath = [ "/usr/share/zoneinfo", "/share/zoneinfo", "/etc/zoneinfo" ] var zonecache : std.htab(byte[:], zifile#)# const __init__ = { zonecache = std.mkht() } const findtzoff = {tz, tm -> std.option(date.duration) var path var zone var cur var sb var ds var i match std.htget(zonecache, tz) | `std.Some z: zone = z | `std.None: /* load zone */ if std.eq(tz, "") || std.eq(tz, "UTC") -> `std.Some 0 elif std.eq(tz, "local") path = std.sldup("/etc/localtime") else path = "" for z : zonepath path = std.pathcat(z, tz) if sys.stat(path, &sb) == 0 goto found ;; std.slfree(path) ;; std.slfree(path) -> `std.None ;; :found zone = load(path) std.slfree(path) std.htput(zonecache, std.sldup(tz), zone) ;; /* find applicable gmt offset */ cur = (tm / 1_000_000 : int32) if zone.time.len == 0 -> `std.None ;; for i = 0; i < zone.time.len && cur < zone.time[i]; i++ /* nothing */ ;; ds = zone.ttinfo[zone.timetype[i]].gmtoff -> `std.Some ((ds : date.duration) * 1_000_000) } const load = {file var nisgmt, nisstd, nleap, ntime, ntype, nchar var i, f, p, data /* check magic */ match std.slurp(file) | `std.Ok d: data = d | `std.Err m: -> std.zalloc() ;; if !std.eq(data[:4], "TZif") std.put("{} is not a zone info file\n", file) -> std.zalloc() ;; /* skip to data */ p = data[20:] (nisgmt, p) = fetchbe32(p) (nisstd, p) = fetchbe32(p) (nleap, p) = fetchbe32(p) (ntime, p) = fetchbe32(p) (ntype, p) = fetchbe32(p) (nchar, p) = fetchbe32(p) f = std.alloc() f.time = std.slalloc((ntime : std.size)) for i = 0; i < ntime; i++ (f.time[i], p) = fetchbe32(p) ;; f.timetype = std.slalloc((ntime : std.size)) for i = 0; i < ntime; i++ (f.timetype[i], p) = fetchbe8(p) ;; f.ttinfo = std.slalloc((ntype : std.size)) for i = 0; i < ntype; i++ p = fetchttinfo(p, &f.ttinfo[i]) ;; f.abbrev = std.slalloc((nchar : std.size)) for i = 0; i < nchar; i++ (f.abbrev[i], p) = fetchbe8(p) ;; f.leap = std.slalloc((nleap : std.size)) for i = 0; i < nleap; i++ (f.leap[i][0], p) = fetchbe32(p) (f.leap[i][1], p) = fetchbe32(p) ;; f.isstd = std.slalloc((nisstd : std.size)) for i = 0; i < nisstd; i++ (f.isstd[i], p) = fetchbe8(p) ;; f.isgmt = std.slalloc((nisgmt : std.size)) for i = 0; i < nisgmt; i++ (f.isgmt[i], p) = fetchbe8(p) ;; std.slfree(data) -> f } const free = {zi std.slfree(zi.time) std.slfree(zi.timetype) std.slfree(zi.ttinfo) std.slfree(zi.abbrev) std.slfree(zi.leap) std.slfree(zi.isstd) std.slfree(zi.isgmt) std.free(zi) } const fetchbe32 = {sl var v std.assert(sl.len >= 4, "Slice too small to fetch int32 from") v = std.getbe32(sl[:4]) -> (v, sl[4:]) } const fetchbe8 = {sl var v std.assert(sl.len >= 1, "Slice too small to fetch int8 from") v = sl[0] -> (v, sl[1:]) } const fetchttinfo = {sl, dst : ttinfo# (dst.gmtoff, sl) = fetchbe32(sl) (dst.isdst, sl) = fetchbe8(sl) (dst.abbrind, sl) = fetchbe8(sl) -> sl }