1% mathnodes.w
2%
3% Copyright 2006-2012 Taco Hoekwater <taco@@luatex.org>
4% Copyright 2012 Khaled Hosny <khaledhosny@@eglug.org>
5%
6% This file is part of LuaTeX.
7%
8% LuaTeX is free software; you can redistribute it and/or modify it under
9% the terms of the GNU General Public License as published by the Free
10% Software Foundation; either version 2 of the License, or (at your
11% option) any later version.
12%
13% LuaTeX is distributed in the hope that it will be useful, but WITHOUT
14% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15% FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16% License for more details.
17%
18% You should have received a copy of the GNU General Public License along
19% with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
20
21@ @c
22
23
24#include "ptexlib.h"
25
26@ math codes
27@c
28static sa_tree mathcode_head = NULL;
29
30#define MATHCODEHEAP 8
31
32static mathcodeval *mathcode_heap = NULL;
33static int mathcode_heapsize = MATHCODEHEAP;
34static int mathcode_heapptr = 0;
35
36/* the 0xFFFFFFFF is a flag value */
37#define MATHCODESTACK 8
38#define MATHCODEDEFAULT 0xFFFFFFFF
39
40@ delcodes
41@c
42static sa_tree delcode_head = NULL;
43
44#define DELCODEHEAP 8
45
46static delcodeval *delcode_heap = NULL;
47static int delcode_heapsize = DELCODEHEAP;
48static int delcode_heapptr = 0;
49
50#define DELCODESTACK 4
51#define DELCODEDEFAULT 0xFFFFFFFF
52
53@ some helpers for mathcode printing
54
55@c
56#define print_hex_digit(A) do {                 \
57    if ((A)>=10) print_char('A'+(A)-10);        \
58    else print_char('0'+(A));                   \
59  } while (0)
60
61#define two_hex(A) do {       \
62    print_hex_digit((A)/16);  \
63    print_hex_digit((A)%16);  \
64  } while (0)
65
66#define four_hex(A) do {      \
67    two_hex((A)/256);         \
68    two_hex((A)%256);         \
69  } while (0)
70
71#define six_hex(A) do {       \
72    two_hex((A)/65536);       \
73    two_hex(((A)%65536)/256); \
74    two_hex((A)%256);         \
75  } while (0)
76
77@ @c
78void show_mathcode_value(mathcodeval c)
79{
80    if (c.origin_value == xetex_mathcode) {
81        print_char('"');
82        print_hex_digit(c.class_value);
83        print_char('"');
84        two_hex(c.family_value);
85        print_char('"');
86        six_hex(c.character_value);
87    } else if (c.origin_value == xetexnum_mathcode) {
88        int m;
89        m = (c.class_value + (c.family_value * 8)) * 2097152 +
90            c.character_value;
91        print_int(m);
92    } else {
93        print_char('"');
94	if (c.class_value) {
95	    print_hex_digit(c.class_value);
96            print_hex_digit(c.family_value);
97            two_hex(c.character_value);
98        } else if (c.family_value) {
99            print_hex_digit(c.family_value);
100            two_hex(c.character_value);
101        } else if (c.character_value >= 16) {
102            two_hex(c.character_value);
103        } else {
104            print_hex_digit(c.character_value);
105        }
106    }
107}
108
109@ @c
110static void show_mathcode(int n)
111{
112    mathcodeval c = get_math_code(n);
113    if (c.origin_value == xetex_mathcode) {
114        tprint_esc("Umathcode");
115    } else if (c.origin_value == xetexnum_mathcode) {
116        tprint_esc("Umathcodenum");
117    } else {
118        tprint_esc("mathcode");
119    }
120    print_int(n);
121    print_char('=');
122    show_mathcode_value(c);
123}
124
125@ @c
126static void unsavemathcode(quarterword gl)
127{
128    sa_stack_item st;
129    if (mathcode_head->stack == NULL)
130        return;
131    while (mathcode_head->stack_ptr > 0 &&
132           abs(mathcode_head->stack[mathcode_head->stack_ptr].level)
133           >= (int) gl) {
134        st = mathcode_head->stack[mathcode_head->stack_ptr];
135        if (st.level > 0) {
136            rawset_sa_item(mathcode_head, st.code, st.value);
137            /* now do a trace message, if requested */
138            if (int_par(tracing_restores_code) > 0) {
139                begin_diagnostic();
140                print_char('{');
141                tprint("restoring");
142                print_char(' ');
143                show_mathcode(st.code);
144                print_char('}');
145                end_diagnostic(false);
146            }
147        }
148        (mathcode_head->stack_ptr)--;
149    }
150}
151
152@ @c
153void set_math_code(int n,
154                   int commandorigin,
155                   int mathclass,
156                   int mathfamily, int mathcharacter, quarterword level)
157{
158    mathcodeval d;
159    d.origin_value = commandorigin;
160    d.class_value = mathclass;
161    d.family_value = mathfamily;
162    d.character_value = mathcharacter;
163    if (mathcode_heapptr == mathcode_heapsize) {
164        mathcode_heapsize += MATHCODEHEAP;
165        mathcode_heap =
166            Mxrealloc_array(mathcode_heap, mathcodeval, mathcode_heapsize);
167    }
168    mathcode_heap[mathcode_heapptr] = d;
169    set_sa_item(mathcode_head, n, (sa_tree_item) mathcode_heapptr, level);
170    mathcode_heapptr++;
171    if (int_par(tracing_assigns_code) > 0) {
172        begin_diagnostic();
173        print_char('{');
174        tprint("assigning");
175        print_char(' ');
176        show_mathcode(n);
177        print_char('}');
178        end_diagnostic(false);
179    }
180}
181
182@ @c
183mathcodeval get_math_code(int n)
184{
185    unsigned int ret;
186    ret = get_sa_item(mathcode_head, n);
187    if (ret == MATHCODEDEFAULT) {
188        mathcodeval d;
189        d.class_value = 0;
190        d.family_value = 0;
191        d.origin_value = (n < 256 ? tex_mathcode : xetex_mathcode);
192        d.character_value = n;
193        return d;
194    } else {
195        return mathcode_heap[ret];
196    }
197}
198
199
200@ @c
201int get_math_code_num(int n, boolean compat)
202{
203    mathcodeval mval;
204    mval = get_math_code(n);
205    if (compat) { /* \.{\\the\\mathcode} */
206        if (mval.class_value > 8
207            || mval.family_value > 15
208            || mval.character_value > 255) {
209            print_err("Extended mathchar used as mathchar");
210            help2("A mathchar number must be between 0 and \"8000.",
211                  "I changed this one to zero.");
212            int_error(get_math_code_num(n, false));
213            return 0;
214        } else
215            return mval.class_value * 4096 + mval.family_value * 256 + mval.character_value;
216    } else { /* \.{\\the\\Umathcodenum} */
217        return (mval.class_value + (mval.family_value * 8)) * (65536 * 32) + mval.character_value;
218    }
219    return 0;
220}
221
222@ @c
223static void initializemathcode(void)
224{
225    mathcode_head = new_sa_tree(MATHCODESTACK, MATHCODEDEFAULT);
226    mathcode_heap = Mxmalloc_array(mathcodeval, MATHCODEHEAP);
227}
228
229@ @c
230static void dumpmathcode(void)
231{
232    int k;
233    mathcodeval d;
234    dump_sa_tree(mathcode_head);
235    dump_int(mathcode_heapsize);
236    dump_int(mathcode_heapptr);
237    for (k = 0; k < mathcode_heapptr; k++) {
238        d = mathcode_heap[k];
239        dump_int(d.origin_value);
240        dump_int(d.class_value);
241        dump_int(d.family_value);
242        dump_int(d.character_value);
243    }
244}
245
246static void undumpmathcode(void)
247{
248    int k, x;
249    mathcodeval d;
250    mathcode_head = undump_sa_tree();
251    undump_int(mathcode_heapsize);
252    undump_int(mathcode_heapptr);
253    mathcode_heap = Mxmalloc_array(mathcodeval, mathcode_heapsize);
254    for (k = 0; k < mathcode_heapptr; k++) {
255        undump_int(x);
256        d.origin_value = x;
257        undump_int(x);
258        d.class_value = x;
259        undump_int(x);
260        d.family_value = x;
261        undump_int(x);
262        d.character_value = x;
263        mathcode_heap[k] = d;
264    }
265    d.origin_value = 0;
266    d.class_value = 0;
267    d.family_value = 0;
268    d.character_value = 0;
269    for (k = mathcode_heapptr; k < mathcode_heapsize; k++) {
270        mathcode_heap[k] = d;
271    }
272}
273
274@ @c
275static void show_delcode(int n)
276{
277    delcodeval c;
278    c = get_del_code(n);
279    if (c.origin_value == tex_mathcode) {
280        tprint_esc("delcode");
281    } else if (c.origin_value == xetex_mathcode) {
282        tprint_esc("Udelcode");
283    } else if (c.origin_value == xetexnum_mathcode) {
284        tprint_esc("Udelcodenum");
285    }
286    print_int(n);
287    print_char('=');
288    if (c.small_family_value < 0) {
289        print_char('-');
290        print_char('1');
291    } else {
292        if (c.origin_value == tex_mathcode) {
293            print_char('"');
294            print_hex_digit(c.small_family_value);
295            two_hex(c.small_character_value);
296            print_hex_digit(c.large_family_value);
297            two_hex(c.large_character_value);
298        } else if (c.origin_value == xetex_mathcode) {
299            print_char('"');
300            two_hex(c.small_family_value);
301            six_hex(c.small_character_value);
302        } else if (c.origin_value == xetexnum_mathcode) {
303            int m;
304            m = c.small_family_value * 2097152 + c.small_character_value;
305            print_int(m);
306        }
307    }
308}
309
310
311
312@ TODO: clean up the heap
313@c
314static void unsavedelcode(quarterword gl)
315{
316    sa_stack_item st;
317    if (delcode_head->stack == NULL)
318        return;
319    while (delcode_head->stack_ptr > 0 &&
320           abs(delcode_head->stack[delcode_head->stack_ptr].level)
321           >= (int) gl) {
322        st = delcode_head->stack[delcode_head->stack_ptr];
323        if (st.level > 0) {
324            rawset_sa_item(delcode_head, st.code, st.value);
325            /* now do a trace message, if requested */
326            if (int_par(tracing_restores_code) > 0) {
327                begin_diagnostic();
328                print_char('{');
329                tprint("restoring");
330                print_char(' ');
331                show_delcode(st.code);
332                print_char('}');
333                end_diagnostic(false);
334            }
335        }
336        (delcode_head->stack_ptr)--;
337    }
338
339}
340
341@ @c
342void set_del_code(int n,
343                  int commandorigin,
344                  int smathfamily,
345                  int smathcharacter,
346                  int lmathfamily, int lmathcharacter, quarterword gl)
347{
348    delcodeval d;
349    d.class_value = 0;
350    d.origin_value = commandorigin;
351    d.small_family_value = smathfamily;
352    d.small_character_value = smathcharacter;
353    d.large_family_value = lmathfamily;
354    d.large_character_value = lmathcharacter;
355    if (delcode_heapptr == delcode_heapsize) {
356        delcode_heapsize += DELCODEHEAP;
357        delcode_heap =
358            Mxrealloc_array(delcode_heap, delcodeval, delcode_heapsize);
359    }
360    delcode_heap[delcode_heapptr] = d;
361    set_sa_item(delcode_head, n, (sa_tree_item) delcode_heapptr, gl);
362    if (int_par(tracing_assigns_code) > 0) {
363        begin_diagnostic();
364        print_char('{');
365        tprint("assigning");
366        print_char(' ');
367        show_delcode(n);
368        print_char('}');
369        end_diagnostic(false);
370    }
371    delcode_heapptr++;
372}
373
374@ @c
375delcodeval get_del_code(int n)
376{
377    unsigned ret;
378    ret = get_sa_item(delcode_head, n);
379    if (ret == DELCODEDEFAULT) {
380        delcodeval d;
381        d.class_value = 0;
382        d.origin_value = tex_mathcode;
383        d.small_family_value = -1;
384        d.small_character_value = 0;
385        d.large_family_value = 0;
386        d.large_character_value = 0;
387        return d;
388    } else {
389        return delcode_heap[ret];
390    }
391}
392
393@ this really only works for old-style delcodes!
394
395@c
396int get_del_code_num(int n)
397{
398    unsigned ret;
399    ret = get_sa_item(delcode_head, n);
400    if (ret == DELCODEDEFAULT) {
401        return -1;
402    } else {
403        delcodeval d = delcode_heap[ret];
404        if (d.origin_value == tex_mathcode) {
405            return ((d.small_family_value * 256 +
406                     d.small_character_value) * 4096 +
407                    (d.large_family_value * 256) + d.large_character_value);
408        } else {
409            return -1;
410        }
411    }
412}
413
414@ @c
415static void initializedelcode(void)
416{
417    delcode_head = new_sa_tree(DELCODESTACK, DELCODEDEFAULT);
418    delcode_heap = Mxmalloc_array(delcodeval, DELCODEHEAP);
419}
420
421@ @c
422static void dumpdelcode(void)
423{
424    int k;
425    delcodeval d;
426    dump_sa_tree(delcode_head);
427    dump_int(delcode_heapsize);
428    dump_int(delcode_heapptr);
429    for (k = 0; k < delcode_heapptr; k++) {
430        d = delcode_heap[k];
431        dump_int(d.origin_value);
432        dump_int(d.class_value);
433        dump_int(d.small_family_value);
434        dump_int(d.small_character_value);
435        dump_int(d.large_family_value);
436        dump_int(d.large_character_value);
437    }
438}
439
440static void undumpdelcode(void)
441{
442    int k;
443    delcodeval d;
444    delcode_head = undump_sa_tree();
445    undump_int(delcode_heapsize);
446    undump_int(delcode_heapptr);
447    delcode_heap = Mxmalloc_array(delcodeval, delcode_heapsize);
448    for (k = 0; k < delcode_heapptr; k++) {
449        undump_int(d.origin_value);
450        undump_int(d.class_value);
451        undump_int(d.small_family_value);
452        undump_int(d.small_character_value);
453        undump_int(d.large_family_value);
454        undump_int(d.large_character_value);
455        delcode_heap[k] = d;
456    }
457    d.origin_value = tex_mathcode;
458    d.class_value = 0;
459    d.small_family_value = -1;
460    d.small_character_value = 0;
461    d.large_family_value = 0;
462    d.large_character_value = 0;
463    for (k = delcode_heapptr; k < delcode_heapsize; k++) {
464        delcode_heap[k] = d;
465    }
466}
467
468@ @c
469void unsave_math_codes(quarterword grouplevel)
470{
471    unsavemathcode(grouplevel);
472    unsavedelcode(grouplevel);
473}
474
475@ @c
476void initialize_math_codes(void)
477{
478    initializemathcode();
479    initializedelcode();
480}
481
482@ @c
483void free_math_codes(void)
484{
485    destroy_sa_tree(mathcode_head);
486    xfree(mathcode_heap);
487    destroy_sa_tree(delcode_head);
488    xfree(delcode_heap);
489}
490
491@ @c
492void dump_math_codes(void)
493{
494    dumpmathcode();
495    dumpdelcode();
496}
497
498void undump_math_codes(void)
499{
500    undumpmathcode();
501    undumpdelcode();
502}
503