1
4
5# include "luametatex.h"
6
7
181
182
208
209typedef enum align_options {
210 align_option_exactly = 0x01,
211 align_option_reverse = 0x10,
212 align_option_discard = 0x20,
213 align_option_noskips = 0x40,
214 align_option_callback = 0x80,
215} align_options;
216
217
218
219typedef enum saved_align_entries {
220 saved_align_mode_entry = 0,
221 saved_align_amount_entry = 0,
222 saved_align_callback_entry = 0,
223 saved_align_n_of_records = 1,
224} saved_align_entries;
225
226# define saved_align_mode saved_value_1(saved_align_mode_entry)
227# define saved_align_amount saved_value_2(saved_align_amount_entry)
228# define saved_align_callback saved_value_3(saved_align_amount_entry)
229
230static inline void saved_alignment_initialize(void)
231{
232 saved_type(0) = saved_record_0;
233 saved_record(0) = alignment_save_type;
234}
235
236int tex_show_alignment_record(void)
237{
238 tex_print_str("alignment ");
239 switch (saved_type(0)) {
240 case saved_record_0:
241 tex_print_format("mode %i, amount %p", saved_value_1(0), saved_value_2(0));
242 break;
243 default:
244 return 0;
245 }
246 return 1;
247}
248
249typedef struct alignment_row_state {
250 halfword orientation;
251 scaled xoffset;
252 scaled yoffset;
253 scaled xmove;
254 scaled ymove;
255 halfword shift;
256 halfword source;
257 halfword target;
258 halfword anchor;
259 halfword attrlist;
260} alignment_row_state;
261
262typedef struct alignment_state_info {
263 halfword cur_align;
264 halfword cur_span;
265 halfword cur_loop;
266 halfword align_ptr;
267 halfword cur_post_adjust_head;
268 halfword cur_post_adjust_tail;
269 halfword cur_pre_adjust_head;
270 halfword cur_pre_adjust_tail;
271 halfword cur_post_migrate_head;
272 halfword cur_post_migrate_tail;
273 halfword cur_pre_migrate_head;
274 halfword cur_pre_migrate_tail;
275 halfword hold_token_head;
276 halfword omit_template;
277 halfword no_align_level;
278 halfword attr_list;
279 halfword cell_source;
280 halfword wrap_source;
281 halfword row_state_set;
282 halfword options;
283 halfword callback;
284 alignment_row_state row_state;
285} alignment_state_info ;
286
287static alignment_state_info lmt_alignment_state = {
288 .cur_align = null,
289 .cur_span = null,
290 .cur_loop = null,
291 .align_ptr = null,
292 .cur_post_adjust_head = null,
293 .cur_post_adjust_tail = null,
294 .cur_pre_adjust_head = null,
295 .cur_pre_adjust_tail = null,
296 .cur_post_migrate_head = null,
297 .cur_post_migrate_tail = null,
298 .cur_pre_migrate_head = null,
299 .cur_pre_migrate_tail = null,
300 .hold_token_head = null,
301 .omit_template = null,
302 .no_align_level = 0,
303 .attr_list = null,
304 .cell_source = 0,
305 .wrap_source = 0,
306 .row_state_set = 0,
307 .options = 0,
308 .callback = 0,
309 .row_state = {
310 .attrlist = null,
311 .orientation = 0,
312 .xoffset = 0,
313 .yoffset = 0,
314 .xmove = 0,
315 .ymove = 0,
316 .shift = 0,
317 .source = 0,
318 .target = 0,
319 .anchor = 0,
320 }
321};
322
323int tex_in_alignment(void)
324{
325
326 return lmt_alignment_state.align_ptr ? 1 : 0;
327}
328
329static void tex_aux_wipe_row_state(void)
330{
331 lmt_alignment_state.row_state.attrlist = null;
332 lmt_alignment_state.row_state.orientation = 0;
333 lmt_alignment_state.row_state.xoffset = 0;
334 lmt_alignment_state.row_state.yoffset = 0;
335 lmt_alignment_state.row_state.xmove = 0;
336 lmt_alignment_state.row_state.ymove = 0;
337 lmt_alignment_state.row_state.shift = 0;
338 lmt_alignment_state.row_state.source = 0;
339 lmt_alignment_state.row_state.target = 0;
340 lmt_alignment_state.row_state.anchor = 0;
341 lmt_alignment_state.row_state_set = 0;
342}
343
344
345
346# define preamble node_next(align_head)
347
348
349
350static void tex_aux_initialize_row (void);
351static void tex_aux_initialize_column (void);
352static void tex_aux_finish_row (void);
353static int tex_aux_finish_column (void);
354static void tex_aux_finish_align (void);
355
356
362
363static inline void tex_aux_change_list_type(halfword n, quarterword type)
364{
365 node_type(n) = type;
366 box_w_offset(n) = 0;
367 box_h_offset(n) = 0;
368 box_d_offset(n) = 0;
369 box_x_offset(n) = 0;
370 box_y_offset(n) = 0;
371
372 box_orientation(n) = 0;
373}
374
375
390
391static void tex_aux_push_alignment(void)
392{
393
394 halfword p = tex_new_node(align_stack_node, 0);
395
396 align_stack_align_ptr(p) = lmt_alignment_state.align_ptr;
397 align_stack_cur_align(p) = lmt_alignment_state.cur_align;
398 align_stack_preamble(p) = preamble;
399 align_stack_cur_span(p) = lmt_alignment_state.cur_span;
400 align_stack_cur_loop(p) = lmt_alignment_state.cur_loop;
401 align_stack_align_state(p) = lmt_input_state.align_state;
402 align_stack_wrap_source(p) = lmt_alignment_state.wrap_source;
403 align_stack_no_align_level(p) = lmt_alignment_state.no_align_level;
404 align_stack_cur_post_adjust_head(p) = lmt_alignment_state.cur_post_adjust_head;
405 align_stack_cur_post_adjust_tail(p) = lmt_alignment_state.cur_post_adjust_tail;
406 align_stack_cur_pre_adjust_head(p) = lmt_alignment_state.cur_pre_adjust_head;
407 align_stack_cur_pre_adjust_tail(p) = lmt_alignment_state.cur_pre_adjust_tail;
408 align_stack_cur_post_migrate_head(p) = lmt_alignment_state.cur_post_migrate_head;
409 align_stack_cur_post_migrate_tail(p) = lmt_alignment_state.cur_post_migrate_tail;
410 align_stack_cur_pre_migrate_head(p) = lmt_alignment_state.cur_pre_migrate_head;
411 align_stack_cur_pre_migrate_tail(p) = lmt_alignment_state.cur_pre_migrate_tail;
412 align_stack_options(p) = lmt_alignment_state.options;
413 align_stack_attr_list(p) = lmt_alignment_state.attr_list;
414 align_stack_callback(p) = lmt_alignment_state.callback;
415
416 align_stack_row_attrlist(p) = lmt_alignment_state.row_state.attrlist;
417 align_stack_row_orientation(p) = lmt_alignment_state.row_state.orientation;
418 align_stack_row_yoffset(p) = lmt_alignment_state.row_state.xoffset;
419 align_stack_row_xoffset(p) = lmt_alignment_state.row_state.yoffset;
420 align_stack_row_ymove(p) = lmt_alignment_state.row_state.xmove;
421 align_stack_row_xmove(p) = lmt_alignment_state.row_state.ymove;
422 align_stack_row_shift(p) = lmt_alignment_state.row_state.shift;
423 align_stack_row_source(p) = lmt_alignment_state.row_state.source;
424 align_stack_row_target(p) = lmt_alignment_state.row_state.target;
425 align_stack_row_anchor(p) = lmt_alignment_state.row_state.anchor;
426
427 lmt_alignment_state.align_ptr = p;
428 lmt_alignment_state.cur_post_adjust_head = tex_new_temp_node();
429 lmt_alignment_state.cur_pre_adjust_head = tex_new_temp_node();
430 lmt_alignment_state.cur_post_migrate_head = tex_new_temp_node();
431 lmt_alignment_state.cur_pre_migrate_head = tex_new_temp_node();
432
433 lmt_alignment_state.cell_source = 0;
434 lmt_alignment_state.wrap_source = 0;
435
436
437 tex_aux_wipe_row_state();
438}
439
440static void tex_aux_pop_alignment(void)
441{
442
443 halfword p = lmt_alignment_state.align_ptr;
444 tex_flush_node(lmt_alignment_state.cur_post_adjust_head);
445 tex_flush_node(lmt_alignment_state.cur_pre_adjust_head);
446 tex_flush_node(lmt_alignment_state.cur_post_migrate_head);
447 tex_flush_node(lmt_alignment_state.cur_pre_migrate_head);
448 lmt_alignment_state.align_ptr = align_stack_align_ptr(p);
449 lmt_alignment_state.cur_align = align_stack_cur_align(p);
450 preamble = align_stack_preamble(p);
451 lmt_alignment_state.cur_span = align_stack_cur_span(p);
452 lmt_alignment_state.cur_loop = align_stack_cur_loop(p);
453 lmt_input_state.align_state = align_stack_align_state(p);
454 lmt_alignment_state.wrap_source = align_stack_wrap_source(p);
455 lmt_alignment_state.no_align_level = align_stack_no_align_level(p);
456 lmt_alignment_state.cur_post_adjust_head = align_stack_cur_post_adjust_head(p);
457 lmt_alignment_state.cur_post_adjust_tail = align_stack_cur_post_adjust_tail(p);
458 lmt_alignment_state.cur_pre_adjust_head = align_stack_cur_pre_adjust_head(p);
459 lmt_alignment_state.cur_pre_adjust_tail = align_stack_cur_pre_adjust_tail(p);
460 lmt_alignment_state.cur_post_migrate_head = align_stack_cur_post_migrate_head(p);
461 lmt_alignment_state.cur_post_migrate_tail = align_stack_cur_post_migrate_tail(p);
462 lmt_alignment_state.cur_pre_migrate_head = align_stack_cur_pre_migrate_head(p);
463 lmt_alignment_state.cur_pre_migrate_tail = align_stack_cur_pre_migrate_tail(p);
464 lmt_alignment_state.options = align_stack_options(p);
465 lmt_alignment_state.attr_list = align_stack_attr_list(p);
466 lmt_alignment_state.callback = align_stack_callback(p);
467
468 lmt_alignment_state.row_state.attrlist = align_stack_row_attrlist(p);
469 lmt_alignment_state.row_state.orientation = align_stack_row_orientation(p);
470 lmt_alignment_state.row_state.xoffset = align_stack_row_yoffset(p);
471 lmt_alignment_state.row_state.yoffset = align_stack_row_xoffset(p);
472 lmt_alignment_state.row_state.xmove = align_stack_row_ymove(p);
473 lmt_alignment_state.row_state.ymove = align_stack_row_xmove(p);
474 lmt_alignment_state.row_state.shift = align_stack_row_shift(p);
475 lmt_alignment_state.row_state.source = align_stack_row_source(p);
476 lmt_alignment_state.row_state.target = align_stack_row_target(p);
477 lmt_alignment_state.row_state.anchor = align_stack_row_anchor(p);
478
479 tex_flush_node(p);
480}
481
482
516
517
527
528static void tex_aux_get_preamble_token(void)
529{
530 RESTART:
531 tex_get_token();
532 while (cur_cmd == alignment_cmd && cur_chr == span_code) {
533
534 tex_get_token();
535 if (cur_cmd > max_command_cmd) {
536 tex_expand_current_token();
537 tex_get_token();
538 }
539 }
540 switch (cur_cmd) {
541 case end_template_cmd:
542 tex_alignment_interwoven_error(5);
543 break;
544 case internal_dimension_cmd:
545 if (cur_chr == internal_dimension_location(tab_size_code)) {
546 scaled v = tex_scan_dimension(0, 0, 0, 1, NULL, NULL);
547 tex_word_define(global_defs_par > 0 ? global_flag_bit : 0, internal_dimension_location(tab_size_code), v);
548 goto RESTART;
549 } else {
550 break;
551 }
552 case internal_glue_cmd:
553 if (cur_chr == internal_glue_location(tab_skip_code)) {
554 halfword v = tex_scan_glue(glue_val_level, 1, 0);
555 if (global_defs_par > 0) {
556 update_tex_tab_skip_global(v);
557 } else {
558 update_tex_tab_skip_local(v);
559 }
560 goto RESTART;
561 } else {
562 break;
563 }
564 case call_cmd:
565 case protected_call_cmd:
566 case semi_protected_call_cmd:
567 case constant_call_cmd:
568 case tolerant_call_cmd:
569 case tolerant_protected_call_cmd:
570 case tolerant_semi_protected_call_cmd:
571 if (has_eq_flag_bits(cur_cs, noaligned_flag_bit)) {
572 tex_expand_current_token();
573 goto RESTART;
574 } else {
575 break;
576 }
577 }
578}
579
580
587
588static void tex_aux_scan_align_spec(quarterword c)
589{
590 quarterword mode = packing_additional;
591 quarterword options = 0;
592 scaled amount = 0;
593 halfword callback = 0;
594 halfword attrlist = null;
595 bool brace = false;
596 while (1) {
597 cur_val = 0;
598 switch (tex_scan_character("acdnrtsACDNRTS", 1, 1, 1)) {
599 case 0:
600 goto DONE;
601 case 'a': case 'A':
602 if (tex_scan_mandate_keyword("attr", 1)) {
603 attrlist = tex_scan_attribute(attrlist);
604 }
605 break;
606 case 'c': case 'C':
607
608 if (tex_scan_mandate_keyword("callback", 1)) {
609 options |= align_option_callback;
610 if (tex_scan_character("sS", 0, 0, 0)) {
611 callback |= tex_scan_integer(0, NULL, NULL);
612 } else {
613 callback = tex_scan_integer(0, NULL, NULL);
614 }
615 }
616 break;
617 case 'd': case 'D':
618 if (tex_scan_mandate_keyword("discard", 1)) {
619 options |= align_option_discard;
620 }
621 break;
622 case 'n': case 'N':
623 if (tex_scan_mandate_keyword("noskips", 1)) {
624 options |= align_option_noskips;
625 }
626 break;
627 case 'r': case 'R':
628 if (tex_scan_mandate_keyword("reverse", 1)) {
629 options |= align_option_reverse;
630 }
631 break;
632 case 't': case 'T':
633 if (tex_scan_mandate_keyword("to", 1)) {
634 mode = packing_exactly;
635 options |= align_option_exactly;
636 amount = tex_scan_dimension(0, 0, 0, 0, NULL, NULL);
637 }
638 break;
639 case 's': case 'S':
640 if (tex_scan_mandate_keyword("spread", 1)) {
641 mode = packing_additional;
642 options &= (~ align_option_exactly);
643 amount = tex_scan_dimension(0, 0, 0, 0, NULL, NULL);
644 }
645 break;
646 case '{':
647 brace = true;
648 goto DONE;
649 default:
650 goto DONE;
651 }
652 }
653 DONE:
654 if (! attrlist) {
655 attrlist = tex_current_attribute_list();
656 }
657 if (options & align_option_noskips) {
658 options &= (~ align_option_discard);
659 }
660
661 add_attribute_reference(attrlist);
662 saved_alignment_initialize();
663 saved_align_mode = mode;
664 saved_align_amount = amount;
665 saved_align_callback = callback;
666 lmt_save_state.save_stack_data.ptr += saved_align_n_of_records;
667 tex_new_save_level(c);
668 if (! brace) {
669 tex_scan_left_brace();
670 }
671 lmt_alignment_state.attr_list = attrlist;
672 lmt_alignment_state.options = options;
673 lmt_alignment_state.callback = callback;
674}
675
676
687
688static void tex_aux_align_peek(void);
689
690static void tex_aux_trace_no_align(const char *s)
691{
692 if (tracing_alignments_par > 0) {
693 tex_begin_diagnostic();
694 tex_print_format("[alignment: %s noalign, level %i]", s, lmt_alignment_state.no_align_level);
695 tex_end_diagnostic();
696 }
697}
698
699static void tex_aux_run_no_align(void)
700{
701
702 int brace = 0;
703 int done = lmt_alignment_state.row_state_set;
704 while (1) {
705 int add = 0;
706 AGAIN:
707 switch (tex_scan_character("atrsoxyATRSOXY", 1, 1, 1)) {
708 case 0:
709 goto DONE;
710 case 't': case 'T':
711 if (tex_scan_mandate_keyword("target", 1)) {
712 lmt_alignment_state.row_state.target = tex_scan_integer(1, NULL, NULL);
713 done = 1;
714 }
715 break;
716 case 'a': case 'A':
717 switch (tex_scan_character("ntdNTD", 0, 0, 0)) {
718 case 'd': case 'D':
719 if (tex_scan_mandate_keyword("add", 2)) {
720 add = 1;
721 goto AGAIN;
722 }
723 break;
724 case 't': case 'T':
725 if (tex_scan_mandate_keyword("attr", 2)) {
726 halfword i = tex_scan_attribute_register_number();
727 halfword v = tex_scan_integer(1, NULL, NULL);
728 if (eq_value(register_attribute_location(i)) != v) {
729 if (lmt_alignment_state.row_state.attrlist) {
730 lmt_alignment_state.row_state.attrlist = tex_patch_attribute_list(lmt_alignment_state.row_state.attrlist, i, v);
731 } else if (lmt_alignment_state.attr_list) {
732 lmt_alignment_state.row_state.attrlist = tex_copy_attribute_list_set(lmt_alignment_state.attr_list, i, v);
733 } else {
734 lmt_alignment_state.row_state.attrlist = tex_copy_attribute_list_set(tex_current_attribute_list(), i, v);
735 }
736 done = 1;
737 }
738 }
739 break;
740 case 'n': case 'N':
741 if (tex_scan_mandate_keyword("anchor", 2)) {
742 switch (tex_scan_character("sS", 0, 0, 0)) {
743 case 's': case 'S':
744 lmt_alignment_state.row_state.anchor = tex_scan_anchors(0);
745 break;
746 default:
747 lmt_alignment_state.row_state.anchor = tex_scan_anchor(0);
748 break;
749 }
750 done = 1;
751 }
752 break;
753 default:
754 tex_aux_show_keyword_error("attr|anchor|add");
755 goto DONE;
756 }
757 break;
758 case 'r': case 'R':
759 if (tex_scan_mandate_keyword("reset", 1)) {
760 tex_aux_wipe_row_state();
761 done = 0;
762 }
763 break;
764 case 's': case 'S':
765 switch (tex_scan_character("hoHO", 0, 0, 0)) {
766 case 'h': case 'H':
767 if (tex_scan_mandate_keyword("shift", 2)) {
768 lmt_alignment_state.row_state.shift = (add ? lmt_alignment_state.row_state.shift : 0)
769 + tex_scan_dimension(0, 0, 0, 0, NULL, NULL);
770 done = 1;
771 }
772 break;
773 case 'o': case 'O':
774 if (tex_scan_mandate_keyword("source", 2)) {
775 lmt_alignment_state.row_state.source = tex_scan_integer(1, NULL, NULL);
776 done = 1;
777 }
778 break;
779 default:
780 tex_aux_show_keyword_error("shift|source");
781 goto DONE;
782 }
783 break;
784 case 'o': case 'O':
785 if (tex_scan_mandate_keyword("orientation", 1)) {
786 lmt_alignment_state.row_state.orientation = tex_scan_orientation(0);
787 done = 1;
788 }
789 break;
790 case 'x': case 'X':
791 switch (tex_scan_character("omOM", 0, 0, 0)) {
792 case 'o': case 'O' :
793 if (tex_scan_mandate_keyword("xoffset", 2)) {
794 lmt_alignment_state.row_state.xoffset = (add ? lmt_alignment_state.row_state.xoffset : 0) + tex_scan_dimension(0, 0, 0, 0, NULL, NULL);
795 done = 1;
796 }
797 break;
798 case 'm': case 'M' :
799 if (tex_scan_mandate_keyword("xmove", 2)) {
800 lmt_alignment_state.row_state.xmove = (add ? lmt_alignment_state.row_state.xmove : 0) + tex_scan_dimension(0, 0, 0, 0, NULL, NULL);
801 done = 1;
802 }
803 break;
804 default:
805 tex_aux_show_keyword_error("xoffset|xmove");
806 goto DONE;
807 }
808 break;
809 case 'y': case 'Y':
810 switch (tex_scan_character("omOM", 0, 0, 0)) {
811 case 'o': case 'O' :
812 if (tex_scan_mandate_keyword("yoffset", 2)) {
813 lmt_alignment_state.row_state.yoffset = (add ? lmt_alignment_state.row_state.yoffset : 0) + tex_scan_dimension(0, 0, 0, 0, NULL, NULL);
814 done = 1;
815 }
816 break;
817 case 'm': case 'M' :
818 if (tex_scan_mandate_keyword("ymove", 2)) {
819 lmt_alignment_state.row_state.ymove = (add ? lmt_alignment_state.row_state.ymove : 0) + tex_scan_dimension(0, 0, 0, 0, NULL, NULL);
820 done = 1;
821 }
822 break;
823 default:
824 tex_aux_show_keyword_error("yoffset|ymove");
825 goto DONE;
826 }
827 break;
828 case '{':
829 brace = 1;
830 goto DONE;
831 default:
832 goto DONE;
833 }
834 add = 0;
835 }
836 DONE:
837 lmt_alignment_state.row_state_set = done;
838
839 if (! brace) {
840 tex_scan_left_brace();
841 }
842 tex_new_save_level(no_align_group);
843 ++lmt_alignment_state.no_align_level;
844 tex_aux_trace_no_align("entering");
845 if (cur_list.mode == internal_vmode) {
846 tex_normal_paragraph(no_align_par_context);
847 }
848}
849
850static int tex_aux_nested_no_align(void)
851{
852 int state = lmt_alignment_state.no_align_level > 0;
853 if (state) {
854
855
856
857
858
859
860
861 tex_aux_run_no_align();
862 }
863 return state;
864}
865
866void tex_finish_no_alignment_group(void)
867{
868 if (! tex_wrapped_up_paragraph(no_align_par_context, 0)) {
869 tex_end_paragraph(no_align_group, no_align_par_context);
870 tex_aux_trace_no_align("leaving");
871 --lmt_alignment_state.no_align_level;
872 tex_unsave();
873 if (lmt_alignment_state.no_align_level == 0) {
874 tex_aux_align_peek();
875 }
876 }
877}
878
879static void tex_aux_align_peek(void)
880{
881 RESTART:
882 lmt_input_state.align_state = busy_alignment_state;
883 AGAIN:
884 tex_get_x_or_protected();
885 switch (cur_cmd) {
886 case spacer_cmd:
887 goto AGAIN;
888 case right_brace_cmd:
889 tex_aux_finish_align();
890 break;
891 case call_cmd:
892 case protected_call_cmd:
893 case semi_protected_call_cmd:
894 case constant_call_cmd:
895 case tolerant_call_cmd:
896 case tolerant_protected_call_cmd:
897 case tolerant_semi_protected_call_cmd:
898 if (has_eq_flag_bits(cur_cs, noaligned_flag_bit)) {
899 tex_expand_current_token();
900 goto RESTART;
901 } else {
902 goto NEXTROW;
903 }
904 case alignment_cmd:
905 switch (cur_chr) {
906 case cr_cr_code:
907
908 goto RESTART;
909 case no_align_code:
910 tex_aux_run_no_align();
911 return;
912 }
913
914 default:
915 NEXTROW:
916
917 tex_aux_initialize_row();
918
919 tex_aux_initialize_column();
920 break;
921 }
922}
923
924
934
935void tex_run_alignment_initialize(void)
936{
937 halfword saved_cs = cur_cs;
938 tex_aux_push_alignment();
939 lmt_input_state.align_state = initial_alignment_state;
940
944 if (cur_list.mode == mmode && ((cur_list.tail != cur_list.head) || cur_list.incomplete_noad)) {
945 tex_handle_error(
946 normal_error_type,
947 "Improper \\halign inside math mode",
948 "Displays can use special alignments (like \\eqalignno) only if nothing but the\n"
949 "alignment itself is in math mode. So I've deleted the formulas that preceded this\n"
950 "alignment."
951 );
952 tex_flush_math();
953 }
954
955 tex_push_nest();
956
961 if (cur_list.mode == mmode) {
962 cur_list.mode = internal_vmode;
963 cur_list.prev_depth = lmt_nest_state.nest[lmt_nest_state.nest_data.ptr - 2].prev_depth;
964 } else if (cur_list.mode > 0) {
965 cur_list.mode = -cur_list.mode;
966 }
967
968 tex_aux_scan_align_spec(align_group);
969
974 preamble = null;
975 lmt_alignment_state.cur_align = align_head;
976 lmt_alignment_state.cur_loop = null;
977 lmt_input_state.scanner_status = scanner_is_aligning;
978 lmt_input_state.warning_index = saved_cs;
979 lmt_input_state.align_state = initial_alignment_state;
980
981 while (1) {
982
983 halfword glue = tex_new_param_glue_node(tab_skip_code, tab_skip_glue);
984 if ((lmt_alignment_state.options & align_option_noskips) && tex_glue_is_zero(glue)) {
985 node_subtype(glue) = ignored_glue;
986 }
987 tex_couple_nodes(lmt_alignment_state.cur_align, glue);
988 lmt_alignment_state.cur_align = glue;
989 if (cur_cmd == alignment_cmd && (cur_chr == cr_code || cur_chr == cr_cr_code)) {
990
991 break;
992 } else {
993
998 halfword record = null;
999 halfword current = lmt_alignment_state.hold_token_head;
1000 token_link(current) = null;
1001 while (1) {
1002 tex_aux_get_preamble_token();
1003 if ((cur_cmd == alignment_cmd && cur_chr == align_content_code) || cur_cmd == parameter_cmd) {
1004 break;
1005 } else if ((cur_cmd == alignment_cmd || cur_cmd == alignment_tab_cmd) && (lmt_input_state.align_state == initial_alignment_state)) {
1006 if ((current == lmt_alignment_state.hold_token_head) && (! lmt_alignment_state.cur_loop) && (cur_cmd == alignment_tab_cmd)) {
1007 lmt_alignment_state.cur_loop = lmt_alignment_state.cur_align;
1008 } else {
1009 tex_back_input(cur_tok);
1010 tex_handle_error(
1011 normal_error_type,
1012 "Missing # inserted in alignment preamble",
1013 "There should be exactly one # between &'s, when an \\halign or \\valign is being\n"
1014 "set up. In this case you had none, so I've put one in; maybe that will work."
1015 );
1016 break;
1017 }
1018 } else if (cur_cmd != spacer_cmd || current != lmt_alignment_state.hold_token_head) {
1019 current = tex_store_new_token(current, cur_tok);
1020 }
1021 }
1022
1023 record = tex_new_node(align_record_node, 0);
1024 tex_couple_nodes(lmt_alignment_state.cur_align, record);
1025 lmt_alignment_state.cur_align = record;
1026 align_record_span_ptr(record) = end_span;
1027 box_width(record) = null_flag;
1028 align_record_pre_part(record) = token_link(lmt_alignment_state.hold_token_head);
1029
1030 current = lmt_alignment_state.hold_token_head;
1031 token_link(current) = null;
1032 while (1) {
1033 tex_aux_get_preamble_token();
1034 if ((cur_cmd == alignment_cmd || cur_cmd == alignment_tab_cmd) && (lmt_input_state.align_state == initial_alignment_state)) {
1035 break;
1036 } else if ((cur_cmd == alignment_cmd && cur_chr == align_content_code) || cur_cmd == parameter_cmd) {
1037 tex_handle_error(
1038 normal_error_type,
1039 "Only one # is allowed per tab",
1040 "There should be exactly one # between &'s, when an \\halign or \\valign is being\n"
1041 "set up. In this case you had more than one, so I'm ignoring all but the first."
1042 );
1043 } else {
1044 current = tex_store_new_token(current, cur_tok);
1045 }
1046 }
1047 if (tab_size_par > 0) {
1048 box_size(record) = tab_size_par;
1049 set_box_package_state(record, package_dimension_size_set);
1050 } else {
1051 box_width(record) = null_flag;
1052 }
1053
1054 current = tex_store_new_token(current, deep_frozen_end_template_token);
1055 align_record_post_part(lmt_alignment_state.cur_align) = token_link(lmt_alignment_state.hold_token_head);
1056 }
1057 }
1058 if (tracing_alignments_par > 1) {
1059 tex_begin_diagnostic();
1060 tex_print_str("<alignment preamble>");
1061 tex_show_node_list(preamble, max_integer, max_integer);
1062 tex_end_diagnostic();
1063 }
1064 if (lmt_alignment_state.options & align_option_callback) {
1065 lmt_alignment_callback(cur_list.head, preamble_pass_alignment_context, lmt_alignment_state.callback, lmt_alignment_state.attr_list, preamble);
1066 }
1067 lmt_input_state.scanner_status = scanner_is_normal;
1068 tex_new_save_level(align_group);
1069 if (every_cr_par) {
1070 tex_begin_token_list(every_cr_par, every_cr_text);
1071 }
1072
1073 tex_aux_align_peek();
1074}
1075
1076void tex_finish_alignment_group(void)
1077{
1078 tex_back_input(cur_tok);
1079 cur_tok = deep_frozen_cr_token;
1080 tex_handle_error(
1081 insert_error_type,
1082 "Missing \\cr inserted",
1083 "I'm guessing that you meant to end an alignment here."
1084 );
1085}
1086
1087
1094
1095static void tex_aux_initialize_span(halfword p)
1096{
1097 tex_push_nest();
1098 if (cur_list.mode == restricted_hmode) {
1099 cur_list.space_factor = default_space_factor;
1100 } else {
1101 cur_list.prev_depth = ignore_depth_criterion_par;
1102 tex_normal_paragraph(span_par_context);
1103 }
1104 lmt_alignment_state.cur_span = p;
1105}
1106
1107
1115
1116static void tex_aux_initialize_row(void)
1117{
1118 tex_push_nest();
1119 cur_list.mode = (- hmode - vmode) - cur_list.mode;
1120 if (cur_list.mode == restricted_hmode) {
1121 cur_list.space_factor = 0;
1122 } else {
1123 cur_list.prev_depth = 0;
1124 }
1125 lmt_alignment_state.cur_align = preamble;
1126 if (node_subtype(preamble) != ignored_glue) {
1127 halfword glue = tex_new_glue_node(preamble, tab_skip_glue);
1128 tex_tail_append(glue);
1129 tex_attach_attribute_list_attribute(glue, lmt_alignment_state.attr_list);
1130 }
1131 lmt_alignment_state.cur_align = node_next(preamble);
1132 lmt_alignment_state.cur_post_adjust_tail = lmt_alignment_state.cur_post_adjust_head;
1133 lmt_alignment_state.cur_pre_adjust_tail = lmt_alignment_state.cur_pre_adjust_head;
1134 lmt_alignment_state.cur_post_migrate_tail = lmt_alignment_state.cur_post_migrate_head;
1135 lmt_alignment_state.cur_pre_migrate_tail = lmt_alignment_state.cur_pre_migrate_head;
1136 tex_aux_initialize_span(lmt_alignment_state.cur_align);
1137
1138}
1139
1140
1148
1149static inline void tex_alignment_aux_flush_local_template(halfword record)
1150{
1151 if (record) {
1152 if (align_record_pre_local(record)) {
1153 tex_flush_token_list(align_record_pre_local(record));
1154 align_record_pre_local(record) = null;
1155 }
1156 if (align_record_post_local(record)) {
1157 tex_flush_token_list(align_record_post_local(record));
1158 align_record_post_local(record) = null;
1159 }
1160 }
1161}
1162
1163static inline void tex_alignment_aux_scan_local_template(halfword record)
1164{
1165 halfword prehead = null;
1166 halfword posthead = null;
1167 halfword pretail = null;
1168 halfword posttail = null;
1169 do {
1170 tex_get_x_token();
1171 } while (cur_cmd == spacer_cmd);
1172 if (cur_cmd == left_brace_cmd) {
1173 prehead = tex_scan_toks_normal(1, &pretail);
1174
1175 } else {
1176 tex_handle_error(
1177 insert_error_type,
1178 "Missing pre cell token list"
1179 );
1180 }
1181 do {
1182 tex_get_x_token();
1183 } while (cur_cmd == spacer_cmd);
1184 if (cur_cmd == left_brace_cmd) {
1185 posthead = tex_scan_toks_normal(1, &posttail);
1186 tex_store_new_token(posttail, deep_frozen_end_template_token);
1187 } else {
1188 tex_handle_error(
1189 insert_error_type,
1190 "Missing post cell token list"
1191 );
1192 }
1193 if (prehead) {
1194 align_record_pre_local(record) = token_link(prehead);
1195 token_link(prehead) = null;
1196 tex_put_available_token(prehead);
1197 }
1198 if (posthead) {
1199 align_record_post_local(record) = token_link(posthead);
1200 token_link(posthead) = null;
1201 tex_put_available_token(posthead);
1202 }
1203}
1204
1205static void tex_aux_initialize_column(void)
1206{
1207 halfword cmd = cur_cmd;
1208 halfword chr = cur_chr;
1209 align_record_cmd(lmt_alignment_state.cur_align) = cmd;
1210 align_record_chr(lmt_alignment_state.cur_align) = chr;
1211 if (cmd == alignment_cmd) {
1212 switch (chr) {
1213 case re_align_code:
1214 {
1215 tex_alignment_aux_scan_local_template(lmt_alignment_state.cur_align);
1216 cur_cmd = cmd;
1217 cur_chr = chr;
1218 lmt_input_state.align_state = busy_alignment_state;
1219 goto OKAY;
1220 }
1221 case omit_code:
1222 {
1223 lmt_input_state.align_state = 0;
1224 return;
1225 }
1226 }
1227 }
1228
1229 tex_back_input(cur_tok);
1230 OKAY:
1231 if (every_tab_par) {
1232 tex_begin_token_list(every_tab_par, every_tab_text);
1233 }
1234 tex_begin_token_list(align_record_pre_local(lmt_alignment_state.cur_align) ? align_record_pre_local(lmt_alignment_state.cur_align) : align_record_pre_part(lmt_alignment_state.cur_align), template_pre_text);
1235}
1236
1237
1249
1250void tex_insert_alignment_template(void)
1251{
1252 if (lmt_input_state.scanner_status == scanner_is_aligning || ! lmt_alignment_state.cur_align) {
1253 tex_alignment_interwoven_error(6);
1254 } else {
1255
1256 halfword cmd = align_record_cmd(lmt_alignment_state.cur_align);
1257 halfword chr = align_record_chr(lmt_alignment_state.cur_align);
1258 halfword tok = (cmd == alignment_cmd && chr == omit_code) ? lmt_alignment_state.omit_template : align_record_post_local(lmt_alignment_state.cur_align) ? align_record_post_local(lmt_alignment_state.cur_align) : align_record_post_part(lmt_alignment_state.cur_align);
1259 align_record_cmd(lmt_alignment_state.cur_align) = cur_cmd;
1260 align_record_chr(lmt_alignment_state.cur_align) = cur_chr;
1261 tex_begin_token_list(tok, template_post_text);
1262 lmt_input_state.align_state = busy_alignment_state;
1263 lmt_alignment_state.cell_source = alignment_cell_source_par;
1264 if (alignment_wrap_source_par) {
1265 lmt_alignment_state.wrap_source = alignment_wrap_source_par;
1266 }
1267 }
1268}
1269
1270
1271
1272static inline singleword tex_aux_determine_order(scaled *total)
1273{
1274 if (total[filll_glue_order]) return filll_glue_order;
1275 else if (total[fill_glue_order]) return fill_glue_order;
1276 else if (total[fil_glue_order]) return fil_glue_order;
1277 else if (total[fi_glue_order]) return fi_glue_order;
1278 else return normal_glue_order;
1279}
1280
1281
1295
1296static halfword tex_aux_new_span_node(halfword n, int s, scaled w)
1297{
1298 halfword p = tex_new_node(span_node, 0);
1299 span_ptr(p) = n;
1300 span_span(p) = s;
1301 span_width(p) = w;
1302 return p;
1303}
1304
1305
1312
1313void tex_alignment_interwoven_error(int n)
1314{
1315 tex_formatted_error("alignment", "interwoven preambles are not allowed, case %d", n);
1316}
1317
1318halfword tex_alignment_hold_token_head(void)
1319{
1320 return lmt_alignment_state.hold_token_head;
1321}
1322
1323static int tex_aux_finish_column(void)
1324{
1325 tex_alignment_aux_flush_local_template(lmt_alignment_state.cur_align);
1326 if (! lmt_alignment_state.cur_align) {
1327 tex_confusion("end template, case 1");
1328 } else {
1329 halfword q = node_next(lmt_alignment_state.cur_align);
1330 if (! q) {
1331 tex_confusion("end template, case 2");
1332 } else if (lmt_input_state.align_state < interwoven_alignment_threshold) {
1333 tex_alignment_interwoven_error(1);
1334 } else {
1335
1336 halfword cmd = align_record_cmd(lmt_alignment_state.cur_align);
1337 halfword chr = align_record_chr(lmt_alignment_state.cur_align);
1338
1342 halfword record = node_next(q);
1343 if (alignment_wrap_source_par) {
1344 lmt_alignment_state.wrap_source = alignment_wrap_source_par;
1345 }
1346 if (! record && ! ((cmd == alignment_cmd) && (chr == cr_code || chr == cr_cr_code))) {
1347 if (lmt_alignment_state.cur_loop) {
1348
1349 record = tex_new_node(align_record_node, 0);
1350 tex_couple_nodes(q, record);
1351 align_record_span_ptr(record) = end_span;
1352 box_width(record) = null_flag;
1353 lmt_alignment_state.cur_loop = node_next(lmt_alignment_state.cur_loop);
1354
1355 {
1356 halfword q = lmt_alignment_state.hold_token_head;
1357 halfword r = align_record_pre_part(lmt_alignment_state.cur_loop);
1358 while (r) {
1359 q = tex_store_new_token(q, token_info(r));
1360 r = token_link(r);
1361 }
1362 token_link(q) = null;
1363 align_record_pre_part(record) = token_link(lmt_alignment_state.hold_token_head);
1364 }
1365 {
1366 halfword q = lmt_alignment_state.hold_token_head;
1367 halfword r = align_record_post_part(lmt_alignment_state.cur_loop);
1368 while (r) {
1369 q = tex_store_new_token(q, token_info(r));
1370 r = token_link(r);
1371 }
1372 token_link(q) = null;
1373 align_record_post_part(record) = token_link(lmt_alignment_state.hold_token_head);
1374 }
1375 lmt_alignment_state.cur_loop = node_next(lmt_alignment_state.cur_loop);
1376 {
1377 halfword glue = tex_new_glue_node(lmt_alignment_state.cur_loop, tab_skip_glue);
1378 if ((lmt_alignment_state.options & align_option_noskips) && tex_glue_is_zero(glue)) {
1379 node_subtype(glue) = ignored_glue;
1380 }
1381 tex_couple_nodes(record, glue);
1382 }
1383 } else {
1384 chr = cr_code;
1385 align_record_chr(lmt_alignment_state.cur_align) = chr;
1386 tex_handle_error(
1387 normal_error_type,
1388 "Extra alignment tab has been changed to \\cr",
1389 "You have given more \\span or & marks than there were in the preamble to the\n"
1390 "\\halign or \\valign now in progress. So I'll assume that you meant to type \\cr\n"
1391 "instead."
1392 );
1393 }
1394 }
1395 if (! (cmd == alignment_cmd && chr == span_code)) {
1396
1397 halfword cell = null;
1398
1399 scaled width = 0;
1400 scaled size = 0;
1401 int state = 0;
1402 int packing = packing_additional;
1403
1404 halfword spans = 0;
1405 tex_unsave();
1406 tex_new_save_level(align_group);
1407
1408 state = has_box_package_state(lmt_alignment_state.cur_align, package_dimension_size_set);
1409 if (state) {
1410 size = box_size(lmt_alignment_state.cur_align);
1411 packing = packing_exactly;
1412 }
1413 if (cur_list.mode == restricted_hmode) {
1414 lmt_packaging_state.post_adjust_tail = lmt_alignment_state.cur_post_adjust_tail;
1415 lmt_packaging_state.pre_adjust_tail = lmt_alignment_state.cur_pre_adjust_tail;
1416 lmt_packaging_state.post_migrate_tail = lmt_alignment_state.cur_post_migrate_tail;
1417 lmt_packaging_state.pre_migrate_tail = lmt_alignment_state.cur_pre_migrate_tail;
1418 cell = tex_filtered_hpack(cur_list.head, cur_list.tail, size, packing, align_set_group, direction_unknown, 0, null, 0, 0);
1419 width = box_width(cell);
1420 lmt_alignment_state.cur_post_adjust_tail = lmt_packaging_state.post_adjust_tail;
1421 lmt_alignment_state.cur_pre_adjust_tail = lmt_packaging_state.pre_adjust_tail;
1422 lmt_alignment_state.cur_post_migrate_tail = lmt_packaging_state.post_migrate_tail;
1423 lmt_alignment_state.cur_pre_migrate_tail = lmt_packaging_state.pre_migrate_tail;
1424 lmt_packaging_state.post_adjust_tail = null;
1425 lmt_packaging_state.pre_adjust_tail = null;
1426 lmt_packaging_state.post_migrate_tail = null;
1427 lmt_packaging_state.pre_migrate_tail = null;
1428 lmt_packaging_state.except = 0;
1429 } else {
1430 cell = tex_filtered_vpack(node_next(cur_list.head), size, packing, 0, align_set_group, direction_unknown, 0, null, 0, 0, NULL);
1431 width = box_height(cell);
1432 }
1433 if (lmt_alignment_state.cell_source) {
1434 box_source_anchor(cell) = lmt_alignment_state.cell_source;
1435 tex_set_box_geometry(cell, anchor_geometry);
1436 }
1437 tex_attach_attribute_list_attribute(cell, lmt_alignment_state.attr_list);
1438 if (lmt_alignment_state.cur_span != lmt_alignment_state.cur_align) {
1439
1440 halfword ptr = lmt_alignment_state.cur_span;
1441 do {
1442 ++spans;
1443 ptr = node_next(node_next(ptr));
1444 } while (ptr != lmt_alignment_state.cur_align);
1445 if (spans > max_quarterword) {
1446
1447 tex_confusion("too many spans");
1448 }
1449 ptr = lmt_alignment_state.cur_span;
1450 while (span_span(align_record_span_ptr(ptr)) < spans) {
1451 ptr = align_record_span_ptr(ptr);
1452 }
1453 if (span_span(align_record_span_ptr(ptr)) > spans) {
1454 halfword span = tex_aux_new_span_node(align_record_span_ptr(ptr), spans, width);
1455 align_record_span_ptr(ptr) = span;
1456 } else if (span_width(align_record_span_ptr(ptr)) < width) {
1457 span_width(align_record_span_ptr(ptr)) = width;
1458 }
1459 } else if (width > box_width(lmt_alignment_state.cur_align)) {
1460 box_width(lmt_alignment_state.cur_align) = width;
1461 }
1462 tex_aux_change_list_type(cell, unset_node);
1463 box_span_count(cell) = spans;
1464 if (! state) {
1465 singleword order = tex_aux_determine_order(lmt_packaging_state.total_stretch);
1466 box_glue_order(cell) = order;
1467 box_glue_stretch(cell) = lmt_packaging_state.total_stretch[order];
1468 order = tex_aux_determine_order(lmt_packaging_state.total_shrink);
1469 box_glue_sign(cell) = order;
1470 box_glue_shrink(cell) = lmt_packaging_state.total_shrink[order];
1471 }
1472 tex_pop_nest();
1473 tex_tail_append(cell);
1474
1475 if (node_subtype(node_next(lmt_alignment_state.cur_align)) != ignored_glue) {
1476 halfword glue = tex_new_glue_node(node_next(lmt_alignment_state.cur_align), tab_skip_glue);
1477 tex_attach_attribute_list_attribute(cell, lmt_alignment_state.attr_list);
1478 tex_tail_append(glue);
1479 }
1480 if (cmd == alignment_cmd && (chr == cr_code || chr == cr_cr_code)) {
1481 return 1;
1482 } else {
1483 tex_aux_initialize_span(record);
1484 }
1485 }
1486 lmt_input_state.align_state = busy_alignment_state;
1487 do {
1488 tex_get_x_or_protected();
1489 } while (cur_cmd == spacer_cmd);
1490 lmt_alignment_state.cur_align = record;
1491 tex_aux_initialize_column();
1492 }
1493 }
1494 return 0;
1495}
1496
1497
1504
1505static void tex_aux_finish_row(void)
1506{
1507 halfword row;
1508 if (cur_list.mode == restricted_hmode) {
1509 row = tex_filtered_hpack(cur_list.head, cur_list.tail, 0, packing_additional, finish_row_group, direction_unknown, 0, null, 0, 0);
1510 tex_pop_nest();
1511 if (lmt_alignment_state.cur_pre_adjust_head != lmt_alignment_state.cur_pre_adjust_tail) {
1512 tex_inject_adjust_list(lmt_alignment_state.cur_pre_adjust_head, 0, null, NULL);
1513 }
1514 if (lmt_alignment_state.cur_pre_migrate_head != lmt_alignment_state.cur_pre_migrate_tail) {
1515 tex_append_list(lmt_alignment_state.cur_pre_migrate_head, lmt_alignment_state.cur_pre_migrate_tail);
1516 }
1517 tex_append_to_vlist(row, lua_key_index(alignment), NULL);
1518 if (lmt_alignment_state.cur_post_migrate_head != lmt_alignment_state.cur_post_migrate_tail) {
1519 tex_append_list(lmt_alignment_state.cur_post_migrate_head, lmt_alignment_state.cur_post_migrate_tail);
1520 }
1521 if (lmt_alignment_state.cur_post_adjust_head != lmt_alignment_state.cur_post_adjust_tail) {
1522 tex_inject_adjust_list(lmt_alignment_state.cur_post_adjust_head, 0, null, NULL);
1523 }
1524 } else {
1525 row = tex_filtered_vpack(node_next(cur_list.head), 0, packing_additional, max_depth_par, finish_row_group, direction_unknown, 0, null, 0, 0, NULL);
1526 tex_pop_nest();
1527 tex_tail_append(row);
1528 cur_list.space_factor = default_space_factor;
1529 }
1530
1534 if (lmt_alignment_state.wrap_source) {
1535 box_source_anchor(row) = lmt_alignment_state.wrap_source;
1536 box_geometry(row) |= anchor_geometry;
1537 }
1538
1542 tex_aux_change_list_type(row, unset_node);
1543
1544 tex_attach_attribute_list_attribute(row, lmt_alignment_state.row_state.attrlist ?
1545 lmt_alignment_state.row_state.attrlist : lmt_alignment_state.attr_list);
1546
1551 if (lmt_alignment_state.row_state_set) {
1552 halfword orientation = lmt_alignment_state.row_state.orientation;
1553 halfword anchor = lmt_alignment_state.row_state.anchor;
1554 scaled shift = lmt_alignment_state.row_state.shift;
1555 halfword source = lmt_alignment_state.row_state.source;
1556 halfword target = lmt_alignment_state.row_state.target;
1557 scaled xoffset = lmt_alignment_state.row_state.xoffset;
1558 scaled yoffset = lmt_alignment_state.row_state.yoffset;
1559 scaled xmove = lmt_alignment_state.row_state.xmove;
1560 scaled ymove = lmt_alignment_state.row_state.ymove;
1561 singleword geometry = box_geometry(row);
1562
1563 if (xoffset || yoffset || xmove || ymove) {
1564 geometry |= offset_geometry;
1565 }
1566 if (orientation) {
1567 geometry |= orientation_geometry;
1568 }
1569
1570 if (tex_has_geometry(geometry, offset_geometry) || tex_has_geometry(geometry, orientation_geometry)) {
1571 scaled wd = box_width(row);
1572 scaled ht = box_height(row);
1573 scaled dp = box_depth(row);
1574 if (xmove) {
1575 xoffset = tex_aux_checked_dimension1(xoffset + xmove);
1576 wd = tex_aux_checked_dimension2(wd + xmove);
1577 set_box_package_state(row, package_dimension_size_set);
1578 }
1579 if (ymove) {
1580 yoffset = tex_aux_checked_dimension1(yoffset + ymove);
1581 ht = tex_aux_checked_dimension2(ht + ymove);
1582 dp = tex_aux_checked_dimension2(dp - ymove);
1583 }
1584 box_w_offset(row) = wd;
1585 box_h_offset(row) = ht;
1586 box_d_offset(row) = dp;
1587 switch (orientationonly(orientation)) {
1588 case 0 :
1589 break;
1590 case 2 :
1591 box_height(row) = dp;
1592 box_depth(row) = ht;
1593 geometry |= orientation_geometry;
1594 break;
1595 case 1 :
1596 case 3 :
1597 box_width(row) = ht + dp;
1598 box_height(row) = wd;
1599 box_depth(row) = 0;
1600 geometry |= orientation_geometry;
1601 break;
1602 case 4 :
1603 box_height(row) = ht + dp;
1604 box_depth(row) = 0;
1605 geometry |= orientation_geometry;
1606 break;
1607 case 5 :
1608 box_height(row) = 0;
1609 box_depth(row) = ht + dp;
1610 geometry |= orientation_geometry;
1611 break;
1612 default :
1613 break;
1614 }
1615 if (xoffset || yoffset) {
1616 box_x_offset(row) = xoffset;
1617 box_y_offset(row) = yoffset;
1618 geometry |= offset_geometry;
1619 }
1620 }
1621 if (shift) {
1622 box_shift_amount(row) = shift;
1623 }
1624 if (source || target) {
1625 box_source_anchor(row) = source;
1626 box_target_anchor(row) = target;
1627 geometry |= anchor_geometry;
1628 }
1629 box_anchor(row) = anchor;
1630 box_orientation(row) = orientation;
1631 box_geometry(row) = (singleword) geometry;
1632 }
1633
1636 tex_aux_wipe_row_state();
1637
1638 if (every_cr_par) {
1639 tex_begin_token_list(every_cr_par, every_cr_text);
1640 }
1641 tex_aux_align_peek();
1642
1643}
1644
1645
1658
1659static void tex_aux_strip_zero_tab_skips(halfword q)
1660{
1661 halfword h = box_list(q);
1662 halfword t = h;
1663 while (t) {
1664 halfword n = node_next(t);
1665 if (node_type(t) == glue_node && node_subtype(t) == tab_skip_glue && tex_glue_is_zero(t)) {
1666 tex_try_couple_nodes(node_prev(t),n);
1667 if (t == h) {
1668
1669 h = n;
1670 box_list(q) = h;
1671 }
1672 tex_flush_node(t);
1673 }
1674 t = n;
1675 }
1676}
1677
1678
1682
1683static void tex_aux_finish_align(void)
1684{
1685
1686 halfword preroll;
1687
1688 scaled offset = 0;
1689
1690 halfword reverse = lmt_alignment_state.options & align_option_reverse;
1691 halfword callback = lmt_alignment_state.options & align_option_callback;
1692 halfword discard = normalize_line_mode_option(discard_zero_tab_skips_mode) || (lmt_alignment_state.options & align_option_discard);
1693 halfword amount = 0;
1694 halfword mode = 0;
1695
1696 if (cur_group != align_group) {
1697 tex_confusion("align, case 1");
1698 }
1699 tex_unsave();
1700
1701 if (cur_group != align_group) {
1702 tex_confusion("align, case 2");
1703 }
1704 tex_unsave();
1705 if (lmt_nest_state.nest[lmt_nest_state.nest_data.ptr - 1].mode == mmode) {
1706 offset = display_indent_par;
1707 }
1708 lmt_save_state.save_stack_data.ptr -= saved_align_n_of_records;
1709 lmt_packaging_state.pack_begin_line = -cur_list.mode_line;
1710
1719 amount = saved_align_amount;
1720 mode = saved_align_mode;
1721
1722 {
1723 halfword q = node_next(preamble);
1724 do {
1725 tex_flush_token_list(align_record_pre_part(q));
1726 tex_flush_token_list(align_record_post_part(q));
1727 align_record_pre_part(q) = null;
1728 align_record_post_part(q) = null;
1729 q = node_next(node_next(q));
1730 } while (q);
1731 }
1732 if (callback) {
1733 lmt_alignment_callback(cur_list.head, preroll_pass_alignment_context, lmt_alignment_state.callback, lmt_alignment_state.attr_list, preamble);
1734 }
1735
1760 {
1761 halfword q = node_next(preamble);
1762 do {
1763
1764 halfword p = node_next(node_next(q));
1765 if (box_width(q) == null_flag) {
1766
1767 box_width(q) = 0;
1768 tex_reset_glue_to_zero(node_next(q));
1769 }
1770 if (align_record_span_ptr(q) != end_span) {
1771
1784 halfword t = box_width(q) + glue_amount(node_next(q));
1785 halfword n = 1;
1786 halfword r = align_record_span_ptr(q);
1787 halfword s = end_span;
1788 align_record_span_ptr(s) = p;
1789 do {
1790 halfword u = align_record_span_ptr(r);
1791 span_width(r) -= t;
1792 while (span_span(r) > n) {
1793 s = align_record_span_ptr(s);
1794 n = span_span(align_record_span_ptr(s)) + 1;
1795 }
1796 if (span_span(r) < n) {
1797 align_record_span_ptr(r) = align_record_span_ptr(s);
1798 align_record_span_ptr(s) = r;
1799 --span_span(r);
1800 s = r;
1801 } else {
1802 if (span_width(r) > span_width(align_record_span_ptr(s))) {
1803 span_width(align_record_span_ptr(s)) = span_width(r);
1804 }
1805 tex_flush_node(r);
1806 }
1807 r = u;
1808 } while (r != end_span);
1809 }
1810 tex_aux_change_list_type(q, unset_node);
1811 box_glue_order(q) = normal_glue_order;
1812 box_glue_sign(q) = normal_glue_sign;
1813 box_height(q) = 0;
1814 box_depth(q) = 0;
1815 q = p;
1816 } while (q);
1817 }
1818 if (callback) {
1819 lmt_alignment_callback(cur_list.head, package_pass_alignment_context, lmt_alignment_state.callback, lmt_alignment_state.attr_list, preamble);
1820 }
1821
1832 if (cur_list.mode == internal_vmode) {
1833 halfword rule_save = overfull_rule_par;
1834
1835 overfull_rule_par = 0;
1836 preroll = tex_hpack(preamble, amount, mode, direction_unknown, holding_none_option, box_limit_none);
1837 overfull_rule_par = rule_save;
1838 } else {
1839 halfword unset = node_next(preamble);
1840 do {
1841 box_height(unset) = box_width(unset);
1842 box_width(unset) = 0;
1843 unset = node_next(node_next(unset));
1844 } while (unset);
1845
1846 preroll = tex_filtered_vpack(preamble, amount, mode, max_depth_par, preamble_group, direction_unknown, 0, 0, 0, holding_none_option, NULL);
1847
1848
1849 unset = node_next(preamble);
1850 do {
1851 box_width(unset) = box_height(unset);
1852 box_height(unset) = 0;
1853 unset = node_next(node_next(unset));
1854 } while (unset);
1855 }
1856 lmt_packaging_state.pack_begin_line = 0;
1857
1861 {
1862 halfword rowptr = node_next(cur_list.head);
1863 while (rowptr) {
1864 switch (node_type(rowptr)) {
1865 case unset_node:
1866 {
1867
1875 halfword preptr;
1876 halfword colptr;
1877 if (cur_list.mode == internal_vmode) {
1878
1879 node_type(rowptr) = hlist_node;
1880 box_width(rowptr) = box_width(preroll);
1881 } else {
1882
1883 node_type(rowptr) = vlist_node;
1884 box_height(rowptr) = box_height(preroll);
1885 }
1886 node_subtype(rowptr) = align_row_list;
1887 box_glue_order(rowptr) = box_glue_order(preroll);
1888 box_glue_sign(rowptr) = box_glue_sign(preroll);
1889 box_glue_set(rowptr) = box_glue_set(preroll);
1890 box_shift_amount(rowptr) = offset;
1891 colptr = box_list(rowptr);
1892 preptr = box_list(preroll);
1893 if (node_type(colptr) == glue_node) {
1894 colptr = node_next(colptr);
1895 }
1896 if (node_type(preptr) == glue_node) {
1897 preptr = node_next(preptr);
1898 }
1899 if (node_type(colptr) != unset_node) {
1900 tex_formatted_error("alignment", "bad box");
1901 }
1902 do {
1903
1911 halfword spans = box_span_count(colptr);
1912 scaled total = box_width(preptr);
1913 scaled width = total;
1914 halfword tail = hold_head;
1915 int state = has_box_package_state(preptr, package_dimension_size_set);
1916
1922 while (spans > 0) {
1923 --spans;
1924 preptr = node_next(preptr);
1925 if (node_subtype(preptr) != ignored_glue) {
1926
1927 halfword glue = tex_new_glue_node(preptr, node_subtype(preptr));
1928 tex_try_couple_nodes(tail, glue);
1929 tex_attach_attribute_list_attribute(glue, lmt_alignment_state.attr_list);
1930 total += glue_amount(preptr);
1931
1932 switch (box_glue_sign(preroll)) {
1933 case stretching_glue_sign:
1934 if (glue_stretch_order(preptr) == box_glue_order(preroll)) {
1935 total += glueround((glueratio) (box_glue_set(preroll)) * (glueratio) (glue_stretch(preptr)));
1936 }
1937 break;
1938 case shrinking_glue_sign:
1939 if (glue_shrink_order(preptr) == box_glue_order(preroll)) {
1940 total -= glueround((glueratio) (box_glue_set(preroll)) * (glueratio) (glue_shrink(preptr)));
1941 }
1942 break;
1943 }
1944 tail = glue;
1945
1946 }
1947 preptr = node_next(preptr);
1948 {
1949 halfword box = tex_new_null_box_node(cur_list.mode == internal_vmode ? hlist_node : vlist_node, align_cell_list);
1950 tex_couple_nodes(tail, box);
1951 tex_attach_attribute_list_attribute(box, lmt_alignment_state.attr_list);
1952 total += box_width(preptr);
1953 if (cur_list.mode == internal_vmode) {
1954 box_width(box) = box_width(preptr);
1955 } else {
1956 box_height(box) = box_width(preptr);
1957 }
1958 tail = box;
1959 }
1960 }
1961 if (cur_list.mode == internal_vmode) {
1962
1966 box_height(colptr) = box_height(rowptr);
1967 box_depth(colptr) = box_depth(rowptr);
1968 if (! state) {
1969 if (total == box_width(colptr)) {
1970 box_glue_sign(colptr) = normal_glue_sign;
1971 box_glue_order(colptr) = normal_glue_order;
1972 box_glue_set(colptr) = 0.0;
1973 } else if (total > box_width(colptr)) {
1974 box_glue_sign(colptr) = stretching_glue_sign;
1975 if (box_glue_stretch(colptr) == 0) {
1976 box_glue_set(colptr) = 0.0;
1977 } else {
1978 box_glue_set(colptr) = (glueratio) ( ( (glueratio) total - (glueratio) box_width(colptr) ) / ( (glueratio) box_glue_stretch(colptr) ) );
1979 }
1980 } else {
1981 box_glue_order(colptr) = box_glue_sign(colptr);
1982 box_glue_sign(colptr) = shrinking_glue_sign;
1983 if (box_glue_shrink(colptr) == 0) {
1984 box_glue_set(colptr) = 0.0;
1985 } else if ((box_glue_order(colptr) == normal_glue_order) && (box_width(colptr) - total > box_glue_shrink(colptr))) {
1986 box_glue_set(colptr) = 1.0;
1987 } else {
1988 box_glue_set(colptr) = (glueratio) ( ( (glueratio) box_width(colptr) - (glueratio) total ) / ( (glueratio) box_glue_shrink(colptr) ) );
1989 }
1990 }
1991 }
1992 box_width(colptr) = width;
1993 tex_aux_change_list_type(colptr, hlist_node);
1994 node_subtype(colptr) = align_cell_list;
1995 } else {
1996
2000 box_width(colptr) = box_width(rowptr);
2001 if (! state) {
2002 if (total == box_height(colptr)) {
2003 box_glue_sign(colptr) = normal_glue_sign;
2004 box_glue_order(colptr) = normal_glue_order;
2005 box_glue_set(colptr) = 0.0;
2006 } else if (total > box_height(colptr)) {
2007 box_glue_sign(colptr) = stretching_glue_sign;
2008 if (box_glue_stretch(colptr) == 0) {
2009 box_glue_set(colptr) = 0.0;
2010 } else {
2011 box_glue_set(colptr) = (glueratio) ( ( (glueratio) total - (glueratio) box_height(colptr) ) / ( (glueratio) box_glue_stretch(colptr) ) );
2012 }
2013 } else {
2014 box_glue_order(colptr) = box_glue_sign(colptr);
2015 box_glue_sign(colptr) = shrinking_glue_sign;
2016 if (box_glue_shrink(colptr) == 0) {
2017 box_glue_set(colptr) = 0.0;
2018 } else if ((box_glue_order(colptr) == normal_glue_order) && (box_height(colptr) - total > box_glue_shrink(colptr))) {
2019 box_glue_set(colptr) = 1.0;
2020 } else {
2021 box_glue_set(colptr) = (glueratio) ( ( (glueratio) box_height(colptr) - (glueratio) total) / ( (glueratio) box_glue_shrink(colptr) ) );
2022 }
2023 }
2024 }
2025 box_height(colptr) = width;
2026 tex_aux_change_list_type(colptr, vlist_node);
2027 node_subtype(colptr) = align_cell_list;
2028 }
2029 box_shift_amount(colptr) = 0;
2030 if (tail != hold_head) {
2031
2032 tex_try_couple_nodes(tail, node_next(colptr));
2033 tex_try_couple_nodes(colptr, node_next(hold_head));
2034 colptr = tail;
2035 }
2036 colptr = node_next(colptr);
2037 preptr = node_next(preptr);
2038 if (node_type(colptr) == glue_node) {
2039 colptr = node_next(colptr);
2040 }
2041 if (node_type(preptr) == glue_node) {
2042 preptr = node_next(preptr);
2043 }
2044 } while (colptr);
2045 if (discard) {
2046 tex_aux_strip_zero_tab_skips(rowptr);
2047 }
2048 if (reverse) {
2049 box_list(rowptr) = tex_reversed_node_list(box_list(rowptr));
2050 }
2051 if (has_box_package_state(rowptr, package_dimension_size_set)) {
2052 if (box_w_offset(rowptr) > box_width(rowptr)) {
2053 box_width(rowptr) = box_w_offset(rowptr);
2054 }
2055 }
2056 }
2057 break;
2058 case rule_node:
2059 {
2060
2064 if (rule_width(rowptr) == null_flag) {
2065 rule_width(rowptr) = box_width(preroll);
2066 }
2067 if (rule_height(rowptr) == null_flag) {
2068 rule_height(rowptr) = box_height(preroll);
2069 }
2070 if (rule_depth(rowptr) == null_flag) {
2071 rule_depth(rowptr) = box_depth(preroll);
2072 }
2073
2074 if (offset) {
2075 halfword prv = node_prev(rowptr);
2076 halfword nxt = node_next(rowptr);
2077 halfword box = null;
2078 node_prev(rowptr) = null;
2079 node_next(rowptr) = null;
2080 box = tex_hpack(rowptr, 0, packing_additional, direction_unknown, holding_none_option, box_limit_none);
2081 tex_attach_attribute_list_attribute(box, rowptr);
2082 box_shift_amount(box) = offset;
2083 node_subtype(box) = align_cell_list;
2084
2085 tex_try_couple_nodes(prv, box);
2086 tex_try_couple_nodes(box, nxt);
2087 rowptr = box;
2088 }
2089 }
2090 break;
2091 default:
2092
2098 break;
2099 }
2100 rowptr = node_next(rowptr);
2101 }
2102 }
2103 if (callback) {
2104 lmt_alignment_callback(cur_list.head, wrapup_pass_alignment_context, lmt_alignment_state.callback, lmt_alignment_state.attr_list, preamble);
2105 }
2106 tex_flush_node_list(preroll);
2107 delete_attribute_reference(lmt_alignment_state.attr_list);
2108 tex_aux_pop_alignment();
2109
2116 {
2117 scaled prevdepth = cur_list.prev_depth;
2118 halfword head = node_next(cur_list.head);
2119 halfword tail = cur_list.tail;
2120 tex_pop_nest();
2121 if (cur_list.mode == mmode) {
2122 tex_finish_display_alignment(head, tail, prevdepth);
2123 } else {
2124 cur_list.prev_depth = prevdepth;
2125 if (head) {
2126 tex_tail_append(head);
2127 cur_list.tail = tail;
2128 }
2129 if (cur_list.mode == vmode) {
2130 tex_build_page(alignment_page_context, 0);
2131 }
2132 }
2133 }
2134}
2135
2136
2142
2143void tex_initialize_alignments(void)
2144{
2145 lmt_alignment_state.hold_token_head = tex_get_available_token(null);
2146 lmt_alignment_state.omit_template = tex_get_available_token(deep_frozen_end_template_token);
2147 span_span(end_span) = max_quarterword + 1;
2148 align_record_span_ptr(end_span) = null;
2149}
2150
2151
2157
2158void tex_cleanup_alignments(void)
2159{
2160 tex_put_available_token(lmt_alignment_state.hold_token_head);
2161 tex_put_available_token(lmt_alignment_state.omit_template);
2162 lmt_alignment_state.hold_token_head = null;
2163 lmt_alignment_state.omit_template = null;
2164 delete_attribute_reference(lmt_alignment_state.attr_list);
2165 lmt_alignment_state.attr_list = null;
2166}
2167
2168
2180
2181void tex_run_alignment_end_template(void)
2182{
2183 lmt_input_state.base_ptr = lmt_input_state.input_stack_data.ptr;
2184 lmt_input_state.input_stack[lmt_input_state.base_ptr] = lmt_input_state.cur_input;
2185 while (( lmt_input_state.input_stack[lmt_input_state.base_ptr].index != template_post_text)
2186 && (! lmt_input_state.input_stack[lmt_input_state.base_ptr].loc)
2187 && ( lmt_input_state.input_stack[lmt_input_state.base_ptr].state == token_list_state)) {
2188 --lmt_input_state.base_ptr;
2189 }
2190 if (lmt_input_state.input_stack[lmt_input_state.base_ptr].index != template_post_text) {
2191 tex_alignment_interwoven_error(2);
2192 } else if (lmt_input_state.input_stack[lmt_input_state.base_ptr].loc) {
2193 tex_alignment_interwoven_error(3);
2194 } else if (lmt_input_state.input_stack[lmt_input_state.base_ptr].state != token_list_state) {
2195 tex_alignment_interwoven_error(4);
2196 } else if (cur_group == align_group) {
2197 if (! tex_wrapped_up_paragraph(align_par_context, 0)) {
2198 tex_end_paragraph(align_group, align_par_context);
2199 if (tex_aux_finish_column()) {
2200 tex_aux_finish_row();
2201 }
2202 }
2203 } else {
2204 tex_off_save();
2205 }
2206}
2207
2208
2224
2225void tex_run_alignment_error(void)
2226{
2227 int cmd = cur_cmd;
2228 int chr = cur_chr;
2229 if (cmd == alignment_cmd && chr == no_align_code) {
2230 if (tex_aux_nested_no_align()) {
2231
2232 } else {
2233 tex_handle_error(
2234 normal_error_type,
2235 "Misplaced \\noalign",
2236 "I expect to see \\noalign only after the \\cr of an alignment. Proceed, and I'll\n"
2237 "ignore this case."
2238 );
2239 }
2240 } else if (abs(lmt_input_state.align_state) > 2) {
2241
2248 switch (cmd) {
2249 case alignment_tab_cmd:
2250 tex_handle_error(normal_error_type, "Misplaced %C", cmd, chr,
2251 "I can't figure out why you would want to use a tab mark here. If some right brace\n"
2252 "up above has ended a previous alignment prematurely, you're probably due for more\n"
2253 "error messages."
2254 );
2255 break;
2256 default:
2257 tex_handle_error(normal_error_type, "Misplaced %C", cmd, chr,
2258 "I can't figure out why you would want to use a tab mark or \\cr or \\span just\n"
2259 "now. If something like a right brace up above has ended a previous alignment\n"
2260 "prematurely, you're probably due for more error messages."
2261 );
2262 break;
2263 }
2264 } else {
2265 const char * helpinfo =
2266 "I've put in what seems to be necessary to fix the current column of the current\n"
2267 "alignment. Try to go on, since this might almost work.";
2268 tex_back_input(cur_tok);
2269 if (lmt_input_state.align_state < 0) {
2270 ++lmt_input_state.align_state;
2271 cur_tok = left_brace_token + '{';
2272 tex_handle_error(
2273 insert_error_type,
2274 "Missing { inserted",
2275 helpinfo
2276 );
2277 } else {
2278 --lmt_input_state.align_state;
2279 cur_tok = right_brace_token + '}';
2280 switch (cmd) {
2281 case alignment_cmd:
2282 tex_handle_error(
2283 insert_error_type,
2284 "Missing } inserted, unexpected ",
2285 cmd, chr,
2286 helpinfo
2287 );
2288 break;
2289 case alignment_tab_cmd:
2290 tex_handle_error(
2291 insert_error_type,
2292 "Missing } inserted, unexpected tab character (normally &)",
2293 helpinfo
2294 );
2295 break;
2296 }
2297 }
2298 }
2299}
2300 |