ref: 155c90d05b745a22fceb60c44ff0a69d3a6466b5
dir: /mbld/syssel.myr/
use std use "opts" use "types" pkg bld = type syssel(@a) = struct file : byte[:] line : int targ : byte[:] sysattrs : std.htab(byte[:], bool)# _match : std.htab(byte[:], int)# _best : std.htab(byte[:], @a)# ;; generic mksyssel : (b : build#, f : byte[:], line : int, targ : byte[:] -> syssel(@a)#) generic sysseladd : (syssel : syssel(byte[:])#, file : byte[:] -> void) generic sysseladdlist : (syssel : syssel(@a)#, base : byte[:], attrs : byte[:][:], val : @a -> void) generic sysselfin : (syssel : syssel(@a)# -> @a[:]) const addsysattrs : (sa : build#, tags : byte[:][:] -> void) ;; generic mksyssel = {b, file, line, targ var syssel syssel = std.mk([ .file = file, .line = line, .targ = targ, ._match = std.mkht(std.strhash, std.streq), ._best = std.mkht(std.strhash, std.streq), .sysattrs = b.sysattrs ]) -> syssel } generic sysseladd = {syssel, f var basename, attrs var attrlist match std.strfind(f, "+") | `std.Some i: basename = f[:i] match std.strrfind(f[i+1:], ".") | `std.Some j: attrs = f[i+1:][:j] | `std.None: std.fatal("unrecognized type for file {}\n", f) ;; | `std.None: match std.strrfind(f, ".") | `std.None: std.fatal("unrecognized type for file {}\n", f) | `std.Some i: basename = f[:i] attrs = "" ;; ;; attrlist = std.strsplit(attrs, "-") sysseladdlist(syssel, basename, attrlist, f) std.slfree(attrlist) } generic sysseladdlist = {syssel, base, attrs, val var nmatch, curbest nmatch = 0 for a in attrs if std.hthas(syssel.sysattrs, a) nmatch++ else nmatch = -1 break ;; ;; curbest = std.htgetv(syssel._match, base, -1) if curbest < nmatch std.htput(syssel._match, base, nmatch) std.htput(syssel._best, base, val) ;; } generic sysselfin = {syssel var keys, nmatch, ret keys = std.htkeys(syssel._match) ret = [][:] for k in keys nmatch = std.htgetv(syssel._match, k, -1) if nmatch == -1 std.fatal("{}:{}: target {}, no applicable file for '{}'\n", syssel.file, syssel.line, syssel.targ, k) ;; std.slpush(&ret, std.get(std.htget(syssel._best, k))) ;; std.htfree(syssel._match) std.htfree(syssel._best) -> ret } const addsysattrs = {b, tags var tagfile match opt_sys | "freebsd": tag(b.sysattrs, ["freebsd", "posixy"][:]) | "openbsd": tag(b.sysattrs, ["openbsd", "posixy"][:]) | "osx": tag(b.sysattrs, ["osx", "posixy"][:]) | "linux": tag(b.sysattrs, ["linux", "posixy"][:]) | "plan9": tag(b.sysattrs, ["plan9"][:]) | unknown: std.fatal("unknown systemx \"{}\"\n", unknown) ;; match opt_arch | "x64": tag(b.sysattrs, ["x64"][:]) | unknown: std.fatal("unknown architecture {}\n", unknown) ;; tag(b.sysattrs, tags) tagfile = std.pathcat(b.basedir, "systags") if std.fexists(tagfile) loadtagfile(b, tagfile) ;; std.slfree(tagfile) } const loadtagfile = {b, tagfile var data, tag data = std.try(std.slurp(tagfile)) while true data = skipspace(data) (tag, data) = word(data) match tag | `std.Some w: std.htput(b.sysattrs, w, true) | `std.None: if data.len > 0 std.fatal("junk character near '{}'\n", trailing(data, 10)) else break ;; ;; ;; } const skipspace = {data var c c = std.decode(data) while std.isspace(c) data = data[std.charlen(c):] ;; -> data } const word = {data var c, split split = 0 c = std.decode(data[:]) while std.isalnum(c) || c == '.' || c == '_' || c == '$' split += std.charlen(c) ;; if split > 0 -> (`std.Some data[:split], data[split:]) else -> (`std.None, data) ;; } const tag = {sa, tags for t in tags std.htput(sa, t, true) ;; } const trailing = {str, len -> str[:std.min(len, str.len)] }