texmathcodes.c /size: 10 Kb    last modification: 2024-01-16 10:22
1/*
2    See license.txt in the root of this project.
3*/
4
5# include "luametatex.h"
6
7/*tex
8
9    We support the traditional math codes as well as larger ones suitable for \UNICODE\ input and
10    fonts.
11
12*/
13
14/*tex the |0xFFFFFFFF| is a flag value. */
15
16# define MATHCODESTACK   8
17# define MATHCODEDEFAULT 0xFFFFFFFF
18# define MATHCODEACTIVE  0xFFFFFFFE
19
20/*tex Delcodes are also went larger. */
21
22# define DELCODESTACK   4
23# define DELCODEDEFAULT 0xFFFFFFFF
24
25typedef struct mathcode_state_info {
26    sa_tree mathcode_head;
27    sa_tree delcode_head;
28} mathcode_state_info;
29
30static mathcode_state_info lmt_mathcode_state = {
31    .mathcode_head = NULL,
32    .delcode_head  = NULL,
33};
34
35/*tex
36
37    We now get lots of helpers for definitions and printing. The storage model that we use is
38    different because we can have many more so we need to be sparse. Therefore we use trees.
39
40*/
41
42# define print_hex_digit_one(A) do { \
43    if ((A) >= 10) { \
44        tex_print_char('A' + (A) - 10); \
45    } else { \
46        tex_print_char('0' + (A)); \
47    } \
48} while (0)
49
50# define print_hex_digit_two(A) do { \
51    print_hex_digit_one((A) / 16); \
52    print_hex_digit_one((A) % 16); \
53} while (0)
54
55# define print_hex_digit_four(A) do { \
56    print_hex_digit_two((A) / 256); \
57    print_hex_digit_two((A) % 256); \
58} while (0)
59
60# define print_hex_digit_six(A) do { \
61    print_hex_digit_two( (A) / 65536); \
62    print_hex_digit_two(((A) % 65536) / 256); \
63    print_hex_digit_two( (A)          % 256); \
64} while (0)
65
66/* 0xFFFFF is plenty for math */
67
68mathcodeval tex_mathchar_from_integer(int value, int extcode)
69{
70    mathcodeval mval;
71    if (extcode == tex_mathcode) {
72        mval.class_value = math_old_class_part(value);
73        mval.family_value = math_old_family_part(value);
74        mval.character_value = math_old_character_part(value);
75    } else {
76        mval.class_value = math_class_part(value);
77        mval.family_value = math_family_part(value);
78        mval.character_value = math_character_part(value);
79    }
80    return mval;
81}
82
83mathcodeval tex_mathchar_from_spec(int value)
84{
85    mathcodeval mval = tex_no_math_code();
86    if (value) {
87        mval.class_value = math_spec_class(value);
88        mval.family_value = math_spec_family(value);
89        mval.character_value = math_spec_character(value);
90    }
91    return mval;
92}
93
94void tex_show_mathcode_value(mathcodeval mval, int extcode) /* todo: format option */
95{
96    tex_print_char('"');
97    if (extcode == tex_mathcode) {
98        print_hex_digit_one(math_old_class_mask(mval.class_value));
99        print_hex_digit_one(math_old_family_mask(mval.family_value));
100        print_hex_digit_two(math_old_character_mask(mval.character_value));
101    } else {
102        print_hex_digit_two(mval.class_value);
103        tex_print_char('"');
104        print_hex_digit_two(mval.family_value);
105        tex_print_char('"');
106        print_hex_digit_six(mval.character_value);
107    }
108}
109
110static void tex_aux_show_mathcode(int n)
111{
112    mathcodeval mval = tex_get_math_code(n);
113    tex_print_format("%eUmathcode%i=", n);
114    tex_show_mathcode_value(mval, umath_mathcode);
115}
116
117static void tex_aux_unsave_mathcode(int level)
118{
119    if (lmt_mathcode_state.mathcode_head->stack) {
120        while (lmt_mathcode_state.mathcode_head->sa_stack_ptr > 0 && abs(lmt_mathcode_state.mathcode_head->stack[lmt_mathcode_state.mathcode_head->sa_stack_ptr].level) >= level) {
121            sa_stack_item item = lmt_mathcode_state.mathcode_head->stack[lmt_mathcode_state.mathcode_head->sa_stack_ptr];
122            if (item.level > 0) {
123                sa_rawset_item_4(lmt_mathcode_state.mathcode_head, item.code, item.value_1);
124                if (tracing_restores_par > 1) {
125                    tex_begin_diagnostic();
126                    tex_print_str("{restoring ");
127                    tex_aux_show_mathcode(item.code);
128                    tex_print_char('}');
129                    tex_end_diagnostic();
130                }
131            }
132            (lmt_mathcode_state.mathcode_head->sa_stack_ptr)--;
133        }
134    }
135}
136
137mathcodeval tex_no_math_code(void)
138{
139    return (mathcodeval) { 0, 0, 0 };
140}
141
142void tex_set_math_code(int n, mathcodeval v, int level)
143{
144    sa_tree_item item;
145    if (v.class_value == active_math_class_value && v.family_value == 0 && v.character_value == 0) {
146        item.uint_value = MATHCODEACTIVE;
147    } else if (v.class_value == 0 && v.family_value == 0) {
148        /*tex This is rather safe because we don't decide on it. */
149        item.uint_value = MATHCODEDEFAULT;
150    } else {
151        item.math_code_value.class_value = v.class_value;
152        item.math_code_value.family_value = v.family_value;
153        item.math_code_value.character_value = v.character_value;
154    }
155    sa_set_item_4(lmt_mathcode_state.mathcode_head, n, item, level);
156    if (tracing_assigns_par > 1) {
157        tex_begin_diagnostic();
158        tex_print_str("{assigning ");
159        tex_aux_show_mathcode(n);
160        tex_print_char('}');
161        tex_end_diagnostic();
162    }
163}
164
165mathcodeval tex_get_math_code(int n)
166{
167    sa_tree_item item;
168    mathcodeval m = tex_no_math_code();
169    sa_get_item_4(lmt_mathcode_state.mathcode_head, n, &item);
170    if (item.uint_value == MATHCODEDEFAULT) {
171        m.character_value = n;
172    } else if (item.uint_value == MATHCODEACTIVE) {
173        m.class_value = active_math_class_value;
174    } else if (item.math_code_value.class_value == active_math_class_value) {
175        m.class_value = active_math_class_value;
176        m.character_value = n;
177    } else {
178        m.class_value = (short) item.math_code_value.class_value;
179        m.family_value = (short) item.math_code_value.family_value;
180        m.character_value = item.math_code_value.character_value;
181    }
182    return m;
183}
184
185int tex_get_math_code_number(int n) /* should be unsigned */
186{
187    mathcodeval d = tex_get_math_code(n);
188    return math_packed_character(d.class_value, d.family_value, d.character_value);
189}
190
191static void tex_aux_initialize_mathcode(void)
192{
193    lmt_mathcode_state.mathcode_head = sa_new_tree(MATHCODESTACK, 4, (sa_tree_item) { .uint_value = MATHCODEDEFAULT });
194}
195
196static void tex_aux_dump_mathcode(dumpstream f)
197{
198    sa_dump_tree(f, lmt_mathcode_state.mathcode_head);
199}
200
201static void tex_aux_undump_mathcode(dumpstream f)
202{
203    lmt_mathcode_state.mathcode_head = sa_undump_tree(f);
204}
205
206static void tex_aux_show_delcode(int n)
207{
208    delcodeval dval = tex_get_del_code(n);
209    tex_print_format("%eUdelcode=", n);
210    if (tex_has_del_code(dval)) {
211        tex_print_char('"');
212        print_hex_digit_two(dval.small.family_value);
213        print_hex_digit_six(dval.small.character_value);
214    } else {
215        tex_print_str("-1");
216    }
217}
218
219static void tex_aux_unsave_delcode(int level)
220{
221    if (lmt_mathcode_state.delcode_head->stack) {
222        while (lmt_mathcode_state.delcode_head->sa_stack_ptr > 0 && abs(lmt_mathcode_state.delcode_head->stack[lmt_mathcode_state.delcode_head->sa_stack_ptr].level) >= level) {
223            sa_stack_item item = lmt_mathcode_state.delcode_head->stack[lmt_mathcode_state.delcode_head->sa_stack_ptr];
224            if (item.level > 0) {
225                sa_rawset_item_8(lmt_mathcode_state.delcode_head, item.code, item.value_1, item.value_2);
226                if (tracing_restores_par > 1) {
227                    tex_begin_diagnostic();
228                    tex_print_str("{restoring ");
229                    tex_aux_show_delcode(item.code);
230                    tex_print_char('}');
231                    tex_end_diagnostic();
232                }
233            }
234            (lmt_mathcode_state.delcode_head->sa_stack_ptr)--;
235        }
236    }
237}
238
239void tex_set_del_code(int n, delcodeval v, int level)
240{
241    sa_tree_item v1, v2; /* seldom all zero */
242    v1.math_code_value.class_value = v.small.class_value;
243    v1.math_code_value.family_value = v.small.family_value;
244    v1.math_code_value.character_value = v.small.character_value;
245    v2.math_code_value.class_value = v.large.class_value;
246    v2.math_code_value.family_value = v.large.family_value;
247    v2.math_code_value.character_value = v.large.character_value;
248    /*tex Always global! */
249    sa_set_item_8(lmt_mathcode_state.delcode_head, n, v1, v2, level);
250    if (tracing_assigns_par > 1) {
251        tex_begin_diagnostic();
252        tex_print_str("{assigning ");
253        tex_aux_show_delcode(n);
254        tex_print_char('}');
255        tex_end_diagnostic();
256    }
257}
258
259int tex_has_del_code(delcodeval d)
260{
261    return d.small.family_value >= 0;
262}
263
264delcodeval tex_no_del_code(void)
265{
266    return (delcodeval) { { 0, -1, 0 }, { 0, 0, 0 } };
267}
268
269delcodeval tex_get_del_code(int n)
270{
271    sa_tree_item v1, v2;
272    delcodeval d = { { 0, -1, 0 }, { 0, 0, 0} };
273    sa_get_item_8(lmt_mathcode_state.delcode_head, n, &v1, &v2);
274    if (v1.uint_value != DELCODEDEFAULT) {
275        d.small.class_value = (short) v1.math_code_value.class_value;
276        d.small.family_value = (short) v1.math_code_value.family_value;
277        d.small.character_value = v1.math_code_value.character_value;
278        d.large.class_value = (short) v2.math_code_value.class_value;
279        d.large.family_value = (short) v2.math_code_value.family_value;
280        d.large.character_value = v2.math_code_value.character_value;
281    }
282    return d;
283}
284
285/*tex */
286
287mathdictval tex_no_dict_code(void) 
288{
289    return (mathdictval) { 0, 0, 0 };
290}
291
292
293/*tex  This really only works for old-style delcodes! */
294
295int tex_get_del_code_number(int n)
296{
297    delcodeval d = tex_get_del_code(n);
298    if (tex_has_del_code(d)) {
299        return ((d.small.family_value * 256  + d.small.character_value) * 4096 +
300                (d.large.family_value * 256) + d.large.character_value);
301    } else {
302        return -1;
303    }
304}
305
306static void tex_aux_initialize_delcode(void)
307{
308    lmt_mathcode_state.delcode_head = sa_new_tree(DELCODESTACK, 8, (sa_tree_item) { .uint_value = DELCODEDEFAULT });
309}
310
311static void tex_aux_dump_delcode(dumpstream f)
312{
313    sa_dump_tree(f, lmt_mathcode_state.delcode_head);
314}
315
316static void tex_aux_undump_delcode(dumpstream f)
317{
318    lmt_mathcode_state.delcode_head = sa_undump_tree(f);
319}
320
321void tex_unsave_math_codes(int grouplevel)
322{
323    tex_aux_unsave_mathcode(grouplevel);
324    tex_aux_unsave_delcode(grouplevel);
325}
326
327void tex_initialize_math_codes(void)
328{
329    tex_aux_initialize_mathcode();
330    tex_aux_initialize_delcode();
331    /*tex This might become optional: */
332    tex_set_default_math_codes();
333    tex_set_del_code('.', (delcodeval) { { 0, 0, 0, }, { 0, 0, 0 } }, level_one);
334}
335
336void tex_free_math_codes(void)
337{
338    sa_destroy_tree(lmt_mathcode_state.mathcode_head);
339    sa_destroy_tree(lmt_mathcode_state.delcode_head);
340}
341
342void tex_dump_math_codes(dumpstream f)
343{
344    tex_aux_dump_mathcode(f);
345    tex_aux_dump_delcode(f);
346}
347
348void tex_undump_math_codes(dumpstream f)
349{
350    tex_aux_undump_mathcode(f);
351    tex_aux_undump_delcode(f);
352}
353