From 69f51727fba1c348d78348d9f163cf884e7ab558 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 9 May 2013 13:45:14 +0200 Subject: add querying of font metadata to luaotfload-tool --- luaotfload-auxiliary.lua | 4 ++ luaotfload-database.lua | 26 +++++---- luaotfload-tool.lua | 147 +++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 162 insertions(+), 15 deletions(-) diff --git a/luaotfload-auxiliary.lua b/luaotfload-auxiliary.lua index 2d459d0..9f7974a 100644 --- a/luaotfload-auxiliary.lua +++ b/luaotfload-auxiliary.lua @@ -64,6 +64,10 @@ local add_fontdata_fallbacks = function (fontdata) metadata = fontdata.shared.rawdata.metadata fontdata.units = fontparameters.units local resources = fontdata.resources + --- the next line is a hack that fixes scaling of fonts with + --- non-standard em-sizes (most ms fonts have 2048, others + --- come with 256) + --- this is considered a bug in the font loader fontdata.size = fontparameters.size * fontdata.units / 1000 --- for legacy fontspec.lua and unicode-math.lua fontdata.shared.otfdata = metadata diff --git a/luaotfload-database.lua b/luaotfload-database.lua index 576341f..96db195 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -146,10 +146,11 @@ This is a sketch of the luaotfload db: psname : string; subfamily : string; } - size : int list; - slant : int; - weight : int; - width : int; + size : int list; + slant : int; + weight : int; + width : int; + units_per_em : int; // mainly 1000, but also 2048 or 256 } and filestatus = (fullname, { index : int list; timestamp : int }) dict @@ -836,13 +837,16 @@ font_fullinfo = function (filename, subfont) report("log", 1, "db", "broken font rejected", "%s", basefile) return end - tfmdata.fontname = metadata.fontname - tfmdata.fullname = metadata.fullname - tfmdata.familyname = metadata.familyname - tfmdata.filename = { filename, subfont } -- always store full path - tfmdata.weight = metadata.pfminfo.weight - tfmdata.width = metadata.pfminfo.width - tfmdata.slant = metadata.italicangle + tfmdata.fontname = metadata.fontname + tfmdata.fullname = metadata.fullname + tfmdata.familyname = metadata.familyname + tfmdata.filename = { filename, subfont } -- always store full path + tfmdata.weight = metadata.pfminfo.weight + tfmdata.width = metadata.pfminfo.width + tfmdata.slant = metadata.italicangle + --- this is for querying + tfmdata.units_per_em = metadata.units_per_em + tfmdata.version = metadata.version -- don't waste the space with zero values tfmdata.size = { metadata.design_size ~= 0 and metadata.design_size or nil, diff --git a/luaotfload-tool.lua b/luaotfload-tool.lua index 0cd19b1..6662291 100755 --- a/luaotfload-tool.lua +++ b/luaotfload-tool.lua @@ -32,6 +32,8 @@ 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 +66,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 @@ -228,7 +228,7 @@ set. --]]-- local action_sequence = { - "loglevel", "help", "version", "flush", "generate", "query" + "loglevel", "help", "version", "flush", "generate", "list", "query" } local action_pending = table.tohash(action_sequence, false) @@ -286,7 +286,7 @@ actions.query = function (job) lookup = "name", specification = "name:" .. query, optsize = 0, - } + } local foundname, subfont, success = fonts.names.resolve(nil, nil, tmpspec) @@ -317,6 +317,137 @@ actions.query = function (job) return true, true end +--- --list= +--- --list=: +--- +--- --list= --fields=,,,... + +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] = "" + 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, ntargets + + if asked_value then + logs.names_report(false, 2, "list", "restricting to value %s", asked_value) + targets = { } + 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 + ntargets = #targets + else --- all + targets = mappings + ntargets = nmappings + end + 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,6 +461,7 @@ 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 } @@ -337,12 +469,14 @@ local process_cmdline = function ( ) -- unit -> jobspec local long_options = { alias = 1, ["flush-cache"] = "c", + fields = 1, find = 1, force = "f", fuzzy = "F", help = "h", info = "i", limit = 1, + list = 1, log = 1, quiet = "q", update = "u", @@ -401,6 +535,11 @@ local process_cmdline = function ( ) -- unit -> jobspec config.luaotfload.self = optarg[n] elseif v == "c" 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] end end -- cgit v1.2.3