-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathluaotfload-tool.lua
More file actions
1647 lines (1429 loc) · 51 KB
/
luaotfload-tool.lua
File metadata and controls
1647 lines (1429 loc) · 51 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/env texlua
-----------------------------------------------------------------------
-- FILE: luaotfload-tool.lua
-- DESCRIPTION: database functionality
-- REQUIREMENTS: matching luaotfload
-- AUTHOR: Khaled Hosny, Élie Roux, Philipp Gesang
-- LICENSE: GPL v2.0
-----------------------------------------------------------------------
local ProvidesLuaModule = {
name = "luaotfload-tool",
version = "3.15", --TAGVERSION
date = "2020-09-02", --TAGDATE
description = "luaotfload-tool / database functionality",
license = "GPL v2.0"
}
if luatexbase and luatexbase.provides_module then
luatexbase.provides_module (ProvidesLuaModule)
end
luaotfload = luaotfload or { }
local version = ProvidesLuaModule.version
luaotfload.version = ProvidesLuaModule.version
luaotfload.self = "luaotfload-tool"
luaotfload.fontloader = _G -- We don't isolate the fontloader here
--[[doc--
luaotfload-tool(1)
This file was originally written (as \fileent{mkluatexfontdb.lua}) by
Elie Roux and Khaled Hosny and, as a derived work of ConTeXt, is
provided under the terms of the GPL v2.0 license as printed in full
text in the manual (luaotfload.pdf).
\url{http://www.gnu.org/licenses/old-licenses/gpl-2.0.html}.
This file is a wrapper for the luaotfload font names module
(luaotfload-database.lua). It is part of the luaotfload bundle, please
see the luaotfload documentation for more info. Report bugs to
\url{https://github.com/latex3/luaotfload/issues}.
--doc]]--
kpse.set_program_name "luatex"
local iowrite = io.write
local kpsefind_file = kpse.find_file
local mathfloor = math.floor
local next = next
local osdate = os.date
local ostype = os.type
local stringexplode = string.explode
local stringformat = string.format
local stringlower = string.lower
local stringrep = string.rep
local tableconcat = table.concat
local texiowrite_nl = texio.write_nl
local texiowrite = texio.write
local tonumber = tonumber
local type = type
do
local runtime = _G.jit and { "jit" , jit.version }
or { "stock", _VERSION }
local minimum = {110, 0}
local revn = tonumber (status.luatex_revision) or 0 --[[ : string ]]
if status.luatex_version < minimum[1]
or status.luatex_version == minimum[1] and status.luatex_revision < minimum[2] then
texio.write_nl ("term and log",
string.format ("\tFATAL ERROR\n\z
\tLuaotfload requires a Luatex version >= %d.%d.%d.\n\z
\tPlease update your TeX distribution!\n\n",
math.floor(minimum[1] / 100), minimum[1] % 100, minimum[2]))
error "version check failed"
end
luaotfload.runtime = runtime
end
local C, Ct, P, S = lpeg.C, lpeg.Ct, lpeg.P, lpeg.S
local lpegmatch = lpeg.match
string.quoted = string.quoted or function (str)
return string.format("%q",str)
end
--[[doc--
XXX:
Creating the config table will be moved to the common
initialization when the times comes.
--doc]]--
config = config or { }
local config = config
config.luaotfload = config.luaotfload or { }
config.lualibs = config.lualibs or { }
config.lualibs.verbose = false
config.lualibs.prefer_merged = true
config.lualibs.load_extended = true
require "lualibs"
local iosavedata = io.savedata
local lfsisdir = lfs.isdir
local lfsisfile = lfs.isfile
local stringsplit = string.split
local tablekeys = table.keys
local tableserialize = table.serialize
local tablesortedkeys = table.sortedkeys
local tabletohash = table.tohash
--[[doc--
\fileent{luatex-basics-gen.lua} calls functions from the
\luafunction{texio.*} library; too much for our taste.
We intercept them with dummies.
Also, it sets up dummies in place of the tables created by the Context
libraries. Since we have loaded the lualibs already this would cause
collateral damage for some libraries whose namespace would be
overridden. We employ our usual backup-restore strategy to work around
this. (Postponing the loading of the lualibs code is not an option
because the functionality is needed by basics-gen itself.)
--doc]]--
local function dummy_function ( ) end
local backup = {
write = texio.write,
write_nl = texio.write_nl,
utilities = utilities,
}
texio.write, texio.write_nl = dummy_function, dummy_function
require "fontloader-basics-gen.lua"
texio.write, texio.write_nl = backup.write, backup.write_nl
utilities = backup.utilities
pdf = pdf or { } --- for fonts-tfm
require "fontloader-data-con"
require "fontloader-font-ini"
require "fontloader-font-con"
require "fontloader-fonts-enc"
require "fontloader-font-cid"
require "fontloader-font-map"
require "fontloader-font-oti"
require "fontloader-font-otr"
require "fontloader-font-ott"
require "fontloader-font-cff"
require "fontloader-font-ttf"
require "fontloader-font-dsp"
require "fontloader-font-oup"
require "fontloader-font-onr"
require "fontloader-font-def"
fonts = fonts or { }
local fontsnames = fonts.names or { }
fonts.names = fontsnames
local require_init = { }
local function loadmodule (name)
local v = require ("luaotfload-" .. name)
if v then
local mod = { }
local tv = type (v)
if tv == "table" then
mod.name = name
mod.init = v.init
require_init [#require_init + 1] = mod
elseif tv == "function" then
mod.name = name
mod.init = v
require_init [#require_init + 1] = mod
end
end
end
require "alt_getopt"
loadmodule "log" --- this populates the luaotfload.log.* namespace
loadmodule "parsers" --- fonts.conf, configuration, and request syntax
loadmodule "configuration" --- configuration file handling
loadmodule "database"
loadmodule "resolvers" --- Font lookup
local logreport
local function init_modules ()
--- NB we don’t command the logger at this point.
local todo = #require_init
local ret = true
for i = 1, todo do
local mod = require_init[i]
local name = mod.name
local init = mod.init
if type (init) ~= "function" then
error ("luaotfload broken; module "
.. name .. " missing initializers!")
end
local v = mod.init ()
if v == true then
--- evaluated well
elseif type (v) == "table" then
luaotfload[name] = v
else
error ("luaotfload broken; initialization of module "
.. name .. " returned " .. tostring (v) .. ".")
return false
end
end
logreport = luaotfload.log.report
return ret
end
local help_messages = {
["luaotfload-tool"] = [[
Usage: %s [OPTIONS...]
Luaotfload font management and diagnostic utility.
This program is part of the Luaotfload package.
Valid options are:
-------------------------------------------------------------------------------
VERBOSITY AND DIAGNOSTICS
-q --quiet don't output anything
-v --verbose=LEVEL be more verbose (print the searched directories)
-v, -vv .. -vvvvvvvvv set loglevel in unary
--log=stdout redirect log output to stdout
-V --version print version and exit
-h --help print this message
--diagnose=CHECK run a self test procedure; one of "files",
"environment", "index", "permissions", or
"repository"
-------------------------------------------------------------------------------
DATABASE
-u --update update the database
-n --no-reload suppress db update
--no-strip keep redundant information in db
-f --force force re-indexing all fonts
-L --local scan font files in $PWD
-c --no-compress do not gzip index file (text version only)
-l --flush-lookups empty lookup cache of font requests
-D --dry-run skip loading of fonts, just scan
--formats=[+|-]EXTENSIONS set, add, or subtract file formats
-p --prefer-texmf prefer fonts in the TEXMF over system fonts
--max-fonts=N process at most N font files
--find="font name" query the database for a font name
-F --fuzzy look for approximate matches if --find fails
--limit=n limit display of fuzzy matches to <n>
(default: n = 1)
-i --info display basic font metadata
-I --inspect display detailed font metadata
--list=<criterion> output list of entries by field <criterion>
--list=<criterion>:<value> restrict to entries with <criterion>=<value>
--fields=<f1>,<f2>,…,<fn> which fields <f> to print with --list
-b --show-blacklist show blacklisted files
--bisect=<directive> control database bisection: valid
directives are "start", "stop", "run", "status",
"good", "bad"
The font database will be saved to
%s
%s
-------------------------------------------------------------------------------
FONT CACHE
--cache=<directive> operate on font cache, where <directive> is
"show", "purge", or "erase"
The font cache will be written to
%s
]],
mkluatexfontdb = [[
FATAL ERROR
As of Luaotfload v2.5, legacy behavior is not supported anymore. Please
update your scripts and/or habits! Kthxbye.
]],
short = [[
Usage: luaotfload-tool [--help] [--version] [--verbose=<lvl>]
[--update] [--force] [--prefer-texmf] [--local]
[--dry-run] [--formats=<extension list>]
[--find=<font name>] [--fuzzy] [--info] [--inspect]
[--list=<criterion>] [--fields=<field list>]
[--cache=<directive>] [--flush-lookups]
[--show-blacklist] [--diagnose=<procedure>]
[--no-compress] [--no-strip] [--local]
[--max-fonts=<n>] [--bisect=<directive>]
Enter 'luaotfload-tool --help' for a larger list of options.
]]
}
local function help_msg (version)
local template = help_messages[version]
local paths = config.luaotfload.paths
local names_plain = paths.index_path_lua
local names_gzip = names_plain .. ".gz"
local names_bin = paths.index_path_luc
iowrite(stringformat(template,
luaotfload.self,
names_gzip,
names_bin,
caches.getwritablepath (config.luaotfload.paths.cache_dir, "")))
end
local about = [[
%s:
Luaotfload font management and diagnostic utility.
License: GNU GPL v2.0.
Report problems to <https://github.com/latex3/luaotfload/issues>
]]
local function version_msg ( )
local out = function (...) texiowrite_nl (stringformat (...)) end
local uname = os.uname ()
local meta = fonts.names.getmetadata ()
local runtime = luaotfload.runtime
local notes = config.luaotfload.status
local notes = status and status.notes or { }
out (about, luaotfload.self)
out ("%s version: %q", luaotfload.self, version)
if notes.description then
out ("Luaotfload: %q", notes.description)
end
out ("Revision: %q", notes.revision)
out ("Lua interpreter: %s; version %q", runtime[1], runtime[2])
--[[out ("Luatex SVN revision: %d", info.luatex_svn)]] --> SVN r5624
out ("Luatex version: %d.%d", math.floor(status.luatex_version / 100), status.luatex_version % 100)
out ("Platform: type=%s name=%s", os.type, os.name)
local uname_vars = tablesortedkeys (uname)
for i = 1, #uname_vars do
local var = uname_vars[i]
out (" + %8s: %s", var, uname[var])
end
if meta == false then
out("No database metadata available.")
else
out ("Index: version=%q created=%q modified=%q",
meta.version or "too old",
meta.created or "ages ago",
meta.modified or "ages ago")
end
out ""
end
--- makeshift formatting
local head_adornchars = {
[1] = "*", [2] = "=", [3] = "~", [4] = "-", [5] = "·",
}
local textwidth = 80
local wd_leftcolumn = mathfloor(textwidth * .25)
local key_fmt = stringformat([[%%%ds]], wd_leftcolumn)
local val_fmt = [[%s]]
local fieldseparator = ":"
local info_fmt = key_fmt .. fieldseparator .. " " .. val_fmt
local currentdepth = 0
local counterstack = { } -- counters per level
local counterformat = "%d"
local function format_counter (stack)
local acc = { }
for lvl=1, #stack do
acc[#acc+1] = stringformat(counterformat, stack[lvl])
end
return tableconcat(acc, ".")
end
local function print_heading (title, level)
if not title then return end
local structuredata
if currentdepth == level then -- top is current
counterstack[#counterstack] = counterstack[#counterstack] + 1
elseif currentdepth < level then -- push new
counterstack[#counterstack+1] = 1
else -- pop
local diff = currentdepth - level
while diff > 0 do
counterstack[#counterstack] = nil
diff = diff - 1
end
counterstack[#counterstack] = counterstack[#counterstack] + 1
end
currentdepth = level
texiowrite_nl ""
if not level or level > #head_adornchars then
level = #head_adornchars
end
local adornchar = head_adornchars[level]
local counter = format_counter(counterstack)
local s = adornchar .. adornchar .. " "
.. counter .. " "
.. title .. " "
texiowrite_nl (s .. stringrep(adornchar, textwidth-utf.len(s)))
end
local baseindent = " "
--[[doc--
show_info_items -- Together with show_info_table prints the table returned by
readers.getinfo(), recursing into nested tables if appropriate (as necessitated
by Luatex versions 0.78+ which include the pfminfo table in the result.
--doc]]--
local function show_info_table (t, depth)
depth = depth or 0
local indent = stringrep (baseindent, depth)
local keys = tablesortedkeys (t)
for n = 1, #keys do
local key = keys [n]
local val = t [key]
if key == "subfontindex" then
val = val - 1 -- We use 0-based subfont indices
end
if type (val) == "table" then
texiowrite_nl (indent .. stringformat (info_fmt, key, "<table>"))
show_info_table (val, depth + 1)
else
texiowrite_nl (indent .. stringformat (info_fmt, key, val))
end
end
end
local function show_info_items (fontinfo)
print_heading (fontinfo.fullname, 1)
texiowrite_nl ""
show_info_table (fontinfo)
texiowrite_nl ""
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 function reflow (text, width)
local words
local t_text = type (text)
if t_text == "string" then
words = lpegmatch(p_words, text)
if #words < 2 then
return { text }
end
elseif t_text == "table" then
words = text
if #text < 2 then
return text
end
end
local space = " "
local utflen = utf.len
local reflowed = { }
local first = words[1]
local linelen = #first
local line = { first }
for i=2, #words do
local word = words[i]
local lword = utflen(word)
linelen = linelen + lword + 1
if linelen > width then
reflowed[#reflowed+1] = tableconcat(line)
linelen = #word
line = { word }
else
line[#line+1] = space
line[#line+1] = word
end
end
reflowed[#reflowed+1] = tableconcat(line)
return reflowed
end
--- string -> 'a -> string list
local function print_field (key, val)
val = tostring(val)
local lhs = stringformat(key_fmt, key) .. fieldseparator .. " "
local wd_lhs = #lhs
local lines = reflow(val, textwidth - wd_lhs)
texiowrite_nl(lhs)
texiowrite(lines[1])
if #lines > 1 then
local indent = stringrep(" ", wd_lhs)
for i=2, #lines do
texiowrite_nl(indent)
texiowrite (lines[i])
end
end
end
--- see luafflib.c
local general_fields = {
--- second: l -> literal | n -> length | d -> date
{ "fullname", "l", "font name" },
{ "version", "l", "font version" },
{ "width", "l", "width" },
{ "averagewidth", "l", "average width" },
{ "panosewidth", "l", "panose width" },
{ "weight", "l", "weight indicator" },
{ "pfmweight", "l", "numerical weight" },
{ "panoseweight", "l", "panose weight" },
{ "designsize", "l", "design size" },
{ "minsize", "l", "design size min" },
{ "maxsize", "l", "design size max" },
{ "units", "l", "units per em" },
{ "ascender", "l", "ascender height" },
{ "descender", "l", "descender height" },
{ "capheight", "l", "capital height" },
}
local function display_general (fullinfo)
texiowrite_nl ""
print_heading("General Information", 2)
texiowrite_nl ""
for i=1, #general_fields do
local field = general_fields[i]
local key, mode, desc = unpack(field)
local val
if mode == "l" then
val = fullinfo[key]
elseif mode == "S" then --- style names table
local data = fullinfo[key]
if type (data) == "table" then
if #data > 0 then
for n = 1, #data do
local nth = data[n]
if nth.lang == 1033 then
val = nth.name
goto found
end
end
val = next (data).name
else
val = ""
end
::found::
else
val = data
end
elseif mode == "n" then
local v = fullinfo[key]
if v then
val = #fullinfo[key]
end
elseif mode == "d" then
if ostype == "unix" then
val = osdate("%F %T", fullinfo[key])
else
--- the MS compiler doesn’t support C99, so
--- strftime is missing some functionality;
--- see loslib.c for details.
val = osdate("%Y-%m-d %H:%M:%S", fullinfo[key])
end
end
if not val then
val = "<none>"
end
print_field(desc, val)
end
end
local function print_features (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(tablekeys(languages), 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 function display_feature_set (set)
print_features(set)
end
local function display_features_type (id, feat)
if feat and next (feat) then
print_heading(id, 3)
display_feature_set(feat)
return true
end
return false
end
local function display_features (features)
texiowrite_nl ""
print_heading("Features", 2)
local status = 0
if not display_features_type ("GSUB Features", features.gsub) then
status = status + 1
end
if not display_features_type ("GPOS Features", features.gpos) then
status = status + 2
end
if status == 3 then
texiowrite_nl("font defines neither gsub nor gpos features")
elseif status == 2 then
texiowrite_nl("font defines no gpos feature")
elseif status == 1 then
texiowrite_nl("font defines no gsub feature")
end
end
local function show_full_info (path, subfont)
local rawinfo, warn = fonts.handlers.otf.readers.loadfont (path, subfont)
if not rawinfo then
texiowrite_nl(stringformat([[cannot open font %s]], path))
return
end
display_general(rawinfo.metadata)
display_features(rawinfo.resources.features)
end
local function subfont_by_name (lst, askedname, n)
for n = 1, #lst do
local font = lst[n]
if fonts.names.sanitize_fontname (font.fullname) == askedname then
return font
end
end
return false
end
--[[doc--
The font info knows two levels of detail:
a) basic information returned by readers.getinfo(); and
b) detailed information that is a subset of the font table
returned by readers.loadfont().
--doc]]--
local function show_font_info (basename, askedname, detail, subfont)
local filenames = fonts.names.data().files
local index = filenames.base[basename]
local fullname = filenames.full[index]
askedname = fonts.names.sanitize_fontname (askedname)
if not fullname then -- texmf
fullname = resolvers.findfile(basename)
end
if fullname then
local shortinfo = fonts.handlers.otf.readers.getinfo (fullname, {
subfont = subfont,
platformnames = true,
rawfamilynames = true,
})
local nfonts = #shortinfo
if nfonts > 0 then -- true type collection
local subfont
if askedname then
logreport (true, 1, "resolve",
[[%s is part of the font collection %s]],
askedname, basename)
subfont = subfont_by_name(shortinfo, askedname)
end
if subfont then
show_info_items(subfont)
if detail == true then
show_full_info(fullname, subfont)
end
else -- list all subfonts
logreport (true, 1, "resolve",
[[%s is a font collection]], basename)
for subfont = 1, nfonts do
logreport (true, 1, "resolve",
[[Showing info for font no. %d]],
subfont - 1)
show_info_items(shortinfo[subfont])
if detail == true then
show_full_info(fullname, subfont)
end
end
end
else
show_info_items(shortinfo)
if detail == true then
show_full_info(fullname, subfont)
end
end
else
logreport (true, 1, "resolve", "Font %s not found", filename)
end
end
--[[--
Running the scripts triggers one or more actions that have to be
executed in the correct order. To avoid duplication we track them in a
set.
--]]--
local action_sequence = {
"config" , "loglevel" , "help" , "version" ,
"dumpconf" , "diagnose" , "blacklist" , "cache" ,
"flush" , "bisect" , "generate" , "list" ,
"query" ,
}
local action_pending = tabletohash(action_sequence, false)
action_pending.config = true --- always read the configuration
action_pending.loglevel = true --- always set the loglevel
action_pending.generate = false --- this is the default action
local actions = { } --- (jobspec -> (bool * bool)) list
function actions.loglevel (job)
local lvl = job.log_level
if lvl then
luaotfload.log.set_loglevel(lvl)
logreport ("info", 3, "util", "Setting the log level to %d.", lvl)
logreport ("log", 2, "util", "Lua=%q", _VERSION)
end
return true, true
end
function actions.config (job)
local defaults = luaotfload.default_config
local vars = config.actions.read (job.extra_config)
config.luaotfload = config.actions.apply (defaults, vars)
config.luaotfload = config.actions.apply (config.luaotfload, job.config)
--inspect(config.luaotfload)
--os.exit()
if not config.actions.reconfigure () then
return false, false
end
return true, true
end
function actions.version (job)
version_msg()
return true, false
end
function actions.dumpconf (job)
config.actions.dump ()
return true, false
end
function actions.help (job)
help_msg (job.help_version or "luaotfload-tool")
return true, false
end
function actions.blacklist (job)
fonts.names.read_blacklist()
local n = 0
for n, entry in next, tablesortedkeys(fonts.names.blacklist) do
iowrite (stringformat("(%d %s)\n", n, entry))
end
return true, false
end
function actions.generate (job)
local _ = fonts.names.update ({ }, job.force_reload, job.dry_run)
local namedata = fonts.names.data ()
if namedata then
logreport ("info", 2, "db",
"Fonts in the database: %i",
#namedata.mappings)
return true, true
end
return false, false
end
-------------------------------------------------------------------------------
--- bisect mode
-------------------------------------------------------------------------------
local bisect_status_path = caches.getwritablepath ("bisect", "")
local bisect_status_file = bisect_status_path .."/" .. "luaotfload-bisect-status.lua"
local bisect_status_fmt = [[
--[==[-------------------------------------------------------------------------
This file is generated by Luaotfload. It can be safely deleted.
Creation date: %s.
-------------------------------------------------------------------------]==]--
%s
--- vim:ft=lua:ts=8:et:sw=2
]]
--[[doc--
write_bisect_status -- Write the history of the current bisection to disk.
--doc]]--
--- state list -> bool
local function write_bisect_status (data)
local payload = tableserialize (data, true)
local status = stringformat (bisect_status_fmt,
osdate ("%Y-%m-d %H:%M:%S", os.time ()),
payload)
if status and iosavedata (bisect_status_file, status) then
logreport ("info", 4, "bisect",
"Bisection state written to %s.",
bisect_status_file)
return true
end
logreport ("info", 0, "bisect",
"Failed to write bisection state to %s.",
bisect_status_file)
return false
end
--[[doc--
read_bisect_status -- Read the bisect log from disk.
--doc]]--
--- unit -> state list
local function read_bisect_status ()
logreport ("info", 4, "bisect",
"Testing for status file: %q.",
bisect_status_file)
if not lfsisfile (bisect_status_file) then
logreport ("info", 2, "bisect",
"No such file: %q.", bisect_status_file)
logreport ("info", 0, "bisect",
"Not in bisect mode.")
return false
end
logreport ("info", 4, "bisect",
"Reading status file: %q.", bisect_status_file)
local success, status = pcall (dofile, bisect_status_file)
if not success then
logreport ("info", 0, "bisect",
"Could not read status file.")
return false
end
return status
end
--[[doc--
bisect_start -- Begin a bisect session. Determines the number of
fonts and sets the initial high, low, and pivot values.
--doc]]--
local function bisect_start ()
if lfsisfile (bisect_status_file) then
logreport ("info", 0, "bisect",
"Bisect session in progress.",
bisect_status_file)
logreport ("info", 0, "bisect",
"Use --bisect=stop to erase it before starting over.")
return false, false
end
logreport ("info", 2, "bisect",
"Starting bisection of font database %q.",
bisect_status_file)
local n = fonts.names.count_font_files ()
local pivot = mathfloor (n / 2)
local data = { { 1, n, pivot } }
logreport ("info", 0, "bisect",
"Initializing pivot to %d.", pivot)
if write_bisect_status (data) then
return true, false
end
return false, false
end
--[[doc--
bisect_stop -- Terminate bisection session by removing all state info.
--doc]]--
local function bisect_stop ()
logreport ("info", 3, "bisect",
"Erasing bisection state at %s.",
bisect_status_file)
if lfsisfile (bisect_status_file) then
local success, msg = os.remove (bisect_status_file)
if not success then
logreport ("info", 2, "bisect",
"Failed to erase file %s (%s).",
bisect_status_file, msg)
end
end
if lfsisdir (bisect_status_path) then
local success, msg = os.remove (bisect_status_path)
if not success then
logreport ("info", 2, "bisect",
"Failed to erase directory %s (%s).",
bisect_status_path, msg)
end
end
if lfsisfile (bisect_status_file) then
return false, false
end
return true, false
end
--[[doc--
bisect_terminate -- Wrap up a bisect session by printing the
offending font and removing the state file.
--doc]]--
local function bisect_terminate (nsteps, culprit)
logreport ("info", 1, "bisect",
"Bisection completed after %d steps.", nsteps)
logreport ("info", 0, "bisect",
"Bad file: %s.", fonts.names.nth_font_filename (culprit))
logreport ("info", 0, "bisect",
"Run with --bisect=stop to finish bisection.")
return true, false
end
--[[doc--
list_remainder -- Show remaining fonts in bisect slice.
--doc]]--
local function list_remainder (lo, hi)
local fonts = fonts.names.font_slice (lo, hi)
logreport ("info", 0, "bisect", "%d fonts left.", hi - lo + 1)
for i = 1, #fonts do
logreport ("info", 1, "bisect", " · %2d: %s", lo, fonts[i])
lo = lo + 1
end
end
--[[doc--
bisect_set -- Prepare the next bisection step by setting high, low,
and pivot to new values.
The “run” directive always picks the segment below the pivot so we
can rely on the “outcome parameter” to be referring to that.
--doc]]--
local function bisect_set (outcome)
local status = read_bisect_status ()
if not status then
return false, false
end
local nsteps = #status
local previous = status[nsteps]
if previous == true then
--- Bisection already completed; we exit early through
--- bisect_terminate() to avoid further writes to the
--- state files that mess up step counting.
nsteps = nsteps - 1
return bisect_terminate (nsteps, status[nsteps][1])
end