1use crate::Engine;
18use crate::cmd::Cmd;
19use crate::eqtb::{Loc, Val};
20use crate::glue::{FIL, FILL, Glue};
21use crate::input::TokKind;
22use crate::maincontrol::{BoxContext, IGNORE_DEPTH, Mode, ModeKind};
23use crate::nodes::{BoxData, NodeData, NodeRef, glue_sub, id, kern_sub};
24use crate::primitives_gen::{assign_dimen as dp, assign_glue as gp, assign_int as ip};
25use crate::save::{GroupCode, SaveEntry};
26use crate::scan::ValLevel;
27use crate::token::Token;
28use crate::typeset::NULL_FLAG;
29
30#[allow(missing_docs)]
32pub mod chr {
33 pub const BOX: u32 = 0;
34 pub const COPY: u32 = 1;
35 pub const LAST_BOX: u32 = 2;
36 pub const VSPLIT: u32 = 3;
37 pub const TPACK: u32 = 4;
38 pub const VPACK: u32 = 5;
39 pub const HPACK: u32 = 6;
40 pub const VTOP: u32 = 7;
41 pub const VBOX: u32 = 8;
42 pub const HBOX: u32 = 141;
43 pub const SHIPOUT: u32 = 98;
44 pub const FIL: u32 = 0;
45 pub const FILL: u32 = 1;
46 pub const SS: u32 = 2;
47 pub const FIL_NEG: u32 = 3;
48 pub const SKIP: u32 = 4;
49 pub const MSKIP: u32 = 5;
50 pub const NOINDENT: u32 = 0;
51 pub const INDENT: u32 = 1;
52 pub const QUITVMODE: u32 = 2;
53}
54
55#[derive(Clone, Copy, Debug, PartialEq, Eq)]
57pub enum PackSpec {
58 Exactly(i32),
60 Additional(i32),
62}
63
64impl PackSpec {
65 pub const NATURAL: PackSpec = PackSpec::Additional(0);
67}
68
69const BOX_FLAG: i64 = 1 << 40;
70const GLOBAL_BOX_FLAG: i64 = BOX_FLAG + 0x1_0000;
71const SHIP_OUT_FLAG: i64 = BOX_FLAG + 0x2_0000;
72const LEADER_FLAG: i64 = BOX_FLAG + 0x3_0000;
73
74pub fn ctx_to_i64(c: BoxContext) -> i64 {
76 match c {
77 BoxContext::Shift(s) => i64::from(s),
78 BoxContext::SetBox(n) => BOX_FLAG + i64::from(n),
79 BoxContext::GlobalSetBox(n) => GLOBAL_BOX_FLAG + i64::from(n),
80 BoxContext::Shipout => SHIP_OUT_FLAG,
81 BoxContext::Leaders(s) => LEADER_FLAG + i64::from(s),
82 }
83}
84
85pub fn ctx_from_i64(v: i64) -> BoxContext {
87 if v < BOX_FLAG {
88 BoxContext::Shift(v as i32)
89 } else if v < GLOBAL_BOX_FLAG {
90 BoxContext::SetBox((v - BOX_FLAG) as u32)
91 } else if v < SHIP_OUT_FLAG {
92 BoxContext::GlobalSetBox((v - GLOBAL_BOX_FLAG) as u32)
93 } else if v == SHIP_OUT_FLAG {
94 BoxContext::Shipout
95 } else {
96 BoxContext::Leaders((v - LEADER_FLAG) as u16)
97 }
98}
99
100pub fn norm_min(h: i32) -> u8 {
102 h.clamp(1, 63) as u8
103}
104
105impl Engine {
106 pub fn push_saved(&mut self, v: i64) {
108 self.save.stack.push(SaveEntry::Value(v));
109 }
110
111 pub fn pop_saved(&mut self) -> i64 {
113 match self.save.stack.pop() {
114 Some(SaveEntry::Value(v)) => v,
115 other => {
116 if let Some(e) = other {
117 self.save.stack.push(e);
118 }
119 debug_assert!(false, "save stack out of sync");
120 0
121 }
122 }
123 }
124
125 pub fn peek_saved(&self, k: usize) -> i64 {
127 let n = self.save.stack.len();
128 match self.save.stack.get(n.wrapping_sub(1 + k)) {
129 Some(SaveEntry::Value(v)) => *v,
130 _ => 0,
131 }
132 }
133
134 pub fn set_peek_saved(&mut self, k: usize, v: i64) {
136 let n = self.save.stack.len();
137 if let Some(SaveEntry::Value(x)) = self.save.stack.get_mut(n.wrapping_sub(1 + k)) {
138 *x = v;
139 }
140 }
141
142 pub fn new_param_glue(&mut self, sub: u16) -> NodeRef {
144 let g = self.eqtb.glue(glue_param_of_subtype(sub));
145 self.new_node(
146 id::GLUE,
147 sub,
148 NodeData::Glue {
149 spec: g,
150 leader: NodeRef::NULL,
151 },
152 )
153 }
154
155 pub fn new_glue_node(&mut self, spec: Glue, sub: u16) -> NodeRef {
157 self.new_node(
158 id::GLUE,
159 sub,
160 NodeData::Glue {
161 spec,
162 leader: NodeRef::NULL,
163 },
164 )
165 }
166
167 pub fn new_kern_node(&mut self, w: i32, sub: u16) -> NodeRef {
169 self.new_node(
170 id::KERN,
171 sub,
172 NodeData::Kern {
173 kern: w,
174 expansion_factor: 0,
175 },
176 )
177 }
178
179 pub fn new_penalty_node(&mut self, m: i32) -> NodeRef {
181 self.new_node(id::PENALTY, 0, NodeData::Penalty { penalty: m })
182 }
183
184 pub fn new_null_box_node(&mut self, hlist: bool) -> NodeRef {
186 let p = self.nodes.new_null_box(hlist);
187 if self.eqtb.attrs_in_use {
188 let a = self.cur_attr();
189 self.nodes.set_attr(p, a);
190 }
191 p
192 }
193
194 pub fn typeset_command(&mut self) {
197 use ModeKind as K;
198 let kind = self.mode.abs_kind();
199 let cmd = self.cur_cmd;
200 match (kind, cmd) {
201 (
203 K::Vertical,
204 Cmd::Letter
205 | Cmd::OtherChar
206 | Cmd::CharNum
207 | Cmd::CharGiven
208 | Cmd::MathShift
209 | Cmd::MathShiftCs
210 | Cmd::UnHbox
211 | Cmd::Vrule
212 | Cmd::Accent
213 | Cmd::Discretionary
214 | Cmd::Hskip
215 | Cmd::Valign
216 | Cmd::ExSpace
217 | Cmd::Boundary
218 | Cmd::CharGhost
219 | Cmd::MathCharNum
220 | Cmd::MathGiven
221 | Cmd::XmathGiven,
222 ) => {
223 self.back_input();
224 self.new_graf(true);
225 }
226 (K::Horizontal, Cmd::MathCharNum | Cmd::MathGiven | Cmd::XmathGiven) => {
227 self.math_char_in_text();
228 }
229 (K::Vertical, Cmd::StartPar) => {
230 let c = self.cur_chr;
231 self.new_graf(c != chr::NOINDENT);
232 }
233 (K::Horizontal | K::Math, Cmd::StartPar) => self.indent_in_hmode(),
234 (K::Vertical, Cmd::Hrule) | (K::Horizontal | K::Math, Cmd::Vrule) => {
235 let r = self.scan_rule_spec();
236 self.tail_append(r);
237 if kind == K::Vertical {
238 self.cur_list_mut().prev_depth = IGNORE_DEPTH;
239 } else if kind == K::Horizontal {
240 self.cur_list_mut().space_factor = 1000;
241 }
242 }
243 (K::Vertical, Cmd::Nohrule) | (K::Horizontal | K::Math, Cmd::Novrule) => {
244 let r = self.scan_rule_spec();
245 self.nodes.set_subtype(r, 3);
246 self.tail_append(r);
247 if kind == K::Vertical {
248 self.cur_list_mut().prev_depth = IGNORE_DEPTH;
249 } else if kind == K::Horizontal {
250 self.cur_list_mut().space_factor = 1000;
251 }
252 }
253 (K::Vertical, Cmd::Vskip)
254 | (K::Horizontal | K::Math, Cmd::Hskip)
255 | (K::Math, Cmd::Mskip) => self.append_glue(),
256 (_, Cmd::Kern) | (K::Math, Cmd::Mkern) => self.append_kern(),
257 (K::Vertical, Cmd::Hmove) | (K::Horizontal | K::Math, Cmd::Vmove) => {
258 let t = self.cur_chr;
259 self.scan_normal_dimen();
260 let v = self.cur_val;
261 self.scan_box(BoxContext::Shift(if t == 0 { v } else { -v }));
262 }
263 (_, Cmd::LeaderShip) => {
264 let c = self.cur_chr;
265 if c == chr::SHIPOUT {
266 self.scan_box(BoxContext::Shipout);
267 } else if c >= glue_sub::A_LEADERS as u32 {
268 self.scan_box(BoxContext::Leaders(c as u16));
269 } else {
270 self.scan_box(BoxContext::Shipout);
272 }
273 }
274 (_, Cmd::MakeBox) => self.begin_box(BoxContext::Shift(0)),
275 (K::Vertical, Cmd::ParEnd) => {
276 self.normal_paragraph();
277 if self.mode.is_privileged() {
278 self.build_page();
279 }
280 }
281 (K::Horizontal, Cmd::ParEnd) => {
282 if self.input.align_state < 0 {
283 self.off_save();
284 }
285 self.end_graf();
286 if self.mode == Mode::Vertical {
287 self.build_page();
288 }
289 }
290 (K::Horizontal, Cmd::Stop | Cmd::Vskip | Cmd::Hrule | Cmd::UnVbox | Cmd::Halign) => {
291 self.head_for_vmode()
292 }
293 (_, Cmd::Insert) | (K::Horizontal | K::Math, Cmd::Vadjust) => {
294 self.begin_insert_or_adjust()
295 }
296 (K::Vertical, Cmd::Vadjust) => self.report_illegal_case(),
297 (_, Cmd::Mark) => self.make_mark(),
298 (_, Cmd::BreakPenalty) => self.append_penalty(),
299 (_, Cmd::RemoveItem) => self.delete_last(),
300 (K::Vertical, Cmd::UnVbox) | (K::Horizontal | K::Math, Cmd::UnHbox) => self.unpackage(),
301 (K::Horizontal, Cmd::ItalCorr) => self.append_italic_correction(),
302 (K::Math, Cmd::ItalCorr) => {
303 let k = self.new_kern_node(0, kern_sub::USER);
304 self.tail_append(k);
305 }
306 (K::Vertical, Cmd::ItalCorr) => self.report_illegal_case(),
307 (K::Horizontal | K::Math, Cmd::Discretionary) => self.append_discretionary(),
308 (K::Horizontal, Cmd::Accent) => self.make_accent(),
309 (K::Horizontal, Cmd::Boundary) => self.append_boundary(),
310 (K::Horizontal, Cmd::CharGhost) => self.append_ghost(),
311 (_, Cmd::CarRet | Cmd::TabMark) => self.align_error(),
312 (_, Cmd::NoAlign) => self.no_align_error(),
313 (_, Cmd::Omit) => self.omit_error(),
314 (K::Vertical, Cmd::Halign) | (K::Horizontal, Cmd::Valign) => self.init_align(),
315 (K::Math, Cmd::Halign) => {
316 if self.privileged() {
317 if self.save.cur_group == GroupCode::MathShift {
318 self.init_align();
319 } else {
320 self.off_save();
321 }
322 }
323 }
324 (K::Vertical | K::Horizontal, Cmd::Endv) => self.do_endv(),
325 (_, Cmd::EndCsName) => self.cs_error(),
326 (_, Cmd::AssignLocalBox) => self.begin_local_box(),
327 (K::Horizontal, Cmd::MathShift | Cmd::MathShiftCs) => self.init_math(),
328 (K::Math, _) => self.math_command(),
329 (
330 K::Vertical | K::Horizontal,
331 Cmd::SupMark
332 | Cmd::SubMark
333 | Cmd::MathComp
334 | Cmd::DelimNum
335 | Cmd::LeftRight
336 | Cmd::Above
337 | Cmd::Radical
338 | Cmd::MathStyle
339 | Cmd::MathChoice
340 | Cmd::Vcenter
341 | Cmd::NonScript
342 | Cmd::Mkern
343 | Cmd::LimitSwitch
344 | Cmd::Mskip
345 | Cmd::MathAccent
346 | Cmd::SuperSubScript
347 | Cmd::NoSuperSubScript,
348 ) => self.insert_dollar_sign(),
349 (K::Vertical | K::Horizontal, Cmd::EqNo) => self.report_illegal_case(),
350 (_, Cmd::Option) => {
351 self.scan_int();
353 self.scan_optional_equals();
354 self.scan_int();
355 }
356 (_, Cmd::Node) => {
357 self.scan_int();
358 }
359 _ => {
360 let (c, r) = (self.cur_cmd, self.cur_chr);
361 let s = self.print_to_string(|e| e.print_cmd_chr(c, r));
362 self.not_implemented(&String::from_utf8_lossy(&s));
363 }
364 }
365 }
366
367 pub fn append_glue(&mut self) {
369 let s = self.cur_chr;
370 let g = match s {
371 chr::FIL => Glue {
372 stretch: retex_arith::UNITY,
373 stretch_order: FIL,
374 ..Glue::ZERO
375 },
376 chr::FILL => Glue {
377 stretch: retex_arith::UNITY,
378 stretch_order: FILL,
379 ..Glue::ZERO
380 },
381 chr::SS => Glue {
382 stretch: retex_arith::UNITY,
383 stretch_order: FIL,
384 shrink: retex_arith::UNITY,
385 shrink_order: FIL,
386 ..Glue::ZERO
387 },
388 chr::FIL_NEG => Glue {
389 stretch: -retex_arith::UNITY,
390 stretch_order: FIL,
391 ..Glue::ZERO
392 },
393 chr::SKIP => {
394 self.scan_glue(ValLevel::Glue);
395 self.cur_glue
396 }
397 _ => {
398 self.scan_glue(ValLevel::Mu);
399 self.cur_glue
400 }
401 };
402 let sub = if s == chr::MSKIP {
403 glue_sub::MU_GLUE
404 } else {
405 glue_sub::USER
406 };
407 let p = self.new_glue_node(g, sub);
408 self.tail_append(p);
409 }
410
411 pub fn append_kern(&mut self) {
413 let s = self.cur_chr as u16;
414 let mu = s == glue_sub::MU_GLUE;
415 self.scan_dimen(mu, false, false);
416 let v = self.cur_val;
417 let p = self.new_kern_node(
418 v,
419 if mu {
420 glue_sub::MU_GLUE
421 } else {
422 kern_sub::USER
423 },
424 );
425 self.tail_append(p);
426 }
427
428 pub fn scan_rule_spec(&mut self) -> NodeRef {
430 let vertical_rule = matches!(self.cur_cmd, Cmd::Vrule | Cmd::Novrule);
431 let (mut w, mut h, mut d) = if vertical_rule {
432 (26214, NULL_FLAG, NULL_FLAG)
433 } else {
434 (NULL_FLAG, 26214, 0)
435 };
436 let (mut left, mut right) = (0, 0);
437 loop {
438 if self.scan_keyword("width") {
439 self.scan_normal_dimen();
440 w = self.cur_val;
441 continue;
442 }
443 if self.scan_keyword("height") {
444 self.scan_normal_dimen();
445 h = self.cur_val;
446 continue;
447 }
448 if self.scan_keyword("depth") {
449 self.scan_normal_dimen();
450 d = self.cur_val;
451 continue;
452 }
453 if self.scan_keyword("left") {
454 self.scan_normal_dimen();
455 left = self.cur_val;
456 continue;
457 }
458 if self.scan_keyword("right") {
459 self.scan_normal_dimen();
460 right = self.cur_val;
461 continue;
462 }
463 break;
464 }
465 self.new_node(
466 id::RULE,
467 0,
468 NodeData::Rule {
469 width: w,
470 depth: d,
471 height: h,
472 dir: 0,
473 index: 0,
474 left,
475 right,
476 },
477 )
478 }
479
480 pub fn scan_spec(&mut self, c: GroupCode, ctx: Option<i64>) {
483 let mut dir: i64 = -1;
487 loop {
488 if self.scan_keyword("attr") {
489 self.scan_register_num();
490 self.scan_optional_equals();
491 self.scan_int();
492 continue;
493 }
494 if dir < 0 && self.scan_keyword("dir") {
495 dir = i64::from(self.scan_direction_spec());
496 continue;
497 }
498 if dir < 0 && self.scan_keyword("bdir") {
499 self.scan_int();
500 dir = if (0..=3).contains(&self.cur_val) {
501 i64::from(self.cur_val)
502 } else {
503 0
504 };
505 continue;
506 }
507 break;
508 }
509 let is_box = matches!(
510 c,
511 GroupCode::Hbox | GroupCode::AdjustedHbox | GroupCode::Vbox | GroupCode::Vtop
512 );
513 if dir < 0 && is_box {
514 dir = i64::from(self.default_box_dir());
515 }
516 let spec = if self.scan_keyword("to") {
517 self.scan_normal_dimen();
518 PackSpec::Exactly(self.cur_val)
519 } else if self.scan_keyword("spread") {
520 self.scan_normal_dimen();
521 PackSpec::Additional(self.cur_val)
522 } else {
523 PackSpec::NATURAL
524 };
525 if let Some(v) = ctx {
526 self.push_saved(v);
527 }
528 let (code, v) = match spec {
529 PackSpec::Exactly(v) => (0, v),
530 PackSpec::Additional(v) => (1, v),
531 };
532 self.push_saved(code);
533 self.push_saved(i64::from(v));
534 self.push_saved(dir);
535 self.new_save_level(c);
536 self.begin_box_dirs(c, dir as i32);
537 self.scan_left_brace();
538 }
539
540 pub fn pop_spec_pub(&mut self) -> (PackSpec, i64) {
542 self.pop_spec()
543 }
544
545 fn pop_spec(&mut self) -> (PackSpec, i64) {
547 let dir = self.pop_saved();
548 let v = self.pop_saved() as i32;
549 let code = self.pop_saved();
550 (
551 if code == 0 {
552 PackSpec::Exactly(v)
553 } else {
554 PackSpec::Additional(v)
555 },
556 dir,
557 )
558 }
559
560 pub fn scan_box(&mut self, ctx: BoxContext) {
562 self.get_nonblank_nonrelax_noncall();
563 if self.cur_cmd == Cmd::MakeBox {
564 self.begin_box(ctx);
565 } else if matches!(ctx, BoxContext::Leaders(_))
566 && matches!(
567 self.cur_cmd,
568 Cmd::Hrule | Cmd::Vrule | Cmd::Nohrule | Cmd::Novrule
569 )
570 {
571 let r = self.scan_rule_spec();
572 self.box_end(ctx, r);
573 } else {
574 self.print_err("A <box> was supposed to be here");
575 self.help(&[
576 "I was expecting to see \\hbox or \\vbox or \\copy or \\box or",
577 "something like that. So you might find something missing in",
578 "your output. But keep trying; you can fix this later.",
579 ]);
580 self.back_error();
581 }
582 }
583
584 pub fn begin_box(&mut self, ctx: BoxContext) {
587 let cur_box: NodeRef;
588 match self.cur_chr {
589 chr::BOX => {
590 self.scan_register_num();
591 let n = self.cur_val as usize;
592 cur_box = self.eqtb.boxes[n].val;
593 self.eqtb.boxes[n].val = NodeRef::NULL;
594 }
595 chr::COPY => {
596 self.scan_register_num();
597 let b = self.eqtb.boxes[self.cur_val as usize].val;
598 cur_box = self.copy_node_list(b);
599 }
600 chr::LAST_BOX => {
601 cur_box = self.take_last_box();
602 }
603 chr::VSPLIT => {
604 self.scan_register_num();
605 let n = self.cur_val as u32;
606 if !self.scan_keyword("to") {
607 self.print_err("Missing `to' inserted");
608 self.help(&[
609 "I'm working on `\\vsplit<box number> to <dimen>';",
610 "will look for the <dimen> next.",
611 ]);
612 self.error();
613 }
614 self.scan_normal_dimen();
615 let h = self.cur_val;
616 cur_box = self.vsplit(n, h);
617 }
618 c => {
619 let k = match c {
621 chr::HBOX | chr::HPACK => ModeKind::Horizontal,
622 _ => ModeKind::Vertical,
623 };
624 let ctxv = ctx_to_i64(ctx);
625 self.push_saved(i64::from(c));
627 if k == ModeKind::Horizontal {
628 if matches!(ctx, BoxContext::Shift(_))
629 && self.mode.abs_kind() == ModeKind::Vertical
630 {
631 self.scan_spec(GroupCode::AdjustedHbox, Some(ctxv));
632 } else {
633 self.scan_spec(GroupCode::Hbox, Some(ctxv));
634 }
635 } else {
636 if c == chr::VBOX || c == chr::VPACK {
637 self.scan_spec(GroupCode::Vbox, Some(ctxv));
638 } else {
639 self.scan_spec(GroupCode::Vtop, Some(ctxv));
640 }
641 self.normal_paragraph();
642 }
643 if k == ModeKind::Vertical {
644 self.push_nest(Mode::InternalVertical);
645 self.cur_list_mut().prev_depth = IGNORE_DEPTH;
646 let t = self
647 .eqtb
648 .toks_param(crate::primitives_gen::assign_toks::EVERYVBOX)
649 .clone();
650 if !t.is_empty() {
651 self.begin_token_list(t, TokKind::EveryVboxText);
652 }
653 } else {
654 self.push_nest(Mode::RestrictedHorizontal);
655 self.cur_list_mut().space_factor = 1000;
656 let t = self
657 .eqtb
658 .toks_param(crate::primitives_gen::assign_toks::EVERYHBOX)
659 .clone();
660 if !t.is_empty() {
661 self.begin_token_list(t, TokKind::EveryHboxText);
662 }
663 }
664 return;
665 }
666 }
667 self.box_end(ctx, cur_box);
668 }
669
670 pub fn copy_node_list(&mut self, p: NodeRef) -> NodeRef {
672 if p.is_null() {
673 return p;
674 }
675 self.nodes.copy_node(p)
676 }
677
678 fn take_last_box(&mut self) -> NodeRef {
680 if self.mode.abs_kind() == ModeKind::Math {
681 self.you_cant();
682 self.help(&["Sorry; this \\lastbox will be void."]);
683 self.error();
684 return NodeRef::NULL;
685 }
686 let (head, tail) = (self.cur_list().head, self.cur_list().tail);
687 if self.mode == Mode::Vertical && head == tail {
688 self.you_cant();
689 self.help(&[
690 "Sorry...I usually can't take things from the current page.",
691 "This \\lastbox will therefore be void.",
692 ]);
693 self.error();
694 return NodeRef::NULL;
695 }
696 if tail == head {
697 return NodeRef::NULL;
698 }
699 let t = self.nodes.id(tail);
700 if t != id::HLIST && t != id::VLIST {
701 return NodeRef::NULL;
702 }
703 let p = self.nodes.prev(tail);
704 let p = if p.is_null() { self.find_prev(tail) } else { p };
705 self.nodes.set_next(p, NodeRef::NULL);
706 self.nodes.set_prev(tail, NodeRef::NULL);
707 self.cur_list_mut().tail = p;
708 if let Some(b) = self.nodes.box_data_mut(tail) {
709 b.shift = 0;
710 }
711 tail
712 }
713
714 fn find_prev(&self, q: NodeRef) -> NodeRef {
716 let mut p = self.cur_list().head;
717 while !p.is_null() {
718 let n = self.nodes.next(p);
719 if n == q {
720 return p;
721 }
722 p = n;
723 }
724 self.cur_list().head
725 }
726
727 pub fn box_end(&mut self, ctx: BoxContext, cur_box: NodeRef) {
729 match ctx {
730 BoxContext::Shift(s) => {
731 if cur_box.is_null() {
732 return;
733 }
734 if let Some(b) = self.nodes.box_data_mut(cur_box) {
735 b.shift = s;
736 }
737 match self.mode.abs_kind() {
738 ModeKind::Vertical => {
739 self.append_box_with_adjustments(cur_box);
740 if self.mode.is_privileged() {
741 self.build_page();
742 }
743 }
744 ModeKind::Horizontal => {
745 self.cur_list_mut().space_factor = 1000;
746 self.tail_append(cur_box);
747 }
748 _ => {
749 self.math_box_end(cur_box);
750 }
751 }
752 }
753 BoxContext::SetBox(n) => self.set_box_register(n, false, cur_box),
754 BoxContext::GlobalSetBox(n) => self.set_box_register(n, true, cur_box),
755 BoxContext::Shipout => {
756 if !cur_box.is_null() {
757 self.ship_out(cur_box);
758 }
759 }
760 BoxContext::Leaders(sub) => {
761 if cur_box.is_null() {
762 return;
763 }
764 self.get_nonblank_nonrelax_noncall();
765 let v = self.mode.abs_kind() == ModeKind::Vertical;
766 if (self.cur_cmd == Cmd::Hskip && !v) || (self.cur_cmd == Cmd::Vskip && v) {
767 self.append_glue();
768 let t = self.cur_list().tail;
769 self.nodes.set_subtype(t, sub);
770 if let NodeData::Glue { leader, .. } = self.nodes.data_mut(t) {
771 *leader = cur_box;
772 }
773 } else {
774 self.print_err("Leaders not followed by proper glue");
775 self.help(&[
776 "You should say `\\leaders <box or rule><hskip or vskip>'.",
777 "I found the <box or rule>, but there's no suitable",
778 "<hskip or vskip>, so I'm ignoring these leaders.",
779 ]);
780 self.back_error();
781 self.nodes.flush_list(cur_box);
782 }
783 }
784 }
785 }
786
787 pub fn start_adjust_lists(&mut self) {
790 if self.ts.adjust_head.is_null() {
791 self.ts.adjust_head = self.nodes.new_temp();
792 self.ts.pre_adjust_head = self.nodes.new_temp();
793 }
794 self.nodes.set_next(self.ts.adjust_head, NodeRef::NULL);
795 self.nodes.set_next(self.ts.pre_adjust_head, NodeRef::NULL);
796 self.ts.adjust_tail = Some(self.ts.adjust_head);
797 self.ts.pre_adjust_tail = Some(self.ts.pre_adjust_head);
798 }
799
800 fn append_adjust_list(&mut self, head: NodeRef) {
802 let first = self.nodes.next(head);
803 if first.is_null() {
804 return;
805 }
806 let tail = self.cur_list().tail;
807 self.nodes.link(tail, first);
808 let t = self.nodes.tail_of(first);
809 self.cur_list_mut().tail = t;
810 self.nodes.set_next(head, NodeRef::NULL);
811 }
812
813 fn append_box_with_adjustments(&mut self, b: NodeRef) {
816 let active = self.ts.adjust_tail.is_some();
817 if active {
818 let h = self.ts.pre_adjust_head;
819 self.append_adjust_list(h);
820 }
821 self.append_to_vlist(b);
822 if active {
823 let h = self.ts.adjust_head;
824 self.append_adjust_list(h);
825 }
826 self.ts.adjust_tail = None;
827 self.ts.pre_adjust_tail = None;
828 }
829
830 pub fn set_box_register(&mut self, n: u32, global: bool, b: NodeRef) {
833 let old = self.eqtb.boxes[n as usize].val;
834 let old_level = self.eqtb.boxes[n as usize].level;
835 let saved = !global && old_level != self.save.cur_level && self.save.cur_level > 1;
836 self.define(global, Loc::Box(n), Val::Node(b));
837 if !saved && !old.is_null() && old != b {
838 self.nodes.flush_list(old);
839 }
840 }
841
842 fn package(&mut self, vtop: bool) {
844 let d = self.eqtb.dimen(dp::BOXMAXDEPTH);
845 let group = self.save.cur_group;
846 self.unsave();
847 self.end_box_dirs();
848 let (spec, dir) = self.pop_spec();
849 let ctx = ctx_from_i64(self.pop_saved());
850 let kind = self.pop_saved() as u32;
851 let head = self.cur_list().head;
852 let first = self.nodes.next(head);
853 self.nodes.set_next(head, NodeRef::NULL);
854 let cur_box = if self.mode == Mode::RestrictedHorizontal {
855 let first = if kind == chr::HPACK {
856 first
857 } else {
858 let first = self.node_process_list(first, crate::nodeproc::Context::Hbox);
859 let g = if group == GroupCode::AdjustedHbox {
860 "adjusted_hbox"
861 } else {
862 "hbox"
863 };
864 self.filter_list("hpack_filter", first, g)
865 };
866 self.pack_dir = dir as i8;
867 self.hpack(first, spec)
868 } else {
869 let first = if kind == chr::VPACK || kind == chr::TPACK {
870 first
871 } else {
872 self.filter_list("vpack_filter", first, if vtop { "vtop" } else { "vbox" })
873 };
874 self.pack_dir = dir as i8;
875 let b = self.vpackage(first, spec, d);
876 if vtop {
877 let p = self.nodes.list_ptr(b);
879 let h = if !p.is_null() && self.nodes.id(p) <= id::RULE {
880 self.node_height(p)
881 } else {
882 0
883 };
884 if let Some(bd) = self.nodes.box_data_mut(b) {
885 bd.depth = bd.depth - h + bd.height;
886 bd.height = h;
887 }
888 }
889 b
890 };
891 if self.nodes.id(cur_box) == id::HLIST {
892 self.nodes.set_subtype(cur_box, 2);
893 }
894 self.pop_nest();
895 self.box_end(ctx, cur_box);
896 }
897
898 pub fn node_height(&self, p: NodeRef) -> i32 {
900 match self.nodes.data(p) {
901 NodeData::Box(b) => b.height,
902 NodeData::Unset { b, .. } => b.height,
903 NodeData::Rule { height, .. } => *height,
904 _ => 0,
905 }
906 }
907
908 pub fn node_depth(&self, p: NodeRef) -> i32 {
910 match self.nodes.data(p) {
911 NodeData::Box(b) => b.depth,
912 NodeData::Unset { b, .. } => b.depth,
913 NodeData::Rule { depth, .. } => *depth,
914 _ => 0,
915 }
916 }
917
918 pub fn new_local_par(&mut self) -> NodeRef {
920 let lb = self.eqtb.local_box[0].val;
921 let rb = self.eqtb.local_box[1].val;
922 let box_left = self.copy_node_list(lb);
923 let box_right = self.copy_node_list(rb);
924 let box_left_width = if lb.is_null() {
925 0
926 } else {
927 self.nodes.width(lb)
928 };
929 let box_right_width = if rb.is_null() {
930 0
931 } else {
932 self.nodes.width(rb)
933 };
934 let dir = self.dir_param(crate::primitives_gen::assign_dir::PARDIR) as i8;
935 self.new_node(
936 id::LOCAL_PAR,
937 0,
938 NodeData::LocalPar {
939 pen_inter: self.eqtb.int(ip::LOCALINTERLINEPENALTY),
940 pen_broken: self.eqtb.int(ip::LOCALBROKENPENALTY),
941 dir,
942 box_left,
943 box_left_width,
944 box_right,
945 box_right_width,
946 },
947 )
948 }
949
950 pub fn new_graf(&mut self, indented: bool) {
952 self.cur_list_mut().prev_graf = 0;
953 let (head, tail) = (self.cur_list().head, self.cur_list().tail);
954 if self.mode == Mode::Vertical || head != tail {
955 let g = self.new_param_glue(glue_sub::PAR_SKIP);
956 self.tail_append(g);
957 }
958 self.push_nest(Mode::Horizontal);
959 self.cur_list_mut().space_factor = 1000;
960 let l = self.cur_lang() as i32;
961 self.cur_list_mut().clang = l;
962 let lp = self.new_local_par();
963 self.tail_append(lp);
964 self.par_text_dir();
965 if indented {
966 let b = self.new_null_box_node(true);
967 let w = self.eqtb.dimen(dp::PARINDENT);
968 let dir = self.dir_param(crate::primitives_gen::assign_dir::PARDIR) as i8;
969 if let Some(bd) = self.nodes.box_data_mut(b) {
970 bd.width = w;
971 bd.dir = dir;
972 }
973 self.nodes.set_subtype(b, 3);
974 self.tail_append(b);
975 }
976 let t = self
977 .eqtb
978 .toks_param(crate::primitives_gen::assign_toks::EVERYPAR)
979 .clone();
980 if !t.is_empty() {
981 self.begin_token_list(t, TokKind::EveryParText);
982 }
983 if self.nest.len() == 2 {
984 self.build_page();
985 }
986 }
987
988 fn indent_in_hmode(&mut self) {
990 if self.cur_chr == chr::INDENT {
991 let b = self.new_null_box_node(true);
992 let w = self.eqtb.dimen(dp::PARINDENT);
993 if let Some(bd) = self.nodes.box_data_mut(b) {
994 bd.width = w;
995 }
996 if self.mode.abs_kind() == ModeKind::Horizontal {
997 self.cur_list_mut().space_factor = 1000;
998 self.tail_append(b);
999 } else {
1000 self.math_box_end(b);
1001 }
1002 }
1003 }
1004
1005 fn head_for_vmode(&mut self) {
1008 if self.mode.is_inner() {
1009 if self.cur_cmd != Cmd::Hrule {
1010 self.off_save();
1011 } else {
1012 self.print_err("You can't use `");
1013 self.print_esc_str("hrule");
1014 self.printer.print_str("' here except with leaders");
1015 self.help(&[
1016 "To put a horizontal rule in an hbox or an alignment,",
1017 "you should use \\leaders or \\hrulefill (see The TeXbook).",
1018 ]);
1019 self.error();
1020 }
1021 } else {
1022 self.back_input();
1023 self.cur_tok = Token::cs(self.par_token_cs);
1024 self.back_input();
1025 if let Some(crate::input::Level::Tokens(t)) = self.input.stack.last_mut() {
1026 t.kind = TokKind::Inserted;
1027 }
1028 }
1029 }
1030
1031 pub fn end_graf(&mut self) {
1033 if self.mode == Mode::Horizontal {
1034 let (head, tail) = (self.cur_list().head, self.cur_list().tail);
1035 let only_local_par = self.nodes.next(head) == tail
1038 && matches!(self.nodes.data(tail), NodeData::LocalPar { .. });
1039 if head == tail || only_local_par {
1040 self.nodes.flush_list(tail);
1041 self.pop_nest();
1042 } else {
1043 let wp = self.eqtb.int(ip::WIDOWPENALTY);
1044 self.line_break(wp);
1045 }
1046 self.normal_paragraph();
1047 self.err.error_count = 0;
1048 }
1049 }
1050
1051 pub fn normal_paragraph(&mut self) {
1053 use crate::primitives_gen::set_etex_shape as es;
1054 if self.eqtb.int(ip::LOOSENESS) != 0 {
1055 self.eq_define(Loc::IntPar(ip::LOOSENESS), Val::Int(0));
1056 }
1057 if self.eqtb.dimen(dp::HANGINDENT) != 0 {
1058 self.eq_define(Loc::DimenPar(dp::HANGINDENT), Val::Int(0));
1059 }
1060 if self.eqtb.int(ip::HANGAFTER) != 1 {
1061 self.eq_define(Loc::IntPar(ip::HANGAFTER), Val::Int(1));
1062 }
1063 if self.eqtb.par_shape.val.is_some() {
1064 self.eq_define(Loc::ParShape, Val::Shape(None));
1065 }
1066 if self.eqtb.etex_shape[es::INTERLINEPENALTIES as usize]
1067 .val
1068 .is_some()
1069 {
1070 self.eq_define(Loc::EtexShape(es::INTERLINEPENALTIES), Val::Shape(None));
1071 }
1072 }
1073
1074 fn begin_insert_or_adjust(&mut self) {
1076 let v: i64 = if self.cur_cmd == Cmd::Vadjust {
1077 let pre = self.scan_keyword("pre");
1078 if pre { -2 } else { -1 }
1079 } else {
1080 self.scan_register_num();
1081 let mut n = self.cur_val;
1082 if n == self.output_box_num() {
1083 self.print_err("You can't ");
1084 self.print_esc_str("insert");
1085 self.printer.print_int(i64::from(n));
1086 self.help(&["I'm changing to \\insert0; box \\outputbox is special."]);
1087 self.error();
1088 n = 0;
1089 }
1090 i64::from(n)
1091 };
1092 self.push_saved(v);
1093 self.new_save_level(GroupCode::Insert);
1094 self.scan_left_brace();
1095 self.normal_paragraph();
1096 self.push_nest(Mode::InternalVertical);
1097 self.cur_list_mut().prev_depth = IGNORE_DEPTH;
1098 }
1099
1100 pub fn output_box_num(&self) -> i32 {
1102 let n = self.eqtb.int(ip::OUTPUTBOX);
1103 if (0..65536).contains(&n) { n } else { 255 }
1104 }
1105
1106 fn finish_insert_group(&mut self) {
1108 self.end_graf();
1109 let q = self.eqtb.glue(gp::SPLITTOPSKIP);
1110 let d = self.eqtb.dimen(dp::SPLITMAXDEPTH);
1111 let f = self.eqtb.int(ip::FLOATINGPENALTY);
1112 self.unsave();
1113 let n = self.pop_saved();
1114 let head = self.cur_list().head;
1115 let first = self.nodes.next(head);
1116 self.nodes.set_next(head, NodeRef::NULL);
1117 let p = self.vpack(first, PackSpec::NATURAL);
1118 self.pop_nest();
1119 let list = self.nodes.list_ptr(p);
1120 self.nodes.set_list_ptr(p, NodeRef::NULL);
1121 let (h, dd) = match self.nodes.box_data(p) {
1122 Some(b) => (b.height, b.depth),
1123 None => (0, 0),
1124 };
1125 if n >= 0 {
1126 let node = self.new_node(
1127 id::INS,
1128 n as u16,
1129 NodeData::Ins {
1130 cost: f,
1131 depth: d,
1132 height: h + dd,
1133 spec: q,
1134 head: list,
1135 },
1136 );
1137 self.tail_append(node);
1138 } else {
1139 let node = self.new_node(
1140 id::ADJUST,
1141 if n == -2 { 1 } else { 0 },
1142 NodeData::Adjust { head: list },
1143 );
1144 self.tail_append(node);
1145 }
1146 self.nodes.free(p);
1147 if self.nest.len() == 1 {
1148 self.build_page();
1149 }
1150 }
1151
1152 fn make_mark(&mut self) {
1154 let c: u32 = if self.cur_chr == 0 {
1155 0
1156 } else if self.cur_chr == 1 {
1157 self.scan_register_num();
1159 let n = self.cur_val as u32;
1160 self.marks.classes.remove(&n);
1161 return;
1162 } else {
1163 self.scan_register_num();
1164 self.cur_val as u32
1165 };
1166 let toks = self.scan_toks_expanded();
1167 let p = self.new_node(
1168 id::MARK,
1169 0,
1170 NodeData::Mark {
1171 class: c,
1172 mark: std::rc::Rc::from(toks),
1173 },
1174 );
1175 self.tail_append(p);
1176 }
1177
1178 fn append_penalty(&mut self) {
1180 self.scan_int();
1181 let p = self.new_penalty_node(self.cur_val);
1182 self.tail_append(p);
1183 if self.mode == Mode::Vertical {
1184 self.build_page();
1185 }
1186 }
1187
1188 fn delete_last(&mut self) {
1190 let (head, tail) = (self.cur_list().head, self.cur_list().tail);
1191 let want = self.cur_chr as u8;
1192 if self.mode == Mode::Vertical && tail == head {
1193 if want != id::GLUE || self.page.last_glue.is_some() {
1195 self.you_cant();
1196 let l0 = if want == id::KERN {
1197 "Try `I\\kern-\\lastkern' instead."
1198 } else if want != id::GLUE {
1199 "Perhaps you can make the output routine do it."
1200 } else {
1201 "Try `I\\vskip-\\lastskip' instead."
1202 };
1203 self.help(&[
1204 "Sorry...I usually can't take things from the current page.",
1205 l0,
1206 ]);
1207 self.error();
1208 }
1209 return;
1210 }
1211 if tail == head || self.nodes.id(tail) != want {
1212 return;
1213 }
1214 let p = self.find_prev(tail);
1215 self.nodes.set_next(p, NodeRef::NULL);
1216 self.nodes.flush_list(tail);
1217 self.cur_list_mut().tail = p;
1218 }
1219
1220 fn unpackage(&mut self) {
1223 let c = self.cur_chr;
1224 if c > chr::COPY {
1225 let k = c as usize;
1227 let p = self.ts.disc_ptr[k];
1228 self.ts.disc_ptr[k] = NodeRef::NULL;
1229 if !p.is_null() {
1230 let tail = self.cur_list().tail;
1231 self.nodes.link(tail, p);
1232 let t = self.nodes.tail_of(p);
1233 self.cur_list_mut().tail = t;
1234 }
1235 return;
1236 }
1237 self.scan_register_num();
1238 let n = self.cur_val as usize;
1239 let p = self.eqtb.boxes[n].val;
1240 if p.is_null() {
1241 return;
1242 }
1243 let t = self.nodes.id(p);
1244 let k = self.mode.abs_kind();
1245 if k == ModeKind::Math
1246 || (k == ModeKind::Vertical && t != id::VLIST)
1247 || (k == ModeKind::Horizontal && t != id::HLIST)
1248 {
1249 self.print_err("Incompatible list can't be unboxed");
1250 self.help(&[
1251 "Sorry, Pandora. (You sneaky devil.)",
1252 "I refuse to unbox an \\hbox in vertical mode or vice versa.",
1253 "And I can't open any boxes in math mode.",
1254 ]);
1255 self.error();
1256 return;
1257 }
1258 let list = if c == chr::COPY {
1259 let l = self.nodes.list_ptr(p);
1260 self.nodes.copy_list(l)
1261 } else {
1262 let l = self.nodes.list_ptr(p);
1263 self.nodes.set_list_ptr(p, NodeRef::NULL);
1264 self.eqtb.boxes[n].val = NodeRef::NULL;
1265 self.nodes.free(p);
1266 l
1267 };
1268 let list = if t == id::HLIST {
1269 self.strip_margin_kerns(list)
1270 } else {
1271 list
1272 };
1273 if !list.is_null() {
1274 let tail = self.cur_list().tail;
1275 self.nodes.link(tail, list);
1276 let t = self.nodes.tail_of(list);
1277 self.cur_list_mut().tail = t;
1278 }
1279 }
1280
1281 fn append_italic_correction(&mut self) {
1283 let (head, tail) = (self.cur_list().head, self.cur_list().tail);
1284 if tail == head {
1285 return;
1286 }
1287 let Some(g) = self.nodes.glyph(tail) else {
1288 return;
1289 };
1290 let (f, c) = (g.font, g.chr);
1291 let ic = self.font_char_dimen(f, c, 3);
1292 let k = self.new_kern_node(ic, kern_sub::ITALIC);
1293 self.tail_append(k);
1294 }
1295
1296 fn append_discretionary(&mut self) {
1298 let c = self.cur_chr;
1299 if c == 1 {
1300 let pen = self.eqtb.int(ip::EXHYPHENPENALTY);
1302 let d = self.new_node(
1303 id::DISC,
1304 1,
1305 NodeData::Disc {
1306 pre: NodeRef::NULL,
1307 post: NodeRef::NULL,
1308 replace: NodeRef::NULL,
1309 penalty: pen,
1310 },
1311 );
1312 let lang = self.cur_lang();
1313 let (pre_c, post_c) = {
1314 let l = self.lang_params(lang);
1315 (l.pre_hyphen_char, l.post_hyphen_char)
1316 };
1317 let f = self.eqtb.cur_font.val;
1318 let pre = if pre_c > 0 {
1319 self.new_char_node(f, pre_c as u32)
1320 } else {
1321 NodeRef::NULL
1322 };
1323 let post = if post_c > 0 {
1324 self.new_char_node(f, post_c as u32)
1325 } else {
1326 NodeRef::NULL
1327 };
1328 self.nodes.set_disc_lists(d, (pre, post, NodeRef::NULL));
1329 self.tail_append(d);
1330 return;
1331 }
1332 let mut pen = self.eqtb.int(ip::HYPHENPENALTY);
1333 if self.scan_keyword("penalty") {
1334 self.scan_int();
1335 pen = self.cur_val;
1336 }
1337 let d = self.new_node(
1338 id::DISC,
1339 if c == 2 { 2 } else { 0 },
1340 NodeData::Disc {
1341 pre: NodeRef::NULL,
1342 post: NodeRef::NULL,
1343 replace: NodeRef::NULL,
1344 penalty: pen,
1345 },
1346 );
1347 self.tail_append(d);
1348 self.push_saved(0);
1349 self.new_save_level(GroupCode::Disc);
1350 self.scan_left_brace();
1351 self.push_nest(Mode::RestrictedHorizontal);
1352 self.cur_list_mut().space_factor = 1000;
1353 }
1354
1355 fn build_discretionary(&mut self) {
1358 self.unsave();
1359 let head = self.cur_list().head;
1361 let mut q = head;
1362 let mut p = self.nodes.next(q);
1363 while !p.is_null() {
1364 let t = self.nodes.id(p);
1365 if !matches!(t, id::GLYPH | id::KERN | id::HLIST | id::VLIST | id::RULE) {
1366 self.print_err("Improper discretionary list");
1367 self.help(&["Discretionary lists must contain only boxes and kerns."]);
1368 self.error();
1369 self.begin_diagnostic();
1370 self.printer
1371 .print_nl("The following discretionary sublist has been deleted:");
1372 self.show_box(p);
1373 self.end_diagnostic(true);
1374 self.nodes.flush_list(p);
1375 self.nodes.set_next(q, NodeRef::NULL);
1376 break;
1377 }
1378 q = p;
1379 p = self.nodes.next(q);
1380 }
1381 let list = self.nodes.next(head);
1382 self.nodes.set_next(head, NodeRef::NULL);
1383 if !list.is_null() {
1384 self.nodes.set_prev(list, NodeRef::NULL);
1385 }
1386 self.pop_nest();
1387 let k = self.pop_saved();
1388 let d = self.cur_list().tail;
1389 let (mut pre, mut post, mut rep) = self.nodes.disc_lists(d);
1390 match k {
1391 0 => pre = list,
1392 1 => post = list,
1393 _ => {
1394 if !list.is_null() && self.mode.abs_kind() == ModeKind::Math {
1395 self.print_err("Illegal math ");
1396 self.print_esc_str("discretionary");
1397 self.help(&[
1398 "Sorry: The third part of a discretionary break must be",
1399 "empty, in math formulas. I had to delete your third part.",
1400 ]);
1401 self.nodes.flush_list(list);
1402 self.error();
1403 } else {
1404 rep = list;
1405 }
1406 self.nodes.set_disc_lists(d, (pre, post, rep));
1407 return;
1408 }
1409 }
1410 self.nodes.set_disc_lists(d, (pre, post, rep));
1411 self.push_saved(k + 1);
1412 self.new_save_level(GroupCode::Disc);
1413 self.scan_left_brace();
1414 self.push_nest(Mode::RestrictedHorizontal);
1415 self.cur_list_mut().space_factor = 1000;
1416 }
1417
1418 fn make_accent(&mut self) {
1420 self.scan_char_num();
1421 let f = self.eqtb.cur_font.val;
1422 let p = self.new_char_node(f, self.cur_val as u32);
1423 let x = self.x_height(f);
1424 let s = f64::from(self.font(f).params.get(1).copied().unwrap_or(0)) / 65536.0;
1425 let a = self.char_width(f, self.cur_val as u32);
1426 self.do_assignments();
1427 let mut q = NodeRef::NULL;
1428 let f2 = self.eqtb.cur_font.val;
1429 if matches!(self.cur_cmd, Cmd::Letter | Cmd::OtherChar | Cmd::CharGiven) {
1430 q = self.new_char_node(f2, self.cur_chr);
1431 } else if self.cur_cmd == Cmd::CharNum {
1432 self.scan_char_num();
1433 q = self.new_char_node(f2, self.cur_val as u32);
1434 } else {
1435 self.back_input();
1436 }
1437 let mut p = p;
1438 if !q.is_null() {
1439 let t = f64::from(self.font(f2).params.get(1).copied().unwrap_or(0)) / 65536.0;
1440 let qc = self.nodes.glyph(q).map_or(0, |g| g.chr);
1441 let w = self.char_width(f2, qc);
1442 let h = self.font_char_dimen(f2, qc, 1);
1443 if h != x {
1444 p = self.hpack(p, PackSpec::NATURAL);
1445 if let Some(b) = self.nodes.box_data_mut(p) {
1446 b.shift = x - h;
1447 }
1448 }
1449 let delta =
1450 ((f64::from(w - a)) / 2.0 + f64::from(h) * t - f64::from(x) * s).round() as i32;
1451 let r = self.new_kern_node(delta, kern_sub::ACCENT);
1452 self.tail_append(r);
1453 self.tail_append(p);
1454 let k = self.new_kern_node(-a - delta, kern_sub::ACCENT);
1455 self.tail_append(k);
1456 p = q;
1457 }
1458 self.tail_append(p);
1459 self.cur_list_mut().space_factor = 1000;
1460 }
1461
1462 #[inline]
1464 pub fn char_width(&self, f: u32, c: u32) -> i32 {
1465 self.font(f).chars.get(&c).map_or(0, |m| m.width)
1466 }
1467
1468 pub fn do_assignments(&mut self) {
1470 loop {
1471 self.get_nonblank_nonrelax_noncall();
1472 if self.cur_cmd <= Cmd::MAX_NON_PREFIXED {
1473 return;
1474 }
1475 self.err.set_box_allowed = false;
1476 self.prefixed_command();
1477 self.err.set_box_allowed = true;
1478 }
1479 }
1480
1481 pub fn append_boundary(&mut self) {
1484 let c = self.cur_chr;
1485 let v = if c == 1 || c == 2 {
1486 self.scan_int();
1487 self.cur_val
1488 } else {
1489 0
1490 };
1491 let p = self.new_node(id::BOUNDARY, c as u16, NodeData::Boundary { value: v });
1492 self.tail_append(p);
1493 }
1494
1495 fn append_ghost(&mut self) {
1497 let right = self.cur_chr == 1;
1498 self.scan_char_num();
1499 let f = self.eqtb.cur_font.val;
1500 let g = self.new_char_node(f, self.cur_val as u32);
1501 let sub = crate::nodes::glyph_sub::GHOST
1502 | if right {
1503 crate::nodes::glyph_sub::RIGHT
1504 } else {
1505 crate::nodes::glyph_sub::LEFT
1506 };
1507 self.nodes.set_subtype(g, sub);
1508 self.tail_append(g);
1509 }
1510
1511 fn begin_local_box(&mut self) {
1513 let k = self.cur_chr;
1514 self.push_saved(i64::from(k));
1515 self.new_save_level(GroupCode::LocalBox);
1516 self.scan_left_brace();
1517 self.push_nest(Mode::RestrictedHorizontal);
1518 self.cur_list_mut().space_factor = 1000;
1519 }
1520
1521 fn finish_local_box(&mut self) {
1523 self.unsave();
1524 let k = self.pop_saved() as usize;
1525 let head = self.cur_list().head;
1526 let first = self.nodes.next(head);
1527 self.nodes.set_next(head, NodeRef::NULL);
1528 self.pop_nest();
1529 let b = if first.is_null() {
1530 NodeRef::NULL
1531 } else {
1532 let first = self.node_process_list(first, crate::nodeproc::Context::Hbox);
1533 let b = self.hpack(first, PackSpec::NATURAL);
1534 self.nodes.set_subtype(b, 2);
1535 b
1536 };
1537 self.eq_define(Loc::LocalBox(k as u32), Val::Node(b));
1538 if self.mode == Mode::Horizontal {
1539 let lp = self.new_local_par();
1541 self.tail_append(lp);
1542 }
1543 }
1544
1545 fn align_error(&mut self) {
1547 if self.input.align_state.abs() > 2 {
1548 self.print_err("Misplaced ");
1549 self.print_cmd_chr(self.cur_cmd, self.cur_chr);
1550 if self.cur_tok == Token::char(Cmd::TabMark, '&' as u32) {
1551 self.help(&[
1552 "I can't figure out why you would want to use a tab mark",
1553 "here. If you just want an ampersand, the remedy is",
1554 "simple: Just type `I\\&' now. But if some right brace",
1555 "up above has ended a previous alignment prematurely,",
1556 "you're probably due for more error messages, and you",
1557 "might try typing `S' now just to see what is salvageable.",
1558 ]);
1559 } else {
1560 self.help(&[
1561 "I can't figure out why you would want to use a tab mark",
1562 "or \\cr or \\span just now. If something like a right brace",
1563 "up above has ended a previous alignment prematurely,",
1564 "you're probably due for more error messages, and you",
1565 "might try typing `S' now just to see what is salvageable.",
1566 ]);
1567 }
1568 self.error();
1569 } else {
1570 self.back_input();
1571 if self.input.align_state < 0 {
1572 self.print_err("Missing { inserted");
1573 self.input.align_state += 1;
1574 self.cur_tok = Token::LEFT_BRACE;
1575 } else {
1576 self.print_err("Missing } inserted");
1577 self.input.align_state -= 1;
1578 self.cur_tok = Token::RIGHT_BRACE;
1579 }
1580 self.help(&[
1581 "I've put in what seems to be necessary to fix",
1582 "the current column of the current alignment.",
1583 "Try to go on, since this might almost work.",
1584 ]);
1585 self.ins_error();
1586 }
1587 }
1588
1589 fn no_align_error(&mut self) {
1590 self.print_err("Misplaced ");
1591 self.print_esc_str("noalign");
1592 self.help(&[
1593 "I expect to see \\noalign only after the \\cr of",
1594 "an alignment. Proceed, and I'll ignore this case.",
1595 ]);
1596 self.error();
1597 }
1598
1599 fn omit_error(&mut self) {
1600 self.print_err("Misplaced ");
1601 self.print_esc_str("omit");
1602 self.help(&[
1603 "I expect to see \\omit only after tab marks or the \\cr of",
1604 "an alignment. Proceed, and I'll ignore this case.",
1605 ]);
1606 self.error();
1607 }
1608
1609 fn cs_error(&mut self) {
1610 self.print_err("Extra ");
1611 self.print_esc_str("endcsname");
1612 self.help(&["I'm ignoring this, since I wasn't doing a \\csname."]);
1613 self.error();
1614 }
1615
1616 pub fn append_to_vlist(&mut self, b: NodeRef) {
1619 let pd = self.cur_list().prev_depth;
1620 if pd > IGNORE_DEPTH {
1621 let bs = self.eqtb.glue(gp::BASELINESKIP);
1622 let h = self.node_height(b);
1623 let d = bs.width - pd - h;
1624 let p = if d < self.eqtb.dimen(dp::LINESKIPLIMIT) {
1625 self.new_param_glue(glue_sub::LINE_SKIP)
1626 } else {
1627 let g = Glue { width: d, ..bs };
1628 self.new_glue_node(g, glue_sub::BASELINE_SKIP)
1629 };
1630 self.tail_append(p);
1631 }
1632 self.tail_append(b);
1633 let d = self.node_depth(b);
1634 self.cur_list_mut().prev_depth = d;
1635 }
1636
1637 pub fn handle_right_brace_typesetting(&mut self) {
1640 match self.save.cur_group {
1641 GroupCode::Hbox => self.package(false),
1642 GroupCode::AdjustedHbox => {
1643 self.start_adjust_lists();
1644 self.package(false);
1645 }
1646 GroupCode::Vbox => {
1647 self.end_graf();
1648 self.package(false);
1649 }
1650 GroupCode::Vtop => {
1651 self.end_graf();
1652 self.package(true);
1653 }
1654 GroupCode::Insert => self.finish_insert_group(),
1655 GroupCode::Output => self.resume_output(),
1656 GroupCode::Disc => self.build_discretionary(),
1657 GroupCode::Align => {
1658 self.back_input();
1659 self.cur_tok = Token::cs(self.cs.frozen_cr);
1660 self.print_err("Missing ");
1661 self.print_esc_str("cr");
1662 self.printer.print_str(" inserted");
1663 self.help(&["I'm guessing that you meant to end an alignment here."]);
1664 self.ins_error();
1665 }
1666 GroupCode::NoAlign => {
1667 self.end_graf();
1668 self.unsave();
1669 self.align_peek();
1670 }
1671 GroupCode::LocalBox => self.finish_local_box(),
1672 GroupCode::Vcenter | GroupCode::Math | GroupCode::MathChoice => self.math_right_brace(),
1673 _ => self.confusion("rightbrace"),
1674 }
1675 }
1676}
1677
1678pub fn glue_param_of_subtype(sub: u16) -> u32 {
1680 match sub {
1681 glue_sub::LINE_SKIP => gp::LINESKIP,
1682 glue_sub::BASELINE_SKIP => gp::BASELINESKIP,
1683 glue_sub::PAR_SKIP => gp::PARSKIP,
1684 glue_sub::ABOVE_DISPLAY => gp::ABOVEDISPLAYSKIP,
1685 glue_sub::BELOW_DISPLAY => gp::BELOWDISPLAYSKIP,
1686 glue_sub::ABOVE_DISPLAY_SHORT => gp::ABOVEDISPLAYSHORTSKIP,
1687 glue_sub::BELOW_DISPLAY_SHORT => gp::BELOWDISPLAYSHORTSKIP,
1688 glue_sub::LEFT_SKIP => gp::LEFTSKIP,
1689 glue_sub::RIGHT_SKIP => gp::RIGHTSKIP,
1690 glue_sub::TOP_SKIP => gp::TOPSKIP,
1691 glue_sub::SPLIT_TOP_SKIP => gp::SPLITTOPSKIP,
1692 glue_sub::TAB_SKIP => gp::TABSKIP,
1693 glue_sub::SPACE_SKIP => gp::SPACESKIP,
1694 glue_sub::XSPACE_SKIP => gp::XSPACESKIP,
1695 glue_sub::PAR_FILL_SKIP => gp::PARFILLSKIP,
1696 glue_sub::MATH_SKIP => gp::MATHSURROUNDSKIP,
1697 _ => gp::LINESKIP,
1698 }
1699}
1700
1701pub fn box_with(width: i32, height: i32, depth: i32) -> BoxData {
1703 BoxData {
1704 width,
1705 height,
1706 depth,
1707 ..BoxData::default()
1708 }
1709}