summaryrefslogtreecommitdiff
path: root/source/luametatex/source/tex/texmarks.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/luametatex/source/tex/texmarks.c')
-rw-r--r--source/luametatex/source/tex/texmarks.c346
1 files changed, 346 insertions, 0 deletions
diff --git a/source/luametatex/source/tex/texmarks.c b/source/luametatex/source/tex/texmarks.c
new file mode 100644
index 000000000..060c5f579
--- /dev/null
+++ b/source/luametatex/source/tex/texmarks.c
@@ -0,0 +1,346 @@
+/*
+ See license.txt in the root of this project.
+*/
+
+# include "luametatex.h"
+
+/*tex
+
+ A control sequence that has been |\def|'ed by the user is expanded by \TEX's |macro_call|
+ procedure.
+
+ Before we get into the details of |macro_call|, however, let's consider the treatment of
+ primitives like |\topmark|, since they are essentially macros without parameters. The token
+ lists for such marks are kept in five global arrays of pointers; we refer to the individual
+ entries of these arrays by symbolic macros |top_mark|, etc. The value of |top_mark (x)|, etc.
+ is either |null| or a pointer to the reference count of a token list.
+
+ The variable |biggest_used_mark| is an aid to try and keep the code somehwat efficient without
+ too much extra work: it registers the highest mark class ever instantiated by the user, so the
+ loops in |fire_up| and |vsplit| do not have to traverse the full range |0 .. biggest_mark|.
+
+ Watch out: zero is always valid and the good old single mark!
+
+ Todo: class -> index
+
+*/
+
+mark_state_info lmt_mark_state = {
+ .data = NULL,
+ .min_used = -1,
+ .max_used = -1,
+ .mark_data = {
+ .minimum = min_mark_size,
+ .maximum = max_mark_size,
+ .size = memory_data_unset,
+ .step = stp_mark_size,
+ .allocated = 0,
+ .itemsize = sizeof(mark_record),
+ .top = 0,
+ .ptr = 0,
+ .initial = memory_data_unset,
+ .offset = 0,
+ },
+};
+
+void tex_initialize_marks(void)
+{
+ /* allocated: minimum + 1 */
+ lmt_mark_state.data = aux_allocate_clear_array(sizeof(mark_record), lmt_mark_state.mark_data.minimum, 1);
+ if (lmt_mark_state.data) {
+ lmt_mark_state.mark_data.allocated = sizeof(mark_record) * lmt_mark_state.mark_data.minimum;
+ lmt_mark_state.mark_data.top = lmt_mark_state.mark_data.minimum;
+ }
+}
+
+void tex_reset_mark(halfword m)
+{
+ if (m >= lmt_mark_state.mark_data.top) {
+ int step = lmt_mark_state.mark_data.step;
+ int size = lmt_mark_state.mark_data.top;
+ /* regular stepwise bump */
+ while (m >= size) {
+ size += step;
+ }
+ /* last resort */
+ if (size > lmt_mark_state.mark_data.maximum) {
+ size = m;
+ }
+ if (size <= lmt_mark_state.mark_data.maximum) {
+ mark_record *tmp = aux_reallocate_array(lmt_mark_state.data, sizeof(mark_record), (size_t) size, 1);
+ if (tmp) {
+ lmt_mark_state.data = tmp;
+ memset(&lmt_mark_state.data[lmt_mark_state.mark_data.top], 0, sizeof(mark_record) * (size - lmt_mark_state.mark_data.top));
+ lmt_mark_state.mark_data.top = size;
+ lmt_mark_state.mark_data.allocated = sizeof(mark_record) * ((size_t) size);
+ } else {
+ tex_overflow_error("marks", size);
+ }
+ } else {
+ tex_overflow_error("marks", lmt_mark_state.mark_data.maximum);
+ }
+ }
+ if (m > lmt_mark_state.mark_data.ptr) {
+ lmt_mark_state.mark_data.ptr = m;
+ }
+ tex_wipe_mark(m);
+}
+
+halfword tex_get_mark(halfword m, halfword s)
+{
+ if (s >= 0 && s <= last_unique_mark_code) {
+ return lmt_mark_state.data[m][s];
+ } else {
+ return null;
+ }
+}
+
+void tex_set_mark(halfword m, halfword s, halfword v)
+{
+ if (s >= 0 && s <= last_unique_mark_code) {
+ if (lmt_mark_state.data[m][s]) {
+ tex_delete_token_reference(lmt_mark_state.data[m][s]);
+ }
+ if (v) {
+ tex_add_token_reference(v);
+ }
+ lmt_mark_state.data[m][s] = v;
+ }
+}
+
+int tex_valid_mark(halfword m) {
+ if (m >= lmt_mark_state.mark_data.top) {
+ tex_reset_mark(m);
+ }
+ return m < lmt_mark_state.mark_data.top;
+}
+
+halfword tex_new_mark(quarterword subtype, halfword class, halfword ptr)
+{
+ halfword mark = tex_new_node(mark_node, subtype);
+ mark_index(mark) = class;
+ mark_ptr(mark) = ptr;
+ if (lmt_mark_state.min_used < 0) {
+ lmt_mark_state.min_used = class;
+ lmt_mark_state.max_used = class;
+ } else {
+ if (class < lmt_mark_state.min_used) {
+ lmt_mark_state.min_used = class;
+ }
+ if (class > lmt_mark_state.max_used) {
+ lmt_mark_state.max_used = class;
+ }
+ }
+ tex_set_mark(class, current_marks_code, ptr);
+ return mark;
+}
+
+static void tex_aux_print_mark(const char *s, halfword t)
+{
+ if (t) {
+ tex_print_token_list(s, token_link(t));
+ }
+}
+
+void tex_show_marks()
+{
+ if (tracing_marks_par > 0 && lmt_mark_state.min_used >= 0) {
+ tex_begin_diagnostic();
+ for (halfword m = lmt_mark_state.min_used; m <= lmt_mark_state.max_used; m++) {
+ if (tex_has_mark(m)) {
+ tex_print_format("[mark: class %i, page state]",m);
+ tex_aux_print_mark("top", tex_get_mark(m, top_marks_code));
+ tex_aux_print_mark("first", tex_get_mark(m, first_marks_code));
+ tex_aux_print_mark("bot", tex_get_mark(m, bot_marks_code));
+ tex_aux_print_mark("split first", tex_get_mark(m, split_first_marks_code));
+ tex_aux_print_mark("split bot", tex_get_mark(m, split_bot_marks_code));
+ tex_aux_print_mark("current", tex_get_mark(m, current_marks_code));
+ }
+ }
+ tex_end_diagnostic();
+ }
+}
+
+void tex_update_top_marks()
+{
+ if (lmt_mark_state.min_used >= 0) {
+ for (halfword m = lmt_mark_state.min_used; m <= lmt_mark_state.max_used; m++) {
+ halfword bot = tex_get_mark(m, bot_marks_code);
+ if (bot) {
+ tex_set_mark(m, top_marks_code, bot);
+ if (tracing_marks_par > 1) {
+ tex_begin_diagnostic();
+ tex_print_format("[mark: class %i, top becomes bot]", m);
+ tex_aux_print_mark(NULL, bot);
+ tex_end_diagnostic();
+ }
+ tex_delete_mark(m, first_marks_code);
+ }
+ }
+ }
+}
+
+void tex_update_first_and_bot_mark(halfword n)
+{
+ halfword index = mark_index(n);
+ halfword ptr = mark_ptr(n);
+ if (node_subtype(n) == reset_mark_value_code) {
+ /*tex Work in progress. */
+ if (tracing_marks_par > 1) {
+ tex_begin_diagnostic();
+ tex_print_format("[mark: index %i, reset]", index);
+ tex_end_diagnostic();
+ }
+ tex_reset_mark(index);
+ } else {
+ /*tex Update the values of |first_mark| and |bot_mark|. */
+ halfword first = tex_get_mark(index, first_marks_code);
+ if (! first) {
+ tex_set_mark(index, first_marks_code, ptr);
+ if (tracing_marks_par > 1) {
+ tex_begin_diagnostic();
+ tex_print_format("[mark: index %i, first becomes mark]", index);
+ tex_aux_print_mark(NULL, ptr);
+ tex_end_diagnostic();
+ }
+ }
+ tex_set_mark(index, bot_marks_code, ptr);
+ if (tracing_marks_par > 1) {
+ tex_begin_diagnostic();
+ tex_print_format("[mark: index %i, bot becomes mark]", index);
+ tex_aux_print_mark(NULL, ptr);
+ tex_end_diagnostic();
+ }
+ }
+}
+
+void tex_update_first_marks(void)
+{
+ if (lmt_mark_state.min_used >= 0) {
+ for (halfword m = lmt_mark_state.min_used; m <= lmt_mark_state.max_used; m++) {
+ halfword top = tex_get_mark(m, top_marks_code);
+ halfword first = tex_get_mark(m, first_marks_code);
+ if (top && ! first) {
+ tex_set_mark(m, first_marks_code, top);
+ if (tracing_marks_par > 1) {
+ tex_begin_diagnostic();
+ tex_print_format("[mark: class %i, first becomes top]", m);
+ tex_aux_print_mark(NULL, top);
+ tex_end_diagnostic();
+ }
+ }
+ }
+ }
+}
+
+void tex_update_split_mark(halfword n)
+{
+ halfword index = mark_index(n);
+ halfword ptr = mark_ptr(n);
+ if (node_subtype(n) == reset_mark_value_code) {
+ tex_reset_mark(index);
+ } else {
+ if (tex_get_mark(index, split_first_marks_code)) {
+ tex_set_mark(index, split_bot_marks_code, ptr);
+ if (tracing_marks_par > 1) {
+ tex_begin_diagnostic();
+ tex_print_format("[mark: index %i, split bot becomes mark]", index);
+ tex_aux_print_mark(NULL, tex_get_mark(index, split_bot_marks_code));
+ tex_end_diagnostic();
+ }
+ } else {
+ tex_set_mark(index, split_first_marks_code, ptr);
+ tex_set_mark(index, split_bot_marks_code, ptr);
+ if (tracing_marks_par > 1) {
+ tex_begin_diagnostic();
+ tex_print_format("[mark: index %i, split first becomes mark]", index);
+ tex_aux_print_mark(NULL, tex_get_mark(index, split_first_marks_code));
+ tex_print_format("[mark: index %i, split bot becomes split first]", index);
+ tex_aux_print_mark(NULL, tex_get_mark(index, split_bot_marks_code));
+ tex_end_diagnostic();
+ }
+ }
+ }
+}
+
+
+void tex_delete_mark(halfword m, int what)
+{
+ switch (what) {
+ case top_mark_code : what = top_marks_code;
+ case first_mark_code : what = first_marks_code;
+ case bot_mark_code : what = bot_marks_code;
+ case split_first_mark_code: what = split_first_marks_code;
+ case split_bot_mark_code : what = split_bot_marks_code;
+ }
+ tex_set_mark(m, what, null);
+}
+
+halfword tex_get_some_mark(halfword chr, halfword val)
+{
+ switch (chr) {
+ case top_mark_code : val = top_marks_code;
+ case first_mark_code : val = first_marks_code;
+ case bot_mark_code : val = bot_marks_code;
+ case split_first_mark_code: val = split_first_marks_code;
+ case split_bot_mark_code : val = split_bot_marks_code;
+ }
+ return tex_get_mark(val, chr);
+}
+
+void tex_wipe_mark(halfword m)
+{
+ for (int what = 0; what <= last_unique_mark_code; what++) {
+ tex_set_mark(m, what, null);
+ }
+}
+
+int tex_has_mark(halfword m)
+{
+ for (int what = 0; what <= last_unique_mark_code; what++) {
+ if (lmt_mark_state.data[m][what]) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*tex
+
+ The |make_mark| procedure has been renamed, because if the current chr code is 1, then the
+ actual command was |\clearmarks|, which did not generate a mark node but instead destroyed the
+ current mark related tokenlists. We now have proper reset nodes.
+
+*/
+
+void tex_run_mark(void)
+{
+ halfword class = 0;
+ halfword code = cur_chr;
+ switch (code) {
+ case set_marks_code:
+ case clear_marks_code:
+ case flush_marks_code:
+ class = tex_scan_mark_number();
+ break;
+ }
+ if (tex_valid_mark(class)) {
+ quarterword subtype = set_mark_value_code;
+ halfword ptr = null;
+ switch (code) {
+ case set_marks_code:
+ case set_mark_code:
+ ptr = tex_scan_toks_expand(0, NULL, 0);
+ break;
+ case clear_marks_code:
+ tex_wipe_mark(class);
+ return;
+ case flush_marks_code:
+ subtype = reset_mark_value_code;
+ break;
+ }
+ tex_tail_append(tex_new_mark(subtype, class, ptr));
+ } else {
+ /* error already issued */
+ }
+}