summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/scripts/luaotfload/luaotfload-tool.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/scripts/luaotfload/luaotfload-tool.lua')
-rwxr-xr-xMaster/texmf-dist/scripts/luaotfload/luaotfload-tool.lua287
1 files changed, 258 insertions, 29 deletions
diff --git a/Master/texmf-dist/scripts/luaotfload/luaotfload-tool.lua b/Master/texmf-dist/scripts/luaotfload/luaotfload-tool.lua
index 0cd19b1d3a4..352697ced37 100755
--- a/Master/texmf-dist/scripts/luaotfload/luaotfload-tool.lua
+++ b/Master/texmf-dist/scripts/luaotfload/luaotfload-tool.lua
@@ -26,12 +26,29 @@ see the luaotfload documentation for more info. Report bugs to
--doc]]--
+--[[doc--
+
+ We test for Lua 5.1 by means of capability detection to see if
+ we’re running an outdated Luatex. If so, we hand over control to
+ the legacy db runner.
+
+ \url{http://lua-users.org/wiki/LuaVersionCompatibility}
+
+--doc]]--
+
kpse.set_program_name"luatex"
+if _G.getfenv then
+ local oldscript = kpse.find_file"luaotfload-legacy-tool.lua"
+ return require(oldscript)
+end
+
local stringformat = string.format
local texiowrite_nl = texio.write_nl
local stringlower = string.lower
+local C, Ct, P = lpeg.C, lpeg.Ct, lpeg.P
+local lpegmatch = lpeg.match
local loader_file = "luatexbase.loader.lua"
local loader_path = assert(kpse.find_file(loader_file, "lua"),
@@ -64,8 +81,6 @@ local config = config
config.luaotfload = config.luaotfload or { }
do -- we don’t have file.basename and the likes yet, so inline parser ftw
- local C, P = lpeg.C, lpeg.P
- local lpegmatch = lpeg.match
local slash = P"/"
local dot = P"."
local noslash = 1 - slash
@@ -90,6 +105,19 @@ config.lualibs.load_extended = false
require"lualibs"
+--- prepare directories: the cache function in Luatex-Fonts
+--- checks for writable directory only on startup, so everything
+--- has to be laid out before we load basics-gen
+
+local cachepath = kpse.expand_var"$TEXMFVAR"
+if not lfs.isdir(cachepath) then
+ dir.mkdirs(cachepath)
+ if not lfs.isdir(cachepath) then
+ texiowrite(stringformat(
+ "ERROR could not create directory %s", cachepath))
+ end
+end
+
--[[doc--
\fileent{luatex-basics-gen.lua} calls functions from the
\luafunction{texio.*} library; too much for our taste.
@@ -129,17 +157,21 @@ This tool is part of the luaotfload package. Valid options are:
-v --verbose=LEVEL be more verbose (print the searched directories)
-vv print the loaded fonts
-vvv print all steps of directory searching
+ --log=stdout redirect log output to stdout
+
-V --version print version and exit
-h --help print this message
--alias=<name> force behavior of “luaotfload-tool” or legacy
“mkluatexfontdb”
+
-------------------------------------------------------------------------------
DATABASE
-u --update update the database
-f --force force re-indexing all fonts
- -c --flush-cache empty cache of font requests
+ -l --flush-lookups empty lookup cache of font requests
+ -D --dry-run skip loading of fonts, just scan
--find="font name" query the database for a font name
-F --fuzzy look for approximate matches if --find fails
@@ -147,18 +179,26 @@ This tool is part of the luaotfload package. Valid options are:
(default: n = 1)
-i --info display font metadata
- --log=stdout redirect log output to stdout
+ --list=<criterion> output list of entries by field <criterion>
+ --list=<criterion>:<value> restrict to entries with <criterion>=<value>
+ --fields=<f1>,<f2>,…,<fn> which fields <f> to print with --list
The font database will be saved to
%s
%s
+-------------------------------------------------------------------------------
+ FONT CACHE
+
+ --cache=<directive> operate on font cache, where <directive> is
+ “show”, “purge”, or “erase”
+
]],
mkluatexfontdb = [[
Usage: %s [OPTION]...
-Rebuild the LuaTeX font database.
+Rebuild or update the LuaTeX font database.
Valid options:
-f --force force re-indexing all fonts
@@ -228,7 +268,8 @@ set.
--]]--
local action_sequence = {
- "loglevel", "help", "version", "flush", "generate", "query"
+ "loglevel", "help", "version", "cache",
+ "flush", "generate", "list", "query",
}
local action_pending = table.tohash(action_sequence, false)
@@ -241,6 +282,7 @@ actions.loglevel = function (job)
logs.set_loglevel(job.log_level)
logs.names_report("info", 3, "util",
"setting log level", "%d", job.log_level)
+ logs.names_report("log", 0, "util", "lua=%s", _VERSION)
return true, true
end
@@ -256,28 +298,47 @@ end
actions.generate = function (job)
local fontnames, savedname
- fontnames = names.update(fontnames, job.force_reload)
+ fontnames = names.update(fontnames, job.force_reload, job.dry_run)
logs.names_report("info", 2, "db",
"Fonts in the database: %i", #fontnames.mappings)
- savedname = names.save(fontnames)
- if savedname then --- FIXME have names.save return bool
+ local success = names.save(fontnames)
+ if success then
return true, true
end
return false, false
end
actions.flush = function (job)
- local success, lookups = names.flush_cache()
+ local success, lookups = names.flush_lookup_cache()
if success then
- local savedname = names.save_lookups()
- logs.names_report("info", 2, "cache", "Cache emptied")
- if savedname then
+ local success = names.save_lookups()
+ if success then
+ logs.names_report("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,
+}
+
+actions.cache = function (job)
+ local directive = cache_directives[job.cache]
+ if not directive or type(directive) ~= "function" then
+ logs.names_report("info", 2, "cache",
+ "Invalid font cache directive %s.", job.cache)
+ return false, false
+ end
+ if directive() then
+ return true, true
+ end
+ return false, false
+end
+
actions.query = function (job)
local query = job.query
@@ -286,7 +347,7 @@ actions.query = function (job)
lookup = "name",
specification = "name:" .. query,
optsize = 0,
- }
+ }
local foundname, subfont, success =
fonts.names.resolve(nil, nil, tmpspec)
@@ -317,6 +378,158 @@ actions.query = function (job)
return true, true
end
+--- --list=<criterion>
+--- --list=<criterion>:<value>
+---
+--- --list=<criterion> --fields=<f1>,<f2>,<f3>,...<fn>
+
+local get_fields get_fields = function (entry, fields, acc, n)
+ if not acc then
+ return get_fields(entry, fields, { }, 1)
+ end
+
+ local field = fields[n]
+ if field then
+ local value = entry[field]
+ acc[#acc+1] = value or false
+ return get_fields(entry, fields, acc, n+1)
+ end
+ return acc
+end
+
+local comma = P","
+local noncomma = 1-comma
+local split_comma = Ct((C(noncomma^1) + comma)^1)
+
+local texiowrite_nl = texio.write_nl
+local tableconcat = table.concat
+local stringexplode = string.explode
+
+local separator = "\t" --- could be “,” for csv
+
+local format_fields format_fields = function (fields, acc, n)
+ if not acc then
+ return format_fields(fields, { }, 1)
+ end
+
+ local field = fields[n]
+ if field ~= nil then
+ if field == false then
+ acc[#acc+1] = "<none>"
+ else
+ acc[#acc+1] = tostring(field)
+ end
+ return format_fields(fields, acc, n+1)
+ end
+ return tableconcat(acc, separator)
+end
+
+local set_primary_field
+set_primary_field = function (fields, addme, acc, n)
+ if not acc then
+ return set_primary_field(fields, addme, { addme }, 1)
+ end
+
+ local field = fields[n]
+ if field then
+ if field ~= addme then
+ acc[#acc+1] = field
+ end
+ return set_primary_field(fields, addme, acc, n+1)
+ end
+ return acc
+end
+
+actions.list = function (job)
+ local criterion = job.criterion
+
+ local asked_fields = job.asked_fields
+ if asked_fields then
+ asked_fields = lpegmatch(split_comma, asked_fields)
+ else
+ --- some defaults
+ asked_fields = { "fullname", "version", }
+ end
+
+ if not names.data then
+ names.data = names.load()
+ end
+
+ local mappings = names.data.mappings
+ local nmappings = #mappings
+
+ if criterion == "*" then
+ logs.names_report(false, 1, "list", "all %d entries", nmappings)
+ for i=1, nmappings do
+ local entry = mappings[i]
+ local fields = get_fields(entry, asked_fields)
+ --- we could collect these instead ...
+ local formatted = format_fields(fields)
+ texiowrite_nl(formatted)
+ end
+
+ else
+ criterion = stringexplode(criterion, ":") --> { field, value }
+ local asked_value = criterion[2]
+ criterion = criterion[1]
+ asked_fields = set_primary_field(asked_fields, criterion)
+
+ logs.names_report(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
+ logs.names_report(false, 2, "list", "restricting to value %s", asked_value)
+ for i=1, nmappings do
+ local entry = mappings[i]
+ if entry[criterion]
+ and tostring(entry[criterion]) == asked_value
+ then
+ targets[#targets+1] = entry
+ end
+ end
+
+ else --- whichever have the field, sorted
+ local categories, by_category = { }, { }
+ for i=1, nmappings do
+ local entry = mappings[i]
+ local value = entry[criterion]
+ if value then
+ --value = tostring(value)
+ local entries = by_category[value]
+ if not entries then
+ entries = { entry }
+ categories[#categories+1] = value
+ else
+ entries[#entries+1] = entry
+ end
+ by_category[value] = entries
+ end
+ end
+ table.sort(categories)
+
+ for i=1, #categories do
+ local entries = by_category[categories[i]]
+ for j=1, #entries do
+ targets[#targets+1] = entries[j]
+ end
+ end
+ end
+ local ntargets = #targets
+ logs.names_report(false, 2, "list", "%d entries", ntargets)
+
+ --- now, output the collection
+ for i=1, ntargets do
+ local entry = targets[i]
+ local fields = get_fields(entry, asked_fields)
+ local formatted = format_fields(fields)
+ texiowrite_nl(formatted)
+ end
+ end
+
+ return true, true
+end
+
--[[--
Command-line processing.
mkluatexfontdb.lua relies on the script alt_getopt to process argv and
@@ -330,27 +543,32 @@ alt_getopt.
local process_cmdline = function ( ) -- unit -> jobspec
local result = { -- jobspec
force_reload = nil,
+ criterion = "",
query = "",
log_level = 1, --- 2 is approx. the old behavior
}
local long_options = {
- alias = 1,
- ["flush-cache"] = "c",
- find = 1,
- force = "f",
- fuzzy = "F",
- help = "h",
- info = "i",
- limit = 1,
- log = 1,
- quiet = "q",
- update = "u",
- verbose = 1 ,
- version = "V",
+ alias = 1,
+ cache = 1,
+ ["dry-run"] = "D",
+ ["flush-lookups"] = "l",
+ fields = 1,
+ find = 1,
+ force = "f",
+ fuzzy = "F",
+ help = "h",
+ info = "i",
+ limit = 1,
+ list = 1,
+ log = 1,
+ quiet = "q",
+ update = "u",
+ verbose = 1 ,
+ version = "V",
}
- local short_options = "cfFiquvVh"
+ local short_options = "DfFilquvVh"
local options, _, optarg =
alt_getopt.get_ordered_opts (arg, short_options, long_options)
@@ -399,14 +617,25 @@ local process_cmdline = function ( ) -- unit -> jobspec
result.show_info = true
elseif v == "alias" then
config.luaotfload.self = optarg[n]
- elseif v == "c" then
+ elseif v == "l" then
action_pending["flush"] = true
+ elseif v == "list" then
+ action_pending["list"] = true
+ result.criterion = optarg[n]
+ elseif v == "fields" then
+ result.asked_fields = optarg[n]
+ elseif v == "cache" then
+ action_pending["cache"] = true
+ result.cache = optarg[n]
+ elseif v == "D" then
+ result.dry_run = true
end
end
if config.luaotfload.self == "mkluatexfontdb" then
action_pending["generate"] = true
result.log_level = math.max(2, result.log_level)
+ logs.set_logout"stdout"
end
return result
end