From f8d43e62f3927545d06e39d01499442b0f64fe79 Mon Sep 17 00:00:00 2001
From: Philipp Gesang <phg42.2a@gmail.com>
Date: Mon, 21 Apr 2014 16:48:02 +0200
Subject: [parsers] add INI file parser

---
 src/luaotfload-parsers.lua | 121 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 120 insertions(+), 1 deletion(-)

(limited to 'src')

diff --git a/src/luaotfload-parsers.lua b/src/luaotfload-parsers.lua
index c3c3843..a45fcb8 100644
--- a/src/luaotfload-parsers.lua
+++ b/src/luaotfload-parsers.lua
@@ -21,6 +21,8 @@ luaotfload              = luaotfload or { }
 luaotfload.parsers      = luaotfload.parsers or { }
 local parsers           = luaotfload.parsers
 
+local rawset            = rawset
+
 local lpeg              = require "lpeg"
 local P, R, S           = lpeg.P, lpeg.R, lpeg.S
 local lpegmatch         = lpeg.match
@@ -62,14 +64,22 @@ local semicolon         = P";"
 local comma             = P","
 local noncomma          = 1 - comma
 local slash             = P"/"
+local backslash         = P"\\"
 local equals            = P"="
+local dash              = P"-"
+local gartenzaun        = P"#"
 local lbrk, rbrk        = P"[", P"]"
+local squote            = P"'"
+local dquote            = P"\""
 
+local newline           = P"\n"
+local returnchar        = P"\r"
 local spacing           = S" \t\v"
 local linebreak         = S"\n\r"
 local whitespace        = spacing + linebreak
 local ws                = spacing^0
 local xmlws             = whitespace^1
+local eol               = P"\n\r" + P"\r\n" + linebreak
 
 local digit             = R"09"
 local alpha             = R("az", "AZ")
@@ -339,7 +349,7 @@ parsers.splitcomma      = splitcomma
 
 
 -------------------------------------------------------------------------------
----                          FONT REQUEST
+---                              FONT REQUEST
 -------------------------------------------------------------------------------
 
 
@@ -576,3 +586,112 @@ local font_request      = Ct(path_lookup   * (colon^-1 * features)^-1
 
 luaotfload.parsers.font_request = font_request
 
+-------------------------------------------------------------------------------
+---                                INI FILES
+-------------------------------------------------------------------------------
+
+--[[doc--
+
+    Luaotfload uses the pervasive flavor of the INI files that allows '#' in
+    addition to ';' to indicate comment lines (see git-config(1) for a
+    description of the syntax we’re targeting).
+
+--doc]]--
+
+local truth_ids = {
+  ["true"]  = true,
+  ["1"]     = true,
+  yes       = true,
+  on        = true,
+  ["false"] = false,
+  ["2"]     = false,
+  no        = false,
+  off       = false,
+}
+
+local maybe_cast = function (var)
+  local bool = truth_ids[var]
+  if bool ~= nil then
+    return bool
+  end
+  return tonumber (var) or var
+end
+local escape = function (chr, repl)
+  return (backslash * P(chr) / (repl or chr))
+end
+local valid_escapes     = escape "\""
+                        + escape "\\"
+                        + escape ("n", "\n")
+                        + escape ("t", "\t")
+                        + escape ("b", "\b")
+local comment_char      = semicolon + gartenzaun
+local comment_line      = ws * comment_char * (1 - eol)^0 * eol
+local blank_line        = ws * eol
+local skip_line         = comment_line + blank_line
+local ini_id_char       = alpha + dash
+local ini_id            = (alpha * ini_id_char^0) / stringlower
+local ini_value_char    = (valid_escapes + (1 - newline - backslash - comment_char))
+local ini_value         = (Cs (ini_value_char^0) / string.strip)
+                        * (comment_char * (1 - eol)^0)^-1
+local ini_string_char   = (valid_escapes + (1 - newline - dquote - backslash))
+local ini_string        = dquote
+                        * Cs (ini_string_char^0)
+                        * dquote
+
+local ini_heading_title = Ct (Cg (ini_id, "title")
+                            * (ws * Cg (ini_string / stringlower, "subtitle"))^-1)
+local ini_heading       = lbrk * ws
+                        * Cg (ini_heading_title, "section")
+                        * ws * rbrk * ws * eol
+
+local ini_variable_full = Cg (ws
+                            * ini_id
+                            * ws
+                            * equals
+                            * ws
+                            * (ini_string + (ini_value / maybe_cast))
+                            * ws
+                            * eol)
+local ini_variable_true = Cg (ws * ini_id * ws * eol * Cc (true))
+local ini_variable      = ini_variable_full
+                        + ini_variable_true
+                        + skip_line
+local ini_variables     = Cg (Cf (Ct "" * ini_variable^0, rawset), "variables")
+
+local ini_section       = Ct (ini_heading * ini_variables)
+local ini_sections      = skip_line^0 * ini_section^0
+local config            = Ct (ini_sections)
+
+--[[doc--
+
+    The INI parser converts an input of the form
+
+            [==[
+              [foo]
+              bar = baz
+              xyzzy = no
+              buzz
+
+              [lavernica "brutalitops"]
+              # It’s a locomotive that runs on us.
+                laan-ev = zip zop zooey   ; jib-jab
+              Crouton = "Fibrosis \"\\ # "
+
+            ]==]
+
+    to a Lua table of the form
+
+            { { section = { title = "foo" },
+                variables = { bar = "baz",
+                              xyzzy = false,
+                              buzz = true } },
+              { section = { title = "boing",
+                            subtitle = "brutalitops" },
+                variables = { ["laan-ev"] = "zip zop zooey",
+                              crouton = "Fibrosis \"\\ # " } } }
+
+--doc]]--
+
+luaotfload.parsers.config = config
+
+-- vim:ft=lua:tw=71:et:sts=4:ts=8
-- 
cgit v1.2.3