shithub: mc

Download patch

ref: da67a46215a8c4f16e958e86354c7514132abc92
parent: a57ce36f628ff500404b41064bd2a95c7bfa510d
author: Ori Bernstein <[email protected]>
date: Tue Nov 24 17:28:27 EST 2015

Add ini file parser.

--- a/lib/bld.sub
+++ b/lib/bld.sub
@@ -4,4 +4,5 @@
 	bio
 	regex
 	cryptohash
+	inifile
 ;;
--- /dev/null
+++ b/lib/inifile/access.myr
@@ -1,0 +1,29 @@
+use std
+use bio
+
+use "types.use"
+
+pkg inifile =
+	/* key getting/setting */
+	const get	: (ini : inifile#, sect : byte[:], key : byte[:]	-> std.option(byte[:]))
+	const getv	: (ini : inifile#, sect : byte[:], key : byte[:], val : byte[:]	-> byte[:])
+	const has	: (ini : inifile#, sect : byte[:], key : byte[:] -> bool)
+	const put	: (ini : inifile#, sect : byte[:], key : byte[:], val : byte[:]	-> void)
+;;
+
+const get = {ini, sect, key
+	-> std.htget(ini.elts, (sect, key))
+}
+
+const getv = {ini, sect, key, val
+	-> std.htgetv(ini.elts, (sect, key), val)
+}
+
+const has = {ini, sect, key
+	-> std.hthas(ini.elts, (sect, key))
+}
+
+const put = {ini, sect, key, val
+	std.htput(ini.elts, (std.sldup(sect), std.sldup(key)), std.sldup(val))
+}
+
--- /dev/null
+++ b/lib/inifile/bld.sub
@@ -1,0 +1,10 @@
+lib inifile =
+	access.myr
+	parse.myr
+	types.myr
+	write.myr
+
+	lib ../std:std
+	lib ../sys:sys
+	lib ../bio:bio
+;;
--- /dev/null
+++ b/lib/inifile/parse.myr
@@ -1,0 +1,153 @@
+use std
+use bio
+
+use "types.use"
+
+pkg inifile =
+	/* reading */
+	const load	: (path : byte[:]	-> std.result(inifile#, error))
+	const loadf	: (file : std.fd	-> std.result(inifile#, error))
+	const free	: (ini : inifile#	-> void)
+;;
+
+
+type parser = struct
+	line	: int
+	sect	: byte[:]
+	err	: std.option(error)
+;;
+
+const load = {path
+	match std.open(path, std.Ordonly)
+	| `std.Ok fd:	-> loadf(fd)
+	| `std.Fail e:	-> `std.Fail `Fileerr
+	;;
+}
+
+const free = {ini
+	var kl
+
+	kl = std.htkeys(ini.elts)
+	for (sect, key) in kl
+		std.slfree(std.htgetv(ini.elts, (sect, key), ""))
+		std.slfree(sect)
+		std.slfree(key)
+	;;
+	std.slfree(kl)
+	std.htfree(ini.elts)
+	std.free(ini)
+}
+
+const loadf = {fd
+	var p : parser#
+	var ini
+	var f
+
+	ini = std.mk([
+		.elts = std.mkht(keyhash, keyeq)
+	])
+	p = std.mk([
+		.line = 1,
+		.sect = "",
+		.err = `std.None
+	])
+	f = bio.mkfile(fd, bio.Rd)
+	while true
+		match bio.readln(f)
+		| `bio.Eof:
+			break
+		| `bio.Ok ln:
+			if !parseline(p, ini, ln)
+				break
+			;;
+		| `bio.Err e:
+			p.err = `std.Some `Fileerr
+			break
+		;;
+		p.line++
+	;;
+	match p.err
+	| `std.None:
+		std.slfree(p.sect)
+		-> `std.Ok ini 
+	| `std.Some e:
+		free(ini)
+		-> `std.Fail e
+	;;
+}
+
+const parseline = {p, ini, ln
+	ln = std.strstrip(ln)
+
+	/* remove comments */
+	match std.strfind(ln, ";")
+	| `std.Some idx:	ln = ln[:idx]
+	| `std.None:
+	;;
+	match std.strfind(ln, "#")
+	| `std.Some idx:	ln = ln[:idx]
+	| `std.None:
+	;;
+
+	/* skip empty lines */
+	if ln.len == 0
+		-> true
+	;;
+
+	match ln[0] castto(char)
+	| '[':	-> parsesection(p, ini, ln)
+	| _:	-> parsekvp(p, ini, ln)
+	;;
+}
+
+const parsesection = {p, ini, ln
+	match std.strfind(ln, "]")
+	| `std.Some idx:
+		if idx != ln.len - 1
+			p.err = `std.Some (`Parseerr p.line)
+			-> false
+		;;
+		std.slfree(p.sect)
+		p.sect = std.sldup(std.strstrip(ln[1:$-1]))
+	| `std.None:
+		p.err = `std.Some (`Parseerr p.line)
+		-> false
+	;;
+	-> true
+}
+
+const parsekvp = {p, ini, ln
+	var key, val
+
+	match std.strfind(ln, "=")
+	| `std.None:
+		p.err = `std.Some (`Parseerr p.line)
+		-> false
+	| `std.Some idx:
+		key = std.strstrip(ln[:idx])
+		val = std.strstrip(ln[idx+1:])
+		if std.hthas(ini.elts, (p.sect, key))
+			p.err = `std.Some(`Dupkey p.line)
+			-> false
+		;;
+		std.htput(ini.elts, (std.sldup(p.sect), std.sldup(key)), std.sldup(val))
+		-> true
+	;;
+}
+
+const keyhash = {k
+	var sect, key
+
+	(sect, key) = k
+	-> std.strhash(sect) ^ std.strhash(key)
+}
+
+const keyeq = {a, b
+	var s1, k1
+	var s2, k2
+
+	(s1, k1) = a
+	(s2, k2) = a
+	-> std.streq(s1, s2) && std.streq(k1, k2)
+}
+
--- /dev/null
+++ b/lib/inifile/types.myr
@@ -1,0 +1,13 @@
+use std
+
+pkg inifile =
+	type error = union
+		`Fileerr
+		`Parseerr int
+		`Dupkey int
+	;;
+
+	type inifile = struct
+		elts	: std.htab((byte[:], byte[:]), byte[:])#
+	;;
+;;
--- /dev/null
+++ b/lib/inifile/write.myr
@@ -1,0 +1,12 @@
+use std
+use bio
+
+use "types.use"
+
+pkg inifile =
+	const write	: (ini : inifile#, path : byte[:]	-> bool)
+;;
+
+const write = {ini, path
+	-> true
+}