summaryrefslogtreecommitdiff
path: root/appl/lib/cfg.b
diff options
context:
space:
mode:
Diffstat (limited to 'appl/lib/cfg.b')
-rw-r--r--appl/lib/cfg.b234
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;
+}