summaryrefslogtreecommitdiff
path: root/scripts/mkcharacters
blob: a31c19c035e0c0b458e01ffd9e65b8820145b6bd (plain)
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
#!/usr/bin/env texlua
-----------------------------------------------------------------------
--         FILE:  mkcharacters.lua
--        USAGE:  ./mkcharacters.lua 
--  DESCRIPTION:  import parts of char-def.lua
-- REQUIREMENTS:  lua, ConTeXt, the lualibs package
--       AUTHOR:  Philipp Gesang (Phg), <phg@phi-gamma.net>
-----------------------------------------------------------------------
-- We create a stripped-down version of char-def.lua, suitable for use
-- with the generic font loader.
-----------------------------------------------------------------------

-----------------------------------------------------------------------
--                              config
-----------------------------------------------------------------------
local mkivpath      = arg[1]
local charfile      = arg[2] or "./build/luaotfload-characters.lua"

---  for every code point char-def.lua provides a set of fields. they
---  are:
---
---     * adobename
---     * category
---     * cjkwd
---     * comment
---     * contextname
---     * description
---     * direction
---     * lccode
---     * linebreak
---     * mathclass
---     * mathextensible
---     * mathfiller
---     * mathname
---     * mathspec
---     * mathstretch
---     * mathsymbol
---     * mirror
---     * shcode
---     * specials
---     * textclass
---     * uccode
---     * unicodeslot
---     * variants

local import = {
  "direction", "mirror", --> πολυγλωσσία/uax9
  "category",            --> https://gist.github.com/phi-gamma/5812290
  "textclass",           --> https://gist.github.com/phi-gamma/6488187 
}

-----------------------------------------------------------------------
--                             includes
-----------------------------------------------------------------------

kpse.set_program_name"luatex"

require "lualibs"

local chardef
local charini

if not mkivpath then
  mkivpath = assert (kpse.expand_path
                      "~/context/tex/texmf-context/tex/context/base/mkiv/",
                     "Failed to locate ConTeXt.")
end

chardef = mkivpath .. "/char-def.lua"
charini = mkivpath .. "/char-ini.lua"

--- we could grab the files from contextgarden but as Context is part
--- of TL it’s not worth bothering
if not (chardef and lfs.isfile(chardef)) then
  chardef = assert(kpse.find_file("char-def.lua", "lua"),
                   "Failed to locate file char-def.lua from ConTeXt.")
end

if not (charini and lfs.isfile(charini)) then
  charini = assert(kpse.find_file("char-ini.lua", "lua"),
                   "Failed to locate file char-ini.lua from ConTeXt.")
end

io.write(string.format("extracting data from char-def.lua at %s\n",
                       chardef))
io.write(string.format("loading code from char-ini.lua at %s\n",
                       charini))

-----------------------------------------------------------------------
--                           functionality
-----------------------------------------------------------------------

local get_characters = function ( )
  local data
  local inchan = io.open(chardef, "r")
  if not inchan then
    io.write("Could not open file for reading: "..chardef.."\n.")
    goto fail
  end
  data = inchan:read "*all"
  inchan:close()
  data = loadstring(data)
  if data then
    data() --> characters.data
    data = nil
    collectgarbage "collect"
    if characters.data and next(characters.data) then
      return characters.data
    end
    io.write "Character table empty.\n"
    goto fail
  end
  io.write(chardef .. " is not a valid Lua file.\n")
  ::fail::
  io.write "Emergency exit.\n"
  os.exit(1)
end

local extract_fields_indeed
extract_fields_indeed = function (data, acc, lastidx)
  local idx, char = next(data, lastidx)
  if idx then
    local imported = { }
    for i=1, #import do
      local field = import[i]
      imported[field] = char[field]
    end
    acc[idx] = imported
    return extract_fields_indeed(data, acc, idx)
  end
  return acc
end

local extract_fields = function (data)
  return extract_fields_indeed(data, {}, nil)
end

--[[ extract_classifiers : from luatex-basics-prepare.tex ]]

local extract_classifiers = function (chardata)
  dofile (charini)
  local s_init = 1    local s_rphf =  7
  local s_medi = 2    local s_half =  8
  local s_fina = 3    local s_pref =  9
  local s_isol = 4    local s_blwf = 10
  local s_mark = 5    local s_pstf = 11
  local s_rest = 6

  local mappers = {
    l = s_init,  -- left
    d = s_medi,  -- double
    c = s_medi,  -- joiner
    r = s_fina,  -- right
    u = s_isol,  -- nonjoiner
  }

  local first_arabic,  last_arabic  = characters.blockrange("arabic")
  local first_syriac,  last_syriac  = characters.blockrange("syriac")
  local first_mandiac, last_mandiac = characters.blockrange("mandiac")
  local first_nko,     last_nko     = characters.blockrange("nko")

  local classifiers = { }

  for k, c in next, chardata do
    if k > 0 then
      local c = chardata[k]
      if c then
        local arabic = c.arabic
        if arabic then
          classifiers[k] = mappers[arabic]
          elseif k >= first_arabic  and k <= last_arabic  or k >= first_syriac  and k <= last_syriac  or
            k >= first_mandiac and k <= last_mandiac or k >= first_nko     and k <= last_nko     then
            if c.category == "mn" then
              classifiers[k] = s_mark
            else
              classifiers[k] = s_rest
            end
          end
        end
      end
    end
    return classifiers
  end

local amend_table_fields = function (data, classifiers)
  --- installed by luatex-basics-prepare.tex
  data.characters  = { }
  data.classifiers = classifiers
  return data
end

local writedata = function (data)
  local outchan = io.open(charfile, "w")
  if not outchan then
    io.write("Could not open "..charfile.." for writing.\n")
    return false
  end
  outchan:write(data)
  outchan:close()
  return true
end

do
  local chardata    = get_characters()
  local classifiers = extract_classifiers(chardata)
  local stripped    = extract_fields(chardata)
  local amended     = amend_table_fields(stripped, classifiers)
  local serialized  = table.serialize(amended, true, {
    compact   = true,
    noquotes  = true,
    hexify    = true, --- for consistency with char-def
  })
  if writedata(serialized) then
    goto done
  end
  goto fail
end

::done::
  os.exit(0)

::fail::
  io.write "Emergency exit.\n"
  os.exit(1)

--- vim:ft=lua:ts=2:et:sw=2