From aa588d1815253d034c8a4d2c35b4b9225d8af080 Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Fri, 3 Dec 2021 03:01:05 +0000 Subject: CTAN sync 202112030301 --- support/luafindfont/scripts/luafindfont.lua | 461 ++++++++++++++++++++++++++++ 1 file changed, 461 insertions(+) create mode 100755 support/luafindfont/scripts/luafindfont.lua (limited to 'support/luafindfont/scripts/luafindfont.lua') diff --git a/support/luafindfont/scripts/luafindfont.lua b/support/luafindfont/scripts/luafindfont.lua new file mode 100755 index 0000000000..cad6ee4044 --- /dev/null +++ b/support/luafindfont/scripts/luafindfont.lua @@ -0,0 +1,461 @@ +#!/usr/bin/env texlua +-- % $Id: luafindfont.lua 330 2021-11-28 13:47:56Z herbert $ + +----------------------------------------------------------------------- +-- FILE: luafindfont.lua +-- DESCRIPTION: search for fonts in the database +-- REQUIREMENTS: luatex v.0.80 or later; packages lualibs, xindex-lapp +-- AUTHOR: Herbert Voß (C) 2021-11-27 +----------------------------------------------------------------------- + luafindfont = luafindfont or { } + local version = 0.04 +luafindfont.version = version + +--[[ +Search the font database for fontnames. The database is used +by Lua(La)TeX and created by default with the first run of +Lua(La)TeX. If there is no such data file then "luafindfont" +will execute the command to create it. + +luafindfont(1) + +%% This file may be distributed and/or modified under the +%% conditions of the LaTeX Project Public License, either version 1.3c +%% of this license or (at your option) any later version. +%% The latest version of this license is in +%% http://www.latex-project.org/lppl.txt +%% and version 1.3c or later is part of all distributions of LaTeX +%% version 2005/12/01 or later. + +Report bugs to hvoss@tug.org + +]] + +kpse.set_program_name("luatex") +local f = kpse.find_file("lualibs.lua") + +require("lualibs") -- all part of LuaTeX +--require("luafindfont-utflib") + +if #arg == 0 then + print("I need at least one argument or option! Will exit ...") + os.exit() +end + +local args_verbose = 0 +local args_nosymbolixnames = 0 +local args_otfinfo = 0 +local args_info = 0 +local args_max_string = 90 + +local i = 1 +while i <= #arg do + if arg[i] == "-h" or arg[i] == "--help" then + print("Version "..version..", Copyright 2021 by Herbert Voß") + print([[Syntax: luafintfont [options] + By default the Lua program 'luafindfont' creates a list of the + fonts which have in its names the given string. + + parameter handling + -h,--help + -n,--nosymbolicnames + -o,--otfinfo (default 0) + -i,--info (default 0) + -v, --verbose + -m,--max_string (default 90) + (string) ]]) + elseif arg[i] == "-v" or arg[i] == "--verbose" then + args_verbose = 1 + elseif arg[i] == "-n" or arg[i] == "--nosymbolicnames" then + args_nosymbolicnames = 1 + elseif arg[i] == "-o" or arg[i] == "--otfinfo" then + local fontNr = tonumber(arg[i+1]) + if fontNr then + args_otfinfo = fontNr + i = i + 1 + else + print("Option -o needs a following fontnumber!") + args_otfinfo = 0 + end + elseif arg[i] == "-i" or arg[i] == "--info" then + local fontNr = tonumber(arg[i+1]) + if fontNr then + args_info = fontNr + i = i + 1 + else + print("Option -i needs a following fontnumber!") + args_info = 0 + end + elseif arg[i] == "-m" or arg[i] == "--max_string" then + local string_len = tonumber(arg[i+1]) + if string_len then + args_max_string = string_len + i = i + 1 + else + print("Option -m needs a following fontnumber!") + args_max_string = 90 + end + else + args_font = arg[i] + end + i = i + 1 +end + +if not args_font then + print("No fontname given, will close ...") + os.exit() +end + +local vlevel = args_verbose +local otfinfo = args_otfinfo +local info = args_info +local noSymbolicNames = args_nosymbolicnames +local maxStrLength = args_max_string +local font_str = args_font + +local luaVersion = _VERSION +print("We are using "..luaVersion) +print('Looking for font \"'..font_str..'\"') + +function getFileParts(fullpath,part) + local path, file, ext = string.match(fullpath, "(.-)([^/]-([^%.]+))$") + if part == "path" then return path + elseif part == "ext" then return ext + else return file end +end + +function getFileLocation() + local cachepaths = kpse.expand_var('$TEXMFCACHE') or "" + if cachepaths == "" or cachepaths == "$TEXMFCACHE" then + cachepaths = kpse.expand_var('$TEXMFVAR') or "" + end + if vlevel > 0 then print("cachepaths: ",cachepaths) end + if cachepaths == "" then + print("umghhh ....") + print("No cache path found ... ") + return "" + end + if os.type == "windows" then + paths = string.split(cachepaths,";") + else + paths = string.split(cachepaths,":") + end + if vlevel > 0 then print ("Pathes: ", paths[1], paths[2]) end + local file = paths[1].."/luatex-cache/generic/names" + if vlevel > 0 then print("try: ",file) end + local f,err = io.open (file.."/test.tmp", "w") + if not f and #paths > 1 then + if vlevel > 0 then print("first path has no file, I'll try the second one ...") end + file = paths[2].."/luatex-cache/generic/names" + if vlevel > 0 then print("try: ",file) end + f,err = io.open (file.."/test.tmp", "w") + if not f then + print("Error getting file location: \n",err) + return "" + else + f:close() + end + else + f:close() + end +-- print("File: "..fontListFile) + return file +end + +function readBinaryOrZippedFile(file) + print("Check for file "..file) + local f,err = io.open (file..".luc", "rb") + if not f then + if vlevel > 0 then print("There is no binary data file ... ") end + f,err = io.open (file..".lua.gz", "r") + if not f then + if vlevel > 0 then print("There is no gzipped data file ... ") end + f,err = io.open (file..".lua", "r") + if not f then + if vlevel > 0 then print("There is no data file ... ") end + print("Error reading file: ",err) + return nil + else + if vlevel > 0 then print("Found a normal data file ... ") end + local str = dofile(f) + f:close() + return str + end + else + if vlevel > 0 then print("Found a gzipped data file ... ") end + local str = f:read("*all") + local str2 = loadstring(gzip.decompress(str)) + str = str2() + f:close() + return str + end + else + if vlevel > 0 then print("Found a binary data file ... ") end + local chunk = f:read"*all" + f:close() + local func = load (chunk, "b") + str = func() + return str + end +end + +function compareEntries(f1, f2) + if (f1["basename"] == f2["basename"]) and + (f1["familyname"] == f2["familyname"]) and + (f1["fullpath"] == f2["fullpath"]) then + return true + else + return false + end +end + + +local fontData = {} +local fontListFile = getFileLocation() +if fontListFile == "" then + print("There is no cached font file list!") + print('Will run at first "luaotfload-tool --update --force" ... Wait a minute, please ...') + local exrun = io.popen('luaotfload-tool --update --force', 'r') + local output = exrun:read('*all') + print(output) + exrun:close() + fontListFile = getFileLocation() +end + +fontListFile = fontListFile.."/luaotfload-names" +fontData = readBinaryOrZippedFile(fontListFile) + +if not fontData then + print("umghhh ....") + print("It does not work! I'll give it up ... :-(") + os.exit() +end + +--print(require 'xindex-pretty'.dump(fontData)) --["families"]["system"]["otf"])) + +fontDataMap = fontData["mappings"] +fontFilesTable = fontData["files"]["full"] + +--print(require 'xindex-pretty'.dump(fontFilesTable)) --["families"]["system"]["otf"])) +--print(require 'xindex-pretty'.dump(fontFilesTable["bare"]["system"]["otf"])) --["families"]["system"]["otf"])) + +--[[ +print("Dateiliste für System->OTF") +for i, v in ipairs(fontFilesTable) do + print(i,v) +end +]] + +table.sort(fontDataMap, + function(a,b) + if not a["basename"] or not b["basename"] then + return false + else + return string.lower(a["basename"]) < string.lower(b["basename"]) + end end) +-- strip duplicates +local newFontDataMap = {} +if #fontDataMap > 0 then + newFontDataMap[1] = fontDataMap[1] +end +for i = 2,#fontDataMap do + if not compareEntries(fontDataMap[i],newFontDataMap[#newFontDataMap]) then + newFontDataMap[#newFontDataMap+1] = fontDataMap[i] + end +end + +fontDataMap = newFontDataMap +--for i, v in ipairs(fontDataMap) do +-- print(i, v["basename"],v["familyname"], v["fullpath"]) +-- end + +local j = 1 +local fontList = {} +local l_max = {1, 1, 1} +for i, v in ipairs(fontDataMap) do + if v["familyname"] then + if string.find (v["familyname"], font_str, 1, true) or (font_str == "*") then +-- print(string.format("%2d. %30s %20s %50s",j,v["basename"],v["familyname"],v["fullpath"])) + fontList[#fontList+1] = v + local fullpath = getFileParts(v["fullpath"],"path") -- strip file name + local basename = v["basename"] +-- local basename = string.fromutf8(v["basename"]) + if string.len(basename) > l_max[1] then l_max[1] = string.len(basename) end + if string.len(v["familyname"]) > l_max[2] then l_max[2] = string.len(v["familyname"]) end + if string.len(fullpath) > l_max[3] then l_max[3] = string.len(fullpath) end + j = j + 1 + end + end +end + +-- print(l_max[1],l_max[2],l_max[3]) +if l_max[3] > maxStrLength then l_max[3] = maxStrLength end + +local minChars = 26 +local Fontname = "Fontname" +local Path = "Path" +local SymbolicName = "Symbolic Name" +local lfdNr = "Nr." +if (font_str ~= "*") and not noSymbolicNames then + print(string.format("%4s %"..l_max[1].."s %"..l_max[2].."s %"..l_max[3].."s",lfdNr,Fontname,SymbolicName,Path)) + else + print(string.format("%4s %"..l_max[1].."s %"..l_max[3].."s",lfdNr,Fontname,Path)) +end + +for i, v in ipairs(fontList) do + local path = getFileParts(v["fullpath"],"path") + if string.len(path) > l_max[3] then + path = string.sub (path, 1, minChars).."..."..string.sub (path, string.len(path)-maxStrLength+minChars+4) + end + if (font_str ~= "*") and not noSymbolicNames then + print(string.format("%4d. %"..l_max[1].."s %"..l_max[2].."s %"..l_max[3].."s",i,v["basename"],v["familyname"],path)) + else + print(string.format("%4d. %"..l_max[1].."s %"..l_max[3].."s",i,v["basename"],path)) + end +end + +if otfinfo > 0 then + print() + print("Run otfinfo:"..otfinfo) + local font = fontList[otfinfo]["fullpath"] + local exrun = io.popen("otfinfo -i \""..font.."\"", 'r') -- ".." font may have spaces + local output = exrun:read('*all') + print(output) + exrun:close() +end + +if info > 0 then + font = fontList[info]["familyname"] + print("\nFont: "..font) + local font_dir = {"local","system","texmf"} + local font_ext = {"ttf","otf","ttc"} + for j = 1,#font_dir do + for i = 1,#font_ext do + local fonttype = "" + local ext = font_ext[i] + local dir = font_dir[j] + if fontData["families"][dir][ext] then -- font extension exists? + local entry = fontData["families"][dir][ext][font] + if entry then + if entry["r"] then fonttype = fonttype.."Regular " end + if entry["b"] then fonttype = fonttype.."| Bold " end + if entry["i"] then fonttype = fonttype.."| Italic " end + if entry["bi"] then fonttype = fonttype.."| BoldItalic" end + io.write("Fonttype "..ext.."("..dir..") --> ") + if #fonttype > 0 then + print("| "..fonttype.." |") + else + print(" undefined ") --- no regular definiert + end + else + print() + end + end + end + end +end +--print(require 'xindex-pretty'.dump(fontData["families"]["system"]["otf"])) --["families"]["system"]["otf"])) + + +--[[ + + ["families"]={ + ["local"]={}, + ["system"]={ + ["otf"]={ + ["adobecaslonpro"]={ + ["b"]={ + ["default"]=3143, + }, + ["bi"]={ + ["default"]=3146, + }, + ["i"]={ + ["default"]=3145, + }, + ["r"]={ + ["default"]=3147, + }, + }, + }, + }, + }, + +]] + +--[[ +This is a sketch of the luaotfload db: + + type dbobj = { + families : familytable; + fontnames : fontnametable; + files : filemap; + status : filestatus; + mappings : fontentry list; + meta : metadata; + } + and familytable = { + local : (format, familyentry) hash; // specified with include dir + texmf : (format, familyentry) hash; + system : (format, familyentry) hash; + } + and familyentry = { + r : sizes; // regular + i : sizes; // italic + b : sizes; // bold + bi : sizes; // bold italic + } + and sizes = { + default : int; // points into mappings or names + optical : (int, int) list; // design size -> index entry + } + and fontnametable = { + local : (format, index) hash; + texmf : (format, index) hash; + system : (format, index) hash; + } + and metadata = { + created : string // creation time + formats : string list; // { "otf", "ttf", "ttc" } + local : bool; (* set if local fonts were added to the db *) + modified : string // modification time + statistics : TODO; // created when built with "--stats" + version : float; // index version + } + and filemap = { // created by generate_filedata() + base : { + local : (string, int) hash; // basename -> idx + system : (string, int) hash; + texmf : (string, int) hash; + }; + bare : { + local : (string, (string, int) hash) hash; // location -> (barename -> idx) + system : (string, (string, int) hash) hash; + texmf : (string, (string, int) hash) hash; + }; + full : (int, string) hash; // idx -> full path + } + and fontentry = { // finalized by collect_families() + basename : string; // file name without path "foo.otf" + conflicts : { barename : int; basename : int }; // filename conflict with font at index; happens with subfonts + familyname : string; // sanitized name of the font family the font belongs to, usually from the names table + fontname : string; // sanitized name of the font + format : string; // "otf" | "ttf" | "afm" (* | "pfb" *) + fullname : string; // sanitized full name of the font including style modifiers + fullpath : string; // path to font in filesystem + index : int; // index in the mappings table + italicangle : float; // italic angle; non-zero with oblique faces + location : string; // "texmf" | "system" | "local" + plainname : string; // unsanitized font name + typographicsubfamily : string; // sanitized preferred subfamily (names table 14) + psname : string; // PostScript name + size : (false | float * float * float); // if available, size info from the size table converted from decipoints + subfamily : string; // sanitized subfamily (names table 2) + subfont : (int | bool); // integer if font is part of a TrueType collection ("ttc") + version : string; // font version string + weight : int; // usWeightClass + } + and filestatus = (string, // fullname + { index : int list; // pointer into mappings + timestamp : int; }) dict +]] -- cgit v1.2.3