summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS2
-rw-r--r--doc/luaotfload-latex.tex7
-rw-r--r--doc/luaotfload-main.tex36
-rwxr-xr-xscripts/mktests73
-rw-r--r--src/luaotfload-auxiliary.lua45
-rw-r--r--src/luaotfload-basics-gen.lua25
-rw-r--r--src/luaotfload-basics-nod.lua15
-rw-r--r--src/luaotfload-colors.lua2
-rw-r--r--src/luaotfload-configuration.lua536
-rw-r--r--src/luaotfload-database.lua216
-rw-r--r--src/luaotfload-diagnostics.lua34
-rw-r--r--src/luaotfload-features.lua49
-rw-r--r--src/luaotfload-fontloader.lua65
-rw-r--r--src/luaotfload-main.lua152
-rw-r--r--src/luaotfload-parsers.lua141
-rwxr-xr-xsrc/luaotfload-tool.lua152
16 files changed, 1179 insertions, 371 deletions
diff --git a/NEWS b/NEWS
index 2aa319e..4a8da57 100644
--- a/NEWS
+++ b/NEWS
@@ -17,6 +17,8 @@ Change History
* Scan local font files (``--local`` flag to luaotfload-tool, flag
``scan_local`` during TeX run).
* Add bisection mode (``--bisect``) to luaotfload-tool.
+ * Add functions for accessing the database: ``aux.font_index()`` and
+ ``aux.read_font_index()``.
2013/12/31, luaotfload v2.4
* Additional self-tests, now in separate file (luaotfload-diagnostics.lua)
diff --git a/doc/luaotfload-latex.tex b/doc/luaotfload-latex.tex
index c886462..34c494d 100644
--- a/doc/luaotfload-latex.tex
+++ b/doc/luaotfload-latex.tex
@@ -34,7 +34,7 @@
\makeatletter
-\usepackage {metalogo,multicol,mdwlist,fancyvrb,xspace}
+\usepackage {metalogo,multicol,fancyvrb,xspace}
\usepackage [x11names] {xcolor}
\def \primarycolor {DodgerBlue4} %%-> rgb 16 78 139 | #104e8b
@@ -244,9 +244,14 @@
\directlua {
local texprint = tex.print
+ local stringsub = string.sub
+ local backslash = string.byte (0x5c)
document = document or { }
document.printlines = function (buffer)
for _, line in next, string.explode (buffer, "\noexpand\n") do
+ if stringsub (line, 1, 1) == " " then
+ line = backslash .. line
+ end
texprint (-1, line)
texprint (-1, "")
end
diff --git a/doc/luaotfload-main.tex b/doc/luaotfload-main.tex
index a0df7f0..034b704 100644
--- a/doc/luaotfload-main.tex
+++ b/doc/luaotfload-main.tex
@@ -877,9 +877,6 @@ rebuild of the database.
\beginlisting
luaotfload-tool --update --force
\endlisting
-Whenever it is run under this name, it will update the database
-first, mimicking the behavior of earlier versions of
-\identifier{luaotfload}.
\endsubsection
@@ -1415,17 +1412,35 @@ are defined for which scripts.
\endsubsubsection
+\beginsubsubsection{Database}
+
%% not implemented, may come back later
-% \beginsubsubsection{Database}
-%
-% \beginfunctionlist
+\beginfunctionlist
% \beginaltitem {aux.scan_external_dir(dir : string)}
% Include fonts in directory \luafunction{dir} in font lookups without
% adding them to the database.
%
-% \endfunctionlist
-%
-% \endsubsubsection
+ \beginaltitem {aux.read_font_index (void)}
+ Read the index file from the appropriate location (usually
+ the bytecode file \fileent{luaotfload-names.luc} somewhere
+ in the \fileent{texmf-var} tree) and return the result as a
+ table. The file is processed with each call so it is up to
+ the user to store the result for later access.
+ \endaltitem
+
+ \beginaltitem {aux.font_index (void)}
+ Return a reference of the font names table used internally
+ by \identifier{luaotfload}. The index will be read if it
+ has not been loaded up to this point. Also a font scan that
+ overwrites the current index file might be triggered. Since
+ the return value points to the actual index, any
+ modifications to the table might influence runtime behavior
+ of \identifier{luaotfload}.
+ \endaltitem
+
+\endfunctionlist
+
+\endsubsubsection
\endsubsection
\endsection
@@ -1443,8 +1458,7 @@ target.
%
The development takes place on \identifier{github} at
\hyperlink {https://github.com/lualatex/luaotfload} where there is an issue
-tracker for submitting bug reports, feature requests and the likes
-requests and the likes.
+tracker for submitting bug reports, feature requests and the likes.
Bug reports are more likely to be addressed if they contain the output
of
diff --git a/scripts/mktests b/scripts/mktests
index 0bf3f64..b36b6dd 100755
--- a/scripts/mktests
+++ b/scripts/mktests
@@ -6,7 +6,7 @@
-- REQUIREMENTS: Luatex > 0.76, Luaotfload
-- AUTHOR: Philipp Gesang (Phg), <phg42.2a@gmail.com>
-- VERSION: 2.4
--- MODIFIED: 2013-08-26 09:31:22+0200
+-- MODIFIED: 2014-05-15 22:16:47+0200
-----------------------------------------------------------------------
--
--===================================================================--
@@ -16,15 +16,9 @@
--===================================================================--
-local tests = { }
-
-config = { luaotfload = {
- names_dir = "names",
- cache_dir = "fonts",
- index_file = "luaotfload-names.lua",
- resolver = "normal",
- update_live = true, --- suppress db updates
-}}
+local tests = { }
+local lpeg = require "lpeg"
+local lpegmatch = lpeg.match
kpse.set_program_name "luatex"
@@ -32,6 +26,7 @@ require "lualibs"
require "luaotfload-basics-gen.lua"
require "luaotfload-log.lua"
require "luaotfload-parsers"
+require "luaotfload-configuration"
require "luaotfload-database"
local names = fonts.names
@@ -66,10 +61,64 @@ local pprint_spec = function (spec)
end
-----------------------------------------------------------------------
---- tool tests
+--- parser tests
-----------------------------------------------------------------------
+local test_config_input = [==[
+
+
+[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 \"\\ # "
+]==]
+
+local test_config_output = {
+ { section = { title = "foo" },
+ variables = { bar = "baz",
+ xyzzy = false,
+ buzz = true } },
+ { section = { title = "lavernica",
+ subtitle = "brutalitops" },
+ variables = { ["laan-ev"] = "zip zop zooey",
+ crouton = "Fibrosis \"\\ # " } }
+}
+
+local parse_config = function ()
+ local parser = luaotfload.parsers.config
+ local result = lpegmatch (parser, test_config_input)
+ --- compare values recursively
+ local aux aux = function (t1, t2)
+ --- cheaply non-tail recursive
+ local k1 = table.keys (t1)
+ local k2 = table.keys (t2)
+ if #k1 ~= #k2 then
+ return false
+ end
+ for i = 1, #k1 do
+ local k = k1[i]
+ local v1 = t1[k]
+ local v2 = t2[k]
+ if type (v1) == "table" then
+ if type (v2) ~= "table" or not aux (v1, v2) then
+ return false
+ end
+ elseif v1 ~= v2 then
+ return false
+ end
+ end
+ return true
+ end
+ return aux (result, test_config_output) and 0 or 1, 1
+end
+
+tests["parse_config"] = parse_config
-----------------------------------------------------------------------
--- font tests
@@ -228,12 +277,14 @@ end
tests ["resolve_font_name"] = resolve_font_name
+
-----------------------------------------------------------------------
--- runner
-----------------------------------------------------------------------
local main = function ()
local failed, total = 0, 0
+ config.actions.apply_defaults ()
for name, test in next, tests do
texio.write_nl ("[" .. name .. "]")
local newfailed, newtotal = test ()
diff --git a/src/luaotfload-auxiliary.lua b/src/luaotfload-auxiliary.lua
index 716af98..89bf51b 100644
--- a/src/luaotfload-auxiliary.lua
+++ b/src/luaotfload-auxiliary.lua
@@ -20,6 +20,7 @@ local log = luaotfload.log
local report = log.report
local fonthashes = fonts.hashes
local identifiers = fonthashes.identifiers
+local fontnames = fonts.names
local fontid = font.id
local texsprint = tex.sprint
@@ -54,7 +55,7 @@ local start_rewrite_fontname = function ()
rewrite_fontname,
"luaotfload.rewrite_fontname")
rewriting = true
- report ("log", 0, "aux",
+ report ("log", 1, "aux",
"start rewriting tfmdata.name field")
end
end
@@ -66,7 +67,7 @@ local stop_rewrite_fontname = function ()
luatexbase.remove_fromt_callback
("luaotfload.patch_font", "luaotfload.rewrite_fontname")
rewriting = false
- report ("log", 0, "aux",
+ report ("log", 1, "aux",
"stop rewriting tfmdata.name field")
end
end
@@ -590,8 +591,8 @@ aux.sprint_math_dimension = sprint_math_dimension
--- extra database functions
-----------------------------------------------------------------------
-local namesresolve = fonts.names.resolve
-local namesscan_dir = fonts.names.scan_dir
+local namesresolve = fontnames.resolve
+local namesscan_dir = fontnames.scan_dir
--[====[-- TODO -> port this to new db model
@@ -663,6 +664,42 @@ end
aux.resolve_fontlist = resolve_fontlist
+--- index access ------------------------------------------------------
+
+--- Based on a discussion on the Luatex mailing list:
+--- http://tug.org/pipermail/luatex/2014-June/004881.html
+
+--[[doc--
+
+ aux.read_font_index -- Read the names index from the canonical
+ location and return its contents. This does not affect the behavior
+ of Luaotfload: The returned table is independent of what the font
+ resolvers use internally. Access is raw: each call to the function
+ will result in the entire table being re-read from disk.
+
+--doc]]--
+
+local load_names = fontnames.load
+local access_font_index = fontnames.access_font_index
+
+local read_font_index = function ()
+ return load_names (true) or { }
+end
+
+--[[doc--
+
+ aux.font_index -- Access Luaotfload’s internal database. If the
+ database hasn’t been loaded yet this will cause it to be loaded, with
+ all the possible side-effects like for instance creating the index
+ file if it doesn’t exist, reading all font files, &c.
+
+--doc]]--
+
+local font_index = function () return access_font_index () end
+
+aux.read_font_index = read_font_index
+aux.font_index = font_index
+
--- loaded fonts ------------------------------------------------------
--- just a proof of concept
diff --git a/src/luaotfload-basics-gen.lua b/src/luaotfload-basics-gen.lua
index 9cf5b93..c19a49a 100644
--- a/src/luaotfload-basics-gen.lua
+++ b/src/luaotfload-basics-gen.lua
@@ -254,6 +254,18 @@ function caches.loaddata(paths,name)
for i=1,#paths do
local data = false
local luaname, lucname = makefullname(paths[i],name)
+ if lucname and not lfs.isfile(lucname) and type(caches.compile) == "function" then
+ -- in case we used luatex and luajittex mixed ... lub or luc file
+ texio.write(string.format("(compiling luc: %s)",lucname))
+ data = loadfile(luaname)
+ if data then
+ data = data()
+ end
+ if data then
+ caches.compile(data,luaname,lucname)
+ return data
+ end
+ end
if lucname and lfs.isfile(lucname) then -- maybe also check for size
texio.write(string.format("(load luc: %s)",lucname))
data = loadfile(lucname)
@@ -341,3 +353,16 @@ end
function table.setmetatableindex(t,f)
setmetatable(t,{ __index = f })
end
+
+-- helper for plain:
+
+arguments = { }
+
+if arg then
+ for i=1,#arg do
+ local k, v = string.match(arg[i],"^%-%-([^=]+)=?(.-)$")
+ if k and v then
+ arguments[k] = v
+ end
+ end
+end
diff --git a/src/luaotfload-basics-nod.lua b/src/luaotfload-basics-nod.lua
index 50a1e86..373dab5 100644
--- a/src/luaotfload-basics-nod.lua
+++ b/src/luaotfload-basics-nod.lua
@@ -54,22 +54,33 @@ nodes.handlers = { }
local nodecodes = { } for k,v in next, node.types () do nodecodes[string.gsub(v,"_","")] = k end
local whatcodes = { } for k,v in next, node.whatsits() do whatcodes[string.gsub(v,"_","")] = k end
local glyphcodes = { [0] = "character", "glyph", "ligature", "ghost", "left", "right" }
+local disccodes = { [0] = "discretionary", "explicit", "automatic", "regular", "first", "second" }
nodes.nodecodes = nodecodes
nodes.whatcodes = whatcodes
nodes.whatsitcodes = whatcodes
nodes.glyphcodes = glyphcodes
+nodes.disccodes = disccodes
local free_node = node.free
local remove_node = node.remove
local new_node = node.new
local traverse_id = node.traverse_id
-local math_code = nodecodes.math
-
nodes.handlers.protectglyphs = node.protect_glyphs
nodes.handlers.unprotectglyphs = node.unprotect_glyphs
+local math_code = nodecodes.math
+local end_of_math = node.end_of_math
+
+function node.end_of_math(n)
+ if n.id == math_code and n.subtype == 1 then
+ return n
+ else
+ return end_of_math(n)
+ end
+end
+
function nodes.remove(head, current, free_too)
local t = current
head, current = remove_node(head,current)
diff --git a/src/luaotfload-colors.lua b/src/luaotfload-colors.lua
index d999df6..56acfee 100644
--- a/src/luaotfload-colors.lua
+++ b/src/luaotfload-colors.lua
@@ -20,7 +20,7 @@ explanation: http://tug.org/pipermail/luatex/2013-May/004305.html
--doc]]--
-local color_callback = config.luaotfload.color_callback
+local color_callback = config.luaotfload.run.color_callback
if not color_callback then
--- maybe this would be better as a method: "early" | "late"
color_callback = "pre_linebreak_filter"
diff --git a/src/luaotfload-configuration.lua b/src/luaotfload-configuration.lua
new file mode 100644
index 0000000..db42f99
--- /dev/null
+++ b/src/luaotfload-configuration.lua
@@ -0,0 +1,536 @@
+#!/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 { }
+config = config or { }
+config.luaotfload = { }
+
+local status_file = "luaotfload-status"
+local luaotfloadstatus = require (status_file)
+
+local string = string
+local stringsub = string.sub
+local stringexplode = string.explode
+
+local table = table
+local tableappend = table.append
+local tablecopy = table.copy
+
+local math = math
+local mathfloor = math.floor
+
+local io = io
+local ioloaddata = io.loaddata
+local iopopen = io.popen
+
+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 filereplacesuffix = file.replacesuffix
+
+
+local parsers = luaotfload.parsers
+
+local log = luaotfload.log
+local logreport = log.report
+
+local config_parser = parsers.config
+local stripslashes = parsers.stripslashes
+
+local getwritablepath = caches.getwritablepath
+
+-------------------------------------------------------------------------------
+--- 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" },
+}
+
+-------------------------------------------------------------------------------
+--- DEFAULTS
+-------------------------------------------------------------------------------
+
+local default_config = {
+ db = {
+ formats = "otf,ttf,ttc,dfont",
+ reload = false,
+ scan_local = false,
+ skip_read = false,
+ strip = true,
+ update_live = true,
+ compress = true,
+ max_fonts = 2^51,
+ },
+ run = {
+ resolver = "cached",
+ definer = "patch",
+ log_level = 0,
+ color_callback = "pre_linebreak_filter",
+ },
+ misc = {
+ bisect = false,
+ version = luaotfload.version,
+ statistics = false,
+ termwidth = nil,
+ },
+ paths = {
+ names_dir = "names",
+ cache_dir = "fonts",
+ index_file = "luaotfload-names.lua",
+ lookups_file = "luaotfload-lookup-cache.lua",
+ lookup_path_lua = nil,
+ lookup_path_luc = nil,
+ index_path_lua = nil,
+ index_path_luc = nil,
+ },
+}
+
+-------------------------------------------------------------------------------
+--- RECONFIGURATION TASKS
+-------------------------------------------------------------------------------
+
+--[[doc--
+
+ Procedures to be executed in order to put the new configuration into effect.
+
+--doc]]--
+
+local reconf_tasks = nil
+
+local min_terminal_width = 40
+
+--- The “termwidth” value is only considered when printing
+--- short status messages, e.g. when building the database
+--- online.
+local check_termwidth = function ()
+ if config.luaotfload.misc.termwidth == nil then
+ local tw = 79
+ if not ( os.type == "windows" --- Assume broken terminal.
+ or osgetenv "TERM" == "dumb")
+ then
+ local p = iopopen "tput cols"
+ if p then
+ result = tonumber (p:read "*all")
+ p:close ()
+ if result then
+ tw = result
+ else
+ logreport ("log", 2, "db", "tput returned non-number.")
+ end
+ else
+ logreport ("log", 2, "db", "Shell escape disabled or tput executable missing.")
+ logreport ("log", 2, "db", "Assuming 79 cols terminal width.")
+ end
+ end
+ config.luaotfload.misc.termwidth = tw
+ end
+ return true
+end
+
+local set_font_filter = function ()
+ local names = fonts.names
+ if names and names.set_font_filter then
+ local formats = config.luaotfload.db.formats
+ if not formats or formats == "" then
+ formats = default_config.db.formats
+ end
+ names.set_font_filter (formats)
+ end
+ return true
+end
+
+local set_name_resolver = function ()
+ local names = fonts.names
+ if names and names.resolve_cached then
+ --- replace the resolver from luatex-fonts
+ if config.luaotfload.db.resolver == "cached" then
+ logreport ("both", 2, "cache", "Caching of name: lookups active.")
+ names.resolvespec = names.resolve_cached
+ else
+ names.resolvespec = names.resolve_name
+ end
+ end
+ return true
+end
+
+local set_loglevel = function ()
+ log.set_loglevel (config.luaotfload.run.log_level)
+ return true
+end
+
+local build_cache_paths = function ()
+ local paths = config.luaotfload.paths
+ local prefix = getwritablepath (paths.names_dir, "")
+
+ if not prefix then
+ luaotfload.error ("Impossible to find a suitable writeable cache...")
+ return false
+ end
+
+ prefix = lpegmatch (stripslashes, prefix)
+ logreport ("log", 0, "conf", "Root cache directory is %s.", prefix)
+
+ local index_file = filejoin (prefix, paths.index_file)
+ local lookups_file = filejoin (prefix, paths.lookups_file)
+
+ paths.prefix = prefix
+ paths.index_path_lua = filereplacesuffix (index_file, "lua")
+ paths.index_path_luc = filereplacesuffix (index_file, "luc")
+ paths.lookup_path_lua = filereplacesuffix (lookups_file, "lua")
+ paths.lookup_path_luc = filereplacesuffix (lookups_file, "luc")
+ return true
+end
+
+reconf_tasks = {
+ { "Set the log level" , set_loglevel },
+ { "Build cache paths" , build_cache_paths },
+ { "Check terminal dimensions" , check_termwidth },
+ { "Set the font filter" , set_font_filter },
+ { "Install font name resolver", set_name_resolver },
+}
+
+-------------------------------------------------------------------------------
+--- OPTION SPECIFICATION
+-------------------------------------------------------------------------------
+
+local string_t = "string"
+local table_t = "table"
+local number_t = "number"
+local boolean_t = "boolean"
+local function_t = "function"
+
+local tointeger = function (n)
+ n = tonumber (n)
+ if n then
+ return mathfloor (n + 0.5)
+ end
+end
+
+local option_spec = {
+ db = {
+ formats = { in_t = string_t, },
+ reload = { in_t = boolean_t, },
+ scan_local = { in_t = boolean_t, },
+ skip_read = { in_t = boolean_t, },
+ strip = { in_t = boolean_t, },
+ update_live = { in_t = boolean_t, },
+ compress = { in_t = boolean_t, },
+ max_fonts = {
+ in_t = number_t,
+ out_t = number_t, --- TODO int_t from 5.3.x on
+ transform = tointeger,
+ },
+ },
+ run = {
+ resolver = {
+ in_t = string_t,
+ out_t = string_t,
+ transform = function (r) return r == "normal" and r or "cached" end,
+ },
+ definer = {
+ in_t = string_t,
+ out_t = string_t,
+ transform = function (d) return d == "generic" and d or "patch" end,
+ },
+ log_level = {
+ in_t = number_t,
+ out_t = number_t, --- TODO int_t from 5.3.x on
+ transform = tointeger,
+ },
+ color_callback = {
+ in_t = string_t,
+ out_t = string_t,
+ transform = function (cb)
+ --- These are the two that make sense.
+ return cb == "pre_output_filter" and cb or "pre_linebreak_filter"
+ end,
+ },
+ },
+ misc = {
+ bisect = { in_t = boolean_t, }, --- doesn’t make sense in a config file
+ version = { in_t = string_t, },
+ statistics = { in_t = boolean_t, },
+ termwidth = {
+ in_t = number_t,
+ out_t = number_t,
+ transform = function (w)
+ w = tointeger (w)
+ if w < min_terminal_width then
+ return min_terminal_width
+ end
+ return w
+ end,
+ },
+ },
+ paths = {
+ names_dir = { in_t = string_t, },
+ cache_dir = { in_t = string_t, },
+ index_file = { in_t = string_t, },
+ lookups_file = { in_t = string_t, },
+ lookup_path_lua = { in_t = string_t, },
+ lookup_path_luc = { in_t = string_t, },
+ index_path_lua = { in_t = string_t, },
+ index_path_luc = { in_t = string_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 ()
+ 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 = tableappend (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 apply
+apply = function (old, new)
+ if not new then
+ if not old then
+ return false
+ end
+ return tablecopy (old)
+ elseif not old then
+ return tablecopy (new)
+ end
+ local result = tablecopy (old)
+ for name, section in next, new do
+ local t_section = type (section)
+ if t_section ~= table_t then
+ logreport ("both", 1, "conf",
+ "Error applying configuration: entry %s is %s, expected table.",
+ section, t_section)
+ --- ignore
+ else
+ local currentsection = result[name]
+ for var, val in next, section do
+ currentsection[var] = val
+ end
+ end
+ end
+ result.status = luaotfloadstatus
+ return result
+end
+
+local reconfigure = function ()
+ for i = 1, #reconf_tasks do
+ local name, task = unpack (reconf_tasks[i])
+ logreport ("both", 3, "conf", "Launch post-configuration task %q.", name)
+ if not task () then
+ logreport ("both", 0, "conf", "Post-configuration task %q failed.", name)
+ return false
+ end
+ end
+ return true
+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
+
+local apply_defaults = function ()
+ local defaults = default_config
+ local vars = read ()
+ --- Side-effects galore ...
+ config.luaotfload = apply (defaults, vars)
+ return reconfigure ()
+end
+
+-------------------------------------------------------------------------------
+--- EXPORTS
+-------------------------------------------------------------------------------
+
+luaotfload.default_config = default_config
+
+config.actions = {
+ read = read,
+ apply = apply,
+ apply_defaults = apply_defaults,
+ reconfigure = reconfigure,
+}
+
diff --git a/src/luaotfload-database.lua b/src/luaotfload-database.lua
index dc783d8..e171c52 100644
--- a/src/luaotfload-database.lua
+++ b/src/luaotfload-database.lua
@@ -119,7 +119,6 @@ local tablefastcopy = table.fastcopy
local tabletofile = table.tofile
local tabletohash = table.tohash
local tableserialize = table.serialize
-local runasscript = caches == nil
--- the font loader namespace is “fonts”, same as in Context
--- we need to put some fallbacks into place for when running
--- as a script
@@ -127,16 +126,6 @@ fonts = fonts or { }
fonts.names = fonts.names or { }
fonts.definers = fonts.definers or { }
-local luaotfloadconfig = config.luaotfload --- always present
-luaotfloadconfig.resolver = luaotfloadconfig.resolver or "normal"
-luaotfloadconfig.formats = luaotfloadconfig.formats or "otf,ttf,ttc,dfont"
-luaotfloadconfig.strip = luaotfloadconfig.strip == true
-
---- this option allows for disabling updates
---- during a TeX run
-luaotfloadconfig.update_live = luaotfloadconfig.update_live ~= false
-luaotfloadconfig.compress = luaotfloadconfig.compress ~= false
-
local names = fonts.names
local name_index = nil --> upvalue for names.data
local lookup_cache = nil --> for names.lookups
@@ -144,46 +133,12 @@ names.version = 2.51
names.data = nil --- contains the loaded database
names.lookups = nil --- contains the lookup cache
-names.path = { index = { }, lookups = { } }
-names.path.globals = {
- prefix = "", --- writable_path/names_dir
- names_dir = luaotfloadconfig.names_dir or "names",
- index_file = luaotfloadconfig.index_file
- or "luaotfload-names.lua",
- lookups_file = "luaotfload-lookup-cache.lua",
-}
-
--- string -> (string * string)
local make_luanames = function (path)
return filereplacesuffix(path, "lua"),
filereplacesuffix(path, "luc")
end
---- The “termwidth” value is only considered when printing
---- short status messages, e.g. when building the database
---- online.
-if not luaotfloadconfig.termwidth then
- local tw = 79
- if not ( os.type == "windows" --- Assume broken terminal.
- or osgetenv "TERM" == "dumb")
- then
- local p = iopopen "tput cols"
- if p then
- result = tonumber (p:read "*all")
- p:close ()
- if result then
- tw = result
- else
- report ("log", 2, "db", "tput returned non-number.")
- end
- else
- report ("log", 2, "db", "Shell escape disabled or tput executable missing.")
- report ("log", 2, "db", "Assuming 79 cols terminal width.")
- end
- end
- luaotfloadconfig.termwidth = tw
-end
-
local format_precedence = {
"otf", "ttc", "ttf",
"dfont", "afm", "pfb",
@@ -199,51 +154,9 @@ local set_location_precedence = function (precedence)
end
--[[doc--
- We use the functions in the cache.* namespace that come with the
- fontloader (see luat-basics-gen). it’s safe to use for the most part
- since most checks and directory creations are already done. It
- uses TEXMFCACHE or TEXMFVAR as starting points.
-
- There is one quirk, though: ``getwritablepath()`` will always
- assume that files in subdirectories of the cache tree are writable.
- It gives no feedback at all if it fails to open a file in write
- mode. This may cause trouble when the index or lookup cache were
- created by different user.
---doc]]--
-
-if not runasscript then
- local globals = names.path.globals
- local names_dir = globals.names_dir
- prefix = getwritablepath (names_dir, "")
- if not prefix then
- luaotfload.error
- ("Impossible to find a suitable writeable cache...")
- else
- prefix = lpegmatch (stripslashes, prefix)
- report ("log", 0, "db",
- "Root cache directory is %s.", prefix)
- end
+ Auxiliary functions
- globals.prefix = prefix
- local lookup_path = names.path.lookups
- local index = names.path.index
- local lookups_file = filejoin (prefix, globals.lookups_file)
- local index_file = filejoin (prefix, globals.index_file)
- lookup_path.lua, lookup_path.luc = make_luanames (lookups_file)
- index.lua, index.luc = make_luanames (index_file)
-else --- running as script, inject some dummies
- caches = { }
- local dummy_function = function () end
- log = { report = dummy_function,
- report_status = dummy_function,
- report_status_start = dummy_function,
- report_status_stop = dummy_function, }
-end
-
-
---[[doc--
-Auxiliary functions
--doc]]--
--- fontnames contain all kinds of garbage; as a precaution we
@@ -355,8 +268,10 @@ This is a sketch of the luaotfload db:
optical : (int, int) list; // design size -> index entry
}
and metadata = {
- local : bool; (* set if local fonts were added to the db *)
+ created : string // creation time
formats : string list; // { "otf", "ttf", "ttc", "dfont" }
+ local : bool; (* set if local fonts were added to the db *)
+ modified : string // modification time
statistics : TODO; // created when built with "--stats"
version : float; // index version
}
@@ -439,9 +354,10 @@ mtx-fonts has in names.tma:
--doc]]--
---- string list -> dbobj
+--- string list -> string option -> dbobj
-local initialize_namedata = function (formats)
+local initialize_namedata = function (formats, created)
+ local now = os.date "%F %T"
return {
--families = { },
status = { }, -- was: status; map abspath -> mapping
@@ -449,8 +365,10 @@ local initialize_namedata = function (formats)
names = { },
-- files = { }, -- created later
meta = {
- ["local"] = false,
+ created = created or now,
formats = formats,
+ ["local"] = false,
+ modified = now,
statistics = { },
version = names.version,
},
@@ -534,6 +452,7 @@ local load_lua_file = function (path)
end
--- define locals in scope
+local access_font_index
local collect_families
local crude_file_lookup
local crude_file_lookup_verbose
@@ -544,6 +463,7 @@ local get_font_filter
local group_modifiers
local load_lookups
local load_names
+local getmetadata
local order_design_sizes
local ot_fullinfo
local read_blacklist
@@ -566,11 +486,13 @@ local fuzzy_limit = 1 --- display closest only
--- bool? -> dbobj
load_names = function (dry_run)
local starttime = osgettimeofday ()
- local foundname, data = load_lua_file (names.path.index.lua)
+ local foundname, data = load_lua_file (config.luaotfload.paths.index_path_lua)
if data then
- report ("both", 2, "db",
- "Font names database loaded", "%s", foundname)
+ report ("log", 0, "db",
+ "Font names database loaded from %s", foundname)
+ report ("term", 3, "db",
+ "Font names database loaded from %s", foundname)
report ("info", 3, "db", "Loading took %0.f ms.",
1000 * (osgettimeofday () - starttime))
@@ -611,11 +533,29 @@ load_names = function (dry_run)
return data
end
+--[[doc--
+
+ access_font_index -- Provide a reference of the index table. Will
+ cause the index to be loaded if not present.
+
+--doc]]--
+
+access_font_index = function ()
+ if not name_index then name_index = load_names () end
+ return name_index
+end
+
+getmetadata = function ()
+ if not name_index then name_index = load_names() end
+ return tablefastcopy (name_index.meta)
+end
+
--- unit -> unit
load_lookups = function ( )
- local foundname, data = load_lua_file(names.path.lookups.lua)
+ local foundname, data = load_lua_file(config.luaotfload.paths.lookup_path_lua)
if data then
- report("both", 3, "cache",
+ report("log", 0, "cache", "Lookup cache loaded from %s.", foundname)
+ report("term", 3, "cache",
"Lookup cache loaded from %s.", foundname)
else
report("both", 1, "cache",
@@ -650,7 +590,7 @@ local style_category = {
i = "italic",
}
-local type1_formats = { "tfm", "ofm", }
+local type1_metrics = { "tfm", "ofm", }
local dummy_findfile = resolvers.findfile -- from basics-gen
@@ -692,12 +632,18 @@ crude_file_lookup_verbose = function (filename)
end
--- ofm and tfm, returns pair
- for i=1, #type1_formats do
- local format = type1_formats[i]
+ for i=1, #type1_metrics do
+ local format = type1_metrics[i]
if resolvers.findfile(filename, format) then
return file.addsuffix(filename, format), format, true
end
end
+
+ if not fonts_reloaded and config.luaotfload.db.update_live == true then
+ return reload_db (stringformat ("File not found: %s.", filename),
+ crude_file_lookup_verbose,
+ filename)
+ end
return filename, nil, false
end
@@ -748,13 +694,18 @@ crude_file_lookup = function (filename)
return found, nil, true
end
- for i=1, #type1_formats do
- local format = type1_formats[i]
+ for i=1, #type1_metrics do
+ local format = type1_metrics[i]
if resolvers.findfile(filename, format) then
return file.addsuffix(filename, format), format, true
end
end
+ if not fonts_reloaded and config.luaotfload.db.update_live == true then
+ return reload_db (stringformat ("File not found: %s.", filename),
+ crude_file_lookup_verbose,
+ filename)
+ end
return filename, nil, false
end
@@ -1171,8 +1122,9 @@ resolve_name = function (specification)
end
if not resolved then
- if not fonts_reloaded then
- return reload_db ("Font not found.",
+ if not fonts_reloaded and config.luaotfload.db.update_live == true then
+ return reload_db (stringformat ("Font %s not found.",
+ specification.name or "<?>"),
resolve_name,
specification)
end
@@ -1213,7 +1165,7 @@ reload_db = function (why, caller, ...)
local namedata = name_index
local formats = tableconcat (namedata.meta.formats, ",")
- report ("both", 1, "db",
+ report ("both", 0, "db",
"Reload initiated (formats: %s); reason: %q.",
formats, why)
@@ -1265,7 +1217,7 @@ find_closest = function (name, limit)
if not name_index then name_index = load_names () end
if not name_index or type (name_index) ~= "table" then
if not fonts_reloaded then
- return reload_db("no database", find_closest, name)
+ return reload_db("Font index missing.", find_closest, name)
end
return false
end
@@ -2072,9 +2024,6 @@ do
get_font_filter = function (formats)
return tablefastcopy (current_formats)
end
-
- --- initialize
- set_font_filter (luaotfloadconfig.formats)
end
local process_dir_tree
@@ -2177,7 +2126,7 @@ end
--- indicates the number of characters already consumed on the
--- line.
local truncate_string = function (str, restrict)
- local tw = luaotfloadconfig.termwidth
+ local tw = config.luaotfload.misc.termwidth
local wd = tw - restrict
local len = utf8len (str)
if wd - len < 0 then
@@ -2670,7 +2619,7 @@ local pull_values = function (entry)
entry.splitstyle = style.split
entry.weight = style.weight
- if luaotfloadconfig.strip == true then
+ if config.luaotfload.db.strip == true then
entry.file = nil
entry.names = nil
entry.style = nil
@@ -2789,7 +2738,7 @@ end
--[[doc--
- add_bold_spectrum -- For not-quite-bold faces, determine whether
+ group_modifiers -- For not-quite-bold faces, determine whether
they can fill in for a missing bold face slot in a matching family.
Some families like Lucida do not contain real bold / bold italic
@@ -2931,12 +2880,12 @@ local collect_font_filenames = function ()
report ("info", 4, "db", "Scanning the filesystem for font files.")
local filenames = { }
- local bisect = luaotfloadconfig.bisect
- local max_fonts = luaotfloadconfig.max_fonts or 2^51 --- XXX revisit for lua 5.3 wrt integers
+ local bisect = config.luaotfload.misc.bisect
+ local max_fonts = config.luaotfload.db.max_fonts --- XXX revisit for lua 5.3 wrt integers
tableappend (filenames, collect_font_filenames_texmf ())
tableappend (filenames, collect_font_filenames_system ())
- if luaotfloadconfig.scan_local == true then
+ if config.luaotfload.db.scan_local == true then
tableappend (filenames, collect_font_filenames_local ())
end
--- Now drop everything above max_fonts.
@@ -3175,7 +3124,7 @@ end
update_names = function (currentnames, force, dry_run)
local targetnames
- if luaotfloadconfig.update_live == false then
+ if config.luaotfload.db.update_live == false then
report ("info", 2, "db",
"Skipping database update.")
--- skip all db updates
@@ -3192,7 +3141,7 @@ update_names = function (currentnames, force, dry_run)
report("both", 1, "db", "Updating the font names database"
.. (force and " forcefully." or "."))
- if luaotfloadconfig.skip_read == true then
+ if config.luaotfload.db.skip_read == true then
--- the difference to a “dry run” is that we don’t search
--- for font files entirely. we also ignore the “force”
--- parameter since it concerns only the font files.
@@ -3214,7 +3163,8 @@ update_names = function (currentnames, force, dry_run)
end
end
- targetnames = initialize_namedata (get_font_filter ())
+ targetnames = initialize_namedata (get_font_filter (),
+ currentnames.meta and currentnames.meta.created)
read_blacklist ()
@@ -3234,7 +3184,7 @@ update_names = function (currentnames, force, dry_run)
end
--- pass 3 (optional): collect some stats about the raw font info
- if luaotfloadconfig.statistics == true then
+ if config.luaotfload.misc.statistics == true then
targetnames.meta.statistics = collect_statistics
(targetnames.mappings)
end
@@ -3285,8 +3235,8 @@ end
--- unit -> bool
save_lookups = function ( )
- local path = names.path.lookups
- local luaname, lucname = path.lua, path.luc
+ local paths = config.luaotfload.paths
+ local luaname, lucname = paths.lookup_path_lua, paths.lookup_path_luc
if fileiswritable (luaname) and fileiswritable (lucname) then
tabletofile (luaname, lookup_cache, true)
osremove (lucname)
@@ -3320,12 +3270,12 @@ save_names = function (currentnames)
elseif currentnames.meta and currentnames.meta["local"] then
return false, "table contains local entries"
end
- local path = names.path.index
- local luaname, lucname = path.lua, path.luc
+ local paths = config.luaotfload.paths
+ local luaname, lucname = paths.index_path_lua, paths.index_path_luc
if fileiswritable (luaname) and fileiswritable (lucname) then
osremove (lucname)
local gzname = luaname .. ".gz"
- if luaotfloadconfig.compress then
+ if config.luaotfload.db.compress then
local serialized = tableserialize (currentnames, true)
save_gzipped (gzname, serialized)
caches.compile (currentnames, "", lucname)
@@ -3443,7 +3393,7 @@ end
local getwritablecachepath = function ( )
--- fonts.handlers.otf doesn’t exist outside a Luatex run,
--- so we have to improvise
- local writable = getwritablepath (luaotfloadconfig.cache_dir)
+ local writable = getwritablepath (config.luaotfload.paths.cache_dir)
if writable then
return writable
end
@@ -3451,7 +3401,7 @@ end
local getreadablecachepaths = function ( )
local readables = caches.getreadablepaths
- (luaotfloadconfig.cache_dir)
+ (config.luaotfload.paths.cache_dir)
local result = { }
if readables then
for i=1, #readables do
@@ -3520,6 +3470,7 @@ names.set_font_filter = set_font_filter
names.flush_lookup_cache = flush_lookup_cache
names.save_lookups = save_lookups
names.load = load_names
+names.access_font_index = access_font_index
names.data = function () return name_index end
names.save = save_names
names.update = update_names
@@ -3528,26 +3479,19 @@ names.crude_file_lookup_verbose = crude_file_lookup_verbose
names.read_blacklist = read_blacklist
names.sanitize_fontname = sanitize_fontname
names.getfilename = resolve_fullpath
+names.getmetadata = getmetadata
names.set_location_precedence = set_location_precedence
names.count_font_files = count_font_files
names.nth_font_filename = nth_font_filename
names.font_slice = font_slice
+names.resolve_cached = resolve_cached
+names.resolve_name = resolve_name
--- font cache
names.purge_cache = purge_cache
names.erase_cache = erase_cache
names.show_cache = show_cache
---- replace the resolver from luatex-fonts
-if luaotfloadconfig.resolver == "cached" then
- report("both", 2, "cache", "Caching of name: lookups active.")
- names.resolvespec = resolve_cached
- names.resolve_name = resolve_cached
-else
- names.resolvespec = resolve_name
- names.resolve_name = resolve_name
-end
-
names.find_closest = find_closest
-- for testing purpose
diff --git a/src/luaotfload-diagnostics.lua b/src/luaotfload-diagnostics.lua
index 67119de..d9b13f5 100644
--- a/src/luaotfload-diagnostics.lua
+++ b/src/luaotfload-diagnostics.lua
@@ -9,8 +9,6 @@
-----------------------------------------------------------------------
--
local names = fonts.names
-local luatexstatus = status
-local status = config.luaotfload.status
local kpse = require "kpse"
local kpseexpand_path = kpse.expand_path
@@ -99,8 +97,9 @@ local check_index = function (errcnt)
return errcnt
end
-local verify_files = function (errcnt, status)
+local verify_files = function (errcnt)
out "================ verify files ================="
+ local status = config.luaotfload.status
local hashes = status.hashes
local notes = status.notes
if not hashes or #hashes == 0 then
@@ -241,19 +240,23 @@ local check_conformance = function (spec, permissions, errcnt)
return errcnt
end
-local path = names.path
-
-local desired_permissions = {
- { "d", {"r","w"}, function () return caches.getwritablepath () end },
- { "d", {"r","w"}, path.globals.prefix },
- { "f", {"r","w"}, path.index.lua .. ".gz" },
- { "f", {"r","w"}, path.index.luc },
- { "f", {"r","w"}, path.lookups.lua },
- { "f", {"r","w"}, path.lookups.luc },
-}
+local desired_permissions
+local init_desired_permissions = function ()
+ inspect(config.luaotfload.paths)
+ local paths = config.luaotfload.paths
+ desired_permissions = {
+ { "d", {"r","w"}, function () return caches.getwritablepath () end },
+ { "d", {"r","w"}, paths.prefix },
+ { "f", {"r","w"}, paths.index_path_lua .. ".gz" },
+ { "f", {"r","w"}, paths.index_path_luc },
+ { "f", {"r","w"}, paths.lookup_path_lua },
+ { "f", {"r","w"}, paths.lookup_path_luc },
+ }
+end
local check_permissions = function (errcnt)
out [[=============== file permissions ==============]]
+ if not desired_permissions then init_desired_permissions () end
for i = 1, #desired_permissions do
local t, spec, path = unpack (desired_permissions[i])
if type (path) == "function" then
@@ -337,8 +340,7 @@ else
end
out ("Requesting <%s>.", request)
- local response, code, headers, status
- = https.request (request)
+ local response, code, headers, status = https.request (request)
if status ~= alright then
out "Request failed!"
return false
@@ -629,7 +631,7 @@ local diagnose = function (job)
end
if asked.files == true then
- errcnt = verify_files (errcnt, status)
+ errcnt = verify_files (errcnt)
asked.files = nil
end
diff --git a/src/luaotfload-features.lua b/src/luaotfload-features.lua
index 4237d71..4ad188f 100644
--- a/src/luaotfload-features.lua
+++ b/src/luaotfload-features.lua
@@ -6,7 +6,8 @@ if not modules then modules = { } end modules ["features"] = {
license = "see context related readme files"
}
-local type, next = type, next
+local type = type
+local next = next
local tonumber = tonumber
local tostring = tostring
@@ -16,6 +17,11 @@ local P = lpeg.P
local R = lpeg.R
local C = lpeg.C
+local table = table
+local tabletohash = table.tohash
+local setmetatableindex = table.setmetatableindex
+local insert = table.insert
+
---[[ begin included font-ltx.lua ]]
--- this appears to be based in part on luatex-fonts-def.lua
@@ -755,7 +761,7 @@ local verbosebaselines = swapped(baselines)
--doc]]--
-local support_incomplete = table.tohash({
+local support_incomplete = tabletohash({
"deva", "beng", "guru", "gujr",
"orya", "taml", "telu", "knda",
"mlym", "sinh",
@@ -802,13 +808,13 @@ local set_default_features = function (speclist)
end
speclist.script = script
- report("log", 0, "load",
+ report("log", 1, "load",
"auto-selecting default features for script: %s",
script)
local requested = defaults[script]
if not requested then
- report("log", 0, "load",
+ report("log", 1, "load",
"no defaults for script %q, falling back to \"dflt\"",
script)
requested = defaults.dflt
@@ -983,7 +989,6 @@ local report_otf = logs.reporter("fonts","otf loading")
local otf = fonts.handlers.otf
local registerotffeature = otf.features.register
-local setmetatableindex = table.setmetatableindex
--[[HH--
@@ -1039,6 +1044,7 @@ local function addfeature(data,feature,specifications)
local subtables = specification.subtables or { specification.data } or { }
local featuretype = types[specification.type or "substitution"]
local featureflags = specification.flags or noflags
+ local featureorder = specification.order or { feature }
local added = false
local featurename = stringformat("ctx_%s_%s",feature,s)
local st = { }
@@ -1099,17 +1105,23 @@ local function addfeature(data,feature,specifications)
-- script = { lang1, lang2, lang3 } or script = { lang1 = true, ... }
for k, v in next, askedfeatures do
if v[1] then
- askedfeatures[k] = table.tohash(v)
+ askedfeatures[k] = tabletohash(v)
end
end
- sequences[#sequences+1] = {
+ local sequence = {
chain = 0,
features = { [feature] = askedfeatures },
flags = featureflags,
name = featurename,
+ order = featureorder,
subtables = st,
type = featuretype,
}
+ if specification.prepend then
+ insert(sequences,1,sequence)
+ else
+ insert(sequences,sequence)
+ end
-- register in metadata (merge as there can be a few)
if not gsubfeatures then
gsubfeatures = { }
@@ -1139,6 +1151,7 @@ local function addfeature(data,feature,specifications)
end
end
+
otf.enhancers.addfeature = addfeature
local extrafeatures = { }
@@ -1167,6 +1180,8 @@ local tlig = {
[0x0060] = 0x2018, -- quoteright
},
flags = { },
+ order = { "tlig" },
+ prepend = true,
},
{
type = "ligature",
@@ -1185,6 +1200,8 @@ local tlig = {
[0x00BB] = {0x003E, 0x003E}, -- RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK
},
flags = { },
+ order = { "tlig" },
+ prepend = true,
},
{
type = "ligature",
@@ -1196,6 +1213,8 @@ local tlig = {
[0x00BF] = {0x003F, 0x0060}, -- questiondown
},
flags = { },
+ order = { "tlig" },
+ prepend = true,
},
}
@@ -1247,6 +1266,7 @@ local anum_specification = {
features = { arab = { far = true, urd = true, snd = true } },
data = anum_persian,
flags = { },
+ order = { "anum" },
valid = valid,
},
{
@@ -1254,23 +1274,16 @@ local anum_specification = {
features = { arab = { ["*"] = true } },
data = anum_arabic,
flags = { },
+ order = { "anum" },
valid = valid,
},
}
---[[doc--
-
- Below the specifications as given in the removed font-otc.lua.
- The rest was identical to what this file had from the beginning.
- Both make the “anum.tex” test pass anyways.
-
---doc]]--
-
-otf.addfeature("anum",anum_specification)
+otf.addfeature ("anum", anum_specification)
registerotffeature {
- name = 'anum',
- description = 'arabic digits',
+ name = "anum",
+ description = "arabic digits",
}
-- vim:tw=71:sw=4:ts=4:expandtab
diff --git a/src/luaotfload-fontloader.lua b/src/luaotfload-fontloader.lua
index d4311b2..1732a23 100644
--- a/src/luaotfload-fontloader.lua
+++ b/src/luaotfload-fontloader.lua
@@ -1,6 +1,6 @@
-- merged file : luatex-fonts-merged.lua
-- parent file : luatex-fonts.lua
--- merge date : 04/15/14 09:51:32
+-- merge date : 05/30/14 23:26:41
do -- begin closure to overcome local limits and interference
@@ -125,7 +125,7 @@ local uppercase=R("AZ")
local underscore=P("_")
local hexdigit=digit+lowercase+uppercase
local cr,lf,crlf=P("\r"),P("\n"),P("\r\n")
-local newline=crlf+S("\r\n")
+local newline=P("\r")*(P("\n")+P(true))+P("\n")
local escaped=P("\\")*anything
local squote=P("'")
local dquote=P('"')
@@ -147,8 +147,8 @@ patterns.utfbom_32_le=utfbom_32_le
patterns.utfbom_16_be=utfbom_16_be
patterns.utfbom_16_le=utfbom_16_le
patterns.utfbom_8=utfbom_8
-patterns.utf_16_be_nl=P("\000\r\000\n")+P("\000\r")+P("\000\n")
-patterns.utf_16_le_nl=P("\r\000\n\000")+P("\r\000")+P("\n\000")
+patterns.utf_16_be_nl=P("\000\r\000\n")+P("\000\r")+P("\000\n")
+patterns.utf_16_le_nl=P("\r\000\n\000")+P("\r\000")+P("\n\000")
patterns.utf8one=R("\000\127")
patterns.utf8two=R("\194\223")*utf8next
patterns.utf8three=R("\224\239")*utf8next*utf8next
@@ -2851,9 +2851,13 @@ local format_f=function(f)
n=n+1
return format("format('%%%sf',a%s)",f,n)
end
-local format_F=function(f)
+local format_F=function()
n=n+1
- return format("((a%s == 0 and '0') or (a%s == 1 and '1') or format('%%%sf',a%s))",n,n,f,n)
+ if not f or f=="" then
+ return format("(((a%s > -0.0000000005 and a%s < 0.0000000005) and '0') or format((a%s %% 1 == 0) and '%%i' or '%%.9f',a%s))",n,n,n,n)
+ else
+ return format("format((a%s %% 1 == 0) and '%%i' or '%%%sf',a%s)",n,f,n)
+ end
end
local format_g=function(f)
n=n+1
@@ -3460,6 +3464,15 @@ end
function table.setmetatableindex(t,f)
setmetatable(t,{ __index=f })
end
+arguments={}
+if arg then
+ for i=1,#arg do
+ local k,v=string.match(arg[i],"^%-%-([^=]+)=?(.-)$")
+ if k and v then
+ arguments[k]=v
+ end
+ end
+end
end -- closure
@@ -4170,6 +4183,7 @@ function constructors.scale(tfmdata,specification)
if changed then
local c=changed[unicode]
if c then
+ local ligatures=character.ligatures
description=descriptions[c] or descriptions[unicode] or character
character=characters[c] or character
index=description.index or c
@@ -4181,6 +4195,9 @@ function constructors.scale(tfmdata,specification)
touni=tounicode[i]
end
end
+ if ligatures and not character.ligatures then
+ character.ligatures=ligatures
+ end
else
description=descriptions[unicode] or character
index=description.index or unicode
@@ -4858,6 +4875,7 @@ end
local fonts=fonts
fonts.encodings={}
fonts.encodings.agl={}
+fonts.encodings.known={}
setmetatable(fonts.encodings.agl,{ __index=function(t,k)
if k=="unicodes" then
texio.write(" <loading (extended) adobe glyph list>")
@@ -8542,13 +8560,14 @@ local function gref(descriptions,n)
return f_unicode(n)
end
elseif n then
- local num,nam={},{}
- for i=2,#n do
+ local num,nam,j={},{},0
+ for i=1,#n do
local ni=n[i]
if tonumber(ni) then
+ j=j+1
local di=descriptions[ni]
- num[i]=f_unicode(ni)
- nam[i]=di and di.name or "-"
+ num[j]=f_unicode(ni)
+ nam[j]=di and di.name or "-"
end
end
return f_unilist(num,nam)
@@ -8631,8 +8650,8 @@ local function finalize_ligatures(tfmdata,ligatures)
local ligature=ligatures[i]
if ligature then
local unicode,lookupdata=ligature[1],ligature[2]
- if trace then
- trace_ligatures_detail("building % a into %a",lookupdata,unicode)
+ if trace_ligatures_detail then
+ report_prepare("building % a into %a",lookupdata,unicode)
end
local size=#lookupdata
local firstcode=lookupdata[1]
@@ -8644,8 +8663,8 @@ local function finalize_ligatures(tfmdata,ligatures)
local firstdata=characters[firstcode]
if not firstdata then
firstcode=private
- if trace then
- trace_ligatures_detail("defining %a as %a",firstname,firstcode)
+ if trace_ligatures_detail then
+ report_prepare("defining %a as %a",firstname,firstcode)
end
unicodes[firstname]=firstcode
firstdata={ intermediate=true,ligatures={} }
@@ -8668,8 +8687,8 @@ local function finalize_ligatures(tfmdata,ligatures)
break
end
end
- if trace then
- trace_ligatures_detail("codes (%a,%a) + (%a,%a) -> %a",firstname,firstcode,secondname,secondcode,target)
+ if trace_ligatures_detail then
+ report_prepare("codes (%a,%a) + (%a,%a) -> %a",firstname,firstcode,secondname,secondcode,target)
end
local firstligs=firstdata.ligatures
if firstligs then
@@ -8680,6 +8699,8 @@ local function finalize_ligatures(tfmdata,ligatures)
firstcode=target
firstname=secondname
end
+ elseif trace_ligatures_detail then
+ report_prepare("no glyph (%a,%a) for building %a",firstname,firstcode,target)
end
if okay then
ligatures[i]=false
@@ -8689,12 +8710,14 @@ local function finalize_ligatures(tfmdata,ligatures)
end
alldone=done==0
end
- if trace then
- for k,v in next,characters do
- if v.ligatures then table.print(v,k) end
+ if trace_ligatures_detail then
+ for k,v in table.sortedhash(characters) do
+ if v.ligatures then
+ table.print(v,k)
+ end
end
end
- tfmdata.resources.private=private
+ resources.private=private
end
end
local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplist)
@@ -8913,7 +8936,7 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis
end
changed[unicode]=data
elseif lookuptype=="alternate" then
- local replacement=data[alternate]
+ local replacement=data[alternate]
if replacement then
changed[unicode]=replacement
if trace_alternatives then
diff --git a/src/luaotfload-main.lua b/src/luaotfload-main.lua
index fe4e792..4baa225 100644
--- a/src/luaotfload-main.lua
+++ b/src/luaotfload-main.lua
@@ -43,32 +43,14 @@ if not modules then modules = { } end modules ["luaotfload-main"] = {
--doc]]--
+local initial_log_level = 0
+
luaotfload = luaotfload or { }
local luaotfload = luaotfload
luaotfload.log = luaotfload.log or { }
-config = config or { }
-config.luaotfload = config.luaotfload or { }
-local luaotfloadconfig = config.luaotfload
-----------------.resolver = luaotfloadconfig.resolver or "normal"
-luaotfloadconfig.resolver = luaotfloadconfig.resolver or "cached"
-luaotfloadconfig.definer = luaotfloadconfig.definer or "patch"
-luaotfloadconfig.bisect = false --- useless when running TeX
-luaotfloadconfig.loglevel = luaotfloadconfig.loglevel or 2
-luaotfloadconfig.color_callback = luaotfloadconfig.color_callback or "pre_linebreak_filter"
-luaotfloadconfig.prioritize = luaotfloadconfig.prioritize or "sys"
-luaotfloadconfig.names_dir = luaotfloadconfig.names_dir or "names"
-luaotfloadconfig.cache_dir = luaotfloadconfig.cache_dir or "fonts"
-luaotfloadconfig.index_file = luaotfloadconfig.index_file or "luaotfload-names.lua"
-luaotfloadconfig.formats = luaotfloadconfig.formats or "otf,ttf,ttc,dfont"
-luaotfloadconfig.scan_local = luaotfloadconfig.scan_local == true
-
-if luaotfloadconfig.strip == nil then
- luaotfloadconfig.strip = true
-end
-
luaotfload.module = {
- name = "luaotfload",
+ name = "luaotfload-main",
version = 2.50000,
date = "2014/**/**",
description = "OpenType layout system.",
@@ -81,16 +63,17 @@ local luatexbase = luatexbase
local setmetatable = setmetatable
local type, next = type, next
+local stringlower = string.lower
local kpsefind_file = kpse.find_file
local lfsisfile = lfs.isfile
-local add_to_callback, create_callback =
- luatexbase.add_to_callback, luatexbase.create_callback
-local reset_callback, call_callback =
- luatexbase.reset_callback, luatexbase.call_callback
+local add_to_callback = luatexbase.add_to_callback
+local create_callback = luatexbase.create_callback
+local reset_callback = luatexbase.reset_callback
+local call_callback = luatexbase.call_callback
-local dummy_function = function () end
+local dummy_function = function () end --- XXX this will be moved to the luaotfload namespace when we have the init module
local error, warning, info, log =
luatexbase.provides_module(luaotfload.module)
@@ -116,18 +99,18 @@ luaotfload.log.tex = {
--doc]]--
-local luatex_version = 76
+local min_luatex_version = 76
-if tex.luatexversion < luatex_version then
- warning("LuaTeX v%.2f is old, v%.2f is recommended.",
- tex.luatexversion/100,
- luatex_version /100)
+if tex.luatexversion < min_luatex_version then
+ warning ("LuaTeX v%.2f is old, v%.2f or later is recommended.",
+ tex.luatexversion / 100,
+ min_luatex_version / 100)
--- we install a fallback for older versions as a safety
if not node.end_of_math then
- local math_t = node.id"math"
+ local math_t = node.id "math"
local traverse_nodes = node.traverse_id
node.end_of_math = function (n)
- for n in traverse_nodes(math_t, n.next) do
+ for n in traverse_nodes (math_t, n.next) do
return n
end
end
@@ -146,14 +129,17 @@ end
local fl_prefix = "luaotfload" -- “luatex” for luatex-plain
local loadmodule = function (name)
- require(fl_prefix .."-"..name)
+ require (fl_prefix .."-"..name)
end
-loadmodule "log.lua" --- messages; used to be part of -override
+loadmodule "log.lua" --- log messages
+--loadmodule "parsers.lua" --- new in 2.5; fonts.conf and syntax
+--loadmodule "configuration.lua" --- configuration options
+
local log = luaotfload.log
local report = log.report
-log.set_loglevel(luaotfloadconfig.loglevel)
+log.set_loglevel (default_log_level)
--[[doc--
@@ -216,8 +202,7 @@ end
--doc]]--
-local starttime = os.gettimeofday()
-
+local starttime = os.gettimeofday ()
local trapped_register = callback.register
callback.register = dummy_function
@@ -431,10 +416,21 @@ loadmodule "override.lua" --- load glyphlist on demand
Now we load the modules written for \identifier{luaotfload}.
--doc]]--
-loadmodule "parsers.lua" --- new in 2.5; fonts.conf and syntax
-loadmodule "loaders.lua" --- “font-pfb” new in 2.0, added 2011
-loadmodule "database.lua" --- “font-nms”
-loadmodule "colors.lua" --- “font-clr”
+
+loadmodule "parsers.lua" --- fonts.conf and syntax
+loadmodule "configuration.lua" --- configuration options
+
+if not config.actions.apply_defaults () then
+ report ("log", 0, "load", "Configuration unsuccessful.")
+end
+
+loadmodule "loaders.lua" --- Type1 font wrappers
+loadmodule "database.lua" --- Font management.
+loadmodule "colors.lua" --- Per-font colors.
+
+if not config.actions.reconfigure () then
+ report ("log", 0, "load", "Post-configuration hooks failed.")
+end
--[[doc--
@@ -482,15 +478,14 @@ fonts.encodings.known = fonts.encodings.known or { }
--doc]]--
-local resolve_file = names.crude_file_lookup
---local resolve_file = names.crude_file_lookup_verbose
-local resolve_name = names.resolve_name
+--local resolve_file = names.crude_file_lookup
+local resolve_file = names.crude_file_lookup_verbose
local file_resolver = function (specification)
local name = resolve_file (specification.name)
local suffix = filesuffix(name)
if formats[suffix] then
- specification.forced = suffix
+ specification.forced = stringlower (suffix)
specification.forcedname = file.removesuffix(name)
else
specification.name = name
@@ -528,7 +523,7 @@ request_resolvers.file = file_resolver
--doc]]--
-local type1_formats = { "tfm", "ofm", }
+local type1_formats = { "tfm", "ofm", "TFM", "OFM", }
request_resolvers.anon = function (specification)
local name = specification.name
@@ -571,14 +566,14 @@ request_resolvers.path = function (specification)
local name = specification.name
local exists, _ = lfsisfile(name)
if not exists then -- resort to file: lookup
- report ("log", 1, "load",
+ report ("log", 0, "load",
"path lookup of %q unsuccessful, falling back to file:",
name)
file_resolver (specification)
else
local suffix = filesuffix (name)
if formats[suffix] then
- specification.forced = suffix
+ specification.forced = stringlower (suffix)
specification.name = file.removesuffix(name)
specification.forcedname = name
else
@@ -601,7 +596,7 @@ request_resolvers.kpse = function (specification)
if suffix and formats[suffix] then
name = file.removesuffix(name)
if resolvers.findfile(name, suffix) then
- specification.forced = suffix
+ specification.forced = stringlower (suffix)
specification.forcedname = name
return
end
@@ -617,8 +612,7 @@ end
--[[doc--
- The \verb|name:| resolver wraps the database function
- \luafunction{resolve_name}.
+ The \verb|name:| resolver.
--doc]]--
@@ -626,11 +620,17 @@ end
--- generic name resolver.
request_resolvers.name = function (specification)
- local resolved, subfont = resolve_name (specification)
+ local resolver = names.resolve_cached
+ if config.luaotfload.run.resolver == "normal" then
+ resolver = names.resolve_name
+ end
+ local resolved, subfont = resolver (specification)
if resolved then
+ report ("log", 0, "load", "Lookup/name: %q -> \"%s(%d)\"",
+ specification.name, resolved, subfont)
specification.resolved = resolved
specification.sub = subfont
- specification.forced = filesuffix (resolved)
+ specification.forced = stringlower (filesuffix (resolved) or "")
specification.forcedname = resolved
specification.name = fileremovesuffix (resolved)
else
@@ -671,17 +671,20 @@ create_callback("luaotfload.patch_font", "simple", dummy_function)
local read_font_file = fonts.definers.read
---- spec -> size -> id -> tmfdata
-local patch_defined_font = function (specification, size, id)
- local tfmdata = read_font_file(specification, size, id)
- if type(tfmdata) == "table" and tfmdata.shared then
- --- We need to test for the “shared” field here
- --- or else the fontspec capheight callback will
- --- operate on tfm fonts.
- call_callback("luaotfload.patch_font", tfmdata, specification)
- end
- return tfmdata
-end
+local definers = {
+ generic = read_font_file,
+ --- spec -> size -> id -> tmfdata
+ patch = function (specification, size, id)
+ local tfmdata = read_font_file (specification, size, id)
+ if type (tfmdata) == "table" and tfmdata.shared then
+ --- We need to test for the “shared” field here
+ --- or else the fontspec capheight callback will
+ --- operate on tfm fonts.
+ call_callback ("luaotfload.patch_font", tfmdata, specification)
+ end
+ return tfmdata
+ end,
+}
reset_callback "define_font"
@@ -691,23 +694,12 @@ reset_callback "define_font"
--doc]]--
-local font_definer = luaotfloadconfig.definer
-
-if font_definer == "generic" then
- add_to_callback("define_font",
- fonts.definers.read,
- "luaotfload.define_font",
- 1)
-elseif font_definer == "patch" then
- add_to_callback("define_font",
- patch_defined_font,
- "luaotfload.define_font",
- 1)
-end
+local definer = config.luaotfload.run.definer
+add_to_callback ("define_font", definers[definer], "luaotfload.define_font", 1)
-loadmodule "features.lua" --- contains what was “font-ltx” and “font-otc”
+loadmodule "features.lua" --- font request and feature handling
loadmodule "letterspace.lua" --- extra character kerning
-loadmodule "auxiliary.lua" --- additionaly high-level functionality (new)
+loadmodule "auxiliary.lua" --- additional high-level functionality
luaotfload.aux.start_rewrite_fontname () --- to be migrated to fontspec
diff --git a/src/luaotfload-parsers.lua b/src/luaotfload-parsers.lua
index d5f64fc..73be67a 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
@@ -39,7 +41,7 @@ local io = io
local ioopen = io.open
local log = luaotfload.log
-local report = log.report
+local logreport = log.report
local string = string
local stringsub = string.sub
@@ -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")
@@ -182,7 +192,7 @@ local p_cheapxml = header * root
local fonts_conf_scanner = function (path)
local fh = ioopen(path, "r")
if not fh then
- report("both", 3, "db", "Cannot open fontconfig file %s.", path)
+ logreport("both", 3, "db", "Cannot open fontconfig file %s.", path)
return
end
local raw = fh:read"*all"
@@ -190,7 +200,7 @@ local fonts_conf_scanner = function (path)
local confdata = lpegmatch(p_cheapxml, raw)
if not confdata then
- report("both", 3, "db", "Cannot scan fontconfig file %s.", path)
+ logreport("both", 3, "db", "Cannot scan fontconfig file %s.", path)
return
end
return confdata
@@ -346,7 +356,7 @@ parsers.splitcomma = splitcomma
-------------------------------------------------------------------------------
---- FONT REQUEST
+--- FONT REQUEST
-------------------------------------------------------------------------------
@@ -461,7 +471,7 @@ end
--doc]]--
local handle_invalid_option = function (opt)
- report("log", 0, "load", "font option %q unknown.", opt)
+ logreport("log", 0, "load", "font option %q unknown.", opt)
return "", false
end
@@ -475,12 +485,12 @@ end
local check_garbage = function (_,i, garbage)
if stringfind(garbage, "/") then
- report("log", 0, "load", --- ffs use path!
- "warning: path in file: lookups is deprecated; ")
- report("log", 0, "load", "use bracket syntax instead!")
- report("log", 0, "load",
- "position: %d; full match: %q",
- i, garbage)
+ logreport("log", 0, "load", --- ffs use path!
+ "warning: path in file: lookups is deprecated; ")
+ logreport("log", 0, "load", "use bracket syntax instead!")
+ logreport("log", 0, "load",
+ "position: %d; full match: %q",
+ i, garbage)
return true
end
return false
@@ -583,3 +593,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
diff --git a/src/luaotfload-tool.lua b/src/luaotfload-tool.lua
index 1923040..0db3eca 100755
--- a/src/luaotfload-tool.lua
+++ b/src/luaotfload-tool.lua
@@ -6,7 +6,7 @@
-- AUTHOR: Khaled Hosny, Élie Roux, Philipp Gesang
-- VERSION: 2.5
-- LICENSE: GPL v2.0
--- MODIFIED: 2014-01-14 13:17:04+0100
+-- MODIFIED: 2014-05-15 21:47:39+0200
-----------------------------------------------------------------------
luaotfload = luaotfload or { }
@@ -45,7 +45,6 @@ kpse.set_program_name "luatex"
--doc]]--
-local ioopen = io.open
local iowrite = io.write
local kpsefind_file = kpse.find_file
local mathfloor = math.floor
@@ -90,24 +89,19 @@ string.quoted = string.quoted or function (str)
return string.format("%q",str)
end
-require(loader_path)
-
-config = config or { }
-local config = config
-local luaotfloadconfig = config.luaotfload or { }
-config.luaotfload = luaotfloadconfig
-luaotfloadconfig.bisect = false
-luaotfloadconfig.version = luaotfloadconfig.version or version
-luaotfloadconfig.names_dir = luaotfloadconfig.names_dir or "names"
-luaotfloadconfig.cache_dir = luaotfloadconfig.cache_dir or "fonts"
-luaotfloadconfig.index_file = luaotfloadconfig.index_file
- or "luaotfload-names.lua"
-luaotfloadconfig.formats = luaotfloadconfig.formats
- or "otf,ttf,ttc,dfont"
-luaotfloadconfig.reload = false
-if not luaotfloadconfig.strip then
- luaotfloadconfig.strip = true
-end
+require (loader_path)
+
+--[[doc--
+
+ XXX:
+ Creating the config table will be moved to the common
+ initialization when the times comes.
+
+--doc]]--
+
+config = config or { }
+local config = config
+config.luaotfload = config.luaotfload or { }
config.lualibs = config.lualibs or { }
config.lualibs.verbose = false
@@ -120,6 +114,7 @@ local lfsisdir = lfs.isdir
local lfsisfile = lfs.isfile
local stringsplit = string.split
local tableserialize = table.serialize
+local tablesortedkeys = table.sortedkeys
local tabletohash = table.tohash
--[[doc--
@@ -148,25 +143,18 @@ require"luaotfload-basics-gen.lua"
texio.write, texio.write_nl = backup.write, backup.write_nl
utilities = backup.utilities
-require"luaotfload-log.lua" --- this populates the luaotfload.log.* namespace
-require"luaotfload-parsers" --- fonts.conf and request syntax
-require"luaotfload-database"
-require"alt_getopt"
+require "luaotfload-log.lua" --- this populates the luaotfload.log.* namespace
+require "luaotfload-parsers" --- fonts.conf, configuration, and request syntax
+require "luaotfload-configuration" --- configuration file handling
+require "luaotfload-database"
+require "alt_getopt"
local names = fonts.names
-local status_file = "luaotfload-status"
-local luaotfloadstatus = require (status_file)
-luaotfloadconfig.status = luaotfloadstatus
local sanitize_fontname = names.sanitize_fontname
local log = luaotfload.log
local report = log.report
-local pathdata = names.path
-local names_plain = pathdata.index.lua
-local names_gzip = names_plain .. ".gz"
-local names_bin = pathdata.index.luc
-
local help_messages = {
["luaotfload-tool"] = [[
@@ -261,14 +249,17 @@ Enter 'luaotfload-tool --help' for a larger list of options.
}
local help_msg = function (version)
- local template = help_messages[version]
+ local template = help_messages[version]
+ local paths = config.luaotfload.paths
+ local names_plain = paths.index_path_lua
+ local names_gzip = names_plain .. ".gz"
+ local names_bin = paths.index_path_luc
+
iowrite(stringformat(template,
luaotfload.self,
--- names_plain,
names_gzip,
names_bin,
- caches.getwritablepath (
- luaotfloadconfig.cache_dir)))
+ caches.getwritablepath (config.luaotfload.cache_dir)))
end
local about = [[
@@ -279,16 +270,28 @@ local about = [[
]]
local version_msg = function ( )
- local out = function (...) texiowrite_nl (stringformat (...)) end
+ local out = function (...) texiowrite_nl (stringformat (...)) end
+ local uname = os.uname ()
+ local meta = names.getmetadata ()
out (about, luaotfload.self)
- out ("%s version %q", luaotfload.self, version)
- out ("revision %q", luaotfloadstatus.notes.revision)
- out ("database version %q", names.version)
+ out ("%s version: %q", luaotfload.self, version)
+ out ("Revision: %q", config.luaotfload.status.notes.revision)
out ("Lua interpreter: %s; version %q", runtime[1], runtime[2])
- out ("Luatex SVN revision %d", status.luatex_svn)
- out ("Luatex version %.2f.%d",
+ out ("Luatex SVN revision: %d", status.luatex_svn)
+ out ("Luatex version: %.2f.%d",
status.luatex_version / 100,
status.luatex_revision)
+ out ("Platform: type=%s name=%s", os.type, os.name)
+
+ local uname_vars = tablesortedkeys (uname)
+ for i = 1, #uname_vars do
+ local var = uname_vars[i]
+ out (" + %8s: %s", var, uname[var])
+ end
+ out ("Index: version=%q created=%q modified=%q",
+ config.luaotfload.status.notes.revision,
+ meta.created or "ages ago",
+ meta.modified or "ages ago")
out ""
end
@@ -361,7 +364,7 @@ local baseindent = " "
local show_info_table show_info_table = function (t, depth)
depth = depth or 0
local indent = stringrep (baseindent, depth)
- local keys = table.sortedkeys (t)
+ local keys = tablesortedkeys (t)
for n = 1, #keys do
local key = keys [n]
local val = t [key]
@@ -736,13 +739,14 @@ set.
--]]--
local action_sequence = {
- "loglevel", "help", "version", "diagnose",
- "blacklist", "cache", "flush", "bisect",
- "generate", "list", "query",
+ "loglevel", "config", "help", "version",
+ "diagnose", "blacklist", "cache", "flush",
+ "bisect", "generate", "list", "query",
}
local action_pending = tabletohash(action_sequence, false)
+action_pending.config = true --- always read the configuration
action_pending.loglevel = true --- always set the loglevel
action_pending.generate = false --- this is the default action
@@ -755,6 +759,20 @@ actions.loglevel = function (job)
return true, true
end
+actions.config = function (job)
+ local defaults = luaotfload.default_config
+ local vars = config.actions.read (job.extra_config)
+ config.luaotfload = config.actions.apply (defaults, vars)
+ config.luaotfload = config.actions.apply (config.luaotfload, job.config)
+
+ --inspect(config.luaotfload)
+ --os.exit()
+ if not config.actions.reconfigure () then
+ return false, false
+ end
+ return true, true
+end
+
actions.version = function (job)
version_msg()
return true, false
@@ -768,7 +786,7 @@ end
actions.blacklist = function (job)
names.read_blacklist()
local n = 0
- for n, entry in next, table.sortedkeys(names.blacklist) do
+ for n, entry in next, tablesortedkeys(names.blacklist) do
iowrite (stringformat("(%d %s)\n", n, entry))
end
return true, false
@@ -1054,7 +1072,7 @@ local bisect_run = function ()
nsteps, lo, hi, pivot)
report ("info", 1, "bisect", "Step %d: Testing fonts from %d to %d.",
currentstep, lo, pivot)
- luaotfloadconfig.bisect = { lo, pivot }
+ config.luaotfload.misc.bisect = { lo, pivot }
return true, true
end
@@ -1383,11 +1401,13 @@ local process_cmdline = function ( ) -- unit -> jobspec
query = "",
log_level = 0, --- 2 is approx. the old behavior
bisect = nil,
+ config = { db = { }, misc = { }, run = { }, paths = { } },
}
local long_options = {
+ ["bisect"] = 1,
cache = 1,
- ["no-compress"] = "c",
+ conf = 1,
diagnose = 1,
["dry-run"] = "D",
["flush-lookups"] = "l",
@@ -1404,11 +1424,12 @@ local process_cmdline = function ( ) -- unit -> jobspec
["local"] = "L",
log = 1,
["max-fonts"] = 1,
- ["bisect"] = 1,
+ ["no-compress"] = "c",
["no-reload"] = "n",
["no-strip"] = 0,
["skip-read"] = "R",
["prefer-texmf"] = "p",
+ ["print-conf"] = 0,
quiet = "q",
["show-blacklist"] = "b",
stats = "S",
@@ -1478,7 +1499,7 @@ local process_cmdline = function ( ) -- unit -> jobspec
action_pending["flush"] = true
elseif v == "L" then
action_pending["generate"] = true
- luaotfloadconfig.scan_local = true
+ config.luaotfload.db.scan_local = true
elseif v == "list" then
action_pending["list"] = true
result.criterion = optarg[n]
@@ -1499,29 +1520,42 @@ local process_cmdline = function ( ) -- unit -> jobspec
action_pending["diagnose"] = true
result.asked_diagnostics = optarg[n]
elseif v == "formats" then
- names.set_font_filter (optarg[n])
+ result.config.db.formats = optarg[n]
+ --names.set_font_filter (optarg[n])
elseif v == "n" then
- luaotfloadconfig.update_live = false
+ config.luaotfload.db.update_live = false
elseif v == "S" then
- luaotfloadconfig.statistics = true
+ config.luaotfload.misc.statistics = true
elseif v == "R" then
--- dev only, undocumented
- luaotfloadconfig.skip_read = true
+ config.luaotfload.db.skip_read = true
elseif v == "c" then
- luaotfloadconfig.compress = false
+ config.luaotfload.db.compress = false
elseif v == "no-strip" then
- luaotfloadconfig.strip = false
+ config.luaotfload.db.strip = false
elseif v == "max-fonts" then
local n = optarg[n]
if n then
n = tonumber(n)
if n and n > 0 then
- luaotfloadconfig.max_fonts = n
+ config.luaotfload.db.max_fonts = n
end
end
elseif v == "bisect" then
- result.bisect = optarg[n]
+ result.bisect = optarg[n]
action_pending.bisect = true
+ elseif v == "conf" then
+ local extra = stringexplode (optarg[n], ",+")
+ if extra then
+ local extra_config = result.extra_config
+ if extra_config then
+ table.append (extra_config, extra)
+ else
+ result.extra_config = extra
+ end
+ end
+ elseif v == "print-conf" then
+ result.print_config = true
end
end