diff options
author | Karl Berry <karl@freefriends.org> | 2015-12-11 23:16:34 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2015-12-11 23:16:34 +0000 |
commit | 71945bfdf73e58a09c05155c6d49729528cac3f7 (patch) | |
tree | aa614024e79d15166a1aa500e223c748b1a66c83 /Master/texmf-dist/scripts/luaotfload | |
parent | fa3dbdbd11bbc7da0c06e2871472419998e645c9 (diff) |
luaotfload (11dec15)
git-svn-id: svn://tug.org/texlive/trunk@39078 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/scripts/luaotfload')
-rwxr-xr-x | Master/texmf-dist/scripts/luaotfload/luaotfload-tool.lua | 389 | ||||
-rwxr-xr-x | Master/texmf-dist/scripts/luaotfload/mkcharacters | 12 | ||||
-rwxr-xr-x | Master/texmf-dist/scripts/luaotfload/mkglyphlist | 2 | ||||
-rwxr-xr-x | Master/texmf-dist/scripts/luaotfload/mkimport | 871 | ||||
-rwxr-xr-x | Master/texmf-dist/scripts/luaotfload/mkstatus | 174 | ||||
-rwxr-xr-x | Master/texmf-dist/scripts/luaotfload/mktests | 362 |
6 files changed, 1615 insertions, 195 deletions
diff --git a/Master/texmf-dist/scripts/luaotfload/luaotfload-tool.lua b/Master/texmf-dist/scripts/luaotfload/luaotfload-tool.lua index 8a65298d03a..69b6c976fb1 100755 --- a/Master/texmf-dist/scripts/luaotfload/luaotfload-tool.lua +++ b/Master/texmf-dist/scripts/luaotfload/luaotfload-tool.lua @@ -2,15 +2,13 @@ ----------------------------------------------------------------------- -- FILE: luaotfload-tool.lua -- DESCRIPTION: database functionality --- REQUIREMENTS: luaotfload 2.5 +-- REQUIREMENTS: luaotfload 2.6 -- AUTHOR: Khaled Hosny, Élie Roux, Philipp Gesang --- VERSION: 2.5 -- LICENSE: GPL v2.0 --- MODIFIED: 2014-08-10 23:13:18+0200 ----------------------------------------------------------------------- luaotfload = luaotfload or { } -local version = "2.5-4" --- <int: major>.<int: minor>-<int: fixes> +local version = "2.6" luaotfload.version = version luaotfload.self = "luaotfload-tool" @@ -76,21 +74,13 @@ else -- 5.2 runtime = { "stock", _VERSION } end - local C, Ct, P, S = lpeg.C, lpeg.Ct, lpeg.P, lpeg.S local lpegmatch = lpeg.match -local loader_file = "luatexbase.loader.lua" -local loader_path = assert(kpsefind_file(loader_file, "lua"), - "File '"..loader_file.."' not found") - - string.quoted = string.quoted or function (str) return string.format("%q",str) end -require (loader_path) - --[[doc-- XXX: @@ -109,6 +99,7 @@ config.lualibs.prefer_merged = true config.lualibs.load_extended = true require "lualibs" + local iosavedata = io.savedata local lfsisdir = lfs.isdir local lfsisfile = lfs.isfile @@ -138,22 +129,69 @@ local backup = { } texio.write, texio.write_nl = dummy_function, dummy_function -require"luaotfload-basics-gen.lua" +require "fontloader-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, configuration, and request syntax -require "luaotfload-configuration" --- configuration file handling -require "luaotfload-database" +fonts = { names = { } } -- for db; normally provided by the fontloaders + +local require_init = { } + +local loadmodule = function (name) + local v = require ("luaotfload-" .. name) + if v then + local mod = { } + local tv = type (v) + if tv == "table" then + mod.name = name + mod.init = v.init + require_init [#require_init + 1] = mod + elseif tv == "function" then + mod.name = name + mod.init = v + require_init [#require_init + 1] = mod + end + end +end + require "alt_getopt" -local names = fonts.names -local sanitize_fontname = names.sanitize_fontname +loadmodule "log.lua" --- this populates the luaotfload.log.* namespace +loadmodule "parsers" --- fonts.conf, configuration, and request syntax +loadmodule "configuration" --- configuration file handling +loadmodule "database" +loadmodule "resolvers" --- Font lookup + +local logreport + +local init_modules = function () + --- NB we don’t command the logger at this point. + local todo = #require_init + local ret = true + for i = 1, todo do + local mod = require_init[i] + local name = mod.name + local init = mod.init + if type (init) ~= "function" then + error ("luaotfload broken; module " + .. name .. " missing initializers!") + end + local v = mod.init () + if v == true then + --- evaluated well + elseif type (v) == "table" then + luaotfload[name] = v + else + error ("luaotfload broken; initialization of module " + .. name .. " returned " .. tostring (v) .. ".") + return false + end + end + logreport = luaotfload.log.report + return ret +end -local log = luaotfload.log -local report = log.report local help_messages = { ["luaotfload-tool"] = [[ @@ -170,8 +208,7 @@ Usage: %s [OPTIONS...] -q --quiet don't output anything -v --verbose=LEVEL be more verbose (print the searched directories) - -vv print the loaded fonts - -vvv print all steps of directory searching + -v, -vv .. -vvvvvvvvv set loglevel in unary --log=stdout redirect log output to stdout -V --version print version and exit @@ -191,7 +228,7 @@ Usage: %s [OPTIONS...] -c --no-compress do not gzip index file (text version only) -l --flush-lookups empty lookup cache of font requests -D --dry-run skip loading of fonts, just scan - --formats=[+|-]EXTENSIONS set, add, or subtract formats to index + --formats=[+|-]EXTENSIONS set, add, or subtract file formats -p --prefer-texmf prefer fonts in the TEXMF over system fonts --max-fonts=N process at most N font files @@ -259,7 +296,7 @@ local help_msg = function (version) luaotfload.self, names_gzip, names_bin, - caches.getwritablepath (config.luaotfload.cache_dir))) + caches.getwritablepath (config.luaotfload.paths.cache_dir, ""))) end local about = [[ @@ -272,7 +309,7 @@ local about = [[ local version_msg = function ( ) local out = function (...) texiowrite_nl (stringformat (...)) end local uname = os.uname () - local meta = names.getmetadata () + local meta = fonts.names.getmetadata () out (about, luaotfload.self) out ("%s version: %q", luaotfload.self, version) out ("Revision: %q", config.luaotfload.status.notes.revision) @@ -288,10 +325,14 @@ local version_msg = function ( ) 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") + if meta == false then + out("No database metadata available.") + else + out ("Index: version=%q created=%q modified=%q", + config.luaotfload.status.notes.revision, + meta.created or "ages ago", + meta.modified or "ages ago") + end out "" end @@ -669,7 +710,7 @@ subfont_by_name = function (lst, askedname, n) local font = lst[n] if font then - if sanitize_fontname (font.fullname) == askedname then + if fonts.names.sanitize_fontname (font.fullname) == askedname then return font end return subfont_by_name (lst, askedname, n+1) @@ -686,10 +727,10 @@ The font info knows two levels of detail: --doc]]-- local show_font_info = function (basename, askedname, detail, warnings) - local filenames = names.data().files + local filenames = fonts.names.data().files local index = filenames.base[basename] local fullname = filenames.full[index] - askedname = sanitize_fontname (askedname) + askedname = fonts.names.sanitize_fontname (askedname) if not fullname then -- texmf fullname = resolvers.findfile(basename) end @@ -699,9 +740,9 @@ local show_font_info = function (basename, askedname, detail, warnings) if nfonts > 0 then -- true type collection local subfont if askedname then - report (true, 1, "resolve", - [[%s is part of the font collection %s]], - askedname, basename) + logreport (true, 1, "resolve", + [[%s is part of the font collection %s]], + askedname, basename) subfont = subfont_by_name(shortinfo, askedname) end if subfont then @@ -710,11 +751,11 @@ local show_font_info = function (basename, askedname, detail, warnings) show_full_info(fullname, subfont, warnings) end else -- list all subfonts - report (true, 1, "resolve", - [[%s is a font collection]], basename) + logreport (true, 1, "resolve", + [[%s is a font collection]], basename) for subfont = 1, nfonts do - report (true, 1, "resolve", - [[Showing info for font no. %d]], n) + logreport (true, 1, "resolve", + [[Showing info for font no. %d]], n) show_info_items(shortinfo[subfont]) if detail == true then show_full_info(fullname, subfont, warnings) @@ -728,7 +769,7 @@ local show_font_info = function (basename, askedname, detail, warnings) end end else - report (true, 1, "resolve", "Font %s not found", filename) + logreport (true, 1, "resolve", "Font %s not found", filename) end end @@ -739,9 +780,10 @@ set. --]]-- local action_sequence = { - "config", "loglevel", "help", "version", - "diagnose", "blacklist", "cache", "flush", - "bisect", "generate", "list", "query", + "config" , "loglevel" , "help" , "version" , + "dumpconf" , "diagnose" , "blacklist" , "cache" , + "flush" , "bisect" , "generate" , "list" , + "query" , } local action_pending = tabletohash(action_sequence, false) @@ -755,9 +797,9 @@ local actions = { } --- (jobspec -> (bool * bool)) list actions.loglevel = function (job) local lvl = job.log_level if lvl then - log.set_loglevel(lvl) - report ("info", 3, "util", "Setting the log level to %d.", lvl) - report ("log", 2, "util", "Lua=%q", _VERSION) + luaotfload.log.set_loglevel(lvl) + logreport ("info", 3, "util", "Setting the log level to %d.", lvl) + logreport ("log", 2, "util", "Lua=%q", _VERSION) end return true, true end @@ -781,25 +823,32 @@ actions.version = function (job) return true, false end +actions.dumpconf = function (job) + config.actions.dump () + return true, false +end + actions.help = function (job) help_msg (job.help_version or "luaotfload-tool") return true, false end actions.blacklist = function (job) - names.read_blacklist() + fonts.names.read_blacklist() local n = 0 - for n, entry in next, tablesortedkeys(names.blacklist) do + for n, entry in next, tablesortedkeys(fonts.names.blacklist) do iowrite (stringformat("(%d %s)\n", n, entry)) end return true, false end actions.generate = function (job) - local _ = names.update (fontnames, job.force_reload, job.dry_run) - local namedata = names.data () + local _ = fonts.names.update (fontnames, job.force_reload, job.dry_run) + local namedata = fonts.names.data () if namedata then - report ("info", 2, "db", "Fonts in the database: %i", #namedata.mappings) + logreport ("info", 2, "db", + "Fonts in the database: %i", + #namedata.mappings) return true, true end return false, false @@ -809,7 +858,7 @@ end --- bisect mode ------------------------------------------------------------------------------- -local bisect_status_path = caches.getwritablepath "bisect" +local bisect_status_path = caches.getwritablepath ("bisect", "") local bisect_status_file = bisect_status_path .."/" .. "luaotfload-bisect-status.lua" local bisect_status_fmt = [[ --[==[------------------------------------------------------------------------- @@ -835,12 +884,14 @@ local write_bisect_status = function (data) osdate ("%Y-%m-d %H:%M:%S", os.time ()), payload) if status and iosavedata (bisect_status_file, status) then - report ("info", 4, "bisect", - "Bisection state written to %s.", bisect_status_file) + logreport ("info", 4, "bisect", + "Bisection state written to %s.", + bisect_status_file) return true end - report ("info", 0, "bisect", - "Failed to write bisection state to %s.", bisect_status_file) + logreport ("info", 0, "bisect", + "Failed to write bisection state to %s.", + bisect_status_file) return false end @@ -852,16 +903,22 @@ end --- unit -> state list local read_bisect_status = function () - report ("info", 4, "bisect", "Testing for status file: %q.", bisect_status_file) + logreport ("info", 4, "bisect", + "Testing for status file: %q.", + bisect_status_file) if not lfsisfile (bisect_status_file) then - report ("info", 2, "bisect", "No such file: %q.", bisect_status_file) - report ("info", 0, "bisect", "Not in bisect mode.") + logreport ("info", 2, "bisect", + "No such file: %q.", bisect_status_file) + logreport ("info", 0, "bisect", + "Not in bisect mode.") return false end - report ("info", 4, "bisect", "Reading status file: %q.", bisect_status_file) + logreport ("info", 4, "bisect", + "Reading status file: %q.", bisect_status_file) local success, status = pcall (dofile, bisect_status_file) if not success then - report ("info", 0, "bisect", "Could not read status file.") + logreport ("info", 0, "bisect", + "Could not read status file.") return false end return status @@ -876,19 +933,21 @@ end local bisect_start = function () if lfsisfile (bisect_status_file) then - report ("info", 0, "bisect", - "Bisect session in progress.", - bisect_status_file) - report ("info", 0, "bisect", - "Use --bisect=stop to erase it before starting over.") + logreport ("info", 0, "bisect", + "Bisect session in progress.", + bisect_status_file) + logreport ("info", 0, "bisect", + "Use --bisect=stop to erase it before starting over.") return false, false end - report ("info", 2, "bisect", - "Starting bisection of font database %q.", bisect_status_file) - local n = names.count_font_files () + logreport ("info", 2, "bisect", + "Starting bisection of font database %q.", + bisect_status_file) + local n = fonts.names.count_font_files () local pivot = mathfloor (n / 2) local data = { { 1, n, pivot } } - report ("info", 0, "bisect", "Initializing pivot to %d.", pivot) + logreport ("info", 0, "bisect", + "Initializing pivot to %d.", pivot) if write_bisect_status (data) then return true, false end @@ -902,21 +961,23 @@ end --doc]]-- local bisect_stop = function () - report ("info", 3, "bisect", "Erasing bisection state at %s.", bisect_status_file) + logreport ("info", 3, "bisect", + "Erasing bisection state at %s.", + bisect_status_file) if lfsisfile (bisect_status_file) then local success, msg = os.remove (bisect_status_file) if not success then - report ("info", 2, "bisect", - "Failed to erase file %s (%s).", - bisect_status_file, msg) + logreport ("info", 2, "bisect", + "Failed to erase file %s (%s).", + bisect_status_file, msg) end end if lfsisdir (bisect_status_path) then local success, msg = os.remove (bisect_status_path) if not success then - report ("info", 2, "bisect", - "Failed to erase directory %s (%s).", - bisect_status_path, msg) + logreport ("info", 2, "bisect", + "Failed to erase directory %s (%s).", + bisect_status_path, msg) end end if lfsisfile (bisect_status_file) then @@ -933,12 +994,12 @@ end --doc]]-- local bisect_terminate = function (nsteps, culprit) - report ("info", 1, "bisect", - "Bisection completed after %d steps.", nsteps) - report ("info", 0, "bisect", - "Bad file: %s.", names.nth_font_filename (culprit)) - report ("info", 0, "bisect", - "Run with --bisect=stop to finish bisection.") + logreport ("info", 1, "bisect", + "Bisection completed after %d steps.", nsteps) + logreport ("info", 0, "bisect", + "Bad file: %s.", fonts.names.nth_font_filename (culprit)) + logreport ("info", 0, "bisect", + "Run with --bisect=stop to finish bisection.") return true, false end @@ -949,10 +1010,10 @@ end --doc]]-- local list_remainder = function (lo, hi) - local fonts = names.font_slice (lo, hi) - report ("info", 0, "bisect", "%d fonts left.", hi - lo + 1) + local fonts = fonts.names.font_slice (lo, hi) + logreport ("info", 0, "bisect", "%d fonts left.", hi - lo + 1) for i = 1, #fonts do - report ("info", 1, "bisect", " · %2d: %s", lo, fonts[i]) + logreport ("info", 1, "bisect", " · %2d: %s", lo, fonts[i]) lo = lo + 1 end end @@ -985,8 +1046,9 @@ local bisect_set = function (outcome) local lo, hi, pivot = unpack (previous) - report ("info", 3, "bisect", "Previous step %d: lo=%d, hi=%d, pivot=%d.", - nsteps, lo, hi, pivot) + logreport ("info", 3, "bisect", + "Previous step %d: lo=%d, hi=%d, pivot=%d.", + nsteps, lo, hi, pivot) if outcome == "bad" then hi = pivot @@ -997,9 +1059,9 @@ local bisect_set = function (outcome) return bisect_terminate (nsteps, lo) end pivot = mathfloor ((lo + hi) / 2) - report ("info", 0, "bisect", - "Continuing with the lower segment: lo=%d, hi=%d, pivot=%d.", - lo, hi, pivot) + logreport ("info", 0, "bisect", + "Continuing with the lower segment: lo=%d, hi=%d, pivot=%d.", + lo, hi, pivot) elseif outcome == "good" then lo = pivot + 1 if lo >= hi then --- complete @@ -1009,11 +1071,12 @@ local bisect_set = function (outcome) return bisect_terminate (nsteps, lo) end pivot = mathfloor ((lo + hi) / 2) - report ("info", 0, "bisect", - "Continuing with the upper segment: lo=%d, hi=%d, pivot=%d.", - lo, hi, pivot) + logreport ("info", 0, "bisect", + "Continuing with the upper segment: lo=%d, hi=%d, pivot=%d.", + lo, hi, pivot) else -- can’t happen - report ("info", 0, "bisect", "What the hell?", lo, hi, pivot) + logreport ("info", 0, "bisect", + "What the hell?", lo, hi, pivot) return false, false end @@ -1040,13 +1103,13 @@ local bisect_status = function () if nsteps > 1 then for i = nsteps - 1, 1, -1 do local step = status[i] - report ("info", 2, "bisect", "Step %d: lo=%d, hi=%d, pivot=%d.", - i, unpack (step)) + logreport ("info", 2, "bisect", "Step %d: lo=%d, hi=%d, pivot=%d.", + i, unpack (step)) end end local current = status[nsteps] - report ("info", 0, "bisect", "Step %d: lo=%d, hi=%d, pivot=%d.", - nsteps, unpack (current)) + logreport ("info", 0, "bisect", "Step %d: lo=%d, hi=%d, pivot=%d.", + nsteps, unpack (current)) return true, false end @@ -1072,10 +1135,10 @@ local bisect_run = function () current = status[nsteps - 1] end local lo, hi, pivot = unpack (current) - report ("info", 3, "bisect", "Previous step %d: lo=%d, hi=%d, pivot=%d.", - nsteps, lo, hi, pivot) - report ("info", 1, "bisect", "Step %d: Testing fonts from %d to %d.", - currentstep, lo, pivot) + logreport ("info", 3, "bisect", "Previous step %d: lo=%d, hi=%d, pivot=%d.", + nsteps, lo, hi, pivot) + logreport ("info", 1, "bisect", "Step %d: Testing fonts from %d to %d.", + currentstep, lo, pivot) config.luaotfload.misc.bisect = { lo, pivot } return true, true end @@ -1093,35 +1156,38 @@ actions.bisect = function (job) local mode = job.bisect local runner = bisect_modes[mode] if not runner then - report ("info", 0, "bisect", "Unknown directive %q.", mode) + logreport ("info", 0, "bisect", "Unknown directive %q.", mode) return false, false end return runner (job) end actions.flush = function (job) - local success = names.flush_lookup_cache() + local success = fonts.names.flush_lookup_cache() if success then - local success = names.save_lookups() + local success = fonts.names.save_lookups() if success then - report ("info", 2, "cache", "Lookup cache emptied") + logreport ("info", 2, "cache", "Lookup cache emptied") return true, true end end return false, false end -local cache_directives = { - ["purge"] = names.purge_cache, - ["erase"] = names.erase_cache, - ["show"] = names.show_cache, -} +local cache_directives = function () + --- These exist only after initialization. + return { + ["purge"] = fonts.names.purge_cache, + ["erase"] = fonts.names.erase_cache, + ["show"] = fonts.names.show_cache, + } +end actions.cache = function (job) - local directive = cache_directives[job.cache] + local directive = cache_directives()[job.cache] if not directive or type(directive) ~= "function" then - report ("info", 2, "cache", - "Invalid font cache directive %s.", job.cache) + logreport ("info", 2, "cache", + "Invalid font cache directive %s.", job.cache) return false, false end if directive() then @@ -1144,7 +1210,7 @@ actions.query = function (job) features = { }, } - tmpspec = names.handle_request (tmpspec) + tmpspec = fonts.names.handle_request (tmpspec) if not tmpspec.size then tmpspec.size = 655360 --- assume 10pt @@ -1155,38 +1221,38 @@ actions.query = function (job) if tmpspec.lookup == "name" or tmpspec.lookup == "anon" --- not *exactly* as resolvers.anon then - foundname, subfont = names.resolve_name (tmpspec) + foundname, _, success = fonts.names.lookup_font_name (tmpspec) if foundname then - foundname, _, success = names.font_file_lookup (foundname) + foundname, _, success = fonts.names.lookup_font_file (foundname) end elseif tmpspec.lookup == "file" then - foundname, _, success = - names.font_file_lookup (tmpspec.name) + foundname, _, success = fonts.names.lookup_font_file (tmpspec.name) end if success then - report (false, 0, "resolve", "Font %q found!", query) + logreport (false, 0, "resolve", "Font %q found!", query) if subfont then - report (false, 0, "resolve", - "Resolved file name %q, subfont nr. %q", - foundname, subfont) + logreport (false, 0, "resolve", + "Resolved file name %q, subfont nr. %q", + foundname, subfont) else - report (false, 0, "resolve", - "Resolved file name %q", foundname) + logreport (false, 0, "resolve", + "Resolved file name %q", foundname) end if job.show_info then show_font_info (foundname, query, job.full_info, job.warnings) iowrite "\n" end else - report (false, 0, "resolve", "Cannot find %q in index.", query) - report (false, 0, "resolve", - "Hint: use the --fuzzy option to display suggestions.", - query) + logreport (false, 0, "resolve", "Cannot find %q in index.", query) if job.fuzzy == true then - report (false, 0, "resolve", - "Looking for close matches, this may take a while ...") - local _success = names.find_closest(query, job.fuzzy_limit) + logreport (false, 0, "resolve", + "Looking for close matches, this may take a while ...") + local _success = fonts.names.find_closest(query, job.fuzzy_limit) + else + logreport (false, 0, "resolve", + "Hint: use the --fuzzy option to display suggestions.", + query) end end return true, true @@ -1259,14 +1325,13 @@ set_primary_field = function (fields, addme, acc, n) return acc end -local splitcomma = luaotfload.parsers.splitcomma - actions.list = function (job) local criterion = job.criterion local asked_fields = job.asked_fields - local name_index = names.data () + local name_index = fonts.names.data () if asked_fields then + local splitcomma = luaotfload.parsers.splitcomma asked_fields = lpegmatch(splitcomma, asked_fields) end @@ -1276,14 +1341,14 @@ actions.list = function (job) end if not name_index then - name_index = names.load() + name_index = fonts.names.load() end local mappings = name_index.mappings local nmappings = #mappings if criterion == "*" then - report (false, 1, "list", "All %d entries", nmappings) + logreport (false, 1, "list", "All %d entries", nmappings) for i=1, nmappings do local entry = mappings[i] local fields = get_fields(entry, asked_fields) @@ -1298,12 +1363,12 @@ actions.list = function (job) criterion = criterion[1] asked_fields = set_primary_field(asked_fields, criterion) - report (false, 1, "list", "By %s", criterion) + logreport (false, 1, "list", "By %s", criterion) --- firstly, build a list of fonts to operate on local targets = { } if asked_value then --- only those whose value matches - report (false, 2, "list", "Restricting to value %s", asked_value) + logreport (false, 2, "list", "Restricting to value %s", asked_value) for i=1, nmappings do local entry = mappings[i] if entry[criterion] @@ -1348,7 +1413,7 @@ actions.list = function (job) end end local ntargets = #targets - report (false, 2, "list", "%d entries", ntargets) + logreport (false, 2, "list", "%d entries", ntargets) --- now, output the collection for i=1, ntargets do @@ -1413,6 +1478,7 @@ local process_cmdline = function ( ) -- unit -> jobspec cache = 1, conf = 1, diagnose = 1, + dumpconf = 0, ["dry-run"] = "D", ["flush-lookups"] = "l", fields = 1, @@ -1484,7 +1550,7 @@ local process_cmdline = function ( ) -- unit -> jobspec elseif v == "log" then local str = optarg[n] if str then - finalizers = log.set_logout(str, finalizers) + finalizers = luaotfload.log.set_logout(str, finalizers) end elseif v == "find" then action_pending["query"] = true @@ -1517,7 +1583,7 @@ local process_cmdline = function ( ) -- unit -> jobspec elseif v == "D" then result.dry_run = true elseif v == "p" then - names.set_location_precedence { + fonts.names.set_location_precedence { "local", "texmf", "system" } elseif v == "b" then @@ -1551,15 +1617,20 @@ local process_cmdline = function ( ) -- unit -> jobspec 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 + local confname = optarg[n] + if confname 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 end + elseif v == "dumpconf" then + action_pending["dumpconf"] = true elseif v == "print-conf" then result.print_config = true end @@ -1573,6 +1644,8 @@ local process_cmdline = function ( ) -- unit -> jobspec end local main = function ( ) -- unit -> int + if init_modules () == false then return -42 end + local retval = 0 local job = process_cmdline() @@ -1583,23 +1656,23 @@ local main = function ( ) -- unit -> int local actionname = action_sequence[i] local exit = false if action_pending[actionname] then - report ("log", 3, "util", "Preparing for task", "%s", actionname) + logreport ("log", 3, "util", "Preparing for task", "%s", actionname) local action = actions[actionname] local success, continue = action(job) if not success then - report (false, 0, "util", - "Failed to execute task.", "%s", actionname) + logreport (false, 0, "util", + "Failed to execute task.", "%s", actionname) retval = -1 exit = true elseif not continue then - report (false, 3, "util", - "Task completed, exiting.", "%s", actionname) + logreport (false, 3, "util", + "Task completed, exiting.", "%s", actionname) exit = true else - report (false, 3, "util", - "Task completed successfully.", "%s", actionname) + logreport (false, 3, "util", + "Task completed successfully.", "%s", actionname) end end if exit then break end diff --git a/Master/texmf-dist/scripts/luaotfload/mkcharacters b/Master/texmf-dist/scripts/luaotfload/mkcharacters index abed2c936ba..59582f211cb 100755 --- a/Master/texmf-dist/scripts/luaotfload/mkcharacters +++ b/Master/texmf-dist/scripts/luaotfload/mkcharacters @@ -5,8 +5,6 @@ -- DESCRIPTION: import parts of char-def.lua -- REQUIREMENTS: lua, ConTeXt, the lualibs package -- AUTHOR: Philipp Gesang (Phg), <phg42.2a@gmail.com> --- VERSION: 2.5 --- MODIFIED: 2014-02-11 07:24:25+0100 ----------------------------------------------------------------------- -- we create a stripped-down version of char-def.lua ----------------------------------------------------------------------- @@ -15,7 +13,7 @@ -- config ----------------------------------------------------------------------- local charfile = "./build/luaotfload-characters.lua" -local chardef = "/home/phg/base/char-def.lua" +local chardef = arg[1] --- for every code point char-def.lua provides a set of fields. they --- are: @@ -65,6 +63,11 @@ for _, lib in next, { "lualibs-lua.lua", require(found) end +if not chardef then + chardef = kpse.expand_path("~/context/tex/texmf-context/tex/context/base/") + .. "/char-def.lua" +end + if not (chardef and lfs.isfile(chardef)) then --- we could grab the file from contextgarden but as Context is part --- of TL it’s not worth bothering @@ -72,6 +75,9 @@ if not (chardef and lfs.isfile(chardef)) then "Could not find ConTeXt.") end +io.write(string.format("extracting data from char-def.lua at %s\n", + chardef)) + ----------------------------------------------------------------------- -- functionality ----------------------------------------------------------------------- diff --git a/Master/texmf-dist/scripts/luaotfload/mkglyphlist b/Master/texmf-dist/scripts/luaotfload/mkglyphlist index 8fde098f1a5..f66a686322b 100755 --- a/Master/texmf-dist/scripts/luaotfload/mkglyphlist +++ b/Master/texmf-dist/scripts/luaotfload/mkglyphlist @@ -5,8 +5,6 @@ -- DESCRIPTION: part of the luaotfload package -- REQUIREMENTS: lua, lpeg, luasocket, the lualibs package -- AUTHOR: Philipp Gesang (Phg), <phg42.2a@gmail.com> --- VERSION: 2.5 --- MODIFIED: 2014-02-11 06:44:50+0100 ----------------------------------------------------------------------- -- interesting thread on the Context list: -- http://www.ntg.nl/pipermail/ntg-context/2008/029057.html diff --git a/Master/texmf-dist/scripts/luaotfload/mkimport b/Master/texmf-dist/scripts/luaotfload/mkimport new file mode 100755 index 00000000000..abe1608a60f --- /dev/null +++ b/Master/texmf-dist/scripts/luaotfload/mkimport @@ -0,0 +1,871 @@ +#!/usr/bin/env texlua +------------------------------------------------------------------------------- +-- FILE: mkimport.lua +-- USAGE: texlua ./mkimport.lua +-- DESCRIPTION: check luaotfload imports against Context +-- REQUIREMENTS: luatex, the lualibs package, Context MkIV +-- AUTHOR: Philipp Gesang (Phg), <phg@phi-gamma.net> +------------------------------------------------------------------------------- +-- + +------------------------------------------------------------------------------- +--- PURPOSE +--- +--- - Facilitate detecting changes in the fontloader source. +--- - Assist in updating source code and (partially) automate importing. +--- +--- - Account for files in the plain fontloader distribution, alert in case of +--- additions or deletions. +--- +--- - Fontloader packaging. +--- +------------------------------------------------------------------------------- + +local debug = false + +kpse.set_program_name "luatex" + +local lfs = require "lfs" +local md5 = require "md5" +local os = require "os" + +require "lualibs" + +local filedirname = file.dirname +local fileiswritable = file.is_writable +local ioloaddata = io.loaddata +local iopopen = io.popen +local iowrite = io.write +local lfschdir = lfs.chdir +local lfscurrentdir = lfs.currentdir +local lfsisdir = lfs.isdir +local lfsisfile = lfs.isfile +local md5sumhexa = md5.sumhexa +local osdate = os.date +local osgettimeofday = os.gettimeofday +local osrename = os.rename +local stringformat = string.format +local tableconcat = table.concat + +------------------------------------------------------------------------------- +-- config +------------------------------------------------------------------------------- + +local parms = { } +local our_prefix = "fontloader" +local luatex_fonts_prefix = "luatex" +local fontloader_subdir = "src/fontloader" + +local origin_paths = { + context = "tex/context/base", + fontloader = "tex/generic/context/luatex", +} + +local subdirs = { + "runtime", + "misc" +} + +local searchdirs = { + --- order is important! + fontloader_subdir, +} + +local prefixes = { + context = nil, + fontloader = "luatex", +} + +--[[doc-- + + The output name is fixed so we have to deal with it but maybe we + can get a patch to mtx-package upstreamed in the future. In any + case, we are content with renaming the result for the time being. + + The target name is constructed on the fly from the current date. + TODO It should be possible to supply a name and possibly + destination path on the command line. + + Paths are relative to the base directory (``$PWD``). + +--doc]]-- + +local loader_merge_name = "luaotfload-package.lua" +local loader_output_name = "luaotfload-package-merged.lua" +local loader_target_name = "fontloader-%s.lua" +local loader_orig_dir = "/src/fontloader/" +local loader_target_dir = "/build/" + +------------------------------------------------------------------------------- +-- helpers +------------------------------------------------------------------------------- + +local die = function (...) + io.stderr:write "[\x1b[1;30;41mfatal error\x1b[0m]: " + io.stderr:write (stringformat (...)) + io.stderr:write "\naborting.\n" + os.exit (1) +end + +local emphasis = function (txt) + return stringformat("\x1b[1m%s\x1b[0m", txt) +end + +local msg = function (...) + iowrite (stringformat (...)) + iowrite "\n" +end + +local separator_string = string.rep ("-", 79) +local separator = function () + iowrite (separator_string) + iowrite "\n" +end + +local good_tag = stringformat("[\x1b[1;30;%dmgood\x1b[0m] · ", 42) +local bad_tag = stringformat("[\x1b[1;30;%dmBAD\x1b[0m] · ", 41) +local alert_tag = stringformat("[\x1b[1;%dmalert\x1b[0m] · " , 36) +local status_tag = stringformat("[\x1b[0;%dmstatus\x1b[0m] · " , 36) + +local good = function (...) + local msg = (stringformat (...)) + iowrite (good_tag) + iowrite (msg) + iowrite "\n" +end + +local bad = function (...) + local msg = (stringformat (...)) + iowrite (bad_tag) + iowrite (msg) + iowrite "\n" +end + +local attention = function (...) + local msg = (stringformat (...)) + iowrite (alert_tag) + iowrite (msg) + iowrite "\n" +end + +local status = function (...) + local msg = (stringformat (...)) + iowrite (status_tag) + iowrite (msg) + iowrite "\n" +end + +------------------------------------------------------------------------------- +-- definitions +------------------------------------------------------------------------------- + +--- Accounting of upstream files. There are different categories: +--- +--- · *essential*: Files required at runtime. +--- · *merged*: Files merged into the fontloader package. +--- · *ignored*: Lua files not merged, but part of the format. +--- · *tex*: TeX code, i.e. format and examples. +--- · *lualibs*: Files merged, but also provided by the Lualibs package. + +local kind_essential = 0 +local kind_merged = 1 +local kind_tex = 2 +local kind_ignored = 3 +local kind_lualibs = 4 + +local kind_name = { + [0] = "essential", + [1] = "merged" , + [2] = "tex" , + [3] = "ignored" , + [4] = "lualibs" , +} + +local imports = { + + fontloader = { + { name = "basics-gen" , ours = nil , kind = kind_essential }, + { name = "basics-nod" , ours = nil , kind = kind_merged }, + { name = "basics" , ours = nil , kind = kind_tex }, + { name = "fonts-cbk" , ours = nil , kind = kind_merged }, + { name = "fonts-def" , ours = nil , kind = kind_merged }, + { name = "fonts-demo-vf-1" , ours = nil , kind = kind_ignored }, + { name = "fonts-enc" , ours = nil , kind = kind_merged }, + { name = "fonts-ext" , ours = nil , kind = kind_merged }, + { name = "fonts-inj" , ours = nil , kind = kind_merged }, + { name = "fonts-lua" , ours = nil , kind = kind_merged }, + { name = "fonts-merged" , ours = "reference" , kind = kind_essential }, + { name = "fonts-ota" , ours = nil , kind = kind_merged }, + { name = "fonts-otn" , ours = nil , kind = kind_merged }, + { name = "fonts" , ours = nil , kind = kind_merged }, + { name = "fonts" , ours = nil , kind = kind_tex }, + { name = "fonts-syn" , ours = nil , kind = kind_ignored }, + { name = "fonts-tfm" , ours = nil , kind = kind_merged }, + { name = "languages" , ours = nil , kind = kind_ignored }, + { name = "languages" , ours = nil , kind = kind_tex }, + { name = "math" , ours = nil , kind = kind_ignored }, + { name = "math" , ours = nil , kind = kind_tex }, + { name = "mplib" , ours = nil , kind = kind_ignored }, + { name = "mplib" , ours = nil , kind = kind_tex }, + { name = "plain" , ours = nil , kind = kind_tex }, + { name = "preprocessor" , ours = nil , kind = kind_ignored }, + { name = "preprocessor" , ours = nil , kind = kind_tex }, + { name = "preprocessor-test" , ours = nil , kind = kind_tex }, + { name = "swiglib" , ours = nil , kind = kind_ignored }, + { name = "swiglib" , ours = nil , kind = kind_tex }, + { name = "swiglib-test" , ours = nil , kind = kind_ignored }, + { name = "swiglib-test" , ours = nil , kind = kind_tex }, + { name = "test" , ours = nil , kind = kind_tex }, + }, --[[ [fontloader] ]] + + context = { --=> all merged + { name = "data-con" , ours = "data-con" , kind = kind_merged }, + { name = "font-afk" , ours = "font-afk" , kind = kind_merged }, + { name = "font-afm" , ours = "font-afm" , kind = kind_merged }, + { name = "font-cid" , ours = "font-cid" , kind = kind_merged }, + { name = "font-con" , ours = "font-con" , kind = kind_merged }, + { name = "font-def" , ours = "font-def" , kind = kind_merged }, + { name = "font-ini" , ours = "font-ini" , kind = kind_merged }, + { name = "font-map" , ours = "font-map" , kind = kind_merged }, + { name = "font-otb" , ours = "font-otb" , kind = kind_merged }, + { name = "font-otf" , ours = "font-otf" , kind = kind_merged }, + { name = "font-oti" , ours = "font-oti" , kind = kind_merged }, + { name = "font-otp" , ours = "font-otp" , kind = kind_merged }, + { name = "font-tfm" , ours = "font-tfm" , kind = kind_merged }, + { name = "l-boolean" , ours = "l-boolean" , kind = kind_lualibs }, + { name = "l-file" , ours = "l-file" , kind = kind_lualibs }, + { name = "l-function" , ours = "l-function" , kind = kind_lualibs }, + { name = "l-io" , ours = "l-io" , kind = kind_lualibs }, + { name = "l-lpeg" , ours = "l-lpeg" , kind = kind_lualibs }, + { name = "l-lua" , ours = "l-lua" , kind = kind_lualibs }, + { name = "l-math" , ours = "l-math" , kind = kind_lualibs }, + { name = "l-string" , ours = "l-string" , kind = kind_lualibs }, + { name = "l-table" , ours = "l-table" , kind = kind_lualibs }, + { name = "util-str" , ours = "util-str" , kind = kind_lualibs }, + }, --[[ [context] ]] +} --[[ [imports] ]] + +local hash_file = function (fname) + if not lfsisfile (fname) then + die ("cannot find %s.", fname) + end + local raw = ioloaddata (fname) + if not raw then + die ("cannot read from %s.", fname) + end + return md5sumhexa (raw) +end + +local derive_category_path = function (cat) + local subpath = origin_paths[cat] or die ("category " .. cat .. " unknown") + local location = file.join (parms.context_root, subpath) + if not lfsisdir (location) then + die ("invalid base path defined for category " + .. cat .. " at " .. location) + end + return location +end + +local derive_suffix = function (kind) + if kind == kind_tex then return ".tex" end + return ".lua" +end + +local pfxlen = { } +local strip_prefix = function (fname, prefix) + prefix = prefix or our_prefix + if not pfxlen[prefix] then pfxlen[prefix] = #prefix end + local len = pfxlen[prefix] + if #fname <= len + 2 then + --- too short to accomodate prefix + basename + return + end + if string.sub (fname, 1, len) == prefix then + return string.sub (fname, len + 2) + end +end + +local derive_fullname = function (cat, name, kind) + local tmp = prefixes[cat] + tmp = tmp and tmp .. "-" .. name or name + return tmp .. derive_suffix (kind) +end + +local derive_ourname = function (name, kind) + local suffix = derive_suffix (kind) + local subdir = kind == kind_essential and "runtime" or "misc" + return subdir, our_prefix .. "-" .. name .. suffix +end + +local format_file_definition = function (def) + return stringformat ("name = \"%s\", kind = \"%s\"", + def.name, + kind_name[def.kind] or def.kind) + .. (def.ours and (", ours = \"" .. def.ours .. "\"") or "") +end + +local is_readable = function (f) + local fh = io.open (f, "r") + if fh then + fh:close() + return true + end + return false +end + +local summarize_news = function (status) + local ni = #status.import + local nc = #status.create + local ng = #status.good + local nm = #status.missing + + separator () + msg ("Summary: Inspected %d files.", ni + nc + ng + nm) + separator () + if ng > 0 then good ("%d are up to date", ng) end + if ni > 0 then attention ("%d changed" , ni) end + if nc > 0 then attention ("%d new" , nc) end + if nm > 0 then bad ("%d missing" , nm) end + separator () + + if nm == 0 and nc == 0 and ni == 0 then + return 0 + end + + return -1 +end + +local news = function () + local status = { + import = { }, + good = { }, + create = { }, + missing = { }, + } + + for cat, entries in next, imports do + local location = derive_category_path (cat) + local nfiles = #entries + + for i = 1, nfiles do + local def = entries[i] + local name = def.name + local ours = def.ours + local kind = def.kind + local fullname = derive_fullname (cat, name, kind) + local fullpath = file.join (location, fullname) + local subdir, ourname = derive_ourname (ours or name, kind) + local ourpath = file.join (fontloader_subdir, subdir, ourname) -- relative + local imported = false + + if not is_readable (fullpath) then + bad ("source for file %s not found at %s", + emphasis (ourname), + emphasis (fullpath)) + status.missing[#status.missing + 1] = ourname + else + --- Source file exists and is readable. + if not lfsisdir (fontloader_subdir) then + die ("path for fontloader tree (" + .. fontloader_subdir .. ") is not a directory") + end + if is_readable (ourpath) then imported = true end + local src_hash = hash_file (fullpath) + local dst_hash = imported and hash_file (ourpath) + local same = src_hash == dst_hash -- same! + + if same then + good ("file %s unchanged", emphasis (ourname)) + status.good[#status.good + 1] = ourname + elseif not dst_hash then + attention ("new file %s requires import from %s", + emphasis (ourname), + emphasis (fullpath)) + status.create[#status.create + 1] = ourname + else --- src and dst exist but differ + attention ("file %s requires import", emphasis (ourname)) + status.import[#status.import + 1] = ourname + end + end + + end + end + + return summarize_news (status) +end --[[ [local news = function ()] ]] + +local get_file_definition = function (name, ourname, kind) + kind = kind or "lua" + for cat, defs in next, imports do + local fullname = derive_fullname (cat, name, kind) + local ndefs = #defs + for i = 1, ndefs do + local def = defs[i] + local dname = def.name + local dours = def.ours or def.name + local dkind = def.kind + + --- test properties + local subdir, derived = derive_ourname (dours, dkind) + if derived == ourname then return def, cat end + if derive_fullname (cat, dname, dkind) == fullname then return def, cat end + if dours == ourname then return def, cat end + if dname == fullname then return def, cat end + end + end + --- search unsuccessful +end --[[ [local get_file_definition = function (name, ourname, kind)] ]] + +local import_imported = 0 +local import_skipped = 1 +local import_failed = 2 +local import_created = 3 + +local import_status = { + [import_imported] = "imported", + [import_skipped ] = "skipped", + [import_failed ] = "failed", + [import_created ] = "created", +} + +local summarize_status = function (counters) + local imported = counters[import_imported] or 0 + local skipped = counters[import_skipped ] or 0 + local created = counters[import_created ] or 0 + local failed = counters[import_failed ] or 0 + local sum = imported + skipped + created + failed + if sum < 1 then die ("garbage total of imported files: %s", sum) end + separator () + status (" RESULT: %d files processed", sum) + separator () + if created > 0 then status ("created: %d (%d %%)", created , created * 100 / sum) end + if imported > 0 then status ("imported: %d (%d %%)", imported, imported * 100 / sum) end + if skipped > 0 then status ("skipped: %d (%d %%)", skipped , skipped * 100 / sum) end + separator () +end + +local import_file = function (name, kind, def, cat) + local expected_ourname = derive_ourname (name) + if not def or not cat then + def, cat = get_file_definition (name, expected_ourname, kind) + end + + if not def then die ("unable to find a definition matching " .. name) end + if not cat then die ("missing category for file " .. name .. " -- WTF‽") end + + local dname = def.name + local dours = def.ours or dname + local dkind = def.kind + local srcdir = derive_category_path (cat) + local fullname = derive_fullname (cat, dname, kind) + local subdir, ourname = derive_ourname (dours, kind) + local ourpath = file.join (fontloader_subdir, subdir) + local src = file.join (srcdir, fullname) + local dst = file.join (ourpath, ourname) + local new = not lfsisfile (dst) + if not new and hash_file (src) == hash_file (dst) then + status ("file %s is unchanged, skipping", fullname) + return import_skipped + end + if not (lfsisdir (ourpath) or not lfs.mkdirs (ourpath)) then + die ("failed to create directory %s for file %s", + ourpath, ourname) + end + status ("importing file %s", fullname) + file.copy (src, dst) + if hash_file (src) == hash_file (dst) then + if new then return import_created end + return import_imported end + return import_failed +end --[[ [local import_file = function (name, kind)] ]] + +local import = function (arg) + --- Multiple files + local statcount = { } -- import status codes -> size_t + for cat, defs in next, imports do + local ndefs = #defs + for i = 1, ndefs do + local def = defs[i] + local stat = import_file (def.name, def.kind, def, cat) + if stat == import_failed then + die (stringformat ("import failed at file %d of %d (%s)", + i, ndefs, def.name)) + end + statcount[stat] = statcount[stat] or 0 + statcount[stat] = statcount[stat] + 1 + end + end + summarize_status (statcount) + return 0 +end --[[ [local import = function (arg)] ]] + +local find_in_path = function (root, subdir, target) + local file = file.join (root, subdir, target) + if lfsisfile (file) then + return file + end +end + +local search_paths = function (target) + for i = 1, #searchdirs do + local root = searchdirs[i] + + for j = 1, #subdirs do + local found = find_in_path (root, subdirs[j], target) + if found then return found end + end + + end + + local found = find_in_path (parms.context_root, origin_paths.context, target) + if found then return found end + + local found = find_in_path (parms.context_root, origin_paths.fontloader, target) + if found then return found end + return false +end + +local search_defs = function (target) + local variants = { target, --[[ unstripped ]] } + local tmp + tmp = strip_prefix (target) + if tmp then variants[#variants + 1] = tmp end + tmp = strip_prefix (target, luatex_fonts_prefix) + if tmp then variants[#variants + 1] = tmp end + + local nvariants = #variants + + for cat, defs in next, imports do + local ndefs = #defs + for i = 1, ndefs do + local def = defs[i] + + for i = 1, nvariants do + local variant = variants[i] + + local dname = def.name + if variant == dname then + local found = search_paths (variant .. derive_suffix (def.kind)) + if found then return found end + end + + local dkind = def.kind + local dfull = derive_fullname (cat, dname, dkind) + if derive_fullname (cat, variant, dkind) == dfull then + local found = search_paths (dfull) + if found then return found end + end + + local dours = def.ours + if dours then + + local _, ourname = derive_ourname (dours, dkind) + if variant == dours then + local found = search_paths (ourname) + if found then return found end + end + + if variant == ourname then + local found = search_paths (ourname) + if found then return found end + end + end + + end + end + end + return false +end + +local search = function (target) + local look_for + --- pick a file + if lfsisfile (target) then --- absolute path given + look_for = target + goto found + else + + --- search as file name in local tree + look_for = search_paths (target) + if look_for then goto found end + + --- seach the definitions + look_for = search_defs (target) + if look_for then goto found end + + end + +::fail:: + if not look_for then return end + +::found:: + return look_for +end + +local find_matching_def = function (location) + local basename = file.basename (location) + if not basename then die ("corrupt path %s", location) end + local barename = file.removesuffix (basename) + local pfxless = strip_prefix (barename) + local kind = file.suffix (pfxless) or "lua" + for cat, defs in next, imports do + for _, def in next, defs do + local dname = def.name + local dours = def.ours + if dname == pfxless + or dname == barename + -- dname == basename -- can’t happen for lack of suffix + or dours == pfxless + or dours == barename + then + return cat, def + end + end + end + return false +end + +local describe = function (target, location) + --- Map files to import definitions + separator () + status ("found file %s at %s", target, location) + local cat, def = find_matching_def (location) + if not cat or not def then + die ("file %s not found in registry", location) + end + + local dname = def.name + local dkind = def.kind + local subdir, ourname = derive_ourname (def.ours or dname, dkind) + separator () + status ("category %s", cat) + status ("kind %s", kind_name[dkind]) + status ("in Context %s", derive_fullname (cat, dname, dkind)) + status ("in Luaotfload %s", ourname) + separator () + return 0 +end + +local tell = function (arg) + local target = parms.target + if not target then die "no filename given" end + + local location = search (target) + if not location then + die ("file %s not found in any of the search locations", target) + end + + return describe (target, location) +end + +local build_paths = function (argv) + if not argv or type (argv) ~= "table" then die "build_paths" end + + local orig_dir = lfscurrentdir () + local base_dir = orig_dir .. loader_orig_dir + local target_name = orig_dir .. loader_target_dir + .. stringformat (loader_target_name, os.date ("%F")) + local merge_name = base_dir .. loader_merge_name + local output_name = base_dir .. loader_output_name + + if #argv >= 2 then + local fname = argv[2] + local dir = filedirname (fname) .. "/" + if not lfsisdir (dir) then + die ("second argument must be point into existing directory, not “%s”", + argv[2]) + end + base_dir = dir + merge_name = fname + output_name = dir .. loader_output_name + end + + if #argv == 3 then + --- also set the target name + local fname = argv[3] + local dir = filedirname (fname) + if not string.is_empty (dir) and not lfsisdir (dir) then + die ("third argument must be point into writable directory, not “%s”", + argv[3]) + end + target_name = fname + end + + local ret = { + orig_dir = orig_dir, + base_dir = base_dir, + merge_name = merge_name, + target_name = target_name, + output_name = output_name, + } + return ret +end + +--[[doc-- + + Packaging works as follows: + + * Files are looked up the usual way, allowing us to override the + distribution-supplied scripts with our own alternatives in the + local path. + + * The merged package is written to the same directory as the + packaging script (not ``$PWD``). + + There is some room for improvements: Instead of reading a file with + fixed content from disk, the merge script could be composed + on-the-fly from a list of files and then written to memory (not sure + though if we can access shm_open or memfd and the likes from Lua). + +--doc]]-- + +local package = function (argv) + local t0 = osgettimeofday () + local paths = build_paths (argv) + + status ("assuming fontloader source in %s", paths.base_dir) + status ("reading merge instructions from %s", paths.merge_name) + status ("mtx-package result at %s", paths.output_name) + status ("writing output to %s", paths.target_name) + + --- check preconditions + + if not lfsisdir (paths.base_dir) then die ("directory %s does not exist", emphasis (paths.base_dir )) end + if not lfsisfile (paths.merge_name) then die ("missing merge file at %s", emphasis (paths.merge_name )) end + if not fileiswritable (paths.output_name) then die ("cannot write to %s", emphasis (paths.output_name)) end + if not fileiswritable (paths.target_name) then die ("cannot write to %s", emphasis (paths.target_name)) end +---- not lfschdir (paths.base_dir) then die ("failed to cd into %s", emphasis (paths.base_dir )) end + + if lfsisfile (paths.output_name) then + status ("output file already exists at “%s”, unlinking", + paths.output_name) + local ret, err = os.remove (paths.output_name) + if ret == nil then + if not lfschdir (paths.orig_dir) then + status ("warning: failed to cd retour into %s", + emphasis (paths.orig_dir)) + end + die ("failed to remove existing merge package") + end + end + --die ("missing merge file at %s", emphasis (paths.merge_name )) end + + --- perform merge + + local cmd = { "mtxrun", "--script", "package", "--merge", paths.merge_name } + local shl = tableconcat (cmd, " ") + + status ("invoking %s as “%s”", emphasis "mtx-package", shl) + + local fh = iopopen (shl, "r") + + if not fh then + if not lfschdir (paths.orig_dir) then + status ("warning: failed to cd retour into %s", + emphasis (paths.orig_dir)) + end + die ("merge failed; failed to invoke mtxrun") + end + + local junk = fh.read (fh, "*all") + if not junk then + status ("warning: received no output from mtxrun; this is strange") + end + + fh.close (fh) + + if debug then print (junk) end + + --- clean up + + if not lfschdir (paths.orig_dir) then + status ("warning: failed to cd retour into %s", + emphasis (paths.orig_dir)) + end + + --- check postconditions + + if not lfsisfile (paths.output_name) then + die ("merge failed; package not found at " .. paths.output_name) + end + + --- at this point we know that mtxrun was invoked correctly and the + --- result file has been created + + if lfsisfile (paths.target_name) then + status ("target file %s exists, overwriting", emphasis (paths.target_name)) + end + + local res, err = osrename (paths.output_name, paths.target_name) + + if res == nil then + die ("merge failed; failed to move package from %s to %s", + paths.output_name, paths.target_name) + end + + status ("merge complete; operation finished in %.0f ms", + (osgettimeofday() - t0) * 1000) + status ("a fresh fontloader at %s is ready to roll", paths.target_name) +end + +local help = function () + iowrite "usage: mkimport <command> [<args>]\n" + iowrite "\n" + iowrite "Where <command> is one of\n" + iowrite " help Print this help message\n" + iowrite " tell Display information about a file’s integration\n" + iowrite " news Check Context for updated files\n" + iowrite " import Update with files from Context\n" + iowrite " package Invoke mtx-package on the current fontloader\n" + iowrite "\n" +end + +local job_kind = table.mirrored { + help = help, + import = import, + news = news, + package = package, + tell = tell, +} + +------------------------------------------------------------------------------- +-- functionality +------------------------------------------------------------------------------- + +--- job_kind -> bool +local check_job = function (j) + return job_kind[j] or die ("invalid job type “%s”.", j) +end + +local parse_argv = function (argv) + local job + local tgt + local pth + + local argc = #arg + if argc < 1 or argc > 3 then return "help" end + job = arg[1] or "help" + if argc > 1 then + tgt = arg[2] + if argc == 3 then pth = arg[3] end + end + if not pth then pth = "~/context/tex/texmf-context" end + parms.context_root = kpse.expand_path (pth) + parms.target = tgt + searchdirs [#searchdirs + 1] = pth + return job +end + +------------------------------------------------------------------------------- +-- entry point +------------------------------------------------------------------------------- + +local main = function () + local job = parse_argv (arg) + local runner = check_job (job) + return runner(arg) +end + +os.exit (main ()) + +--- vim:ft=lua:ts=2:et:sw=2 diff --git a/Master/texmf-dist/scripts/luaotfload/mkstatus b/Master/texmf-dist/scripts/luaotfload/mkstatus index 802b2cd4555..f27d57118cb 100755 --- a/Master/texmf-dist/scripts/luaotfload/mkstatus +++ b/Master/texmf-dist/scripts/luaotfload/mkstatus @@ -26,6 +26,7 @@ local iosavedata = io.savedata local iopopen = io.popen local iowrite = io.write local lfsisdir = lfs.isdir +local stringmatch = string.match ----------------------------------------------------------------------- -- settings @@ -34,35 +35,95 @@ local lfsisdir = lfs.isdir local verbose = false local filelist = "./build/luaotfload-status.lua" --- result +local srcdir = "src" +local builddir = "build" +local scriptdir = "scripts" +local loaderdir = "src/fontloader" +local rtdir = "src/fontloader/runtime" +local miscdir = "src/fontloader/misc" + local names = { - --- only the runtime files and scripts - { "src", "luaotfload-auxiliary.lua", }, - { "src", "luaotfload-basics-gen.lua", }, - { "src", "luaotfload-basics-nod.lua", }, - { "build", "luaotfload-characters.lua", }, - { "src", "luaotfload-colors.lua", }, - { "src", "luaotfload-database.lua", }, - { "src", "luaotfload-diagnostics.lua", }, - { "src", "luaotfload-features.lua", }, - { "src", "luaotfload-fonts-cbk.lua", }, - { "src", "luaotfload-fonts-def.lua", }, - { "src", "luaotfload-fonts-enc.lua", }, - { "src", "luaotfload-fonts-ext.lua", }, - { "src", "luaotfload-fonts-lua.lua", }, - { "src", "luaotfload-fonts-tfm.lua", }, - { "build", "luaotfload-glyphlist.lua", }, - { "src", "luaotfload-letterspace.lua", }, - { "src", "luaotfload-loaders.lua", }, - { "src", "luaotfload-log.lua", }, - { "src", "luaotfload-main.lua", }, - { "src", "luaotfload-fontloader.lua", }, - { "src", "luaotfload-override.lua", }, - { "src", "luaotfload-parsers.lua", }, - { "src", "luaotfload-tool.lua", }, - { "scripts", "mkcharacters", }, - { "scripts", "mkglyphlist", }, - { "scripts", "mkstatus", }, -} + + --- Luaotfload runtime files + { srcdir, "luaotfload-auxiliary.lua", }, + { srcdir, "luaotfload-colors.lua", }, + { srcdir, "luaotfload-configuration.lua", }, + { srcdir, "luaotfload-database.lua", }, + { srcdir, "luaotfload-diagnostics.lua", }, + { srcdir, "luaotfload-features.lua", }, + { srcdir, "luaotfload-init.lua", }, + { srcdir, "luaotfload-letterspace.lua", }, + { srcdir, "luaotfload-loaders.lua", }, + { srcdir, "luaotfload-log.lua", }, + { srcdir, "luaotfload-main.lua", }, + { srcdir, "luaotfload-parsers.lua", }, + { srcdir, "luaotfload-resolvers.lua", }, + { srcdir, "luaotfload-tool.lua", }, + + --- generated files + { builddir, "luaotfload-characters.lua", }, + { builddir, "luaotfload-glyphlist.lua", }, + + --- scripts + { scriptdir, "mkcharacters", }, + { scriptdir, "mkglyphlist", }, + { scriptdir, "mkimport", }, + { scriptdir, "mkstatus", }, + { scriptdir, "mktests", }, + + --- merge script + { loaderdir, "luaotfload-package.lua", }, + + --- fontloader runtimes + { rtdir, "fontloader-basics-gen.lua", }, + { rtdir, "fontloader-reference.lua", }, + { rtdir, "fontloader-tl2014.lua", }, + + --- fontloader constituents + { miscdir, "fontloader-basics-nod.lua", }, + { miscdir, "fontloader-data-con.lua", }, + { miscdir, "fontloader-font-afk.lua", }, + { miscdir, "fontloader-font-afm.lua", }, + { miscdir, "fontloader-font-cid.lua", }, + { miscdir, "fontloader-font-con.lua", }, + { miscdir, "fontloader-font-def.lua", }, + { miscdir, "fontloader-font-ini.lua", }, + { miscdir, "fontloader-font-map.lua", }, + { miscdir, "fontloader-font-otb.lua", }, + { miscdir, "fontloader-font-otf.lua", }, + { miscdir, "fontloader-font-oti.lua", }, + { miscdir, "fontloader-font-otp.lua", }, + { miscdir, "fontloader-fonts-cbk.lua", }, + { miscdir, "fontloader-fonts-def.lua", }, + { miscdir, "fontloader-fonts-demo-vf-1.lua", }, + { miscdir, "fontloader-fonts-enc.lua", }, + { miscdir, "fontloader-fonts-ext.lua", }, + { miscdir, "fontloader-fonts-inj.lua", }, + { miscdir, "fontloader-fonts.lua", }, + { miscdir, "fontloader-fonts-lua.lua", }, + { miscdir, "fontloader-fonts-ota.lua", }, + { miscdir, "fontloader-fonts-otn.lua", }, + { miscdir, "fontloader-fonts-syn.lua", }, + { miscdir, "fontloader-fonts-tfm.lua", }, + { miscdir, "fontloader-font-tfm.lua", }, + { miscdir, "fontloader-languages.lua", }, + { miscdir, "fontloader-l-boolean.lua", }, + { miscdir, "fontloader-l-file.lua", }, + { miscdir, "fontloader-l-function.lua", }, + { miscdir, "fontloader-l-io.lua", }, + { miscdir, "fontloader-l-lpeg.lua", }, + { miscdir, "fontloader-l-lua.lua", }, + { miscdir, "fontloader-l-math.lua", }, + { miscdir, "fontloader-l-string.lua", }, + { miscdir, "fontloader-l-table.lua", }, + { miscdir, "fontloader-math.lua", }, + { miscdir, "fontloader-mplib.lua", }, + { miscdir, "fontloader-preprocessor.lua", }, + { miscdir, "fontloader-swiglib.lua", }, + { miscdir, "fontloader-swiglib-test.lua", }, + { miscdir, "fontloader-util-str.lua", }, + +} --[[local names]] ----------------------------------------------------------------------- -- helpers @@ -121,8 +182,9 @@ end local hash_all hash_all = function (list, acc) - if list == nil then - return hash_all (table.fastcopy (names), { }) + if acc == nil then + local base = table.fastcopy (names) + return hash_all (table.append (base, list), { }) end local finfo = list[#list] @@ -156,10 +218,58 @@ hash_all = function (list, acc) return acc end +local handle_argv = function (argv) + local ret = { files = { }, loader = nil } + local argc = #argv + if argc < 1 then return ret end + local argoff = 1 + if argv [1] == "-v" then + verbose = true + if argc == 1 then return ret end + argoff = 2 + end + local aux aux = function (acc, i) + if i > argc then return acc else + local cur = argv[i] + if type (cur) == "string" then + local loader = stringmatch (cur, "--fontloader=(.+)$") + if loader then + cur = loader + acc.loader = file.basename (cur) + end + if lfs.isfile (cur) then + local files = acc.files + files[#files + 1] = cur + end + else + die ("file not found: %s", tostring (cur)) + end + return aux (acc, i + 1) + end + end + return aux (ret, argoff) +end + +local add_files +add_files = function (lst, acc) + if lst == nil then return end + if acc == nil then return add_files (lst, { }) end + local len = #lst + if len == 0 then return acc end + local cur = lst[len] + local fname = file.basename (cur) + local path = file.dirname (cur) + acc[#acc + 1] = { path, fname } + lst[len] = nil + return add_files (lst, acc) +end + local main = function () - if arg [1] == "-v" then verbose = true end - local hashes = hash_all () + local raw_extra = handle_argv (arg) + local cuit_extra = add_files (raw_extra.files) + local hashes = hash_all (cuit_extra) local notes = git_info () + notes.loader = raw_extra.loader local serialized = table.serialize ({ notes = notes, hashes = hashes }, true) local success = io.savedata (filelist, serialized) diff --git a/Master/texmf-dist/scripts/luaotfload/mktests b/Master/texmf-dist/scripts/luaotfload/mktests new file mode 100755 index 00000000000..ad8c4f5c594 --- /dev/null +++ b/Master/texmf-dist/scripts/luaotfload/mktests @@ -0,0 +1,362 @@ +#!/usr/bin/env texlua +----------------------------------------------------------------------- +-- FILE: mktests +-- USAGE: ./mktests +-- DESCRIPTION: test the behavior of Luaotfload +-- REQUIREMENTS: Luatex > 0.76, Luaotfload +-- AUTHOR: Philipp Gesang (Phg), <phg42.2a@gmail.com> +----------------------------------------------------------------------- +-- +--===================================================================-- +-- NOTE +-- this is a stub, to be completed long-term +-- suggestions welcome +--===================================================================-- + + +local tests = { } +local lpeg = require "lpeg" +local lpegmatch = lpeg.match + +config = { luaotfload = { } } +luatexbase = { } + +kpse.set_program_name "luatex" + +require "lualibs" +require "luaotfload-basics-gen.lua" +require "luaotfload-log.lua" + +fonts = { names = { } } -- for db; normally provided by the fontloaders + +local require_init = { } + +local loadmodule = function (name) + local v = require ("luaotfload-" .. name) + if v then + local mod = { } + local tv = type (v) + if tv == "table" then + mod.name = name + mod.init = v.init + require_init [#require_init + 1] = mod + elseif tv == "function" then + mod.name = name + mod.init = v + require_init [#require_init + 1] = mod + end + end +end + +require "alt_getopt" + +loadmodule "log.lua" --- this populates the luaotfload.log.* namespace +loadmodule "parsers" --- fonts.conf, configuration, and request syntax +loadmodule "configuration" --- configuration file handling +loadmodule "database" +loadmodule "resolvers" --- Font lookup + +do --- init_modules + --- NB we don’t command the logger at this point. + local todo = #require_init + local ret = true + for i = 1, todo do + local mod = require_init[i] + local name = mod.name + local init = mod.init + if type (init) ~= "function" then + error ("luaotfload broken; module " + .. name .. " missing initializers!") + end + local v = mod.init () + if v == true then + --- evaluated well + elseif type (v) == "table" then + luaotfload[name] = v + else + error ("luaotfload broken; initialization of module " + .. name .. " returned " .. tostring (v) .. ".") + return false + end + end +end + +local names = fonts.names + +----------------------------------------------------------------------- +--- helper functions +----------------------------------------------------------------------- + +local pprint_resolve = function (input, output, result) + texio.write_nl (string.format ("[%s] “%s” -> “%s”", + result == true and "passed" or "failed", + input, + output)) +end + +local pprint_result = function (name, failed, total) + if failed == 0 then + texio.write_nl (string.format ("[%s] all %d passed", name, total)) + else + texio.write_nl (string.format ("[%s] %d of %d failed", + name, + failed, + total)) + end +end + +local pprint_spec = function (spec) + return string.format ("%s/%s*%.2fpt", + spec.specification, + spec.style or "regular", + spec.optsize or 0) +end + +----------------------------------------------------------------------- +--- 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 +----------------------------------------------------------------------- + +--- test sets + +local infer_regular_style = { + --- inferring which one is the correct style for “regular”; can be + --- obscured by synonyms like “book” etc. + { "Iwona", "Iwona-Regular.otf" }, -- trivial case + { "DejaVu Serif", "DejaVuSerif.ttf" }, + { "DejaVu Sans", "DejaVuSans.ttf" }, + { "Adobe Garamond Pro", "agaramondpro_regular.otf" }, + { "Garamond Premier Pro", "GaramondPremrPro.otf" }, + { "CMU Serif", "cmunrm.otf" }, + { "CMU Sans Serif", "cmunss.otf" }, + { "Minion Pro", "MinionPro-Regular.otf" }, + --- Below test will succeed only if we match for the + --- splainname (= sanitized tfmdata.fullname) field + --- explicitly. + { "Minion Pro Italic", "MinionPro-It.otf" }, +} + +local choose_optical_size = { + { { name = "Latin Modern Roman", optsize = 1 }, "lmroman5-regular.otf" }, + { { name = "Latin Modern Roman", optsize = 10 }, "lmroman10-regular.otf" }, + { { name = "Latin Modern Roman", optsize = 12 }, "lmroman12-regular.otf" }, + { { name = "Latin Modern Roman", optsize = 42 }, "lmroman17-regular.otf" }, + { { name = "EB Garamond", optsize = 1 }, "EBGaramond08-Regular.otf" }, + { { name = "EB Garamond", optsize = 8 }, "EBGaramond08-Regular.otf" }, + { { name = "EB Garamond", optsize = 12 }, "EBGaramond12-Regular.otf" }, + { { name = "EB Garamond", optsize = 42 }, "EBGaramond12-Regular.otf" }, + { { name = "Garamond Premier Pro", optsize = 1 }, "GaramondPremrPro-Capt.otf" }, + { { name = "Garamond Premier Pro", optsize = 10 }, "GaramondPremrPro.otf" }, + { { name = "Garamond Premier Pro", optsize = 15 }, "GaramondPremrPro-Subh.otf" }, + { { name = "Garamond Premier Pro", optsize = 42 }, "GaramondPremrPro-Disp.otf" }, +} + +local choose_style = { + { { name = "DejaVu Sans", style = "regular" }, "DejaVuSans.ttf" }, + { { name = "DejaVu Sans", style = "italic" }, "DejaVuSans-Oblique.ttf" }, + { { name = "DejaVu Sans", style = "bold" }, "DejaVuSans-Bold.ttf" }, + { { name = "DejaVu Sans", style = "bolditalic" }, "DejaVuSans-BoldOblique.ttf" }, + { { name = "Linux Libertine O", style = "regular" }, "LinLibertine_R.otf" }, + { { name = "Linux Libertine O", style = "italic" }, "LinLibertine_RI.otf" }, + { { name = "Linux Libertine O", style = "bold" }, "LinLibertine_RB.otf" }, + { { name = "Linux Libertine O", style = "bolditalic" }, "LinLibertine_RBI.otf" }, + { { name = "Liberation Serif", style = "regular" }, "LiberationSerif-Regular.ttf" }, + { { name = "Liberation Serif", style = "italic" }, "LiberationSerif-Italic.ttf" }, + { { name = "Liberation Serif", style = "bold" }, "LiberationSerif-Bold.ttf" }, + { { name = "Liberation Serif", style = "bolditalic" }, "LiberationSerif-BoldItalic.ttf" }, + { { name = "CMU Sans Serif", style = "regular" }, "cmunss.otf" }, -- no “regular” but “medium” + { { name = "CMU Sans Serif", style = "italic" }, "cmunsi.otf" }, -- no “italic” but “oblique” + { { name = "CMU Sans Serif", style = "bold" }, "cmunsx.otf" }, + { { name = "CMU Sans Serif", style = "bolditalic" }, "cmunso.otf" }, + --[[-- + Minion Pro Italic is exceptionally weird regarding identifiers in + that the postscript fontname and both info.fontname and + info.fullname are given as “minionproit”. Now its english fullname + (field 18) is “minionproital”. Only the value “fullname” in the root of + the tfmdata structure (not the one returned by fontloader.info()!) + accurately yields “Minion Pro Italic”. + + To complete the picture, the file naming isn’t very consistent either: + we find the suffixes “Regular” and “Bold”, but “It” and “BoldIt”. What + the hell were the designers smoking? + + Also, the full Minion Pro set comes with different optical sizes which + for monetary reasons cannot considered here. + --]]-- + { { name = "Minion Pro", style = "regular" }, "MinionPro-Regular.otf" }, + { { name = "Minion Pro", style = "italic" }, "MinionPro-It.otf" }, + { { name = "Minion Pro", style = "bold" }, "MinionPro-Bold.otf" }, + { { name = "Minion Pro", style = "bolditalic" }, "MinionPro-BoldIt.otf" }, +} + +--- this needs a database built with --formats=+pfa,pfb,afm + +local resolve_t1_font = { + { { name = "URW Gothic L", style = "regular" }, "a010013l.pfb" }, --> “book” +-- { { name = "URW Gothic L", style = "italic" }, "a010033l.pfb" }, --> “book oblique” +-- { { name = "URW Gothic L", style = "bold" }, "a010015l.pfb" }, --> “demi” +-- { { name = "URW Gothic L", style = "bolditalic" }, "a010035l.pfb" }, --> “demi oblique” + { { name = "Century Schoolbook L", style = "regular" }, "c059013l.pfb" }, + { { name = "Century Schoolbook L", style = "italic" }, "c059033l.pfb" }, + { { name = "Century Schoolbook L", style = "bold" }, "c059016l.pfb" }, + { { name = "Century Schoolbook L", style = "bolditalic" }, "c059036l.pfb" }, + { { name = "Nimbus Roman No9 L", style = "regular" }, "n021003l.pfb" }, + { { name = "Nimbus Roman No9 L", style = "italic" }, "n021023l.pfb" }, + { { name = "Nimbus Roman No9 L", style = "bold" }, "n021004l.pfb" }, --- medium, actually + { { name = "Nimbus Roman No9 L", style = "bolditalic" }, "n021024l.pfb" }, +} + +local translate_style = { + regular = "r", + italic = "i", + bold = "b", + bolditalic = "bi", +} + +local font_name_tests = { + infer_regular_style, + choose_optical_size, + choose_style, + resolve_t1_font, +} + +local default_spec = { + name = false, + lookup = "name", + specification = false, + optsize = 0, +} + +local resolve_font_name = function () + local failed, total = 0, 0 + for nset = 1, #font_name_tests do + local set = font_name_tests[nset] + + for ntest = 1, #set do + local test = set[ntest] + local input, output = test[1], test[2] + + if type (input) == "string" then + local input_spec = table.copy (default_spec) + input_spec.name = input + input_spec.specification = input_spec.lookup .. ":" .. input + local result = fonts.names.lookup_font_name (input_spec) == output + total = total + 1 + if not result then + failed = failed + 1 + end + pprint_resolve (input, output, result) + + else + local input_spec, output = test[1], test[2] + input_spec.specification = (input_spec.lookup + or default_spec.lookup) + .. ":" .. input_spec.name + input_spec.optsize = input_spec.optsize or default_spec.optsize + input_spec.style = translate_style [input_spec.style] + local result = fonts.names.lookup_font_name (input_spec) == output + total = total + 1 + if not result then + failed = failed + 1 + end + pprint_resolve (pprint_spec (input_spec), output, result) + end + + end + end + return failed, total +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 () + total = total + 1 + pprint_result (name, newfailed, newtotal) + failed = failed + newfailed + total = total + newtotal + end + + if failed == 0 then + texio.write_nl (string.format ("[report] all %d tests passed.", total)) + else + texio.write_nl (string.format ("[report] %d of %d tests failed (%d %%).", + failed, + total, + failed / total * 100)) + end + texio.write_nl "" + os.exit (0) +end + +return main () + +--- vim:ft=lua:ts=2:et:sw=2 |