summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/luatex/luatexbase/attr.lua
blob: e86bbdedfda136c9269e2f531977658a29748dd4 (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
-- 
--  This is file `attr.lua',
--  generated with the docstrip utility.
-- 
--  The original source files were:
-- 
--  luatexbase-attr.dtx  (with options: `luamodule')
--  
--  See the aforementioned source file(s) for copyright and licensing information.
--  
--- locals
local copynode          = node.copy
local newnode           = node.new
local nodesubtype       = node.subtype
local nodetype          = node.id
local stringfind        = string.find
local stringformat      = string.format
local tableunpack       = unpack or table.unpack
local texiowrite_nl     = texio.write_nl
local texiowrite        = texio.write
--- luatex internal types
local whatsit_t         = nodetype"whatsit"
local user_defined_t    = nodesubtype"user_defined"
local unassociated      = "__unassociated"
luatexbase              = luatexbase or { }
local luatexbase        = luatexbase
local err, warning, info, log = luatexbase.provides_module({
    name          = "luatexbase-attr",
    version       = 0.6,
    date          = "2013/05/11",
    description   = "Attributes allocation for LuaTeX",
    author        = "Elie Roux, Manuel Pegourie-Gonnard and Philipp Gesang",
    copyright     = "Elie Roux, Manuel Pegourie-Gonnard and Philipp Gesang",
    license       = "CC0",
})
luatexbase.attributes   = luatexbase.attributes or { }
local attributes        = luatexbase.attributes
local new_attribute
local unset_attribute
local luatex_sty_counter = 'LuT@AllocAttribute'
if tex.count[luatex_sty_counter] then
  if tex.count[luatex_sty_counter] > -1 then
    error("luatexbase error: attribute 0 has already been set by \newattribute"
        .."macro from luatex.sty, not belonging to this package, this makes"
        .."luaotfload unusable. Please report to the maintainer of luatex.sty")
  else
    tex.count[luatex_sty_counter] = 0
  end
end
local last_alloc = 0
function new_attribute(name, silent)
    if last_alloc >= 65535 then
        if silent then
            return -1
        else
            error("No room for a new \\attribute", 1)
        end
    end
    local lsc = tex.count[luatex_sty_counter]
    if lsc and lsc > last_alloc then
      last_alloc = lsc
    end
    last_alloc = last_alloc + 1
    if lsc then
      tex.setcount('global', luatex_sty_counter, last_alloc)
    end
    attributes[name] = last_alloc
    unset_attribute(name)
    if not silent then
        log('luatexbase.attributes[%q] = %d', name, last_alloc)
    end
    return last_alloc
end
luatexbase.new_attribute = new_attribute
local unset_value = (luatexbase.luatexversion < 37) and -1 or -2147483647
function unset_attribute(name)
    tex.setattribute(attributes[name], unset_value)
end
luatexbase.unset_attribute = unset_attribute
luatexbase.get_unset_value = function () return unset_value end
--- cf. luatexref-t.pdf, sect. 8.1.4.25
local user_whatsits       = {    --- (package, (name, id hash)) hash
    __unassociated = { },        --- those without package name
}
local whatsit_ids         = { }  --- (id, (name * package)) hash
local whatsit_cap         = 2^53 --- Lua numbers are doubles
local current_whatsit     = 0
local anonymous_whatsits  = 0
local anonymous_prefix    = "anon"
--- string -> string -> int
local new_user_whatsit_id = function (name, package)
    if name then
        if not package then
            package = unassociated
        end
    else -- anonymous
        anonymous_whatsits = anonymous_whatsits + 1
        warning("defining anonymous user whatsit no. %d", anonymous_whatsits)
        warning("dear package authors, please name your whatsits!")
        package = unassociated
        name    = anonymous_prefix .. tostring(anonymous_whatsits)
    end

    local whatsitdata = user_whatsits[package]
    if not whatsitdata then
        whatsitdata             = { }
        user_whatsits[package]  = whatsitdata
    end

    local id = whatsitdata[name]
    if id then --- warning
        warning("replacing whatsit %s:%s (%d)", package, name, id)
    else --- new id
        current_whatsit     = current_whatsit + 1
        if current_whatsit >= whatsit_cap then
            warning("maximum of %d integral user whatsit ids reached",
                whatsit_cap)
            warning("further whatsit allocation may be inconsistent")
        end
        id                  = current_whatsit
        whatsitdata[name]   = id
        whatsit_ids[id]     = { name, package }
    end
    log("new user-defined whatsit %d (%s:%s)", id, package, name)
    return id
end
luatexbase.new_user_whatsit_id = new_user_whatsit_id
--- (string | node_t) -> string -> ((unit -> node_t) * int)
local new_user_whatsit = function (req, package)
    local id, whatsit
    if type(req) == "string" then
        id              = new_user_whatsit_id(req, package)
        whatsit         = newnode(whatsit_t, user_defined_t)
        whatsit.user_id = id
    elseif req.id == whatsit_t and req.subtype == user_defined_t then
        id      = req.user_id
        whatsit = copynode(req)
        if not whatsit_ids[id] then
            warning("whatsit id %d unregistered; "
                    .. "inconsistencies may arise", id)
        end
    end
    return function () return copynode(whatsit) end, id
end
luatexbase.new_user_whatsit         = new_user_whatsit
--- string -> string -> int
local get_user_whatsit_id = function (name, package)
    if not package then
        package = unassociated
    end
    return user_whatsits[package][name]
end
luatexbase.get_user_whatsit_id = get_user_whatsit_id
--- int | fun | node -> (string, string)
local get_user_whatsit_name = function (asked)
    local id
    if type(asked) == "number" then
        id = asked
    elseif type(asked) == "function" then
        --- node generator
        local n = asked()
        id = n.user_id
    else --- node
        id = asked.user_id
    end
    local metadata = whatsit_ids[id]
    if not metadata then -- unknown
        warning("whatsit id %d unregistered; inconsistencies may arise", id)
        return "", ""
    end
    return tableunpack(metadata)
end
luatexbase.get_user_whatsit_name = get_user_whatsit_name
--- string -> unit
local dump_registered_whatsits = function (asked_package)
    local whatsit_list = { }
    if asked_package then
        local whatsitdata = user_whatsits[asked_package]
        if not whatsitdata then
            error("(no user whatsits registered for package %s)",
                  asked_package)
            return
        end
        texiowrite_nl("(user whatsit allocation stats for " .. asked_package)
        for name, id in next, whatsitdata do
            whatsit_list[#whatsit_list+1] =
                stringformat("(%s:%s %d)", asked_package, name, id)
        end
    else
        texiowrite_nl("(user whatsit allocation stats")
        texiowrite_nl(stringformat(" ((total %d)\n  (anonymous %d))",
            current_whatsit, anonymous_whatsits))
        for package, whatsitdata in next, user_whatsits do
            for name, id in next, whatsitdata do
                whatsit_list[#whatsit_list+1] =
                    stringformat("(%s:%s %d)", package, name, id)
            end
        end
    end

    texiowrite_nl" ("
    --- in an attempt to be clever the texio.write* functions
    --- mess up line breaking, so concatenation is unusable ...
    local first = true
    for i=1, #whatsit_list do
        if first then
            first = false
        else -- indent
            texiowrite_nl"  "
        end
        texiowrite(whatsit_list[i])
    end
    texiowrite"))\n"
end
luatexbase.dump_registered_whatsits = dump_registered_whatsits
luatexbase.newattribute            = new_attribute
luatexbase.newuserwhatsit          = new_user_whatsit
luatexbase.newuserwhatsitid        = new_user_whatsit_id
luatexbase.getuserwhatsitid        = get_user_whatsit_id
luatexbase.getuserwhatsitname      = get_user_whatsit_name
luatexbase.dumpregisteredwhatsits  = dump_registered_whatsits
-- 
--  End of File `attr.lua'.