summaryrefslogtreecommitdiff
path: root/src/luaotfload-configuration.lua
diff options
context:
space:
mode:
authorPhilipp Gesang <phg42.2a@gmail.com>2014-04-21 21:40:21 +0200
committerPhilipp Gesang <phg42.2a@gmail.com>2014-04-21 21:40:21 +0200
commita84ec1cd4b7cc06fec1d2cf5e5f5e0cbd9115637 (patch)
tree05c63b5fd96f66a1874e081ac4239db6b1655896 /src/luaotfload-configuration.lua
parent70a6425e1b6041d5c476117fa7c5a3acb9bc386a (diff)
downloadluaotfload-a84ec1cd4b7cc06fec1d2cf5e5f5e0cbd9115637.tar.gz
[conf,tool] integrate configuration parser
Diffstat (limited to 'src/luaotfload-configuration.lua')
-rw-r--r--src/luaotfload-configuration.lua255
1 files changed, 255 insertions, 0 deletions
diff --git a/src/luaotfload-configuration.lua b/src/luaotfload-configuration.lua
new file mode 100644
index 0000000..973810a
--- /dev/null
+++ b/src/luaotfload-configuration.lua
@@ -0,0 +1,255 @@
+#!/usr/bin/env texlua
+-------------------------------------------------------------------------------
+-- FILE: luaotfload-configuration.lua
+-- DESCRIPTION: config file reader
+-- REQUIREMENTS: Luaotfload > 2.4
+-- AUTHOR: Philipp Gesang (Phg), <phg42.2a@gmail.com>
+-- VERSION: same as Luaotfload
+-- CREATED: 2014-04-21 14:03:52+0200
+-------------------------------------------------------------------------------
+--
+
+if not modules then modules = { } end modules ["luaotfload-configuration"] = {
+ version = "2.5",
+ comment = "part of Luaotfload",
+ author = "Philipp Gesang",
+ copyright = "Luaotfload Development Team",
+ license = "GNU GPL v2.0"
+}
+
+luaotfload = luaotfload or { }
+luaotfload.config = luaotfload.config or { }
+
+local string = string
+local stringsub = string.sub
+local stringexplode = string.explode
+
+local io = io
+local ioloaddata = io.loaddata
+
+local os = os
+local osgetenv = os.getenv
+
+local lpeg = require "lpeg"
+local lpegmatch = lpeg.match
+
+local kpse = kpse
+local kpselookup = kpse.lookup
+
+local lfs = lfs
+local lfsisfile = lfs.isfile
+local lfsisdir = lfs.isdir
+
+local file = file
+local filejoin = file.join
+
+local parsers = luaotfload.parsers
+local config = luaotfload.config
+local log = luaotfload.log
+local logreport = log.report
+
+local config_parser = parsers.config
+
+-------------------------------------------------------------------------------
+--- SETTINGS
+-------------------------------------------------------------------------------
+
+local path_t = 0
+local kpse_t = 1
+
+local config_paths = {
+ --- needs adapting for those other OS
+ { path_t, "./luaotfloadrc" },
+ { path_t, "~/.config/luaotfload/luaotfloadrc" },
+ { path_t, "~/.luaotfloadrc" },
+ { kpse_t, "luaotfloadrc" },
+ { kpse_t, "luaotfload.conf" },
+}
+
+-------------------------------------------------------------------------------
+--- OPTION SPECIFICATION
+-------------------------------------------------------------------------------
+
+local string_t = "string"
+local table_t = "table"
+local boolean_t = "boolean"
+local function_t = "function"
+
+local option_spec = {
+ db = {
+ formats = {
+ --- e.g. "otf ttf" -> { "otf", "ttf" }
+ in_t = string_t,
+ out_t = table_t,
+ transform = function (str) return stringexplode (str, " +") end
+ },
+ reload = {
+ in_t = boolean_t,
+ },
+ },
+}
+
+-------------------------------------------------------------------------------
+--- MAIN FUNCTIONALITY
+-------------------------------------------------------------------------------
+
+--[[doc--
+
+ tilde_expand -- Rudimentary tilde expansion; covers just the “substitute ‘~’
+ by the current users’s $HOME” part.
+
+--doc]]--
+
+local tilde_expand = function (p)
+ if #p > 2 then
+ if stringsub (p, 1, 2) == "~/" then
+ local homedir = osgetenv "HOME"
+ if homedir and lfsisdir (homedir) then
+ p = filejoin (homedir, stringsub (p, 3))
+ end
+ end
+ end
+ return p
+end
+
+local resolve_config_path = function ()
+ inspect (config_paths)
+ for i = 1, #config_paths do
+ local t, p = unpack (config_paths[i])
+ local fullname
+ if t == kpse_t then
+ fullname = kpse.lookup (p)
+ logreport ("both", 6, "conf", "kpse lookup: %s -> %s.", p, fullname)
+ elseif t == path_t then
+ local expanded = tilde_expand (p)
+ if lfsisfile (expanded) then
+ fullname = expanded
+ end
+ logreport ("both", 6, "conf", "path lookup: %s -> %s.", p, fullname)
+ end
+ if fullname then
+ logreport ("both", 3, "conf", "Reading configuration file at %q.", fullname)
+ return fullname
+ end
+ end
+ logreport ("both", 2, "conf", "No configuration file found.")
+ return false
+end
+
+local add_config_paths = function (t)
+ if not next (t) then
+ return
+ end
+ local result = { }
+ for i = 1, #t do
+ local path = t[i]
+ result[#result + 1] = { path_t, path }
+ end
+ config_paths = table.append (result, config_paths)
+end
+
+local process_options = function (opts)
+ local new = { }
+ for i = 1, #opts do
+ local section = opts[i]
+ local title = section.section.title
+ local vars = section.variables
+
+ if not title then --- trigger warning: arrow code ahead
+ logreport ("both", 2, "conf", "Section %d lacks a title; skipping.", i)
+ elseif not vars then
+ logreport ("both", 2, "conf", "Section %d (%s) lacks a variable section; skipping.", i, title)
+ else
+ local spec = option_spec[title]
+ if not spec then
+ logreport ("both", 2, "conf", "Section %d (%s) unknown; skipping.", i, title)
+ else
+ local newsection = new[title]
+ if not newsection then
+ newsection = { }
+ new[title] = newsection
+ end
+
+ for var, val in next, vars do
+ local vspec = spec[var]
+ local t_val = type (val)
+ if t_val ~= vspec.in_t then
+ logreport ("both", 2, "conf",
+ "Section %d (%s): type mismatch of input value %q (%q, %s != %s); ignoring.",
+ i, title,
+ var, tostring (val), t_val, vspec.in_t)
+ else --- type matches
+ local transform = vspec.transform
+ if transform then
+ local dval
+ local t_transform = type (transform)
+ if t_transform == function_t then
+ dval = transform (val)
+ elseif t_transform == table_t then
+ dval = transform[val]
+ end
+ if dval then
+ local out_t = vspec.out_t
+ if out_t then
+ local t_dval = type (dval)
+ if t_dval == out_t then
+ newsection[var] = dval
+ else
+ logreport ("both", 2, "conf",
+ "Section %d (%s): type mismatch of derived value of %q (%q, %s != %s); ignoring.",
+ i, title,
+ var, tostring (dval), t_dval, out_t)
+ end
+ else
+ newsection[var] = dval
+ end
+ else
+ logreport ("both", 2, "conf",
+ "Section %d (%s): value of %q could not be derived via %s from input %q; ignoring.",
+ i, title, var, t_transform, tostring (val))
+ end
+ else --- insert as is
+ newsection[var] = val
+ end
+ end
+ end
+ end
+ end
+ end
+ return new
+end
+
+local read = function (extra)
+ if extra then
+ add_config_paths (extra)
+ end
+
+ local readme = resolve_config_path ()
+ if readme == false then
+ logreport ("both", 2, "conf", "No configuration file.")
+ return false
+ end
+
+ local raw = ioloaddata (readme)
+ if not raw then
+ logreport ("both", 2, "conf", "Error reading the configuration file %q.", readme)
+ return false
+ end
+
+ local parsed = lpegmatch (parsers.config, raw)
+ if not parsed then
+ logreport ("both", 2, "conf", "Error parsing configuration file %q.", readme)
+ return false
+ end
+
+ local ret, msg = process_options (parsed)
+ if not ret then
+ logreport ("both", 2, "conf", "File %q is not a valid configuration file.", readme)
+ logreport ("both", 2, "conf", "Error: %s", msg)
+ return false
+ end
+ return ret
+end
+
+config.read = read
+