diff options
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | doc/luaotfload-latex.tex | 7 | ||||
-rw-r--r-- | doc/luaotfload-main.tex | 36 | ||||
-rwxr-xr-x | scripts/mktests | 73 | ||||
-rw-r--r-- | src/luaotfload-auxiliary.lua | 45 | ||||
-rw-r--r-- | src/luaotfload-basics-gen.lua | 25 | ||||
-rw-r--r-- | src/luaotfload-basics-nod.lua | 15 | ||||
-rw-r--r-- | src/luaotfload-colors.lua | 2 | ||||
-rw-r--r-- | src/luaotfload-configuration.lua | 536 | ||||
-rw-r--r-- | src/luaotfload-database.lua | 216 | ||||
-rw-r--r-- | src/luaotfload-diagnostics.lua | 34 | ||||
-rw-r--r-- | src/luaotfload-features.lua | 49 | ||||
-rw-r--r-- | src/luaotfload-fontloader.lua | 65 | ||||
-rw-r--r-- | src/luaotfload-main.lua | 152 | ||||
-rw-r--r-- | src/luaotfload-parsers.lua | 141 | ||||
-rwxr-xr-x | src/luaotfload-tool.lua | 152 |
16 files changed, 1179 insertions, 371 deletions
@@ -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 |