1
4
5# include "luametatex.h"
6
7
8
9# define page_goal lmt_page_builder_state.goal
10
11
55
56const char *tex_string_mode(int m)
57{
58 switch (m) {
59 case nomode : return "no mode";
60 case vmode : return "vertical mode";
61 case hmode : return "horizontal mode";
62 case mmode : return "display math mode";
63 case internal_vmode : return "internal vertical mode";
64 case restricted_hmode: return "restricted horizontal mode";
65 case inline_mmode : return "inline math mode";
66 default : return "unknown mode";
67 }
68}
69
70
146
147nest_state_info lmt_nest_state = {
148 .nest = NULL,
149 .nest_data = {
150 .minimum = min_nest_size,
151 .maximum = max_nest_size,
152 .size = siz_nest_size,
153 .step = stp_nest_size,
154 .allocated = 0,
155 .itemsize = sizeof(list_state_record),
156 .top = 0,
157 .ptr = 0,
158 .initial = memory_data_unset,
159 .offset = 0,
160 .extra = 0,
161 },
162 .shown_mode = 0,
163 .math_mode = 0,
164};
165
166
176
177# define reserved_nest_slots 0
178
179void tex_initialize_nest_state(void)
180{
181 int size = lmt_nest_state.nest_data.minimum;
182 lmt_nest_state.nest = aux_allocate_clear_array(sizeof(list_state_record), size, reserved_nest_slots);
183 if (lmt_nest_state.nest) {
184 lmt_nest_state.nest_data.allocated = size;
185 } else {
186 tex_overflow_error("nest", size);
187 }
188}
189
190static int tex_aux_room_on_nest_stack(void)
191{
192 int top = lmt_nest_state.nest_data.ptr;
193 if (top > lmt_nest_state.nest_data.top) {
194 lmt_nest_state.nest_data.top = top;
195 if (top > lmt_nest_state.nest_data.allocated) {
196 list_state_record *tmp = NULL;
197 top = lmt_nest_state.nest_data.allocated + lmt_nest_state.nest_data.step;
198 if (top > lmt_nest_state.nest_data.size) {
199 top = lmt_nest_state.nest_data.size;
200 }
201 if (top > lmt_nest_state.nest_data.allocated) {
202 lmt_nest_state.nest_data.allocated = top;
203 tmp = aux_reallocate_array(lmt_nest_state.nest, sizeof(list_state_record), top, reserved_nest_slots);
204 lmt_nest_state.nest = tmp;
205 }
206 lmt_run_memory_callback("nest", tmp ? 1 : 0);
207 if (! tmp) {
208 tex_overflow_error("nest", top);
209 return 0;
210 }
211 }
212 }
213 return 1;
214}
215
216void tex_initialize_nesting(void)
217{
218 lmt_nest_state.nest_data.ptr = 0;
219 lmt_nest_state.nest_data.top = 0;
220# if 1
221 lmt_nest_state.shown_mode = 0;
222 lmt_nest_state.math_mode = 0;
223 cur_list.mode = vmode;
224 cur_list.head = contribute_head;
225 cur_list.tail = contribute_head;
226 cur_list.delimiter = null;
227 cur_list.prev_graf = 0;
228 cur_list.mode_line = 0;
229 cur_list.prev_depth = ignore_depth;
230 cur_list.space_factor = default_space_factor;
231 cur_list.incomplete_noad = null;
232 cur_list.direction_stack = null;
233 cur_list.math_dir = 0;
234 cur_list.math_style = -1;
235 cur_list.math_main_style = -1;
236 cur_list.math_parent_style = -1;
237 cur_list.math_flatten = 1;
238 cur_list.math_begin = unset_noad_class;
239 cur_list.math_end = unset_noad_class;
240 cur_list.math_mode = 0;
241 cur_list.options = 0;
242# else
243 cur_list = (list_state_record) {
244 .mode = vmode,
245 .head = contribute_head,
246 .tail = contribute_head,
247 .delimiter = null,
248 .prev_graf = 0,
249 .mode_line = 0,
250 .prev_depth = ignore_depth,
251 .space_factor = default_space_factor,
252 .incomplete_noad = null,
253 .direction_stack = null,
254 .math_dir = 0,
255 .math_style = -1,
256 .math_main_style = -1,
257 .math_parent_style = -1,
258 .math_flatten = 1,
259 .math_begin = unset_noad_class,
260 .math_end = unset_noad_class,
261 .math_mode = 0,
262 .options = 0,
263 };
264# endif
265}
266
267halfword tex_pop_tail(void)
268{
269 if (cur_list.tail != cur_list.head) {
270 halfword r = cur_list.tail;
271 halfword n = node_prev(r);
272 if (node_next(n) != r) {
273 n = cur_list.head;
274 while (node_next(n) != r) {
275 n = node_next(n);
276 }
277 }
278 cur_list.tail = n;
279 node_prev(r) = null;
280 node_next(n) = null;
281 return r;
282 } else {
283 return null;
284 }
285}
286
287
294
295void tex_push_nest(void)
296{
297 list_state_record *top = &lmt_nest_state.nest[lmt_nest_state.nest_data.ptr];
298 lmt_nest_state.nest_data.ptr += 1;
299
300 lmt_nest_state.math_mode = 0;
301 if (tex_aux_room_on_nest_stack()) {
302# if 1
303 cur_list.mode = top->mode;
304 cur_list.head = tex_new_temp_node();
305 cur_list.tail = cur_list.head;
306 cur_list.delimiter = null;
307 cur_list.prev_graf = 0;
308 cur_list.mode_line = lmt_input_state.input_line;
309 cur_list.prev_depth = top->prev_depth;
310 cur_list.space_factor = top->space_factor;
311 cur_list.incomplete_noad = top->incomplete_noad;
312 cur_list.direction_stack = null;
313 cur_list.math_dir = 0;
314 cur_list.math_style = -1;
315 cur_list.math_main_style = top->math_main_style;
316 cur_list.math_parent_style = top->math_parent_style;
317 cur_list.math_flatten = 1;
318 cur_list.math_begin = unset_noad_class;
319 cur_list.math_end = unset_noad_class;
320
321
322 cur_list.math_mode = 0;
323 cur_list.options = 0;
324# else
325 cur_list = (list_state_record) {
326 .mode = top->mode,
327 .head = null,
328 .tail = null,
329 .delimiter = null,
330 .prev_graf = 0,
331 .mode_line = lmt_input_state.input_line,
332 .prev_depth = top->prev_depth,
333 .space_factor = top->space_factor,
334 .incomplete_noad = top->incomplete_noad,
335 .direction_stack = null,
336 .math_dir = 0,
337 .math_style = -1,
338 .math_main_style = top->math_main_style,
339 .math_parent_style = top->math_parent_style,
340 .math_flatten = 1,
341 .math_begin = unset_noad_class,
342 .math_end = unset_noad_class,
343
344
345 .math_mode = 0,
346 .options = 0,
347 };
348 cur_list.head = tex_new_temp_node(),
349 cur_list.tail = cur_list.head;
350# endif
351
352 } else {
353 tex_overflow_error("semantic nest size", lmt_nest_state.nest_data.size);
354 }
355}
356
357
364
365void tex_pop_nest(void)
366{
367 if (cur_list.head) {
368
369 tex_flush_node(cur_list.head);
370
371
372
373 }
374 --lmt_nest_state.nest_data.ptr;
375}
376
377
378
379void tex_show_activities(void)
380{
381 tex_print_nlp();
382 for (int p = lmt_nest_state.nest_data.ptr; p >= 0; p--) {
383 list_state_record n = lmt_nest_state.nest[p];
384 tex_print_format("%l[%M entered at line %i%s]", n.mode, abs(n.mode_line), n.mode_line < 0 ? " (output routine)" : "");
385 if (p == 0) {
386
387 if (page_head != lmt_page_builder_state.page_tail) {
388 tex_print_format("%l[current page:%s]", lmt_page_builder_state.output_active ? " (held over for next output)" : "");
389 tex_show_box(node_next(page_head));
390 if (lmt_page_builder_state.contents != contribute_nothing) {
391 halfword r;
392 tex_print_format("%l[total height %P, goal height %p]",
393 page_total, page_stretch, page_filstretch, page_fillstretch, page_filllstretch, page_shrink,
394 page_goal
395 );
396 r = node_next(page_insert_head);
397 while (r != page_insert_head) {
398 halfword index = insert_index(r);
399 halfword multiplier = tex_get_insert_multiplier(index);
400 halfword size = multiplier == scaling_factor ? insert_total_height(r) : tex_x_over_n(insert_total_height(r), scaling_factor) * multiplier;
401 if (node_type(r) == split_node && node_subtype(r) == insert_split_subtype) {
402 halfword q = page_head;
403 halfword n = 0;
404 do {
405 q = node_next(q);
406 if (node_type(q) == insert_node && split_insert_index(q) == insert_index(r)) {
407 ++n;
408 }
409 } while (q != split_broken_insert(r));
410 tex_print_format("%l[insert %i adds %p, might split to %i]", index, size, n);
411 } else {
412 tex_print_format("%l[insert %i adds %p]", index, size);
413 }
414 r = node_next(r);
415 }
416 }
417 }
418 if (node_next(contribute_head)) {
419 tex_print_format("%l[recent contributions:]");
420 }
421 }
422 tex_print_format("%l[begin list]");
423 tex_show_box(node_next(n.head));
424 tex_print_format("%l[end list]");
425
426 switch (n.mode) {
427 case vmode:
428 case internal_vmode:
429 {
430 if (n.prev_depth <= ignore_depth_criterion_par) {
431 tex_print_format("%l[prevdepth ignored");
432 } else {
433 tex_print_format("%l[prevdepth %p", n.prev_depth);
434 }
435 if (n.prev_graf != 0) {
436 tex_print_format(", prevgraf %i line%s", n.prev_graf, n.prev_graf == 1 ? "" : "s");
437 }
438 tex_print_char(']');
439 break;
440 }
441 case mmode:
442 case inline_mmode:
443 {
444 if (n.incomplete_noad) {
445 tex_print_format("%l[this will be denominator of:]");
446 tex_print_format("%l[begin list]");
447 tex_show_box(n.incomplete_noad);
448 tex_print_format("%l[end list]");
449 }
450 break;
451 }
452 }
453 }
454}
455
456int tex_vmode_nest_index(void)
457{
458 int p = lmt_nest_state.nest_data.ptr;
459 while (! is_v_mode(lmt_nest_state.nest[p].mode)) {
460 --p;
461 }
462 return p;
463}
464
465void tex_tail_prepend(halfword n)
466{
467 tex_couple_nodes(node_prev(cur_list.tail), n);
468 tex_couple_nodes(n, cur_list.tail);
469 if (cur_list.tail == cur_list.head) {
470 cur_list.head = n;
471 }
472}
473
474void tex_tail_append(halfword p)
475{
476 node_next(cur_list.tail) = p;
477 node_prev(p) = cur_list.tail;
478 cur_list.tail = p;
479}
480
481
492
493halfword tex_tail_fetch_callback(void)
494{
495 halfword tail = cur_list.tail;
496 if (node_type(tail) == boundary_node && node_subtype(tail) == lua_boundary) {
497 cur_list.tail = node_prev(tail);
498 node_next(cur_list.tail) = null;
499 node_prev(tail) = null;
500 node_next(tail) = null;
501 return tail;
502 } else {
503 return null;
504 }
505}
506
507halfword tex_tail_apply_callback(halfword p, halfword c)
508{
509 if (p && c) {
510 int callback_id = lmt_callback_defined(tail_append_callback);
511 if (callback_id > 0) {
512 lmt_run_callback(lmt_lua_state.lua_instance, callback_id, "Ndd->N", p, boundary_data(c), boundary_reserved(c), &p);
513 }
514 tex_flush_node(c);
515 }
516 return p;
517}
518
519void tex_tail_append_list(halfword p)
520{
521 if (p) {
522 node_next(cur_list.tail) = p;
523 node_prev(p) = cur_list.tail;
524 cur_list.tail = tex_tail_of_node_list(p);
525 }
526}
527
528void tex_tail_append_callback(halfword p)
529{
530 halfword c = tex_tail_fetch_callback();
531 if (c) {
532 p = tex_tail_apply_callback(p, c);
533 }
534 tex_tail_append_list(p);
535}
536
537
540
541
542
548
549
553
554mvl_state_info lmt_mvl_state = {
555 .mvl = NULL,
556 .mvl_data = {
557 .minimum = min_mvl_size,
558 .maximum = max_mvl_size,
559 .size = memory_data_unset,
560 .step = stp_mvl_size,
561 .allocated = 0,
562 .itemsize = sizeof(list_state_record),
563 .top = 0,
564 .ptr = 0,
565 .initial = memory_data_unset,
566 .offset = 0,
567 .extra = 0,
568 },
569};
570
571static void tex_aux_reset_mvl(int i)
572{
573 lmt_mvl_state.mvl[i] = (list_state_record) {
574 .mode = vmode,
575 .head = null,
576 .tail = null,
577 .delimiter = null,
578 .prev_graf = 0,
579 .mode_line = 0,
580 .prev_depth = ignore_depth,
581 .space_factor = default_space_factor,
582 .incomplete_noad = null,
583 .direction_stack = null,
584 .math_dir = 0,
585 .math_style = -1,
586 .math_main_style = -1,
587 .math_parent_style = -1,
588 .math_flatten = 1,
589 .math_begin = unset_noad_class,
590 .math_end = unset_noad_class,
591 .options = 0,
592 };
593}
594
595# define reserved_mvl_slots 0
596
597void tex_initialize_mvl_state(void)
598{
599 list_state_record *tmp = aux_allocate_clear_array(sizeof(list_state_record), lmt_mvl_state.mvl_data.minimum, 1);
600 if (tmp) {
601 lmt_mvl_state.mvl = tmp;
602 lmt_mvl_state.mvl_data.allocated = lmt_mvl_state.mvl_data.minimum;
603 lmt_mvl_state.mvl_data.top = lmt_mvl_state.mvl_data.minimum;
604 lmt_mvl_state.mvl_data.ptr = 0;
605 } else {
606 tex_overflow_error("mvl", lmt_mvl_state.mvl_data.minimum);
607 }
608 tex_aux_reset_mvl(0);
609 lmt_mvl_state.slot = 0;
610}
611
612static int tex_valid_mvl_id(halfword n)
613{
614
615
616
617
618
619
620
621 if (n <= lmt_mvl_state.mvl_data.ptr) {
622 return 1;
623 } else if (n < lmt_mvl_state.mvl_data.top) {
624 lmt_mvl_state.mvl_data.ptr = n;
625 return 1;
626 } else if (n < lmt_mvl_state.mvl_data.maximum && lmt_mvl_state.mvl_data.top < lmt_mvl_state.mvl_data.maximum) {
627 list_state_record *tmp = NULL;
628 int top = n + lmt_mvl_state.mvl_data.step;
629 if (top > lmt_mvl_state.mvl_data.maximum) {
630 top = lmt_mvl_state.mvl_data.maximum;
631 }
632 tmp = aux_reallocate_array(lmt_mvl_state.mvl, sizeof(list_state_record), top, 1);
633 if (tmp) {
634 size_t extra = ((size_t) top - lmt_mvl_state.mvl_data.top) * sizeof(list_state_record);
635 memset(&tmp[lmt_mvl_state.mvl_data.top + 1], 0, extra);
636 lmt_mvl_state.mvl = tmp;
637 lmt_mvl_state.mvl_data.allocated = top;
638 lmt_mvl_state.mvl_data.top = top;
639 lmt_mvl_state.mvl_data.ptr = n;
640 return 1;
641 }
642 }
643 tex_overflow_error("mvl", lmt_mvl_state.mvl_data.maximum);
644 return 0;
645}
646
647void tex_start_mvl(void)
648{
649 halfword index = 0;
650 halfword options = 0;
651 halfword prevdepth = max_dimen;
652 while (1) {
653 switch (tex_scan_character("iopIOP", 0, 1, 0)) {
654 case 'i': case 'I':
655 if (tex_scan_mandate_keyword("index", 1)) {
656 index = tex_scan_integer(0, NULL, NULL);
657 }
658 break;
659 case 'o': case 'O':
660 if (tex_scan_mandate_keyword("options", 1)) {
661 options = tex_scan_integer(0, NULL, NULL);
662 }
663 break;
664 case 'p': case 'P':
665 if (tex_scan_mandate_keyword("prevdepth", 1)) {
666 prevdepth = tex_scan_dimension(0, 0, 0, 0, NULL, NULL);
667 }
668 break;
669 default:
670 goto DONE;
671 }
672 }
673 DONE:
674 if (! index) {
675 index = tex_scan_integer(0, NULL, NULL);
676 }
677 if (lmt_mvl_state.slot) {
678
679 } else if (index <= 0) {
680
681 } else if (! tex_valid_mvl_id(index)) {
682
683 } else {
684
685 list_state_record *mvl = &lmt_mvl_state.mvl[index];
686 int start = ! mvl->head;
687 if (options & mvl_ignore_prev_depth) {
688 prevdepth = ignore_depth_criterion_par;
689 } else if (options & mvl_no_prev_depth) {
690 prevdepth = 0;
691 } else if (prevdepth == max_dimen) {
692 prevdepth = lmt_mvl_state.mvl[index].prev_depth;
693 }
694 if (tracing_mvl_par) {
695 tex_begin_diagnostic();
696 tex_print_format("[mvl: index %i, options %x, prevdepth %p, %s]", index, options, prevdepth, start ? "start" : "restart");
697 tex_end_diagnostic();
698 }
699 if (start) {
700 mvl->head = tex_new_temp_node();
701 mvl->tail = mvl->head;
702 }
703 mvl->options = options;
704 lmt_mvl_state.mvl[0].prev_depth = lmt_nest_state.nest[0].prev_depth;
705 lmt_nest_state.nest[0].prev_depth = prevdepth;
706 lmt_mvl_state.slot = index;
707 }
708}
709
710void tex_stop_mvl(void)
711{
712 halfword index = lmt_mvl_state.slot;
713 if (index) {
714 list_state_record *mvl = &lmt_mvl_state.mvl[index];
715 int something = mvl->tail != mvl->head;
716 if (tracing_mvl_par) {
717 tex_begin_diagnostic();
718 tex_print_format("[mvl: index %i, options %x, stop with%s contributions]", index, mvl->options, something ? "" : "out");
719 tex_end_diagnostic();
720 }
721 if (something && (mvl->options & mvl_discard_bottom)) {
722 halfword last = mvl->tail;
723 while (last) {
724 if (non_discardable(last)) {
725 break;
726 } else if (node_type(last) == kern_node && ! (node_subtype(last) == explicit_kern_subtype)) {
727 break;
728 } else {
729 halfword preceding = node_prev(last);
730 node_next(preceding) = null;
731 tex_flush_node(last);
732 mvl->tail = preceding;
733 if (mvl->head == preceding) {
734 break;
735 } else {
736 last = preceding;
737 }
738 }
739 }
740 }
741 mvl->prev_depth = lmt_nest_state.nest[0].prev_depth;
742 lmt_nest_state.nest[0].prev_depth = mvl->prev_depth;
743 lmt_mvl_state.slot = 0;
744 }
745}
746
747# define page_callback 1
748
749halfword tex_flush_mvl(halfword index)
750{
751
752 if (lmt_mvl_state.slot) {
753
754 return null;
755 } else if (! tex_valid_mvl_id(index)) {
756
757 return null;
758 } else if (! lmt_mvl_state.mvl[index].tail || lmt_mvl_state.mvl[index].tail == lmt_mvl_state.mvl[index].head) {
759
760 return null;
761 } else {
762
763 halfword head = node_next(lmt_mvl_state.mvl[index].head);
764 tex_flush_node(lmt_mvl_state.mvl[index].head);
765 tex_aux_reset_mvl(index);
766 if (tracing_mvl_par) {
767 tex_begin_diagnostic();
768 tex_print_format("[mvl: index %i, %s]", index, "flush");
769 tex_end_diagnostic();
770 }
771 node_prev(head) = null;
772# if page_callback
773 return tex_vpack(head, 0, packing_additional, max_dimension, 0, holding_none_option, NULL);
774# else
775 if (head) {
776 return tex_filtered_vpack(head, 0, packing_additional, max_dimension, 0, 0, 0, node_attr(head), 0, 0, NULL);
777 } else {
778 return tex_vpack(head, 0, packing_additional, max_dimension, 0, holding_none_option, NULL);
779 }
780# endif
781 }
782}
783
784int tex_appended_mvl(halfword context, halfword boundary)
785{
786 if (! lmt_mvl_state.slot) {
787
788 return 0;
789 } else {
790# if page_callback
791 if (! lmt_page_builder_state.output_active) {
792 lmt_page_filter_callback(context, boundary);
793 }
794# endif
795 if (node_next(contribute_head) && ! lmt_page_builder_state.output_active) {
796 halfword first = node_next(contribute_head);
797 int assign = lmt_mvl_state.mvl[lmt_mvl_state.slot].tail == lmt_mvl_state.mvl[lmt_mvl_state.slot].head;
798 if (assign && (lmt_mvl_state.mvl[lmt_mvl_state.slot].options & mvl_discard_top)) {
799 while (first) {
800 if (non_discardable(first)) {
801 break;
802 } else if (node_type(first) == kern_node && ! (node_subtype(first) == explicit_kern_subtype)) {
803 break;
804 } else {
805 halfword following = node_next(first);
806 node_prev(following) = null;
807 tex_flush_node(first);
808 first = following;
809 }
810 }
811 }
812 if (contribute_head != contribute_tail && first) {
813 if (tracing_mvl_par) {
814 tex_begin_diagnostic();
815 tex_print_format("[mvl: index %i, %s]", lmt_mvl_state.slot, assign ? "assign" : "append");
816 tex_end_diagnostic();
817 }
818 if (assign) {
819 node_next(lmt_mvl_state.mvl[lmt_mvl_state.slot].head) = first;
820
821 } else {
822 tex_couple_nodes(lmt_mvl_state.mvl[lmt_mvl_state.slot].tail, first);
823 }
824 lmt_mvl_state.mvl[lmt_mvl_state.slot].tail = contribute_tail;
825 }
826 node_next(contribute_head) = null;
827 contribute_tail = contribute_head;
828 }
829 return 1;
830 }
831}
832
833int tex_current_mvl(halfword *head, halfword *tail)
834{
835 if (lmt_mvl_state.slot == 0) {
836 if (head && tail) {
837 *head = node_next(page_head);
838 *tail = lmt_page_builder_state.page_tail;
839 }
840 return 0;
841 } else if (lmt_mvl_state.slot > 0) {
842 if (head && tail) {
843 *head = lmt_mvl_state.mvl[lmt_mvl_state.slot].head;
844 *tail = lmt_mvl_state.mvl[lmt_mvl_state.slot].tail;
845 }
846 return lmt_mvl_state.slot;
847 } else {
848 if (head && tail) {
849 *head = null;
850 *tail = null;
851 }
852 return 0;
853 }
854}
855 |