diff options
Diffstat (limited to 'source/luametatex/source/tex/texmathcodes.c')
-rw-r--r-- | source/luametatex/source/tex/texmathcodes.c | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/source/luametatex/source/tex/texmathcodes.c b/source/luametatex/source/tex/texmathcodes.c new file mode 100644 index 000000000..7d80eac19 --- /dev/null +++ b/source/luametatex/source/tex/texmathcodes.c @@ -0,0 +1,347 @@ +/* + See license.txt in the root of this project. +*/ + +# include "luametatex.h" + +/*tex + + We support the traditional math codes as well as larger ones suitable for \UNICODE\ input and + fonts. + +*/ + +/*tex the |0xFFFFFFFF| is a flag value. */ + +# define MATHCODESTACK 8 +# define MATHCODEDEFAULT 0xFFFFFFFF +# define MATHCODEACTIVE 0xFFFFFFFE + +/*tex Delcodes are also went larger. */ + +# define DELCODESTACK 4 +# define DELCODEDEFAULT 0xFFFFFFFF + +typedef struct mathcode_state_info { + sa_tree mathcode_head; + sa_tree delcode_head; +} mathcode_state_info; + +static mathcode_state_info lmt_mathcode_state = { + .mathcode_head = NULL, + .delcode_head = NULL, +}; + +/*tex + + We now get lots of helpers for definitions and printing. The storage model that we use is + different because we can have many more so we need to be sparse. Therefore we use trees. + +*/ + +# define print_hex_digit_one(A) do { \ + if ((A) >= 10) { \ + tex_print_char('A' + (A) - 10); \ + } else { \ + tex_print_char('0' + (A)); \ + } \ +} while (0) + +# define print_hex_digit_two(A) do { \ + print_hex_digit_one((A) / 16); \ + print_hex_digit_one((A) % 16); \ +} while (0) + +# define print_hex_digit_four(A) do { \ + print_hex_digit_two((A) / 256); \ + print_hex_digit_two((A) % 256); \ +} while (0) + +# define print_hex_digit_six(A) do { \ + print_hex_digit_two( (A) / 65536); \ + print_hex_digit_two(((A) % 65536) / 256); \ + print_hex_digit_two( (A) % 256); \ +} while (0) + +/* 0xFFFFF is plenty for math */ + +mathcodeval tex_mathchar_from_integer(int value, int extcode) +{ + mathcodeval mval; + if (extcode == tex_mathcode) { + mval.class_value = math_old_class_part(value); + mval.family_value = math_old_family_part(value); + mval.character_value = math_old_character_part(value); + } else { + mval.class_value = math_class_part(value); + mval.family_value = math_family_part(value); + mval.character_value = math_character_part(value); + } + return mval; +} + +mathcodeval tex_mathchar_from_spec(int value) +{ + mathcodeval mval = { 0, 0, 0 }; + if (value) { + mval.class_value = math_spec_class(value); + mval.family_value = math_spec_family(value); + mval.character_value = math_spec_character(value); + } + return mval; +} + +void tex_show_mathcode_value(mathcodeval mval, int extcode) +{ + tex_print_char('"'); + if (extcode == tex_mathcode) { + print_hex_digit_one(math_old_class_mask(mval.class_value)); + print_hex_digit_one(math_old_family_mask(mval.family_value)); + print_hex_digit_two(math_old_character_mask(mval.character_value)); + } else { + print_hex_digit_two(mval.class_value); + tex_print_char('"'); + print_hex_digit_two(mval.family_value); + tex_print_char('"'); + print_hex_digit_six(mval.character_value); + } +} + +static void tex_aux_show_mathcode(int n) +{ + mathcodeval mval = tex_get_math_code(n); + tex_print_str_esc("Umathcode"); + tex_print_int(n); + tex_print_char('='); + tex_show_mathcode_value(mval, umath_mathcode); +} + +static void tex_aux_unsave_mathcode(int level) +{ + if (lmt_mathcode_state.mathcode_head->stack) { + 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) { + sa_stack_item item = lmt_mathcode_state.mathcode_head->stack[lmt_mathcode_state.mathcode_head->sa_stack_ptr]; + if (item.level > 0) { + sa_rawset_item_4(lmt_mathcode_state.mathcode_head, item.code, item.value_1); + if (tracing_restores_par > 1) { + tex_begin_diagnostic(); + tex_print_str("{restoring "); + tex_aux_show_mathcode(item.code); + tex_print_char('}'); + tex_end_diagnostic(); + } + } + (lmt_mathcode_state.mathcode_head->sa_stack_ptr)--; + } + } +} + +mathcodeval tex_no_math_code(void) +{ + return (mathcodeval) { 0, 0, 0 }; +} + +void tex_set_math_code(int n, mathcodeval v, int level) +{ + sa_tree_item item; + if (v.class_value == active_math_class_value && v.family_value == 0 && v.character_value == 0) { + item.uint_value = MATHCODEACTIVE; + } else if (v.class_value == 0 && v.family_value == 0) { + /*tex This is rather safe because we don't decide on it. */ + item.uint_value = MATHCODEDEFAULT; + } else { + item.math_code_value.class_value = v.class_value; + item.math_code_value.family_value = v.family_value; + item.math_code_value.character_value = v.character_value; + } + sa_set_item_4(lmt_mathcode_state.mathcode_head, n, item, level); + if (tracing_assigns_par > 1) { + tex_begin_diagnostic(); + tex_print_str("{assigning "); + tex_aux_show_mathcode(n); + tex_print_char('}'); + tex_end_diagnostic(); + } +} + +mathcodeval tex_get_math_code(int n) +{ + sa_tree_item item = sa_get_item_4(lmt_mathcode_state.mathcode_head, n); + mathcodeval m = { 0, 0, 0 }; + if (item.uint_value == MATHCODEDEFAULT) { + m.character_value = n; + } else if (item.uint_value == MATHCODEACTIVE) { + m.class_value = active_math_class_value; + } else if (item.math_code_value.class_value == active_math_class_value) { + m.class_value = active_math_class_value; + m.character_value = n; + } else { + m.class_value = (short) item.math_code_value.class_value; + m.family_value = (short) item.math_code_value.family_value; + m.character_value = item.math_code_value.character_value; + } + return m; +} + +int tex_get_math_code_number(int n) /* should be unsigned */ +{ + mathcodeval d = tex_get_math_code(n); + return math_packed_character(d.class_value, d.family_value, d.character_value); +} + +static void tex_aux_initialize_mathcode(void) +{ + lmt_mathcode_state.mathcode_head = sa_new_tree(MATHCODESTACK, 4, (sa_tree_item) { .uint_value = MATHCODEDEFAULT }); +} + +static void tex_aux_dump_mathcode(dumpstream f) +{ + sa_dump_tree(f, lmt_mathcode_state.mathcode_head); +} + +static void tex_aux_undump_mathcode(dumpstream f) +{ + lmt_mathcode_state.mathcode_head = sa_undump_tree(f); +} + +static void tex_aux_show_delcode(int n) +{ + delcodeval dval = tex_get_del_code(n); + tex_print_str_esc("Udelcode"); + tex_print_int(n); + tex_print_char('='); + if (tex_has_del_code(dval)) { + tex_print_char('"'); + print_hex_digit_two(dval.small.family_value); + print_hex_digit_six(dval.small.character_value); + } else { + tex_print_str("-1"); + } +} + +static void tex_aux_unsave_delcode(int level) +{ + if (lmt_mathcode_state.delcode_head->stack) { + 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) { + sa_stack_item item = lmt_mathcode_state.delcode_head->stack[lmt_mathcode_state.delcode_head->sa_stack_ptr]; + if (item.level > 0) { + sa_rawset_item_8(lmt_mathcode_state.delcode_head, item.code, item.value_1, item.value_2); + if (tracing_restores_par > 1) { + tex_begin_diagnostic(); + tex_print_str("{restoring "); + tex_aux_show_delcode(item.code); + tex_print_char('}'); + tex_end_diagnostic(); + } + } + (lmt_mathcode_state.delcode_head->sa_stack_ptr)--; + } + } +} + +void tex_set_del_code(int n, delcodeval v, int level) +{ + sa_tree_item v1, v2; /* seldom all zero */ + v1.math_code_value.class_value = v.small.class_value; + v1.math_code_value.family_value = v.small.family_value; + v1.math_code_value.character_value = v.small.character_value; + v2.math_code_value.class_value = v.large.class_value; + v2.math_code_value.family_value = v.large.family_value; + v2.math_code_value.character_value = v.large.character_value; + /*tex Always global! */ + sa_set_item_8(lmt_mathcode_state.delcode_head, n, v1, v2, level); + if (tracing_assigns_par > 1) { + tex_begin_diagnostic(); + tex_print_str("{assigning "); + tex_aux_show_delcode(n); + tex_print_char('}'); + tex_end_diagnostic(); + } +} + +int tex_has_del_code(delcodeval d) +{ + return d.small.family_value >= 0; +} + +delcodeval tex_no_del_code(void) +{ + return (delcodeval) { { 0, -1, 0 }, { 0, 0, 0} }; +} + +delcodeval tex_get_del_code(int n) +{ + sa_tree_item v2; + sa_tree_item v1 = sa_get_item_8(lmt_mathcode_state.delcode_head, n, &v2); + delcodeval d = { { 0, -1, 0 }, { 0, 0, 0} }; + if (v1.uint_value != DELCODEDEFAULT) { + d.small.class_value = (short) v1.math_code_value.class_value; + d.small.family_value = (short) v1.math_code_value.family_value; + d.small.character_value = v1.math_code_value.character_value; + d.large.class_value = (short) v2.math_code_value.class_value; + d.large.family_value = (short) v2.math_code_value.family_value; + d.large.character_value = v2.math_code_value.character_value; + } + return d; +} + +/*tex This really only works for old-style delcodes! */ + +int tex_get_del_code_number(int n) +{ + delcodeval d = tex_get_del_code(n); + if (tex_has_del_code(d)) { + return ((d.small.family_value * 256 + d.small.character_value) * 4096 + + (d.large.family_value * 256) + d.large.character_value); + } else { + return -1; + } +} + +static void tex_aux_initialize_delcode(void) +{ + lmt_mathcode_state.delcode_head = sa_new_tree(DELCODESTACK, 8, (sa_tree_item) { .uint_value = DELCODEDEFAULT }); +} + +static void tex_aux_dump_delcode(dumpstream f) +{ + sa_dump_tree(f, lmt_mathcode_state.delcode_head); +} + +static void tex_aux_undump_delcode(dumpstream f) +{ + lmt_mathcode_state.delcode_head = sa_undump_tree(f); +} + +void tex_unsave_math_codes(int grouplevel) +{ + tex_aux_unsave_mathcode(grouplevel); + tex_aux_unsave_delcode(grouplevel); +} + +void tex_initialize_math_codes(void) +{ + tex_aux_initialize_mathcode(); + tex_aux_initialize_delcode(); + /*tex This might become optional: */ + tex_set_default_math_codes(); + tex_set_del_code('.', (delcodeval) { { 0, 0, 0, }, { 0, 0, 0 } }, level_one); +} + +void tex_free_math_codes(void) +{ + sa_destroy_tree(lmt_mathcode_state.mathcode_head); + sa_destroy_tree(lmt_mathcode_state.delcode_head); +} + +void tex_dump_math_codes(dumpstream f) +{ + tex_aux_dump_mathcode(f); + tex_aux_dump_delcode(f); +} + +void tex_undump_math_codes(dumpstream f) +{ + tex_aux_undump_mathcode(f); + tex_aux_undump_delcode(f); +} |