diff options
author | Philipp Gesang <phg42.2a@gmail.com> | 2014-02-12 07:50:06 +0100 |
---|---|---|
committer | Philipp Gesang <phg42.2a@gmail.com> | 2014-02-12 07:50:06 +0100 |
commit | 9138da7d4a53d65bc15f3a5dc73fd373db40bdf7 (patch) | |
tree | 702093c750d81aa2e8810f484627b51d6b485c27 /luaotfload-tool.lua | |
parent | ffa5a347f68805e218c61c344c0b8a895c4bb8db (diff) | |
download | luaotfload-9138da7d4a53d65bc15f3a5dc73fd373db40bdf7.tar.gz |
[*] move source files to ./src
Diffstat (limited to 'luaotfload-tool.lua')
-rwxr-xr-x | luaotfload-tool.lua | 1263 |
1 files changed, 0 insertions, 1263 deletions
diff --git a/luaotfload-tool.lua b/luaotfload-tool.lua deleted file mode 100755 index 35765b5..0000000 --- a/luaotfload-tool.lua +++ /dev/null @@ -1,1263 +0,0 @@ -#!/usr/bin/env texlua ------------------------------------------------------------------------ --- FILE: luaotfload-tool.lua --- DESCRIPTION: database functionality --- REQUIREMENTS: luaotfload 2.5 --- AUTHOR: Khaled Hosny, Élie Roux, Philipp Gesang --- VERSION: 2.5 --- LICENSE: GPL v2.0 --- MODIFIED: 2014-01-14 13:17:04+0100 ------------------------------------------------------------------------ - -luaotfload = luaotfload or { } -local version = "2.5" --- <int: major>.<int: minor>-<int: fixes> -luaotfload.version = version -luaotfload.self = "luaotfload-tool" - ---[[doc-- - -luaotfload-tool(1) - -This file was originally written (as \fileent{mkluatexfontdb.lua}) by -Elie Roux and Khaled Hosny and, as a derived work of ConTeXt, is -provided under the terms of the GPL v2.0 license as printed in full -text in the manual (luaotfload.pdf). - - \url{http://www.gnu.org/licenses/old-licenses/gpl-2.0.html}. - -This file is a wrapper for the luaotfload font names module -(luaotfload-database.lua). It is part of the luaotfload bundle, please -see the luaotfload documentation for more info. Report bugs to - - \url{https://github.com/lualatex/luaotfload/issues}. - ---doc]]-- - -kpse.set_program_name "luatex" - ---[[doc-- - - We test for Lua 5.1 by means of capability detection to see if - we’re running an outdated Luatex. If so, we bail. - - \url{http://lua-users.org/wiki/LuaVersionCompatibility} - ---doc]]-- - - -local ioopen = io.open -local iowrite = io.write -local kpsefind_file = kpse.find_file -local next = next -local osdate = os.date -local ostype = os.type -local stringexplode = string.explode -local stringformat = string.format -local stringlower = string.lower -local stringrep = string.rep -local tableconcat = table.concat -local texiowrite_nl = texio.write_nl -local texiowrite = texio.write -local tonumber = tonumber -local type = type - -local runtime -if _G.getfenv ~= nil then -- 5.1 or LJ - if _G.jit ~= nil then - runtime = { "jit", jit.version } - else - runtime = { "stock", _VERSION } - print "FATAL ERROR" - print "Luaotfload requires a Luatex version >=0.76." - print "Please update your TeX distribution!" - os.exit (-1) - end -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) - -config = config or { } -local config = config -local luaotfloadconfig = config.luaotfload or { } -config.luaotfload = luaotfloadconfig -luaotfloadconfig.version = luaotfloadconfig.version or version -luaotfloadconfig.names_dir = luaotfloadconfig.names_dir or "names" -luaotfloadconfig.cache_dir = luaotfloadconfig.cache_dir or "fonts" -luaotfloadconfig.index_file = luaotfloadconfig.index_file - or "luaotfload-names.lua" -luaotfloadconfig.formats = luaotfloadconfig.formats - or "otf,ttf,ttc,dfont" -luaotfloadconfig.reload = false -if not luaotfloadconfig.strip then - luaotfloadconfig.strip = true -end - -config.lualibs = config.lualibs or { } -config.lualibs.verbose = false -config.lualibs.prefer_merged = true -config.lualibs.load_extended = true - -require "lualibs" -local tabletohash = table.tohash -local stringsplit = string.split - ---[[doc-- -\fileent{luatex-basics-gen.lua} calls functions from the -\luafunction{texio.*} library; too much for our taste. -We intercept them with dummies. - -Also, it sets up dummies in place of the tables created by the Context -libraries. Since we have loaded the lualibs already this would cause -collateral damage for some libraries whose namespace would be -overridden. We employ our usual backup-restore strategy to work around -this. (Postponing the loading of the lualibs code is not an option -because the functionality is needed by basics-gen itself.) ---doc]]-- - -local dummy_function = function ( ) end -local backup = { - write = texio.write, - write_nl = texio.write_nl, - utilities = utilities, -} - -texio.write, texio.write_nl = dummy_function, dummy_function -require"luaotfload-basics-gen.lua" - -texio.write, texio.write_nl = backup.write, backup.write_nl -utilities = backup.utilities - -require"luaotfload-log.lua" --- this populates the luaotfload.log.* namespace -require"luaotfload-parsers" --- fonts.conf and request syntax -require"luaotfload-database" -require"alt_getopt" - -local names = fonts.names -local status_file = "luaotfload-status" -local luaotfloadstatus = require (status_file) -luaotfloadconfig.status = luaotfloadstatus -local sanitize_fontname = names.sanitize_fontname - -local log = luaotfload.log -local report = log.report - -local pathdata = names.path -local names_plain = pathdata.index.lua -local names_gzip = names_plain .. ".gz" -local names_bin = pathdata.index.luc - -local help_messages = { - ["luaotfload-tool"] = [[ - -Usage: %s [OPTIONS...] - - Luaotfload font management and diagnostic utility. - This program is part of the Luaotfload package. - - Valid options are: - -------------------------------------------------------------------------------- - VERBOSITY AND DIAGNOSTICS - - -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 - --log=stdout redirect log output to stdout - - -V --version print version and exit - -h --help print this message - --diagnose=CHECK run a self test procedure; one of "files", - "environment", "index", "permissions", or - "repository" - -------------------------------------------------------------------------------- - DATABASE - - -u --update update the database - -n --no-reload suppress db update - --no-strip keep redundant information in db - -f --force force re-indexing all fonts - -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 - -p --prefer-texmf prefer fonts in the TEXMF over system fonts - --max-fonts=N process at most N font files - - --find="font name" query the database for a font name - -F --fuzzy look for approximate matches if --find fails - --limit=n limit display of fuzzy matches to <n> - (default: n = 1) - - -i --info display basic font metadata - -I --inspect display detailed font metadata - -w --warnings display warnings generated by the - fontloader library - - --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 - -b --show-blacklist show blacklisted files - -The font database will be saved to - %s - %s - -------------------------------------------------------------------------------- - FONT CACHE - - --cache=<directive> operate on font cache, where <directive> is - "show", "purge", or "erase" - -The font cache will be written to - %s - -]], - mkluatexfontdb = [[ -FATAL ERROR -As of Luaotfload v2.5, legacy behavior is not supported anymore. Please -update your scripts and/or habits! Kthxbye. -]], - short = [[ -Usage: luaotfload-tool [--help] [--version] [--verbose=<lvl>] - [--update] [--force] [--prefer-texmf] - [--dry-run] [--formats=<extension list>] - [--find=<font name>] [--fuzzy] [--info] [--inspect] - [--list=<criterion>] [--fields=<field list>] - [--cache=<directive>] [--flush-lookups] - [--show-blacklist] [--diagnose=<procedure>] - -Enter 'luaotfload-tool --help' for a larger list of options. -]] -} - -local help_msg = function (version) - local template = help_messages[version] - iowrite(stringformat(template, - luaotfload.self, --- names_plain, - names_gzip, - names_bin, - caches.getwritablepath ( - luaotfloadconfig.cache_dir))) -end - -local about = [[ -%s: - Luaotfload font management and diagnostic utility. - License: GNU GPL v2.0. - Report problems to <https://github.com/lualatex/luaotfload/issues> -]] - -local version_msg = function ( ) - local out = function (...) texiowrite_nl (stringformat (...)) end - out (about, luaotfload.self) - out ("%s version %q", luaotfload.self, version) - out ("revision %q", luaotfloadstatus.notes.revision) - out ("database version %q", names.version) - out ("Lua interpreter: %s; version %q", runtime[1], runtime[2]) - out ("Luatex SVN revision %d", status.luatex_svn) - out ("Luatex version %.2f.%d", - status.luatex_version / 100, - status.luatex_revision) - out "" -end - - ---- makeshift formatting - -local head_adornchars = { - [1] = "*", [2] = "=", [3] = "~", [4] = "-", [5] = "·", -} - -local textwidth = 80 -local wd_leftcolumn = math.floor(textwidth * .25) -local key_fmt = stringformat([[%%%ds]], wd_leftcolumn) -local val_fmt = [[%s]] -local fieldseparator = ":" -local info_fmt = key_fmt .. fieldseparator .. " " .. val_fmt - -local currentdepth = 0 -local counterstack = { } -- counters per level -local counterformat = "%d" - -local format_counter = function (stack) - local acc = { } - for lvl=1, #stack do - acc[#acc+1] = stringformat(counterformat, stack[lvl]) - end - return tableconcat(acc, ".") -end - -local print_heading = function (title, level) - local structuredata - if currentdepth == level then -- top is current - counterstack[#counterstack] = counterstack[#counterstack] + 1 - elseif currentdepth < level then -- push new - counterstack[#counterstack+1] = 1 - else -- pop - local diff = currentdepth - level - while diff > 0 do - counterstack[#counterstack] = nil - diff = diff - 1 - end - counterstack[#counterstack] = counterstack[#counterstack] + 1 - end - currentdepth = level - - texiowrite_nl "" - if not level or level > #head_adornchars then - level = #head_adornchars - end - local adornchar = head_adornchars[level] - - local counter = format_counter(counterstack) - - local s = adornchar .. adornchar .. " " - .. counter .. " " - .. title .. " " - texiowrite_nl (s .. stringrep(adornchar, textwidth-utf.len(s))) -end - -local baseindent = " " - ---[[doc-- - - show_info_items -- Together with show_info_table prints the table returned by - fontloader.info(), recursing into nested tables if appropriate (as necessitated - by Luatex versions 0.78+ which include the pfminfo table in the result. - ---doc]]-- - -local show_info_table show_info_table = function (t, depth) - depth = depth or 0 - local indent = stringrep (baseindent, depth) - local keys = table.sortedkeys (t) - for n = 1, #keys do - local key = keys [n] - local val = t [key] - if type (val) == "table" then - texiowrite_nl (indent .. stringformat (info_fmt, key, "<table>")) - show_info_table (val, depth + 1) - else - texiowrite_nl (indent .. stringformat (info_fmt, key, val)) - end - end -end - -local show_info_items = function (fontinfo) - print_heading (fontinfo.fullname, 1) - texiowrite_nl "" - show_info_table (fontinfo) - texiowrite_nl "" -end - -local p_eol = S"\n\r"^1 -local p_space = S" \t\v"^0 -local p_line = p_space * C((1 - p_eol)^1)^-1 -local p_lines = Ct(p_line * (p_eol^1 * p_line^-1)^0) - -local show_fontloader_warnings = function (ws) - local nws = #ws - print_heading(stringformat( - [[the fontloader emitted %d warnings]], - nws), 2) - texiowrite_nl "" - for i=1, nws do - local w = ws[i] - texiowrite_nl (stringformat("%d:", i)) - local lines = lpegmatch(p_lines, w) - for i=1, #lines do - local line = lines[i] - texiowrite_nl(" · " .. line) - end - texiowrite_nl "" - end -end - -local p_spacechar = S" \n\r\t\v" -local p_wordchar = (1 - p_spacechar) -local p_whitespace = p_spacechar^1 -local p_word = C(p_wordchar^1) -local p_words = Ct(p_word * (p_whitespace * p_word)^0) - ---- string -> int -> string list -local reflow = function (text, width) - local words - if type(text) == "string" then - words = lpegmatch(p_words, text) - if #words < 2 then - return { text } - end - else - words = text - if #words < 2 then - return words - end - end - - local space = " " - local utflen = utf.len - local reflowed = { } - - local first = words[1] - local linelen = #first - local line = { first } - - for i=2, #words do - local word = words[i] - local lword = utflen(word) - linelen = linelen + lword + 1 - if linelen > width then - reflowed[#reflowed+1] = tableconcat(line) - linelen = #word - line = { word } - else - line[#line+1] = space - line[#line+1] = word - end - end - reflowed[#reflowed+1] = tableconcat(line) - return reflowed -end - ---- string -> 'a -> string list -local print_field = function (key, val) - val = tostring(val) - local lhs = stringformat(key_fmt, key) .. fieldseparator .. " " - local wd_lhs = #lhs - local lines = reflow(val, textwidth - wd_lhs) - - texiowrite_nl(lhs) - texiowrite(lines[1]) - if #lines > 1 then - local indent = stringrep(" ", wd_lhs) - for i=2, #lines do - texiowrite_nl(indent) - texiowrite (lines[i]) - end - end -end - -local display_names = function (names) - print_heading("Font Metadata", 2) - for i=1, #names do - local lang, namedata = names[i].lang, names[i].names - print_heading(stringformat("Language: %s ", i, lang), 3) - texiowrite_nl "" - if namedata then - for field, value in next, namedata do - print_field(field, value) - end - end - end -end - ---- see luafflib.c -local general_fields = { - --- second: l -> literal | n -> length | d -> date - { "fullname", "l", "font name" }, - { "version", "l", "font version" }, - { "creationtime", "d", "creation time" }, - { "modificationtime", "d", "modification time" }, - { "subfonts", "n", "number of subfonts" }, - { "glyphcnt", "l", "number of glyphs" }, - { "weight", "l", "weight indicator" }, - { "design_size", "l", "design size" }, - { "design_range_bottom", "l", "design size min" }, - { "design_range_top", "l", "design size max" }, - { "fontstyle_id", "l", "font style id" }, - { "fontstyle_name", "S", "font style name" }, - { "strokewidth", "l", "stroke width" }, - { "units_per_em", "l", "units per em" }, - { "ascent", "l", "ascender height" }, - { "descent", "l", "descender height" }, - { "comments", "l", "comments" }, - { "os2_version", "l", "os2 version" }, - { "sfd_version", "l", "sfd version" }, -} - -local display_general = function (fullinfo) - texiowrite_nl "" - print_heading("General Information", 2) - texiowrite_nl "" - for i=1, #general_fields do - local field = general_fields[i] - local key, mode, desc = unpack(field) - local val - if mode == "l" then - val = fullinfo[key] - elseif mode == "S" then --- style names table - local data = fullinfo[key] - if type (data) == "table" then - if #data > 0 then - for n = 1, #data do - local nth = data[n] - if nth.lang == 1033 then - val = nth.name - goto found - end - end - val = next (data).name - else - val = "" - end - ::found:: - else - val = data - end - elseif mode == "n" then - local v = fullinfo[key] - if v then - val = #fullinfo[key] - end - elseif mode == "d" then - if ostype == "unix" then - val = osdate("%F %T", fullinfo[key]) - else - --- the MS compiler doesn’t support C99, so - --- strftime is missing some functionality; - --- see loslib.c for details. - val = osdate("%Y-%m-d %H:%M:%S", fullinfo[key]) - end - end - if not val then - val = "<none>" - end - print_field(desc, val) - end -end - -local print_features = function (features) - for tag, data in next, features do - print_heading(tag, 4) - for script, languages in next, data do - local field = stringformat(key_fmt, script).. fieldseparator .. " " - local wd_field = #field - local lines = reflow(languages.list, textwidth - wd_field) - local indent = stringrep(" ", wd_field) - texiowrite_nl(field) - texiowrite(lines[1]) - if #lines > 1 then - for i=1, #lines do - texiowrite_nl(indent .. lines[i]) - end - end - end - end -end - -local extract_feature_info = function (set) - local collected = { } - for i=1, #set do - local features = set[i].features - if features then - for j=1, #features do - local feature = features[j] - local scripts = feature.scripts - local tagname = stringlower(feature.tag) - local entry = collected[tagname] or { } - - for k=1, #scripts do - local script = scripts[k] - local scriptname = stringlower(script.script) - local c_script = entry[scriptname] or { - list = { }, - set = { }, - } - local list, set = c_script.list, c_script.set - - for l=1, #script.langs do - local langname = stringlower(script.langs[l]) - if not set[langname] then - list[#list+1] = langname - set[langname] = true - end - end - entry[scriptname] = c_script - end - collected[tagname] = entry - end - end - end - return collected -end - -local display_feature_set = function (set) - local collected = extract_feature_info(set) - print_features(collected) -end - -local display_features = function (gsub, gpos) - texiowrite_nl "" - - if gsub or gpos then - print_heading("Features", 2) - - if gsub then - print_heading("GSUB Features", 3) - display_feature_set(gsub) - end - - if gpos then - print_heading("GPOS Features", 3) - display_feature_set(gpos) - end - end -end - -local show_full_info = function (path, subfont, warnings) - local rawinfo, warn = fontloader.open(path, subfont) - if warnings then - show_fontloader_warnings(warn) - end - if not rawinfo then - texiowrite_nl(stringformat([[cannot open font %s]], path)) - return - end - local fontdata = { } - local fullinfo = fontloader.to_table(rawinfo) - local fields = fontloader.fields(rawinfo) - fontloader.close(rawinfo) - display_names(fullinfo.names) - display_general(fullinfo) - display_features(fullinfo.gsub, fullinfo.gpos) -end - ---- Subfonts returned by fontloader.info() do not correspond ---- to the actual indices required by fontloader.open(), so ---- we try and locate the correct one by matching the request ---- against the full name. - -local subfont_by_name -subfont_by_name = function (lst, askedname, n) - if not n then - return subfont_by_name (lst, askedname, 1) - end - - local font = lst[n] - if font then - if sanitize_fontname (font.fullname) == askedname then - return font - end - return subfont_by_name (lst, askedname, n+1) - end - return false -end - ---[[doc-- -The font info knows two levels of detail: - - a) basic information returned by fontloader.info(); and - b) detailed information that is a subset of the font table - returned by fontloader.open(). ---doc]]-- - -local show_font_info = function (basename, askedname, detail, warnings) - local filenames = names.data().files - local index = filenames.base[basename] - local fullname = filenames.full[index] - askedname = sanitize_fontname (askedname) - if not fullname then -- texmf - fullname = resolvers.findfile(basename) - end - if fullname then - local shortinfo = fontloader.info(fullname) - local nfonts = #shortinfo - 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) - subfont = subfont_by_name(shortinfo, askedname) - end - if subfont then - show_info_items(subfont) - if detail == true then - show_full_info(fullname, subfont, warnings) - end - else -- list all subfonts - report (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) - show_info_items(shortinfo[subfont]) - if detail == true then - show_full_info(fullname, subfont, warnings) - end - end - end - else - show_info_items(shortinfo) - if detail == true then - show_full_info(fullname, subfont, warnings) - end - end - else - report (true, 1, "resolve", "Font %s not found", filename) - end -end - ---[[-- -Running the scripts triggers one or more actions that have to be -executed in the correct order. To avoid duplication we track them in a -set. ---]]-- - -local action_sequence = { - "loglevel", "help", "version", "diagnose", - "blacklist", "cache", "flush", "generate", - "list", "query", -} - -local action_pending = tabletohash(action_sequence, false) - -action_pending.loglevel = true --- always set the loglevel -action_pending.generate = false --- this is the default action - -local actions = { } --- (jobspec -> (bool * bool)) list - -actions.loglevel = function (job) - log.set_loglevel(job.log_level) - report ("info", 3, "util", "Setting log level", "%d", job.log_level) - report ("log", 2, "util", "Lua=%q", _VERSION) - return true, true -end - -actions.version = function (job) - version_msg() - 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() - local n = 0 - for n, entry in next, table.sortedkeys(names.blacklist) do - iowrite (stringformat("(%d %s)\n", n, entry)) - end - return true, false -end - -actions.generate = function (job) - local fontnames, savedname - fontnames = names.update(fontnames, job.force_reload, job.dry_run) - report ("info", 2, "db", "Fonts in the database: %i", #fontnames.mappings) - if names.data() then - return true, true - end - return false, false -end - -actions.flush = function (job) - local success, lookups = names.flush_lookup_cache() - if success then - local success = names.save_lookups() - if success then - 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 - 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) - - require "luaotfload-features" - - local query = job.query - - local tmpspec = { - name = query, - lookup = "name", - specification = query, - optsize = 0, - features = { }, - } - - tmpspec = names.handle_request (tmpspec) - - if not tmpspec.size then - tmpspec.size = 655360 --- assume 10pt - end - - local foundname, subfont, success - - if tmpspec.lookup == "name" - or tmpspec.lookup == "anon" --- not *exactly* as resolvers.anon - then - foundname, subfont = names.resolve_name (tmpspec) - if foundname then - foundname, _, success = names.crude_file_lookup (foundname) - end - elseif tmpspec.lookup == "file" then - foundname, _, success = - names.crude_file_lookup (tmpspec.name) - end - - if success then - report (false, 0, "resolve", "Font %q found!", query) - if subfont then - report (false, 0, "resolve", - "Resolved file name %q, subfont nr. %q", - foundname, subfont) - else - report (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) - 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) - end - end - 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 chain = stringsplit (field, "->") - local tmp = entry - for i = 1, #chain - 1 do - tmp = tmp [chain [i]] - if not tmp then - --- invalid field - break - end - end - if tmp then - local value = tmp [chain [#chain]] - acc[#acc+1] = value or false - else - acc[#acc+1] = false - end - return get_fields (entry, fields, acc, n+1) - end - return acc -end - -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 - -local splitcomma = luaotfload.parsers.splitcomma - -actions.list = function (job) - local criterion = job.criterion - local asked_fields = job.asked_fields - local name_index = names.data () - - if asked_fields then - asked_fields = lpegmatch(splitcomma, asked_fields) - end - - if not asked_fields then - --- some defaults - asked_fields = { "plainname", "version", } - end - - if not name_index then - name_index = names.load() - end - - local mappings = name_index.mappings - local nmappings = #mappings - - if criterion == "*" then - 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) - - 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 - 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 tmp = entry - local chain = stringsplit (criterion, "->") - for i = 1, #chain - 1 do - tmp = tmp [chain [i]] - if not tmp then - break - end - end - local value = tmp and tmp [chain [#chain]] or "<none>" - 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 - 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 - - texiowrite_nl "" - - return true, true -end - -actions.diagnose = function (job) - --- diagnostics are loaded on demand - local diagnose = require "luaotfload-diagnostics.lua" - return diagnose (job) -end - ---- stuff to be carried out prior to exit - -local finalizers = { } - ---- returns false if at least one of the actions failed, mainly ---- for closing io channels -local finalize = function () - local success = true - for _, fun in next, finalizers do - if type (fun) == "function" then - if fun () == false then success = false end - end - end - return success -end - ---[[-- -Command-line processing. -luaotfload-tool relies on the script alt_getopt to process argv and -analyzes its output. - -TODO with extended lualibs we have the functionality from the -environment.* namespace that could eliminate the dependency on -alt_getopt. ---]]-- - -local process_cmdline = function ( ) -- unit -> jobspec - local result = { -- jobspec - force_reload = nil, - full_info = false, - warnings = false, - criterion = "", - query = "", - log_level = 0, --- 2 is approx. the old behavior - } - - local long_options = { - cache = 1, - ["no-compress"] = "c", - diagnose = 1, - ["dry-run"] = "D", - ["flush-lookups"] = "l", - fields = 1, - find = 1, - force = "f", - formats = 1, - fuzzy = "F", - help = "h", - info = "i", - inspect = "I", - limit = 1, - list = 1, - log = 1, - ["max-fonts"] = 1, - ["no-reload"] = "n", - ["no-strip"] = 0, - ["skip-read"] = "R", - ["prefer-texmf"] = "p", - quiet = "q", - ["show-blacklist"] = "b", - stats = "S", - update = "u", - verbose = 1, - version = "V", - warnings = "w", - } - - local short_options = "bcDfFiIlnpqRSuvVhw" - - local options, _, optarg = - alt_getopt.get_ordered_opts (arg, short_options, long_options) - - local nopts = #options - for n=1, nopts do - local v = options[n] - if v == "q" then - result.log_level = 0 - elseif v == "u" then - action_pending["generate"] = true - elseif v == "v" then - if result.log_level > 0 then - result.log_level = result.log_level + 1 - else - result.log_level = 1 - end - elseif v == "V" then - action_pending["version"] = true - elseif v == "h" then - action_pending["help"] = true - elseif v == "f" then - result.update = true - result.force_reload = 1 - elseif v == "verbose" then - local lvl = optarg[n] - if lvl then - lvl = tonumber(lvl) - result.log_level = lvl - if lvl > 2 then - result.warnings = true - end - end - elseif v == "w" then - result.warnings = true - elseif v == "log" then - local str = optarg[n] - if str then - finalizers = log.set_logout(str, finalizers) - end - elseif v == "find" then - action_pending["query"] = true - result.query = optarg[n] - elseif v == "F" then - result.fuzzy = true - elseif v == "limit" then - local lim = optarg[n] - if lim then - result.fuzzy_limit = tonumber(lim) - end - elseif v == "i" then - result.show_info = true - elseif v == "I" then - result.show_info = true - result.full_info = true - 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 - elseif v == "p" then - names.set_location_precedence { - "local", "texmf", "system" - } - elseif v == "b" then - action_pending["blacklist"] = true - elseif v == "diagnose" then - action_pending["diagnose"] = true - result.asked_diagnostics = optarg[n] - elseif v == "formats" then - names.set_font_filter (optarg[n]) - elseif v == "n" then - luaotfloadconfig.update_live = false - elseif v == "S" then - luaotfloadconfig.statistics = true - elseif v == "R" then - --- dev only, undocumented - luaotfloadconfig.skip_read = true - elseif v == "c" then - luaotfloadconfig.compress = false - elseif v == "no-strip" then - luaotfloadconfig.strip = false - elseif v == "max-fonts" then - local n = optarg[n] - if n then - n = tonumber(n) - if n and n > 0 then - luaotfloadconfig.max_fonts = n - end - end - end - end - - if nopts == 0 then - action_pending["help"] = true - result.help_version = "short" - end - return result -end - -local main = function ( ) -- unit -> int - local retval = 0 - local job = process_cmdline() - --- inspect(action_pending) --- inspect(job) - - for i=1, #action_sequence do - local actionname = action_sequence[i] - local exit = false - if action_pending[actionname] then - report ("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", - "Could not finish task", "%s", actionname) - retval = -1 - exit = true - elseif not continue then - report (false, 3, "util", - "Task completed, exiting", "%s", actionname) - exit = true - else - report (false, 3, "util", - "Task completed successfully", "%s", actionname) - end - end - if exit then break end - end - - if finalize () == false then - retval = -1 - end - - --texiowrite_nl"" - return retval -end - -return main() - --- vim:tw=71:sw=4:ts=4:expandtab |