diff options
Diffstat (limited to 'appl/lib/cfg.b')
| -rw-r--r-- | appl/lib/cfg.b | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/appl/lib/cfg.b b/appl/lib/cfg.b new file mode 100644 index 00000000..49e60262 --- /dev/null +++ b/appl/lib/cfg.b @@ -0,0 +1,234 @@ +implement Cfg; + +include "sys.m"; +include "bufio.m"; +include "cfg.m"; + +sys : Sys; +bufio : Bufio; + +Iobuf : import bufio; +ENOMOD : con "cannot load module"; +EBADPATH : con "bad path"; + + +init(path : string) : string +{ + sys = load Sys Sys->PATH; + bufio = load Bufio Bufio->PATH; + if (bufio == nil) + return sys->sprint("%s: %r", ENOMOD); + + iob := bufio->open(path, Sys->OREAD); + if (iob == nil) + return sys->sprint("%s: %r", EBADPATH); + + # parse the config file + r : list of ref Tuple; + lnum := 0; + rlist : list of list of ref Tuple; + + while ((line := iob.gets('\n')) != nil) { + lnum++; + (tuple, err) := parseline(line, lnum); + if (err != nil) + return sys->sprint("%s:%d: %s", path, lnum, err); + + if (tuple == nil) + continue; + if (line[0] != ' ' && line[0] != '\t') { + # start of a new record + if (r != nil) + rlist = r :: rlist; + r = nil; + } + r = tuple :: r; + } + if (r != nil) + rlist = r :: rlist; + for (; rlist != nil; rlist = tl rlist) + insert(hd rlist); + return nil; +} + +parseline(s : string, lnum : int) : (ref Tuple, string) +{ + attrs : list of Attr; + quote := 0; + word := ""; + lastword := ""; + name := ""; + +loop: + for (i := 0 ; i < len s; i++) { + if (quote) { + if (s[i] == quote) { + if (i + 1 < len s && s[i+1] == quote) { + word[len word] = quote; + i++; + } else { + quote = 0; + continue; + } + } else + word[len word] = s[i]; + continue; + } + case s[i] { + '\'' or '\"' => + quote = s[i]; + continue; + '#' => + break loop; + ' ' or '\t' or '\n' => + if (word == nil) + continue; + if (lastword != nil) { + # lastword space word space + attrs = Attr(lastword, nil) :: attrs; + } + lastword = word; + word = nil; + + if (name != nil) { + # name = lastword space + attrs = Attr(name, lastword) :: attrs; + name = lastword = nil; + } + '=' => + if (lastword == nil) { + # word= + lastword = word; + word = nil; + } + if (word != nil) { + # lastword word= + attrs = Attr(lastword, nil) :: attrs; + lastword = word; + word = nil; + } + if (lastword == nil) + return (nil, "empty name"); + name = lastword; + lastword = nil; + * => + word[len word] = s[i]; + } + } + if (quote) + return (nil, "missing quote"); + + if (lastword == nil) { + lastword = word; + word = nil; + } + + if (name == nil) { + name = lastword; + lastword = nil; + } + + if (name != nil) + attrs = Attr(name, lastword) :: attrs; + + if (attrs == nil) + return (nil, nil); + + fattrs : list of Attr; + for (; attrs != nil; attrs = tl attrs) + fattrs = hd attrs :: fattrs; + return (ref Tuple(lnum, fattrs), nil); +} + +lookup(name : string) : list of (string, ref Record) +{ + l := buckets[hash(name)]; + for (; l != nil; l = tl l) { + hr := hd l; + if (hr.name != name) + continue; + return hr.vrecs; + } + return nil; +} + +Record.lookup(r : self ref Record, name : string) : (string, ref Tuple) +{ + for (ts := r.tuples; ts != nil; ts = tl ts) { + t := hd ts; + for (as := t.attrs; as != nil; as = tl as) { + a := hd as; + if (a.name == name) + return (a.value, t); + } + } + return (nil, nil); +} + +Tuple.lookup(t : self ref Tuple, name : string) : string +{ + for (as := t.attrs; as != nil; as = tl as) { + a := hd as; + if (a.name == name) + return a.value; + } + return nil; +} + +reset() +{ + keynames = nil; + buckets = array[HSIZE+1] of list of ref HRecord; +} + +# Record hash table +HRecord : adt { + name : string; + vrecs : list of (string, ref Record); +}; + +keynames : list of string; + +HSIZE : con 16rff; # must be (2^n)-1 due to hash() defn +buckets := array [HSIZE+1] of list of ref HRecord; + +hash(name : string) : int +{ + # maybe use hashPJW? + h := 0; + for (i := 0; i < len name; i++) + h = (h + name[i]) & HSIZE; + return h; +} + +insert(rtups : list of ref Tuple) { + # tuple list is currently in reverse order + ftups : list of ref Tuple; + for (; rtups != nil; rtups = tl rtups) + ftups = hd rtups :: ftups; + + maintuple := hd ftups; + mainattr := hd maintuple.attrs; + name := mainattr.name; + value := mainattr.value; + + # does name already exist? + hr : ref HRecord; + h := hash(name); + l := buckets[h]; + for (; l != nil; l = tl l) { + hr = hd l; + if (hr.name == name) + break; + } + if (l == nil) { + keynames = name :: keynames; + buckets[h] = ref HRecord(name, (value, ref Record(ftups))::nil) :: buckets[h]; + } else + hr.vrecs = (value, ref Record(ftups)) :: hr.vrecs; +} + +getkeys() : list of string +{ + return keynames; +} |
