diff options
author | Denis Bitouzé <dbitouze@wanadoo.fr> | 2021-02-25 18:23:07 +0000 |
---|---|---|
committer | Denis Bitouzé <dbitouze@wanadoo.fr> | 2021-02-25 18:23:07 +0000 |
commit | c6101f91d071883b48b1b4b51e5eba0f36d9a78d (patch) | |
tree | 1bf7f5a881d7a4f5c5bf59d0b2821943dd822372 /Build/source/texk/web2c/luatexdir/tex/align.c | |
parent | 07ee7222e389b0777456b427a55c22d0e6ffd267 (diff) |
French translation for tlmgr updated
git-svn-id: svn://tug.org/texlive/trunk@57912 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/tex/align.c')
-rw-r--r-- | Build/source/texk/web2c/luatexdir/tex/align.c | 1299 |
1 files changed, 0 insertions, 1299 deletions
diff --git a/Build/source/texk/web2c/luatexdir/tex/align.c b/Build/source/texk/web2c/luatexdir/tex/align.c deleted file mode 100644 index bb721856fac..00000000000 --- a/Build/source/texk/web2c/luatexdir/tex/align.c +++ /dev/null @@ -1,1299 +0,0 @@ -/* - -Copyright 2009-2010 Taco Hoekwater <taco@luatex.org> - -This file is part of LuaTeX. - -LuaTeX is free software; you can redistribute it and/or modify it under -the terms of the GNU General Public License as published by the Free -Software Foundation; either version 2 of the License, or (at your -option) any later version. - -LuaTeX is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -License for more details. - -You should have received a copy of the GNU General Public License along -with LuaTeX; if not, see <http://www.gnu.org/licenses/>. - -*/ - -#include "ptexlib.h" - -void fin_align(void); -void init_row(void); -void init_col(void); - -#define noDEBUG - -/*tex - - It's sort of a miracle whenever \.{\\halign} and \.{\\valign} work, because - they cut across so many of the control structures of \TeX. Therefore the - present page is probably not the best place for a beginner to start reading - this program; it is better to master everything else first. - - Let us focus our thoughts on an example of what the input might be, in order - to get some idea about how the alignment miracle happens. The example doesn't - do anything useful, but it is sufficiently general to indicate all of the - special cases that must be dealt with; please do not be disturbed by its - apparent complexity and meaninglessness. - - \starttyping - \tabskip 2pt plus 3pt - \halign to 300pt{u1#v1& - \hskip 50pt \tabskip 1pt plus 1fil u2#v2& - \hskip 50pt u3#v3\cr - \hskip 25pt a1&\omit a2&\vrule\cr - \hskip 25pt \noalign\{\vskip 3pt} - \hskip 25pt b1\span b2\cr - \hskip 25pt \omit&c2\span\omit\cr} - \stoptyping - - Here's what happens: - - \startitemize - - \startitem - When `\.{\\halign to 300pt\{}' is scanned, the |scan_spec| routine - places the 300pt dimension onto the |save_stack|, and an - |align_group| code is placed above it. This will make it possible to - complete the alignment when the matching `\.\}' is found. - \stopitem - - \startitem - The preamble is scanned next. Macros in the preamble are not - expanded, except as part of a tabskip specification. For example, if - \.{u2} had been a macro in the preamble above, it would have been - expanded, since \TeX\ must look for `\.{minus...}' as part of the - tabskip glue. A ``preamble list'' is constructed based on the user's - preamble; in our case it contains the following seven items: - - \starttabulate - \NC \type{\glue 2pt plus 3pt} \NC the tabskip preceding column 1 \NC \NR - \NC \type{\alignrecord} of width $-\infty$ \NC preamble info for column 1 \NC \NR - \NC \type{\glue 2pt plus 3pt} \NC the tabskip between columns 1 and 2 \NC \NR - \NC \type{\alignrecord} of width $-\infty$ \NC preamble info for column 2 \NC \NR - \NC \type{\glue 1pt plus 1fil} \NC the tabskip between columns 2 and 3 \NC \NR - \NC \type{\alignrecord} of width $-\infty$ \NC preamble info for column 3 \NC \NR - \NC \type{\glue 1pt plus 1fil} \NC the tabskip following column 3 \NC \NR - \stoptabulate - - These ``alignrecord'' entries have the same size as an |unset_node|, - since they will later be converted into such nodes. These alignrecord - nodes have no |depth| field; this is split into |u_part| and - |v_part|, and they point to token lists for the templates of the - alignment. For example, the |u_part| field in the first alignrecord - points to the token list `\.{u1}', i.e., the template preceding the - `\.\#' for column~1. Furthermore, They have a |span_ptr| instead of a - |node_attr| field, and these |span_ptr| fields are initially set to - the value |end_span|, for reasons explained below. - \stopitem - - \startitem - \TeX\ now looks at what follows the \.{\\cr} that ended the preamble. - It is not `\.{\\noalign}' or `\.{\\omit}', so this input is put back - to be read again, and the template `\.{u1}' is fed to the scanner. - Just before reading `\.{u1}', \TeX\ goes into restricted horizontal - mode. Just after reading `\.{u1}', \TeX\ will see `\.{a1}', and then - (when the {\.\&} is sensed) \TeX\ will see `\.{v1}'. Then \TeX\ scans - an |endv| token, indicating the end of a column. At this point an - |unset_node| is created, containing the contents of the current hlist - (i.e., `\.{u1a1v1}'). The natural width of this unset node replaces - the |width| field of the alignrecord for column~1; in general, the - alignrecords will record the maximum natural width that has occurred - so far in a given column. - \stopitem - - \startitem - Since `\.{\\omit}' follows the `\.\&', the templates for column~2 are - now bypassed. Again \TeX\ goes into restricted horizontal mode and - makes an |unset_node| from the resulting hlist; but this time the - hlist contains simply `\.{a2}'. The natural width of the new unset - box is remembered in the |width| field of the alignrecord for - column~2. - \stopitem - - \startitem - A third |unset_node| is created for column 3, using essentially the - mechanism that worked for column~1; this unset box contains - `\.{u3\\vrule v3}'. The vertical rule in this case has running - dimensions that will later extend to the height and depth of the - whole first row, since each |unset_node| in a row will eventually - inherit the height and depth of its enclosing box. - \stopitem - - \startitem - The first row has now ended; it is made into a single unset box - comprising the following seven items: - - \starttyping - \glue 2pt plus 3pt - \unsetbox for 1 column: u1a1v1 - \glue 2pt plus 3pt - \unsetbox for 1 column: a2 - \glue 1pt plus 1fil - \unsetbox for 1 column: u3\vrule v3 - \glue 1pt plus 1fil - \stoptyping - - The width of this unset row is unimportant, but it has the correct - height and depth, so the correct baselineskip glue will be computed - as the row is inserted into a vertical list. - \stopitem - - \startitem - Since `\.{\\noalign}' follows the current \.{\\cr}, \TeX\ appends - additional material (in this case \.{\\vskip 3pt}) to the vertical - list. While processing this material, \TeX\ will be in internal - vertical mode, and |no_align_group| will be on |save_stack|. - \stopitem - - \startitem - The next row produces an unset box that looks like this: - - \starttyping - \glue 2pt plus 3pt - \unsetbox for 2 columns: u1b1v1u2b2v2 - \glue 1pt plus 1fil - \unsetbox for 1 column: {(empty)} - \glue 1pt plus 1fil - \stoptyping - - The natural width of the unset box that spans columns 1~and~2 is - stored in a ``span node,'' which we will explain later; the - |span_ptr| field of the alignrecord for column~1 now points to the - new span node, and the |span_ptr| of the span node points to - |end_span|. - \stopitem - - \startitem - - The final row produces the unset box - - \starttyping - \glue 2pt plus 3pt\cr - \unsetbox for 1 column: {(empty)} - \glue 2pt plus 3pt\cr - \unsetbox for 2 columns: u2c2v2 - \glue 1pt plus 1fil - \stoptyping - - A new span node is attached to the alignrecord for column 2. - \stopitem - - \startitem - The last step is to compute the true column widths and to change all - the unset boxes to hboxes, appending the whole works to the vertical - list that encloses the \.{\\halign}. The rules for deciding on the - final widths of each unset column box will be explained below. - \stopitem - - \stopitemize - - Note that as \.{\\halign} is being processed, we fearlessly give up control - to the rest of \TeX. At critical junctures, an alignment routine is called - upon to step in and do some little action, but most of the time these - routines just lurk in the background. It's something like post-hypnotic - suggestion. - - We have mentioned that alignrecords contain no |height| or |depth| fields. - Their |glue_sign| and |glue_order| are pre-empted as well, since it is - necessary to store information about what to do when a template ends. This - information is called the |extra_info| field. - -*/ - -/*tex The pointer to \<u_j> token list: */ - -#define u_part(A) vlink((A)+depth_offset) - -/*tex The pointer to \<v_j> token list */ - -#define v_part(A) vinfo((A)+depth_offset) - -/*tex A column spanning list */ - -#define span_ptr(A) vinfo((A)+1) - -/*tex Info to remember during template */ - -#define extra_info(A) vinfo((A)+list_offset) - -/*tex - - Alignments can occur within alignments, so a small stack is used to access - the alignrecord information. At each level we have a |preamble| pointer, - indicating the beginning of the preamble list; a |cur_align| pointer, - indicating the current position in the preamble list; a |cur_span| pointer, - indicating the value of |cur_align| at the beginning of a sequence of spanned - columns; a |cur_loop| pointer, indicating the tabskip glue before an - alignrecord that should be copied next if the current list is extended; and - the |align_state| variable, which indicates the nesting of braces so that - \.{\\cr} and \.{\\span} and tab marks are properly intercepted. There also - are pointers |cur_head| and |cur_tail| to the head and tail of a list of - adjustments being moved out from horizontal mode to vertical~mode, and alike - |cur_pre_head| and |cur_pre_tail| for pre-adjust lists. - - The current values of these nine quantities appear in global variables; when - they have to be pushed down, they are stored in 6-word nodes, and |align_ptr| - points to the topmost such node. - -*/ - -/*tex This could be in |texnodes.h| but it's documented here. */ - -/*tex The current preamble list: */ - -#define preamble vlink(align_head) - -/*tex The current position in the preamble list: */ - -pointer cur_align = null; - -/*tex The start of the currently spanned columns in the preamble list: */ - -pointer cur_span = null; - -/*tex A place to copy when extending a periodic preamble: */ - -pointer cur_loop = null; - -/*tex The most recently pushed-down alignment stack node: */ - -pointer align_ptr = null; - -/*tex Adjustment list pointers: */ - -pointer cur_head = null, cur_tail = null; - -/*tex Pre-adjustment list pointers: */ - -pointer cur_pre_head = null, cur_pre_tail = null; - -/*tex - - The |align_state| and |preamble| variables are initialized elsewhere. - - Alignment stack maintenance is handled by a pair of trivial routines called - |push_alignment| and |pop_alignment|. - - (HH:) It makes not much sense to add support for an \.{attr} keyword to - \.{\\halign} and \.{\\valign} because then we need to decide if we tag rows - or cells or both or come up with \.{cellattr} and \.{rowattr} and such. But - then it even makes sense to have explicit commands (in addition to the - seperator) to tags individual cells. Too muss hassle for now and the - advantages are not that large. - -*/ - -static void push_alignment(void) -{ - /*tex The new alignment stack node: */ - pointer p; - p = new_node(align_stack_node, 0); - vinfo(p + 1) = align_ptr; - vlink(p + 1) = cur_align; - vinfo(p + 2) = preamble; - vlink(p + 2) = cur_span; - vinfo(p + 3) = cur_loop; - vlink(p + 3) = align_state; - vinfo(p + 4) = cur_head; - vlink(p + 4) = cur_tail; - vinfo(p + 5) = cur_pre_head; - vlink(p + 5) = cur_pre_tail; - align_ptr = p; - cur_head = new_node(temp_node, 0); - cur_pre_head = new_node(temp_node, 0); -} - -static void pop_alignment(void) -{ - /*tex The top alignment stack node: */ - pointer p; - flush_node(cur_head); - flush_node(cur_pre_head); - p = align_ptr; - cur_pre_tail = vlink(p + 5); - cur_pre_head = vinfo(p + 5); - cur_tail = vlink(p + 4); - cur_head = vinfo(p + 4); - align_state = vlink(p + 3); - cur_loop = vinfo(p + 3); - cur_span = vlink(p + 2); - preamble = vinfo(p + 2); - cur_align = vlink(p + 1); - align_ptr = vinfo(p + 1); - flush_node(p); -} - -/*tex - - \TeX\ has eight procedures that govern alignments: |init_align| and - |fin_align| are used at the very beginning and the very end; |init_row| and - |fin_row| are used at the beginning and end of individual rows; |init_span| - is used at the beginning of a sequence of spanned columns (possibly involving - only one column); |init_col| and |fin_col| are used at the beginning and end - of individual columns; and |align_peek| is used after \.{\\cr} to see whether - the next item is \.{\\noalign}. - - We shall consider these routines in the order they are first used during the - course of a complete \.{\\halign}, namely |init_align|, |align_peek|, - |init_row|, |init_span|, |init_col|, |fin_col|, |fin_row|, |fin_align|. - - The preamble is copied directly, except that \.{\\tabskip} causes a change to - the tabskip glue, thereby possibly expanding macros that immediately follow - it. An appearance of \.{\\span} also causes such an expansion. - - Note that if the preamble contains `\.{\\global\\tabskip}', the - `\.{\\global}' token survives in the preamble and the `\.{\\tabskip}' defines - new tabskip glue (locally). - -*/ - -static void get_preamble_token(void) -{ - RESTART: - get_token(); - while ((cur_chr == span_code) && (cur_cmd == tab_mark_cmd)) { - /*tex This token will be expanded once. */ - get_token(); - if (cur_cmd > max_command_cmd) { - expand(); - get_token(); - } - } - if (cur_cmd == endv_cmd) - fatal_error("(interwoven alignment preambles are not allowed)"); - if ((cur_cmd == assign_glue_cmd) - && (cur_chr == glue_base + tab_skip_code)) { - scan_optional_equals(); - scan_glue(glue_val_level); - if (global_defs_par > 0) - geq_define(glue_base + tab_skip_code, glue_ref_cmd, cur_val); - else - eq_define(glue_base + tab_skip_code, glue_ref_cmd, cur_val); - goto RESTART; - } -} - -/*tex - - When \.{\\halign} or \.{\\valign} has been scanned in an appropriate mode, - \TeX\ calls |init_align|, whose task is to get everything off to a good - start. This mostly involves scanning the preamble and putting its information - into the preamble list. - -*/ - -void init_align(void) -{ - /*tex |warning_index| value for error messages */ - pointer save_cs_ptr; - /*tex for short-term temporary use */ - pointer p, r; - /*tex \.{\\halign} or \.{\\valign}, usually */ - save_cs_ptr = cur_cs; - push_alignment(); - /*tex enter a new alignment level */ - align_state = -1000000; - /*tex - - When \.{\\halign} is used as a displayed formula, there should be no - other pieces of mlists present. - - */ - if ((cur_list.mode_field == mmode) && ((cur_list.tail_field != cur_list.head_field) || (incompleat_noad_par != null))) { - const char *hlp[] = { - "Displays can use special alignments (like \\eqalignno)", - "only if nothing but the alignment itself is between $$'s.", - "So I've deleted the formulas that preceded this alignment.", - NULL - }; - tex_error("Improper \\halign inside $$'s", hlp); - flush_math(); - } - /*tex Enter a new semantic level. */ - push_nest(); - /*tex - - In vertical modes, |prev_depth| already has the correct value. But if we - are in |mmode| (displayed formula mode), we reach out to the enclosing - vertical mode for the |prev_depth| value that produces the correct - baseline calculations. - */ - if (cur_list.mode_field == mmode) { - cur_list.mode_field = -vmode; - prev_depth_par = nest[nest_ptr - 2].prev_depth_field; - } else if (cur_list.mode_field > 0) { - cur_list.mode_field = -(cur_list.mode_field); - } - scan_spec(align_group); - /*tex Scan the preamble. */ - preamble = null; - cur_align = align_head; - cur_loop = null; - scanner_status = aligning; - warning_index = save_cs_ptr; - align_state = -1000000; - /*tex At this point, |cur_cmd=left_brace|. */ - while (true) { - /*tex Append the current tabskip glue to the preamble list. */ - r = new_param_glue(tab_skip_code); - vlink(cur_align) = r; - cur_align = vlink(cur_align); - if (cur_cmd == car_ret_cmd) { - /*tex \.{\\cr} ends the preamble. */ - break; - } - /*tex - - Scan preamble text until |cur_cmd| is |tab_mark| or |car_ret| and - then scan the template \<u_j>, putting the resulting token list in - |hold_token_head|. Spaces are eliminated from the beginning of a - template. - - */ - p = hold_token_head; - token_link(p) = null; - while (1) { - get_preamble_token(); - if (cur_cmd == mac_param_cmd) - break; - if ((cur_cmd <= car_ret_cmd) && (cur_cmd >= tab_mark_cmd) - && (align_state == -1000000)) { - if ((p == hold_token_head) && (cur_loop == null) && (cur_cmd == tab_mark_cmd)) { - cur_loop = cur_align; - } else { - const char *hlp[] = { - "There should be exactly one # between &'s, when an", - "\\halign or \\valign is being set up. In this case you had", - "none, so I've put one in; maybe that will work.", - NULL - }; - back_input(); - tex_error("Missing # inserted in alignment preamble", hlp); - break; - } - } else if ((cur_cmd != spacer_cmd) || (p != hold_token_head)) { - r = get_avail(); - token_link(p) = r; - p = token_link(p); - token_info(p) = cur_tok; - } - } - r = new_node(align_record_node, 0); - vlink(cur_align) = r; - /*tex A new align record: */ - cur_align = vlink(cur_align); - span_ptr(cur_align) = end_span; - width(cur_align) = null_flag; - u_part(cur_align) = token_link(hold_token_head); - /*tex - - Scan the template \<v_j>, putting the resulting token list in - |hold_token_head|. - - */ - p = hold_token_head; - token_link(p) = null; - while (1) { - CONTINUE: - get_preamble_token(); - if ((cur_cmd <= car_ret_cmd) && (cur_cmd >= tab_mark_cmd) && (align_state == -1000000)) - break; - if (cur_cmd == mac_param_cmd) { - const char *hlp[] = { - "There should be exactly one # between &'s, when an", - "\\halign or \\valign is being set up. In this case you had", - "more than one, so I'm ignoring all but the first.", - NULL - }; - tex_error("Only one # is allowed per tab", hlp); - goto CONTINUE; - } - r = get_avail(); - token_link(p) = r; - p = token_link(p); - token_info(p) = cur_tok; - } - r = get_avail(); - token_link(p) = r; - p = token_link(p); - /*tex Put \.{\\endtemplate} at the end: */ - token_info(p) = end_template_token; - v_part(cur_align) = token_link(hold_token_head); - } - scanner_status = normal; - new_save_level(align_group); - if (every_cr_par != null) - begin_token_list(every_cr_par, every_cr_text); - /*tex Look for \.{\\noalign} or \.{\\omit}. */ - align_peek(); -} - -/*tex - - The tricky part about alignments is getting the templates into the scanner at - the right time, and recovering control when a row or column is finished. - - We usually begin a row after each \.{\\cr} has been sensed, unless that - \.{\\cr} is followed by \.{\\noalign} or by the right brace that terminates - the alignment. The |align_peek| routine is used to look ahead and do the - right thing; it either gets a new row started, or gets a \.{\\noalign} - started, or finishes off the alignment. - -*/ - -void align_peek(void) -{ - RESTART: - align_state = 1000000; - do { - get_x_or_protected(); - } while (cur_cmd == spacer_cmd); - if (cur_cmd == no_align_cmd) { - scan_left_brace(); - new_save_level(no_align_group); - if (cur_list.mode_field == -vmode) - normal_paragraph(); - } else if (cur_cmd == right_brace_cmd) { - fin_align(); - } else if ((cur_cmd == car_ret_cmd) && (cur_chr == cr_cr_code)) { - /*tex Ignore \.{\\crcr}. */ - goto RESTART; - } else { - /*tex Start a new row. */ - init_row(); - /*tex Start a new column and replace what we peeked at. */ - init_col(); - } -} - - -/*tex - - The parameter to |init_span| is a pointer to the alignrecord where the next - column or group of columns will begin. A new semantic level is entered, so - that the columns will generate a list for subsequent packaging. - -*/ - -static void init_span(pointer p) -{ - push_nest(); - if (cur_list.mode_field == -hmode) { - space_factor_par = 1000; - } else { - prev_depth_par = ignore_depth; - normal_paragraph(); - } - cur_span = p; -} - -/*tex - - To start a row (i.e., a `row' that rhymes with `dough' but not with `bough'), - we enter a new semantic level, copy the first tabskip glue, and change from - internal vertical mode to restricted horizontal mode or vice versa. The - |space_factor| and |prev_depth| are not used on this semantic level, but we - clear them to zero just to be tidy. - -*/ - -void init_row(void) -{ - push_nest(); - cur_list.mode_field = (-hmode - vmode) - cur_list.mode_field; - if (cur_list.mode_field == -hmode) - space_factor_par = 0; - else - prev_depth_par = 0; - tail_append(new_glue(preamble)); - subtype(cur_list.tail_field) = tab_skip_code + 1; - cur_align = vlink(preamble); - cur_tail = cur_head; - cur_pre_tail = cur_pre_head; - init_span(cur_align); -} - -/*tex - - When a column begins, we assume that |cur_cmd| is either |omit| or else the - current token should be put back into the input until the \<u_j> template has - been scanned. (Note that |cur_cmd| might be |tab_mark| or |car_ret|.) We also - assume that |align_state| is approximately 1000000 at this time. We remain in - the same mode, and start the template if it is called for. - -*/ - -void init_col(void) -{ - extra_info(cur_align) = cur_cmd; - if (cur_cmd == omit_cmd) - align_state = 0; - else { - back_input(); - begin_token_list(u_part(cur_align), u_template); - } - /*tex now |align_state=1000000| */ -} - - -/*tex - - The scanner sets |align_state| to zero when the \<u_j> template ends. When a - subsequent \.{\\cr} or \.{\\span} or tab mark occurs with |align_state=0|, - the scanner activates the following code, which fires up the \<v_j> template. - We need to remember the |cur_chr|, which is either |cr_cr_code|, |cr_code|, - |span_code|, or a character code, depending on how the column text has ended. - - This part of the program had better not be activated when the preamble to - another alignment is being scanned, or when no alignment preamble is active. - -*/ - -void insert_vj_template(void) -{ - if ((scanner_status == aligning) || (cur_align == null)) - fatal_error("(interwoven alignment preambles are not allowed)"); - cur_cmd = extra_info(cur_align); - extra_info(cur_align) = cur_chr; - if (cur_cmd == omit_cmd) - begin_token_list(omit_template, v_template); - else - begin_token_list(v_part(cur_align), v_template); - align_state = 1000000; -} - -/*tex Determine the stretch order */ - -#define determine_stretch_order() do { \ - if (total_stretch[filll]!= 0) o = filll; \ - else if (total_stretch[fill] != 0) o = fill; \ - else if (total_stretch[fil] != 0) o = fil; \ - else if (total_stretch[sfi] != 0) o = sfi; \ - else o=normal; \ -} while (0) - -/*tex Determine the shrink order */ - -#define determine_shrink_order() do { \ - if (total_shrink[filll] != 0) o = filll; \ - else if (total_shrink[fill] != 0) o = fill; \ - else if (total_shrink[fil] != 0) o = fil; \ - else if (total_shrink[sfi] != 0) o = sfi; \ - else o=normal; \ -} while (0) - -/*tex - - When the |endv| command at the end of a \<v_j> template comes through the - scanner, things really start to happen; and it is the |fin_col| routine that - makes them happen. This routine returns |true| if a row as well as a column - has been finished. - -*/ - -boolean fin_col(void) -{ - /*tex the alignrecord after the current one */ - pointer p; - /*tex temporary pointers for list manipulation */ - pointer q, r; - /*tex a new span node */ - pointer s; - /*tex a new unset box */ - pointer u; - /*tex natural width */ - scaled w; - /*tex order of infinity */ - unsigned char o; - /*tex span counter */ - halfword n; - if (cur_align == null) - confusion("endv"); - q = vlink(cur_align); - if (q == null) - confusion("endv"); - if (align_state < 500000) - fatal_error("(interwoven alignment preambles are not allowed)"); - p = vlink(q); - /*tex If the preamble list has been traversed, check that the row has ended. */ - if ((p == null) && (extra_info(cur_align) < cr_code)) { - if (cur_loop != null) { - /*tex Lengthen the preamble periodically: */ - r = new_node(align_record_node, 0); - vlink(q) = r; - /*tex A new align record: */ - p = vlink(q); - span_ptr(p) = end_span; - width(p) = null_flag; - cur_loop = vlink(cur_loop); - /*tex Copy the templates from node |cur_loop| into node |p|. */ - q = hold_token_head; - r = u_part(cur_loop); - while (r != null) { - s = get_avail(); - token_link(q) = s; - q = token_link(q); - token_info(q) = token_info(r); - r = token_link(r); - } - token_link(q) = null; - u_part(p) = token_link(hold_token_head); - q = hold_token_head; - r = v_part(cur_loop); - while (r != null) { - s = get_avail(); - token_link(q) = s; - q = token_link(q); - token_info(q) = token_info(r); - r = token_link(r); - } - token_link(q) = null; - v_part(p) = token_link(hold_token_head); - cur_loop = vlink(cur_loop); - r = new_glue(cur_loop); - vlink(p) = r; - } else { - const char *hlp[] = { - "You have given more \\span or & marks than there were", - "in the preamble to the \\halign or \\valign now in progress.", - "So I'll assume that you meant to type \\cr instead.", - NULL - }; - extra_info(cur_align) = cr_code; - tex_error("Extra alignment tab has been changed to \\cr", hlp); - } - } - if (extra_info(cur_align) != span_code) { - unsave(); - new_save_level(align_group); - /*tex Package an unset box for the current column and record its width. */ - if (cur_list.mode_field == -hmode) { - adjust_tail = cur_tail; - pre_adjust_tail = cur_pre_tail; - u = filtered_hpack(cur_list.head_field, cur_list.tail_field, 0, additional, align_set_group, -1, 0, 0); - w = width(u); - cur_tail = adjust_tail; - adjust_tail = null; - cur_pre_tail = pre_adjust_tail; - pre_adjust_tail = null; - } else { - u = filtered_vpackage(vlink(cur_list.head_field), 0, additional, 0, align_set_group, -1, 0, 0); - w = height(u); - } - /*tex This represents a span count of 1: */ - n = min_quarterword; - if (cur_span != cur_align) { - /*tex Update width entry for spanned columns. */ - q = cur_span; - do { - incr(n); - q = vlink(vlink(q)); - } while (q != cur_align); - if (n > max_quarterword) { - /*tex This can happen, but won't. */ - confusion("too many spans"); - } - q = cur_span; - while (span_span(span_ptr(q)) < n) { - q = span_ptr(q); - } - if (span_span(span_ptr(q)) > n) { - s = new_span_node(span_ptr(q), n, w); - span_ptr(q) = s; - } else if (width(span_ptr(q)) < w) { - width(span_ptr(q)) = w; - } - } else if (w > width(cur_align)) { - width(cur_align) = w; - } - type(u) = unset_node; - span_count(u) = (quarterword) n; - determine_stretch_order(); - glue_order(u) = o; - glue_stretch(u) = total_stretch[o]; - determine_shrink_order(); - glue_sign(u) = o; - glue_shrink(u) = total_shrink[o]; - pop_nest(); - vlink(cur_list.tail_field) = u; - cur_list.tail_field = u; - /*tex Copy the tabskip glue between columns. */ - tail_append(new_glue(vlink(cur_align))); - subtype(cur_list.tail_field) = tab_skip_code + 1; - if (extra_info(cur_align) >= cr_code) { - return true; - } - init_span(p); - } - align_state = 1000000; - do { - get_x_or_protected(); - } while (cur_cmd == spacer_cmd); - cur_align = p; - init_col(); - return false; -} - -/*tex - - A span node is a 3-word record containing |width|, |span_span|, and - |span_ptr| fields. The |span_span| field indicates the number of spanned - columns; the |span_ptr| field points to a span node for the same starting - column, having a greater extent of spanning, or to |end_span|, which has the - largest possible |span_span| field; the |width| field holds the largest - natural width corresponding to a particular set of spanned columns. - - A list of the maximum widths so far, for spanned columns starting at a given - column, begins with the |span_ptr| field of the alignrecord for that column. - The code has to make sure that there is room for |span_ptr| in both the - alignrecord and the span nodes, which is why |span_ptr| replaces |node_attr|. - - The |new_span_node| function is defined in |texnodes.c|. - -*/ - -/*tex This is normally |alink|: */ - -#ifndef span_span -# define span_span(A) vlink((A)+1) -#endif - -/*tex - - At the end of a row, we append an unset box to the current vlist (for - \.{\\halign}) or the current hlist (for \.{\\valign}). This unset box - contains the unset boxes for the columns, separated by the tabskip glue. - Everything will be set later. - -*/ - -void fin_row(void) -{ - /*tex The new unset box: */ - pointer p; - if (cur_list.mode_field == -hmode) { - p = filtered_hpack(cur_list.head_field, cur_list.tail_field, 0, - additional, fin_row_group, -1, 0, 0); - pop_nest(); - if (cur_pre_head != cur_pre_tail) - append_list(cur_pre_head, cur_pre_tail); - append_to_vlist(p,lua_key_index(alignment)); - if (cur_head != cur_tail) - append_list(cur_head, cur_tail); - } else { - p = filtered_vpackage(vlink(cur_list.head_field), - 0, additional, max_depth_par, fin_row_group, -1, 0, 0); - pop_nest(); - vlink(cur_list.tail_field) = p; - cur_list.tail_field = p; - space_factor_par = 1000; - } - type(p) = unset_node; - glue_stretch(p) = 0; - if (every_cr_par != null) - begin_token_list(every_cr_par, every_cr_text); - align_peek(); - /*tex Note that |glue_shrink(p)=0| since |glue_shrink==shift_amount|. */ -} - -/*tex - - Finally, we will reach the end of the alignment, and we can breathe a sigh of - relief that memory hasn't overflowed. All the unset boxes will now be set so - that the columns line up, taking due account of spanned columns. - -*/ - -void fin_align(void) -{ - /*tex registers for the list operations */ - pointer p, q, r, s, u, rr; - /*tex width of column */ - scaled t, w; - /*tex shift offset for unset boxes */ - scaled o; - /*tex matching span amount */ - halfword n; - /*tex temporary storage for |overfull_rule| */ - scaled rule_save; - /*tex temporary storage for |prev_depth| */ - halfword pd; - /*tex temporary storage for |new_glue| */ - halfword ng; - /*tex The |align_group| was for individual entries: */ - if (cur_group != align_group) - confusion("align1"); - unsave(); - /*tex The |align_group| was for the whole alignment: */ - if (cur_group != align_group) - confusion("align0"); - unsave(); - if (nest[nest_ptr - 1].mode_field == mmode) { - o = display_indent_par; - } else { - o = 0; - } - /*tex - - Go through the preamble list, determining the column widths and - changing the alignrecords to dummy unset boxes. - - It's time now to dismantle the preamble list and to compute the - column widths. Let $w_{ij}$ be the maximum of the natural widths of - all entries that span columns $i$ through $j$, inclusive. The - alignrecord for column~$i$ contains $w_{ii}$ in its |width| field, - and there is also a linked list of the nonzero $w_{ij}$ for - increasing $j$, accessible via the |info| field; these span nodes - contain the value $j-i+|min_quarterword|$ in their |link| fields. The - values of $w_{ii}$ were initialized to |null_flag|, which we regard - as $-\infty$. - - The final column widths are defined by the formula $$w_j=\max_{1\L - i\L j}\biggl( w_{ij}-\sum_{i\L k<j}(t_k+w_k)\biggr),$$ where $t_k$ is - the natural width of the tabskip glue between columns $k$ and~$k+1$. - However, if $w_{ij}=-\infty$ for all |i| in the range |1<=i<=j| - (i.e., if every entry that involved column~|j| also involved - column~|j+1|), we let $w_j=0$, and we zero out the tabskip glue after - column~|j|. - - \TeX\ computes these values by using the following scheme: First - $w_1=w_{11}$. Then replace $w_{2j}$ by $\max(w_{2j},w_{1j}-t_1-w_1)$, - for all $j>1$. Then $w_2=w_{22}$. Then replace $w_{3j}$ by - $\max(w_{3j},w_{2j}-t_2-w_2)$ for all $j>2$; and so on. If any $w_j$ - turns out to be $-\infty$, its value is changed to zero and so is the - next tabskip. - - */ - q = vlink(preamble); - do { - flush_list(u_part(q)); - flush_list(v_part(q)); - p = vlink(vlink(q)); - if (width(q) == null_flag) { - /*tex Nullify |width(q)| and the tabskip glue following this column. */ - width(q) = 0; - r = vlink(q); - reset_glue_to_zero(r); - } - if (span_ptr(q) != end_span) { - /*tex - - Merge the widths in the span nodes of |q| with those of |p|, - destroying the span nodes of |q|. - - Merging of two span-node lists is a typical exercise in the - manipulation of linearly linked data structures. The essential - invariant in the following |repeat| loop is that we want to - dispense with node |r|, in |q|'s list, and |u| is its successor; - all nodes of |p|'s list up to and including |s| have been - processed, and the successor of |s| matches |r| or precedes |r| - or follows |r|, according as |link(r)=n| or |link(r)>n| or - |link(r)<n|. - - */ - t = width(q) + width(vlink(q)); - r = span_ptr(q); - s = end_span; - span_ptr(s) = p; - n = min_quarterword + 1; - do { - width(r) = width(r) - t; - u = span_ptr(r); - while (span_span(r) > n) { - s = span_ptr(s); - n = span_span(span_ptr(s)) + 1; - } - if (span_span(r) < n) { - span_ptr(r) = span_ptr(s); - span_ptr(s) = r; - decr(span_span(r)); - s = r; - } else { - if (width(r) > width(span_ptr(s))) - width(span_ptr(s)) = width(r); - flush_node(r); - } - r = u; - } while (r != end_span); - } - type(q) = unset_node; - span_count(q) = min_quarterword; - height(q) = 0; - depth(q) = 0; - glue_order(q) = normal; - glue_sign(q) = normal; - glue_stretch(q) = 0; - glue_shrink(q) = 0; - q = p; - } while (q != null); - /*tex - - Package the preamble list, to determine the actual tabskip glue amounts, - and let |p| point to this prototype box. - - Now the preamble list has been converted to a list of alternating unset - boxes and tabskip glue, where the box widths are equal to the final - column sizes. In case of \.{\\valign}, we change the widths to heights, - so that a correct error message will be produced if the alignment is - overfull or underfull. - - */ - decr(save_ptr); - pack_begin_line = -cur_list.ml_field; - if (cur_list.mode_field == -vmode) { - rule_save = overfull_rule_par; - /*tex Prevent the rule from being packaged. */ - overfull_rule_par = 0; - p = hpack(preamble, saved_value(0), saved_level(0), -1); - overfull_rule_par = rule_save; - } else { - q = vlink(preamble); - do { - height(q) = width(q); - width(q) = 0; - q = vlink(vlink(q)); - } while (q != null); - p = filtered_vpackage(preamble, - saved_value(0), saved_level(0), max_depth_par, preamble_group, -1, 0, 0); - q = vlink(preamble); - do { - width(q) = height(q); - height(q) = 0; - q = vlink(vlink(q)); - } while (q != null); - } - pack_begin_line = 0; - /*tex Set the glue in all the unset boxes of the current list. */ - q = vlink(cur_list.head_field); - s = cur_list.head_field; - while (q != null) { - if (!is_char_node(q)) { - if (type(q) == unset_node) { - /*tex - - We set the unset box |q| and the unset boxes in it. The unset - box |q| represents a row that contains one or more unset - boxes, depending on how soon \.{\\cr} occurred in that row. - - */ - if (cur_list.mode_field == -vmode) { - type(q) = hlist_node; - subtype(q) = align_row_list; - width(q) = width(p); - } else { - type(q) = vlist_node; - subtype(q) = align_row_list; - height(q) = height(p); - } - glue_order(q) = glue_order(p); - glue_sign(q) = glue_sign(p); - glue_set(q) = glue_set(p); - shift_amount(q) = o; - r = vlink(list_ptr(q)); - if (type(r) != unset_node) { - formatted_error("alignment","bad box"); - } - s = vlink(list_ptr(p)); - do { - /*tex - - We set the glue in node |r| and change it from an unset - node. A box made from spanned columns will be followed by - tabskip glue nodes and by empty boxes as if there were no - spanning. This permits perfect alignment of subsequent - entries, and it prevents values that depend on floating - point arithmetic from entering into the dimensions of any - boxes. - - */ - n = span_count(r); - t = width(s); - w = t; - u = hold_head; - while (n > min_quarterword) { - decr(n); - /*tex - - Append tabskip glue and an empty box to list |u|, and - update |s| and |t| as the prototype nodes are passed. - - */ - s = vlink(s); - ng = new_glue(s); - vlink(u) = ng; - u = vlink(u); - subtype(u) = tab_skip_code + 1; - t = t + width(s); - if (glue_sign(p) == stretching) { - if (stretch_order(s) == glue_order(p)) - t = t + round(float_cast(glue_set(p)) * float_cast(stretch(s))); - } else if (glue_sign(p) == shrinking) { - if (shrink_order(s) == glue_order(p)) - t = t - round(float_cast(glue_set(p)) * float_cast(shrink(s))); - } - s = vlink(s); - rr = new_null_box(); - vlink(u) = rr; - u = vlink(u); - t = t + width(s); - subtype(u) = align_cell_list; - if (cur_list.mode_field == -vmode) { - width(u) = width(s); - } else { - type(u) = vlist_node; - height(u) = width(s); - } - } - if (cur_list.mode_field == -vmode) { - /*tex - - Make the unset node |r| into an |hlist_node| of width - |w|, setting the glue as if the width were |t|. - - */ - height(r) = height(q); - depth(r) = depth(q); - if (t == width(r)) { - glue_sign(r) = normal; - glue_order(r) = normal; - set_glue_ratio_zero(glue_set(r)); - } else if (t > width(r)) { - glue_sign(r) = stretching; - if (glue_stretch(r) == 0) - set_glue_ratio_zero(glue_set(r)); - else - glue_set(r) = unfloat((double) (t - width(r)) / glue_stretch(r)); - } else { - glue_order(r) = glue_sign(r); - glue_sign(r) = shrinking; - if (glue_shrink(r) == 0) - set_glue_ratio_zero(glue_set(r)); - else if ((glue_order(r) == normal) && (width(r) - t > glue_shrink(r))) - set_glue_ratio_one(glue_set(r)); - else - glue_set(r) = unfloat((double) (width(r) - t) / glue_shrink(r)); - } - width(r) = w; - type(r) = hlist_node; - subtype(r) = align_cell_list; - - } else { - /*tex - - Make the unset node |r| into a |vlist_node| of height - |w|, setting the glue as if the height were |t|. - - */ - width(r) = width(q); - if (t == height(r)) { - glue_sign(r) = normal; - glue_order(r) = normal; - set_glue_ratio_zero(glue_set(r)); - } else if (t > height(r)) { - glue_sign(r) = stretching; - if (glue_stretch(r) == 0) - set_glue_ratio_zero(glue_set(r)); - else - glue_set(r) = unfloat((t - height(r)) / glue_stretch(r)); - } else { - glue_order(r) = glue_sign(r); - glue_sign(r) = shrinking; - if (glue_shrink(r) == 0) - set_glue_ratio_zero(glue_set(r)); - else if ((glue_order(r) == normal) && (height(r) - t > glue_shrink(r))) - set_glue_ratio_one(glue_set(r)); - else - glue_set(r) = unfloat((height(r) - t) / glue_shrink(r)); - } - height(r) = w; - type(r) = vlist_node; - subtype(r) = align_cell_list; - } - shift_amount(r) = 0; - if (u != hold_head) { - /*tex Append blank boxes to account for spanned nodes. */ - vlink(u) = vlink(r); - vlink(r) = vlink(hold_head); - r = u; - } - - r = vlink(vlink(r)); - s = vlink(vlink(s)); - } while (r != null); - - } else if (type(q) == rule_node) { - /*tex - - Make the running dimensions in rule |q| extend to the - boundaries of the alignment. - - */ - if (is_running(width(q))) - width(q) = width(p); - if (is_running(height(q))) - height(q) = height(p); - if (is_running(depth(q))) - depth(q) = depth(p); - if (o != 0) { - r = vlink(q); - vlink(q) = null; - q = hpack(q, 0, additional, -1); - shift_amount(q) = o; - subtype(q) = align_cell_list; - vlink(q) = r; - vlink(s) = q; - } - } - } - s = q; - q = vlink(q); - } - flush_node_list(p); - pop_alignment(); - /*tex - - We now have a completed alignment, in the list that starts at - |cur_list.head_field| and ends at |cur_list.tail_field|. This list will - be merged with the one that encloses it. (In case the enclosing mode is - |mmode|, for displayed formulas, we will need to insert glue before and - after the display; that part of the program will be deferred until we're - more familiar with such operations.) - - */ - pd = prev_depth_par; - p = vlink(cur_list.head_field); - q = cur_list.tail_field; - pop_nest(); - if (cur_list.mode_field == mmode) { - finish_display_alignment(p, q, pd); - } else { - prev_depth_par = pd; - vlink(cur_list.tail_field) = p; - if (p != null) - cur_list.tail_field = q; - if (cur_list.mode_field == vmode) { - if (!output_active) - lua_node_filter_s(buildpage_filter_callback,lua_key_index(alignment)); - build_page(); - } - } -} - -/*tex - - The token list |omit_template| just referred to is a constant token list that - contains the special control sequence \.{\\endtemplate} only. - -*/ - -void initialize_alignments(void) -{ - token_info(omit_template) = end_template_token; - span_span(end_span) = max_quarterword + 1; - span_ptr(end_span) = null; -} |