summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/scripts/luaotfload
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2015-12-11 23:16:34 +0000
committerKarl Berry <karl@freefriends.org>2015-12-11 23:16:34 +0000
commit71945bfdf73e58a09c05155c6d49729528cac3f7 (patch)
treeaa614024e79d15166a1aa500e223c748b1a66c83 /Master/texmf-dist/scripts/luaotfload
parentfa3dbdbd11bbc7da0c06e2871472419998e645c9 (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-xMaster/texmf-dist/scripts/luaotfload/luaotfload-tool.lua389
-rwxr-xr-xMaster/texmf-dist/scripts/luaotfload/mkcharacters12
-rwxr-xr-xMaster/texmf-dist/scripts/luaotfload/mkglyphlist2
-rwxr-xr-xMaster/texmf-dist/scripts/luaotfload/mkimport871
-rwxr-xr-xMaster/texmf-dist/scripts/luaotfload/mkstatus174
-rwxr-xr-xMaster/texmf-dist/scripts/luaotfload/mktests362
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