Skip to content

Instantly share code, notes, and snippets.

@zr-tex8r
Last active October 21, 2018 15:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zr-tex8r/d7d0788d5e2c0f987c978e25f484ba8e to your computer and use it in GitHub Desktop.
Save zr-tex8r/d7d0788d5e2c0f987c978e25f484ba8e to your computer and use it in GitHub Desktop.
Lua: SATySFi用のupdmapみたいなやつ(未完成)
# stupdmap.cfg
# To be placed in ~/.satysfi/dist/stupdmap
Nishiki-teki = C:/windows/fonts/nishiki-teki.ttf
--
-- This is file 'stupdmap.lua'.
--
-- Copyright (c) 2018 Takayuki YATO (aka. "ZR")
-- GitHub: https://github.com/zr-tex8r
-- Twitter: @zr_tex8r
--
-- This package is distributed under the MIT License.
--
prog_name = "stupdmap"
version = "0.1.5"
mod_date = "2018-07-16"
---------------------------------------- global parameters
verbose = 0
dry_run = false
locate = true
symlink = false
cfg_file = nil
hash_dir = 'dist/hash'
fonts_dir = 'dist/fonts'
stupdmap_dir = 'dist/stupdmap'
default_cfg_file = 'stupdmap.cfg'
---------------------------------------- helpers
lfs = require "lfs"
do
unpack = unpack or table.unpack
insert = table.insert
is_file = lfs.isfile or function (path)
return (lfs.attributes(path, 'mode') == 'file')
end
is_dir = lfs.isdir or function (path)
return (lfs.attributes(path, 'mode') == 'directory')
end
is_win = (function()
local o = os.type or (jit and jit.os) or (ffi and ffi.os)
if o then return (o:lower() == 'windows') end
o = (os.getenv('OS') or ''):lower()
return (o:match('^windows') ~= nil)
end)()
function is_abspath(pname)
if is_win then
return (pname:match("^%w:") ~= nil or pname:match("^[/\\]") ~= nil)
else return (pname:match("^/") ~= nil)
end
end
function unxpath(pname)
pname = tostring(pname)
return (is_win) and pname:gsub('\\', '/') or pname
end
function natpath(pname)
pname = tostring(pname)
return (is_win) and pname:gsub('/', '\\') or pname
end
function mkpath(...)
return concat({...}, '/')
end
function mkdir(bpath, path)
if dry_run then return end
for p in path:gmatch('[^/]+') do
bpath = mkpath(bpath, p)
if not (is_dir(bpath) or lfs.mkdir(bpath)) then
abort('cannot make directory', bpath)
end
end
end
function read_whole(path)
local h = sure(io.open(path, 'rb'), "cannot open for input", path)
local d = sure(h:read('*a'), "cannot read from file", path)
h:close()
return d
end
function write_whole(path, data)
local d = tostring(data or "")
log(1, "write "..tostring(#d).." bytes to", path)
if dry_run then return end
local h = sure(io.open(path, 'wb'), "cannot open for output", path)
sure(h:write(d or ""), "cannot write to file", path)
h:close()
end
function str(val)
return (type(val) == 'table') and '{'..concat(val, ',')..'}'
or tostring(val)
end
function concat(tbl, ...)
local t = {}
for i = 1, #tbl do t[i] = str(tbl[i]) end
return table.concat(t, ...)
end
function append(tbl1, tbl2)
local t = { unpack(tbl1) }
for _, v in ipairs(tbl2) do table.insert(t, v) end
return t
end
end
---------------------------------------- search path
do
user_root = (function()
local p = (is_win) and unxpath(os.getenv('USERPROFILE') or '')
or (os.getenv('HOME') or '')
return (p == '') and {} or { p..'/.satysfi' }
end)()
sys_root = (function()
if is_win then
local p = unxpath(os.getenv('SATYSFI_RUNTIME') or '')
return (p == '') and {} or { p }
else
return { '/usr/local/share/satysfi', '/usr/share/satysfi' }
end
end)()
all_root = append(user_root, sys_root)
function find_file(path, root)
if is_abspath(path) then
log(2, "find_file", "is an absolute path", path)
return nil
end
log(2, "find_file", path)
for _, r in ipairs(root) do
local p = mkpath(r, path)
log(2, 'find_file', 'search path', p)
if is_file(p) then
log(1, 'find_file', 'found', p)
return p
end
end
end
end
---------------------------------------- config file
do
function get_cfg_path()
if cfg_file and is_file(cfg_file) then
log(1, "cfg file found", cfg_file)
return cfg_file
end
local fcfg = mkpath(stupdmap_dir, cfg_file or default_cfg_file)
log(1, "search path for cfg file", fcfg)
return sure(find_file(fcfg, user_root),
"file not found on search path", fcfg)
end
function read_cfg_file(pcfg)
log(1, "read cfg file", pcfg)
local hcfg = sure(io.open(pcfg, 'rb'),
"cannot read from file", pcfg)
local cfg, lno = {}, 0
while true do
local line = hcfg:read('*l')
if not line then break end
lno = lno + 1; local msglno = "line "..tostring(lno)
line = line:gsub('^%s+', ''):gsub('%s+$', ''):gsub('%s', ' ')
if not (line == '' or line:match('^[%%%#]')) then
sure(not (line:find('\0', 1, true) or line:find('[\1-\31]')),
"bad character in cfg file", msglno)
local key, val = line:match("^([^ \"\'=]+) *= *(.+)")
sure(key, "error in cfg file", msglno, line)
log(2, msglno, key, val)
insert(cfg, {name=key, path=val})
end
end
log(1, "total "..tostring(#cfg).." entires", pcfg)
return cfg
end
function resolve_location(cfg)
log(1, "resolve font location")
for _, e in ipairs(cfg) do
local dn, fn = e.path:match('(.*)/(.*)')
if dn then e.dir, e.file = dn, fn
else e.dir, e.file = '.', e.path
end
log(1, "resolve", "dir="..e.dir, "file="..e.file)
end
end
end
---------------------------------------- hash
do
local function str_step(str, pos, rep, ...)
local chunk, rxlst = {}, {...}
pos, rep = pos or 1, rep or -1
while rep ~= 0 do
local ps, pe
for k, rx in ipairs(rxlst) do
ps, pe = str:find('^'..rx, pos)
if ps then break end
end
if not ps then break end
insert(chunk, str:sub(ps, pe))
log(2, 'str_step', ps, pe)
pos, rep = pe + 1, rep - 1
end
return pos, chunk
end
local function array_insert(hash, chunk)
local p, c = str_step(hash, 1, nil, '%s+', '//.-\n', '/*.-*/')
p, c = str_step(hash, p, 1, '{')
if #c ~= 1 then return end
p, c = str_step(hash, p, 1, '[^%S\n]+')
return hash:sub(1, p - 1)..'\n'..chunk..
hash:sub(p + ((hash:sub(p, p) == '\n') and 1 or 0))
end
local function new_hash_entries(cfg)
local chunk = {}
insert(chunk, '//------ stupdmap BEGIN\n')
local fmt = ' "%s": <Single: {"src-dist": "%s"}>,\n'
for _, e in ipairs(cfg) do
insert(chunk, fmt:format(e.name, e.file))
end
insert(chunk, '//------ stupdmap END\n')
return concat(chunk)
end
function compose_hash(cfg)
local fhash = mkpath(hash_dir, 'fonts.satysfi-hash')
local phash = sure(find_file(fhash, sys_root),
"system hash file is not found", fhash)
local hash = read_whole(phash)
hash = sure(array_insert(hash, new_hash_entries(cfg)),
"bad hash data")
log(3, "composed hash data", "========\n"..hash.."========")
mkdir(user_root[1], hash_dir)
write_whole(mkpath(user_root[1], fhash), hash)
end
end
---------------------------------------- logging
do
function log(level, ...)
if verbose < level then return end
io.stderr:write(concat({prog_name, ...}, ": ").."\n")
end
function info(...) log(0, ...) end
function warn(...) log(-1, "warning", ...) end
function abort(...) log(-2, ...); os.exit(1) end
function sure(val, a1, ...)
if val then return val end
abort((type(a1) == "number") and ("ERROR("..a1..")") or a1, ...)
end
end
---------------------------------------- main
do
local function show_usage()
io.stdout:write(([[
This is %s, version %s <%s>
Usage: %s[.lua] [OPTION...] [CONF_FILE]
When CONF_FILE is omitted, then '%s' in the user library
root is assumed.
Options:
-h --help show this help
-V --version show the version
-q --quiet show less information
-v --verbose show more information
-d --dry-run dry run
-L --no-locate do not locate font files
-s --symlink use symbolic links to locate font files
]]):format(prog_name, version, mod_date, prog_name, default_cfg_file))
os.exit(0)
end
local function show_version()
io.stdout:write(([[
%s version %s
]]):format(prog_name, version))
os.exit(0)
end
local function read_option()
local idx = 1
while idx <= #arg do
if arg[idx]:sub(1, 1) ~= '-' then break end
local opt = arg[idx]; idx = idx + 1
if opt == '-h' or opt == '--help' then
show_usage()
elseif opt == '-V' or opt == '--version' then
show_version()
elseif opt == '-q' or opt == '--quiet' then
verbose = -1
elseif opt == '--verbose' then
verbose = 1
elseif opt:match("^-v+$") then
verbose = #opt - 1
elseif opt == '-d' or opt == '--dry-run' then
dry_run = true
elseif opt == '-L' or opt == '--no-locate' then
locate = false
elseif opt == '-s' or opt == '--symlink' then
if is_win then
warn("'-s' is not supported on Windows")
else
symlink = true
end
else abort("unknown option", opt)
end
end
cfg_file = arg[idx]
end
function main()
read_option()
log(1, 'is_win', is_win)
sure(user_root[1], 'user library root is unknown')
sure(is_dir(user_root[1]),
'user library root does not exist', user_root[1])
local cfg_path = get_cfg_path()
local cfg_data = read_cfg_file(cfg_path)
resolve_location(cfg_data)
compose_hash(cfg_data)
end
end
---------------------------------------- done
main()
-- EOF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment