From 310fa29531fd6003ed840165b8041105827040cb Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 23 Jun 2013 00:38:44 +0200 Subject: refine list of style synonyms --- luaotfload-database.lua | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index 4c45d21..f374617 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -326,22 +326,49 @@ end local style_synonyms = { set = { } } do + local combine = function (ta, tb) + local result = { } + for i=1, #ta do + for j=1, #tb do + result[#result+1] = ta[i] .. tb[j] + end + end + return result + end + --- read this: http://blogs.adobe.com/typblography/2008/05/indesign_font_conflicts.html --- tl;dr: font style synonyms are unreliable. - style_synonyms.list = { + --- + --- Context matches font names against lists of known identifiers + --- for weight, style, width, and variant, so that including + --- the family name there are five dimensions for choosing a + --- match. The sad thing is, while this is a decent heuristic it + --- makes no sense to imitate it in luaotfload because the user + --- interface must fit into the much more limited Xetex scheme that + --- distinguishes between merely four style categories: “regular”, + --- “italic”, “bold”, and “bolditalic”. As a result, some of the + --- styles are lumped together although they can differ + --- significantly (like “medium” and “bold”). + + local list = { regular = { "normal", "roman", - "plain", "book", }, + "plain", "book", + "light", "extralight", + "ultralight", }, bold = { "demi", "demibold", "semibold", "boldregular", - "medium" }, + "medium", "mediumbold", + "ultrabold", "extrabold", + "heavy", "black", + "bold", }, italic = { "regularitalic", "normalitalic", - "oblique", "slanted", }, - bolditalic = { "boldoblique", "boldslanted", - "demiitalic", "demioblique", - "demislanted", "demibolditalic", - "semibolditalic", }, + "oblique", "slanted", + "italic", }, } + list.bolditalic = combine(list.bold, list.italic) + style_synonyms.list = list + for category, synonyms in next, style_synonyms.list do style_synonyms.set[category] = tabletohash(synonyms, true) end -- cgit v1.2.3 From 79a75e8efc0d4df83f9ae73f7107e86d81147da9 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 23 Jun 2013 00:50:58 +0200 Subject: move db version check to load time --- luaotfload-database.lua | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index f374617..f8f9391 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -295,6 +295,17 @@ load_names = function (dry_run) "Font names database loaded", "%s", foundname) report("info", 3, "db", "Loading took %0.f ms", 1000*(os.gettimeofday()-starttime)) + + local db_version, nms_version = data.version, names.version + if db_version ~= nms_version then + report("log", 0, "db", + [[version mismatch; expected %4.3f, got %4.3f]], + nms_version, db_version) + if not fonts_reloaded then + report("log", 0, "db", [[force rebuild]]) + return update_names({ }, true, false) + end + end else report("both", 0, "db", [[Font names database not found, generating new one.]]) @@ -663,7 +674,7 @@ the font database created by the luaotfload-tool script. --- values. --- -resolve = function (_,_,specification) -- the 1st two parameters are used by ConTeXt +resolve = function (_, _, specification) -- the 1st two parameters are used by ConTeXt if not fonts_loaded then names.data = load_names() end local data = names.data @@ -691,18 +702,6 @@ resolve = function (_,_,specification) -- the 1st two parameters are used by Con return specification.name, false, false end - local db_version, nms_version = data.version, names.version - if db_version ~= nms_version then - report("log", 0, "db", - [[version mismatch; expected %4.3f, got %4.3f]], - nms_version, db_version) - if not fonts_reloaded then - return reload_db("version mismatch", - resolve, nil, nil, specification) - end - return specification.name, false, false - end - if not data.mappings then if not fonts_reloaded then return reload_db("invalid database; missing font mapping", -- cgit v1.2.3 From 2938e7d63404f1d2e129b13f5bb69ddf0653a71e Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 23 Jun 2013 01:39:26 +0200 Subject: prioritize exact matches over style synonyms --- luaotfload-database.lua | 45 ++++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index f8f9391..8c9f42e 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -356,11 +356,13 @@ do --- match. The sad thing is, while this is a decent heuristic it --- makes no sense to imitate it in luaotfload because the user --- interface must fit into the much more limited Xetex scheme that - --- distinguishes between merely four style categories: “regular”, - --- “italic”, “bold”, and “bolditalic”. As a result, some of the - --- styles are lumped together although they can differ + --- distinguishes between merely four style categories (variants): + --- “regular”, “italic”, “bold”, and “bolditalic”. As a result, + --- some of the styles are lumped together although they can differ --- significantly (like “medium” and “bold”). + --- Xetex (XeTeXFontMgr.cpp) appears to recognize only “plain”, + --- “normal”, and “roman” as synonyms for “regular”. local list = { regular = { "normal", "roman", "plain", "book", @@ -710,7 +712,8 @@ resolve = function (_, _, specification) -- the 1st two parameters are used by C return specification.name, false, false end - local found = { } --> collect results + local exact = { } --> collect exact style matches + local synonymous = { } --> collect matching style synonyms local fallback --> e.g. non-matching style (fontspec is anal about this) local candidates = { } --> secondary results, incomplete matches @@ -747,21 +750,16 @@ resolve = function (_, _, specification) -- the 1st two parameters are used by C then if style == prefmodifiers or style == subfamily - or synonym_set[style] and - (synonym_set[style][prefmodifiers] or - synonym_set[style][subfamily]) then local continue - found, continue = add_to_match( - found, optsize, dsnsize, size, + exact, continue = add_to_match( + exact, optsize, dsnsize, size, minsize, maxsize, face) if continue == false then break end elseif prefmodifiers == "regular" or subfamily == "regular" --- TODO this match should be performed when building the db - or synonym_set.regular[prefmodifiers] - or synonym_set.regular[subfamily] then fallback = face elseif name == fullname @@ -770,10 +768,19 @@ resolve = function (_, _, specification) -- the 1st two parameters are used by C or name == psname then local continue - found, continue = add_to_match( - found, optsize, dsnsize, size, + exact, continue = add_to_match( + exact, optsize, dsnsize, size, minsize, maxsize, face) if continue == false then break end + elseif synonym_set[style] and + (synonym_set[style][prefmodifiers] or + synonym_set[style][subfamily]) + or synonym_set.regular[prefmodifiers] + or synonym_set.regular[subfamily] + then + synonymous = add_to_match(synonymous, + optsize, dsnsize, size, + minsize, maxsize, face) else --- mark as last straw but continue candidates[#candidates+1] = face end @@ -783,14 +790,22 @@ resolve = function (_, _, specification) -- the 1st two parameters are used by C or name == fontname or name == psname then local continue - found, continue = add_to_match( - found, optsize, dsnsize, size, + exact, continue = add_to_match( + exact, optsize, dsnsize, size, minsize, maxsize, face) if continue == false then break end end end end + local found + if next(exact) then + found = exact + else + found = synonymous + end + + --- this is a monster if #found == 1 then --- “found” is really synonymous with “registered in the db”. -- cgit v1.2.3 From b20de3f5c45fc767e1a17c8dab12cae1aa4430b7 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 23 Jun 2013 21:29:38 +0200 Subject: treat subfamily style matches as second-rate --- luaotfload-database.lua | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index 8c9f42e..22f9455 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -748,19 +748,14 @@ resolve = function (_, _, specification) -- the 1st two parameters are used by C if name == family or name == metafamily then - if style == prefmodifiers - or style == subfamily - then + if style == prefmodifiers then -- exact local continue exact, continue = add_to_match( exact, optsize, dsnsize, size, minsize, maxsize, face) if continue == false then break end - - elseif prefmodifiers == "regular" - or subfamily == "regular" + elseif prefmodifiers == "regular" then --- TODO this match should be performed when building the db - then fallback = face elseif name == fullname or name == pfullname @@ -772,7 +767,9 @@ resolve = function (_, _, specification) -- the 1st two parameters are used by C exact, optsize, dsnsize, size, minsize, maxsize, face) if continue == false then break end - elseif synonym_set[style] and + elseif style == subfamily --- unreliable (see Ad. Garm. Pro) + or subfamily == "regular" + or synonym_set[style] and (synonym_set[style][prefmodifiers] or synonym_set[style][subfamily]) or synonym_set.regular[prefmodifiers] -- cgit v1.2.3 From baaeef6616db498218f6269fac7a6ec6fb185878 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 23 Jun 2013 21:59:54 +0200 Subject: refactor optical size matching --- luaotfload-database.lua | 45 ++++++++++++++++++--------------------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index 22f9455..0903404 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -619,9 +619,16 @@ end --- this used to be inlined; with the lookup cache we don’t --- have to be parsimonious wrt function calls anymore --- “found” is the match accumulator -local add_to_match = function ( - found, optsize, dsnsize, size, - minsize, maxsize, face) +local add_to_match = function (found, size, face) + + local optsize, dsnsize, maxsize, minsize + if #face.size > 0 then + optsize = face.size + dsnsize = optsize[1] and optsize[1] / 10 + -- can be nil + maxsize = optsize[2] and optsize[2] / 10 or dsnsize + minsize = optsize[3] and optsize[3] / 10 or dsnsize + end local continue = true if optsize then if dsnsize == size or (size > minsize and size <= maxsize) then @@ -683,11 +690,11 @@ resolve = function (_, _, specification) -- the 1st two parameters are used by C local name = sanitize_string(specification.name) local style = sanitize_string(specification.style) or "regular" - local size + local askedsize if specification.optsize then - size = tonumber(specification.optsize) + askedsize = tonumber(specification.optsize) elseif specification.size then - size = specification.size / 65536 + askedsize = specification.size / 65536 end if type(data) ~= "table" then @@ -736,23 +743,13 @@ resolve = function (_, _, specification) -- the 1st two parameters are used by C fontname = fontname or sanitize_string(face.fontname) pfullname = pfullname or sanitize_string(face.fullname) - local optsize, dsnsize, maxsize, minsize - if #face.size > 0 then - optsize = face.size - dsnsize = optsize[1] and optsize[1] / 10 - -- can be nil - maxsize = optsize[2] and optsize[2] / 10 or dsnsize - minsize = optsize[3] and optsize[3] / 10 or dsnsize - end if name == family or name == metafamily then if style == prefmodifiers then -- exact local continue - exact, continue = add_to_match( - exact, optsize, dsnsize, size, - minsize, maxsize, face) + exact, continue = add_to_match(exact, askedsize, face) if continue == false then break end elseif prefmodifiers == "regular" then --- TODO this match should be performed when building the db @@ -763,9 +760,7 @@ resolve = function (_, _, specification) -- the 1st two parameters are used by C or name == psname then local continue - exact, continue = add_to_match( - exact, optsize, dsnsize, size, - minsize, maxsize, face) + exact, continue = add_to_match(exact, askedsize, face) if continue == false then break end elseif style == subfamily --- unreliable (see Ad. Garm. Pro) or subfamily == "regular" @@ -775,9 +770,7 @@ resolve = function (_, _, specification) -- the 1st two parameters are used by C or synonym_set.regular[prefmodifiers] or synonym_set.regular[subfamily] then - synonymous = add_to_match(synonymous, - optsize, dsnsize, size, - minsize, maxsize, face) + synonymous = add_to_match(synonymous, askedsize, face) else --- mark as last straw but continue candidates[#candidates+1] = face end @@ -787,9 +780,7 @@ resolve = function (_, _, specification) -- the 1st two parameters are used by C or name == fontname or name == psname then local continue - exact, continue = add_to_match( - exact, optsize, dsnsize, size, - minsize, maxsize, face) + exact, continue = add_to_match(exact, askedsize, face) if continue == false then break end end end @@ -824,7 +815,7 @@ resolve = function (_, _, specification) -- the 1st two parameters are used by C local least = math.huge -- initial value is infinity for i,face in next, found do local dsnsize = face.size[1]/10 - local difference = mathabs(dsnsize-size) + local difference = mathabs(dsnsize - askedsize) if difference < least then closest = face least = difference -- cgit v1.2.3 From 0e51cff12b24d264b8e17d8bd7f9a00763699963 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 23 Jun 2013 22:23:12 +0200 Subject: treat subfamily match as exact, but not final match --- luaotfload-database.lua | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index 0903404..4554711 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -743,17 +743,15 @@ resolve = function (_, _, specification) -- the 1st two parameters are used by C fontname = fontname or sanitize_string(face.fontname) pfullname = pfullname or sanitize_string(face.fullname) - if name == family or name == metafamily then - if style == prefmodifiers then -- exact + if style == prefmodifiers then local continue exact, continue = add_to_match(exact, askedsize, face) if continue == false then break end - elseif prefmodifiers == "regular" then - --- TODO this match should be performed when building the db - fallback = face + elseif style == subfamily then + exact = add_to_match(exact, askedsize, face) elseif name == fullname or name == pfullname or name == fontname @@ -762,15 +760,16 @@ resolve = function (_, _, specification) -- the 1st two parameters are used by C local continue exact, continue = add_to_match(exact, askedsize, face) if continue == false then break end - elseif style == subfamily --- unreliable (see Ad. Garm. Pro) - or subfamily == "regular" - or synonym_set[style] and + elseif synonym_set[style] and (synonym_set[style][prefmodifiers] or synonym_set[style][subfamily]) or synonym_set.regular[prefmodifiers] or synonym_set.regular[subfamily] then synonymous = add_to_match(synonymous, askedsize, face) + elseif prefmodifiers == "regular" + or subfamily == "regular" then + fallback = face else --- mark as last straw but continue candidates[#candidates+1] = face end @@ -793,7 +792,6 @@ resolve = function (_, _, specification) -- the 1st two parameters are used by C found = synonymous end - --- this is a monster if #found == 1 then --- “found” is really synonymous with “registered in the db”. -- cgit v1.2.3 From 6e86c9a31ba0f0ba099be6b48d11e114c3ae1cfe Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Mon, 24 Jun 2013 13:46:14 +0200 Subject: fix missing local in luaotfload-tool --- luaotfload-tool.lua | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/luaotfload-tool.lua b/luaotfload-tool.lua index 3eef577..f1302a7 100755 --- a/luaotfload-tool.lua +++ b/luaotfload-tool.lua @@ -43,9 +43,12 @@ if _G.getfenv then return require(oldscript) end +local stringexplode = string.explode local stringformat = string.format -local texiowrite_nl = texio.write_nl local stringlower = string.lower +local tableconcat = table.concat +local texiowrite_nl = texio.write_nl + local C, Ct, P = lpeg.C, lpeg.Ct, lpeg.P local lpegmatch = lpeg.match @@ -103,17 +106,17 @@ config.lualibs.verbose = false config.lualibs.prefer_merged = true config.lualibs.load_extended = false -require"lualibs" +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" +local cachepath = kpse.expand_var "$TEXMFVAR" if not lfs.isdir(cachepath) then dir.mkdirs(cachepath) if not lfs.isdir(cachepath) then - texiowrite(stringformat( + texiowrite_nl(stringformat( "ERROR could not create directory %s", cachepath)) end end @@ -412,10 +415,6 @@ 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) -- cgit v1.2.3 From 80ea10e6238b2da996f1f0247257e16373ce5972 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 25 Jun 2013 10:43:39 +0200 Subject: fix behavior of luaotfload-tool with ttc subfonts --- luaotfload-tool.lua | 82 +++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 70 insertions(+), 12 deletions(-) diff --git a/luaotfload-tool.lua b/luaotfload-tool.lua index f1302a7..f2814ee 100755 --- a/luaotfload-tool.lua +++ b/luaotfload-tool.lua @@ -235,30 +235,83 @@ local version_msg = function ( ) config.luaotfload.self, version, names.version)) end +local tw = 80 +local print_font_name = function (name) + local s = "-- " .. name .. " " + s = s .. string.rep("-", tw-string.len(s)) + texiowrite_nl (s) + texiowrite_nl "" +end + local show_info_items = function (fontinfo) local items = table.sortedkeys(fontinfo) + print_font_name(fontinfo.fullname) for n = 1, #items do local item = items[n] texiowrite_nl(stringformat( [[ %11s: %s]], item, fontinfo[item])) end + texiowrite_nl "" end -local show_font_info = function (filename) - local fullname = resolvers.findfile(filename) +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 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, full) + local filenames = names.data.filenames + local index = filenames.base[basename] + local fullname = filenames.full[index] + if not fullname then -- texmf + fullname = resolvers.findfile(basename) + end + local info = { } if fullname then - local fontinfo = fontloader.info(fullname) - local nfonts = #fontinfo + info.location = fullname + local shortinfo = fontloader.info(fullname) + local nfonts = #shortinfo if nfonts > 0 then -- true type collection - logs.names_report(true, 1, "resolve", - [[%s is a font collection]], filename) - for n = 1, nfonts do + local subfont + if askedname then logs.names_report(true, 1, "resolve", - [[showing info for font no. %d]], n) - show_info_items(fontinfo[n]) + [[%s is part of the font collection %s]], + askedname, basename) + subfont = subfont_by_name(shortinfo, askedname) + end + if subfont then + show_info_items(subfont) + else -- list all subfonts + logs.names_report(true, 1, "resolve", + [[%s is a font collection]], basename) + inspect(shortinfo) + for n = 1, nfonts do + logs.names_report(true, 1, "resolve", + [[showing info for font no. %d]], n) + show_info_items(shortinfo[n]) + end end else - show_info_items(fontinfo) + show_info_items(shortinfo) end else logs.names_report(true, 1, "resolve", @@ -378,7 +431,7 @@ actions.query = function (job) "resolve", "Resolved file name “%s”", foundname) end if job.show_info then - show_font_info(foundname) + show_font_info(foundname, query, job.full_info) end else logs.names_report(false, 0, @@ -553,6 +606,7 @@ alt_getopt. local process_cmdline = function ( ) -- unit -> jobspec local result = { -- jobspec force_reload = nil, + full_info = false, criterion = "", query = "", log_level = 0, --- 2 is approx. the old behavior @@ -569,6 +623,7 @@ local process_cmdline = function ( ) -- unit -> jobspec fuzzy = "F", help = "h", info = "i", + inspect = "I", limit = 1, list = 1, log = 1, @@ -580,7 +635,7 @@ local process_cmdline = function ( ) -- unit -> jobspec version = "V", } - local short_options = "bDfFilpquvVh" + local short_options = "bDfFiIlpquvVh" local options, _, optarg = alt_getopt.get_ordered_opts (arg, short_options, long_options) @@ -627,6 +682,9 @@ local process_cmdline = function ( ) -- unit -> jobspec end elseif v == "i" then result.show_info = true + elseif v == "I" then + result.show_info = true + result.full_info = true elseif v == "alias" then config.luaotfload.self = optarg[n] elseif v == "l" then -- cgit v1.2.3 From ffdbaf60da4815f80f6254a35ec22b7da55fc44c Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 25 Jun 2013 10:50:13 +0200 Subject: fix font file verification (thanks, Kim!) the cached lookup did not load the database when verifying the presence of hashed files. addresses: https://github.com/lualatex/luaotfload/issues/100 --- luaotfload-database.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index 4554711..12bceb5 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -493,6 +493,7 @@ the texmf or filesystem. --doc]]-- local verify_font_file = function (basename) + if not names.data then names.data = load_names() end local filenames = names.data.filenames local idx = filenames.base[basename] if not idx then -- cgit v1.2.3 From 6e7b9389e21c149a667f8db07f9e77723a8ffbe5 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 25 Jun 2013 11:14:23 +0200 Subject: document kpse: and my: lookups --- luaotfload.dtx | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/luaotfload.dtx b/luaotfload.dtx index 70edf8c..9e57bac 100644 --- a/luaotfload.dtx +++ b/luaotfload.dtx @@ -400,7 +400,23 @@ and the derived files % \begin{quote} % |\font\fontname=|\meta{prefix}|:|\meta{fontname}\dots % \end{quote} -% where \meta{prefix} is either \verb|file:| or \verb|name:|. +% where \meta{prefix} is either \verb|file:| or \verb|name:|.\footnote{% +% The development version also knows two further prefixes, +% \verb|kpse:| and \verb|my:|. +% A \verb|kpse| lookup is restricted to files that can be found by +% \identifier{kpathsea} and +% will not attempt to locate system fonts. +% This behavior can be of value when an extra degree of encapsulation is +% needed, for instance when supplying a customized tex distribution. +% +% The \verb|my| lookup takes this a step further: it lets you define +% a custom resolver function and hook it into the \luafunction{resolve_font} +% callback. +% This ensures full control over how a file is located. +% For a working example see the +% \href{https://bitbucket.org/phg/lua-la-tex-tests/src/5f6a535d/pln-lookup-callback-1.tex} +% {test repo}. +% } % It determines whether the font loader should interpret the request as % a \emphasis{file name} or % \emphasis{font name}, respectively, -- cgit v1.2.3 From b4417d6f046b254fa18ee9dc740beabe42508aa1 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 25 Jun 2013 11:31:29 +0200 Subject: [doc] add note concerning unreliability of font names --- luaotfload.dtx | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/luaotfload.dtx b/luaotfload.dtx index 9e57bac..8ebd8ec 100644 --- a/luaotfload.dtx +++ b/luaotfload.dtx @@ -426,7 +426,26 @@ and the derived files % “GFS Bodoni Rg”, and % “PT Serif Caption” % -- they are the human readable identifiers -% usually listed in drop-down menus and the like. +% usually listed in drop-down menus and the like.\footnote{% +% Font names may appear like a great choice at first because they +% offer seemingly more intuitive identifiers in comparison to arguably +% cryptic file names: +% “PT Sans Bold” is a lot more descriptive than \fileent{PTS75F.ttf}. +% On the other hand, font names are quite arbitrary and there is no +% universal method to determine their meaning. +% While \identifier{luaotfload} provides fairly sophisticated heuristic +% to figure out a matching font style, weight, and optical size, it +% cannot be relied upon to work satisfactorily for all font files. +% For an in-depth analysis of the situation and how broken font names +% are, please refer to +% \href{http://www.ntg.nl/pipermail/ntg-context/2013/073889.html} +% {this post} +% by Hans Hagen, the author of the font loader. +% If in doubt, use filenames. +% \fileent{luaotfload-tool} can perform the matching for you with the +% option \verb|--find=|, and you can use the file name it returns +% in your font definition. +% } % In order for fonts installed both in system locations and in your % \fileent{texmf} to be accessible by font name, \identifier{luaotfload} must % first collect the metadata included in the files. -- cgit v1.2.3 From de200c1846690e75a33aeaef920d74af34e4b001 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 25 Jun 2013 15:48:14 +0200 Subject: add --inspect and --warnings flags to luaotfload-tool --- luaotfload-database.lua | 1 + luaotfload-tool.lua | 94 +++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 80 insertions(+), 15 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index 12bceb5..82f6c7c 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -1998,6 +1998,7 @@ names.update = update_names names.crude_file_lookup = crude_file_lookup names.crude_file_lookup_verbose = crude_file_lookup_verbose names.read_blacklist = read_blacklist +names.sanitize_string = sanitize_string names.getfilename = resolve_fullpath --- font cache diff --git a/luaotfload-tool.lua b/luaotfload-tool.lua index f2814ee..7301db2 100755 --- a/luaotfload-tool.lua +++ b/luaotfload-tool.lua @@ -47,10 +47,11 @@ local stringexplode = string.explode local stringformat = string.format local stringlower = string.lower local tableconcat = table.concat +local texiowrite = texio.write local texiowrite_nl = texio.write_nl -local C, Ct, P = lpeg.C, lpeg.Ct, lpeg.P +local C, Ct, P, S = lpeg.C, lpeg.Ct, lpeg.P, lpeg.S local lpegmatch = lpeg.match local loader_file = "luatexbase.loader.lua" @@ -141,6 +142,8 @@ require"alt_getopt" local version = "2.3" -- same version number as luaotfload local names = fonts.names +local sanitize_string = names.sanitize_string + local db_src_out = names.path.dir.."/"..names.path.basename local db_bin_out = file.replacesuffix(db_src_out, "luc") @@ -226,7 +229,10 @@ The font database will be saved to local help_msg = function ( ) local template = help_messages[config.luaotfload.self] or help_messages["luaotfload-tool"] - texiowrite_nl(stringformat(template, config.luaotfload.self, db_src_out, db_bin_out)) + texiowrite_nl(stringformat(template, + config.luaotfload.self, + db_src_out, + db_bin_out)) end local version_msg = function ( ) @@ -243,17 +249,60 @@ local print_font_name = function (name) texiowrite_nl "" end +local info_fmt = [[%13s: %s]] +local warn_fmt = [[(%d %s)]] + local show_info_items = function (fontinfo) local items = table.sortedkeys(fontinfo) print_font_name(fontinfo.fullname) for n = 1, #items do local item = items[n] texiowrite_nl(stringformat( - [[ %11s: %s]], item, fontinfo[item])) + info_fmt, item, fontinfo[item])) end 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 + texiowrite_nl(stringformat( + [[* the fontloader emitted %d warnings *]], + nws, name)) + 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 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 fullinfo = fontloader.to_table(rawinfo) + fontloader.close(rawinfo) +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 @@ -262,7 +311,7 @@ subfont_by_name = function (lst, askedname, n) local font = lst[n] if font then - if font.fullname == askedname then + if sanitize_string(font.fullname) == askedname then return font end return subfont_by_name (lst, askedname, n+1) @@ -274,20 +323,19 @@ end 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(). + b) detailed information that is a subset of the font table + returned by fontloader.open(). --doc]]-- -local show_font_info = function (basename, askedname, full) +local show_font_info = function (basename, askedname, detail, warnings) local filenames = names.data.filenames local index = filenames.base[basename] local fullname = filenames.full[index] + askedname = sanitize_string(askedname) if not fullname then -- texmf fullname = resolvers.findfile(basename) end - local info = { } if fullname then - info.location = fullname local shortinfo = fontloader.info(fullname) local nfonts = #shortinfo if nfonts > 0 then -- true type collection @@ -300,18 +348,26 @@ local show_font_info = function (basename, askedname, full) end if subfont then show_info_items(subfont) + if detail == true then + show_full_info(fullname, subfont, warnings) + end else -- list all subfonts logs.names_report(true, 1, "resolve", [[%s is a font collection]], basename) - inspect(shortinfo) - for n = 1, nfonts do + for subfont = 1, nfonts do logs.names_report(true, 1, "resolve", [[showing info for font no. %d]], n) - show_info_items(shortinfo[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 logs.names_report(true, 1, "resolve", @@ -431,7 +487,7 @@ actions.query = function (job) "resolve", "Resolved file name “%s”", foundname) end if job.show_info then - show_font_info(foundname, query, job.full_info) + show_font_info(foundname, query, job.full_info, job.warnings) end else logs.names_report(false, 0, @@ -607,6 +663,7 @@ 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 @@ -633,9 +690,10 @@ local process_cmdline = function ( ) -- unit -> jobspec update = "u", verbose = 1 , version = "V", + warnings = "w", } - local short_options = "bDfFiIlpquvVh" + local short_options = "bDfFiIlpquvVhw" local options, _, optarg = alt_getopt.get_ordered_opts (arg, short_options, long_options) @@ -663,8 +721,14 @@ local process_cmdline = function ( ) -- unit -> jobspec elseif v == "verbose" then local lvl = optarg[n] if lvl then - result.log_level = tonumber(lvl) + 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 -- cgit v1.2.3 From 23d194d78d1afbe9dcc000e2d108563ba2a8bf76 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 25 Jun 2013 16:13:40 +0200 Subject: add ascii heading formatter to luaotfload-tool --- luaotfload-tool.lua | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/luaotfload-tool.lua b/luaotfload-tool.lua index 7301db2..dd8484d 100755 --- a/luaotfload-tool.lua +++ b/luaotfload-tool.lua @@ -241,11 +241,22 @@ local version_msg = function ( ) config.luaotfload.self, version, names.version)) end + +--- makeshift formatting + +local head_adornchars = { + [1] = "*", [2] = "=", [3] = "~", [4] = "-", [5] = "·", +} local tw = 80 -local print_font_name = function (name) - local s = "-- " .. name .. " " - s = s .. string.rep("-", tw-string.len(s)) - texiowrite_nl (s) + +local print_heading = function (title, level) + if not level or level > #head_adornchars then + level = #head_adornchars + end + local adornchar = head_adornchars[level] + + local s = adornchar .. adornchar .. " " .. title .. " " + texiowrite_nl (s .. string.rep(adornchar, tw-utf.len(s))) texiowrite_nl "" end @@ -254,7 +265,7 @@ local warn_fmt = [[(%d %s)]] local show_info_items = function (fontinfo) local items = table.sortedkeys(fontinfo) - print_font_name(fontinfo.fullname) + print_heading(fontinfo.fullname, 1) for n = 1, #items do local item = items[n] texiowrite_nl(stringformat( @@ -270,9 +281,10 @@ local p_lines = Ct(p_line * (p_eol^1 * p_line^-1)^0) local show_fontloader_warnings = function (ws) local nws = #ws - texiowrite_nl(stringformat( - [[* the fontloader emitted %d warnings *]], - nws, name)) + 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)) @@ -285,6 +297,13 @@ local show_fontloader_warnings = function (ws) end end +local display_names = function (names) + print_heading("Font Metadata", 2) + for i=1, #names do + local namedata = names[i] + end +end + local show_full_info = function (path, subfont, warnings) local rawinfo, warn = fontloader.open(path, subfont) if warnings then @@ -294,8 +313,12 @@ local show_full_info = function (path, subfont, warnings) texiowrite_nl(stringformat([[cannot open font %s]], path)) return end + local fontdata = { } local fullinfo = fontloader.to_table(rawinfo) + local fields = fontloader.fields(rawinfo.glyphs[0]) fontloader.close(rawinfo) + --inspect(fields) + display_names(fullinfo.names) end --- Subfonts returned by fontloader.info() do not correspond -- cgit v1.2.3 From a87bac7a89c8fe38e0f2608f39b1c3c5f7850a93 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 25 Jun 2013 17:31:36 +0200 Subject: printer for the names table --- luaotfload-tool.lua | 81 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 9 deletions(-) diff --git a/luaotfload-tool.lua b/luaotfload-tool.lua index dd8484d..c5c1e47 100755 --- a/luaotfload-tool.lua +++ b/luaotfload-tool.lua @@ -46,10 +46,10 @@ end local stringexplode = string.explode local stringformat = string.format local stringlower = string.lower +local stringrep = string.rep local tableconcat = table.concat -local texiowrite = texio.write local texiowrite_nl = texio.write_nl - +local texiowrite = texio.write local C, Ct, P, S = lpeg.C, lpeg.Ct, lpeg.P, lpeg.S local lpegmatch = lpeg.match @@ -247,7 +247,14 @@ end local head_adornchars = { [1] = "*", [2] = "=", [3] = "~", [4] = "-", [5] = "·", } -local tw = 80 + +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 print_heading = function (title, level) if not level or level > #head_adornchars then @@ -256,13 +263,10 @@ local print_heading = function (title, level) local adornchar = head_adornchars[level] local s = adornchar .. adornchar .. " " .. title .. " " - texiowrite_nl (s .. string.rep(adornchar, tw-utf.len(s))) + texiowrite_nl (s .. stringrep(adornchar, textwidth-utf.len(s))) texiowrite_nl "" end -local info_fmt = [[%13s: %s]] -local warn_fmt = [[(%d %s)]] - local show_info_items = function (fontinfo) local items = table.sortedkeys(fontinfo) print_heading(fontinfo.fullname, 1) @@ -284,7 +288,6 @@ local show_fontloader_warnings = function (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)) @@ -297,10 +300,70 @@ local show_fontloader_warnings = function (ws) 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 = lpegmatch(p_words, text) + if #words < 2 then + return { text } + 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 + +local print_field = function (key, 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 namedata = names[i] + local lang, namedata = names[i].lang, names[i].names + print_heading(stringformat("%d) Language: %s ", i, lang), 3) + if namedata then + for field, value in next, namedata do + print_field(field, value) + end + end end end -- cgit v1.2.3 From f61e64740b13341624f1e9a52f3336a7eda6e3eb Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 25 Jun 2013 18:16:22 +0200 Subject: add font metadata printer --- luaotfload-tool.lua | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/luaotfload-tool.lua b/luaotfload-tool.lua index c5c1e47..31ea5c0 100755 --- a/luaotfload-tool.lua +++ b/luaotfload-tool.lua @@ -338,7 +338,9 @@ local reflow = function (text, width) 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) @@ -367,6 +369,54 @@ local display_names = function (names) 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", "l", "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) + 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 == "n" then + local v = fullinfo[key] + if v then + val = #fullinfo[key] + end + elseif mode == "d" then + val = os.date("%F %T", fullinfo[key]) + end + if not val then + val = "" + end + print_field(desc, val) + end +end + local show_full_info = function (path, subfont, warnings) local rawinfo, warn = fontloader.open(path, subfont) if warnings then @@ -382,6 +432,7 @@ local show_full_info = function (path, subfont, warnings) fontloader.close(rawinfo) --inspect(fields) display_names(fullinfo.names) + display_general(fullinfo) end --- Subfonts returned by fontloader.info() do not correspond -- cgit v1.2.3 From 0cf2e9765e8b9b977f45cc56b0d35df0b7335a96 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 25 Jun 2013 18:25:44 +0200 Subject: [doc] describe -I and -w in manpage --- luaotfload-tool.lua | 6 +++++- luaotfload-tool.rst | 14 ++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/luaotfload-tool.lua b/luaotfload-tool.lua index 31ea5c0..02ca3a0 100755 --- a/luaotfload-tool.lua +++ b/luaotfload-tool.lua @@ -184,7 +184,11 @@ This tool is part of the luaotfload package. Valid options are: -F --fuzzy look for approximate matches if --find fails --limit=n limit display of fuzzy matches to (default: n = 1) - -i --info display font metadata + + -i --info display basic font metadata + -I --inspect display detailed font metadata + -w --warnings display warnings generated by the + fontloader library --list= output list of entries by field --list=: restrict to entries with = diff --git a/luaotfload-tool.rst b/luaotfload-tool.rst index 9b03b37..7b75367 100644 --- a/luaotfload-tool.rst +++ b/luaotfload-tool.rst @@ -15,11 +15,11 @@ SYNOPSIS ======================================================================= -**luaotfload** [ -bDcfFipquvVh ] +**luaotfload** [ -bDcfFiIpquvVwh ] **luaotfload** --update [ --force ] [ --quiet ] [ --verbose ] [ --prefer-texmf ] [ --dry-run ] -**luaotfload** --find=FONTNAME [ --fuzzy ] [ --info ] +**luaotfload** --find=FONTNAME [ --fuzzy ] [ --info ] [ --inspect ] **luaotfload** --flush-lookups @@ -71,8 +71,18 @@ query mode --fuzzy, -F Show approximate matches to the file name if the lookup was unsuccessful (requires ``--find``). + --info, -i Display basic information to a resolved font file (requires ``--find``). +--inspect, -I Display detailed information by loading the + font and analyzing the font table; very slow! + For the meaning of the returned fields see + the LuaTeX documentation. + (requires ``--find``). +--warnings, -w Print the warnings generated by the fontloader + library (assumes ``-I``). Automatically enabled + if the verbosity level exceeds 2. + --show-blacklist, -b Show blacklisted files (not directories). --list=CRITERION Show entries, where *CRITERION* is one of the following: -- cgit v1.2.3 From f8ca3ac8836255ecc59b8db67af1e08ef367d740 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Wed, 26 Jun 2013 01:48:26 +0200 Subject: add gsub/gpos feature list to --inspect --- luaotfload-tool.lua | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 78 insertions(+), 4 deletions(-) diff --git a/luaotfload-tool.lua b/luaotfload-tool.lua index 02ca3a0..af21445 100755 --- a/luaotfload-tool.lua +++ b/luaotfload-tool.lua @@ -312,7 +312,12 @@ local p_words = Ct(p_word * (p_whitespace * p_word)^0) --- string -> int -> string list local reflow = function (text, width) - local words = lpegmatch(p_words, text) + local words + if type(text) == "string" then + words = lpegmatch(p_words, text) + else + words = text + end if #words < 2 then return { text } end @@ -392,7 +397,7 @@ local general_fields = { { "units_per_em", "l", "units per em" }, { "ascent", "l", "ascender height" }, { "descent", "l", "descender height" }, - { "comments", "l", "comments" }, + { "comment", "l", "comments" }, { "os2_version", "l", "os2 version" }, { "sfd_version", "l", "sfd version" }, } @@ -421,6 +426,75 @@ local display_general = function (fullinfo) 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 "" + print_heading("Features", 2) + print_heading("GSUB Features", 3) + display_feature_set(gsub) + print_heading("GPOS Features", 3) + display_feature_set(gpos) +end + local show_full_info = function (path, subfont, warnings) local rawinfo, warn = fontloader.open(path, subfont) if warnings then @@ -432,11 +506,11 @@ local show_full_info = function (path, subfont, warnings) end local fontdata = { } local fullinfo = fontloader.to_table(rawinfo) - local fields = fontloader.fields(rawinfo.glyphs[0]) + local fields = fontloader.fields(rawinfo) fontloader.close(rawinfo) - --inspect(fields) display_names(fullinfo.names) display_general(fullinfo) + display_features(fullinfo.gsub, fullinfo.gpos) end --- Subfonts returned by fontloader.info() do not correspond -- cgit v1.2.3 From 654fb24fdc2b927c59335a379bf7da943d579b08 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Wed, 26 Jun 2013 11:17:47 +0200 Subject: add counters to info output sections for better legibility --- luaotfload-tool.lua | 52 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/luaotfload-tool.lua b/luaotfload-tool.lua index af21445..27b3519 100755 --- a/luaotfload-tool.lua +++ b/luaotfload-tool.lua @@ -259,21 +259,52 @@ 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 s = adornchar .. adornchar .. " " .. title .. " " + local counter = format_counter(counterstack) + + local s = adornchar .. adornchar .. " " + .. counter .. " " + .. title .. " " texiowrite_nl (s .. stringrep(adornchar, textwidth-utf.len(s))) - texiowrite_nl "" end local show_info_items = function (fontinfo) - local items = table.sortedkeys(fontinfo) + local items = table.sortedkeys(fontinfo) print_heading(fontinfo.fullname, 1) + texiowrite_nl "" for n = 1, #items do local item = items[n] texiowrite_nl(stringformat( @@ -292,6 +323,7 @@ local show_fontloader_warnings = function (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)) @@ -315,11 +347,14 @@ 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 - end - if #words < 2 then - return { text } + if #words < 2 then + return words + end end local space = " " @@ -369,7 +404,8 @@ 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("%d) Language: %s ", i, lang), 3) + print_heading(stringformat("Language: %s ", i, lang), 3) + texiowrite_nl "" if namedata then for field, value in next, namedata do print_field(field, value) @@ -405,6 +441,7 @@ local general_fields = { 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) @@ -432,6 +469,7 @@ local print_features = function (features) for script, languages in next, data do local field = stringformat(key_fmt, script).. fieldseparator .. " " local wd_field = #field + --inspect(languages.list) local lines = reflow(languages.list, textwidth - wd_field) local indent = stringrep(" ", wd_field) texiowrite_nl(field) -- cgit v1.2.3 From 488d5b61fdf466b660ca5c86652ee5c661377ce7 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 27 Jun 2013 00:37:08 +0200 Subject: add message about the location of the names db to ``luaotfload-tool --update`` also make log messages more consistent wrt casing --- luaotfload-database.lua | 74 +++++++++++++++++++++++++------------------------ luaotfload-tool.lua | 28 +++++++++---------- 2 files changed, 52 insertions(+), 50 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index 82f6c7c..e0548ea 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -299,7 +299,7 @@ load_names = function (dry_run) local db_version, nms_version = data.version, names.version if db_version ~= nms_version then report("log", 0, "db", - [[version mismatch; expected %4.3f, got %4.3f]], + [[Version mismatch; expected %4.3f, got %4.3f]], nms_version, db_version) if not fonts_reloaded then report("log", 0, "db", [[force rebuild]]) @@ -398,12 +398,12 @@ local verbose_lookup = function (data, kind, filename) found = data.full[found] if found == nil then --> texmf report("info", 0, "db", - "crude file lookup: req=%s; hit=%s => kpse", + "Crude file lookup: req=%s; hit=%s => kpse", filename, kind) found = dummy_findfile(filename) else report("info", 0, "db", - "crude file lookup: req=%s; hit=%s; ret=%s", + "Crude file lookup: req=%s; hit=%s; ret=%s", filename, kind, found) end return found @@ -578,23 +578,23 @@ end resolve_cached = function (_, _, specification) if not names.lookups then names.lookups = load_lookups() end local request = hash_request(specification) - report("both", 4, "cache", "looking for “%s” in cache ...", + report("both", 4, "cache", "Looking for “%s” in cache ...", request) local found = names.lookups[request] --- case 1) cache positive ---------------------------------------- if found then --- replay fields from cache hit - report("info", 4, "cache", "found!") + report("info", 4, "cache", "Found!") local basename = found[1] --- check the presence of the file in case it’s been removed local success = verify_font_file(basename) if success == true then return basename, found[2], true end - report("both", 4, "cache", "cached file not found; resolving again") + report("both", 4, "cache", "Cached file not found; resolving again") else - report("both", 4, "cache", "not cached; resolving") + report("both", 4, "cache", "Not cached; resolving") end --- case 2) cache negative ---------------------------------------- @@ -603,16 +603,16 @@ resolve_cached = function (_, _, specification) if not success then return filename, subfont, false end --- ... then we add the fields to the cache ... ... local entry = { filename, subfont } - report("both", 4, "cache", "new entry: %s", request) + report("both", 4, "cache", "New entry: %s", request) names.lookups[request] = entry --- obviously, the updated cache needs to be stored. --- TODO this should trigger a save only once the --- document is compiled (finish_pdffile callback?) - report("both", 5, "cache", "saving updated cache") + report("both", 5, "cache", "Saving updated cache") local success = save_lookups() if not success then --- sad, but not critical - report("both", 0, "cache", "could not write to cache") + report("both", 0, "cache", "Could not write to cache") end return filename, subfont, true end @@ -801,7 +801,7 @@ resolve = function (_, _, specification) -- the 1st two parameters are used by C = get_font_file(data.filenames.full, entry) if success == true then report("log", 0, "resolve", - "font family='%s', subfamily='%s' found: %s", + "Font family='%s', subfamily='%s' found: %s", name, style, filename ) return filename, subfont, true @@ -824,7 +824,7 @@ resolve = function (_, _, specification) -- the 1st two parameters are used by C = get_font_file(data.filenames.full, closest) if success == true then report("log", 0, "resolve", - "font family='%s', subfamily='%s' found: %s", + "Font family='%s', subfamily='%s' found: %s", name, style, filename ) return filename, subfont, true @@ -834,11 +834,11 @@ resolve = function (_, _, specification) -- the 1st two parameters are used by C = get_font_file(data.filenames.full, fallback) if success == true then report("log", 0, "resolve", - "no exact match for request %s; using fallback", + "No exact match for request %s; using fallback", specification.specification ) report("log", 0, "resolve", - "font family='%s', subfamily='%s' found: %s", + "Font family='%s', subfamily='%s' found: %s", name, style, filename ) return filename, subfont, true @@ -850,7 +850,7 @@ resolve = function (_, _, specification) -- the 1st two parameters are used by C = get_font_file(data.filenames.full, entry) if success == true then report("log", 0, "resolve", - "font family='%s', subfamily='%s' found: %s", + "Font family='%s', subfamily='%s' found: %s", name, style, filename ) return filename, subfont, true @@ -888,7 +888,7 @@ end --- string -> ('a -> 'a) -> 'a list -> 'a reload_db = function (why, caller, ...) - report("both", 1, "db", "reload initiated; reason: “%s”", why) + report("both", 1, "db", "Reload initiated; reason: “%s”", why) names.data = update_names(names.data, false, false) local success = save_names() if success then @@ -984,13 +984,13 @@ find_closest = function (name, limit) tablesort(distances) limit = mathmin(n_distances, limit) report(false, 1, "query", - "displaying %d distance levels", limit) + "Displaying %d distance levels", limit) for i = 1, limit do local dist = distances[i] local namelst = by_distance[dist] report(false, 0, "query", - "distance from “" .. name .. "”: " .. dist + "Distance from “" .. name .. "”: " .. dist .. "\n " .. tableconcat(namelst, "\n ") ) end @@ -1018,7 +1018,7 @@ font_fullinfo = function (filename, subfont, texmf, basename) local tfmdata = { } local rawfont = fontloaderopen(filename, subfont) if not rawfont then - report("log", 1, "error", "failed to open %s", filename) + report("log", 1, "error", "Failed to open %s", filename) return end local metadata = fontloader.to_table(rawfont) @@ -1056,7 +1056,7 @@ font_fullinfo = function (filename, subfont, texmf, basename) end else -- no names table, propably a broken font - report("log", 1, "db", "broken font rejected", "%s", basefile) + report("log", 1, "db", "Broken font rejected", "%s", basefile) return end tfmdata.fontname = metadata.fontname @@ -1108,7 +1108,7 @@ local load_font = function (fullname, fontnames, newfontnames, texmf) if names.blacklist[fullname] or names.blacklist[basename] then report("log", 2, "db", - "ignoring blacklisted font “%s”", fullname) + "Ignoring blacklisted font “%s”", fullname) return false end @@ -1139,7 +1139,7 @@ local load_font = function (fullname, fontnames, newfontnames, texmf) newmappings[location] = fullinfo --- keep newentrystatus.index[index+1] = location --- is this actually used anywhere? end - report("log", 2, "db", "font “%s” already indexed", basename) + report("log", 2, "db", "Font “%s” already indexed", basename) return false end @@ -1172,7 +1172,7 @@ local load_font = function (fullname, fontnames, newfontnames, texmf) end else --- missing info - report("log", 1, "db", "failed to load “%s”", basename) + report("log", 1, "db", "Failed to load “%s”", basename) return false end return true @@ -1253,7 +1253,7 @@ local create_blacklist = function (blacklist, whitelist) local result = { } local dirs = { } - report("info", 2, "db", "blacklisting “%d” files and directories", + report("info", 2, "db", "Blacklisting “%d” files and directories", #blacklist) for i=1, #blacklist do local entry = blacklist[i] @@ -1264,7 +1264,7 @@ local create_blacklist = function (blacklist, whitelist) end end - report("info", 2, "db", "whitelisting “%d” files", #whitelist) + report("info", 2, "db", "Whitelisting “%d” files", #whitelist) for i=1, #whitelist do result[whitelist[i]] = nil end @@ -1313,7 +1313,7 @@ read_blacklist = function () line = stringsub(line, 1, cmt - 1) end line = stringstrip(line) - report("log", 2, "db", "blacklisted file “%s”", line) + report("log", 2, "db", "Blacklisted file “%s”", line) blacklist[#blacklist+1] = line end end @@ -1348,7 +1348,7 @@ local scan_dir = function (dirname, fontnames, newfontnames, dry_run, texmf) end local n_scanned, n_new = 0, 0 --- total of fonts collected - report("both", 3, "db", "scanning directory %s", dirname) + report("both", 3, "db", "Scanning directory %s", dirname) for _,i in next, font_extensions do for _,ext in next, { i, stringupper(i) } do local found = dirglob(stringformat("%s/**.%s$", dirname, ext)) @@ -1362,9 +1362,9 @@ local scan_dir = function (dirname, fontnames, newfontnames, dry_run, texmf) fullname = path_normalize(fullname) local new if dry_run == true then - report("both", 1, "db", "would have been loading “%s”", fullname) + report("both", 1, "db", "Would have been loading “%s”", fullname) else - report("both", 4, "db", "loading font “%s”", fullname) + report("both", 4, "db", "Loading font “%s”", fullname) local new = load_font(fullname, fontnames, newfontnames, texmf) if new == true then n_new = n_new + 1 @@ -1498,7 +1498,7 @@ do --- closure for read_fonts_conf() local fonts_conf_scanner = function (path) local fh = ioopen(path, "r") if not fh then - report("both", 3, "db", "cannot open fontconfig file %s", path) + report("both", 3, "db", "Cannot open fontconfig file %s", path) return end local raw = fh:read"*all" @@ -1506,7 +1506,7 @@ do --- closure for read_fonts_conf() local confdata = lpegmatch(p_cheapxml, raw) if not confdata then - report("both", 3, "db", "cannot scan fontconfig file %s", path) + report("both", 3, "db", "Cannot scan fontconfig file %s", path) return end return confdata @@ -1672,7 +1672,7 @@ end --- dbobj -> dbobj local gen_fast_lookups = function (fontnames) - report("both", 2, "db", "creating filename map") + report("both", 2, "db", "Creating filename map") local mappings = fontnames.mappings local nmappings = #mappings --- this is needlessly complicated due to texmf priorization @@ -1712,7 +1712,7 @@ local gen_fast_lookups = function (fontnames) local known = filenames.base[base] or filenames.bare[bare] if known then --- known report("both", 3, "db", - "font file “%s” already indexed (%d)", + "Font file “%s” already indexed (%d)", base, idx) report("both", 3, "db", "> old location: %s", (filenames.full[known] or "texmf")) @@ -1731,7 +1731,7 @@ local gen_fast_lookups = function (fontnames) end if config.luaotfload.prioritize == "texmf" then - report("both", 2, "db", "preferring texmf fonts") + report("both", 2, "db", "Preferring texmf fonts") addmap(sys) addmap(texmf) else --- sys @@ -1856,6 +1856,8 @@ save_names = function (fontnames) os.remove(lucname) caches.compile(fontnames, luaname, lucname) report("info", 1, "db", "Font names database saved") + report("info", 3, "db", "Text: " .. luaname) + report("info", 3, "db", "Byte: " .. lucname) return true end end @@ -1902,7 +1904,7 @@ local purge_from_cache = function (category, path, list, all) local checkname = file.replacesuffix( filename, "lua", "luc") if lfs.isfile(checkname) then - report("info", 5, "cache", "removing %s", filename) + report("info", 5, "cache", "Removing %s", filename) os.remove(filename) n = n + 1 end @@ -1910,7 +1912,7 @@ local purge_from_cache = function (category, path, list, all) end end end - report("info", 2, "cache", "removed lua files : %i", n) + report("info", 2, "cache", "Removed lua files : %i", n) return true end --- string -> string list -> int -> string list -> string list -> string list -> diff --git a/luaotfload-tool.lua b/luaotfload-tool.lua index 27b3519..45a75ba 100755 --- a/luaotfload-tool.lua +++ b/luaotfload-tool.lua @@ -433,7 +433,7 @@ local general_fields = { { "units_per_em", "l", "units per em" }, { "ascent", "l", "ascender height" }, { "descent", "l", "descender height" }, - { "comment", "l", "comments" }, + { "comments", "l", "comments" }, { "os2_version", "l", "os2 version" }, { "sfd_version", "l", "sfd version" }, } @@ -609,7 +609,7 @@ local show_font_info = function (basename, askedname, detail, warnings) [[%s is a font collection]], basename) for subfont = 1, nfonts do logs.names_report(true, 1, "resolve", - [[showing info for font no. %d]], n) + [[Showing info for font no. %d]], n) show_info_items(shortinfo[subfont]) if detail == true then show_full_info(fullname, subfont, warnings) @@ -624,7 +624,7 @@ local show_font_info = function (basename, askedname, detail, warnings) end else logs.names_report(true, 1, "resolve", - "font %s not found", filename) + "Font %s not found", filename) end end @@ -648,8 +648,8 @@ local actions = { } --- (jobspec -> (bool * bool)) list 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) + "Setting log level", "%d", job.log_level) + logs.names_report("log", 0, "util", "Lua=%s", _VERSION) return true, true end @@ -736,8 +736,8 @@ actions.query = function (job) "Resolved file name “%s”, subfont nr. “%s”", foundname, subfont) else - logs.names_report(false, 0, - "resolve", "Resolved file name “%s”", foundname) + logs.names_report(false, 0, "resolve", + "Resolved file name “%s”", foundname) end if job.show_info then show_font_info(foundname, query, job.full_info, job.warnings) @@ -831,7 +831,7 @@ actions.list = function (job) local nmappings = #mappings if criterion == "*" then - logs.names_report(false, 1, "list", "all %d entries", nmappings) + 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) @@ -846,12 +846,12 @@ actions.list = function (job) criterion = criterion[1] asked_fields = set_primary_field(asked_fields, criterion) - logs.names_report(false, 1, "list", "by %s", 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) + logs.names_report(false, 2, "list", "Restricting to value %s", asked_value) for i=1, nmappings do local entry = mappings[i] if entry[criterion] @@ -1042,7 +1042,7 @@ local main = function ( ) -- unit -> int local actionname = action_sequence[i] local exit = false if action_pending[actionname] then - logs.names_report("log", 3, "util", "preparing for task", + logs.names_report("log", 3, "util", "Preparing for task", "%s", actionname) local action = actions[actionname] @@ -1050,16 +1050,16 @@ local main = function ( ) -- unit -> int if not success then logs.names_report(false, 0, "util", - "could not finish task", "%s", actionname) + "Could not finish task", "%s", actionname) retval = -1 exit = true elseif not continue then logs.names_report(false, 3, "util", - "task completed, exiting", "%s", actionname) + "Task completed, exiting", "%s", actionname) exit = true else logs.names_report(false, 3, "util", - "task completed successfully", "%s", actionname) + "Task completed successfully", "%s", actionname) end end if exit then break end -- cgit v1.2.3 From 62493d4c3d4d3089f7a2ff30d811e8f035d98b8a Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 30 Jun 2013 14:10:04 +0200 Subject: add workaround for globbing of messy paths --- luaotfload-database.lua | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index e0548ea..1f8f34a 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -16,8 +16,8 @@ local lpeg = require "lpeg" local P, R, S, lpegmatch = lpeg.P, lpeg.R, lpeg.S, lpeg.match -local C, Cc, Cf, Cg, Ct - = lpeg.C, lpeg.Cc, lpeg.Cf, lpeg.Cg, lpeg.Ct +local C, Cc, Cf, Cg, Cs, Ct + = lpeg.C, lpeg.Cc, lpeg.Cf, lpeg.Cg, lpeg.Cs, lpeg.Ct --- Luatex builtins local load = load @@ -136,6 +136,17 @@ local sanitize_string = function (str) return nil end +local preescape_path --- working around funky characters +do + local escape = function (chr) return "%" .. chr end + local funkychar = S"()[]" + local pattern = Cs((funkychar/escape + 1)^0) + + preescape_path = function (str) + return lpegmatch (pattern, str) + end +end + --[[doc-- This is a sketch of the luaotfload db: @@ -1351,8 +1362,10 @@ local scan_dir = function (dirname, fontnames, newfontnames, dry_run, texmf) report("both", 3, "db", "Scanning directory %s", dirname) for _,i in next, font_extensions do for _,ext in next, { i, stringupper(i) } do - local found = dirglob(stringformat("%s/**.%s$", dirname, ext)) - local n_found = #found + local escapeddir = preescape_path (dirname) + local found = dirglob (stringformat("%s/**.%s$", + escapeddir, ext)) + local n_found = #found --- note that glob fails silently on broken symlinks, which --- happens sometimes in TeX Live. report("both", 4, "db", "%s '%s' fonts found", n_found, ext) @@ -1572,7 +1585,9 @@ do --- closure for read_fonts_conf() path, home, xdg_home, acc, done, dirs_done) elseif lfsisdir(path) then --- arrow code ahead - local config_files = dirglob(filejoin(path, "*.conf")) + local escapedpath = preescape_path (path) + local config_files = dirglob + (filejoin(escapedpath, "*.conf")) for _, filename in next, config_files do if not done[filename] then acc = read_fonts_conf_indeed( @@ -1920,7 +1935,8 @@ end local collect_cache collect_cache = function (path, all, n, luanames, lucnames, rest) if not all then - local all = dirglob(path .. "/**/*") + local escapedpath = preescape_path (path) + local all = dirglob (escapedpath .. "/**/*") local luanames, lucnames, rest = { }, { }, { } return collect_cache(nil, all, 1, luanames, lucnames, rest) end -- cgit v1.2.3 From 71eb6250e1971b7ead98f6d91a7d325597730ebe Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 2 Jul 2013 12:42:10 +0200 Subject: treat psname matches as second-tier (fixes cambria) --- luaotfload-database.lua | 4 +--- luaotfload-merged.lua | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index 1f8f34a..7baa92a 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -769,9 +769,7 @@ resolve = function (_, _, specification) -- the 1st two parameters are used by C or name == fontname or name == psname then - local continue - exact, continue = add_to_match(exact, askedsize, face) - if continue == false then break end + synonymous, continue = add_to_match(synonymous, askedsize, face) elseif synonym_set[style] and (synonym_set[style][prefmodifiers] or synonym_set[style][subfamily]) diff --git a/luaotfload-merged.lua b/luaotfload-merged.lua index 81e3fec..9d708bf 100644 --- a/luaotfload-merged.lua +++ b/luaotfload-merged.lua @@ -3143,7 +3143,7 @@ function caches.savedata(path,name,data) local luaname,lucname=makefullname(path,name) if luaname then texio.write(string.format("(save: %s)",luaname)) - table.tofile(luaname,data,true,{ reduce=true }) + table.tofile(luaname,data,true,{ reduce=false }) if lucname and type(caches.compile)=="function" then os.remove(lucname) texio.write(string.format("(save: %s)",lucname)) -- cgit v1.2.3 From c640e41c3431821d6bfbbad418f352008cf4f942 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 2 Jul 2013 13:10:00 +0200 Subject: make feature request parser skip empty fields addresses https://github.com/lualatex/luaotfload/issues/103 --- luaotfload-features.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/luaotfload-features.lua b/luaotfload-features.lua index 81d1437..690a33c 100644 --- a/luaotfload-features.lua +++ b/luaotfload-features.lua @@ -1032,7 +1032,7 @@ local feature_expr = ws * Cg(assignment + switch) * ws local option = feature_expr local feature_list = Cf(Ct"" * option - * (featuresep * option)^0 + * (featuresep * option^-1)^0 , rawset) * featuresep^-1 -- cgit v1.2.3 From b4fdea433f1949238fca34af9ba2a8b332e992a4 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 2 Jul 2013 14:38:16 +0200 Subject: replace globber in scan_dir() --- luaotfload-database.lua | 144 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 98 insertions(+), 46 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index 7baa92a..9eb5b1f 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -33,12 +33,11 @@ local iolines = io.lines local ioopen = io.open local kpseexpand_path = kpse.expand_path local kpseexpand_var = kpse.expand_var -local kpselookup = kpse.lookup local kpsefind_file = kpse.find_file +local kpselookup = kpse.lookup local kpsereadable_file = kpse.readable_file -local lfsisdir = lfs.isdir -local lfsisfile = lfs.isfile local lfsattributes = lfs.attributes +local lfsdir = lfs.dir local mathabs = math.abs local mathmin = math.min local stringfind = string.find @@ -49,9 +48,7 @@ local stringlower = string.lower local stringsub = string.sub local stringupper = string.upper local tableconcat = table.concat -local tablecopy = table.copy local tablesort = table.sort -local tabletofile = table.tofile local texiowrite_nl = texio.write_nl local utf8gsub = unicode.utf8.gsub local utf8lower = unicode.utf8.lower @@ -60,18 +57,22 @@ local utf8lower = unicode.utf8.lower local dirglob = dir.glob local dirmkdirs = dir.mkdirs local filebasename = file.basename -local filenameonly = file.nameonly -local filedirname = file.dirname local filecollapsepath = file.collapsepath or file.collapse_path +local filedirname = file.dirname local fileextname = file.extname local fileiswritable = file.iswritable local filejoin = file.join +local filenameonly = file.nameonly local filereplacesuffix = file.replacesuffix local filesplitpath = file.splitpath or file.split_path +local lfsisdir = lfs.isdir +local lfsisfile = lfs.isfile local stringis_empty = string.is_empty local stringsplit = string.split local stringstrip = string.strip local tableappend = table.append +local tablecopy = table.copy +local tabletofile = table.tofile local tabletohash = table.tohash --- the font loader namespace is “fonts”, same as in Context @@ -1206,8 +1207,8 @@ do return path end --[[doc-- - Cygwin used to be treated different from windows and dos. This - special treatment was removed with a patch submitted by Ken Brown. + The special treatment for cygwin was removed with a patch submitted + by Ken Brown. Reference: http://cygwin.com/ml/cygwin/2013-05/msg00006.html --doc]]-- @@ -1301,12 +1302,12 @@ end --- unit -> unit read_blacklist = function () local files = { - kpselookup("luaotfload-blacklist.cnf", {all=true, format="tex"}) + kpselookup ("luaotfload-blacklist.cnf", + {all=true, format="tex"}) } local blacklist = { } local whitelist = { } - --- TODO lpegify if files and type(files) == "table" then for _,v in next, files do for line in iolines(v) do @@ -1331,10 +1332,59 @@ read_blacklist = function () names.blacklist = create_blacklist(blacklist, whitelist) end -local font_extensions = { "otf", "ttf", "ttc", "dfont" } -local font_extensions_set = {} -for key, value in next, font_extensions do - font_extensions_set[value] = true +local font_extensions = { "otf", "ttf", "ttc", "dfont" } +local font_extensions_set = tabletohash (font_extensions) +local p_font_extensions +do + local extns + --tablesort (font_extensions) --- safeguard + for i=#font_extensions, 1, -1 do + local e = font_extensions[i] + if not extns then + extns = P(e) + else + extns = extns + P(e) + end + end + extns = extns * P(-1) + p_font_extensions = (1 - extns)^1 * extns +end + +local process_dir_tree +process_dir_tree = function (acc, dirs) + if not next (dirs) then --- done + return acc + end + + local dir = dirs[#dirs] + dirs[#dirs] = nil + + local newdirs, newfiles = { }, { } + local blacklist = names.blacklist + for ent in lfsdir (dir) do + --- filter right away + if ent ~= "." and ent ~= ".." and not blacklist[ent] then + local fullpath = dir .. "/" .. ent + if lfsisdir (fullpath) + and not lpegmatch (p_blacklist, fullpath) + then + newdirs[#newdirs+1] = fullpath + elseif lfsisfile (fullpath) then + if lpegmatch (p_font_extensions, stringlower(ent)) then + newfiles[#newfiles+1] = fullpath + end + end + end + end + return process_dir_tree (tableappend (acc, newfiles), + tableappend (dirs, newdirs)) +end + +--- string -> string list +local find_font_files = function (root) + if lfsisdir (root) then + return process_dir_tree ({}, { root }) + end end --[[doc-- @@ -1350,42 +1400,45 @@ end --doc]]-- --- string -> dbobj -> dbobj -> bool -> bool -> (int * int) -local scan_dir = function (dirname, fontnames, newfontnames, dry_run, texmf) - if lpegmatch(p_blacklist, dirname) then +local scan_dir = function (dirname, fontnames, newfontnames, + dry_run, texmf) + if lpegmatch (p_blacklist, dirname) then + report ("both", 3, "db", + "Skipping blacklisted directory %s", dirname) --- ignore return 0, 0 end - - local n_scanned, n_new = 0, 0 --- total of fonts collected - report("both", 3, "db", "Scanning directory %s", dirname) - for _,i in next, font_extensions do - for _,ext in next, { i, stringupper(i) } do - local escapeddir = preescape_path (dirname) - local found = dirglob (stringformat("%s/**.%s$", - escapeddir, ext)) - local n_found = #found - --- note that glob fails silently on broken symlinks, which - --- happens sometimes in TeX Live. - report("both", 4, "db", "%s '%s' fonts found", n_found, ext) - n_scanned = n_scanned + n_found - for j=1, n_found do - local fullname = found[j] - fullname = path_normalize(fullname) - local new - if dry_run == true then - report("both", 1, "db", "Would have been loading “%s”", fullname) - else - report("both", 4, "db", "Loading font “%s”", fullname) - local new = load_font(fullname, fontnames, newfontnames, texmf) - if new == true then - n_new = n_new + 1 - end - end + local found = find_font_files (dirname) + if not found then + report ("both", 3, "db", + "No such directory: “%s”; skipping.", dirname) + return 0, 0 + end + report ("both", 3, "db", "Scanning directory %s", dirname) + + local n_new = 0 --- total of fonts collected + local n_found = #found + report ("both", 4, "db", "%d font files detected", n_found) + for j=1, n_found do + local fullname = found[j] + fullname = path_normalize(fullname) + local new + if dry_run == true then + report ("both", 1, "db", + "Would have been loading “%s”", fullname) + else + report ("both", 4, "db", + "Loading font “%s”", fullname) + local new = load_font (fullname, fontnames, + newfontnames, texmf) + if new == true then + n_new = n_new + 1 end end end - report("both", 4, "db", "%d fonts found in '%s'", n_scanned, dirname) - return n_scanned, n_new + + report("both", 4, "db", "%d fonts found in '%s'", n_found, dirname) + return n_found, n_new end --- dbobj -> dbobj -> bool? -> (int * int) @@ -1404,7 +1457,6 @@ local scan_texmf_fonts = function (fontnames, newfontnames, dry_run) fontdirs = fontdirs .. stringgsub(kpseexpand_path("$TTFONTS"), "^%.", "") if not stringis_empty(fontdirs) then for _,d in next, filesplitpath(fontdirs) do - report("info", 4, "db", "Entering directory %s", d) local found, new = scan_dir(d, fontnames, newfontnames, dry_run, true) n_scanned = n_scanned + found n_new = n_new + new -- cgit v1.2.3 From e46b1ade1a0b4cabec661aa0f505efd03b9bdc5a Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 2 Jul 2013 14:53:44 +0200 Subject: limit font cache controls to actual font cache dir --- luaotfload-database.lua | 18 +++++++++++++++--- luaotfload-override.lua | 5 ++++- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index 9eb5b1f..4755396 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -2006,9 +2006,21 @@ local collect_cache collect_cache = function (path, all, n, luanames, return luanames, lucnames, rest, all end +local getfontcachepath = function ( ) + --- fonts.handlers.otf doesn’t exist outside a Luatex run, + --- so we have to improvise + local writable = caches.getwritablepath () + if writable then + writable = writable .. "/fonts" + if lfsisdir (writable) then + return writable + end + end +end + --- unit -> unit local purge_cache = function ( ) - local writable_path = caches.getwritablepath() + local writable_path = getfontcachepath () local luanames, lucnames, rest = collect_cache(writable_path) if logs.get_loglevel() > 1 then print_cache("writable path", writable_path, luanames, lucnames, rest) @@ -2019,7 +2031,7 @@ end --- unit -> unit local erase_cache = function ( ) - local writable_path = caches.getwritablepath() + local writable_path = getfontcachepath () local luanames, lucnames, rest, all = collect_cache(writable_path) if logs.get_loglevel() > 1 then print_cache("writable path", writable_path, luanames, lucnames, rest) @@ -2035,7 +2047,7 @@ end --- unit -> unit local show_cache = function ( ) local readable_paths = caches.getreadablepaths() - local writable_path = caches.getwritablepath() + local writable_path = getfontcachepath () local luanames, lucnames, rest = collect_cache(writable_path) separator() diff --git a/luaotfload-override.lua b/luaotfload-override.lua index caf3627..225ac68 100644 --- a/luaotfload-override.lua +++ b/luaotfload-override.lua @@ -106,7 +106,10 @@ end stdout = function (category, ...) local res = { module_name, "|", category, ":" } - if select("#", ...) == 1 then + local nargs = select("#", ...) + if nargs == 0 then + writeln (tableconcat ({...})) + elseif nargs == 1 then res[#res+1] = select(1, ...) -- around 30% faster than unpack() else res[#res+1] = stringformat(...) -- cgit v1.2.3 From 4a01814961fa764fc246f8f3976ccd830c54dadf Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 2 Jul 2013 15:01:00 +0200 Subject: restrict readable path stats to font cache --- luaotfload-database.lua | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index 4755396..39c6ab5 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -2006,7 +2006,7 @@ local collect_cache collect_cache = function (path, all, n, luanames, return luanames, lucnames, rest, all end -local getfontcachepath = function ( ) +local getwritablecachepath = function ( ) --- fonts.handlers.otf doesn’t exist outside a Luatex run, --- so we have to improvise local writable = caches.getwritablepath () @@ -2018,9 +2018,23 @@ local getfontcachepath = function ( ) end end +local getreadablecachepaths = function ( ) + local readables = caches.getreadablepaths () + local result = { } + if readables then + for i=1, #readables do + local readable = readables[i] .. "/fonts" + if lfsisdir (readable) then + result[#result+1] = readable + end + end + end + return result +end + --- unit -> unit local purge_cache = function ( ) - local writable_path = getfontcachepath () + local writable_path = getwritablecachepath () local luanames, lucnames, rest = collect_cache(writable_path) if logs.get_loglevel() > 1 then print_cache("writable path", writable_path, luanames, lucnames, rest) @@ -2031,7 +2045,7 @@ end --- unit -> unit local erase_cache = function ( ) - local writable_path = getfontcachepath () + local writable_path = getwritablecachepath () local luanames, lucnames, rest, all = collect_cache(writable_path) if logs.get_loglevel() > 1 then print_cache("writable path", writable_path, luanames, lucnames, rest) @@ -2046,19 +2060,20 @@ end --- unit -> unit local show_cache = function ( ) - local readable_paths = caches.getreadablepaths() - local writable_path = getfontcachepath () + local readable_paths = getreadablecachepaths () + local writable_path = getwritablecachepath () local luanames, lucnames, rest = collect_cache(writable_path) - separator() - print_cache("writable path", writable_path, luanames, lucnames, rest) + separator () + print_cache ("writable path", writable_path, + luanames, lucnames, rest) texiowrite_nl"" for i=1,#readable_paths do local readable_path = readable_paths[i] if readable_path ~= writable_path then - local luanames, lucnames = collect_cache(readable_path) - print_cache("readable path", - readable_path,luanames,lucnames,rest) + local luanames, lucnames = collect_cache (readable_path) + print_cache ("readable path", + readable_path, luanames, lucnames, rest) end end separator() -- cgit v1.2.3 From 77531144a0d04d08527d44a9d6316a5d7a24020f Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 2 Jul 2013 15:39:37 +0200 Subject: extend file locator with filtering (no references to dir.glob() anymore --- luaotfload-database.lua | 64 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 51 insertions(+), 13 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index 39c6ab5..04b8720 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -54,7 +54,6 @@ local utf8gsub = unicode.utf8.gsub local utf8lower = unicode.utf8.lower --- these come from Lualibs/Context -local dirglob = dir.glob local dirmkdirs = dir.mkdirs local filebasename = file.basename local filecollapsepath = file.collapsepath or file.collapse_path @@ -137,17 +136,47 @@ local sanitize_string = function (str) return nil end -local preescape_path --- working around funky characters -do - local escape = function (chr) return "%" .. chr end - local funkychar = S"()[]" - local pattern = Cs((funkychar/escape + 1)^0) +local find_files_indeed +find_files_indeed = function (acc, dirs, filter) + if not next (dirs) then --- done + return acc + end + + local dir = dirs[#dirs] + dirs[#dirs] = nil + + local newdirs, newfiles = { }, { } + for ent in lfsdir (dir) do + if ent ~= "." and ent ~= ".." then + local fullpath = dir .. "/" .. ent + if filter (fullpath) == true then + if lfsisdir (fullpath) then + newdirs[#newdirs+1] = fullpath + elseif lfsisfile (fullpath) then + newfiles[#newfiles+1] = fullpath + end + end + end + end + return find_files_indeed (tableappend (acc, newfiles), + tableappend (dirs, newdirs), + filter) +end + +local dummyfilter = function () return true end - preescape_path = function (str) - return lpegmatch (pattern, str) +--- the optional filter function receives the full path of a file +--- system entity. a filter applies if the first argument it returns is +--- true. + +--- string -> function? -> string list +local find_files = function (root, filter) + if lfsisdir (root) then + return find_files_indeed ({}, { root }, filter or dummyfilter) end end + --[[doc-- This is a sketch of the luaotfload db: @@ -1575,6 +1604,16 @@ do --- closure for read_fonts_conf() return confdata end + local p_conf = P".conf" * P(-1) + local p_filter = (1 - p_conf)^1 * p_conf + + local conf_filter = function (path) + if lpegmatch (p_filter, path) then + return true + end + return false + end + --[[doc-- read_fonts_conf_indeed() is called with six arguments; the latter three are tables that represent the state and are @@ -1635,9 +1674,7 @@ do --- closure for read_fonts_conf() path, home, xdg_home, acc, done, dirs_done) elseif lfsisdir(path) then --- arrow code ahead - local escapedpath = preescape_path (path) - local config_files = dirglob - (filejoin(escapedpath, "*.conf")) + local config_files = find_files (path, conf_filter) for _, filename in next, config_files do if not done[filename] then acc = read_fonts_conf_indeed( @@ -1980,13 +2017,14 @@ local purge_from_cache = function (category, path, list, all) report("info", 2, "cache", "Removed lua files : %i", n) return true end + --- string -> string list -> int -> string list -> string list -> string list -> --- (string list * string list * string list * string list) local collect_cache collect_cache = function (path, all, n, luanames, lucnames, rest) if not all then - local escapedpath = preescape_path (path) - local all = dirglob (escapedpath .. "/**/*") + local all = find_files (path) + local luanames, lucnames, rest = { }, { }, { } return collect_cache(nil, all, 1, luanames, lucnames, rest) end -- cgit v1.2.3 From 8a5db2c34e4146946f4674ea3e4caf63e08c8cc9 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 2 Jul 2013 15:48:14 +0200 Subject: replace dir.mkdirs() with lfs.mkdirs() --- luaotfload-database.lua | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index 04b8720..338ffa6 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -54,7 +54,6 @@ local utf8gsub = unicode.utf8.gsub local utf8lower = unicode.utf8.lower --- these come from Lualibs/Context -local dirmkdirs = dir.mkdirs local filebasename = file.basename local filecollapsepath = file.collapsepath or file.collapse_path local filedirname = file.dirname @@ -66,6 +65,7 @@ local filereplacesuffix = file.replacesuffix local filesplitpath = file.splitpath or file.split_path local lfsisdir = lfs.isdir local lfsisfile = lfs.isfile +local lfsmkdirs = lfs.mkdirs local stringis_empty = string.is_empty local stringsplit = string.split local stringstrip = string.strip @@ -83,6 +83,15 @@ fonts.definers = fonts.definers or { } local names = fonts.names +config = config or { } +config.luaotfload = config.luaotfload or { } +config.luaotfload.resolver = config.luaotfload.resolver or "normal" +if config.luaotfload.update_live ~= false then + --- this option allows for disabling updates + --- during a TeX run + config.luaotfload.update_live = true +end + names.version = 2.207 names.data = nil --- contains the loaded database names.lookups = nil --- contains the lookup cache @@ -94,15 +103,6 @@ names.path = { lookup_path = "", --- cache full path } -config = config or { } -config.luaotfload = config.luaotfload or { } -config.luaotfload.resolver = config.luaotfload.resolver or "normal" -if config.luaotfload.update_live ~= false then - --- this option allows for disabling updates - --- during a TeX run - config.luaotfload.update_live = true -end - -- We use the cache.* of ConTeXt (see luat-basics-gen), we can -- use it safely (all checks and directory creations are already done). It -- uses TEXMFCACHE or TEXMFVAR as starting points. @@ -1912,7 +1912,7 @@ end local ensure_names_path = function ( ) local path = names.path.dir if not lfsisdir(path) then - dirmkdirs(path) + lfsmkdirs(path) end return path end -- cgit v1.2.3 From 7a6b20715c61f6da1c2aa67e728935e9b83e5f47 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 2 Jul 2013 15:52:46 +0200 Subject: stop including luaotfload-lib-dir.lua --- luaotfload.dtx | 1 - 1 file changed, 1 deletion(-) diff --git a/luaotfload.dtx b/luaotfload.dtx index 8ebd8ec..7a2710d 100644 --- a/luaotfload.dtx +++ b/luaotfload.dtx @@ -1805,7 +1805,6 @@ add_to_callback("hpack_filter", add_to_callback("find_vf_file", find_vf_file, "luaotfload.find_vf_file") -loadmodule"lib-dir.lua" --- required by luaofload-database.lua loadmodule"override.lua" --- “luat-ovr” logs.set_loglevel(config.luaotfload.loglevel) -- cgit v1.2.3 From a31d6dab37752be4cac12e61cf819a88a6a628b4 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 2 Jul 2013 15:55:39 +0200 Subject: remove references to lib-dir from docs --- filegraph.dot | 3 +-- luaotfload.dtx | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/filegraph.dot b/filegraph.dot index 8db137c..c8a07d3 100644 --- a/filegraph.dot +++ b/filegraph.dot @@ -139,10 +139,9 @@ strict digraph luaotfload_files { //looks weird with circo ... label = < - + -
Luaotfload Libraries
luaotfload-lib-dir.lua luaotfload-features.lua
luaotfload-auxiliary.lua luaotfload-features.lua
luaotfload-override.lua luaotfload-loaders.lua
luaotfload-database.lua luaotfload-color.lua
luaotfload-auxiliary.lua
>, ] diff --git a/luaotfload.dtx b/luaotfload.dtx index 7a2710d..b66a88f 100644 --- a/luaotfload.dtx +++ b/luaotfload.dtx @@ -1194,9 +1194,6 @@ and the derived files % \ouritem {luaotfload-features.lua} font feature handling; % incorporates some of the code from % \fileent{font-otc} from \CONTEXT; -% \ouritem {luaotfload-lib-dir.lua} \fileent{l-dir} from \CONTEXT; -% contains functionality required -% by \fileent{luaotfload-font-nms.lua}. % \ouritem {luaotfload-override.lua} overrides the \CONTEXT logging % functionality. % \ouritem {luaotfload-loaders.lua} registers the \OpenType -- cgit v1.2.3 From 3dcce134ea3785ff1545aa12d203ae8021af1ef3 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 2 Jul 2013 15:55:55 +0200 Subject: remove lib-dir from tracking --- luaotfload-lib-dir.lua | 470 ------------------------------------------------- 1 file changed, 470 deletions(-) delete mode 100644 luaotfload-lib-dir.lua diff --git a/luaotfload-lib-dir.lua b/luaotfload-lib-dir.lua deleted file mode 100644 index 3d0576e..0000000 --- a/luaotfload-lib-dir.lua +++ /dev/null @@ -1,470 +0,0 @@ -if not modules then modules = { } end modules ['l-dir'] = { - version = 1.001, - comment = "companion to luat-lib.mkiv", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - --- dir.expandname will be merged with cleanpath and collapsepath - -local type, select = type, select -local find, gmatch, match, gsub = string.find, string.gmatch, string.match, string.gsub -local concat, insert, remove, unpack = table.concat, table.insert, table.remove, table.unpack -local lpegmatch = lpeg.match - -local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V - -dir = dir or { } -local dir = dir -local lfs = lfs - -local attributes = lfs.attributes -local walkdir = lfs.dir -local isdir = lfs.isdir -local isfile = lfs.isfile -local currentdir = lfs.currentdir -local chdir = lfs.chdir - --- in case we load outside luatex - -if not isdir then - function isdir(name) - local a = attributes(name) - return a and a.mode == "directory" - end - lfs.isdir = isdir -end - -if not isfile then - function isfile(name) - local a = attributes(name) - return a and a.mode == "file" - end - lfs.isfile = isfile -end - --- handy - -function dir.current() - return (gsub(currentdir(),"\\","/")) -end - --- optimizing for no find (*) does not save time - ---~ local function globpattern(path,patt,recurse,action) -- fails in recent luatex due to some change in lfs ---~ local ok, scanner ---~ if path == "/" then ---~ ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe ---~ else ---~ ok, scanner = xpcall(function() return walkdir(path) end, function() end) -- kepler safe ---~ end ---~ if ok and type(scanner) == "function" then ---~ if not find(path,"/$") then path = path .. '/' end ---~ for name in scanner do ---~ local full = path .. name ---~ local mode = attributes(full,'mode') ---~ if mode == 'file' then ---~ if find(full,patt) then ---~ action(full) ---~ end ---~ elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then ---~ globpattern(full,patt,recurse,action) ---~ end ---~ end ---~ end ---~ end - -local lfsisdir = isdir - -local function isdir(path) - path = gsub(path,"[/\\]+$","") - return lfsisdir(path) -end - -lfs.isdir = isdir - -local function globpattern(path,patt,recurse,action) - if path == "/" then - path = path .. "." - elseif not find(path,"/$") then - path = path .. '/' - end - if isdir(path) then -- lfs.isdir does not like trailing / - for name in walkdir(path) do -- lfs.dir accepts trailing / - local full = path .. name - local mode = attributes(full,'mode') - if mode == 'file' then - if find(full,patt) then - action(full) - end - elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then - globpattern(full,patt,recurse,action) - end - end - end -end - -dir.globpattern = globpattern - -local function collectpattern(path,patt,recurse,result) - local ok, scanner - result = result or { } - if path == "/" then - ok, scanner, first = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe - else - ok, scanner, first = xpcall(function() return walkdir(path) end, function() end) -- kepler safe - end - if ok and type(scanner) == "function" then - if not find(path,"/$") then path = path .. '/' end - for name in scanner, first do - local full = path .. name - local attr = attributes(full) - local mode = attr.mode - if mode == 'file' then - if find(full,patt) then - result[name] = attr - end - elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then - attr.list = collectpattern(full,patt,recurse) - result[name] = attr - end - end - end - return result -end - -dir.collectpattern = collectpattern - -local pattern = Ct { - [1] = (C(P(".") + P("/")^1) + C(R("az","AZ") * P(":") * P("/")^0) + Cc("./")) * V(2) * V(3), - [2] = C(((1-S("*?/"))^0 * P("/"))^0), - [3] = C(P(1)^0) -} - -local filter = Cs ( ( - P("**") / ".*" + - P("*") / "[^/]*" + - P("?") / "[^/]" + - P(".") / "%%." + - P("+") / "%%+" + - P("-") / "%%-" + - P(1) -)^0 ) - -local function glob(str,t) - if type(t) == "function" then - if type(str) == "table" then - for s=1,#str do - glob(str[s],t) - end - elseif isfile(str) then - t(str) - else - local split = lpegmatch(pattern,str) -- we could use the file splitter - if split then - local root, path, base = split[1], split[2], split[3] - local recurse = find(base,"%*%*") - local start = root .. path - local result = lpegmatch(filter,start .. base) - globpattern(start,result,recurse,t) - end - end - else - if type(str) == "table" then - local t = t or { } - for s=1,#str do - glob(str[s],t) - end - return t - elseif isfile(str) then - if t then - t[#t+1] = str - return t - else - return { str } - end - else - local split = lpegmatch(pattern,str) -- we could use the file splitter - if split then - local t = t or { } - local action = action or function(name) t[#t+1] = name end - local root, path, base = split[1], split[2], split[3] - local recurse = find(base,"%*%*") - local start = root .. path - local result = lpegmatch(filter,start .. base) - globpattern(start,result,recurse,action) - return t - else - return { } - end - end - end -end - -dir.glob = glob - ---~ list = dir.glob("**/*.tif") ---~ list = dir.glob("/**/*.tif") ---~ list = dir.glob("./**/*.tif") ---~ list = dir.glob("oeps/**/*.tif") ---~ list = dir.glob("/oeps/**/*.tif") - -local function globfiles(path,recurse,func,files) -- func == pattern or function - if type(func) == "string" then - local s = func - func = function(name) return find(name,s) end - end - files = files or { } - local noffiles = #files - for name in walkdir(path) do - if find(name,"^%.") then - --- skip - else - local mode = attributes(name,'mode') - if mode == "directory" then - if recurse then - globfiles(path .. "/" .. name,recurse,func,files) - end - elseif mode == "file" then - if not func or func(name) then - noffiles = noffiles + 1 - files[noffiles] = path .. "/" .. name - end - end - end - end - return files -end - -dir.globfiles = globfiles - --- t = dir.glob("c:/data/develop/context/sources/**/????-*.tex") --- t = dir.glob("c:/data/develop/tex/texmf/**/*.tex") --- t = dir.glob("c:/data/develop/context/texmf/**/*.tex") --- t = dir.glob("f:/minimal/tex/**/*") --- print(dir.ls("f:/minimal/tex/**/*")) --- print(dir.ls("*.tex")) - -function dir.ls(pattern) - return concat(glob(pattern),"\n") -end - ---~ mkdirs("temp") ---~ mkdirs("a/b/c") ---~ mkdirs(".","/a/b/c") ---~ mkdirs("a","b","c") - -local make_indeed = true -- false - -local onwindows = os.type == "windows" or find(os.getenv("PATH"),";") - -if onwindows then - - function dir.mkdirs(...) - local str, pth = "", "" - for i=1,select("#",...) do - local s = select(i,...) - if s == "" then - -- skip - elseif str == "" then - str = s - else - str = str .. "/" .. s - end - end - local first, middle, last - local drive = false - first, middle, last = match(str,"^(//)(//*)(.*)$") - if first then - -- empty network path == local path - else - first, last = match(str,"^(//)/*(.-)$") - if first then - middle, last = match(str,"([^/]+)/+(.-)$") - if middle then - pth = "//" .. middle - else - pth = "//" .. last - last = "" - end - else - first, middle, last = match(str,"^([a-zA-Z]:)(/*)(.-)$") - if first then - pth, drive = first .. middle, true - else - middle, last = match(str,"^(/*)(.-)$") - if not middle then - last = str - end - end - end - end - for s in gmatch(last,"[^/]+") do - if pth == "" then - pth = s - elseif drive then - pth, drive = pth .. s, false - else - pth = pth .. "/" .. s - end - if make_indeed and not isdir(pth) then - lfs.mkdir(pth) - end - end - return pth, (isdir(pth) == true) - end - - --~ print(dir.mkdirs("","","a","c")) - --~ print(dir.mkdirs("a")) - --~ print(dir.mkdirs("a:")) - --~ print(dir.mkdirs("a:/b/c")) - --~ print(dir.mkdirs("a:b/c")) - --~ print(dir.mkdirs("a:/bbb/c")) - --~ print(dir.mkdirs("/a/b/c")) - --~ print(dir.mkdirs("/aaa/b/c")) - --~ print(dir.mkdirs("//a/b/c")) - --~ print(dir.mkdirs("///a/b/c")) - --~ print(dir.mkdirs("a/bbb//ccc/")) - -else - - function dir.mkdirs(...) - local str, pth = "", "" - for i=1,select("#",...) do - local s = select(i,...) - if s and s ~= "" then -- we catch nil and false - if str ~= "" then - str = str .. "/" .. s - else - str = s - end - end - end - str = gsub(str,"/+","/") - if find(str,"^/") then - pth = "/" - for s in gmatch(str,"[^/]+") do - local first = (pth == "/") - if first then - pth = pth .. s - else - pth = pth .. "/" .. s - end - if make_indeed and not first and not isdir(pth) then - lfs.mkdir(pth) - end - end - else - pth = "." - for s in gmatch(str,"[^/]+") do - pth = pth .. "/" .. s - if make_indeed and not isdir(pth) then - lfs.mkdir(pth) - end - end - end - return pth, (isdir(pth) == true) - end - - --~ print(dir.mkdirs("","","a","c")) - --~ print(dir.mkdirs("a")) - --~ print(dir.mkdirs("/a/b/c")) - --~ print(dir.mkdirs("/aaa/b/c")) - --~ print(dir.mkdirs("//a/b/c")) - --~ print(dir.mkdirs("///a/b/c")) - --~ print(dir.mkdirs("a/bbb//ccc/")) - -end - -dir.makedirs = dir.mkdirs - --- we can only define it here as it uses dir.current - -if onwindows then - - function dir.expandname(str) -- will be merged with cleanpath and collapsepath - local first, nothing, last = match(str,"^(//)(//*)(.*)$") - if first then - first = dir.current() .. "/" -- dir.current sanitizes - end - if not first then - first, last = match(str,"^(//)/*(.*)$") - end - if not first then - first, last = match(str,"^([a-zA-Z]:)(.*)$") - if first and not find(last,"^/") then - local d = currentdir() - if chdir(first) then - first = dir.current() - end - chdir(d) - end - end - if not first then - first, last = dir.current(), str - end - last = gsub(last,"//","/") - last = gsub(last,"/%./","/") - last = gsub(last,"^/*","") - first = gsub(first,"/*$","") - if last == "" or last == "." then - return first - else - return first .. "/" .. last - end - end - -else - - function dir.expandname(str) -- will be merged with cleanpath and collapsepath - if not find(str,"^/") then - str = currentdir() .. "/" .. str - end - str = gsub(str,"//","/") - str = gsub(str,"/%./","/") - str = gsub(str,"(.)/%.$","%1") - return str - end - -end - -file.expandname = dir.expandname -- for convenience - -local stack = { } - -function dir.push(newdir) - insert(stack,currentdir()) - if newdir and newdir ~= "" then - chdir(newdir) - end -end - -function dir.pop() - local d = remove(stack) - if d then - chdir(d) - end - return d -end - -local function found(...) -- can have nil entries - for i=1,select("#",...) do - local path = select(i,...) - local kind = type(path) - if kind == "string" then - if isdir(path) then - return path - end - elseif kind == "table" then - -- here we asume no holes, i.e. an indexed table - local path = found(unpack(path)) - if path then - return path - end - end - end - -- return nil -- if we want print("crappath") to show something -end - -dir.found = found -- cgit v1.2.3 From cba3f693b07b52734aa8ef6c35eb99ac4946ba04 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 2 Jul 2013 22:11:03 +0200 Subject: update NEWS --- NEWS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NEWS b/NEWS index b504b9b..f9f3b3d 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,10 @@ Change History * Rewrite the output of ``\fontname`` via ``patch_font`` callback * Allow blacklisting directories * Drop compatibility layer + * Remove dependency on luaotfload-lib-dir (references to dir.glob() and + dir.mkdirs()) + * luaotfload-tool now displays extensive information about a font if given + the argument --inspect 2013/05/20, luaotfload v2.2: * There is now a central, non-personal dev repo on github: -- cgit v1.2.3 From 1a42a842639df21d4738bb8ac12f146d829a9d17 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Wed, 3 Jul 2013 01:48:10 +0200 Subject: add option to redirect log output to file --- luaotfload-override.lua | 77 ++++++++++++++++++++++++++++++++++++++++++++----- luaotfload-tool.lua | 24 +++++++++++++-- luaotfload-tool.rst | 10 +++++-- 3 files changed, 100 insertions(+), 11 deletions(-) diff --git a/luaotfload-override.lua b/luaotfload-override.lua index 225ac68..39cc172 100644 --- a/luaotfload-override.lua +++ b/luaotfload-override.lua @@ -15,17 +15,23 @@ because we lack a user interface to toggle per-subsystem tracing. local module_name = "luaotfload" +local ioopen = io.open +local iowrite = io.write +local lfsisdir = lfs.isdir +local lfsisfile = lfs.isfile +local md5sumhexa = md5.sumhexa +local osdate = os.date +local ostime = os.time local select = select local stringformat = string.format +local stringsub = string.sub local tableconcat = table.concat +local texio_write_nl = texio.write_nl local texiowrite_nl = texio.write_nl +local texio_write = texio.write local texiowrite = texio.write local type = type -local texio_write_nl = texio.write_nl -local texio_write = texio.write -local iowrite = io.write - --[[doc-- We recreate the verbosity levels previously implemented in font-nms: @@ -62,9 +68,67 @@ logs.getloglevel = get_loglevel logs.get_loglevel = get_loglevel logs.get_log_level = get_loglevel -local set_logout = function (s) +local writeln --- scope so we can change it + +local log_msg = [[ +logging output redirected to %s +to monitor the progress run "tail -f %s" in another terminal +]] + +local tmppath = os.getenv "TMPDIR" or "/tmp" + +local choose_logfile = function ( ) + if lfsisdir (tmppath) then + local fname + repeat --- ensure that file of that name doesn’t exist + fname = tmppath .. "/luaotfload-log-" + .. stringsub (md5sumhexa (ostime ()), 1, 8) + until not lfsisfile (fname) + iowrite (stringformat (log_msg, fname, fname)) + return ioopen (fname, "w") + end + --- missing /tmp + return false +end + +local set_logout = function (s, finalizers) if s == "stdout" then logout = "term" + elseif s == "file" then --- inject custom logger + local chan = choose_logfile () + chan:write (stringformat ("logging initiated at %s", + osdate ("%F %T", ostime ()))) + local writefile = function (...) + if select ("#", ...) == 2 then + chan:write (select (2, ...)) + else + chan:write (select (1, ...)) + end + end + local writefile_nl= function (...) + chan:write "\n" + if select ("#", ...) == 2 then + chan:write (select (2, ...)) + else + chan:write (select (1, ...)) + end + end + + local writeln_orig = writeln + + texiowrite = writefile + texiowrite_nl = writefile_nl + writeln = writefile_nl + + finalizers[#finalizers+1] = function () + chan:write (stringformat ("\nlogging finished at %s\n", + osdate ("%F %T", ostime ()))) + chan:close () + texiowrite = texio.write + texiowrite_nl = texio.write_nl + writeln = writeln_orig + end + return finalizers --else --- remains “log” end end @@ -92,7 +156,6 @@ end io.stdout:setvbuf "no" io.stderr:setvbuf "no" -local writeln if tex and (tex.jobname or tex.formatname) then --- TeX writeln = texiowrite_nl @@ -155,7 +218,7 @@ local names_report = function (mode, lvl, ...) if loglevel >= lvl then if mode == "log" then log (...) - elseif mode == "both" then + elseif mode == "both" and log ~= "stdout" then log (...) stdout (...) else diff --git a/luaotfload-tool.lua b/luaotfload-tool.lua index 45a75ba..392be6e 100755 --- a/luaotfload-tool.lua +++ b/luaotfload-tool.lua @@ -902,6 +902,22 @@ actions.list = function (job) return true, true 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. mkluatexfontdb.lua relies on the script alt_getopt to process argv and @@ -985,7 +1001,7 @@ local process_cmdline = function ( ) -- unit -> jobspec elseif v == "log" then local str = optarg[n] if str then - logs.set_logout(str) + finalizers = logs.set_logout(str, finalizers) end elseif v == "find" then action_pending["query"] = true @@ -1065,7 +1081,11 @@ local main = function ( ) -- unit -> int if exit then break end end - texiowrite_nl"" + if finalize () == false then + retval = -1 + end + + --texiowrite_nl"" return retval end diff --git a/luaotfload-tool.rst b/luaotfload-tool.rst index 7b75367..31a1010 100644 --- a/luaotfload-tool.rst +++ b/luaotfload-tool.rst @@ -116,8 +116,14 @@ miscellaneous --verbose=N, -v Set verbosity level to *n* or the number of repetitions of ``-v``. --quiet No verbose output (log level set to zero). ---log=stdout Redirect log output to terminal (for database - troubleshooting). +--log=CHANNEL Redirect log output (for database + troubleshooting), where *CHANNEL* can be + + 1) ``stdout`` -> all output will be + dumped to the terminal; or + 2) ``file`` -> write to a file to the temporary + directory (the name will be chosen + automatically (**experimental!**). --version, -V Show version number and exit. --help, -h Show help message and exit. -- cgit v1.2.3 From 00fd07c628af41b0709d25fd00805385be561459 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Wed, 3 Jul 2013 11:04:52 +0200 Subject: add cache directory hint to luaotfload-tool; manage paths more consistently --- luaotfload-basics-gen.lua | 4 ++-- luaotfload-database.lua | 18 +++++++++--------- luaotfload-merged.lua | 4 ++-- luaotfload-tool.lua | 39 +++++++++++++++++++-------------------- 4 files changed, 32 insertions(+), 33 deletions(-) diff --git a/luaotfload-basics-gen.lua b/luaotfload-basics-gen.lua index 4a46fbb..a5da2fd 100644 --- a/luaotfload-basics-gen.lua +++ b/luaotfload-basics-gen.lua @@ -151,13 +151,13 @@ do -- quite like tex live or so - if cachepaths == "" then + if cachepaths == "$TEXMFCACHE" then cachepaths = kpse.expand_var('$TEXMFVAR') or "" end -- this also happened to be used - if cachepaths == "" then + if cachepaths == "$TEXMFVAR" then cachepaths = kpse.expand_var('$VARTEXMF') or "" end diff --git a/luaotfload-database.lua b/luaotfload-database.lua index 338ffa6..c0aadaf 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -97,7 +97,8 @@ names.data = nil --- contains the loaded database names.lookups = nil --- contains the lookup cache names.path = { dir = "", --- db and cache directory - basename = "luaotfload-names.lua", --- db file name + basename = config.luaotfload.names_file + or "luaotfload-names.lua", path = "", --- full path to db file lookup_basename = "luaotfload-lookup-cache.lua", --- cache file name lookup_path = "", --- cache full path @@ -108,7 +109,7 @@ names.path = { -- uses TEXMFCACHE or TEXMFVAR as starting points. local writable_path if caches then - writable_path = caches.getwritablepath("names","") + writable_path = caches.getwritablepath "names" if not writable_path then luaotfload.error("Impossible to find a suitable writeable cache...") end @@ -2047,21 +2048,20 @@ end local getwritablecachepath = function ( ) --- fonts.handlers.otf doesn’t exist outside a Luatex run, --- so we have to improvise - local writable = caches.getwritablepath () + local writable = caches.getwritablepath + (config.luaotfload.cache_dir) if writable then - writable = writable .. "/fonts" - if lfsisdir (writable) then - return writable - end + return writable end end local getreadablecachepaths = function ( ) - local readables = caches.getreadablepaths () + local readables = caches.getreadablepaths + (config.luaotfload.cache_dir) local result = { } if readables then for i=1, #readables do - local readable = readables[i] .. "/fonts" + local readable = readables[i] if lfsisdir (readable) then result[#result+1] = readable end diff --git a/luaotfload-merged.lua b/luaotfload-merged.lua index 9d708bf..52c199a 100644 --- a/luaotfload-merged.lua +++ b/luaotfload-merged.lua @@ -3044,10 +3044,10 @@ if not caches.namespace or caches.namespace=="" or caches.namespace=="context" t end do local cachepaths=kpse.expand_var('$TEXMFCACHE') or "" - if cachepaths=="" then + if cachepaths=="" or cachepaths == "$TEXMFCACHE" then cachepaths=kpse.expand_var('$TEXMFVAR') or "" end - if cachepaths=="" then + if cachepaths=="" or cachepaths == "$TEXMFVAR" then cachepaths=kpse.expand_var('$VARTEXMF') or "" end if cachepaths=="" then diff --git a/luaotfload-tool.lua b/luaotfload-tool.lua index 392be6e..a353b37 100755 --- a/luaotfload-tool.lua +++ b/luaotfload-tool.lua @@ -80,9 +80,13 @@ After support for querying the database was added, the latter appeared to be the more appropriate. --doc]]-- -config = config or { } -local config = config -config.luaotfload = config.luaotfload or { } +config = config or { } +local config = config +config.luaotfload = config.luaotfload or { } +config.luaotfload.names_dir = config.luaotfload.names_dir or "names" +config.luaotfload.cache_dir = config.luaotfload.cache_dir or "fonts" +config.luaotfload.names_file = config.luaotfload.names_file + or "luaotfload-names.lua" do -- we don’t have file.basename and the likes yet, so inline parser ftw local slash = P"/" @@ -109,19 +113,6 @@ 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_nl(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. @@ -144,8 +135,11 @@ local names = fonts.names local sanitize_string = names.sanitize_string -local db_src_out = names.path.dir.."/"..names.path.basename -local db_bin_out = file.replacesuffix(db_src_out, "luc") +--local db_src_out = names.path.dir.."/"..names.path.basename +local names_plain = file.join + (caches.getwritablepath (config.luaotfload.names_dir), + config.luaotfload.names_file) +local names_bin = file.replacesuffix (names_plain, "luc") local help_messages = { ["luaotfload-tool"] = [[ @@ -205,6 +199,9 @@ The font database will be saved to --cache= operate on font cache, where is “show”, “purge”, or “erase” +The font cache will be written to + %s + ]], mkluatexfontdb = [[ @@ -235,8 +232,10 @@ local help_msg = function ( ) or help_messages["luaotfload-tool"] texiowrite_nl(stringformat(template, config.luaotfload.self, - db_src_out, - db_bin_out)) + names_plain, + names_bin, + caches.getwritablepath + (config.luaotfload.cache_dir))) end local version_msg = function ( ) -- cgit v1.2.3 From 6a30d02676f81dfae238b4ac47463c5781c34576 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Wed, 3 Jul 2013 11:09:03 +0200 Subject: adapt luaotfload.lua to new dir system --- luaotfload.dtx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/luaotfload.dtx b/luaotfload.dtx index b66a88f..bccdc0c 100644 --- a/luaotfload.dtx +++ b/luaotfload.dtx @@ -1460,8 +1460,8 @@ and the derived files %<*lua> % \fi % \begin{macrocode} -luaotfload = luaotfload or {} -local luaotfload = luaotfload +luaotfload = luaotfload or {} +local luaotfload = luaotfload config = config or { } config.luaotfload = config.luaotfload or { } @@ -1472,7 +1472,9 @@ config.luaotfload.compatibility = config.luaotfload.compatibility or false config.luaotfload.loglevel = config.luaotfload.loglevel or 1 config.luaotfload.color_callback = config.luaotfload.color_callback or "pre_linebreak_filter" config.luaotfload.prioritize = config.luaotfload.prioritize or "sys" ---luaotfload.prefer_merge = config.luaotfload.prefer_merge or true +config.luaotfload.names_dir = config.luaotfload.names_dir or "names" +config.luaotfload.cache_dir = config.luaotfload.cache_dir or "fonts" +config.luaotfload.names_file = config.luaotfload.names_file or "luaotfload-names.lua" luaotfload.module = { name = "luaotfload", -- cgit v1.2.3 From 4adcf7591ed8104b0b846d500a5d30d4ff32512e Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Wed, 3 Jul 2013 18:24:50 +0200 Subject: bump version --- NEWS | 2 +- luaotfload.dtx | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/NEWS b/NEWS index f9f3b3d..8615d90 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,7 @@ Change History -------------- -2013/xx/xx, luaotfload v2.3: +2013/07/03, luaotfload v2.3: * New experimental lookups: ``kpse`` (kpathsea), ``my`` (callback) * Precedence of texmf over system fonts can be requested using the ``--prefer-texmf`` option of luaotfload-tool diff --git a/luaotfload.dtx b/luaotfload.dtx index bccdc0c..b8bee75 100644 --- a/luaotfload.dtx +++ b/luaotfload.dtx @@ -40,7 +40,7 @@ \input docstrip.tex \Msg{************************************************************************} \Msg{* Installation} -\Msg{* Package: luaotfload v2.2 OpenType layout system} +\Msg{* Package: luaotfload v2.3 OpenType layout system} \Msg{************************************************************************} \keepsilent @@ -111,7 +111,7 @@ and the derived files %<*driver> \NeedsTeXFormat{LaTeX2e} \ProvidesFile{luaotfload.drv}% - [2013/05/23 v2.2d OpenType layout system]% + [2013/05/23 v2.3d OpenType layout system]% \documentclass{ltxdoc} \usepackage{metalogo,multicol,mdwlist,fancyvrb,xspace} \usepackage[x11names]{xcolor} @@ -231,7 +231,7 @@ and the derived files % \GetFileInfo{luaotfload.drv} % % \title{The \identifier{luaotfload} package} -% \date{2013/05/23 v2.2d} +% \date{2013/05/23 v2.3d} % \author{Elie Roux · Khaled Hosny · Philipp Gesang\\ % Home: \url{https://github.com/lualatex/luaotfload}\\ % Support: \email{lualatex-dev@tug.org}} @@ -2069,7 +2069,7 @@ loadmodule"auxiliary.lua" --- additionaly high-level functionality (new) \else \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{luaotfload}% - [2013/05/23 v2.2d OpenType layout system] + [2013/05/23 v2.3d OpenType layout system] \RequirePackage{luatexbase} \fi \ifnum\luatexversion<76 -- cgit v1.2.3