2 Copyright 2014 Clerk Ma
\r
4 This program is free software; you can redistribute it and/or modify
\r
5 it under the terms of the GNU General Public License as published by
\r
6 the Free Software Foundation; either version 2 of the License, or
\r
7 (at your option) any later version.
\r
9 This program is distributed in the hope that it will be useful, but
\r
10 WITHOUT ANY WARRANTY; without even the implied warranty of
\r
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
12 General Public License for more details.
\r
14 You should have received a copy of the GNU General Public License
\r
15 along with this program; if not, write to the Free Software
\r
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
\r
20 #define EXTERN extern
\r
21 #include "yandytex.h"
\r
24 void build_page (void)
\r
30 /* unsigned char n; */
\r
34 if ((link(contrib_head) == 0) || output_active)
\r
40 p = link(contrib_head);
\r
42 if (last_glue != max_halfword)
\r
43 delete_glue_ref(last_glue);
\r
48 if (type(p) == glue_node)
\r
50 last_glue = glue_ptr(p);
\r
51 add_glue_ref(last_glue);
\r
55 last_glue = max_halfword;
\r
57 if (type(p) == penalty_node)
\r
58 last_penalty = penalty(p);
\r
59 else if (type(p) == kern_node)
\r
60 last_kern = width(p);
\r
68 if (page_contents < box_there)
\r
70 if (page_contents == 0)
\r
71 freeze_page_specs(box_there);
\r
73 page_contents = box_there;
\r
75 q = new_skip_param(top_skip_code);
\r
77 if (width(temp_ptr) > height(p))
\r
78 width(temp_ptr) = width(temp_ptr) - height(p);
\r
80 width(temp_ptr) = 0;
\r
83 link(contrib_head) = q;
\r
88 page_total = page_total + page_depth + height(p);
\r
89 page_depth = depth(p);
\r
99 if (page_contents < box_there)
\r
101 else if (precedes_break(page_tail))
\r
104 goto update_heights;
\r
108 if (page_contents < box_there)
\r
110 else if (link(p) == 0)
\r
112 else if (type(link(p)) == glue_node)
\r
115 goto update_heights;
\r
119 if (page_contents < box_there)
\r
131 if (page_contents == 0)
\r
132 freeze_page_specs(inserts_only);
\r
137 while (n >= subtype(link(r)))
\r
142 if (subtype(r) != n)
\r
144 q = get_node(page_ins_node_size);
\r
149 type(r) = inserting;
\r
155 height(r) = height(box(n)) + depth(box(n));
\r
157 best_ins_ptr(r) = 0;
\r
160 if (count(n) == 1000)
\r
163 h = x_over_n(height(r), 1000) * count(n);
\r
165 page_goal = page_goal - h - width(q);
\r
166 page_so_far[2 + stretch_order(q)] = page_so_far[2 + stretch_order(q)] + stretch(q);
\r
167 page_shrink = page_shrink + shrink(q);
\r
169 if ((shrink_order(q) != normal) && (shrink(q) != 0))
\r
171 print_err("Infinite glue shrinkage inserted from ");
\r
174 help3("The correction glue for page breaking with insertions",
\r
175 "must have finite shrinkability. But you may proceed,",
\r
176 "since the offensive shrinkability has been made finite.");
\r
181 if (type(r) == split_up)
\r
182 insert_penalties = insert_penalties + float_cost(p);
\r
185 last_ins_ptr(r) = p;
\r
186 delta = page_goal - page_total - page_depth + page_shrink;
\r
188 if (count(n) == 1000)
\r
191 h = x_over_n(height(p), 1000) * count(n);
\r
193 if (((h <= 0) || (h <= delta)) && (height(p) + height(r) <= dimen(n)))
\r
195 page_goal = page_goal - h;
\r
196 height(r) = height(r) + height(p);
\r
204 w = page_goal - page_total - page_depth;
\r
206 if (count(n) != 1000)
\r
207 w = x_over_n(w, count(n)) * 1000;
\r
210 if (w > dimen(n) - height(r))
\r
211 w = dimen(n) - height(r);
\r
213 q = vert_break(ins_ptr(p), w, depth(p));
\r
214 height(r) = height(r) + best_height_plus_depth;
\r
216 if (tracing_pages > 0)
\r
218 begin_diagnostic();
\r
219 print_nl("% split");
\r
224 print_scaled(best_height_plus_depth);
\r
228 print_int(eject_penalty);
\r
229 else if (type(q) == penalty_node)
\r
230 print_int(penalty(q));
\r
234 end_diagnostic(false);
\r
237 if (count(n) != 1000)
\r
238 best_height_plus_depth = x_over_n(best_height_plus_depth, 1000) * count(n);
\r
240 page_goal = page_goal - best_height_plus_depth;
\r
241 type(r) = split_up;
\r
246 insert_penalties = insert_penalties + (eject_penalty);
\r
247 else if (type(q) == penalty_node)
\r
248 insert_penalties = insert_penalties + penalty(q);
\r
263 if (pi < inf_penalty)
\r
265 if (page_total < page_goal)
\r
266 if ((page_so_far[3] != 0) || (page_so_far[4] != 0) || (page_so_far[5] != 0))
\r
269 b = badness(page_goal - page_total, page_so_far[2]);
\r
270 else if (page_total - page_goal > page_shrink)
\r
273 b = badness(page_total - page_goal, page_shrink);
\r
276 if (pi <= eject_penalty)
\r
278 else if (b < inf_bad)
\r
279 c = b + pi + insert_penalties;
\r
285 if (insert_penalties >= 10000)
\r
289 if (tracing_pages > 0)
\r
291 begin_diagnostic();
\r
296 print_scaled(page_goal);
\r
299 if (b == awful_bad)
\r
308 if (c == awful_bad)
\r
313 if (c <= least_page_cost)
\r
316 end_diagnostic(false);
\r
320 if (c <= least_page_cost)
\r
322 best_page_break = p;
\r
323 best_size = page_goal;
\r
324 least_page_cost = c;
\r
325 r = link(page_ins_head);
\r
327 while (r != page_ins_head)
\r
329 best_ins_ptr(r) = last_ins_ptr(r);
\r
334 if ((c == awful_bad) || (pi <= eject_penalty))
\r
345 if ((type(p) < glue_node) || (type(p) > kern_node))
\r
349 if (type(p) == kern_node)
\r
354 page_so_far[2 + stretch_order(q)] = page_so_far[2 + stretch_order(q)] + stretch(q);
\r
355 page_shrink = page_shrink + shrink(q);
\r
357 if ((shrink_order(q) != normal) && (shrink(q) != 0))
\r
359 print_err("Infinite glue shrinkage found on current page");
\r
360 help4("The page about to be output contains some infinitely",
\r
361 "shrinkable glue, e.g., `\\vss' or `\\vskip 0pt minus 1fil'.",
\r
362 "Such glue doesn't belong there; but you can safely proceed,",
\r
363 "since the offensive shrinkability has been made finite.");
\r
366 shrink_order(r) = normal;
\r
367 delete_glue_ref(q);
\r
373 page_total = page_total + page_depth + width(q);
\r
377 if (page_depth > page_max_depth)
\r
379 page_total = page_total + page_depth - page_max_depth;
\r
380 page_depth = page_max_depth;
\r
383 link(page_tail) = p;
\r
385 link(contrib_head) = link(p);
\r
390 link(contrib_head) = link(p);
\r
392 flush_node_list(p);
\r
395 while (!(link(contrib_head) == 0));
\r
398 tail = contrib_head;
\r
400 nest[0].tail_field = contrib_head;
\r
403 void app_space (void)
\r
407 if ((space_factor >= 2000) && (xspace_skip != zero_glue))
\r
408 q = new_param_glue(xspace_skip_code);
\r
411 if (space_skip != zero_glue)
\r
412 main_p = space_skip;
\r
415 main_p = font_glue[cur_font];
\r
419 main_p = new_spec(zero_glue);
\r
420 main_k = param_base[cur_font] + space_code;
\r
421 width(main_p) = font_info[main_k].cint;
\r
422 stretch(main_p) = font_info[main_k + 1].cint;
\r
423 shrink(main_p) = font_info[main_k + 2].cint;
\r
424 font_glue[cur_font] = main_p;
\r
428 main_p = new_spec(main_p);
\r
430 if (space_factor >= 2000)
\r
431 width(main_p) = width(main_p) + extra_space(cur_font);
\r
433 stretch(main_p) = xn_over_d(stretch(main_p), space_factor, 1000);
\r
434 shrink(main_p) = xn_over_d(shrink(main_p), 1000, space_factor);
\r
435 q = new_glue(main_p);
\r
436 glue_ref_count(main_p) = 0;
\r
443 void insert_dollar_sign (void)
\r
446 cur_tok = math_shift_token + '$';
\r
447 print_err("Missing $ inserted");
\r
448 help2("I've inserted a begin-math/end-math symbol since I think",
\r
449 "you left one out. Proceed, with fingers crossed.");
\r
453 void you_cant (void)
\r
455 print_err("You can't use `");
\r
456 print_cmd_chr(cur_cmd, cur_chr);
\r
461 void report_illegal_case (void)
\r
464 help4("Sorry, but I'm not programmed to handle this case;",
\r
465 "I'll just pretend that you didn't ask for it.",
\r
466 "If you're in the wrong mode, you might be able to",
\r
467 "return to the right one by typing `I}' or `I$' or `I\\par'.");
\r
471 boolean privileged (void)
\r
477 report_illegal_case();
\r
482 boolean its_all_over (void)
\r
486 if ((page_head == page_tail) && (head == tail) && (dead_cycles == 0))
\r
492 tail_append(new_null_box());
\r
493 width(tail) = hsize;
\r
494 tail_append(new_glue(fill_glue));
\r
495 tail_append(new_penalty(-1073741824L));
\r
502 void append_glue (void)
\r
511 cur_val = fil_glue;
\r
515 cur_val = fill_glue;
\r
523 cur_val = fil_neg_glue;
\r
527 scan_glue(glue_val);
\r
535 tail_append(new_glue(cur_val));
\r
537 if (s >= skip_code)
\r
539 decr(glue_ref_count(cur_val));
\r
542 subtype(tail) = mu_glue;
\r
546 void append_kern (void)
\r
552 scan_dimen((s == mu_glue), false, false);
\r
553 tail_append(new_kern(cur_val));
\r
557 void off_save (void)
\r
561 if (cur_group == bottom_level)
\r
563 print_err("Extra ");
\r
564 print_cmd_chr(cur_cmd, cur_chr);
\r
565 help1("Things are pretty mixed up, but I think the worst is over.");
\r
572 link(temp_head) = p;
\r
573 print_err("Missing ");
\r
577 case semi_simple_group:
\r
579 info(p) = cs_token_flag + frozen_end_group;
\r
580 print_esc("endgroup");
\r
584 case math_shift_group:
\r
586 info(p) = math_shift_token + '$';
\r
591 case math_left_group:
\r
593 info(p) = cs_token_flag + frozen_right;
\r
594 link(p) = get_avail();
\r
596 info(p) = other_token + '.';
\r
597 print_esc("right.");
\r
603 info(p) = right_brace_token + '}';
\r
609 prints(" inserted");
\r
610 ins_list(link(temp_head));
\r
611 help5("I've inserted something that you may have forgotten.",
\r
612 "(See the <inserted text> above.)",
\r
613 "With luck, this will get me unwedged. But if you",
\r
614 "really didn't forget anything, try typing `2' now; then",
\r
615 "my insertion and my current dilemma will both disappear.");
\r
620 void extra_right_brace (void)
\r
622 print_err("Extra }, or forgotten ");
\r
626 case semi_simple_group:
\r
627 print_esc("endgroup");
\r
630 case math_shift_group:
\r
634 case math_left_group:
\r
635 print_esc("right");
\r
639 help5("I've deleted a group-closing symbol because it seems to be",
\r
640 "spurious, as in `$x}$'. But perhaps the } is legitimate and",
\r
641 "you forgot something else, as in `\\hbox{$x}'. In such cases",
\r
642 "the way to recover is to insert both the forgotten and the",
\r
643 "deleted material, e.g., by typing `I$}'.");
\r
648 void normal_paragraph (void)
\r
650 if (looseness != 0)
\r
651 eq_word_define(int_base + looseness_code, 0);
\r
653 if (hang_indent != 0)
\r
654 eq_word_define(dimen_base + hang_indent_code, 0);
\r
656 if (hang_after != 1)
\r
657 eq_word_define(int_base + hang_after_code, 1);
\r
659 if (par_shape_ptr != 0)
\r
660 eq_define(par_shape_loc, shape_ref, 0);
\r
663 void box_end (integer box_context)
\r
667 if (box_context < box_flag)
\r
671 shift_amount(cur_box) = box_context;
\r
673 if (abs(mode) == vmode)
\r
675 append_to_vlist(cur_box);
\r
677 if (adjust_tail != 0)
\r
679 if (adjust_head != adjust_tail)
\r
681 link(tail) = link(adjust_head);
\r
682 tail = adjust_tail;
\r
693 if (abs(mode) == hmode)
\r
694 space_factor = 1000;
\r
698 math_type(nucleus(p)) = sub_box;
\r
699 info(nucleus(p)) = cur_box;
\r
703 link(tail) = cur_box;
\r
708 else if (box_context < ship_out_flag)
\r
709 if (box_context < (box_flag + 256))
\r
710 eq_define((box_base - box_flag) + box_context, box_ref, cur_box);
\r
712 geq_define((box_base - box_flag - 256) + box_context, box_ref, cur_box);
\r
713 else if (cur_box != 0)
\r
714 if (box_context > ship_out_flag)
\r
720 while (!((cur_cmd != spacer) && (cur_cmd != relax)));
\r
722 if (((cur_cmd == hskip) && (abs(mode) != vmode)) || ((cur_cmd == vskip) && (abs(mode) == vmode)))
\r
725 subtype(tail) = box_context - (leader_flag - a_leaders);
\r
726 leader_ptr(tail) = cur_box;
\r
730 print_err("Leaders not followed by proper glue");
\r
731 help3("You should say `\\leaders <box or rule><hskip or vskip>'.",
\r
732 "I found the <box or rule>, but there's no suitable",
\r
733 "<hskip or vskip>, so I'm ignoring these leaders.");
\r
735 flush_node_list(cur_box);
\r
742 void begin_box (integer box_context)
\r
753 scan_eight_bit_int();
\r
754 cur_box = box(cur_val);
\r
761 scan_eight_bit_int();
\r
762 cur_box = copy_node_list(box(cur_val));
\r
766 case last_box_code:
\r
770 if (abs(mode) == mmode)
\r
773 help1("Sorry; this \\lastbox will be void.");
\r
776 else if ((mode == vmode) && (head == cur_list.tail_field))
\r
779 help2("Sorry...I usually can't take things from the current page.",
\r
780 "This \\lastbox will therefore be void.");
\r
785 if (!is_char_node(tail))
\r
786 if ((type(tail) == hlist_node) || (type(tail) == vlist_node))
\r
794 if (!is_char_node(q))
\r
795 if (type(q) == disc_node)
\r
797 for (m = 1; m <= replace_count(q); m++)
\r
806 while (!(q == tail));
\r
809 shift_amount(cur_box) = 0;
\r
820 scan_eight_bit_int();
\r
823 if (!scan_keyword("to"))
\r
825 print_err("Missing `to' inserted");
\r
826 help2("I'm working on `\\vsplit<box number> to <dimen>';",
\r
827 "will look for the <dimen> next.");
\r
831 scan_dimen(false, false, false);
\r
832 cur_box = vsplit(n, cur_val);
\r
838 k = cur_chr - vtop_code;
\r
839 saved(0) = box_context;
\r
842 if ((box_context < box_flag) && (abs(mode) == vmode))
\r
843 scan_spec(adjust_hbox_group, true);
\r
845 scan_spec(hbox_group, true);
\r
849 scan_spec(vbox_group, true);
\r
852 scan_spec(vtop_group, true);
\r
856 normal_paragraph();
\r
860 mode = - (integer) k;
\r
864 prev_depth = ignore_depth;
\r
866 if (every_vbox != 0)
\r
867 begin_token_list(every_vbox, every_vbox_text);
\r
871 space_factor = 1000;
\r
873 if (every_hbox != 0)
\r
874 begin_token_list(every_hbox, every_vbox_text);
\r
882 box_end(box_context);
\r
885 void scan_box_(integer box_context)
\r
891 while (!((cur_cmd != spacer) && (cur_cmd != relax)));
\r
893 if (cur_cmd == make_box)
\r
895 begin_box(box_context);
\r
897 else if ((box_context >= leader_flag) && ((cur_cmd == hrule) || (cur_cmd == vrule)))
\r
899 cur_box = scan_rule_spec();
\r
900 box_end(box_context);
\r
904 print_err("A <box> was supposed to be here");
\r
905 help3("I was expecting to see \\hbox or \\vbox or \\copy or \\box or",
\r
906 "something like that. So you might find something missing in",
\r
907 "your output. But keep trying; you can fix this later.");
\r
912 small_number norm_min (integer h)
\r
922 void new_graf (boolean indented)
\r
926 if ((mode == vmode) || (head != tail))
\r
927 tail_append(new_param_glue(par_skip_code));
\r
931 space_factor = 1000;
\r
934 prev_graf = (norm_min(left_hyphen_min) * 64 + norm_min(right_hyphen_min)) * 65536L + cur_lang;
\r
938 tail = new_null_box();
\r
940 width(tail) = par_indent;
\r
943 if (every_par != 0)
\r
944 begin_token_list(every_par, every_par_text);
\r
950 void indent_in_hmode (void)
\r
956 p = new_null_box();
\r
957 width(p) = par_indent;
\r
959 if (abs(mode) == hmode)
\r
960 space_factor = 1000;
\r
964 math_type(nucleus(q)) = sub_box;
\r
965 info(nucleus(q)) = p;
\r
973 void head_for_vmode (void)
\r
977 if (cur_cmd != hrule)
\r
981 print_err("You can't use `");
\r
982 print_esc("hrule");
\r
983 prints("' here except with leaders");
\r
984 help2("To put a horizontal rule in an hbox or an alignment,",
\r
985 "you should use \\leaders or \\hrulefill (see The TeXbook).");
\r
992 cur_tok = par_token;
\r
998 void end_graf (void)
\r
1000 if (mode == hmode)
\r
1005 line_break(widow_penalty);
\r
1007 normal_paragraph();
\r
1012 void begin_insert_or_adjust (void)
\r
1014 if (cur_cmd == vadjust)
\r
1018 scan_eight_bit_int();
\r
1020 if (cur_val == 255)
\r
1022 print_err("You can't ");
\r
1023 print_esc("insert");
\r
1025 help1("I'm changing to \\insert0; box 255 is special.");
\r
1031 saved(0) = cur_val;
\r
1033 new_save_level(insert_group);
\r
1034 scan_left_brace();
\r
1035 normal_paragraph();
\r
1038 prev_depth = ignore_depth;
\r
1041 void make_mark (void)
\r
1045 p = scan_toks(false, true);
\r
1046 p = get_node(small_node_size);
\r
1047 type(p) = mark_node;
\r
1049 mark_ptr(p) = def_ref;
\r
1054 void append_penalty (void)
\r
1057 tail_append(new_penalty(cur_val));
\r
1059 if (mode == vmode)
\r
1063 void delete_last (void)
\r
1068 if ((mode == vmode) && (tail == head))
\r
1070 if ((cur_chr != glue_node) || (last_glue != max_halfword))
\r
1073 help2("Sorry...I usually can't take things from the current page.",
\r
1074 "Try `I\\vskip-\\lastskip' instead.");
\r
1076 if (cur_chr == kern_node)
\r
1077 help_line[0] = "Try `I\\kern-\\last_kern' instead.";
\r
1078 else if (cur_chr != glue_node)
\r
1079 help_line[0] = "Perhaps you can make the output routine do it.";
\r
1085 if (!is_char_node(tail))
\r
1086 if (type(tail) == cur_chr)
\r
1094 if (!is_char_node(q))
\r
1095 if (type(q) == disc_node)
\r
1097 for (m = 1; m <= replace_count(q); m++)
\r
1106 while (!(q == tail));
\r
1109 flush_node_list(tail);
\r
1115 void unpackage (void)
\r
1121 scan_eight_bit_int();
\r
1127 if ((abs(mode) == mmode) || ((abs(mode) == vmode) && (type(p) != vlist_node)) ||
\r
1128 ((abs(mode) == hmode) && (type(p) != hlist_node)))
\r
1130 print_err("Incompatible list can't be unboxed");
\r
1131 help3("Sorry, Pandora. (You sneaky devil.)",
\r
1132 "I refuse to unbox an \\hbox in vertical mode or vice versa.",
\r
1133 "And I can't open any boxes in math mode.");
\r
1138 if (c == copy_code)
\r
1139 link(tail) = copy_node_list(list_ptr(p));
\r
1142 link(tail) = list_ptr(p);
\r
1144 free_node(p, box_node_size);
\r
1147 while (link(tail) != 0)
\r
1148 tail = link(tail);
\r
1151 void append_italic_correction (void)
\r
1154 internal_font_number f;
\r
1158 if (is_char_node(tail))
\r
1160 else if (type(tail) == ligature_node)
\r
1166 tail_append(new_kern(char_italic(f, char_info(f, character(p)))));
\r
1167 subtype(tail) = explicit;
\r
1171 void append_discretionary (void)
\r
1175 tail_append(new_disc());
\r
1179 c = hyphen_char[cur_font];
\r
1183 pre_break(tail) = new_character(cur_font, c);
\r
1189 new_save_level(disc_group);
\r
1190 scan_left_brace();
\r
1193 space_factor = 1000;
\r
1197 void build_discretionary (void)
\r
1209 if (!is_char_node(p))
\r
1210 if (type(p) > rule_node)
\r
1211 if (type(p) != kern_node)
\r
1212 if (type(p) != ligature_node)
\r
1214 print_err("Improper discretionary list");
\r
1215 help1("Discretionary lists must contain only boxes and kerns.");
\r
1217 begin_diagnostic();
\r
1218 print_nl("The following discretionary sublist has been deleted:");
\r
1220 end_diagnostic(true);
\r
1221 flush_node_list(p);
\r
1235 switch (saved(-1))
\r
1238 pre_break(tail) = p;
\r
1242 post_break(tail) = p;
\r
1247 if ((n > 0) && (abs(mode) == mmode))
\r
1249 print_err("Illegal math ");
\r
1250 print_esc("discretionary");
\r
1251 help2("Sorry: The third part of a discretionary break must be",
\r
1252 "empty, in math formulas. I had to delete your third part.");
\r
1253 flush_node_list(p);
\r
1260 if (n <= max_quarterword)
\r
1261 replace_count(tail) = n;
\r
1264 print_err("Discretionary list is too long");
\r
1265 help2("Wow---I never thought anybody would tweak me here.",
\r
1266 "You can't seriously need such a huge discretionary list?");
\r
1280 new_save_level(disc_group);
\r
1281 scan_left_brace();
\r
1284 space_factor = 1000;
\r
1287 void make_accent (void)
\r
1291 internal_font_number f;
\r
1292 scaled a, h, x, w, delta;
\r
1297 p = new_character(f, cur_val);
\r
1302 s = slant(f) / ((double) 65536.0);
\r
1303 a = char_width(f, char_info(f, character(p)));
\r
1308 if ((cur_cmd == letter) || (cur_cmd == other_char) || (cur_cmd == char_given))
\r
1309 q = new_character(f, cur_chr);
\r
1310 else if (cur_cmd == char_num)
\r
1313 q = new_character(f, cur_val);
\r
1320 t = slant(f) / ((double) 65536.0);
\r
1321 i = char_info(f, character(q));
\r
1322 w = char_width(f, i);
\r
1323 h = char_height(f, height_depth(i));
\r
1327 p = hpack(p, 0, 1);
\r
1328 shift_amount(p) = x - h;
\r
1331 delta = round((w - a) / ((double) 2.0) + h * t - x * s);
\r
1332 r = new_kern(delta);
\r
1333 subtype(r) = acc_kern;
\r
1336 tail = new_kern(- (integer) a - delta);
\r
1337 subtype(tail) = acc_kern;
\r
1344 space_factor = 1000;
\r
1348 void align_error (void)
\r
1350 if (abs(align_state) > 2)
\r
1352 print_err("Misplaced ");
\r
1353 print_cmd_chr(cur_cmd, cur_chr);
\r
1355 if (cur_tok == tab_token + '&')
\r
1357 help6("I can't figure out why you would want to use a tab mark",
\r
1358 "here. If you just want an ampersand, the remedy is",
\r
1359 "simple: Just type `I\\&' now. But if some right brace",
\r
1360 "up above has ended a previous alignment prematurely,",
\r
1361 "you're probably due for more error messages, and you",
\r
1362 "might try typing `S' now just to see what is salvageable.");
\r
1366 help5("I can't figure out why you would want to use a tab mark",
\r
1367 "or \\cr or \\span just now. If something like a right brace",
\r
1368 "up above has ended a previous alignment prematurely,",
\r
1369 "you're probably due for more error messages, and you",
\r
1370 "might try typing `S' now just to see what is salvageable.");
\r
1379 if (align_state < 0)
\r
1381 print_err("Missing { inserted");
\r
1382 incr(align_state);
\r
1383 cur_tok = left_brace_token + '{';
\r
1387 print_err("Missing } inserted");
\r
1388 decr(align_state);
\r
1389 cur_tok = right_brace_token + '}';
\r
1392 help3("I've put in what seems to be necessary to fix",
\r
1393 "the current column of the current alignment.",
\r
1394 "Try to go on, since this might almost work.");
\r
1399 void noalign_error (void)
\r
1401 print_err("Misplaced ");
\r
1402 print_esc("noalign");
\r
1403 help2("I expect to see \\noalign only after the \\cr of",
\r
1404 "an alignment. Proceed, and I'll ignore this case.");
\r
1408 void omit_error (void)
\r
1410 print_err("Misplaced ");
\r
1411 print_esc("omit");
\r
1412 help2("I expect to see \\omit only after tab marks or the \\cr of",
\r
1413 "an alignment. Proceed, and I'll ignore this case.");
\r
1417 void do_endv (void)
\r
1419 base_ptr = input_ptr;
\r
1420 input_stack[base_ptr] = cur_input;
\r
1422 while ((input_stack[base_ptr].index_field != v_template) &&
\r
1423 (input_stack[base_ptr].loc_field == 0) &&
\r
1424 (input_stack[base_ptr].state_field == token_list))
\r
1427 if ((input_stack[base_ptr].index_field != v_template) ||
\r
1428 (input_stack[base_ptr].loc_field != 0) ||
\r
1429 (input_stack[base_ptr].state_field != token_list))
\r
1430 fatal_error("(interwoven alignment preambles are not allowed)");
\r
1432 if (cur_group == align_group)
\r
1443 void cs_error (void)
\r
1445 print_err("Extra ");
\r
1446 print_esc("endcsname");
\r
1447 help1("I'm ignoring this, since I wasn't doing a \\csname.");
\r
1451 void push_math (group_code c)
\r
1455 incompleat_noad = 0;
\r
1456 new_save_level(c);
\r
1459 void init_math (void)
\r
1466 internal_font_number f;
\r
1473 if ((cur_cmd == math_shift) && (mode > 0))
\r
1482 line_break(display_widow_penalty);
\r
1483 v = shift_amount(just_box) + 2 * quad(cur_font);
\r
1485 p = list_ptr(just_box);
\r
1490 if (is_char_node(p))
\r
1493 d = char_width(f, char_info(f, character(p)));
\r
1508 case ligature_node:
\r
1510 mem[lig_trick] = mem[lig_char(p)];
\r
1511 link(lig_trick) = link(p);
\r
1527 if (glue_sign(just_box) == stretching)
\r
1529 if ((glue_order(just_box) == stretch_order(q)) && (stretch(q) != 0))
\r
1532 else if (glue_sign(just_box) == shrinking)
\r
1534 if ((glue_order(just_box) == shrink_order(q)) && (shrink(q) != 0))
\r
1538 if (subtype(p) >= a_leaders)
\r
1543 case whatsit_node:
\r
1552 if (v < max_dimen)
\r
1558 if (v < max_dimen)
\r
1575 if (par_shape_ptr == 0)
\r
1576 if ((hang_indent != 0) && (((hang_after >= 0) &&
\r
1577 (prev_graf + 2 > hang_after)) || (prev_graf + 1 < - (integer) hang_after)))
\r
1579 l = hsize - abs(hang_indent);
\r
1581 if (hang_indent > 0)
\r
1593 n = info(par_shape_ptr);
\r
1595 if (prev_graf + 2 >= n)
\r
1596 p = par_shape_ptr + 2 * n;
\r
1598 p = par_shape_ptr + 2 * (prev_graf + 2);
\r
1600 s = mem[p - 1].cint;
\r
1604 push_math(math_shift_group);
\r
1606 eq_word_define(int_base + cur_fam_code, -1);
\r
1607 eq_word_define(dimen_base + pre_display_size_code, w);
\r
1608 eq_word_define(dimen_base + display_width_code, l);
\r
1609 eq_word_define(dimen_base + display_indent_code, s);
\r
1611 if (every_display != 0)
\r
1612 begin_token_list(every_display, every_display_text);
\r
1614 if (nest_ptr == 1)
\r
1624 push_math(math_shift_group);
\r
1625 eq_word_define(int_base + cur_fam_code, -1);
\r
1627 if (every_math != 0)
\r
1628 begin_token_list(every_math, every_math_text);
\r
1633 void start_eq_no (void)
\r
1635 saved(0) = cur_chr;
\r
1639 push_math(math_shift_group);
\r
1640 eq_word_define(int_base + cur_fam_code, -1);
\r
1642 if (every_math != 0)
\r
1643 begin_token_list(every_math, every_math_text);
\r
1647 void scan_math (pointer p)
\r
1656 while (!((cur_cmd != spacer) && (cur_cmd != relax)));
\r
1665 c = math_code(cur_chr);
\r
1670 cur_cs = cur_chr + active_base;
\r
1671 cur_cmd = eq_type(cur_cs);
\r
1672 cur_chr = equiv(cur_cs);
\r
1685 cur_chr = cur_val;
\r
1686 cur_cmd = char_given;
\r
1691 case math_char_num:
\r
1693 scan_fifteen_bit_int();
\r
1704 scan_twenty_seven_bit_int();
\r
1705 c = cur_val / 4096;
\r
1712 scan_left_brace();
\r
1715 push_math(math_group);
\r
1721 math_type(p) = math_char;
\r
1722 character(p) = c % 256;
\r
1724 if ((c >= var_code) && ((cur_fam >= 0) && (cur_fam < 16)))
\r
1727 fam(p) = (c / 256) % 16;
\r
1730 void set_math_char_(integer c)
\r
1736 cur_cs = cur_chr + active_base;
\r
1737 cur_cmd = eq_type(cur_cs);
\r
1738 cur_chr = equiv(cur_cs);
\r
1745 math_type(nucleus(p)) = math_char;
\r
1746 character(nucleus(p)) = c % 256;
\r
1747 fam(nucleus(p)) = (c / 256) % 16;
\r
1749 if (c >= var_code)
\r
1751 if (((cur_fam >= 0) && (cur_fam < 16)))
\r
1752 fam(nucleus(p)) = cur_fam;
\r
1754 type(p) = ord_noad;
\r
1757 type(p) = ord_noad + (c / 4096);
\r
1764 void math_limit_switch (void)
\r
1767 if (type(tail) == op_noad)
\r
1769 subtype(tail) = cur_chr;
\r
1773 print_err("Limit controls must follow a math operator");
\r
1774 help1("I'm ignoring this misplaced \\limits or \\nolimits command.");
\r
1778 void scan_delimiter_(pointer p, boolean r)
\r
1781 scan_twenty_seven_bit_int();
\r
1788 while (!((cur_cmd != spacer) && (cur_cmd != relax)));
\r
1794 cur_val = del_code(cur_chr);
\r
1798 scan_twenty_seven_bit_int();
\r
1809 print_err("Missing delimiter (. inserted)");
\r
1810 help6("I was expecting to see something like `(' or `\\{' or",
\r
1811 "`\\}' here. If you typed, e.g., `{' instead of `\\{', you",
\r
1812 "should probably delete the `{' by typing `1' now, so that",
\r
1813 "braces don't get unbalanced. Otherwise just proceed.",
\r
1814 "Acceptable delimiters are characters whose \\delcode is",
\r
1815 "nonnegative, or you can use `\\delimiter <delimiter code>'.");
\r
1820 small_fam(p) = (cur_val / 1048576L) % 16;
\r
1821 small_char(p) = (cur_val / 4096) % 256;
\r
1822 large_fam(p) = (cur_val / 256) % 16;
\r
1823 large_char(p) = cur_val % 256;
\r
1826 void math_radical (void)
\r
1828 tail_append(get_node(radical_noad_size));
\r
1829 type(tail) = radical_noad;
\r
1830 subtype(tail) = normal;
\r
1831 mem[nucleus(tail)].hh = empty_field;
\r
1832 mem[subscr(tail)].hh = empty_field;
\r
1833 mem[supscr(tail)].hh = empty_field;
\r
1834 scan_delimiter(left_delimiter(tail), true);
\r
1835 scan_math(nucleus(tail));
\r
1838 void math_ac (void)
\r
1840 if (cur_cmd == accent)
\r
1842 print_err("Please use ");
\r
1843 print_esc("mathaccent");
\r
1844 prints(" for accents in math mode");
\r
1845 help2("I'm changing \\accent to \\mathaccent here; wish me luck.",
\r
1846 "(Accents are not the same in formulas as they are in text.)");
\r
1850 tail_append(get_node(accent_noad_size));
\r
1851 type(tail) = accent_noad;
\r
1852 subtype(tail) = normal;
\r
1853 mem[nucleus(tail)].hh = empty_field;
\r
1854 mem[subscr(tail)].hh = empty_field;
\r
1855 mem[supscr(tail)].hh = empty_field;
\r
1856 math_type(accent_chr(tail)) = math_char;
\r
1857 scan_fifteen_bit_int();
\r
1858 character(accent_chr(tail)) = cur_val % 256;
\r
1860 if ((cur_val >= var_code) && ((cur_fam >= 0) && (cur_fam < 16)))
\r
1861 fam(accent_chr(tail)) = cur_fam;
\r
1863 fam(accent_chr(tail)) = (cur_val / 256) % 16;
\r
1865 scan_math(nucleus(tail));
\r
1868 void append_choices (void)
\r
1870 tail_append(new_choice());
\r
1873 push_math(math_choice_group);
\r
1874 scan_left_brace();
\r
1877 pointer fin_mlist (pointer p)
\r
1881 if (incompleat_noad != 0)
\r
1883 math_type(denominator(incompleat_noad)) = sub_mlist;
\r
1884 info(denominator(incompleat_noad)) = link(head);
\r
1887 q = incompleat_noad;
\r
1890 q = info(numerator(incompleat_noad));
\r
1892 if (type(q) != left_noad)
\r
1894 confusion("right");
\r
1898 info(numerator(incompleat_noad)) = link(q);
\r
1899 link(q) = incompleat_noad;
\r
1900 link(incompleat_noad) = p;
\r
1914 void build_choices (void)
\r
1921 switch (saved(-1))
\r
1924 display_mlist(tail) = p;
\r
1928 text_mlist(tail) = p;
\r
1932 script_mlist(tail) = p;
\r
1937 script_script_mlist(tail) = p;
\r
1945 push_math(math_choice_group);
\r
1946 scan_left_brace();
\r
1949 void sub_sup (void)
\r
1951 /* small_number t; */
\r
1959 if (script_allowed(tail))
\r
1961 p = supscr(tail) + cur_cmd - sup_mark;
\r
1965 if ((p == 0) || (t != 0))
\r
1967 tail_append(new_noad());
\r
1968 p = supscr(tail) + cur_cmd - sup_mark;
\r
1972 if (cur_cmd == sup_mark)
\r
1974 print_err("Double superscript");
\r
1975 help1("I treat `x^1^2' essentially like `x^1{}^2'.");
\r
1979 print_err("Double subscript");
\r
1980 help1("I treat `x_1_2' essentially like `x_1{}_2'.");
\r
1990 void package (small_number c)
\r
1996 d = box_max_depth;
\r
1998 save_ptr = save_ptr - 3;
\r
2000 if (mode == -hmode)
\r
2001 cur_box = hpack(link(head), saved(2), saved(1));
\r
2004 cur_box = vpackage(link(head), saved(2), saved(1), d);
\r
2006 if (c == vtop_code)
\r
2009 p = list_ptr(cur_box);
\r
2012 if (type(p) <= rule_node)
\r
2015 depth(cur_box) = depth(cur_box) - h + height(cur_box);
\r
2016 height(cur_box) = h;
\r
2021 box_end(saved(0));
\r