ref: 94b6dcc7253e53f6a50396f11aa62b94d3e95d2b
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"
]
const findtzoff = {tz, tm -> std.option(date.duration)
var path
var zone
var cur
var sb
var ds
var i
/* load zone */
if std.sleq(tz, "") || std.sleq(tz, "UTC")
-> `std.Some 0
elif std.sleq(tz, "local")
path = std.sldup("/etc/localtime")
else
path = ""
for z in 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)
/* 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
free(zone)
-> `std.Some (ds : date.duration) * 1_000_000
}
const load = {file
var nisgmt, nisstd, nleap, ntime, ntype, nchar
var i, f, p
/* check magic */
match std.slurp(file)
| `std.Ok d: p = d
| `std.Err m:
-> std.zalloc()
;;
if !std.sleq(p[:4], "TZif")
std.put("{} is not a zone info file\n", file)
-> std.zalloc()
;;
/* skip to data */
p = p[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)
;;
-> 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
}