beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / tex / align.w
blobf1984a88c5006170a52d0b1c503d30e96b09f8d3
1 % align.w
3 % Copyright 2009-2010 Taco Hoekwater <taco@@luatex.org>
5 % This file is part of LuaTeX.
7 % LuaTeX is free software; you can redistribute it and/or modify it under
8 % the terms of the GNU General Public License as published by the Free
9 % Software Foundation; either version 2 of the License, or (at your
10 % option) any later version.
12 % LuaTeX is distributed in the hope that it will be useful, but WITHOUT
13 % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 % FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 % License for more details.
17 % You should have received a copy of the GNU General Public License along
18 % with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
20 \def\<#1>{$#1$}
22 @ @c
25 #include "ptexlib.h"
27 @ @c
28 void fin_align(void);
29 void init_row(void);
30 void init_col(void);
32 #define noDEBUG
34 #define end_template_token (cs_token_flag+frozen_end_template)
36 #define prev_depth cur_list.prev_depth_field
37 #define space_factor cur_list.space_factor_field
38 #define incompleat_noad cur_list.incompleat_noad_field
40 #define every_cr equiv(every_cr_loc)
41 #define display_indent dimen_par(display_indent_code)
42 #define max_depth dimen_par(max_depth_code)
43 #define overfull_rule dimen_par(overfull_rule_code)
45 @ It's sort of a miracle whenever \.{\\halign} and \.{\\valign} work, because
46 they cut across so many of the control structures of \TeX.
48 Therefore the present page is probably not the best place for a beginner to
49 start reading this program; it is better to master everything else first.
51 Let us focus our thoughts on an example of what the input might be, in order
52 to get some idea about how the alignment miracle happens. The example doesn't
53 do anything useful, but it is sufficiently general to indicate all of the
54 special cases that must be dealt with; please do not be disturbed by its
55 apparent complexity and meaninglessness.
56 $$\vbox{\halign{\.{#}\hfil\cr
57 {}\\tabskip 2pt plus 3pt\cr
58 {}\\halign to 300pt\{u1\#v1\&\cr
59 \hskip 50pt\\tabskip 1pt plus 1fil u2\#v2\&\cr
60 \hskip 50pt u3\#v3\\cr\cr
61 \hskip 25pt a1\&\\omit a2\&\\vrule\\cr\cr
62 \hskip 25pt \\noalign\{\\vskip 3pt\}\cr
63 \hskip 25pt b1\\span b2\\cr\cr
64 \hskip 25pt \\omit\&c2\\span\\omit\\cr\}\cr}}$$
65 Here's what happens:
67 \yskip
68 (0) When `\.{\\halign to 300pt\{}' is scanned, the |scan_spec| routine
69 places the 300pt dimension onto the |save_stack|, and an |align_group|
70 code is placed above it. This will make it possible to complete the alignment
71 when the matching `\.\}' is found.
73 (1) The preamble is scanned next. Macros in the preamble are not expanded,
74 @^preamble@>
75 except as part of a tabskip specification. For example, if \.{u2} had been
76 a macro in the preamble above, it would have been expanded, since \TeX\
77 must look for `\.{minus...}' as part of the tabskip glue. A ``preamble list''
78 is constructed based on the user's preamble; in our case it contains the
79 following seven items:
80 $$\vbox{\halign{\.{#}\hfil\qquad&(#)\hfil\cr
81 {}\\glue 2pt plus 3pt&the tabskip preceding column 1\cr
82 {}\\alignrecord, width $-\infty$&preamble info for column 1\cr
83 {}\\glue 2pt plus 3pt&the tabskip between columns 1 and 2\cr
84 {}\\alignrecord, width $-\infty$&preamble info for column 2\cr
85 {}\\glue 1pt plus 1fil&the tabskip between columns 2 and 3\cr
86 {}\\alignrecord, width $-\infty$&preamble info for column 3\cr
87 {}\\glue 1pt plus 1fil&the tabskip following column 3\cr}}$$
88 These ``alignrecord'' entries have the same size as an |unset_node|,
89 since they will later be converted into such nodes. These alignrecord
90 nodes have no |depth| field; this is split into |u_part| and |v_part|,
91 and they point to token lists for the templates of the alignment. For
92 example, the |u_part| field in the first alignrecord points to the
93 token list `\.{u1}', i.e., the template preceding the `\.\#' for
94 column~1. Furthermore, They have a |span_ptr| instead of a |node_attr|
95 field, and these |span_ptr| fields are initially set to the value
96 |end_span|, for reasons explained below.
98 (2) \TeX\ now looks at what follows the \.{\\cr} that ended the preamble.
99 It is not `\.{\\noalign}' or `\.{\\omit}', so this input is put back to
100 be read again, and the template `\.{u1}' is fed to the scanner. Just
101 before reading `\.{u1}', \TeX\ goes into restricted horizontal mode.
102 Just after reading `\.{u1}', \TeX\ will see `\.{a1}', and then (when the
103 {\.\&} is sensed) \TeX\ will see `\.{v1}'. Then \TeX\ scans an |endv|
104 token, indicating the end of a column. At this point an |unset_node| is
105 created, containing the contents of the current hlist (i.e., `\.{u1a1v1}').
106 The natural width of this unset node replaces the |width| field of the
107 alignrecord for column~1; in general, the alignrecords will record the
108 maximum natural width that has occurred so far in a given column.
110 (3) Since `\.{\\omit}' follows the `\.\&', the templates for column~2
111 are now bypassed. Again \TeX\ goes into restricted horizontal mode and
112 makes an |unset_node| from the resulting hlist; but this time the
113 hlist contains simply `\.{a2}'. The natural width of the new unset box
114 is remembered in the |width| field of the alignrecord for column~2.
116 (4) A third |unset_node| is created for column 3, using essentially the
117 mechanism that worked for column~1; this unset box contains `\.{u3\\vrule
118 v3}'. The vertical rule in this case has running dimensions that will later
119 extend to the height and depth of the whole first row, since each |unset_node|
120 in a row will eventually inherit the height and depth of its enclosing box.
122 (5) The first row has now ended; it is made into a single unset box
123 comprising the following seven items:
124 $$\vbox{\halign{\hbox to 325pt{\qquad\.{#}\hfil}\cr
125 {}\\glue 2pt plus 3pt\cr
126 {}\\unsetbox for 1 column: u1a1v1\cr
127 {}\\glue 2pt plus 3pt\cr
128 {}\\unsetbox for 1 column: a2\cr
129 {}\\glue 1pt plus 1fil\cr
130 {}\\unsetbox for 1 column: u3\\vrule v3\cr
131 {}\\glue 1pt plus 1fil\cr}}$$
132 The width of this unset row is unimportant, but it has the correct height
133 and depth, so the correct baselineskip glue will be computed as the row
134 is inserted into a vertical list.
136 (6) Since `\.{\\noalign}' follows the current \.{\\cr}, \TeX\ appends
137 additional material (in this case \.{\\vskip 3pt}) to the vertical list.
138 While processing this material, \TeX\ will be in internal vertical
139 mode, and |no_align_group| will be on |save_stack|.
141 (7) The next row produces an unset box that looks like this:
142 $$\vbox{\halign{\hbox to 325pt{\qquad\.{#}\hfil}\cr
143 {}\\glue 2pt plus 3pt\cr
144 {}\\unsetbox for 2 columns: u1b1v1u2b2v2\cr
145 {}\\glue 1pt plus 1fil\cr
146 {}\\unsetbox for 1 column: {\rm(empty)}\cr
147 {}\\glue 1pt plus 1fil\cr}}$$
148 The natural width of the unset box that spans columns 1~and~2 is stored
149 in a ``span node,'' which we will explain later; the |span_ptr| field of the
150 alignrecord for column~1 now points to the new span node, and the |span_ptr|
151 of the span node points to |end_span|.
153 (8) The final row produces the unset box
154 $$\vbox{\halign{\hbox to 325pt{\qquad\.{#}\hfil}\cr
155 {}\\glue 2pt plus 3pt\cr
156 {}\\unsetbox for 1 column: {\rm(empty)}\cr
157 {}\\glue 2pt plus 3pt\cr
158 {}\\unsetbox for 2 columns: u2c2v2\cr
159 {}\\glue 1pt plus 1fil\cr}}$$
160 A new span node is attached to the alignrecord for column 2.
162 (9) The last step is to compute the true column widths and to change all the
163 unset boxes to hboxes, appending the whole works to the vertical list that
164 encloses the \.{\\halign}. The rules for deciding on the final widths of
165 each unset column box will be explained below.
167 \yskip\noindent
168 Note that as \.{\\halign} is being processed, we fearlessly give up control
169 to the rest of \TeX. At critical junctures, an alignment routine is
170 called upon to step in and do some little action, but most of the time
171 these routines just lurk in the background. It's something like
172 post-hypnotic suggestion.
174 @ We have mentioned that alignrecords contain no |height| or |depth| fields.
175 Their |glue_sign| and |glue_order| are pre-empted as well, since it
176 is necessary to store information about what to do when a template ends.
177 This information is called the |extra_info| field.
180 #define u_part(A) vlink((A)+depth_offset) /* pointer to \<u_j> token list */
181 #define v_part(A) vinfo((A)+depth_offset) /* pointer to \<v_j> token list */
182 #define span_ptr(A) vinfo((A)+1) /* column spanning list */
183 #define extra_info(A) vinfo((A)+list_offset) /* info to remember during template */
185 @ Alignments can occur within alignments, so a small stack is used to access
186 the alignrecord information. At each level we have a |preamble| pointer,
187 indicating the beginning of the preamble list; a |cur_align| pointer,
188 indicating the current position in the preamble list; a |cur_span| pointer,
189 indicating the value of |cur_align| at the beginning of a sequence of
190 spanned columns; a |cur_loop| pointer, indicating the tabskip glue before
191 an alignrecord that should be copied next if the current list is extended;
192 and the |align_state| variable, which indicates the nesting of braces so
193 that \.{\\cr} and \.{\\span} and tab marks are properly intercepted.
194 There also are pointers |cur_head| and |cur_tail| to the head and tail
195 of a list of adjustments being moved out from horizontal mode to
196 vertical~mode, and alike |cur_pre_head| and |cur_pre_tail| for pre-adjust
197 lists.
199 The current values of these nine quantities appear in global variables;
200 when they have to be pushed down, they are stored in 6-word nodes, and
201 |align_ptr| points to the topmost such node.
204 #define preamble vlink(align_head) /* the current preamble list */
206 pointer cur_align = null; /* current position in preamble list */
207 pointer cur_span = null; /* start of currently spanned columns in preamble list */
208 pointer cur_loop = null; /* place to copy when extending a periodic preamble */
209 pointer align_ptr = null; /* most recently pushed-down alignment stack node */
210 pointer cur_head = null, cur_tail = null; /* adjustment list pointers */
211 pointer cur_pre_head = null, cur_pre_tail = null; /* pre-adjustment list pointers */
213 /* The |align_state| and |preamble| variables are initialized elsewhere. */
215 @ Alignment stack maintenance is handled by a pair of trivial routines
216 called |push_alignment| and |pop_alignment|.
218 (HH:) It makes not much sense to add support for an \.{attr} keyword to
219 \.{\\halign} and \.{\\valign} because then we need to decide if we tag
220 rows or cells or both or come up with \.{cellattr} and \.{rowattr} and
221 such. But then it even makes sense to have explicit commands (in addition
222 to the seperator) to tags individual cells. Too muss hassle for now and the
223 advantages are not that large.
226 static void push_alignment(void)
228 pointer p; /* the new alignment stack node */
229 p = new_node(align_stack_node, 0);
230 vinfo(p + 1) = align_ptr;
231 vlink(p + 1) = cur_align;
232 vinfo(p + 2) = preamble;
233 vlink(p + 2) = cur_span;
234 vinfo(p + 3) = cur_loop;
235 vlink(p + 3) = align_state;
236 vinfo(p + 4) = cur_head;
237 vlink(p + 4) = cur_tail;
238 vinfo(p + 5) = cur_pre_head;
239 vlink(p + 5) = cur_pre_tail;
240 align_ptr = p;
241 cur_head = new_node(temp_node, 0);
242 cur_pre_head = new_node(temp_node, 0);
245 static void pop_alignment(void)
247 pointer p; /* the top alignment stack node */
248 flush_node(cur_head);
249 flush_node(cur_pre_head);
250 p = align_ptr;
251 cur_pre_tail = vlink(p + 5);
252 cur_pre_head = vinfo(p + 5);
253 cur_tail = vlink(p + 4);
254 cur_head = vinfo(p + 4);
255 align_state = vlink(p + 3);
256 cur_loop = vinfo(p + 3);
257 cur_span = vlink(p + 2);
258 preamble = vinfo(p + 2);
259 cur_align = vlink(p + 1);
260 align_ptr = vinfo(p + 1);
261 flush_node(p);
265 @ \TeX\ has eight procedures that govern alignments: |init_align| and
266 |fin_align| are used at the very beginning and the very end; |init_row| and
267 |fin_row| are used at the beginning and end of individual rows; |init_span|
268 is used at the beginning of a sequence of spanned columns (possibly involving
269 only one column); |init_col| and |fin_col| are used at the beginning and
270 end of individual columns; and |align_peek| is used after \.{\\cr} to see
271 whether the next item is \.{\\noalign}.
273 We shall consider these routines in the order they are first used during
274 the course of a complete \.{\\halign}, namely |init_align|, |align_peek|,
275 |init_row|, |init_span|, |init_col|, |fin_col|, |fin_row|, |fin_align|.
278 @ The preamble is copied directly, except that \.{\\tabskip} causes a change
279 to the tabskip glue, thereby possibly expanding macros that immediately
280 follow it. An appearance of \.{\\span} also causes such an expansion.
282 Note that if the preamble contains `\.{\\global\\tabskip}', the `\.{\\global}'
283 token survives in the preamble and the `\.{\\tabskip}' defines new
284 tabskip glue (locally).
287 static void get_preamble_token(void)
289 RESTART:
290 get_token();
291 while ((cur_chr == span_code) && (cur_cmd == tab_mark_cmd)) {
292 get_token(); /* this token will be expanded once */
293 if (cur_cmd > max_command_cmd) {
294 expand();
295 get_token();
298 if (cur_cmd == endv_cmd)
299 fatal_error("(interwoven alignment preambles are not allowed)");
300 if ((cur_cmd == assign_glue_cmd)
301 && (cur_chr == glue_base + tab_skip_code)) {
302 scan_optional_equals();
303 scan_glue(glue_val_level);
304 if (int_par(global_defs_code) > 0)
305 geq_define(glue_base + tab_skip_code, glue_ref_cmd, cur_val);
306 else
307 eq_define(glue_base + tab_skip_code, glue_ref_cmd, cur_val);
308 goto RESTART;
314 @ When \.{\\halign} or \.{\\valign} has been scanned in an appropriate
315 mode, \TeX\ calls |init_align|, whose task is to get everything off to a
316 good start. This mostly involves scanning the preamble and putting its
317 information into the preamble list.
318 @^preamble@>
321 void init_align(void)
323 /* label done, done1, done2, continue; */
324 pointer save_cs_ptr; /* |warning_index| value for error messages */
325 pointer p, r; /* for short-term temporary use */
326 save_cs_ptr = cur_cs; /* \.{\\halign} or \.{\\valign}, usually */
327 push_alignment();
328 align_state = -1000000; /* enter a new alignment level */
330 /* When \.{\\halign} is used as a displayed formula, there should be
331 no other pieces of mlists present. */
333 if ((cur_list.mode_field == mmode)
334 && ((cur_list.tail_field != cur_list.head_field)
335 || (incompleat_noad != null))) {
336 const char *hlp[] =
337 { "Displays can use special alignments (like \\eqalignno)",
338 "only if nothing but the alignment itself is between $$'s.",
339 "So I've deleted the formulas that preceded this alignment.",
340 NULL
342 tex_error("Improper \\halign inside $$'s", hlp);
343 flush_math();
345 push_nest(); /* enter a new semantic level */
346 /* In vertical modes, |prev_depth| already has the correct value. But
347 if we are in |mmode| (displayed formula mode), we reach out to the
348 enclosing vertical mode for the |prev_depth| value that produces the
349 correct baseline calculations. */
350 if (cur_list.mode_field == mmode) {
351 cur_list.mode_field = -vmode;
352 prev_depth = nest[nest_ptr - 2].prev_depth_field;
353 } else if (cur_list.mode_field > 0) {
354 cur_list.mode_field = -(cur_list.mode_field);
356 scan_spec(align_group);
357 /* Scan the preamble */
358 preamble = null;
359 cur_align = align_head;
360 cur_loop = null;
361 scanner_status = aligning;
362 warning_index = save_cs_ptr;
363 align_state = -1000000;
364 /* at this point, |cur_cmd=left_brace| */
365 while (true) {
366 /* Append the current tabskip glue to the preamble list */
367 r = new_param_glue(tab_skip_code);
368 vlink(cur_align) = r;
369 cur_align = vlink(cur_align);
371 if (cur_cmd == car_ret_cmd)
372 break; /* \.{\\cr} ends the preamble */
374 /* Scan preamble text until |cur_cmd| is |tab_mark| or |car_ret| */
375 /* Scan the template \<u_j>, putting the resulting token list in |hold_token_head| */
376 /* Spaces are eliminated from the beginning of a template. */
378 p = hold_token_head;
379 token_link(p) = null;
380 while (1) {
381 get_preamble_token();
382 if (cur_cmd == mac_param_cmd)
383 break;
384 if ((cur_cmd <= car_ret_cmd) && (cur_cmd >= tab_mark_cmd)
385 && (align_state == -1000000)) {
386 if ((p == hold_token_head) && (cur_loop == null)
387 && (cur_cmd == tab_mark_cmd)) {
388 cur_loop = cur_align;
389 } else {
390 const char *hlp[] =
391 { "There should be exactly one # between &'s, when an",
392 "\\halign or \\valign is being set up. In this case you had",
393 "none, so I've put one in; maybe that will work.",
394 NULL
396 back_input();
397 tex_error("Missing # inserted in alignment preamble", hlp);
398 break;
400 } else if ((cur_cmd != spacer_cmd) || (p != hold_token_head)) {
401 r = get_avail();
402 token_link(p) = r;
403 p = token_link(p);
404 token_info(p) = cur_tok;
407 r = new_node(align_record_node, 0);
408 vlink(cur_align) = r;
409 cur_align = vlink(cur_align); /* a new alignrecord */
410 span_ptr(cur_align) = end_span;
411 width(cur_align) = null_flag;
412 u_part(cur_align) = token_link(hold_token_head);
413 /* Scan the template \<v_j>, putting the resulting token list in |hold_token_head| */
415 p = hold_token_head;
416 token_link(p) = null;
417 while (1) {
418 CONTINUE:
419 get_preamble_token();
420 if ((cur_cmd <= car_ret_cmd) && (cur_cmd >= tab_mark_cmd)
421 && (align_state == -1000000))
422 break;
423 if (cur_cmd == mac_param_cmd) {
424 const char *hlp[] =
425 { "There should be exactly one # between &'s, when an",
426 "\\halign or \\valign is being set up. In this case you had",
427 "more than one, so I'm ignoring all but the first.",
428 NULL
430 tex_error("Only one # is allowed per tab", hlp);
431 goto CONTINUE;
433 r = get_avail();
434 token_link(p) = r;
435 p = token_link(p);
436 token_info(p) = cur_tok;
438 r = get_avail();
439 token_link(p) = r;
440 p = token_link(p);
441 token_info(p) = end_template_token; /* put \.{\\endtemplate} at the end */
443 v_part(cur_align) = token_link(hold_token_head);
445 scanner_status = normal;
447 new_save_level(align_group);
448 if (every_cr != null)
449 begin_token_list(every_cr, every_cr_text);
450 align_peek(); /* look for \.{\\noalign} or \.{\\omit} */
454 @ The tricky part about alignments is getting the templates into the
455 scanner at the right time, and recovering control when a row or column
456 is finished.
458 We usually begin a row after each \.{\\cr} has been sensed, unless that
459 \.{\\cr} is followed by \.{\\noalign} or by the right brace that terminates
460 the alignment. The |align_peek| routine is used to look ahead and do
461 the right thing; it either gets a new row started, or gets a \.{\\noalign}
462 started, or finishes off the alignment.
465 void align_peek(void)
467 RESTART:
468 align_state = 1000000;
469 do {
470 get_x_or_protected();
471 } while (cur_cmd == spacer_cmd);
472 if (cur_cmd == no_align_cmd) {
473 scan_left_brace();
474 new_save_level(no_align_group);
475 if (cur_list.mode_field == -vmode)
476 normal_paragraph();
477 } else if (cur_cmd == right_brace_cmd) {
478 fin_align();
479 } else if ((cur_cmd == car_ret_cmd) && (cur_chr == cr_cr_code)) {
480 goto RESTART; /* ignore \.{\\crcr} */
481 } else {
482 init_row(); /* start a new row */
483 init_col(); /* start a new column and replace what we peeked at */
488 @ The parameter to |init_span| is a pointer to the alignrecord where the
489 next column or group of columns will begin. A new semantic level is
490 entered, so that the columns will generate a list for subsequent packaging.
493 static void init_span(pointer p)
495 push_nest();
496 if (cur_list.mode_field == -hmode) {
497 space_factor = 1000;
498 } else {
499 prev_depth = ignore_depth;
500 normal_paragraph();
502 cur_span = p;
506 @ To start a row (i.e., a `row' that rhymes with `dough' but not with `bough'),
507 we enter a new semantic level, copy the first tabskip glue, and change
508 from internal vertical mode to restricted horizontal mode or vice versa.
509 The |space_factor| and |prev_depth| are not used on this semantic level,
510 but we clear them to zero just to be tidy.
513 void init_row(void)
515 push_nest();
516 cur_list.mode_field = (-hmode - vmode) - cur_list.mode_field;
517 if (cur_list.mode_field == -hmode)
518 space_factor = 0;
519 else
520 prev_depth = 0;
521 tail_append(new_glue(glue_ptr(preamble)));
522 subtype(cur_list.tail_field) = tab_skip_code + 1;
523 cur_align = vlink(preamble);
524 cur_tail = cur_head;
525 cur_pre_tail = cur_pre_head;
526 init_span(cur_align);
530 @ When a column begins, we assume that |cur_cmd| is either |omit| or else
531 the current token should be put back into the input until the \<u_j>
532 template has been scanned. (Note that |cur_cmd| might be |tab_mark| or
533 |car_ret|.) We also assume that |align_state| is approximately 1000000 at
534 this time. We remain in the same mode, and start the template if it is
535 called for.
538 void init_col(void)
540 extra_info(cur_align) = cur_cmd;
541 if (cur_cmd == omit_cmd)
542 align_state = 0;
543 else {
544 back_input();
545 begin_token_list(u_part(cur_align), u_template);
546 } /* now |align_state=1000000| */
550 @ The scanner sets |align_state| to zero when the \<u_j> template ends. When
551 a subsequent \.{\\cr} or \.{\\span} or tab mark occurs with |align_state=0|,
552 the scanner activates the following code, which fires up the \<v_j> template.
553 We need to remember the |cur_chr|, which is either |cr_cr_code|, |cr_code|,
554 |span_code|, or a character code, depending on how the column text has ended.
556 This part of the program had better not be activated when the preamble
557 to another alignment is being scanned, or when no alignment preamble is active.
560 void insert_vj_template(void)
562 if ((scanner_status == aligning) || (cur_align == null))
563 fatal_error("(interwoven alignment preambles are not allowed)");
564 cur_cmd = extra_info(cur_align);
565 extra_info(cur_align) = cur_chr;
566 if (cur_cmd == omit_cmd)
567 begin_token_list(omit_template, v_template);
568 else
569 begin_token_list(v_part(cur_align), v_template);
570 align_state = 1000000;
573 /* Determine the stretch order */
574 #define determine_stretch_order() do { \
575 if (total_stretch[filll]!=0) o=filll; \
576 else if (total_stretch[fill]!=0) o=fill; \
577 else if (total_stretch[fil]!=0) o=fil; \
578 else if (total_stretch[sfi]!=0) o=sfi; \
579 else o=normal; \
580 } while (0)
583 /* Determine the shrink order */
584 #define determine_shrink_order() do { \
585 if (total_shrink[filll]!=0) o=filll; \
586 else if (total_shrink[fill]!=0) o=fill; \
587 else if (total_shrink[fil]!=0) o=fil; \
588 else if (total_shrink[sfi]!=0) o=sfi; \
589 else o=normal; \
590 } while (0)
594 @ When the |endv| command at the end of a \<v_j> template comes through the
595 scanner, things really start to happen; and it is the |fin_col| routine
596 that makes them happen. This routine returns |true| if a row as well as a
597 column has been finished.
600 boolean fin_col(void)
602 pointer p; /* the alignrecord after the current one */
603 pointer q, r; /* temporary pointers for list manipulation */
604 pointer s; /* a new span node */
605 pointer u; /* a new unset box */
606 scaled w; /* natural width */
607 unsigned char o; /* order of infinity */
608 halfword n; /* span counter */
609 if (cur_align == null)
610 confusion("endv");
611 q = vlink(cur_align);
612 if (q == null)
613 confusion("endv");
614 if (align_state < 500000)
615 fatal_error("(interwoven alignment preambles are not allowed)");
616 p = vlink(q);
617 /* If the preamble list has been traversed, check that the row has ended */
618 if ((p == null) && (extra_info(cur_align) < cr_code)) {
619 if (cur_loop != null) {
620 /* Lengthen the preamble periodically */
621 r = new_node(align_record_node, 0);
622 vlink(q) = r;
623 p = vlink(q); /* a new alignrecord */
624 span_ptr(p) = end_span;
625 width(p) = null_flag;
626 cur_loop = vlink(cur_loop);
628 /* Copy the templates from node |cur_loop| into node |p| */
629 q = hold_token_head;
630 r = u_part(cur_loop);
631 while (r != null) {
632 s = get_avail();
633 token_link(q) = s;
634 q = token_link(q);
635 token_info(q) = token_info(r);
636 r = token_link(r);
638 token_link(q) = null;
639 u_part(p) = token_link(hold_token_head);
640 q = hold_token_head;
641 r = v_part(cur_loop);
642 while (r != null) {
643 s = get_avail();
644 token_link(q) = s;
645 q = token_link(q);
646 token_info(q) = token_info(r);
647 r = token_link(r);
649 token_link(q) = null;
650 v_part(p) = token_link(hold_token_head);
652 cur_loop = vlink(cur_loop);
653 r = new_glue(glue_ptr(cur_loop));
654 vlink(p) = r;
655 } else {
656 const char *hlp[] =
657 { "You have given more \\span or & marks than there were",
658 "in the preamble to the \\halign or \\valign now in progress.",
659 "So I'll assume that you meant to type \\cr instead.",
660 NULL
662 extra_info(cur_align) = cr_code;
663 tex_error("Extra alignment tab has been changed to \\cr", hlp);
666 if (extra_info(cur_align) != span_code) {
667 unsave();
668 new_save_level(align_group);
669 /* Package an unset box for the current column and record its width */
670 if (cur_list.mode_field == -hmode) {
671 adjust_tail = cur_tail;
672 pre_adjust_tail = cur_pre_tail;
673 u = filtered_hpack(cur_list.head_field, cur_list.tail_field, 0,
674 additional, align_set_group, -1, 0);
675 w = width(u);
676 cur_tail = adjust_tail;
677 adjust_tail = null;
678 cur_pre_tail = pre_adjust_tail;
679 pre_adjust_tail = null;
680 } else {
681 u = filtered_vpackage(vlink(cur_list.head_field),
682 0, additional, 0, align_set_group, -1, 0);
683 w = height(u);
685 n = min_quarterword; /* this represents a span count of 1 */
686 if (cur_span != cur_align) {
687 /* Update width entry for spanned columns */
688 q = cur_span;
689 do {
690 incr(n);
691 q = vlink(vlink(q));
692 } while (q != cur_align);
693 if (n > max_quarterword)
694 confusion("too many spans"); /* this can happen, but won't */
695 q = cur_span;
696 while (span_span(span_ptr(q)) < n) {
697 q = span_ptr(q);
699 if (span_span(span_ptr(q)) > n) {
700 s = new_span_node(span_ptr(q), n, w);
701 span_ptr(q) = s;
702 } else if (width(span_ptr(q)) < w) {
703 width(span_ptr(q)) = w;
706 } else if (w > width(cur_align)) {
707 width(cur_align) = w;
709 type(u) = unset_node;
710 span_count(u) = (quarterword) n;
711 determine_stretch_order();
712 glue_order(u) = o;
713 glue_stretch(u) = total_stretch[o];
714 determine_shrink_order();
715 glue_sign(u) = o;
716 glue_shrink(u) = total_shrink[o];
717 pop_nest();
718 vlink(cur_list.tail_field) = u;
719 cur_list.tail_field = u;
721 /* Copy the tabskip glue between columns */
722 tail_append(new_glue(glue_ptr(vlink(cur_align))));
723 subtype(cur_list.tail_field) = tab_skip_code + 1;
725 if (extra_info(cur_align) >= cr_code) {
726 return true;
728 init_span(p);
730 align_state = 1000000;
731 do {
732 get_x_or_protected();
733 } while (cur_cmd == spacer_cmd);
734 cur_align = p;
735 init_col();
736 return false;
741 @ A span node is a 3-word record containing |width|, |span_span|, and
742 |span_ptr| fields. The |span_span| field indicates the number of
743 spanned columns; the |span_ptr| field points to a span node for the same
744 starting column, having a greater extent of spanning, or to
745 |end_span|, which has the largest possible |span_span| field; the |width|
746 field holds the largest natural width corresponding to a particular
747 set of spanned columns.
749 A list of the maximum widths so far, for spanned columns starting at a
750 given column, begins with the |span_ptr| field of the alignrecord for
751 that column. The code has to make sure that there is room for
752 |span_ptr| in both the alignrecord and the span nodes, which is why
753 |span_ptr| replaces |node_attr|.
754 @^data structure assumptions@>
756 The |new_span_node| function is defined in |texnodes.c|.
759 #ifndef span_span
760 # define span_span(A) vlink((A)+1) /* that is normally |alink| */
761 #endif
764 @ At the end of a row, we append an unset box to the current vlist (for
765 \.{\\halign}) or the current hlist (for \.{\\valign}). This unset box
766 contains the unset boxes for the columns, separated by the tabskip glue.
767 Everything will be set later.
770 void fin_row(void)
772 pointer p; /* the new unset box */
773 if (cur_list.mode_field == -hmode) {
774 p = filtered_hpack(cur_list.head_field, cur_list.tail_field, 0,
775 additional, fin_row_group, -1, 0);
776 pop_nest();
777 if (cur_pre_head != cur_pre_tail)
778 append_list(cur_pre_head, cur_pre_tail);
779 append_to_vlist(p,lua_key_index(alignment));
780 if (cur_head != cur_tail)
781 append_list(cur_head, cur_tail);
782 } else {
783 p = filtered_vpackage(vlink(cur_list.head_field),
784 0, additional, max_depth, fin_row_group, -1, 0);
785 pop_nest();
786 vlink(cur_list.tail_field) = p;
787 cur_list.tail_field = p;
788 space_factor = 1000;
790 type(p) = unset_node;
791 glue_stretch(p) = 0;
792 if (every_cr != null)
793 begin_token_list(every_cr, every_cr_text);
794 align_peek();
795 /* note that |glue_shrink(p)=0| since |glue_shrink==shift_amount| */
799 @ Finally, we will reach the end of the alignment, and we can breathe a
800 sigh of relief that memory hasn't overflowed. All the unset boxes will now be
801 set so that the columns line up, taking due account of spanned columns.
804 void fin_align(void)
806 pointer p, q, r, s, u, v, rr; /* registers for the list operations */
807 scaled t, w; /* width of column */
808 scaled o; /* shift offset for unset boxes */
809 halfword n; /* matching span amount */
810 scaled rule_save; /* temporary storage for |overfull_rule| */
811 halfword pd; /* temporary storage for |prev_depth| */
812 if (cur_group != align_group)
813 confusion("align1");
814 unsave(); /* that |align_group| was for individual entries */
815 if (cur_group != align_group)
816 confusion("align0");
817 unsave(); /* that |align_group| was for the whole alignment */
818 if (nest[nest_ptr - 1].mode_field == mmode)
819 o = display_indent;
820 else
821 o = 0;
822 /* Go through the preamble list, determining the column widths and
823 * changing the alignrecords to dummy unset boxes
826 /* It's time now to dismantle the preamble list and to compute the column
827 widths. Let $w_{ij}$ be the maximum of the natural widths of all entries
828 that span columns $i$ through $j$, inclusive. The alignrecord for column~$i$
829 contains $w_{ii}$ in its |width| field, and there is also a linked list of
830 the nonzero $w_{ij}$ for increasing $j$, accessible via the |info| field;
831 these span nodes contain the value $j-i+|min_quarterword|$ in their
832 |link| fields. The values of $w_{ii}$ were initialized to |null_flag|, which
833 we regard as $-\infty$.
835 The final column widths are defined by the formula
836 $$w_j=\max_{1\L i\L j}\biggl( w_{ij}-\sum_{i\L k<j}(t_k+w_k)\biggr),$$
837 where $t_k$ is the natural width of the tabskip glue between columns
838 $k$ and~$k+1$. However, if $w_{ij}=-\infty$ for all |i| in the range
839 |1<=i<=j| (i.e., if every entry that involved column~|j| also involved
840 column~|j+1|), we let $w_j=0$, and we zero out the tabskip glue after
841 column~|j|.
843 \TeX\ computes these values by using the following scheme: First $w_1=w_{11}$.
844 Then replace $w_{2j}$ by $\max(w_{2j},w_{1j}-t_1-w_1)$, for all $j>1$.
845 Then $w_2=w_{22}$. Then replace $w_{3j}$ by $\max(w_{3j},w_{2j}-t_2-w_2)$
846 for all $j>2$; and so on. If any $w_j$ turns out to be $-\infty$, its
847 value is changed to zero and so is the next tabskip.
849 q = vlink(preamble);
850 do {
851 flush_list(u_part(q));
852 flush_list(v_part(q));
853 p = vlink(vlink(q));
854 if (width(q) == null_flag) {
855 /* Nullify |width(q)| and the tabskip glue following this column */
856 width(q) = 0;
857 r = vlink(q);
858 s = glue_ptr(r);
859 if (s != zero_glue) {
860 add_glue_ref(zero_glue);
861 delete_glue_ref(s);
862 glue_ptr(r) = zero_glue;
865 if (span_ptr(q) != end_span) {
866 /* Merge the widths in the span nodes of |q| with those of |p|,
867 destroying the span nodes of |q| */
869 Merging of two span-node lists is a typical exercise in the manipulation of
870 linearly linked data structures. The essential invariant in the following
871 |repeat| loop is that we want to dispense with node |r|, in |q|'s list,
872 and |u| is its successor; all nodes of |p|'s list up to and including |s|
873 have been processed, and the successor of |s| matches |r| or precedes |r|
874 or follows |r|, according as |link(r)=n| or |link(r)>n| or |link(r)<n|.
876 t = width(q) + width(glue_ptr(vlink(q)));
877 r = span_ptr(q);
878 s = end_span;
879 span_ptr(s) = p;
880 n = min_quarterword + 1;
881 do {
882 width(r) = width(r) - t;
883 u = span_ptr(r);
884 while (span_span(r) > n) {
885 s = span_ptr(s);
886 n = span_span(span_ptr(s)) + 1;
888 if (span_span(r) < n) {
889 span_ptr(r) = span_ptr(s);
890 span_ptr(s) = r;
891 decr(span_span(r));
892 s = r;
893 } else {
894 if (width(r) > width(span_ptr(s)))
895 width(span_ptr(s)) = width(r);
896 flush_node(r);
898 r = u;
899 } while (r != end_span);
901 type(q) = unset_node;
902 span_count(q) = min_quarterword;
903 height(q) = 0;
904 depth(q) = 0;
905 glue_order(q) = normal;
906 glue_sign(q) = normal;
907 glue_stretch(q) = 0;
908 glue_shrink(q) = 0;
909 q = p;
910 } while (q != null);
912 /* Package the preamble list, to determine the actual tabskip glue amounts,
913 and let |p| point to this prototype box */
914 /* Now the preamble list has been converted to a list of alternating unset
915 boxes and tabskip glue, where the box widths are equal to the final
916 column sizes. In case of \.{\\valign}, we change the widths to heights,
917 so that a correct error message will be produced if the alignment is
918 overfull or underfull.
921 decr(save_ptr);
922 pack_begin_line = -cur_list.ml_field;
923 if (cur_list.mode_field == -vmode) {
924 rule_save = overfull_rule;
925 overfull_rule = 0; /* prevent rule from being packaged */
926 p = hpack(preamble, saved_value(0), saved_level(0), -1);
927 overfull_rule = rule_save;
928 } else {
929 q = vlink(preamble);
930 do {
931 height(q) = width(q);
932 width(q) = 0;
933 q = vlink(vlink(q));
934 } while (q != null);
935 p = filtered_vpackage(preamble,
936 saved_value(0), saved_level(0), max_depth, preamble_group, -1, 0);
937 q = vlink(preamble);
938 do {
939 width(q) = height(q);
940 height(q) = 0;
941 q = vlink(vlink(q));
942 } while (q != null);
944 pack_begin_line = 0;
946 /* Set the glue in all the unset boxes of the current list */
947 q = vlink(cur_list.head_field);
948 s = cur_list.head_field;
949 while (q != null) {
950 if (!is_char_node(q)) {
951 if (type(q) == unset_node) {
952 /* Set the unset box |q| and the unset boxes in it */
953 /* The unset box |q| represents a row that contains one or more unset boxes,
954 depending on how soon \.{\\cr} occurred in that row. */
956 if (cur_list.mode_field == -vmode) {
957 type(q) = hlist_node;
958 subtype(q) = align_row_list;
959 width(q) = width(p);
960 } else {
961 type(q) = vlist_node;
962 subtype(q) = align_row_list;
963 height(q) = height(p);
965 glue_order(q) = glue_order(p);
966 glue_sign(q) = glue_sign(p);
967 glue_set(q) = glue_set(p);
968 shift_amount(q) = o;
969 r = vlink(list_ptr(q));
970 assert (type(r) == unset_node);
971 s = vlink(list_ptr(p));
972 do {
973 /* Set the glue in node |r| and change it from an unset node */
974 /* A box made from spanned columns will be followed by tabskip glue nodes and
975 by empty boxes as if there were no spanning. This permits perfect alignment
976 of subsequent entries, and it prevents values that depend on floating point
977 arithmetic from entering into the dimensions of any boxes.
979 n = span_count(r);
980 t = width(s);
981 w = t;
982 u = hold_head;
983 while (n > min_quarterword) {
984 decr(n);
985 /* Append tabskip glue and an empty box to list |u|,
986 and update |s| and |t| as the prototype nodes are passed */
988 s = vlink(s);
989 v = glue_ptr(s);
990 vlink(u) = new_glue(v);
991 u = vlink(u);
992 subtype(u) = tab_skip_code + 1;
993 t = t + width(v);
994 if (glue_sign(p) == stretching) {
995 if (stretch_order(v) == glue_order(p))
996 t = t +
997 round(float_cast(glue_set(p)) *
998 float_cast(stretch(v)));
999 } else if (glue_sign(p) == shrinking) {
1000 if (shrink_order(v) == glue_order(p))
1001 t = t -
1002 round(float_cast(glue_set(p)) *
1003 float_cast(shrink(v)));
1005 s = vlink(s);
1006 rr = new_null_box();
1007 vlink(u) = rr;
1008 u = vlink(u);
1009 t = t + width(s);
1010 subtype(u) = align_cell_list;
1011 if (cur_list.mode_field == -vmode) {
1012 width(u) = width(s);
1013 } else {
1014 type(u) = vlist_node;
1015 height(u) = width(s);
1019 if (cur_list.mode_field == -vmode) {
1020 /* Make the unset node |r| into an |hlist_node| of width |w|,
1021 setting the glue as if the width were |t| */
1023 height(r) = height(q);
1024 depth(r) = depth(q);
1025 if (t == width(r)) {
1026 glue_sign(r) = normal;
1027 glue_order(r) = normal;
1028 set_glue_ratio_zero(glue_set(r));
1029 } else if (t > width(r)) {
1030 glue_sign(r) = stretching;
1031 if (glue_stretch(r) == 0)
1032 set_glue_ratio_zero(glue_set(r));
1033 else
1034 glue_set(r) =
1035 unfloat((double) (t - width(r)) /
1036 glue_stretch(r));
1037 } else {
1038 glue_order(r) = glue_sign(r);
1039 glue_sign(r) = shrinking;
1040 if (glue_shrink(r) == 0)
1041 set_glue_ratio_zero(glue_set(r));
1042 else if ((glue_order(r) == normal)
1043 && (width(r) - t > glue_shrink(r)))
1044 set_glue_ratio_one(glue_set(r));
1045 else
1046 glue_set(r) =
1047 unfloat((double) (width(r) - t) /
1048 glue_shrink(r));
1050 width(r) = w;
1051 type(r) = hlist_node;
1052 subtype(r) = align_cell_list;
1054 } else {
1055 /* Make the unset node |r| into a |vlist_node| of height |w|,
1056 setting the glue as if the height were |t| */
1058 width(r) = width(q);
1059 if (t == height(r)) {
1060 glue_sign(r) = normal;
1061 glue_order(r) = normal;
1062 set_glue_ratio_zero(glue_set(r));
1063 } else if (t > height(r)) {
1064 glue_sign(r) = stretching;
1065 if (glue_stretch(r) == 0)
1066 set_glue_ratio_zero(glue_set(r));
1067 else
1068 glue_set(r) =
1069 unfloat((t - height(r)) / glue_stretch(r));
1070 } else {
1071 glue_order(r) = glue_sign(r);
1072 glue_sign(r) = shrinking;
1073 if (glue_shrink(r) == 0)
1074 set_glue_ratio_zero(glue_set(r));
1075 else if ((glue_order(r) == normal)
1076 && (height(r) - t > glue_shrink(r)))
1077 set_glue_ratio_one(glue_set(r));
1078 else
1079 glue_set(r) =
1080 unfloat((height(r) - t) / glue_shrink(r));
1082 height(r) = w;
1083 type(r) = vlist_node;
1084 subtype(r) = align_cell_list;
1087 /* subtype(r) = 0; */
1088 shift_amount(r) = 0;
1089 if (u != hold_head) { /* append blank boxes to account for spanned nodes */
1090 vlink(u) = vlink(r);
1091 vlink(r) = vlink(hold_head);
1092 r = u;
1095 r = vlink(vlink(r));
1096 s = vlink(vlink(s));
1097 } while (r != null);
1099 } else if (type(q) == rule_node) {
1100 /* Make the running dimensions in rule |q| extend to the
1101 boundaries of the alignment */
1102 if (is_running(width(q)))
1103 width(q) = width(p);
1104 if (is_running(height(q)))
1105 height(q) = height(p);
1106 if (is_running(depth(q)))
1107 depth(q) = depth(p);
1108 if (o != 0) {
1109 r = vlink(q);
1110 vlink(q) = null;
1111 q = hpack(q, 0, additional, -1);
1112 shift_amount(q) = o;
1113 subtype(q) = align_cell_list;
1114 vlink(q) = r;
1115 vlink(s) = q;
1119 s = q;
1120 q = vlink(q);
1122 flush_node_list(p);
1123 pop_alignment();
1124 /* Insert the current list into its environment */
1125 /* We now have a completed alignment, in the list that starts at |cur_list.head_field|
1126 and ends at |cur_list.tail_field|. This list will be merged with the one that encloses
1127 it. (In case the enclosing mode is |mmode|, for displayed formulas,
1128 we will need to insert glue before and after the display; that part of the
1129 program will be deferred until we're more familiar with such operations.)
1131 pd = cur_list.prev_depth_field;
1132 p = vlink(cur_list.head_field);
1133 q = cur_list.tail_field;
1134 pop_nest();
1135 if (cur_list.mode_field == mmode) {
1136 finish_display_alignment(p, q, pd);
1137 } else {
1138 cur_list.prev_depth_field = pd; /* aux:=aux_save; */
1139 vlink(cur_list.tail_field) = p;
1140 if (p != null)
1141 cur_list.tail_field = q;
1142 if (cur_list.mode_field == vmode) {
1143 if (!output_active)
1144 lua_node_filter_s(buildpage_filter_callback,lua_key_index(alignment));
1145 build_page();
1150 @ The token list |omit_template| just referred to is a constant token
1151 list that contains the special control sequence \.{\\endtemplate} only.
1154 void initialize_alignments(void)
1156 token_info(omit_template) = end_template_token; /* |link(omit_template)=null| */
1157 span_span(end_span) = max_quarterword + 1;
1158 span_ptr(end_span) = null;