diff options
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/luatex.web')
-rw-r--r-- | Build/source/texk/web2c/luatexdir/luatex.web | 11219 |
1 files changed, 3651 insertions, 7568 deletions
diff --git a/Build/source/texk/web2c/luatexdir/luatex.web b/Build/source/texk/web2c/luatexdir/luatex.web index 5bd87dd7b96..df2a5372c85 100644 --- a/Build/source/texk/web2c/luatexdir/luatex.web +++ b/Build/source/texk/web2c/luatexdir/luatex.web @@ -1,19 +1,24 @@ -% Copyright (c) 2007 Hartmut Henkel, Taco Hoekwater - -% 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 General Public License for more details. - -% You should have received a copy of the GNU General Public License -% along with luaTeX; if not, write to the Free Software Foundation, Inc., -% 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +% luatex.web +% +% Copyright 2006-2009 Taco Hoekwater <taco@@luatex.org> +% Copyright 2006-2009 Hartmut Henkel <hartmut@@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/>. +% +% $Id$ % pdfTeX is copyright (C) 1996-2006 Han The Thanh, <thanh@@pdftex.org>. % e-TeX is copyright (C) 1994,98 by Peter Breitenlohner. @@ -62,9 +67,10 @@ % Version 3.1415 preserved nonexplicit kerns, tidied up (February 1993). % Version 3.14159 allowed fontmemsize to change; bulletproofing (March 1995). % Version 3.141592 fixed \xleaders, glueset, weird alignments (December 2002). +% Version 3.1415926 was a general cleanup with minor fixes (February 2008). -% Although considerable effort has been expended to make the luaTeX program +% Although considerable effort has been expended to make the LuaTeX program % correct and reliable, no warranty is implied; the authors disclaim any % obligation or liability for damages, including but not limited to % special, indirect, or consequential damages arising out of or in @@ -177,6 +183,7 @@ complete version of \TeX\ was designed and coded by the author in late {\mc SAIL} language, for which an excellent debugging system was available. Preliminary plans to convert the {\mc SAIL} code into a form somewhat like the present ``web'' were developed by Luis Trabb~Pardo and +@^Trabb Pardo, Luis Isidoro@> the author at the beginning of 1979, and a complete implementation was created by Ignacio~A. Zabala in 1979 and 1980. The \TeX82 program, which @^Zabala Salelles, Ignacio Andr\'es@> @@ -242,15 +249,16 @@ known as `\eTeX'. @d pdftex_revision=="0" { \.{\\pdftexrevision} } @d pdftex_version_string=='-2.00.0' {current \pdfTeX\ version} @# -@d luatex_version==25 { \.{\\luatexversion} } -@d luatex_revision=="4" { \.{\\luatexrevision} } -@d luatex_version_string=='snapshot-0.25.4' {current \LuaTeX\ version} +@d luatex_version==37 { \.{\\luatexversion} } +@d luatex_revision=="0" { \.{\\luatexrevision} } +@d luatex_version_string=='snapshot-0.37.0' {current \LuaTeX\ version} @d luatex_date_info==-extra_version_info { the compile date is negated } +@d luatex_svnversion==SVN_REV { as proposed by Peter M\"unster } @# -@d luaTeX_banner=='This is LuaTeX, Version ',luatex_version_string,extra_version_info +@d LuaTeX_banner=='This is LuaTeX, Version ',luatex_version_string,extra_version_info {printed when \LuaTeX\ starts} @# -@d banner==luaTeX_banner +@d banner==LuaTeX_banner @# @d TEX==ETEX {change program name into |ETEX|} @@ -307,6 +315,7 @@ portions of the program heading. Actually the heading shown here is not quite normal: The |program| line does not mention any |output| file, because \ph\ would ask the \TeX\ user to specify a file name if |output| were specified here. +@:PASCAL H}{\ph@> @^system dependencies@> @d mtype==t@&y@&p@&e {this is a \.{WEB} coding trick:} @@ -327,6 +336,44 @@ procedure initialize; {this procedure gets things started properly} @t\4@>@<Basic printing procedures@>@/ @t\4@>@<Error handling procedures@>@/ +@ Here is a workaround for the unfortunate limitation of WEB2C that +doesn't know how to deal with symbolic case labels. + +@d hlist_node_case==0 +@d vlist_node_case==1 +@d rule_node_case==2 +@d ins_node_case==3 +@d mark_node_case==4 +@d adjust_node_case==5 +@d disc_node_case==7 +@d whatsit_node_case==8 +@d math_node_case==9 +@d glue_node_case==10 +@d kern_node_case==11 +@d penalty_node_case==12 +@d unset_node_case==13 +@d margin_kern_node_case==36 + +@<Initialize whatever \TeX\ might access@>= +pdfassert(hlist_node_case=hlist_node); +pdfassert(vlist_node_case=vlist_node); +pdfassert(rule_node_case=rule_node); +pdfassert(ins_node_case=ins_node); +pdfassert(mark_node_case=mark_node); +pdfassert(adjust_node_case=adjust_node); +pdfassert(disc_node_case=disc_node); +pdfassert(whatsit_node_case=whatsit_node); +pdfassert(math_node_case=math_node); +pdfassert(glue_node_case=glue_node); +pdfassert(kern_node_case=kern_node); +pdfassert(penalty_node_case=penalty_node); +pdfassert(unset_node_case=unset_node); +pdfassert(margin_kern_node_case=margin_kern_node); + + + + + @ The overall \TeX\ program begins with the heading just shown, after which comes a bunch of procedure declarations and function declarations. Finally we will get to the main program, which begins with the @@ -399,8 +446,9 @@ directives shown below specify full checking and inclusion of the \PASCAL\ debugger when \TeX\ is being debugged, but they cause range checking and other redundant code to be eliminated when the production system is being generated. Arithmetic overflow will be detected in all cases. +@:PASCAL H}{\ph@> @^system dependencies@> -@^Overflow in arithmetic@> +@^overflow in arithmetic@> @<Compiler directives@>= @{@&$C-,A+,D-@} {no range check, catch arithmetic overflow, no debug overhead} @@ -434,6 +482,7 @@ if the compiler wants one. (Of course, if no default mechanism is available, the |case| statements of \TeX\ will have to be laboriously extended by listing all remaining cases. People who are stuck with such \PASCAL s have, in fact, done this, successfully but not happily!) +@:PASCAL H}{\ph@> @d othercases == others: {default for cases not listed explicitly} @d endcases == @+end {follows the default case in an extended |case| statement} @@ -492,9 +541,8 @@ emphasize this distinction. @d font_base=0 {smallest internal font number; must not be less than |min_quarterword|} -@d hash_size=2100 {maximum number of control sequences; it should be at most +@d hash_size=65536 {maximum number of control sequences; it should be at most about |(fix_mem_max-fix_mem_min)/10|} -@d hash_prime=1777 {a prime number equal to about 85\pct! of |hash_size|} @d ocp_base=0 {smallest internal ocp number; must not be less than |min_quarterword|} @d ocp_biggest=32767 {the real biggest ocp} @@ -515,17 +563,14 @@ emphasize this distinction. @d too_big_char=1114112 {2097152} {|biggest_char+1|} @d special_char=1114113 {2097153} {|biggest_char+2|} @d number_chars=1114112 {2097152} {|biggest_char+1|} -@d number_active_chars=65536+65536 {to reduce the memory req. only two planes } @d string_offset=2097152 @d font_biggest=5535 {the real biggest font} @d number_fonts=font_biggest-font_base+1 -@d number_math_fonts=768 -@d math_font_biggest=767 @d biggest_lang=32767 @d too_big_lang=32768 @d text_size=0 {size code for the largest size in a family} -@d script_size=256 {size code for the medium size in a family} -@d script_script_size=512 {size code for the smallest size in a family} +@d script_size=1 {size code for the medium size in a family} +@d script_script_size=2 {size code for the smallest size in a family} @ In case somebody has inadvertently made bad settings of the ``constants,'' @@ -1022,13 +1067,13 @@ begin if (test)and(fnam<>0)and(length(fnam)>0) then begin @<Fixup |nameoffile| after callback@>; lua_a_open_out := do_a_open_out(f); - name_file_pointer := f; + name_file_pointer := f; end else lua_a_open_out := false; end else begin - if openoutnameok(stringcast(nameoffile+1)) then begin + if openoutnameok(stringcast(nameoffile+1)) then begin lua_a_open_out := a_open_out(f); name_file_pointer := f; end @@ -1050,13 +1095,13 @@ begin if (test)and(fnam<>0)and(length(fnam)>0) then begin @<Fixup |nameoffile| after callback@>; lua_b_open_out := do_b_open_out(f); - name_file_pointer := f; + name_file_pointer := f; end else lua_b_open_out := false; end else begin - if openoutnameok(stringcast(nameoffile+1)) then begin + if openoutnameok(stringcast(nameoffile+1)) then begin lua_b_open_out := b_open_out(f); name_file_pointer := f; end @@ -1076,6 +1121,7 @@ namelength := length(fnam); flush_string @ Files can be closed with the \ph\ routine `|close(f)|', which +@:PASCAL H}{\ph@> @^system dependencies@> should be used when all input or output with respect to |f| has been completed. This makes |f| available to be opened again, if desired; and if |f| was used for @@ -1210,9 +1256,9 @@ end; function lua_input_ln(var f:alpha_file;n:quarterword;@!bypass_eoln:boolean):boolean; var lua_result:boolean; - last_ptr:integer; + last_ptr:integer; callback_id:integer; - bypass_p:boolean; + bypass_p:boolean; begin if n=0 then callback_id:=input_file_callback_id[index] @@ -1220,12 +1266,12 @@ else callback_id:=read_file_callback_id[n]; if callback_id>0 then begin last:=first; - last_ptr := first; + last_ptr := first; lua_result := run_saved_callback(callback_id,'reader','->l', addressof(last_ptr)); - if (lua_result=true)and(last_ptr<>0) then begin - last := last_ptr; - if last>max_buf_stack then max_buf_stack:=last; - lua_input_ln := true; + if (lua_result=true)and(last_ptr<>0) then begin + last := last_ptr; + if last>max_buf_stack then max_buf_stack:=last; + lua_input_ln := true; @<Fix up the input buffer using callbacks@>; end else @@ -1234,7 +1280,7 @@ if callback_id>0 then begin else begin bypass_p := bypass_eoln; {this is for -Wextra} lua_result := input_ln(f,bypass_p); - if lua_result=true then begin + if lua_result=true then begin lua_input_ln := true; @<Fix up the input buffer using callbacks@>; end @@ -1251,8 +1297,8 @@ if last>=first then begin last_ptr := first; lua_result := run_callback(callback_id, 'l->l', (last-first), addressof(last_ptr)); if (lua_result=true)and(last_ptr<>0) then begin - last := last_ptr; - if last>max_buf_stack then max_buf_stack:=last; + last := last_ptr; + if last>max_buf_stack then max_buf_stack:=last; end; end; end @@ -1271,6 +1317,7 @@ is considered an output file the file variable is |term_out|. @ Here is how to open the terminal files in \ph. The `\.{/I}' switch suppresses the first |get|. +@:PASCAL H}{\ph@> @^system dependencies@> @d t_open_in==reset(term_in,'TTY:','/O/I') {open the terminal for text input} @@ -1288,6 +1335,7 @@ issue an unexpected error message). The third, |wake_up_terminal|, is supposed to revive the terminal if the user has disabled it by some instruction to the operating system. The following macros show how these operations can be specified in \ph: +@:PASCAL H}{\ph@> @^system dependencies@> @d update_terminal == break(term_out) {empty the terminal output buffer} @@ -1416,6 +1464,7 @@ into some integer greater than~|biggest_char|. Some \PASCAL\ compilers won't pack integers into a single byte unless the integers lie in the range |-128..127|. To accommodate such systems we access the string pool only via macros that can easily be redefined. +@^system dependencies@> @d si(#) == # {convert from |ASCII_code| to |packed_ASCII_code|} @d so(#) == # {convert from |packed_ASCII_code| to |ASCII_code|} @@ -1466,12 +1515,12 @@ end @p procedure string_room(t:integer); begin - str_room(t); + str_room(t); end; @# procedure append_pool_char(c:ASCII_code); begin - append_char(c); + append_char(c); end; @@ -1514,37 +1563,37 @@ begin if b<@"80 then a := b else if b>=@"F0 then begin - a := (b-@"F0) * 64; - b := buffer[k+1]; - test_sequence_byte(b); - a := (a + (b-128)) * 64; - b := buffer[k+2]; - test_sequence_byte(b); - a := (a + (b-128)) * 64; - b := buffer[k+3]; - test_sequence_byte(b); - a := a + (b-128); + a := (b-@"F0) * 64; + b := buffer[k+1]; + test_sequence_byte(b); + a := (a + (b-128)) * 64; + b := buffer[k+2]; + test_sequence_byte(b); + a := (a + (b-128)) * 64; + b := buffer[k+3]; + test_sequence_byte(b); + a := a + (b-128); end else if b>=@"E0 then begin - a := (b-@"E0) * 64; - b := buffer[k+1]; - test_sequence_byte(b); - a := (a + (b-128)) * 64; - b := buffer[k+2]; - test_sequence_byte(b); - a := a + (b-128); + a := (b-@"E0) * 64; + b := buffer[k+1]; + test_sequence_byte(b); + a := (a + (b-128)) * 64; + b := buffer[k+2]; + test_sequence_byte(b); + a := a + (b-128); end else if b>=@"C0 then begin - a := (b-@"C0) * 64; - b := buffer[k+1]; - test_sequence_byte(b); - a := a + (b-128); + a := (b-@"C0) * 64; + b := buffer[k+1]; + test_sequence_byte(b); + a := a + (b-128); end else begin { NI: this is an encoding error } - print_err("Buffer contains an invalid utf-8 sequence"); + print_err("Buffer contains an invalid utf-8 sequence"); @.Text line contains...@> - help2("A funny symbol somehow ended up in the input buffer.")@/ - ("Just continue, I'll change it to 0xFFFD.");@/ + help2("A funny symbol somehow ended up in the input buffer.")@/ + ("Just continue, I'll change it to 0xFFFD.");@/ deletions_allowed:=false; error; deletions_allowed:=true; a:=@"FFFD; end; @@ -1601,7 +1650,7 @@ if s<string_offset then begin if length(t)=1 then if str_pool[str_start_macro(t)]=s then goto found; - a := pool_to_unichar(str_start_macro(t)); + a := pool_to_unichar(str_start_macro(t)); if a<>s then goto not_found; end else @@ -1675,8 +1724,8 @@ extended character set recommended in {\sl The \TeX book\/} would, for example, be `|k in [0,@'10..@'12,@'14,@'15,@'33,@'177..@'377]|'. If character |k| cannot be printed, and |k<@'200|, then character |k+@'100| or |k-@'100| must be printable; moreover, ASCII codes |[@'41..@'46, -@'60..@'71, @'141..@'146, @'160..@'171]| must be printable. -Thus, at least 80 printable characters are needed. +@'60..@'71, @'136, @'141..@'146, @'160..@'171]| must be printable. +Thus, at least 81 printable characters are needed. @:TeXbook}{\sl The \TeX book@> @^character set dependencies@> @^system dependencies@> @@ -1878,32 +1927,32 @@ begin if b<=@"7F then a := b else if b>=@"F0 then begin - a := (b-@"F0) * 64; - b := str_pool[t+1]; - a := (a + (b-128)) * 64; - b := str_pool[t+2]; - a := (a + (b-128)) * 64; - b := str_pool[t+3]; - a := a + (b-128); + a := (b-@"F0) * 64; + b := str_pool[t+1]; + a := (a + (b-128)) * 64; + b := str_pool[t+2]; + a := (a + (b-128)) * 64; + b := str_pool[t+3]; + a := a + (b-128); end else if b>=@"E0 then begin - a := (b-@"E0) * 64; - b := str_pool[t+1]; - a := (a + (b-128)) * 64; - b := str_pool[t+2]; - a := a + (b-128); + a := (b-@"E0) * 64; + b := str_pool[t+1]; + a := (a + (b-128)) * 64; + b := str_pool[t+2]; + a := a + (b-128); end else if b>=@"C0 then begin - a := (b-@"C0) * 64; - b := str_pool[t+1]; - a := a + (b-128); + a := (b-@"C0) * 64; + b := str_pool[t+1]; + a := a + (b-128); end else begin { NI: this is an encoding error } - wlog_ln('! Pool contains an invalid utf-8 sequence'); - wterm_ln('! Pool contains an invalid utf-8 sequence'); + wlog_ln('! Pool contains an invalid utf-8 sequence'); + wterm_ln('! Pool contains an invalid utf-8 sequence'); @.Text line contains...@> - help2("A funny symbol somehow ended up in the string pool.")@/ - ("Just continue, I'll change it to 0xFFFD.");@/ + help2("A funny symbol somehow ended up in the string pool.")@/ + ("Just continue, I'll change it to 0xFFFD.");@/ deletions_allowed:=false; error; deletions_allowed:=true; a:=@"FFFD; end; @@ -1941,7 +1990,7 @@ else if s<string_offset then end else begin if s>=@"110000 then - print_char(s-@"110000) + print_char(s-@"110000) else begin print_char(@"F0 + (s div @"40000)); print_char(@"80 + ((s mod @"40000) div @"1000)); @@ -1955,8 +2004,8 @@ j:=str_start_macro(s); while j<str_start_macro(s+1) do begin { 0x110000 in utf=8: 0xF4 0x90 0x80 0x80 } if (str_pool[j]=@"F4)and(j<str_start_macro(s+4))and(str_pool[j+1]=@"90) then begin - v := (((7*64+63)*64)+ (str_pool[j+2]-128))*64 +(str_pool[j+3]-128); - print_char(v-@"110000); j := j+4; + v := (((7*64+63)*64)+ (str_pool[j+2]-128))*64 +(str_pool[j+3]-128); + print_char(v-@"110000); j := j+4; end else begin print_char(str_pool[j]); incr(j); @@ -2034,9 +2083,9 @@ to negative arguments, since such operations are not implemented consistently by all \PASCAL\ compilers. @<Basic print...@>= -procedure print_int(@!n:integer); {prints an integer in decimal form} +procedure print_int(@!n:longinteger); {prints an integer in decimal form} var k:0..23; {index to current digit; we assume that $|n|<10^{23}$} -@!m:integer; {used to negate |n| in possibly dangerous cases} +@!m:longinteger; {used to negate |n| in possibly dangerous cases} begin k:=0; if n<0 then begin print_char("-"); @@ -2302,6 +2351,11 @@ begin help1(a); end; @# +procedure dohelp0; +begin + help0; +end; +@# procedure do_print_err (s:str_number); begin print_err(s); @@ -2529,15 +2583,19 @@ end; @<Error hand...@>= procedure lua_norm_error(@!s:str_number); {lua found a problem} +var saved_new_line_char: integer; begin +saved_new_line_char:=new_line_char; +new_line_char:=10; print_err("LuaTeX error "); print(s); help2("The lua interpreter ran into a problem, so the")@/ ("remainder of this lua chunk will be ignored."); error; +new_line_char:=saved_new_line_char; end; procedure lua_fatal_error(@!s:str_number); {lua found a problem} -begin normalize_selector; +begin new_line_char:=10; normalize_selector; print_err("LuaTeX fatal error "); print(s); succumb; end; @@ -2599,10 +2657,10 @@ a way to make |interrupt| nonzero using the \PASCAL\ debugger. @<Global...@>= @!interrupt:integer; {should \TeX\ pause for instructions?} @!OK_to_interrupt:boolean; {should interrupts be observed?} -@!detokenized_line:boolean; {indicates this is a 'detokenized' input line } -@!line_catcode_table:integer; {the used catcode table for input lines} -@!local_catcode_table:boolean; {the used catcode table for input lines} @!static_int_base:integer; {C version of |int_base|} +@!static_glue_base:integer; {C version of |glue_base|} +@!static_dimen_base:integer; {C version of |dimen_base|} +@!static_local_base:integer; {C version of |local_base|} @ @p procedure check_interrupt; begin @@ -2611,8 +2669,7 @@ end; @ @<Set init...@>= -interrupt:=0; OK_to_interrupt:=true; detokenized_line:=false; -line_catcode_table:=0; local_catcode_table:=false; +interrupt:=0; OK_to_interrupt:=true; @ When an interrupt has been detected, the program goes into its highest interaction level and lets the user have nearly the full flexibility of @@ -2726,7 +2783,7 @@ meters); two such quantities can be added without overflow on a 32-bit computer. The present implementation of \TeX\ does not check for overflow when -@^Overflow in arithmetic@> +@^overflow in arithmetic@> dimensions are added or subtracted. This could be done by inserting a few dozen tests of the form `\ignorespaces|if x>=@'10000000000 then @t\\{report\_overflow}@>|', but the chance of overflow is so remote that @@ -3521,8 +3578,6 @@ end; of |mem| is a nonempty, doubly-linked circular list of empty nodes, pointed to by the roving pointer |rover|. -@d temp_node==46 -@d temp_node_size==2 @d vmem(#) == varmem[#] @d vlink(#) == vmem(#).hh.rh {the |link| field of a memory word} @d vinfo(#) == vmem(#).hh.lh {the |info| field of a memory word} @@ -3625,8 +3680,6 @@ glue should stretch or shrink or remain rigid; and |glue_order(p)| specifies the order of infinity to which glue setting applies (|normal|, |sfi|, |fil|, |fill|, or |filll|). The |subtype| field is not used. -@d hlist_node=0 {|type| of hlist nodes} -@d box_node_size=8 {number of words to allocate for a box node} @d width_offset=2 {position of |width| field in a box node} @d depth_offset=3 {position of |depth| field in a box node} @d height_offset=4 {position of |height| field in a box node} @@ -3642,9 +3695,7 @@ specifies the order of infinity to which glue setting applies (|normal|, @d normal=0 {the most common case when several cases are named} @d stretching = 1 {glue setting applies to the stretch components} @d shrinking = 2 {glue setting applies to the shrink components} -@d glue_offset = 7 {position of |glue_set| in a box node} -@d glue_set(#) == vmem(#+glue_offset).gr - {a word of type |glue_ratio| for glue setting} +@d glue_set(#) == vmem(#+7).gr {a word of type |glue_ratio| for glue setting} @ The |new_null_box| function returns a pointer to an |hlist_node| in which all subfields have the values corresponding to `\.{\\hbox\{\}}'. @@ -3661,8 +3712,6 @@ end; @ A |vlist_node| is like an |hlist_node| in all respects except that it contains a vertical list. -@d vlist_node=1 {|type| of vlist nodes} - @ A |rule_node| stands for a solid black rectangle; it has |width|, |depth|, and |height| fields just as in an |hlist_node|. However, if any of these dimensions is $-2^{30}$, the actual value will be determined @@ -3670,8 +3719,6 @@ by running the rule up to the boundary of the innermost enclosing box. This is called a ``running dimension.'' The |width| is never running in an hlist; the |height| and |depth| are never running in a~vlist. -@d rule_node=2 {|type| of rule nodes} -@d rule_node_size=6 {number of words to allocate for a rule node} @d null_flag==-@'10000000000 {$-2^{30}$, signifies a missing item} @d is_running(#) == (#=null_flag) {tests for a running dimension} @d rule_dir(#)==vlink(#+5) @@ -3700,8 +3747,6 @@ will be used if this insertion floats to a subsequent page after a split insertion of the same class. There is one more field, the |ins_ptr|, which points to the beginning of the vlist for the insertion. -@d ins_node=3 {|type| of insertion nodes} -@d ins_node_size=6 {number of words to allocate for an insertion} @d float_cost(#)==vmem(#+2).int {the |floating_penalty| to be used} @d ins_ptr(#)==vinfo(#+5) {the vertical list to be inserted} @d split_top_ptr(#)==vlink(#+5) {the |split_top_skip| to be used} @@ -3710,8 +3755,6 @@ split insertion of the same class. There is one more field, the of a token list that contains the user's \.{\\mark} text. In addition there is a |mark_class| field that contains the mark class. -@d mark_node=4 {|type| of a mark node} -@d mark_node_size=3 {number of words to allocate for a mark node} @d mark_ptr(#)==vlink(#+2) {head of the token list for a mark} @d mark_class(#)==vinfo(#+2) {the mark class} @@ -3721,8 +3764,6 @@ vertical list; i.e., it is used to implement \TeX's `\.{\\vadjust}' operation. The |adjust_ptr| field points to the vlist containing this material. -@d adjust_node=5 {|type| of an adjust node} -@d adjust_node_size=3 @d adjust_pre == subtype {pre-adjustment?} @d adjust_ptr(#)==vlink(#+2) {vertical list to be moved out of horizontal list} @#{|append_list| is used to append a list to |tail|} @@ -3750,8 +3791,6 @@ and their base (through |make_accent|), and math nucleus items (in the conversion from |mlist| to |hlist|). -@d glyph_node_size=5 -@d glyph_node=33 {|type| of a glyph node} @d is_char_node(#) == ((#<>null)and(type(#)=glyph_node)) @d font(#)==vlink(#+2) {the font code in a |glyph_node|} @d character(#)==vinfo(#+2) {the character code in a |glyph_node|} @@ -3854,8 +3893,6 @@ decides to make the break, and the discretionary node will disappear at that time; thus, the output routine sees only discretionaries that were not chosen. -@d disc_node=7 {|type| of a discretionary node} -@d disc_node_size=10 @d automatic_disc=2 @d syllable_disc=3 @d disc_type==subtype {the kind of discretionary} @@ -3889,15 +3926,11 @@ The present implementation of \TeX\ treats the features associated with illustrate how such routines might be coded. We shall defer further discussion of extensions until the end of this program. -@d whatsit_node=8 {|type| of special extension nodes} - @ A |math_node|, which occurs only in horizontal lists, appears before and after mathematical formulas. The |subtype| field is |before| before the formula and |after| after it. There is a |surround| field, which represents the amount of surrounding space inserted by \.{\\mathsurround}. -@d math_node=9 {|type| of a math node} -@d math_node_size=3 @d surround(#)==vlink(#+2) @d before=0 {|subtype| for math node that introduces a formula} @d after=1 {|subtype| for math node that winds up a formula} @@ -3944,8 +3977,6 @@ instead of scaled \.{pt}); and |cond_math_glue| denotes the `\.{\\nonscript}' feature that cancels the glue node immediately following if it appears in a subscript. -@d glue_node=10 {|type| of node that points to a glue specification} -@d glue_node_size=3 @d cond_math_glue=98 {special |subtype| to suppress glue in the next node} @d mu_glue=99 {|subtype| for math glue} @d a_leaders=100 {|subtype| for aligned leaders} @@ -3968,8 +3999,6 @@ fields called |stretch_order| and |shrink_order|; these contain the orders of infinity (|normal|, |sfi|, |fil|, |fill|, or |filll|) corresponding to the stretch and shrink values. -@d glue_spec_size=4 {number of words to allocate for a glue specification} -@d glue_spec_node=43 @d glue_ref_count(#) == vlink(#+3) {reference count of a glue specification} @d stretch(#) == vlink(#+1) {the stretchability of this glob of glue} @d shrink(#) == vinfo(#+1) {the shrinkability of this glob of glue} @@ -4018,7 +4047,7 @@ glue_ptr(p):=q; incr(glue_ref_count(q)); new_glue:=p; end; -@ Still another subroutine is needed: this one is sort of a combination +@ Still another subroutine is needed: This one is sort of a combination of |new_param_glue| and |new_glue|. It creates a glue node for one of the current glue parameters, but it makes a fresh copy of the glue specification, since that specification will probably be subject to change, @@ -4043,14 +4072,10 @@ kerns inserted from font information or math mode calculations) or |explicit| (for kerns inserted from non-math accents) or |mu_glue| (for kerns inserted from \.{\\mkern} specifications in math formulas). -@d kern_node=11 {|type| of a kern node} -@d kern_node_size=3 @d explicit=1 {|subtype| of kern nodes from \.{\\kern} and \.{\\/}} @d acc_kern=2 {|subtype| of kern nodes from accents} @# {memory structure for marginal kerns} -@d margin_kern_node = 32 -@d margin_kern_node_size = 4 @d margin_char(#) == vlink(#+3) @# {|subtype| of marginal kerns} @@ -4084,8 +4109,6 @@ treated as infinity, and no break will be allowed for such high values. Similarly, any penalty |<=-10000| is treated as negative infinity, and a break will be forced. -@d penalty_node=12 {|type| of a penalty node} -@d penalty_node_size=3 {has to be the same as |glue_node_size|} @d inf_penalty=inf_bad {``infinite'' penalty value} @d eject_penalty=-inf_penalty {``negatively infinite'' penalty value} @d penalty(#) == vlink(#+2) {the added cost of breaking a list here} @@ -4113,8 +4136,7 @@ The |subtype| field is called |span_count|; an unset box typically contains the data for |qo(span_count)+1| columns. Unset nodes will be changed to box nodes when alignment is completed. -@d unset_node=13 {|type| for an unset node} -@d glue_stretch(#)==vmem(#+glue_offset).sc {total stretch in an unset node} +@d glue_stretch(#)==vmem(#+7).sc {total stretch in an unset node} @d glue_shrink==shift_amount {total shrink in an unset node} @d span_count==subtype {indicates the number of spanned columns} @@ -4133,32 +4155,23 @@ the \.{WEB} macro definitions above, so that format changes will leave \TeX's other algorithms intact. @^system dependencies@> -@* \[11] Memory layout. -Some areas of |mem| are dedicated to fixed usage, since static allocation is -more efficient than dynamic allocation when we can get away with it. For -example, |zero_glue| used for glue that is `\.{0pt plus 0pt minus 0pt}'. The -following macro definitions accomplish the static allocation by giving -symbolic names to the fixed positions. - -@d zero_glue==0 {specification for \.{0pt plus 0pt minus 0pt}} -@d sfi_glue==zero_glue+glue_spec_size {\.{0pt plus 1fi minus 0pt}} -@d fil_glue==sfi_glue+glue_spec_size {\.{0pt plus 1fil minus 0pt}} -@d fill_glue==fil_glue+glue_spec_size {\.{0pt plus 1fill minus 0pt}} -@d ss_glue==fill_glue+glue_spec_size {\.{0pt plus 1fil minus 1fil}} -@d fil_neg_glue==ss_glue+glue_spec_size {\.{0pt plus -1fil minus 0pt}} -@d page_ins_head==fil_neg_glue+glue_spec_size {list of insertion data for current page} -@d contrib_head==page_ins_head+temp_node_size {list of items not yet on current page} -@d page_head==contrib_head+temp_node_size {list for current page} -@d temp_head==page_head+temp_node_size {head of a temporary list of some kind} -@d hold_head==temp_head+temp_node_size {head of a temporary list of another kind} -@d adjust_head==hold_head+temp_node_size {head of adjustment list returned by |hpack|} -@d pre_adjust_head==adjust_head+temp_node_size {head of pre-adjustment list returned by |hpack|} -@d active==pre_adjust_head+temp_node_size {head of active list in |line_break|} -@d align_head==active+active_node_size {head of preamble list for alignments} -@d end_span==align_head+temp_node_size {tail of spanned-width lists} -@d begin_point==end_span+span_node_size {left-side dot for words in hyphenation} -@d end_point==begin_point+glyph_node_size {right-side dot for words in hyphenation} -@d var_mem_stat_max==(end_point+glyph_node_size-1) {largest statically allocated word in the variable-size |mem|} +@* \[11] Memory layout. + +Some areas of |mem| are dedicated to fixed usage, since static +allocation is more efficient than dynamic allocation when we can get +away with it. For example, |zero_glue| used for glue that is `\.{0pt +plus 0pt minus 0pt}'. A few C macro definitions accomplish the static +allocation of node memory locations by giving symbolic names to fixed +positions. The list of imported constant identifiers is: |zero_glue|, +|sfi_glue|, |fil_glue|, |fill_glue|, |ss_glue|, |fil_neg_glue| (all +glue specs), |page_ins_head| (list of insertion data for current +page), |contrib_head| (list of insertion data for current page), +|page_head| (list for current page), |temp_head| and |hold_head| +(temporary lists), |adjust_head| (head of adjustment list returned by +|hpack|), |pre_adjust_head| (head of pre-adjustment list returned by +|hpack|), |align_head| (head of alignment preamble), and +|end_span| (tail of spanned-width lists). + @<Glob...@>= garbage:pointer; {head of a junk list, write only} @@ -4176,52 +4189,7 @@ initializing itself the slow~way. @ @<Initialize table entries...@>= procedure init_link_heads;forward; -init_node_mem(var_mem_stat_max,500); -glue_ref_count(zero_glue):=null+1; width(zero_glue):=0; -type(zero_glue):=glue_spec_node; vlink(zero_glue):=null; -stretch(zero_glue):=0; stretch_order(zero_glue):=normal;@/ -shrink(zero_glue):=0; shrink_order(zero_glue):=normal;@/ -glue_ref_count(sfi_glue):=null+1; width(sfi_glue):=0; -type(sfi_glue):=glue_spec_node; vlink(sfi_glue):=null; -stretch(sfi_glue):=0; stretch_order(sfi_glue):=sfi;@/ -shrink(sfi_glue):=0; shrink_order(sfi_glue):=normal;@/ -glue_ref_count(fil_glue):=null+1; width(fil_glue):=0; -type(fil_glue):=glue_spec_node; vlink(fil_glue):=null; -stretch(fil_glue):=unity; stretch_order(fil_glue):=fil;@/ -shrink(fil_glue):=0; shrink_order(fil_glue):=normal;@/ -glue_ref_count(fill_glue):=null+1; width(fill_glue):=0; -type(fill_glue):=glue_spec_node; vlink(fill_glue):=null; -stretch(fill_glue):=unity; stretch_order(fill_glue):=fill;@/ -shrink(fill_glue):=0; shrink_order(fill_glue):=normal;@/ -glue_ref_count(ss_glue):=null+1; width(ss_glue):=0; -type(ss_glue):=glue_spec_node; vlink(ss_glue):=null; -stretch(ss_glue):=unity; stretch_order(ss_glue):=fil;@/ -shrink(ss_glue):=unity; shrink_order(ss_glue):=fil;@/ -glue_ref_count(fil_neg_glue):=null+1; width(fil_neg_glue):=0; -type(fil_neg_glue):=glue_spec_node; vlink(fil_neg_glue):=null; -stretch(fil_neg_glue):=-unity; stretch_order(fil_neg_glue):=fil;@/ -shrink(fil_neg_glue):=0; shrink_order(fil_neg_glue):=normal;@/ -{initialize node list heads} -vinfo(page_ins_head):=0; vlink(page_ins_head):=null; alink(page_ins_head):=null; -vinfo(contrib_head):=0; vlink(contrib_head):=null; alink(contrib_head):=null; -vinfo(page_head):=0; vlink(page_head):=null; alink(page_head):=null; -vinfo(temp_head):=0; vlink(temp_head):=null; alink(temp_head):=null; -vinfo(hold_head):=0; vlink(hold_head):=null; alink(hold_head):=null; -vinfo(adjust_head):=0; vlink(adjust_head):=null; alink(adjust_head):=null; -vinfo(pre_adjust_head):=0; vlink(pre_adjust_head):=null; alink(pre_adjust_head):=null; -vinfo(active):=0; vlink(active):=null; alink(active):=null; -vinfo(align_head):=0; vlink(align_head):=null; alink(align_head):=null; -vinfo(end_span):=0; vlink(end_span):=null; alink(end_span):=null; -type(begin_point):=glyph_node; subtype(begin_point):=0; vlink(begin_point):=null; -vinfo(begin_point+1):=null; alink(begin_point):=null; -font(begin_point):=0; character(begin_point):='.'; -vinfo(begin_point+3):=0; vlink(begin_point+3):=0; -vinfo(begin_point+4):=0; vlink(begin_point+4):=0; -type(end_point):=glyph_node; subtype(end_point):=0; vlink(end_point):=null; -vinfo(end_point+1):=null; alink(end_point):=null; -font(end_point):=0; character(end_point):='.'; -vinfo(end_point+3):=0; vlink(end_point+3):=0; -vinfo(end_point+4):=0; vlink(end_point+4):=0; +init_node_mem(500); avail:=null; fix_mem_end:=0; init_list_heads; @<Initialize the special list heads and constant nodes@>; @@ -4268,11 +4236,21 @@ sort of ``complicated'' are indicated only by printing `\.{[]}'. @p procedure print_font_identifier(f: internal_font_number); +var fonttext:str_number; begin if pdf_font_blink(f) = null_font then - print_esc(font_id_text(f)) + fonttext := font_id_text(f) else - print_esc(font_id_text(pdf_font_blink(f))); + fonttext := font_id_text(pdf_font_blink(f)); + if fonttext>0 then + print_esc(fonttext) + else begin + print_esc("FONT"); + if pdf_font_blink(f) = null_font then + print_int(f) + else + print_int(pdf_font_blink(f)); + end; if pdf_tracing_fonts > 0 then begin print(" ("); print_font_name(f); @@ -4314,17 +4292,7 @@ begin while p<>null do end; @ @<Print a short indication of the contents of node |p|@>= -case type(p) of -hlist_node,vlist_node,ins_node,whatsit_node,mark_node,adjust_node, - unset_node: print("[]"); -rule_node: print_char("|"); -glue_node: if glue_ptr(p)<>zero_glue then print_char(" "); -math_node: print_char("$"); -disc_node: begin short_display(vlink(pre_break(p))); - short_display(vlink(post_break(p)));@/ - end; -othercases do_nothing -endcases +print_short_node_contents(p) @ The |show_node_list| routine requires some auxiliary subroutines: one to print a font-and-character combination, one to print a token list without @@ -4393,8 +4361,7 @@ end; @ We also need to declare some procedures that appear later in this documentation. -@p @<Declare procedures needed for displaying the elements of mlists@>@; -@<Declare the procedure called |print_skip_param|@> +@p @<Declare the procedure called |print_skip_param|@> @ Since boxes can be inside of boxes, |show_node_list| is inherently recursive, @^recursion@> @@ -4402,12 +4369,6 @@ up to a given maximum number of levels. The history of nesting is indicated by the current string, which will be printed at the beginning of each line; the length of this string, namely |cur_length|, is the depth of nesting. -Recursive calls on |show_node_list| therefore use the following pattern: - -@d node_list_display(#)== - begin append_char("."); show_node_list(#); flush_char; - end {|str_room| need not be checked; see |show_box| below} - @ A global variable called |depth_threshold| is used to record the maximum depth of nesting for which |show_node_list| will show information. If we have |depth_threshold=0|, for example, only the top level information will @@ -4419,224 +4380,6 @@ be given and no sublists will be traversed. Another global variable, called @!depth_threshold : integer; {maximum nesting depth in box displays} @!breadth_max : integer; {maximum number of items shown at the same list level} -@ Now we are ready for |show_node_list| itself. This procedure has been -written to be ``extra robust'' in the sense that it should not crash or get -into a loop even if the data structures have been messed up by bugs in -the rest of the program. You can safely call its parent routine -|show_box(p)| for arbitrary values of |p| when you are debugging \TeX. -However, in the presence of bad data, the procedure may -@^dirty \PASCAL@>@^debugging@> -fetch a |memory_word| whose variant is different from the way it was stored; -for example, it might try to read |mem[p].hh| when |mem[p]| -contains a scaled integer, if |p| is a pointer that has been -clobbered or chosen at random. - -@p procedure show_node_list(@!p:integer); {prints a node list symbolically} -label exit; -var n:integer; {the number of items already printed at this level} -@!g:real; {a glue ratio, as a floating point number} -begin if cur_length>depth_threshold then - begin if p>null then print(" []"); - {indicate that there's been some truncation} - return; - end; -n:=0; -while p<>null do - begin print_ln; print_current_string; {display the nesting history} - if tracing_online<-2 then print_int(p); - incr(n); if n>breadth_max then {time to stop} - begin print("etc."); return; -@.etc@> - end; - @<Display node |p|@>; - p:=vlink(p); - end; -exit: -end; - -@ @<Display node |p|@>= -if is_char_node(p) then begin - print_font_and_char(p); - if is_ligature(p) then @<Display ligature |p|@>; - end -else case type(p) of - hlist_node,vlist_node,unset_node: @<Display box |p|@>; - rule_node: @<Display rule |p|@>; - ins_node: @<Display insertion |p|@>; - whatsit_node: @<Display the whatsit node |p|@>; - glue_node: @<Display glue |p|@>; - margin_kern_node: begin - print_esc("kern"); - print_scaled(width(p)); - if subtype(p) = left_side then - print(" (left margin)") - else - print(" (right margin)"); - end; - kern_node: @<Display kern |p|@>; - math_node: @<Display math node |p|@>; - penalty_node: @<Display penalty |p|@>; - disc_node: @<Display discretionary |p|@>; - mark_node: @<Display mark |p|@>; - adjust_node: @<Display adjustment |p|@>; - @t\4@>@<Cases of |show_node_list| that arise in mlists only@>@; - othercases print("Unknown node type!") - endcases - -@ @<Display box |p|@>= -begin if type(p)=hlist_node then print_esc("h") -else if type(p)=vlist_node then print_esc("v") -else print_esc("unset"); -print("box("); print_scaled(height(p)); print_char("+"); -print_scaled(depth(p)); print(")x"); print_scaled(width(p)); -if type(p)=unset_node then - @<Display special fields of the unset node |p|@> -else begin @<Display the value of |glue_set(p)|@>; - if shift_amount(p)<>0 then - begin print(", shifted "); print_scaled(shift_amount(p)); - end; - print(", direction "); print_dir(box_dir(p)); - end; -{|pdfassert(list_ptr(p)<>0);|} -node_list_display(list_ptr(p)); {recursive call} -end - -@ @<Display special fields of the unset node |p|@>= -begin if span_count(p)<>min_quarterword then - begin print(" ("); print_int(qo(span_count(p))+1); - print(" columns)"); - end; -if glue_stretch(p)<>0 then - begin print(", stretch "); print_glue(glue_stretch(p),glue_order(p),0); - end; -if glue_shrink(p)<>0 then - begin print(", shrink "); print_glue(glue_shrink(p),glue_sign(p),0); - end; -end - -@ The code will have to change in this place if |glue_ratio| is -a structured type instead of an ordinary |real|. Note that this routine -should avoid arithmetic errors even if the |glue_set| field holds an -arbitrary random value. The following code assumes that a properly -formed nonzero |real| number has absolute value $2^{20}$ or more when -it is regarded as an integer; this precaution was adequate to prevent -floating point underflow on the author's computer. -@^system dependencies@> -@^dirty \PASCAL@> - -@<Display the value of |glue_set(p)|@>= -g:=float(glue_set(p)); -if (g<>float_constant(0))and(glue_sign(p)<>normal) then - begin print(", glue set "); - if glue_sign(p)=shrinking then print("- "); - if abs(vmem(p+glue_offset).int)<@'4000000 then print("?.?") - else if abs(g)>float_constant(20000) then - begin if g>float_constant(0) then print_char(">") - else print("< -"); - print_glue(20000*unity,glue_order(p),0); - end - else print_glue(round(unity*g),glue_order(p),0); -@^real multiplication@> - end - -@ @<Display rule |p|@>= -begin print_esc("rule("); print_rule_dimen(height(p)); print_char("+"); -print_rule_dimen(depth(p)); print(")x"); print_rule_dimen(width(p)); -end - -@ @<Display insertion |p|@>= -begin print_esc("insert"); print_int(qo(subtype(p))); -print(", natural size "); print_scaled(height(p)); -print("; split("); print_spec(split_top_ptr(p),0); -print_char(","); print_scaled(depth(p)); -print("); float cost "); print_int(float_cost(p)); -node_list_display(ins_ptr(p)); {recursive call} -end - -@ @<Display glue |p|@>= -if subtype(p)>=a_leaders then @<Display leaders |p|@> -else begin print_esc("glue"); - if subtype(p)<>normal then - begin print_char("("); - if subtype(p)<cond_math_glue then - print_skip_param(subtype(p)-1) - else if subtype(p)=cond_math_glue then print_esc("nonscript") - else print_esc("mskip"); - print_char(")"); - end; - if subtype(p)<>cond_math_glue then - begin print_char(" "); - if subtype(p)<cond_math_glue then print_spec(glue_ptr(p),0) - else print_spec(glue_ptr(p),"mu"); - end; - end - -@ @<Display leaders |p|@>= -begin print_esc(""); -if subtype(p)=c_leaders then print_char("c") -else if subtype(p)=x_leaders then print_char("x"); -print("leaders "); print_spec(glue_ptr(p),0); -node_list_display(leader_ptr(p)); {recursive call} -end - -@ An ``explicit'' kern value is indicated implicitly by an explicit space. - -@<Display kern |p|@>= -if subtype(p)<>mu_glue then - begin print_esc("kern"); - if subtype(p)<>normal then print_char(" "); - print_scaled(width(p)); - if subtype(p)=acc_kern then print(" (for accent)"); -@.for accent@> - end -else begin print_esc("mkern"); print_scaled(width(p)); print("mu"); - end - -@ @<Display math node |p|@>= -begin print_esc("math"); -if subtype(p)=before then print("on") -else print("off"); -if width(p)<>0 then - begin print(", surrounded "); print_scaled(width(p)); - end; -end - -@ @<Display ligature |p|@>= -begin print(" (ligature "); -if is_leftboundary(p) then print_char("|"); -font_in_short_display:=font(p); short_display(lig_ptr(p)); -if is_rightboundary(p) then print_char("|"); -print_char(")"); -end - -@ @<Display penalty |p|@>= -begin print_esc("penalty "); print_int(penalty(p)); -end - -@ The |post_break| list of a discretionary node is indicated by a prefixed -`\.{\char'174}' instead of the `\..' before the |pre_break| list. - -@<Display discretionary |p|@>= -begin print_esc("discretionary"); -if vlink(no_break(p))<>null then - begin print(" replacing "); node_list_display(vlink(no_break(p))); - end; -node_list_display(vlink(pre_break(p))); {recursive call} -append_char("|"); show_node_list(vlink(post_break(p))); flush_char; {recursive call} -end - -@ @<Display mark |p|@>= -begin print_esc("mark"); -if mark_class(p)<>0 then - begin print_char("s"); print_int(mark_class(p)); - end; -print_mark(mark_ptr(p)); -end - -@ @<Display adjustment |p|@>= -begin print_esc("vadjust"); if adjust_pre(p) <> 0 then print(" pre "); -node_list_display(adjust_ptr(p)); {recursive call} -end @ The recursive machinery is started by calling |show_box|. @^recursion@> @@ -4830,7 +4573,8 @@ expanded by `\.{\\the}'. @d char_given=min_internal {character code defined by \.{\\chardef}} @d math_given=char_given+1 {math code defined by \.{\\mathchardef}} @d omath_given=math_given+1 {math code defined by \.{\\omathchardef}} -@d last_item=omath_given+1 {most recent item ( \.{\\lastpenalty}, +@d xmath_given=omath_given+1 {math code defined by \.{\\Umathchardef}} +@d last_item=xmath_given+1 {most recent item ( \.{\\lastpenalty}, \.{\\lastkern}, \.{\\lastskip} )} @d max_non_prefixed_command=last_item {largest command code that can't be \.{\\global}} @@ -4874,22 +4618,30 @@ break down otherwise. \.{\\insertpenalties} )} @d set_box_dimen=set_page_int+1 {change dimension of box ( \.{\\wd}, \.{\\ht}, \.{\\dp} )} -@d set_shape=set_box_dimen+1 +@d set_tex_shape=set_box_dimen+1 {specify fancy paragraph shape ( \.{\\parshape} )} -@d def_code=set_shape+1 +@d set_etex_shape=set_tex_shape+1 + {specify etex specials ( \.{\\interlinepenalties}, etc.~)} +@d def_char_code=set_etex_shape+1 {define a character code ( \.{\\catcode}, etc.~)} -@d extdef_code=def_code+1 +@d def_del_code=def_char_code+1 + {define a delimiter code ( \.{\\delcode})} +@d extdef_math_code=def_del_code+1 {define an extended character code ( \.{\\omathcode}, etc.~)} -@d def_family=extdef_code+1 +@d extdef_del_code=extdef_math_code+1 + {define an extended delimiter code ( \.{\\odelcode}, etc.~)} +@d def_family=extdef_del_code+1 {declare math fonts ( \.{\\textfont}, etc.~)} -@d set_font=def_family+1 +@d set_math_param=def_family+1 + {declare math parameters ( \.{\\Umathquad}, etc.~)} +@d set_font=set_math_param+1 {set current font ( font identifiers )} @d def_font=set_font+1 {define a font file ( \.{\\font} )} @d register=def_font+1 {internal register ( \.{\\count}, \.{\\dimen}, etc.~)} @d assign_box_dir=register+1 {(\.{\\boxdir})} -@d assign_dir=register+2 {(\.{\\pagedir}, \.{\\textdir})} +@d assign_dir=register+2 {(\.{\\pagedir}, \.{\\bodydir}, \.{\\pardir}, \.{\\textdir}), \.{\\mathdir}} @d max_internal=assign_dir {the largest code that can follow \.{\\the}} @d advance=max_internal+1 @@ -4916,7 +4668,9 @@ break down otherwise. {define level of interaction ( \.{\\batchmode}, etc.~)} @d letterspace_font=set_interaction+1 {letterspace a font ( \.{\\letterspacefont} )} -@d set_ocp=letterspace_font+1 +@d pdf_copy_font=letterspace_font+1 + {create a new font instance ( \.{\\pdfcopyfont} )} +@d set_ocp=pdf_copy_font+1 {Place a translation process in the stream} @d def_ocp=set_ocp+1 {Define and load a translation process} @@ -5076,7 +4830,7 @@ user's output routine. A seventh quantity, |eTeX_aux|, is used by the extended features \eTeX. In math mode it is known as |delim_ptr| and points to the most -recent |left_noad| or |middle_noad| of a |math_left_group|. +recent |fence_noad| of a |math_left_group|. In horizontal mode, the |prev_graf| field is used for initial language data. @@ -5087,7 +4841,7 @@ level is kept in the global quantities |mode|, |head|, |tail|, |prev_graf|, |aux|, and |mode_line|, which live in a \PASCAL\ record that is ready to be pushed onto |nest| if necessary. -@d ignore_depth==-65536000 {|prev_depth| value that is ignored} +@d ignore_depth==-65536000 {magic dimension value to mean `ignore me'} @<Types...@>= @!list_state_record=record@!mode_field:-mmode..mmode;@+ @@ -5097,8 +4851,6 @@ be pushed onto |nest| if necessary. @!aux_field: memory_word; @!dirs_field: halfword; @!math_field: integer; - @!local_par_field: pointer; - @!local_par_bool_field: boolean; end; @ @d mode==cur_list.mode_field {current mode} @@ -5115,10 +4867,6 @@ be pushed onto |nest| if necessary. @d dir_save==cur_list.dirs_field {dir stack when a paragraph is interrupted} @d dir_math_save==cur_list.math_field {should begin/end dir nodes be placed around mathematics?} -@d local_par==cur_list.local_par_field - {pointer to whatsit for local stuff} -@d local_par_bool==cur_list.local_par_bool_field - {has local stuff been changed in this group?} @<Glob...@>= @!nest:array[0..nest_size] of list_state_record; @@ -5179,7 +4927,6 @@ eTeX_aux:=null; prev_depth:=ignore_depth; mode_line:=0; prev_graf:=0; shown_mode:=0; dir_save:=null; dir_math_save:=false; -local_par:=null; local_par_bool:=false; @<Start a new current page@>; @ @p @<LOCAL: Declare |make_local_par_node|@>; @@ -5199,7 +4946,6 @@ begin if nest_ptr>max_nest_stack then nest[nest_ptr]:=cur_list; {stack the record} incr(nest_ptr); head:=new_node(temp_node,0); tail:=head; prev_graf:=0; mode_line:=line; dir_save:=null; dir_math_save:=false; -local_par:=make_local_par_node; local_par_bool:=false; eTeX_aux:=null; end; @@ -5210,10 +4956,6 @@ is a node that should be returned to free memory. @p procedure pop_nest; {leave a semantic level, re-enter the old} begin -if local_par<>null then begin - if local_par_bool then begin end {|tail_append(local_par)|} - else flush_node(local_par); - end; flush_node(head); decr(nest_ptr); cur_list:=nest[nest_ptr]; end; @@ -5252,7 +4994,7 @@ end; @ @<Show the auxiliary...@>= case abs(m) div (max_command+1) of 0: begin print_nl("prevdepth "); - if a.sc<=ignore_depth then print("ignored") + if a.sc<=pdf_ignored_dimen then print("ignored") else print_scaled(a.sc); if nest[p].pg_field<>0 then begin print(", prevgraf "); @@ -5283,11 +5025,11 @@ or what their current values are, for all quantities that are subject to the nesting structure provided by \TeX's grouping mechanism. There are six parts to |eqtb|: -\yskip\hangg 1) |eqtb[active_base..(hash_base-1)]| holds the current -equivalents of single-character control sequences. +\yskip\hangg 1) |eqtb[null_cs]| holds the current equivalent of the +zero-length control sequence. \yskip\hangg 2) |eqtb[hash_base..(glue_base-1)]| holds the current -equivalents of multiletter control sequences. +equivalents of single- and multiletter control sequences. \yskip\hangg 3) |eqtb[glue_base..(local_base-1)]| holds the current equivalents of glue parameters like the current baselineskip. @@ -5343,8 +5085,9 @@ things. paragraphs is to define these names, and to set up the initial values of the equivalents. -In the first region we have |number_active_chars| equivalents for ``active -characters'' that act as control sequences. +In the first region we have a single entry for the `null csname' of +length zero. In luatex, the active characters and and single-letter +control sequence names are part of the next region. Then comes region~2, which corresponds to the hash table that we will define later. The maximum address in this region is used for a dummy @@ -5352,8 +5095,7 @@ control sequence that is perpetually undefined. There also are several locations for control sequences that are perpetually defined (since they are used in error recovery). -@d active_base=1 {beginning of region 1, for active character equivalents} -@d null_cs=active_base+number_active_chars {equivalent of \.{\\csname\\endcsname}} +@d null_cs=1 {equivalent of \.{\\csname\\endcsname}} @d hash_base=null_cs+1 {beginning of region 2, for the hash table} @d frozen_control_sequence=hash_base+hash_size {for error recovery} @d frozen_protection=frozen_control_sequence {inaccessible but definable} @@ -5369,7 +5111,9 @@ locations for control sequences that are perpetually defined {permanent `\.{\\notexpanded:}'} @d frozen_primitive=frozen_control_sequence+11 {permanent `\.{\\pdfprimitive}'} -@d frozen_null_font=frozen_control_sequence+12 +@d frozen_special=frozen_control_sequence+12 + {permanent `\.{\\special}'} +@d frozen_null_font=frozen_control_sequence+13 {permanent `\.{\\nullfont}'} @d font_id_base=frozen_null_font-font_base {begins table of |number_fonts| permanent font identifiers} @@ -5388,9 +5132,17 @@ locations for control sequences that are perpetually defined eq_type(undefined_control_sequence):=undefined_cs; equiv(undefined_control_sequence):=null; eq_level(undefined_control_sequence):=level_zero; -for k:=active_base to undefined_control_sequence-1 do +for k:=null_cs to undefined_control_sequence-1 do eqtb[k]:=eqtb[undefined_control_sequence]; +@ Create a C version of |undefined_control_sequence|. + +@<Global...@>= +@!static_undefined_control_sequence:integer; + +@ @<Set init...@>= +static_undefined_control_sequence:=undefined_control_sequence; + @ Here is a routine that displays the current meaning of an |eqtb| entry in region 1 or~2. (Similar routines for the other regions will appear below.) @@ -5455,6 +5207,10 @@ parameters have larger numbers than the others. @<Current |mem| equivalent of glue parameter number |n|@>=glue_par(n) +@ @<Set init...@>= +static_local_base:=local_base; +static_glue_base:=glue_base; + @ Sometimes we need to convert \TeX's internal code numbers into symbolic form. The |print_skip_param| routine gives the symbolic name of a glue parameter. @@ -5489,54 +5245,43 @@ by using the routine called |primitive|, defined below. Let us enter them now, so that we don't have to list all those parameter names anywhere else. @<Put each of \TeX's primitives into the hash table@>= -primitive("lineskip",assign_glue,glue_base+line_skip_code);@/ +primitive_tex("lineskip",assign_glue,glue_base+line_skip_code,glue_base);@/ @!@:line_skip_}{\.{\\lineskip} primitive@> -primitive("baselineskip",assign_glue,glue_base+baseline_skip_code);@/ +primitive_tex("baselineskip",assign_glue,glue_base+baseline_skip_code,glue_base);@/ @!@:baseline_skip_}{\.{\\baselineskip} primitive@> -primitive("parskip",assign_glue,glue_base+par_skip_code);@/ +primitive_tex("parskip",assign_glue,glue_base+par_skip_code,glue_base);@/ @!@:par_skip_}{\.{\\parskip} primitive@> -primitive("abovedisplayskip",assign_glue,glue_base+above_display_skip_code);@/ +primitive_tex("abovedisplayskip",assign_glue,glue_base+above_display_skip_code,glue_base);@/ @!@:above_display_skip_}{\.{\\abovedisplayskip} primitive@> -primitive("belowdisplayskip",assign_glue,glue_base+below_display_skip_code);@/ +primitive_tex("belowdisplayskip",assign_glue,glue_base+below_display_skip_code,glue_base);@/ @!@:below_display_skip_}{\.{\\belowdisplayskip} primitive@> -primitive("abovedisplayshortskip", - assign_glue,glue_base+above_display_short_skip_code);@/ +primitive_tex("abovedisplayshortskip",assign_glue,glue_base+above_display_short_skip_code,glue_base);@/ @!@:above_display_short_skip_}{\.{\\abovedisplayshortskip} primitive@> -primitive("belowdisplayshortskip", - assign_glue,glue_base+below_display_short_skip_code);@/ +primitive_tex("belowdisplayshortskip",assign_glue,glue_base+below_display_short_skip_code,glue_base);@/ @!@:below_display_short_skip_}{\.{\\belowdisplayshortskip} primitive@> -primitive("leftskip",assign_glue,glue_base+left_skip_code);@/ +primitive_tex("leftskip",assign_glue,glue_base+left_skip_code,glue_base);@/ @!@:left_skip_}{\.{\\leftskip} primitive@> -primitive("rightskip",assign_glue,glue_base+right_skip_code);@/ +primitive_tex("rightskip",assign_glue,glue_base+right_skip_code,glue_base);@/ @!@:right_skip_}{\.{\\rightskip} primitive@> -primitive("topskip",assign_glue,glue_base+top_skip_code);@/ +primitive_tex("topskip",assign_glue,glue_base+top_skip_code,glue_base);@/ @!@:top_skip_}{\.{\\topskip} primitive@> -primitive("splittopskip",assign_glue,glue_base+split_top_skip_code);@/ +primitive_tex("splittopskip",assign_glue,glue_base+split_top_skip_code,glue_base);@/ @!@:split_top_skip_}{\.{\\splittopskip} primitive@> -primitive("tabskip",assign_glue,glue_base+tab_skip_code);@/ +primitive_tex("tabskip",assign_glue,glue_base+tab_skip_code,glue_base);@/ @!@:tab_skip_}{\.{\\tabskip} primitive@> -primitive("spaceskip",assign_glue,glue_base+space_skip_code);@/ +primitive_tex("spaceskip",assign_glue,glue_base+space_skip_code,glue_base);@/ @!@:space_skip_}{\.{\\spaceskip} primitive@> -primitive("xspaceskip",assign_glue,glue_base+xspace_skip_code);@/ +primitive_tex("xspaceskip",assign_glue,glue_base+xspace_skip_code,glue_base);@/ @!@:xspace_skip_}{\.{\\xspaceskip} primitive@> -primitive("parfillskip",assign_glue,glue_base+par_fill_skip_code);@/ +primitive_tex("parfillskip",assign_glue,glue_base+par_fill_skip_code,glue_base);@/ @!@:par_fill_skip_}{\.{\\parfillskip} primitive@> -primitive("thinmuskip",assign_mu_glue,glue_base+thin_mu_skip_code);@/ +primitive_tex("thinmuskip",assign_mu_glue,glue_base+thin_mu_skip_code,glue_base+thin_mu_skip_code);@/ @!@:thin_mu_skip_}{\.{\\thinmuskip} primitive@> -primitive("medmuskip",assign_mu_glue,glue_base+med_mu_skip_code);@/ +primitive_tex("medmuskip",assign_mu_glue,glue_base+med_mu_skip_code,glue_base+thin_mu_skip_code);@/ @!@:med_mu_skip_}{\.{\\medmuskip} primitive@> -primitive("thickmuskip",assign_mu_glue,glue_base+thick_mu_skip_code);@/ +primitive_tex("thickmuskip",assign_mu_glue,glue_base+thick_mu_skip_code,glue_base+thin_mu_skip_code);@/ @!@:thick_mu_skip_}{\.{\\thickmuskip} primitive@> -@ @<Cases of |print_cmd_chr| for symbolic printing of primitives@>= -assign_glue,assign_mu_glue: if chr_code<skip_base then - print_skip_param(chr_code-glue_base) - else if chr_code<mu_skip_base then - begin print_esc("skip"); print_int(chr_code-skip_base); - end - else begin print_esc("muskip"); print_int(chr_code-mu_skip_base); - end; - @ All glue parameters and registers are initially `\.{0pt plus0pt minus0pt}'. @<Initialize table entries...@>= @@ -5608,10 +5353,8 @@ registers. @d local_right_box_base=local_left_box_base+1 @d box_base=local_right_box_base+1 {table of |number_regs| box registers} @d cur_font_loc=box_base+number_regs {internal font number outside math mode} -@d math_font_base=cur_font_loc+1 - {table of |number_math_fonts| math font numbers} -@d cat_code_base=math_font_base+number_math_fonts - {table of |number_chars| command codes (the ``catcodes'')} +@d math_param_base=cur_font_loc+1 {current math parameter data index } +@d cat_code_base=math_param_base+1 {current category code data index } @d lc_code_base=cat_code_base+1 {table of |number_chars| lowercase mappings} @d uc_code_base=lc_code_base+1 {table of |number_chars| uppercase mappings} @d sf_code_base=uc_code_base+1 {table of |number_chars| spacefactor mappings} @@ -5637,56 +5380,35 @@ registers. @d local_right_box==equiv(local_right_box_base) @d box(#)==equiv(box_base+#) @d cur_font==equiv(cur_font_loc) -@d fam_fnt(#)==equiv(math_font_base+#) @<Put each...@>= -primitive("output",assign_toks,output_routine_loc); +primitive_tex("output",assign_toks,output_routine_loc,local_base); @!@:output_}{\.{\\output} primitive@> -primitive("everypar",assign_toks,every_par_loc); +primitive_tex("everypar",assign_toks,every_par_loc,local_base); @!@:every_par_}{\.{\\everypar} primitive@> -primitive("everymath",assign_toks,every_math_loc); +primitive_tex("everymath",assign_toks,every_math_loc,local_base); @!@:every_math_}{\.{\\everymath} primitive@> -primitive("everydisplay",assign_toks,every_display_loc); +primitive_tex("everydisplay",assign_toks,every_display_loc,local_base); @!@:every_display_}{\.{\\everydisplay} primitive@> -primitive("everyhbox",assign_toks,every_hbox_loc); +primitive_tex("everyhbox",assign_toks,every_hbox_loc,local_base); @!@:every_hbox_}{\.{\\everyhbox} primitive@> -primitive("everyvbox",assign_toks,every_vbox_loc); +primitive_tex("everyvbox",assign_toks,every_vbox_loc,local_base); @!@:every_vbox_}{\.{\\everyvbox} primitive@> -primitive("everyjob",assign_toks,every_job_loc); +primitive_tex("everyjob",assign_toks,every_job_loc,local_base); @!@:every_job_}{\.{\\everyjob} primitive@> -primitive("everycr",assign_toks,every_cr_loc); +primitive_tex("everycr",assign_toks,every_cr_loc,local_base); @!@:every_cr_}{\.{\\everycr} primitive@> -primitive("errhelp",assign_toks,err_help_loc); +primitive_tex("errhelp",assign_toks,err_help_loc,local_base); @!@:err_help_}{\.{\\errhelp} primitive@> -primitive("pdfpagesattr",assign_toks,pdf_pages_attr_loc); +primitive_pdftex("pdfpagesattr",assign_toks,pdf_pages_attr_loc,local_base); @!@:pdf_pages_attr_}{\.{\\pdfpagesattr} primitive@> -primitive("pdfpageattr",assign_toks,pdf_page_attr_loc); +primitive_pdftex("pdfpageattr",assign_toks,pdf_page_attr_loc,local_base); @!@:pdf_page_attr_}{\.{\\pdfpageattr} primitive@> -primitive("pdfpageresources",assign_toks,pdf_page_resources_loc); +primitive_pdftex("pdfpageresources",assign_toks,pdf_page_resources_loc,local_base); @!@:pdf_page_resources_}{\.{\\pdfpageresources} primitive@> -primitive("pdfpkmode",assign_toks,pdf_pk_mode_loc); +primitive_pdftex("pdfpkmode",assign_toks,pdf_pk_mode_loc,local_base); @!@:pdf_pk_mode_}{\.{\\pdfpkmode} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -assign_toks: if chr_code>=toks_base then - begin print_esc("toks"); print_int(chr_code-toks_base); - end -else case chr_code of - output_routine_loc: print_esc("output"); - every_par_loc: print_esc("everypar"); - every_math_loc: print_esc("everymath"); - every_display_loc: print_esc("everydisplay"); - every_hbox_loc: print_esc("everyhbox"); - every_vbox_loc: print_esc("everyvbox"); - every_job_loc: print_esc("everyjob"); - every_cr_loc: print_esc("everycr"); - @/@<Cases of |assign_toks| for |print_cmd_chr|@>@/ - pdf_pages_attr_loc: print_esc("pdfpagesattr"); - pdf_page_attr_loc: print_esc("pdfpageattr"); - pdf_page_resources_loc: print_esc("pdfpageresources"); - pdf_pk_mode_loc: print_esc("pdfpkmode"); - othercases print_esc("errhelp") - endcases; @ We initialize most things to null or undefined values. An undefined font is represented by the internal code |font_base|. @@ -5701,7 +5423,7 @@ possible. @d null_font==font_base @d null_ocp==ocp_base @d null_ocp_list==ocp_list_base -@d var_code==@"7000000 {math code meaning ``use the current family''} +@d var_code==7 {math code meaning ``use the current family''} @<Initialize table entries...@>= par_shape_ptr:=null; eq_type(par_shape_loc):=shape_ref; @@ -5714,19 +5436,21 @@ box(0):=null; eq_type(box_base):=box_ref; eq_level(box_base):=level_one; for k:=box_base+1 to box_base+biggest_reg do eqtb[k]:=eqtb[box_base]; cur_font:=null_font; eq_type(cur_font_loc):=data; eq_level(cur_font_loc):=level_one;@/ -for k:=math_font_base to math_font_base+47 do eqtb[k]:=eqtb[cur_font_loc]; equiv(cat_code_base):=0; eq_type(cat_code_base):=data; eq_level(cat_code_base):=level_one;@/ +eqtb[math_param_base]:=eqtb[cat_code_base]; eqtb[lc_code_base] :=eqtb[cat_code_base]; eqtb[uc_code_base] :=eqtb[cat_code_base]; eqtb[sf_code_base] :=eqtb[cat_code_base]; eqtb[math_code_base]:=eqtb[cat_code_base];@/ cat_code_table:=0; +initialize_math_codes; +initialize_text_codes; initex_cat_codes(0); -for k:="0" to "9" do set_math_code(k,(hi(k+var_code)),level_one);@/ +for k:="0" to "9" do set_math_code(k,tex_mathcode,var_code,0,k,level_one);@/ for k:="A" to "Z" do begin - set_math_code(k,(hi(k+var_code+@"10000)),level_one); - set_math_code(k+32,(hi(k+32+var_code+@"10000)),level_one);@/ + set_math_code(k,tex_mathcode,var_code,1,k,level_one); + set_math_code((k+32),tex_mathcode,var_code,1,(k+32),level_one);@/ set_lc_code(k,k+32,level_one); set_lc_code(k+32,k+32,level_one);@/ set_uc_code(k,k,level_one); set_uc_code(k+32,k,level_one);@/ set_sf_code(k,999,level_one); @@ -5734,19 +5458,19 @@ for k:="A" to "Z" do begin @ @<Set init...@>= static_int_base:=int_base; -initialize_math_codes; -initialize_text_codes; @ @<Show equivalent |n|, in region 4@>= if (n=par_shape_loc) or ((n>=etex_pen_base) and (n<etex_pens)) then - begin print_cmd_chr(set_shape,n); print_char("="); + begin if n=par_shape_loc then print_cmd_chr(set_tex_shape,n) + else print_cmd_chr(set_etex_shape,n); + print_char("="); if equiv(n)=null then print_char("0") else if n>par_shape_loc then begin print_int(penalty(equiv(n))); print_char(" "); print_int(penalty(equiv(n)+1)); if penalty(equiv(n))>1 then print_esc("ETC."); end - else print_int(vinfo(par_shape_ptr)); + else print_int(vinfo(par_shape_ptr+1)); end else if n<toks_base then {TH TODO make extra cases for ocps here! } @@ -5763,52 +5487,14 @@ else if n<cur_font_loc then else begin depth_threshold:=0; breadth_max:=1; show_node_list(equiv(n)); end; end -else if n<cat_code_base then @<Show the font identifier in |eqtb[n]|@> -else @<Show the halfword code in |eqtb[n]|@> +else if n=cur_font_loc then @<Show the font identifier in |eqtb[n]|@> @ @<Show the font identifier in |eqtb[n]|@>= -begin if n=cur_font_loc then print("current font") -else if n<math_font_base+script_size then - begin print_esc("textfont"); print_int(n-math_font_base); - end -else if n<math_font_base+script_script_size then - begin print_esc("scriptfont"); print_int(n-math_font_base-script_size); - end -else begin print_esc("scriptscriptfont"); print_int(n-math_font_base-script_script_size); - end; -print_char("=");@/ +begin print("current font"); print_char("=");@/ print_esc(hash[font_id_base+equiv(n)].rh); {that's |font_id_text(equiv(n))|} end -@ -@d is_omath(#)== ((((#) mod @"1000000) div @"10000)>15) or - (((#) mod @"10000)>255) - -@<Show the halfword code in |eqtb[n]|@>= -if n<math_code_base then - begin if n<lc_code_base then - begin print_esc("catcode"); print_int(n-cat_code_base); - end - else if n<uc_code_base then - begin print_esc("lccode"); print_int(n-lc_code_base); - end - else if n<sf_code_base then - begin print_esc("uccode"); print_int(n-uc_code_base); - end - else begin print_esc("sfcode"); print_int(n-sf_code_base); - end; - print_char("="); print_int(equiv(n)); - end -else begin - if is_omath(get_math_code(n-math_code_base)) then - print_esc("omathcode") - else - print_esc("mathcode"); - print_int(n-math_code_base); - print_char("="); print_int(get_math_code(n-math_code_base)); - end - @ Region 5 of |eqtb| contains the integer parameters and registers defined here, as well as the |del_code| table. The latter table differs from the |cat_code..math_code| tables that precede it, since delimiter codes are @@ -5828,10 +5514,8 @@ that will be defined later. @d broken_penalty_code=8 {penalty for breaking a page at a broken line} @d bin_op_penalty_code=9 {penalty for breaking after a binary operation} @d rel_penalty_code=10 {penalty for breaking after a relation} -@d pre_display_penalty_code=11 - {penalty for breaking just before a displayed formula} -@d post_display_penalty_code=12 - {penalty for breaking just after a displayed formula} +@d pre_display_penalty_code=11 {penalty for breaking just before a displayed formula} +@d post_display_penalty_code=12 {penalty for breaking just after a displayed formula} @d inter_line_penalty_code=13 {additional penalty between lines} @d double_hyphen_demerits_code=14 {demerits for double hyphen break} @d final_hyphen_demerits_code=15 {demerits for final hyphen break} @@ -5883,9 +5567,10 @@ that will be defined later. @d disable_lig_code=61 @d disable_kern_code=62 @d cat_code_table_code=63 -@d cur_lang_code=64 {current language id} -@d ex_hyphen_char_code=65 -@d tex_int_pars=66 {total number of \.{\\TeX} + Aleph integer parameters} +@d output_box_code=64 +@d cur_lang_code=65 {current language id} +@d ex_hyphen_char_code=66 +@d tex_int_pars=67 {total number of \.{\\TeX} + Aleph integer parameters} @# @d dir_base=int_base+tex_int_pars @d page_direction_code=0 @@ -5895,7 +5580,7 @@ that will be defined later. @d math_direction_code=4 @d dir_pars=5 @# -@d pdftex_first_integer_code = dir_base+dir_pars {base for \pdfTeX's integer parameters} +@d pdftex_first_integer_code = tex_int_pars+dir_pars {base for \pdfTeX's integer parameters} @d pdf_output_code = pdftex_first_integer_code + 0 {switch on PDF output if positive} @d pdf_compress_level_code = pdftex_first_integer_code + 1 {compress level of streams} @d pdf_decimal_digits_code = pdftex_first_integer_code + 2 {digits after the decimal point of numbers} @@ -5920,7 +5605,8 @@ that will be defined later. @d pdf_gen_tounicode_code = pdftex_first_integer_code + 24 {generate ToUnicode for fonts?} @d pdf_draftmode_code = pdftex_first_integer_code + 25 {switch on draftmode if positive} @d pdf_replace_font_code = pdftex_first_integer_code + 26 {generate ToUnicode for fonts?} -@d pdf_int_pars=pdftex_first_integer_code + 27 {total number of \pdfTeX's integer parameters} +@d pdf_inclusion_copy_font_code = pdftex_first_integer_code + 27 {generate ToUnicode for fonts?} +@d pdf_int_pars=pdftex_first_integer_code + 28 {total number of \pdfTeX's integer parameters} @# @d etex_int_base=pdf_int_pars {base for \eTeX's integer parameters} @d tracing_assigns_code=etex_int_base {show assignments} @@ -5933,9 +5619,13 @@ that will be defined later. @d saving_vdiscards_code=etex_int_base+7 {save items discarded from vlists} @d saving_hyph_codes_code=etex_int_base+8 {save hyphenation codes for languages} @d suppress_fontnotfound_error_code=etex_int_base+9 {surpress errors for missing fonts} -@d etex_int_pars=etex_int_base+10 {total number of \eTeX's integer parameters} +@d suppress_long_error_code=etex_int_base+10 {surpress errors for missing fonts} +@d suppress_ifcsname_error_code=etex_int_base+11 {surpress errors for failed \.{\\ifcsname}} +@d suppress_outer_error_code=etex_int_base+12 {surpress errors for \.{\\outer}} +@d etex_int_pars=etex_int_base+13 {total number of \eTeX's integer parameters} @# -@d int_pars=etex_int_pars {total number of integer parameters} +@d synctex_code=etex_int_pars { is synctex file generation enabled ? } +@d int_pars=synctex_code+1 {total number of integer parameters} @d count_base=int_base+int_pars {|number_regs| user \.{\\count} registers} @d attribute_base=count_base+number_regs {|number_attrs| user \.{\\attribute} registers} @d del_code_base=attribute_base+number_attrs {|number_chars| delimiter code mappings} @@ -6016,6 +5706,7 @@ that will be defined later. @d disable_lig==int_par(disable_lig_code) @d disable_kern==int_par(disable_kern_code) @d cat_code_table==int_par(cat_code_table_code) +@d output_box==int_par(output_box_code) @# @d pdf_adjust_spacing == int_par(pdf_adjust_spacing_code) @d pdf_protrude_chars == int_par(pdf_protrude_chars_code) @@ -6040,6 +5731,7 @@ that will be defined later. @d pdf_image_hicolor == int_par(pdf_image_hicolor_code) @d pdf_image_apply_gamma == int_par(pdf_image_apply_gamma_code) @d pdf_draftmode == int_par(pdf_draftmode_code) +@d pdf_inclusion_copy_font == int_par(pdf_inclusion_copy_font_code) @d pdf_replace_font == int_par(pdf_replace_font_code) @# @d tracing_assigns==int_par(tracing_assigns_code) @@ -6052,11 +5744,18 @@ that will be defined later. @d saving_vdiscards==int_par(saving_vdiscards_code) @d saving_hyph_codes==int_par(saving_hyph_codes_code) @d suppress_fontnotfound_error==int_par(suppress_fontnotfound_error_code) +@d suppress_long_error==int_par(suppress_long_error_code) +@d suppress_ifcsname_error==int_par(suppress_ifcsname_error_code) +@d synctex==int_par(synctex_code) @<Assign the values |depth_threshold:=show_box_depth|...@>= depth_threshold:=show_box_depth; breadth_max:=show_box_breadth + +@ @<Set init...@>= +static_dimen_base:=dimen_base; + @ We can print the symbolic name of an integer parameter as follows. @p procedure print_param(@!n:integer); @@ -6122,6 +5821,7 @@ luastartup_id_code:print_esc("luastartup"); disable_lig_code:print_esc("noligs"); disable_kern_code:print_esc("nokerns"); cat_code_table_code:print_esc("catcodetable"); +output_box_code:print_esc("outputbox"); @# local_inter_line_penalty_code: print_esc("localinterlinepenalty"); local_broken_penalty_code: print_esc("localbrokenpenalty"); @@ -6153,6 +5853,7 @@ pdf_protrude_chars_code: print_esc("pdfprotrudechars"); pdf_tracing_fonts_code: print_esc("pdftracingfonts"); pdf_gen_tounicode_code: print_esc("pdfgentounicode"); pdf_draftmode_code: print_esc("pdfdraftmode"); +pdf_inclusion_copy_font_code: print_esc("pdfinclusioncopyfonts"); pdf_replace_font_code: print_esc("pdfreplacefont"); @/@<Cases for |print_param|@>@/ othercases begin print("[unknown integer parameter!]"); end @@ -6162,189 +5863,183 @@ end; @ The integer parameter names must be entered into the hash table. @<Put each...@>= -primitive("pretolerance",assign_int,int_base+pretolerance_code);@/ +primitive_tex("pretolerance",assign_int,int_base+pretolerance_code,int_base);@/ @!@:pretolerance_}{\.{\\pretolerance} primitive@> -primitive("tolerance",assign_int,int_base+tolerance_code);@/ +primitive_tex("tolerance",assign_int,int_base+tolerance_code,int_base);@/ @!@:tolerance_}{\.{\\tolerance} primitive@> -primitive("linepenalty",assign_int,int_base+line_penalty_code);@/ +primitive_tex("linepenalty",assign_int,int_base+line_penalty_code,int_base);@/ @!@:line_penalty_}{\.{\\linepenalty} primitive@> -primitive("hyphenpenalty",assign_int,int_base+hyphen_penalty_code);@/ +primitive_tex("hyphenpenalty",assign_int,int_base+hyphen_penalty_code,int_base);@/ @!@:hyphen_penalty_}{\.{\\hyphenpenalty} primitive@> -primitive("exhyphenpenalty",assign_int,int_base+ex_hyphen_penalty_code);@/ +primitive_tex("exhyphenpenalty",assign_int,int_base+ex_hyphen_penalty_code,int_base);@/ @!@:ex_hyphen_penalty_}{\.{\\exhyphenpenalty} primitive@> -primitive("clubpenalty",assign_int,int_base+club_penalty_code);@/ +primitive_tex("clubpenalty",assign_int,int_base+club_penalty_code,int_base);@/ @!@:club_penalty_}{\.{\\clubpenalty} primitive@> -primitive("widowpenalty",assign_int,int_base+widow_penalty_code);@/ +primitive_tex("widowpenalty",assign_int,int_base+widow_penalty_code,int_base);@/ @!@:widow_penalty_}{\.{\\widowpenalty} primitive@> -primitive("displaywidowpenalty", - assign_int,int_base+display_widow_penalty_code);@/ +primitive_tex("displaywidowpenalty", assign_int,int_base+display_widow_penalty_code,int_base);@/ @!@:display_widow_penalty_}{\.{\\displaywidowpenalty} primitive@> -primitive("brokenpenalty",assign_int,int_base+broken_penalty_code);@/ +primitive_tex("brokenpenalty",assign_int,int_base+broken_penalty_code,int_base);@/ @!@:broken_penalty_}{\.{\\brokenpenalty} primitive@> -primitive("binoppenalty",assign_int,int_base+bin_op_penalty_code);@/ +primitive_tex("binoppenalty",assign_int,int_base+bin_op_penalty_code,int_base);@/ @!@:bin_op_penalty_}{\.{\\binoppenalty} primitive@> -primitive("relpenalty",assign_int,int_base+rel_penalty_code);@/ +primitive_tex("relpenalty",assign_int,int_base+rel_penalty_code,int_base);@/ @!@:rel_penalty_}{\.{\\relpenalty} primitive@> -primitive("predisplaypenalty",assign_int,int_base+pre_display_penalty_code);@/ +primitive_tex("predisplaypenalty",assign_int,int_base+pre_display_penalty_code,int_base);@/ @!@:pre_display_penalty_}{\.{\\predisplaypenalty} primitive@> -primitive("postdisplaypenalty",assign_int,int_base+post_display_penalty_code);@/ +primitive_tex("postdisplaypenalty",assign_int,int_base+post_display_penalty_code,int_base);@/ @!@:post_display_penalty_}{\.{\\postdisplaypenalty} primitive@> -primitive("interlinepenalty",assign_int,int_base+inter_line_penalty_code);@/ +primitive_tex("interlinepenalty",assign_int,int_base+inter_line_penalty_code,int_base);@/ @!@:inter_line_penalty_}{\.{\\interlinepenalty} primitive@> -primitive("doublehyphendemerits", - assign_int,int_base+double_hyphen_demerits_code);@/ +primitive_tex("doublehyphendemerits", assign_int,int_base+double_hyphen_demerits_code,int_base);@/ @!@:double_hyphen_demerits_}{\.{\\doublehyphendemerits} primitive@> -primitive("finalhyphendemerits", - assign_int,int_base+final_hyphen_demerits_code);@/ +primitive_tex("finalhyphendemerits", assign_int,int_base+final_hyphen_demerits_code,int_base);@/ @!@:final_hyphen_demerits_}{\.{\\finalhyphendemerits} primitive@> -primitive("adjdemerits",assign_int,int_base+adj_demerits_code);@/ +primitive_tex("adjdemerits",assign_int,int_base+adj_demerits_code,int_base);@/ @!@:adj_demerits_}{\.{\\adjdemerits} primitive@> -primitive("mag",assign_int,int_base+mag_code);@/ +primitive_tex("mag",assign_int,int_base+mag_code,int_base);@/ @!@:mag_}{\.{\\mag} primitive@> -primitive("delimiterfactor",assign_int,int_base+delimiter_factor_code);@/ +primitive_tex("delimiterfactor",assign_int,int_base+delimiter_factor_code,int_base);@/ @!@:delimiter_factor_}{\.{\\delimiterfactor} primitive@> -primitive("looseness",assign_int,int_base+looseness_code);@/ +primitive_tex("looseness",assign_int,int_base+looseness_code,int_base);@/ @!@:looseness_}{\.{\\looseness} primitive@> -primitive("time",assign_int,int_base+time_code);@/ +primitive_tex("time",assign_int,int_base+time_code,int_base);@/ @!@:time_}{\.{\\time} primitive@> -primitive("day",assign_int,int_base+day_code);@/ +primitive_tex("day",assign_int,int_base+day_code,int_base);@/ @!@:day_}{\.{\\day} primitive@> -primitive("month",assign_int,int_base+month_code);@/ +primitive_tex("month",assign_int,int_base+month_code,int_base);@/ @!@:month_}{\.{\\month} primitive@> -primitive("year",assign_int,int_base+year_code);@/ +primitive_tex("year",assign_int,int_base+year_code,int_base);@/ @!@:year_}{\.{\\year} primitive@> -primitive("showboxbreadth",assign_int,int_base+show_box_breadth_code);@/ +primitive_tex("showboxbreadth",assign_int,int_base+show_box_breadth_code,int_base);@/ @!@:show_box_breadth_}{\.{\\showboxbreadth} primitive@> -primitive("showboxdepth",assign_int,int_base+show_box_depth_code);@/ +primitive_tex("showboxdepth",assign_int,int_base+show_box_depth_code,int_base);@/ @!@:show_box_depth_}{\.{\\showboxdepth} primitive@> -primitive("hbadness",assign_int,int_base+hbadness_code);@/ +primitive_tex("hbadness",assign_int,int_base+hbadness_code,int_base);@/ @!@:hbadness_}{\.{\\hbadness} primitive@> -primitive("vbadness",assign_int,int_base+vbadness_code);@/ +primitive_tex("vbadness",assign_int,int_base+vbadness_code,int_base);@/ @!@:vbadness_}{\.{\\vbadness} primitive@> -primitive("pausing",assign_int,int_base+pausing_code);@/ +primitive_tex("pausing",assign_int,int_base+pausing_code,int_base);@/ @!@:pausing_}{\.{\\pausing} primitive@> -primitive("tracingonline",assign_int,int_base+tracing_online_code);@/ +primitive_tex("tracingonline",assign_int,int_base+tracing_online_code,int_base);@/ @!@:tracing_online_}{\.{\\tracingonline} primitive@> -primitive("tracingmacros",assign_int,int_base+tracing_macros_code);@/ +primitive_tex("tracingmacros",assign_int,int_base+tracing_macros_code,int_base);@/ @!@:tracing_macros_}{\.{\\tracingmacros} primitive@> -primitive("tracingstats",assign_int,int_base+tracing_stats_code);@/ +primitive_tex("tracingstats",assign_int,int_base+tracing_stats_code,int_base);@/ @!@:tracing_stats_}{\.{\\tracingstats} primitive@> -primitive("tracingparagraphs",assign_int,int_base+tracing_paragraphs_code);@/ +primitive_tex("tracingparagraphs",assign_int,int_base+tracing_paragraphs_code,int_base);@/ @!@:tracing_paragraphs_}{\.{\\tracingparagraphs} primitive@> -primitive("tracingpages",assign_int,int_base+tracing_pages_code);@/ +primitive_tex("tracingpages",assign_int,int_base+tracing_pages_code,int_base);@/ @!@:tracing_pages_}{\.{\\tracingpages} primitive@> -primitive("tracingoutput",assign_int,int_base+tracing_output_code);@/ +primitive_tex("tracingoutput",assign_int,int_base+tracing_output_code,int_base);@/ @!@:tracing_output_}{\.{\\tracingoutput} primitive@> -primitive("tracinglostchars",assign_int,int_base+tracing_lost_chars_code);@/ +primitive_tex("tracinglostchars",assign_int,int_base+tracing_lost_chars_code,int_base);@/ @!@:tracing_lost_chars_}{\.{\\tracinglostchars} primitive@> -primitive("tracingcommands",assign_int,int_base+tracing_commands_code);@/ +primitive_tex("tracingcommands",assign_int,int_base+tracing_commands_code,int_base);@/ @!@:tracing_commands_}{\.{\\tracingcommands} primitive@> -primitive("tracingrestores",assign_int,int_base+tracing_restores_code);@/ +primitive_tex("tracingrestores",assign_int,int_base+tracing_restores_code,int_base);@/ @!@:tracing_restores_}{\.{\\tracingrestores} primitive@> -primitive("uchyph",assign_int,int_base+uc_hyph_code);@/ +primitive_tex("uchyph",assign_int,int_base+uc_hyph_code,int_base);@/ @!@:uc_hyph_}{\.{\\uchyph} primitive@> -primitive("outputpenalty",assign_int,int_base+output_penalty_code);@/ +primitive_tex("outputpenalty",assign_int,int_base+output_penalty_code,int_base);@/ @!@:output_penalty_}{\.{\\outputpenalty} primitive@> -primitive("maxdeadcycles",assign_int,int_base+max_dead_cycles_code);@/ +primitive_tex("maxdeadcycles",assign_int,int_base+max_dead_cycles_code,int_base);@/ @!@:max_dead_cycles_}{\.{\\maxdeadcycles} primitive@> -primitive("hangafter",assign_int,int_base+hang_after_code);@/ +primitive_tex("hangafter",assign_int,int_base+hang_after_code,int_base);@/ @!@:hang_after_}{\.{\\hangafter} primitive@> -primitive("floatingpenalty",assign_int,int_base+floating_penalty_code);@/ +primitive_tex("floatingpenalty",assign_int,int_base+floating_penalty_code,int_base);@/ @!@:floating_penalty_}{\.{\\floatingpenalty} primitive@> -primitive("globaldefs",assign_int,int_base+global_defs_code);@/ +primitive_tex("globaldefs",assign_int,int_base+global_defs_code,int_base);@/ @!@:global_defs_}{\.{\\globaldefs} primitive@> -primitive("fam",assign_int,int_base+cur_fam_code);@/ +primitive_tex("fam",assign_int,int_base+cur_fam_code,int_base);@/ @!@:fam_}{\.{\\fam} primitive@> -primitive("escapechar",assign_int,int_base+escape_char_code);@/ +primitive_tex("escapechar",assign_int,int_base+escape_char_code,int_base);@/ @!@:escape_char_}{\.{\\escapechar} primitive@> -primitive("defaulthyphenchar",assign_int,int_base+default_hyphen_char_code);@/ +primitive_tex("defaulthyphenchar",assign_int,int_base+default_hyphen_char_code,int_base);@/ @!@:default_hyphen_char_}{\.{\\defaulthyphenchar} primitive@> -primitive("defaultskewchar",assign_int,int_base+default_skew_char_code);@/ +primitive_tex("defaultskewchar",assign_int,int_base+default_skew_char_code,int_base);@/ @!@:default_skew_char_}{\.{\\defaultskewchar} primitive@> -primitive("endlinechar",assign_int,int_base+end_line_char_code);@/ +primitive_tex("endlinechar",assign_int,int_base+end_line_char_code,int_base);@/ @!@:end_line_char_}{\.{\\endlinechar} primitive@> -primitive("newlinechar",assign_int,int_base+new_line_char_code);@/ +primitive_tex("newlinechar",assign_int,int_base+new_line_char_code,int_base);@/ @!@:new_line_char_}{\.{\\newlinechar} primitive@> -primitive("language",assign_int,int_base+language_code);@/ +primitive_tex("language",assign_int,int_base+language_code,int_base);@/ @!@:language_}{\.{\\language} primitive@> -primitive("setlanguage",assign_int,int_base+cur_lang_code);@/ +primitive_tex("setlanguage",assign_int,int_base+cur_lang_code,int_base);@/ @!@:cur_lang_}{\.{\\setlanguage} primitive@> -primitive("exhyphenchar",assign_int,int_base+ex_hyphen_char_code);@/ +primitive_tex("exhyphenchar",assign_int,int_base+ex_hyphen_char_code,int_base);@/ @!@:ex_hyphen_char_}{\.{\\exhyphenchar} primitive@> -primitive("lefthyphenmin",assign_int,int_base+left_hyphen_min_code);@/ +primitive_tex("lefthyphenmin",assign_int,int_base+left_hyphen_min_code,int_base);@/ @!@:left_hyphen_min_}{\.{\\lefthyphenmin} primitive@> -primitive("righthyphenmin",assign_int,int_base+right_hyphen_min_code);@/ +primitive_tex("righthyphenmin",assign_int,int_base+right_hyphen_min_code,int_base);@/ @!@:right_hyphen_min_}{\.{\\righthyphenmin} primitive@> -primitive("holdinginserts",assign_int,int_base+holding_inserts_code);@/ +primitive_tex("holdinginserts",assign_int,int_base+holding_inserts_code,int_base);@/ @!@:holding_inserts_}{\.{\\holdinginserts} primitive@> -primitive("errorcontextlines",assign_int,int_base+error_context_lines_code);@/ +primitive_tex("errorcontextlines",assign_int,int_base+error_context_lines_code,int_base);@/ @!@:error_context_lines_}{\.{\\errorcontextlines} primitive@> -primitive("luastartup",assign_int,int_base+luastartup_id_code);@/ +primitive_luatex("luastartup",assign_int,int_base+luastartup_id_code,int_base);@/ @!@:luastartup_id_}{\.{\\luastartup} primitive@> -primitive("nokerns",assign_int,int_base+disable_kern_code);@/ +primitive_luatex("nokerns",assign_int,int_base+disable_kern_code,int_base);@/ @!@:disable_kern_}{\.{\\noligkerns} primitive@> -primitive("noligs",assign_int,int_base+disable_lig_code);@/ +primitive_luatex("noligs",assign_int,int_base+disable_lig_code,int_base);@/ @!@:disable_lig_}{\.{\\noligs} primitive@> -primitive("catcodetable",assign_int,int_base+cat_code_table_code);@/ +primitive_luatex("catcodetable",assign_int,int_base+cat_code_table_code,int_base);@/ @!@:cat_code_table_}{\.{\\catcodetable} primitive@> -primitive("pdfoutput",assign_int,int_base+pdf_output_code);@/ +primitive_luatex("outputbox",assign_int,int_base+output_box_code,int_base);@/ +@!@:output_box_}{\.{\\outputbox} primitive@> +primitive_pdftex("pdfoutput",assign_int,int_base+pdf_output_code,int_base);@/ @!@:pdf_output_}{\.{\\pdfoutput} primitive@> -primitive("pdfcompresslevel",assign_int,int_base+pdf_compress_level_code);@/ +primitive_pdftex("pdfcompresslevel",assign_int,int_base+pdf_compress_level_code,int_base);@/ @!@:pdf_compress_level_}{\.{\\pdfcompresslevel} primitive@> -primitive("pdfobjcompresslevel",assign_int,int_base+pdf_objcompresslevel_code);@/ +primitive_pdftex("pdfobjcompresslevel",assign_int,int_base+pdf_objcompresslevel_code,int_base);@/ @!@:pdf_objcompresslevel_}{\.{\\pdfobjcompresslevel} primitive@> -primitive("pdfdecimaldigits",assign_int,int_base+pdf_decimal_digits_code);@/ +primitive_pdftex("pdfdecimaldigits",assign_int,int_base+pdf_decimal_digits_code,int_base);@/ @!@:pdf_decimal_digits_}{\.{\\pdfdecimaldigits} primitive@> -primitive("pdfmovechars",assign_int,int_base+pdf_move_chars_code);@/ +primitive_pdftex("pdfmovechars",assign_int,int_base+pdf_move_chars_code,int_base);@/ @!@:pdf_move_chars_}{\.{\\pdfmovechars} primitive@> -primitive("pdfimageresolution",assign_int,int_base+pdf_image_resolution_code);@/ +primitive_pdftex("pdfimageresolution",assign_int,int_base+pdf_image_resolution_code,int_base);@/ @!@:pdf_image_resolution_}{\.{\\pdfimageresolution} primitive@> -primitive("pdfpkresolution",assign_int,int_base+pdf_pk_resolution_code);@/ +primitive_pdftex("pdfpkresolution",assign_int,int_base+pdf_pk_resolution_code,int_base);@/ @!@:pdf_pk_resolution_}{\.{\\pdfpkresolution} primitive@> -primitive("pdfuniqueresname",assign_int,int_base+pdf_unique_resname_code);@/ +primitive_pdftex("pdfuniqueresname",assign_int,int_base+pdf_unique_resname_code,int_base);@/ @!@:pdf_unique_resname_}{\.{\\pdfuniqueresname} primitive@> -primitive("pdfoptionpdfminorversion",assign_int,int_base+pdf_minor_version_code);@/ +primitive_pdftex("pdfoptionpdfminorversion",assign_int,int_base+pdf_minor_version_code,int_base);@/ @!@:pdf_minor_version_}{\.{\\pdfoptionpdfminorversion} primitive@> -primitive("pdfoptionalwaysusepdfpagebox",assign_int,int_base+pdf_option_always_use_pdfpagebox_code);@/ +primitive_pdftex("pdfoptionalwaysusepdfpagebox",assign_int,int_base+pdf_option_always_use_pdfpagebox_code,int_base);@/ @!@:pdf_option_always_use_pdfpagebox_}{\.{\\pdfoptionalwaysusepdfpagebox} primitive@> -primitive("pdfoptionpdfinclusionerrorlevel",assign_int,int_base+pdf_option_pdf_inclusion_errorlevel_code);@/ +primitive_pdftex("pdfoptionpdfinclusionerrorlevel",assign_int,int_base+pdf_option_pdf_inclusion_errorlevel_code,int_base);@/ @!@:pdf_option_pdf_inclusion_errorlevel_}{\.{\\pdfoptionpdfinclusionerrorlevel} primitive@> -primitive("pdfminorversion",assign_int,int_base+pdf_minor_version_code);@/ +primitive_pdftex("pdfminorversion",assign_int,int_base+pdf_minor_version_code,int_base);@/ @!@:pdf_minor_version_}{\.{\\pdfminorversion} primitive@> -primitive("pdfforcepagebox",assign_int,int_base+pdf_force_pagebox_code);@/ +primitive_pdftex("pdfforcepagebox",assign_int,int_base+pdf_force_pagebox_code,int_base);@/ @!@:pdf_force_pagebox_}{\.{\\pdfforcepagebox} primitive@> -primitive("pdfpagebox",assign_int,int_base+pdf_pagebox_code);@/ +primitive_pdftex("pdfpagebox",assign_int,int_base+pdf_pagebox_code,int_base);@/ @!@:pdf_pagebox_}{\.{\\pdfpagebox} primitive@> -primitive("pdfinclusionerrorlevel",assign_int,int_base+pdf_inclusion_errorlevel_code);@/ +primitive_pdftex("pdfinclusionerrorlevel",assign_int,int_base+pdf_inclusion_errorlevel_code,int_base);@/ @!@:pdf_inclusion_errorlevel_}{\.{\\pdfinclusionerrorlevel} primitive@> -primitive("pdfgamma",assign_int,int_base+pdf_gamma_code);@/ +primitive_pdftex("pdfgamma",assign_int,int_base+pdf_gamma_code,int_base);@/ @!@:pdf_gamma_}{\.{\\pdfgamma} primitive@> -primitive("pdfimagegamma",assign_int,int_base+pdf_image_gamma_code);@/ +primitive_pdftex("pdfimagegamma",assign_int,int_base+pdf_image_gamma_code,int_base);@/ @!@:pdf_image_gamma_}{\.{\\pdfimagegamma} primitive@> -primitive("pdfimagehicolor",assign_int,int_base+pdf_image_hicolor_code);@/ +primitive_pdftex("pdfimagehicolor",assign_int,int_base+pdf_image_hicolor_code,int_base);@/ @!@:pdf_image_hicolor_}{\.{\\pdfimagehicolor} primitive@> -primitive("pdfimageapplygamma",assign_int,int_base+pdf_image_apply_gamma_code);@/ +primitive_pdftex("pdfimageapplygamma",assign_int,int_base+pdf_image_apply_gamma_code,int_base);@/ @!@:pdf_image_apply_gamma_}{\.{\\pdfimageapplygamma} primitive@> -primitive("pdfadjustspacing",assign_int,int_base+pdf_adjust_spacing_code);@/ +primitive_pdftex("pdfadjustspacing",assign_int,int_base+pdf_adjust_spacing_code,int_base);@/ @!@:pdf_adjust_spacing_}{\.{\\pdfadjustspacing} primitive@> -primitive("pdfprotrudechars",assign_int,int_base+pdf_protrude_chars_code);@/ +primitive_pdftex("pdfprotrudechars",assign_int,int_base+pdf_protrude_chars_code,int_base);@/ @!@:pdf_protrude_chars_}{\.{\\pdfprotrudechars} primitive@> -primitive("pdftracingfonts",assign_int,int_base+pdf_tracing_fonts_code);@/ +primitive_pdftex("pdftracingfonts",assign_int,int_base+pdf_tracing_fonts_code,int_base);@/ @!@:pdf_tracing_fonts_}{\.{\\pdftracingfonts} primitive@> -primitive("pdfgentounicode",assign_int,int_base+pdf_gen_tounicode_code);@/ +primitive_pdftex("pdfgentounicode",assign_int,int_base+pdf_gen_tounicode_code,int_base);@/ @!@:pdf_gen_tounicode_}{\.{\\pdfgentounicode} primitive@> -primitive("pdfdraftmode",assign_int,int_base+pdf_draftmode_code);@/ +primitive_pdftex("pdfdraftmode",assign_int,int_base+pdf_draftmode_code,int_base);@/ @!@:pdf_draftmode_}{\.{\\pdfdraftmode} primitive@> -primitive("pdfreplacefont",assign_int,int_base+pdf_replace_font_code);@/ +primitive_pdftex("pdfinclusioncopyfonts",assign_int,int_base+pdf_inclusion_copy_font_code,int_base);@/ +@!@:pdf_inclusion_copy_font_}{\.{\\pdfinclusioncopyfonts} primitive@> +primitive_pdftex("pdfreplacefont",assign_int,int_base+pdf_replace_font_code,int_base);@/ @!@:pdf_replace_font_}{\.{\\pdfreplacefont} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -assign_int: if chr_code<count_base then print_param(chr_code-int_base) - else begin print_esc("count"); print_int(chr_code-count_base); - end; -assign_attr: begin print_esc("attribute"); print_int(chr_code-attribute_base); - end; - @ The integer parameters should really be initialized by a macro package; the following initialization does the minimum to keep \TeX\ from complete failure. @@ -6356,8 +6051,9 @@ for k:=attribute_base to del_code_base-1 do eqtb[k].int:=-1; mag:=1000; tolerance:=10000; hang_after:=1; max_dead_cycles:=25; escape_char:="\"; end_line_char:=carriage_return; eqtb[int_base+level_local_dir_code].int:=level_one; -set_del_code(".",0,0,level_one); {this null delimiter is used in error recovery} +set_del_code(".",tex_mathcode,0,0,0,0,level_one); {this null delimiter is used in error recovery} ex_hyphen_char:="-"; +output_box:=255; @ The following procedure, which is called just before \TeX\ initializes its input and output, establishes the initial values of the date and time. @@ -6384,10 +6080,6 @@ else if n<attribute_base then else if n<del_code_base then begin print_esc("attribute"); print_int(n-attribute_base); print_char("="); print_int(eqtb[n].int); - end -else begin - {TH: todo, this stuff doesnt work} - print_esc("delcode"); end; end @@ -6444,9 +6136,11 @@ here, and the |number_regs| \.{\\dimen} registers. @d h_offset_code=18 {amount of horizontal offset when shipping pages out} @d v_offset_code=19 {amount of vertical offset when shipping pages out} @d emergency_stretch_code=20 {reduces badnesses on final pass of line-breaking} -@d page_right_offset_code=21 -@d page_bottom_offset_code=22 -@d pdftex_first_dimen_code = 23 {first number defined in this section} +@d page_left_offset_code=21 +@d page_top_offset_code=22 +@d page_right_offset_code=23 +@d page_bottom_offset_code=24 +@d pdftex_first_dimen_code = 25 {first number defined in this section} @d pdf_h_origin_code = pdftex_first_dimen_code + 0 {horigin of the PDF output} @d pdf_v_origin_code = pdftex_first_dimen_code + 1 {vorigin of the PDF output} @d page_width_code = pdftex_first_dimen_code + 2 {page width of the PDF output} @@ -6458,8 +6152,9 @@ here, and the |number_regs| \.{\\dimen} registers. @d pdf_last_line_depth_code = pdftex_first_dimen_code + 8 @d pdf_each_line_height_code = pdftex_first_dimen_code + 9 @d pdf_each_line_depth_code = pdftex_first_dimen_code + 10 -@d pdf_px_dimen_code = pdftex_first_dimen_code + 11 -@d pdftex_last_dimen_code = pdftex_first_dimen_code + 11 {last number defined in this section} +@d pdf_ignored_dimen_code = pdftex_first_dimen_code + 11 +@d pdf_px_dimen_code = pdftex_first_dimen_code + 12 +@d pdftex_last_dimen_code = pdftex_first_dimen_code + 12 {last number defined in this section} @d dimen_pars = pdftex_last_dimen_code + 1 {total number of dimension parameters} @d scaled_base=dimen_base+dimen_pars {table of |number_regs| user-defined \.{\\dimen} registers} @@ -6488,6 +6183,8 @@ here, and the |number_regs| \.{\\dimen} registers. @d h_offset==dimen_par(h_offset_code) @d v_offset==dimen_par(v_offset_code) @d emergency_stretch==dimen_par(emergency_stretch_code) +@d page_left_offset==dimen_par(page_left_offset_code) +@d page_top_offset==dimen_par(page_top_offset_code) @d page_right_offset==dimen_par(page_right_offset_code) @d page_bottom_offset==dimen_par(page_bottom_offset_code) @d pdf_h_origin == dimen_par(pdf_h_origin_code) @@ -6501,6 +6198,7 @@ here, and the |number_regs| \.{\\dimen} registers. @d pdf_last_line_depth == dimen_par(pdf_last_line_depth_code) @d pdf_each_line_height == dimen_par(pdf_each_line_height_code) @d pdf_each_line_depth == dimen_par(pdf_each_line_depth_code) +@d pdf_ignored_dimen == dimen_par(pdf_ignored_dimen_code) @d pdf_px_dimen == dimen_par(pdf_px_dimen_code) @p procedure print_length_param(@!n:integer); @@ -6526,7 +6224,9 @@ hang_indent_code:print_esc("hangindent"); h_offset_code:print_esc("hoffset"); v_offset_code:print_esc("voffset"); emergency_stretch_code:print_esc("emergencystretch"); -page_right_offset_code:print_esc("pagerightoffset"); +page_left_offset_code: print_esc("pageleftoffset"); +page_top_offset_code: print_esc("pagetopoffset"); +page_right_offset_code: print_esc("pagerightoffset"); page_bottom_offset_code:print_esc("pagebottomoffset"); pdf_h_origin_code: print_esc("pdfhorigin"); pdf_v_origin_code: print_esc("pdfvorigin"); @@ -6539,93 +6239,100 @@ pdf_first_line_height_code: print_esc("pdffirstlineheight"); pdf_last_line_depth_code: print_esc("pdflastlinedepth"); pdf_each_line_height_code: print_esc("pdfeachlineheight"); pdf_each_line_depth_code: print_esc("pdfeachlinedepth"); +pdf_ignored_dimen_code: print_esc("pdfignoreddimen"); pdf_px_dimen_code: print_esc("pdfpxdimen"); othercases print("[unknown dimen parameter!]") endcases; end; @ @<Put each...@>= -primitive("parindent",assign_dimen,dimen_base+par_indent_code);@/ +primitive_tex("parindent",assign_dimen,dimen_base+par_indent_code,dimen_base);@/ @!@:par_indent_}{\.{\\parindent} primitive@> -primitive("mathsurround",assign_dimen,dimen_base+math_surround_code);@/ +primitive_tex("mathsurround",assign_dimen,dimen_base+math_surround_code,dimen_base);@/ @!@:math_surround_}{\.{\\mathsurround} primitive@> -primitive("lineskiplimit",assign_dimen,dimen_base+line_skip_limit_code);@/ +primitive_tex("lineskiplimit",assign_dimen,dimen_base+line_skip_limit_code,dimen_base);@/ @!@:line_skip_limit_}{\.{\\lineskiplimit} primitive@> -primitive("hsize",assign_dimen,dimen_base+hsize_code);@/ +primitive_tex("hsize",assign_dimen,dimen_base+hsize_code,dimen_base);@/ @!@:hsize_}{\.{\\hsize} primitive@> -primitive("vsize",assign_dimen,dimen_base+vsize_code);@/ +primitive_tex("vsize",assign_dimen,dimen_base+vsize_code,dimen_base);@/ @!@:vsize_}{\.{\\vsize} primitive@> -primitive("maxdepth",assign_dimen,dimen_base+max_depth_code);@/ +primitive_tex("maxdepth",assign_dimen,dimen_base+max_depth_code,dimen_base);@/ @!@:max_depth_}{\.{\\maxdepth} primitive@> -primitive("splitmaxdepth",assign_dimen,dimen_base+split_max_depth_code);@/ +primitive_tex("splitmaxdepth",assign_dimen,dimen_base+split_max_depth_code,dimen_base);@/ @!@:split_max_depth_}{\.{\\splitmaxdepth} primitive@> -primitive("boxmaxdepth",assign_dimen,dimen_base+box_max_depth_code);@/ +primitive_tex("boxmaxdepth",assign_dimen,dimen_base+box_max_depth_code,dimen_base);@/ @!@:box_max_depth_}{\.{\\boxmaxdepth} primitive@> -primitive("hfuzz",assign_dimen,dimen_base+hfuzz_code);@/ +primitive_tex("hfuzz",assign_dimen,dimen_base+hfuzz_code,dimen_base);@/ @!@:hfuzz_}{\.{\\hfuzz} primitive@> -primitive("vfuzz",assign_dimen,dimen_base+vfuzz_code);@/ +primitive_tex("vfuzz",assign_dimen,dimen_base+vfuzz_code,dimen_base);@/ @!@:vfuzz_}{\.{\\vfuzz} primitive@> -primitive("delimitershortfall", - assign_dimen,dimen_base+delimiter_shortfall_code);@/ +primitive_tex("delimitershortfall", assign_dimen,dimen_base+delimiter_shortfall_code,dimen_base);@/ @!@:delimiter_shortfall_}{\.{\\delimitershortfall} primitive@> -primitive("nulldelimiterspace", - assign_dimen,dimen_base+null_delimiter_space_code);@/ +primitive_tex("nulldelimiterspace", assign_dimen,dimen_base+null_delimiter_space_code,dimen_base);@/ @!@:null_delimiter_space_}{\.{\\nulldelimiterspace} primitive@> -primitive("scriptspace",assign_dimen,dimen_base+script_space_code);@/ +primitive_tex("scriptspace",assign_dimen,dimen_base+script_space_code,dimen_base);@/ @!@:script_space_}{\.{\\scriptspace} primitive@> -primitive("predisplaysize",assign_dimen,dimen_base+pre_display_size_code);@/ +primitive_tex("predisplaysize",assign_dimen,dimen_base+pre_display_size_code,dimen_base);@/ @!@:pre_display_size_}{\.{\\predisplaysize} primitive@> -primitive("displaywidth",assign_dimen,dimen_base+display_width_code);@/ +primitive_tex("displaywidth",assign_dimen,dimen_base+display_width_code,dimen_base);@/ @!@:display_width_}{\.{\\displaywidth} primitive@> -primitive("displayindent",assign_dimen,dimen_base+display_indent_code);@/ +primitive_tex("displayindent",assign_dimen,dimen_base+display_indent_code,dimen_base);@/ @!@:display_indent_}{\.{\\displayindent} primitive@> -primitive("overfullrule",assign_dimen,dimen_base+overfull_rule_code);@/ +primitive_tex("overfullrule",assign_dimen,dimen_base+overfull_rule_code,dimen_base);@/ @!@:overfull_rule_}{\.{\\overfullrule} primitive@> -primitive("hangindent",assign_dimen,dimen_base+hang_indent_code);@/ +primitive_tex("hangindent",assign_dimen,dimen_base+hang_indent_code,dimen_base);@/ @!@:hang_indent_}{\.{\\hangindent} primitive@> -primitive("hoffset",assign_dimen,dimen_base+h_offset_code);@/ +primitive_tex("hoffset",assign_dimen,dimen_base+h_offset_code,dimen_base);@/ @!@:h_offset_}{\.{\\hoffset} primitive@> -primitive("voffset",assign_dimen,dimen_base+v_offset_code);@/ +primitive_tex("voffset",assign_dimen,dimen_base+v_offset_code,dimen_base);@/ @!@:v_offset_}{\.{\\voffset} primitive@> -primitive("emergencystretch",assign_dimen,dimen_base+emergency_stretch_code);@/ +primitive_tex("emergencystretch",assign_dimen,dimen_base+emergency_stretch_code,dimen_base);@/ @!@:emergency_stretch_}{\.{\\emergencystretch} primitive@> -primitive("pdfhorigin",assign_dimen,dimen_base+pdf_h_origin_code);@/ +primitive_pdftex("pdfhorigin",assign_dimen,dimen_base+pdf_h_origin_code,dimen_base);@/ @!@:pdf_h_origin_}{\.{\\pdfhorigin} primitive@> -primitive("pdfvorigin",assign_dimen,dimen_base+pdf_v_origin_code);@/ +primitive_pdftex("pdfvorigin",assign_dimen,dimen_base+pdf_v_origin_code,dimen_base);@/ @!@:pdf_v_origin_}{\.{\\pdfvorigin} primitive@> @# -primitive("pagewidth",assign_dimen,dimen_base+page_width_code);@/ -primitive("pdfpagewidth",assign_dimen,dimen_base+page_width_code);@/ +primitive_omega("pagewidth",assign_dimen,dimen_base+page_width_code,dimen_base);@/ +primitive_pdftex("pdfpagewidth",assign_dimen,dimen_base+page_width_code,dimen_base);@/ @!@:page_width_}{\.{\\pdfpagewidth} primitive@> -primitive("pageheight",assign_dimen,dimen_base+page_height_code);@/ -primitive("pdfpageheight",assign_dimen,dimen_base+page_height_code);@/ +primitive_omega("pageheight",assign_dimen,dimen_base+page_height_code,dimen_base);@/ +primitive_pdftex("pdfpageheight",assign_dimen,dimen_base+page_height_code,dimen_base);@/ @!@:page_height_}{\.{\\pdfpageheight} primitive@> @# -primitive("pdflinkmargin",assign_dimen,dimen_base+pdf_link_margin_code);@/ +primitive_pdftex("pdflinkmargin",assign_dimen,dimen_base+pdf_link_margin_code,dimen_base);@/ @!@:pdf_link_margin_}{\.{\\pdflinkmargin} primitive@> -primitive("pdfdestmargin",assign_dimen,dimen_base+pdf_dest_margin_code);@/ +primitive_pdftex("pdfdestmargin",assign_dimen,dimen_base+pdf_dest_margin_code,dimen_base);@/ @!@:pdf_dest_margin_}{\.{\\pdfdestmargin} primitive@> -primitive("pdfthreadmargin",assign_dimen,dimen_base+pdf_thread_margin_code);@/ +primitive_pdftex("pdfthreadmargin",assign_dimen,dimen_base+pdf_thread_margin_code,dimen_base);@/ @!@:pdf_thread_margin_}{\.{\\pdfthreadmargin} primitive@> -primitive("pdffirstlineheight",assign_dimen,dimen_base+pdf_first_line_height_code);@/ +primitive_pdftex("pdffirstlineheight",assign_dimen,dimen_base+pdf_first_line_height_code,dimen_base);@/ @!@:pdf_first_line_height_}{\.{\\pdffirstlineheight} primitive@> -primitive("pdflastlinedepth",assign_dimen,dimen_base+pdf_last_line_depth_code);@/ +primitive_pdftex("pdflastlinedepth",assign_dimen,dimen_base+pdf_last_line_depth_code,dimen_base);@/ @!@:pdf_last_line_depth_}{\.{\\pdflastlinedepth} primitive@> -primitive("pdfeachlineheight",assign_dimen,dimen_base+pdf_each_line_height_code);@/ +primitive_pdftex("pdfeachlineheight",assign_dimen,dimen_base+pdf_each_line_height_code,dimen_base);@/ @!@:pdf_each_line_height_}{\.{\\pdfeachlineheight} primitive@> -primitive("pdfeachlinedepth",assign_dimen,dimen_base+pdf_each_line_depth_code);@/ +primitive_pdftex("pdfeachlinedepth",assign_dimen,dimen_base+pdf_each_line_depth_code,dimen_base);@/ @!@:pdf_each_line_depth_}{\.{\\pdfeachlinedepth} primitive@> -primitive("pdfpxdimen",assign_dimen,dimen_base+pdf_px_dimen_code);@/ +primitive_pdftex("pdfignoreddimen",assign_dimen,dimen_base+pdf_ignored_dimen_code,dimen_base);@/ +@!@:pdf_ignored_dimen_}{\.{\\pdfignoreddimen} primitive@> +primitive_pdftex("pdfpxdimen",assign_dimen,dimen_base+pdf_px_dimen_code,dimen_base);@/ @!@:pdf_px_dimen_}{\.{\\pdfpxdimen} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -assign_dimen: if chr_code<scaled_base then - print_length_param(chr_code-dimen_base) - else begin print_esc("dimen"); print_int(chr_code-scaled_base); - end; - @ @<Initialize table entries...@>= for k:=dimen_base to eqtb_size do eqtb[k].sc:=0; +page_left_offset := one_inch; +page_top_offset := one_inch; +page_right_offset := one_inch; +page_bottom_offset := one_inch; + +@ @<Initialize table entries...@>= +pdf_ignored_dimen := ignore_depth; +pdf_each_line_height := pdf_ignored_dimen; +pdf_each_line_depth := pdf_ignored_dimen; +pdf_first_line_height := pdf_ignored_dimen; +pdf_last_line_depth := pdf_ignored_dimen; + @ @<Show equivalent |n|, in region 6@>= begin if n<scaled_base then print_length_param(n-dimen_base) @@ -6637,9 +6344,9 @@ end @ Here is a procedure that displays the contents of |eqtb[n]| symbolically. -@p@t\4@>@<Declare the procedure called |print_cmd_chr|@>@;@/ +@p @!stat procedure show_eqtb(@!n:pointer); -begin if n<active_base then print_char("?") {this can't happen} +begin if n<null_cs then print_char("?") {this can't happen} else if n<glue_base then @<Show equivalent |n|, in region 1 or 2@> else if n<local_base then @<Show equivalent |n|, in region 3@> else if n<int_base then @<Show equivalent |n|, in region 4@> @@ -6655,8 +6362,8 @@ but \TeX\ needs to store the |eq_level| information in another array called |xeq_level|. @<Glob...@>= -@!eqtb:array[active_base..eqtb_size] of memory_word; -@!xeq_level:array[int_base..eqtb_size] of quarterword; +@!eqtb:array[null_cs..eqtb_size] of memory_word; +@!xeq_level:array[null_cs..eqtb_size] of quarterword; @ @<Set init...@>= for k:=int_base to eqtb_size do xeq_level[k]:=level_one; @@ -6701,50 +6408,10 @@ A global boolean variable called |no_new_control_sequence| is set to @!no_new_control_sequence:boolean; {are new identifiers legal?} @!cs_count:integer; {total number of known identifiers} -@ Primitive support needs a few extra variables and definitions - -@d prim_size=2100 {maximum number of primitives } -@d prim_prime=1777 {about 85\pct! of |primitive_size|} -@d prim_base=1 -@d prim_next(#) == prim[#].lh {link for coalesced lists} -@d prim_text(#) == prim[#].rh {string number for control sequence name} -@d prim_is_full == (prim_used=prim_base) {test if all positions are occupied} -@d prim_eq_level_field(#)==#.hh.b1 -@d prim_eq_type_field(#)==#.hh.b0 -@d prim_equiv_field(#)==#.hh.rh -@d prim_eq_level(#)==prim_eq_level_field(prim_eqtb[#]) {level of definition} -@d prim_eq_type(#)==prim_eq_type_field(prim_eqtb[#]) {command code for equivalent} -@d prim_equiv(#)==prim_equiv_field(prim_eqtb[#]) {equivalent value} -@d undefined_primitive=0 - -@<Glob...@>= -@!prim: array [0..prim_size] of two_halves; {the primitives table} -@!prim_used:pointer; {allocation pointer for |prim|} -@!prim_eqtb:array[0..prim_size] of memory_word; - @ The extra set of functions make sure we can query the primitive meanings of thing s from C code @p -function get_char_cat_code(c:integer):quarterword; -begin - if local_catcode_table then - get_char_cat_code:=get_cat_code(line_catcode_table,c) - else - get_char_cat_code:=get_cat_code(cat_code_table,c) -end; -function get_prim_eq_level(p:integer):quarterword; -begin - get_prim_eq_level := prim_eq_level(p); -end; -function get_prim_eq_type(p:integer):quarterword; -begin - get_prim_eq_type := prim_eq_type(p); -end; -function get_prim_equiv(p:integer):halfword; -begin - get_prim_equiv := prim_equiv(p); -end; function get_eq_type(p:integer):quarterword; begin get_eq_type := eq_type(p); @@ -6762,9 +6429,7 @@ begin get_equiv := equiv(p); end; function get_cs_text(cs:integer):str_number; -begin if cs<hash_base then - if cs<null_cs then get_cs_text := cs-active_base - else get_cs_text := "\csname\endcsname" +begin if cs=null_cs then get_cs_text := "\csname\endcsname" else if (text(cs)<0)or(text(cs)>=str_ptr) then get_cs_text := "" else get_cs_text := text(cs); end; @@ -6776,6 +6441,14 @@ function get_count_base:halfword; begin get_count_base := count_base; end; +function get_skip_base:halfword; +begin + get_skip_base := skip_base; +end; +function get_mu_skip_base:halfword; +begin + get_mu_skip_base := mu_skip_base; +end; function get_attribute_base:halfword; begin get_attribute_base := attribute_base; @@ -6788,10 +6461,18 @@ function get_int_base:halfword; begin get_int_base := int_base; end; +function get_dimen_base:halfword; +begin + get_dimen_base := dimen_base; +end; function get_toks_base:halfword; begin get_toks_base := toks_base; end; +function get_del_code_base:halfword; +begin + get_del_code_base := del_code_base; +end; function get_every_eof:halfword; begin get_every_eof := every_eof; @@ -6815,17 +6496,12 @@ end; @ @<Set init...@>= no_new_control_sequence:=true; {new identifiers are usually forbidden} -prim_next(0):=0; prim_text(0):=0; -for k:=1 to prim_size do prim[k]:=prim[0]; -prim_eq_level(0) := level_zero; -prim_eq_type(0) := undefined_cs; -prim_equiv(0) := null; -for k:=1 to prim_size do prim_eqtb[k]:=prim_eqtb[0]; +init_primitives; next(hash_base):=0; text(hash_base):=0; for k:=hash_base+1 to undefined_control_sequence-1 do hash[k]:=hash[hash_base]; @ @<Initialize table entries...@>= -prim_used:=prim_size; {nothing is used} +ini_init_primitives; hash_used:=frozen_control_sequence; {nothing is used} cs_count:=0; eq_type(frozen_dont_expand):=dont_expand; @@ -6837,166 +6513,6 @@ equiv(frozen_primitive):=1; eq_level(frozen_primitive):=level_one; text(frozen_primitive):="primitive"; -@ Here is the subroutine that searches the hash table for an identifier -that matches a given string of length |l>1| appearing in |buffer[j.. -(j+l-1)]|. If the identifier is found, the corresponding hash table address -is returned. Otherwise, if the global variable |no_new_control_sequence| -is |true|, the dummy address |undefined_control_sequence| is returned. -Otherwise the identifier is inserted into the hash table and its location -is returned. - -@p function id_lookup(@!j,@!l:integer):pointer; {search the hash table} -label found; {go here if you found it} -var h:integer; {hash code} -@!d:integer; {number of characters in incomplete current string} -@!p:pointer; {index in |hash| array} -@!k:pointer; {index in |buffer| array} -begin @<Compute the hash code |h|@>; -p:=h+hash_base; {we start searching here; note that |0<=h<hash_prime|} -loop@+begin if text(p)>0 then if length(text(p))=l then - if str_eq_buf(text(p),j) then goto found; - if next(p)=0 then - begin if no_new_control_sequence then - p:=undefined_control_sequence - else @<Insert a new control sequence after |p|, then make - |p| point to it@>; - goto found; - end; - p:=next(p); - end; -found: id_lookup:=p; -end; - -@ @<Insert a new control...@>= -begin if text(p)>0 then - begin repeat if hash_is_full then overflow("hash size",hash_size); -@:TeX capacity exceeded hash size}{\quad hash size@> - decr(hash_used); - until text(hash_used)=0; {search for an empty location in |hash|} - next(p):=hash_used; p:=hash_used; - end; -str_room(l); d:=cur_length; -while pool_ptr>str_start_macro(str_ptr) do - begin decr(pool_ptr); str_pool[pool_ptr+l]:=str_pool[pool_ptr]; - end; {move current string up to make room for another} -for k:=j to j+l-1 do append_char(buffer[k]); -text(p):=make_string; pool_ptr:=pool_ptr+d; -@!stat incr(cs_count);@+tats@;@/ -end - -@ The value of |hash_prime| should be roughly 85\pct! of |hash_size|, and it -should be a prime number. The theory of hashing tells us to expect fewer -than two table probes, on the average, when the search is successful. -[See J.~S. Vitter, {\sl Journal of the ACM\/ \bf30} (1983), 231--258.] -@^Vitter, Jeffrey Scott@> - -@<Compute the hash code |h|@>= -h:=buffer[j]; -for k:=j+1 to j+l-1 do - begin h:=h+h+buffer[k]; - while h>=hash_prime do h:=h-hash_prime; - end - -@ Here is the subroutine that searches the primitive table for an identifier - -@p function prim_lookup(@!s:str_number):pointer; {search the primitives table} -label found; {go here if you found it} -var h:integer; {hash code} -@!p:pointer; {index in |hash| array} -@!k:pointer; {index in string pool} -@!the_hash_prime:halfword; -@!j,@!l:integer; -begin -the_hash_prime:= prim_prime; -if s<string_offset then begin - p := s; - if (p<0) or (get_prim_eq_level(p)<>level_one) then - p := undefined_primitive; -end -else begin - j:=str_start_macro(s); - if s = str_ptr then l := cur_length else l := length(s); - @<Compute the string hash code |h|@>; - p:=h+prim_base; {we start searching here; note that |0<=h<hash_prime|} - loop@+begin if prim_text(p)>0 then if length(prim_text(p))=l then - if str_eq_str(prim_text(p),s) then goto found; - if prim_next(p)=0 then - begin if no_new_control_sequence then - p:=undefined_primitive - else @<Insert a new primitive after |p|, then make - |p| point to it@>; - goto found; - end; - p:=prim_next(p); - end; - end; -found: prim_lookup:=p; -end; - -function string_lookup(@!s:str_number):pointer; {search the primitives table} -label found; {go here if you found it} -var h:integer; {hash code} -@!p:pointer; {index in |hash| array} -@!k:pointer; {index in string pool} -@!the_hash_prime: halfword; -@!j,@!l:integer; -begin -the_hash_prime := hash_prime; -if s<string_offset then begin - p := s; - if (p<0) or (eq_level(p)<>level_one) then - p := undefined_cs; -end -else begin - j:=str_start_macro(s); - if s = str_ptr then l := cur_length else l := length(s); - @<Compute the string hash code |h|@>; - p:=h+hash_base; {we start searching here; note that |0<=h<hash_prime|} - loop@+begin if text(p)>0 then if length(text(p))=l then - if str_eq_str(text(p),s) then goto found; - if next(p)=0 then - begin - p:=undefined_cs ; - goto found; - end; - p:=next(p); - end; - end; -found: string_lookup:=p; -end; - -function is_primitive(csname:str_number):boolean; - var n,m:integer; -begin - m := prim_lookup(csname); - n := string_lookup(csname); - is_primitive :=((n<>undefined_cs) and - (m<>undefined_primitive) and - (eq_type(n)=get_prim_eq_type(m)) and - (equiv(n)=get_prim_equiv(m))); -end; - -@ @<Insert a new primitive...@>= -begin if prim_text(p)>0 then - begin repeat if prim_is_full then overflow("primitive size",prim_size); -@:TeX capacity exceeded primitive size}{\quad primitive size@> - decr(prim_used); - until prim_text(prim_used)=0; {search for an empty location in |prim|} - prim_next(p):=prim_used; p:=prim_used; - end; -prim_text(p):=s; -end - -@ The value of |prim_prime| should be roughly 85\pct! of -|prim_size|, and it should be a prime number. - -@<Compute the string hash code |h|@>= -h:=str_pool[j]; -for k:=j+1 to j+l-1 do - begin h:=h+h+str_pool[k]; - while h>=the_hash_prime do h:=h-the_hash_prime; - end - @ The procedure |print_cs| prints the name of a control sequence, given a pointer to its address in |eqtb|. A space is printed after the name @@ -7010,28 +6526,38 @@ they may be unprintable. ((length(#)=3)and(str_pool[str_start_macro(#)]>=@"E0))or ((length(#)=2)and(str_pool[str_start_macro(#)]>=@"C0)) +@d is_active_csname(#)==((length(text(#))>3)and + (str_pool[str_start_macro(text(#))]=@"EF)and + (str_pool[str_start_macro(text(#))+1]=@"BF)and + (str_pool[str_start_macro(text(#))+2]=@"BF)) + +@d active_csname_value(#)==pool_to_unichar(str_start_macro(text(#))+3) + @<Basic printing...@>= procedure print_cs(@!p:integer); {prints a purported control sequence} -begin if p<hash_base then {single character} +begin if p<hash_base then { nullcs} if p=null_cs then begin print_esc("csname"); print_esc("endcsname"); end - else if p<active_base then print_esc("IMPOSSIBLE.") + else print_esc("IMPOSSIBLE.") @.IMPOSSIBLE@> - else print(p-active_base) else if p>=undefined_control_sequence then print_esc("IMPOSSIBLE.") else if (text(p)<0)or(text(p)>=str_ptr) then print_esc("NONEXISTENT.") @.NONEXISTENT@> -else begin - print_esc(text(p)); - if single_letter(text(p)) then begin - if get_cat_code(cat_code_table,pool_to_unichar(str_start_macro(text(p))))=letter then - print_char(" ") +else begin + if is_active_csname(p) then + print(active_csname_value(p)) + else begin + print_esc(text(p)); + if single_letter(text(p)) then begin + if get_cat_code(cat_code_table,pool_to_unichar(str_start_macro(text(p))))=letter then + print_char(" ") + else + do_nothing; + end else - do_nothing; + print_char(" "); end - else - print_char(" "); end; end; @@ -7040,158 +6566,154 @@ prints a space after the control sequence. @<Basic printing procedures@>= procedure sprint_cs(@!p:pointer); {prints a control sequence} -begin if p<hash_base then - if p<null_cs then print(p-active_base) - else begin print_esc("csname"); print_esc("endcsname"); - end -else print_esc(text(p)); -end; - -@ We need to put \TeX's ``primitive'' control sequences into the hash -table, together with their command code (which will be the |eq_type|) -and an operand (which will be the |equiv|). The |primitive| procedure -does this, in a way that no \TeX\ user can. The global value |cur_val| -contains the new |eqtb| pointer after |primitive| has acted. - -@p @!init procedure primitive(@!ss:str_number;@!c:quarterword;@!o:halfword); -var k:pool_pointer; {index into |str_pool|} -@!s:str_number; {actual |str_number| used } -@!j:0..buf_size; {index into |buffer|} -@!l:small_number; {length of the string} -@!prim_val:integer; {needed to fill |prim_eqtb|} -begin if ss<number_chars then begin - if ss>127 then confusion("prim"); { should be ASCII } - append_char(ss); - s:=make_string; +begin if p=null_cs then begin + print_esc("csname"); print_esc("endcsname"); end -else - s:=ss; -k:=str_start_macro(s); l:=str_start_macro(s+1)-k; - {we will move |s| into the (possibly non-empty) |buffer|} -if first+l>buf_size+1 then - check_buffer_overflow(first+l); -@:TeX capacity exceeded buffer size}{\quad buffer size@> -for j:=0 to l-1 do buffer[first+j]:=so(str_pool[k+j]); -cur_val:=id_lookup(first,l); {|no_new_control_sequence| is |false|} -flush_string; text(cur_val):=s; {we don't want to have the string twice} -prim_val:=prim_lookup(s); -eq_level(cur_val):=level_one; eq_type(cur_val):=c; equiv(cur_val):=o; -prim_eq_level(prim_val) := level_one; -prim_eq_type(prim_val) := c; -prim_equiv(prim_val) := o; +else begin + if is_active_csname(p) then + print(active_csname_value(p)) + else + print_esc(text(p)); + end; end; -tini + @ Many of \TeX's primitives need no |equiv|, since they are identifiable by their |eq_type| alone. These primitives are loaded into the hash table as follows: @<Put each of \TeX's primitives into the hash table@>= -primitive(" ",ex_space,0);@/ +primitive_tex(" ",ex_space,0,0);@/ @!@:Single-character primitives /}{\quad\.{\\\ }@> -primitive("/",ital_corr,0);@/ +primitive_tex("/",ital_corr,0,0);@/ @!@:Single-character primitives /}{\quad\.{\\/}@> -primitive("accent",accent,0);@/ +primitive_tex("accent",accent,0,0);@/ @!@:accent_}{\.{\\accent} primitive@> -primitive("advance",advance,0);@/ +primitive_tex("advance",advance,0,0);@/ @!@:advance_}{\.{\\advance} primitive@> -primitive("afterassignment",after_assignment,0);@/ +primitive_tex("afterassignment",after_assignment,0,0);@/ @!@:after_assignment_}{\.{\\afterassignment} primitive@> -primitive("aftergroup",after_group,0);@/ +primitive_tex("aftergroup",after_group,0,0);@/ @!@:after_group_}{\.{\\aftergroup} primitive@> -primitive("begingroup",begin_group,0);@/ +primitive_tex("begingroup",begin_group,0,0);@/ @!@:begin_group_}{\.{\\begingroup} primitive@> -primitive("char",char_num,0);@/ +primitive_tex("char",char_num,0,0);@/ @!@:char_}{\.{\\char} primitive@> -primitive("csname",cs_name,0);@/ +primitive_tex("csname",cs_name,0,0);@/ @!@:cs_name_}{\.{\\csname} primitive@> -primitive("delimiter",delim_num,0);@/ +primitive_tex("delimiter",delim_num,0,0);@/ @!@:delimiter_}{\.{\\delimiter} primitive@> -primitive("odelimiter",delim_num,1);@/ +primitive_omega("odelimiter",delim_num,1,0);@/ @!@:odelimiter_}{\.{\\odelimiter} primitive@> -primitive("divide",divide,0);@/ +primitive_luatex("Udelimiter",delim_num,2,0);@/ +@!@:odelimiter_}{\.{\\Udelimiter} primitive@> +primitive_tex("divide",divide,0,0);@/ @!@:divide_}{\.{\\divide} primitive@> -primitive("endcsname",end_cs_name,0);@/ +primitive_tex("endcsname",end_cs_name,0,0);@/ @!@:end_cs_name_}{\.{\\endcsname} primitive@> -primitive("endgroup",end_group,0); +primitive_tex("endgroup",end_group,0,0); @!@:end_group_}{\.{\\endgroup} primitive@> text(frozen_end_group):="endgroup"; eqtb[frozen_end_group]:=eqtb[cur_val];@/ -primitive("expandafter",expand_after,0);@/ +primitive_tex("expandafter",expand_after,0,0);@/ @!@:expand_after_}{\.{\\expandafter} primitive@> -primitive("font",def_font,0);@/ +primitive_tex("font",def_font,0,0);@/ @!@:font_}{\.{\\font} primitive@> -primitive("letterspacefont",letterspace_font,0);@/ +primitive_pdftex("letterspacefont",letterspace_font,0,0);@/ @!@:letterspace_font_}{\.{\\letterspacefont} primitive@> -primitive("fontdimen",assign_font_dimen,0);@/ +primitive_pdftex("pdfcopyfont",pdf_copy_font,0,0);@/ +@!@:pdf_copy_font_}{\.{\\pdfcopyfont} primitive@> +primitive_tex("fontdimen",assign_font_dimen,0,0);@/ @!@:font_dimen_}{\.{\\fontdimen} primitive@> -primitive("halign",halign,0);@/ +primitive_tex("halign",halign,0,0);@/ @!@:halign_}{\.{\\halign} primitive@> -primitive("hrule",hrule,0);@/ +primitive_tex("hrule",hrule,0,0);@/ @!@:hrule_}{\.{\\hrule} primitive@> -primitive("ignorespaces",ignore_spaces,0);@/ +primitive_tex("ignorespaces",ignore_spaces,0,0);@/ @!@:ignore_spaces_}{\.{\\ignorespaces} primitive@> -primitive("insert",insert,0);@/ +primitive_tex("insert",insert,0,0);@/ @!@:insert_}{\.{\\insert} primitive@> -primitive("leftghost",char_ghost,0);@/ +primitive_omega("leftghost",char_ghost,0,0);@/ @!@:leftghost_}{\.{\\leftghost} primitive@> -primitive("mark",mark,0);@/ +primitive_tex("mark",mark,0,0);@/ @!@:mark_}{\.{\\mark} primitive@> -primitive("mathaccent",math_accent,0);@/ +primitive_tex("mathaccent",math_accent,0,0);@/ @!@:math_accent_}{\.{\\mathaccent} primitive@> -primitive("mathchar",math_char_num,0);@/ -@!@:math_char_}{\.{\\mathchar} primitive@> -primitive("omathaccent",math_accent,1);@/ +primitive_omega("omathaccent",math_accent,1,0);@/ @!@:math_accent_}{\.{\\omathaccent} primitive@> -primitive("omathchar",math_char_num,1);@/ +primitive_luatex("Umathaccent",math_accent,2,0);@/ +@!@:math_accent_}{\.{\\Umathaccent} primitive@> +primitive_luatex("Umathbotaccent",math_accent,3,0);@/ +@!@:math_accent_}{\.{\\Umathbotaccent} primitive@> +primitive_luatex("Umathaccents",math_accent,4,0);@/ +@!@:math_accent_}{\.{\\Umathaccents} primitive@> +primitive_tex("mathchar",math_char_num,0,0);@/ +@!@:math_char_}{\.{\\mathchar} primitive@> +primitive_omega("omathchar",math_char_num,1,0);@/ @!@:math_char_}{\.{\\omathchar} primitive@> -primitive("mathchoice",math_choice,0);@/ +primitive_luatex("Umathchar",math_char_num,2,0);@/ +@!@:math_char_}{\.{\\Umathchar} primitive@> +primitive_luatex("Umathcharnum",math_char_num,3,0);@/ +@!@:math_char_}{\.{\\Umathcharnum} primitive@> +primitive_tex("mathchoice",math_choice,0,0);@/ @!@:math_choice_}{\.{\\mathchoice} primitive@> -primitive("multiply",multiply,0);@/ +primitive_tex("multiply",multiply,0,0);@/ @!@:multiply_}{\.{\\multiply} primitive@> -primitive("noalign",no_align,0);@/ +primitive_tex("noalign",no_align,0,0);@/ @!@:no_align_}{\.{\\noalign} primitive@> -primitive("noboundary",no_boundary,0);@/ +primitive_tex("noboundary",no_boundary,0,0);@/ @!@:no_boundary_}{\.{\\noboundary} primitive@> -primitive("noexpand",no_expand,0);@/ +primitive_tex("noexpand",no_expand,0,0);@/ @!@:no_expand_}{\.{\\noexpand} primitive@> -primitive("primitive",no_expand,1);@/ +primitive_luatex("primitive",no_expand,1,0);@/ @!@:primitive_}{\.{\\primitive} primitive@> -primitive("pdfprimitive",no_expand,1);@/ +primitive_pdftex("pdfprimitive",no_expand,1,0);@/ @!@:pdfprimitive_}{\.{\\pdfprimitive} primitive@> -primitive("nonscript",non_script,0);@/ +primitive_tex("nonscript",non_script,0,0);@/ @!@:non_script_}{\.{\\nonscript} primitive@> -primitive("omit",omit,0);@/ +primitive_tex("omit",omit,0,0);@/ @!@:omit_}{\.{\\omit} primitive@> -primitive("parshape",set_shape,par_shape_loc);@/ +primitive_tex("parshape",set_tex_shape,par_shape_loc,par_shape_loc);@/ @!@:par_shape_}{\.{\\parshape} primitive@> -primitive("penalty",break_penalty,0);@/ +primitive_tex("penalty",break_penalty,0,0);@/ @!@:penalty_}{\.{\\penalty} primitive@> -primitive("prevgraf",set_prev_graf,0);@/ +primitive_tex("prevgraf",set_prev_graf,0,0);@/ @!@:prev_graf_}{\.{\\prevgraf} primitive@> -primitive("radical",radical,0);@/ +primitive_tex("radical",radical,0,0);@/ @!@:radical_}{\.{\\radical} primitive@> -primitive("oradical",radical,1);@/ +primitive_omega("oradical",radical,1,0);@/ @!@:radical_}{\.{\\oradical} primitive@> -primitive("read",read_to_cs,0);@/ +primitive_luatex("Uradical",radical,2,0);@/ +@!@:radical_}{\.{\\Uradical} primitive@> +primitive_luatex("Uroot",radical,3,0);@/ +@!@:radical_}{\.{\\Uroot} primitive@> +primitive_luatex("Uunderdelimiter",radical,4,0);@/ +@!@:radical_}{\.{\\Uunderdelimiter} primitive@> +primitive_luatex("Uoverdelimiter",radical,5,0);@/ +@!@:radical_}{\.{\\Uoverdelimiter} primitive@> +primitive_luatex("Udelimiterunder",radical,6,0);@/ +@!@:radical_}{\.{\\Udelimiterunder} primitive@> +primitive_luatex("Udelimiterover",radical,7,0);@/ +@!@:radical_}{\.{\\Udelimiterover} primitive@> +primitive_tex("read",read_to_cs,0,0);@/ @!@:read_}{\.{\\read} primitive@> -primitive("relax",relax,too_big_char); +primitive_tex("relax",relax,too_big_char,too_big_char); @!@:relax_}{\.{\\relax} primitive@> text(frozen_relax):="relax"; eqtb[frozen_relax]:=eqtb[cur_val];@/ -primitive("rightghost",char_ghost,1);@/ +primitive_omega("rightghost",char_ghost,1,0);@/ @!@:rightghost_}{\.{\\rightghost} primitive@> -primitive("setbox",set_box,0);@/ +primitive_tex("setbox",set_box,0,0);@/ @!@:set_box_}{\.{\\setbox} primitive@> -primitive("the",the,0);@/ +primitive_tex("the",the,0,0);@/ @!@:the_}{\.{\\the} primitive@> -primitive("toks",toks_register,0);@/ +primitive_tex("toks",toks_register,0,0);@/ @!@:toks_}{\.{\\toks} primitive@> -primitive("vadjust",vadjust,0);@/ +primitive_tex("vadjust",vadjust,0,0);@/ @!@:vadjust_}{\.{\\vadjust} primitive@> -primitive("valign",valign,0);@/ +primitive_tex("valign",valign,0,0);@/ @!@:valign_}{\.{\\valign} primitive@> -primitive("vcenter",vcenter,0);@/ +primitive_tex("vcenter",vcenter,0,0);@/ @!@:vcenter_}{\.{\\vcenter} primitive@> -primitive("vrule",vrule,0);@/ +primitive_tex("vrule",vrule,0,0);@/ @!@:vrule_}{\.{\\vrule} primitive@> @ Each primitive has a corresponding inverse, so that it is possible to @@ -7200,65 +6722,6 @@ Every call of |primitive| in this program is therefore accompanied by some straightforward code that forms part of the |print_cmd_chr| routine below. -@<Cases of |print_cmd_chr|...@>= -accent: print_esc("accent"); -advance: print_esc("advance"); -after_assignment: print_esc("afterassignment"); -after_group: print_esc("aftergroup"); -assign_font_dimen: print_esc("fontdimen"); -begin_group: print_esc("begingroup"); -break_penalty: print_esc("penalty"); -char_num: print_esc("char"); -char_ghost: if cur_chr=0 then print_esc("leftghost") - else print_esc("rightghost"); -cs_name: print_esc("csname"); -def_font: print_esc("font"); -letterspace_font: print_esc("letterspacefont"); -delim_num: if chr_code=0 then print_esc("delimiter") else print_esc("odelimiter") ; -divide: print_esc("divide"); -end_cs_name: print_esc("endcsname"); -end_group: print_esc("endgroup"); -ex_space: print_esc(" "); -expand_after: if chr_code=0 then print_esc("expandafter") - @<Cases of |expandafter| for |print_cmd_chr|@>; -halign: print_esc("halign"); -hrule: print_esc("hrule"); -ignore_spaces: if chr_code=0 then print_esc("ignorespaces") else print_esc("primitive"); -insert: print_esc("insert"); -ital_corr: print_esc("/"); -mark: begin - if chr_code=0 then print_esc("mark") - else if chr_code=1 then print_esc("clearmarks") - else print_esc("marks"); - end; -math_accent: if chr_code=0 then print_esc("mathaccent") else print_esc("omathaccent"); -math_char_num: if chr_code=0 then print_esc("mathchar") else print_esc("omathchar"); -math_choice: print_esc("mathchoice"); -multiply: print_esc("multiply"); -no_align: print_esc("noalign"); -no_boundary:print_esc("noboundary"); -no_expand: if chr_code=0 then print_esc("noexpand") - else print_esc("primitive"); -non_script: print_esc("nonscript"); -omit: print_esc("omit"); -radical: if chr_code=0 then print_esc("radical") else print_esc("oradical"); -read_to_cs: if chr_code=0 then print_esc("read") - @<Cases of |read| for |print_cmd_chr|@>; -relax: print_esc("relax"); -set_box: print_esc("setbox"); -set_prev_graf: print_esc("prevgraf"); -set_shape: case chr_code of - par_shape_loc: print_esc("parshape"); - @<Cases of |set_shape| for |print_cmd_chr|@>@;@/ - end; {there are no other cases} -the: if chr_code=0 then print_esc("the") - @<Cases of |the| for |print_cmd_chr|@>; -toks_register: print_esc("toks"); -vadjust: print_esc("vadjust"); -valign: print_esc("valign"); -vcenter: print_esc("vcenter"); -vrule: print_esc("vrule"); - @ We will deal with the other primitives later, at some point in the program where their |eq_type| and |equiv| values are more meaningful. For example, the primitives for math mode will be loaded when we consider the routines @@ -7312,7 +6775,7 @@ source line number at which the current level of grouping was entered. @d save_level(#)==save_stack[#].hh.b1 {saved level for regions 5 and 6, or group code} @d save_index(#)==save_stack[#].hh.rh - {|eqtb| location or |save_stack| location} + {|eqtb| location or token or |save_stack| location} @d restore_old_value=0 {|save_type| when a value should be restored later} @d restore_zero=1 {|save_type| when an undefined entry should be restored} @d insert_token=2 {|save_type| when a token is being saved for later use} @@ -7340,7 +6803,7 @@ one that starts with \.{\\begingroup} should end with \.{\\endgroup}. @d align_group=6 {code for `\.{\\halign}\grp', `\.{\\valign}\grp'} @d no_align_group=7 {code for `\.{\\noalign}\grp'} @d output_group=8 {code for output routine} -@d math_group=9 {code for, e.g, `\.{\char'136}\grp'} +@d math_group=9 {code for, e.g., `\.{\char'136}\grp'} @d disc_group=10 {code for `\.{\\discretionary}\grp\grp\grp'} @d insert_group=11 {code for `\.{\\insert}\grp', `\.{\\vadjust}\grp'} @d vcenter_group=12 {code for `\.{\\vcenter}\grp'} @@ -7544,6 +7007,7 @@ begin a:=false; l:=level_one; {just in case} unsave_math_codes(cur_level); unsave_cat_codes (cat_code_table,cur_level); unsave_text_codes(cur_level); +unsave_math_data(cur_level); if cur_level>level_one then begin decr(cur_level); @<Clear off top level from |save_stack|@>; @@ -7774,7 +7238,7 @@ if (p<fix_mem_min) or (p>fix_mem_end) then end; if info(p)>=cs_token_flag then begin if not ((inhibit_par_tokens) and (info(p)=par_token)) then - print_cs(info(p)-cs_token_flag); + print_cs(info(p)-cs_token_flag); end else begin m:=info(p) div string_offset; c:=info(p) mod string_offset; if info(p)<0 then print_esc("BAD.") @@ -7790,7 +7254,7 @@ parameters by seeing one in a |match| command before it runs into any case m of left_brace,right_brace,math_shift,tab_mark,sup_mark,sub_mark,spacer, letter,other_char: print(c); -mac_param: begin print(c); print(c); +mac_param: begin if not in_lua_escape then print(c); print(c); end; out_param: begin print(match_chr); if c<=9 then print_char(c+"0") @@ -7877,39 +7341,6 @@ low-level languages that do not support recursion. @!cur_cs: pointer; {control sequence found here, zero if none found} @!cur_tok: halfword; {packed representative of |cur_cmd| and |cur_chr|} -@ The |print_cmd_chr| routine prints a symbolic interpretation of a -command code and its modifier. This is used in certain `\.{You can\'t}' -error messages, and in the implementation of diagnostic routines like -\.{\\show}. - -The body of |print_cmd_chr| is a rather tedious listing of print -commands, and most of it is essentially an inverse to the |primitive| -routine that enters a \TeX\ primitive into |eqtb|. Therefore much of -this procedure appears elsewhere in the program, -together with the corresponding |primitive| calls. - -@d chr_cmd(#)==begin print(#); print(chr_code); - end - -@<Declare the procedure called |print_cmd_chr|@>= -procedure print_cmd_chr(@!cmd:quarterword;@!chr_code:halfword); -var n:integer; {temp variable} -begin case cmd of -left_brace: chr_cmd("begin-group character "); -right_brace: chr_cmd("end-group character "); -math_shift: chr_cmd("math shift character "); -mac_param: chr_cmd("macro parameter character "); -sup_mark: chr_cmd("superscript character "); -sub_mark: chr_cmd("subscript character "); -endv: print("end of alignment template"); -spacer: chr_cmd("blank space "); -letter: chr_cmd("the letter "); -other_char: chr_cmd("the character "); -@t\4@>@<Cases of |print_cmd_chr| for symbolic printing of primitives@>@/ -othercases print("[unknown command code!]") -endcases; -end; - @ Here is a procedure that displays the current command. @p procedure show_cur_cmd_chr; @@ -7968,6 +7399,9 @@ convention~(1), so it is declared in the following way: @!start_field,@!loc_field, @!limit_field, @!name_field, @!ocp_lstack_field: halfword; {used for omega translation processes} @!ocp_no_field: halfword; {used for omega translation processes} + @!synctex_tag_field: integer; {stack the tag of the current file} + @!cattable_field: integer; {category table used by the current line (see textoken.c)} + @!partial_field: boolean; {is the current line partial? (see textoken.c)} @!nofilter_field: boolean; {used by token filtering} end; @@ -7988,8 +7422,11 @@ in our discussion of basic input-output routines. The other components of @d limit==cur_input.limit_field {end of current line in |buffer|} @d nofilter==cur_input.nofilter_field {is token filtering explicitly disallowed?} @d name==cur_input.name_field {name of the current file} +@d synctex_tag==cur_input.synctex_tag_field {{\sl Sync\TeX} tag of the current file} @d current_ocp_lstack==cur_input.ocp_lstack_field {name of the current ocp} @d current_ocp_no==cur_input.ocp_no_field {name of the current ocp} +@d line_catcode_table==cur_input.cattable_field +@d line_partial==cur_input.partial_field @ Let's look more closely now at the control variables (|state|,~|index|,~|start|,~|loc|,~|limit|,~|name|), @@ -8615,6 +8052,8 @@ eof_seen[index]:=false; grp_stack[index]:=cur_boundary; if_stack[index]:=cond_ptr; line_stack[index]:=line; start:=first; state:=mid_line; name:=0; {|terminal_input| is now |true|} +line_catcode_table:=DEFAULT_CAT_TABLE; line_partial:=false; +@<Prepare terminal input {\sl Sync\TeX} information@>; end; @ Conversely, the variables must be downdated when such a level of input @@ -8651,6 +8090,7 @@ scanner_status:=normal; warning_index:=null; first:=1; state:=new_line; start:=1; index:=0; line:=0; name:=0; current_ocp_lstack:=0; current_ocp_no:=0; nofilter:=false; force_eof:=false; luacstrings :=0; +line_catcode_table:=DEFAULT_CAT_TABLE; line_partial:=false; align_state:=1000000;@/ if not init_terminal then goto final_end; limit:=last; first:=last+1; {|init_terminal| has set |loc| and |last|} @@ -8689,13 +8129,10 @@ when detecting a blank line. @!par_token:halfword; {token representing `\.{\\par}'} @ @<Put each...@>= -primitive("par",par_end,too_big_char); {cf. |scan_file_name|} +primitive_tex("par",par_end,too_big_char,too_big_char); {cf.\ |scan_file_name|} @!@:par_}{\.{\\par} primitive@> par_loc:=cur_val; par_token:=cs_token_flag+par_loc; -@ @<Cases of |print_cmd_chr|...@>= -par_end:print_esc("par"); - @ The function |get_next| is now defined in |textoken.c|. Parts of this routine are executed more often than any other instructions of \TeX. @^mastication@>@^inner loop@> @@ -8755,9 +8192,7 @@ or the evaluation of the conditional. |get_next| has already been called. \yskip\noindent -In fact, these three procedures account for {\sl all\/} uses of |get_next|, -except for two places in the ``inner loop'' when |cur_tok| need not be set, -and except when the arguments to \.{\\ifx} are being scanned. +In fact, these three procedures account for almost every use of |get_next|. @ No new control sequences will be defined except during a call of |get_token|, or when \.{\\csname} compresses a token list, because @@ -9029,16 +8464,11 @@ end which will be declared later; the processing of \.{\\endinput} is trivial. @<Put each...@>= -primitive("input",input,0);@/ +primitive_tex("input",input,0,0);@/ @!@:input_}{\.{\\input} primitive@> -primitive("endinput",input,1);@/ +primitive_tex("endinput",input,1,0);@/ @!@:end_input_}{\.{\\endinput} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -input: if chr_code=0 then print_esc("input") - @/@<Cases of |input| for |print_cmd_chr|@>@/ - else print_esc("endinput"); - @ @<Initiate or terminate input...@>= if cur_chr=1 then force_eof:=true @/@<Cases for |input|@>@/ @@ -9157,42 +8587,31 @@ for i:=0 to biggest_mark do begin end; @ @<Put each...@>= -primitive("topmark",top_bot_mark,top_mark_code); +primitive_tex("topmark",top_bot_mark,top_mark_code,0); @!@:top_mark_}{\.{\\topmark} primitive@> -primitive("firstmark",top_bot_mark,first_mark_code); +primitive_tex("firstmark",top_bot_mark,first_mark_code,0); @!@:first_mark_}{\.{\\firstmark} primitive@> -primitive("botmark",top_bot_mark,bot_mark_code); +primitive_tex("botmark",top_bot_mark,bot_mark_code,0); @!@:bot_mark_}{\.{\\botmark} primitive@> -primitive("splitfirstmark",top_bot_mark,split_first_mark_code); +primitive_tex("splitfirstmark",top_bot_mark,split_first_mark_code,0); @!@:split_first_mark_}{\.{\\splitfirstmark} primitive@> -primitive("splitbotmark",top_bot_mark,split_bot_mark_code); +primitive_tex("splitbotmark",top_bot_mark,split_bot_mark_code,0); @!@:split_bot_mark_}{\.{\\splitbotmark} primitive@> -primitive("clearmarks",mark,clear_marks_code);@/ +primitive_luatex("clearmarks",mark,clear_marks_code,0);@/ @!@:clearmarks_}{\.{\\clearmarks} primitive@> -primitive("marks",mark,marks_code); +primitive_etex("marks",mark,marks_code,0); @!@:marks_}{\.{\\marks} primitive@> -primitive("topmarks",top_bot_mark,top_mark_code+marks_code); +primitive_etex("topmarks",top_bot_mark,top_mark_code+marks_code,0); @!@:top_marks_}{\.{\\topmarks} primitive@> -primitive("firstmarks",top_bot_mark,first_mark_code+marks_code); +primitive_etex("firstmarks",top_bot_mark,first_mark_code+marks_code,0); @!@:first_marks_}{\.{\\firstmarks} primitive@> -primitive("botmarks",top_bot_mark,bot_mark_code+marks_code); +primitive_etex("botmarks",top_bot_mark,bot_mark_code+marks_code,0); @!@:bot_marks_}{\.{\\botmarks} primitive@> -primitive("splitfirstmarks",top_bot_mark,split_first_mark_code+marks_code); +primitive_etex("splitfirstmarks",top_bot_mark,split_first_mark_code+marks_code,0); @!@:split_first_marks_}{\.{\\splitfirstmarks} primitive@> -primitive("splitbotmarks",top_bot_mark,split_bot_mark_code+marks_code); +primitive_etex("splitbotmarks",top_bot_mark,split_bot_mark_code+marks_code,0); @!@:split_bot_marks_}{\.{\\splitbotmarks} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -top_bot_mark: begin case (chr_code mod marks_code) of - first_mark_code: print_esc("firstmark"); - bot_mark_code: print_esc("botmark"); - split_first_mark_code: print_esc("splitfirstmark"); - split_bot_mark_code: print_esc("splitbotmark"); - othercases print_esc("topmark") - endcases; - if chr_code>=marks_code then print_char("s"); - end; - @ The following code is activated when |cur_cmd=top_bot_mark| and when |cur_chr| is a code like |top_mark_code|. @@ -9334,8 +8753,9 @@ if cur_tok=info(r) then @<Contribute the recently matched tokens to the current parameter, and |goto continue| if a partial match is still in effect; but abort if |s=null|@>; -if cur_tok=par_token then if long_state<>long_call then - @<Report a runaway argument and abort@>; +if cur_tok=par_token then if long_state<>long_call then + if not suppress_long_error then + @<Report a runaway argument and abort@>; if cur_tok<right_brace_limit then if cur_tok<left_brace_limit then @<Contribute an entire group to the current parameter@> @@ -9379,6 +8799,7 @@ help6("I've run across a `}' that doesn't seem to match anything.")@/ ("argument that might be the root of the problem. But if")@/ ("your `}' was spurious, just type `2' and it will go away."); incr(align_state); long_state:=call; cur_tok:=par_token; ins_error; +goto continue; end {a white lie; the \.{\\par} won't always trigger a runaway} @ If |long_state=outer_call|, a runaway argument has already been reported. @@ -9447,7 +8868,8 @@ begin unbalance:=1; @^inner loop@> loop@+ begin fast_store_new_token(cur_tok); get_token; if cur_tok=par_token then if long_state<>long_call then - @<Report a runaway argument and abort@>; + if not suppress_long_error then + @<Report a runaway argument and abort@>; if cur_tok<right_brace_limit then if cur_tok<left_brace_limit then incr(unbalance) else begin decr(unbalance); @@ -9541,62 +8963,6 @@ end; repeat get_x_token; until cur_cmd<>spacer -@ In case you are getting bored, here is a slightly less trivial routine: -Given a string of lowercase letters, like `\.{pt}' or `\.{plus}' or -`\.{width}', the |scan_keyword| routine checks to see whether the next -tokens of input match this string. The match must be exact, except that -uppercase letters will match their lowercase counterparts; uppercase -equivalents are determined by subtracting |"a"-"A"|, rather than using the -|uc_code| table, since \TeX\ uses this routine only for its own limited -set of keywords. - -If a match is found, the characters are effectively removed from the input -and |true| is returned. Otherwise |false| is returned, and the input -is left essentially unchanged (except for the fact that some macros -may have been expanded, etc.). -@^inner loop@> - -@p function scan_keyword(@!s:str_number):boolean; {look for a given string} -label exit; -var p:pointer; {tail of the backup list} -@!q:pointer; {new node being added to the token list via |store_new_token|} -@!k:pool_pointer; {index into |str_pool|} -begin -if s<number_chars then begin - @<Get the next non-blank non-call token@>; - if (cur_cs=0)and((cur_chr=s)or(cur_chr=s-"a"+"A")) then - scan_keyword:=true - else - begin back_input; - scan_keyword:=false; return; - end; - end -else begin - p:=backup_head; link(p):=null; - k:=str_start_macro(s); - while k<str_start_macro(s+1) do - begin get_x_token; {recursion is possible here} -@^recursion@> - if (cur_cs=0)and@| - ((cur_chr=so(str_pool[k]))or(cur_chr=so(str_pool[k])-"a"+"A")) then - begin store_new_token(cur_tok); incr(k); - end - else if (cur_cmd<>spacer)or(p<>backup_head) then - begin - if p<>backup_head then begin - q:=get_avail; info(q):=cur_tok; link(q):=null; - link(p) := q; - back_list(link(backup_head)); - end - else - back_input; - scan_keyword:=false; return; - end; - end; - flush_list(link(backup_head)); scan_keyword:=true; -end; -exit:end; - @ Here is a procedure that sounds an alarm when mu and non-mu units are being switched. @@ -9673,22 +9039,15 @@ as their command code; they are distinguished by the |chr_code|, which is either |int_val|, |attr_val|, |dimen_val|, |glue_val|, or |mu_val|. @<Put each...@>= -primitive("count",register,int_val); +primitive_tex("count",register,int_val,0); @!@:count_}{\.{\\count} primitive@> -primitive("attribute",register,attr_val); +primitive_luatex("attribute",register,attr_val,0); @!@:count_}{\.{\\attribute} primitive@> -primitive("dimen",register,dimen_val); +primitive_tex("dimen",register,dimen_val,0); @!@:dimen_}{\.{\\dimen} primitive@> -primitive("skip",register,glue_val); +primitive_tex("skip",register,glue_val,0); @!@:skip_}{\.{\\skip} primitive@> -primitive("muskip",register,mu_val); - -@ @<Cases of |print_cmd_chr|...@>= -register: if chr_code=int_val then print_esc("count") - else if chr_code=attr_val then print_esc("attribute") - else if chr_code=dimen_val then print_esc("dimen") - else if chr_code=glue_val then print_esc("skip") - else print_esc("muskip"); +primitive_tex("muskip",register,mu_val,0); @ OK, we're ready for |scan_something_internal| itself. A second parameter, |negative|, is set |true| if the value that is found should be negated. @@ -9708,10 +9067,16 @@ var m:halfword; {|chr_code| part of the operand token} @!p:0..nest_size; {index into |nest|} begin m:=cur_chr; case cur_cmd of -def_code: @<Fetch a character code from some table@>; -extdef_code: @<Fetch an ext character code from some table@>; -toks_register,assign_toks,def_family,set_font,def_font,letterspace_font: @<Fetch a token list or - font identifier, provided that |level=tok_val|@>; +def_char_code: @<Fetch a character code from some table@>; +def_del_code: @<Fetch a character code from some table@>; +extdef_math_code: @<Fetch an ext character code from some table@>; +extdef_del_code: @<Fetch an ext character code from some table@>; +toks_register,assign_toks,set_font,def_font,letterspace_font,pdf_copy_font: + @<Fetch a token list or font identifier, provided that |level=tok_val|@>; +def_family: + @<Fetch a math font identifier@>; +set_math_param: + @<Fetch a math param@>; assign_int: scanned_result(eqtb[m].int)(int_val); assign_attr: scanned_result(eqtb[m].int)(int_val); assign_box_dir: begin @@ -9729,9 +9094,10 @@ set_aux: @<Fetch the |space_factor| or the |prev_depth|@>; set_prev_graf: @<Fetch the |prev_graf|@>; set_page_int:@<Fetch the |dead_cycles| or the |insert_penalties|@>; set_page_dimen: @<Fetch something on the |page_so_far|@>; -set_shape: @<Fetch the |par_shape| size@>; +set_tex_shape: @<Fetch the |par_shape| size@>; +set_etex_shape: @<Fetch a penalties array element@>; set_box_dimen: @<Fetch a box dimension@>; -char_given,math_given,omath_given: scanned_result(cur_chr)(int_val); +char_given,math_given,omath_given,xmath_given: scanned_result(cur_chr)(int_val); assign_font_dimen: @<Fetch a font dimension@>; assign_font_int: @<Fetch a font integer@>; register: @<Fetch a register@>; @@ -9746,9 +9112,13 @@ procedure scan_something_simple(@!cmd:halfword;@!subitem:halfword); {fetch an internal parameter} label exit; var m:halfword; {|chr_code| part of the operand token} +@!q:halfword; {general purpose index} @!p:0..nest_size; {index into |nest|} @!level:small_number; { allowed level} -begin m:=subitem; level:=tok_val; +@!negative:boolean; +@!save_cur_chr:integer; +begin m:=subitem; level:=tok_val; +negative:=false; {never actually used, added for etexs |last_item| cases} case cmd of assign_toks: scanned_result(equiv(m))(tok_val); assign_int: scanned_result(eqtb[m].int)(int_val); @@ -9761,8 +9131,16 @@ set_aux: @<Fetch the |space_factor| or the |prev_depth|@>; set_prev_graf: @<Fetch the |prev_graf|@>; set_page_int:@<Fetch the |dead_cycles| or the |insert_penalties|@>; set_page_dimen: @<Fetch something on the |page_so_far|@>; -set_shape: @<Fetch the |par_shape| size@>; -char_given,math_given,omath_given: scanned_result(m)(int_val); {TH: TODO, doesnt work} +set_tex_shape: @<Fetch the |par_shape| size@>; +set_etex_shape: @<Fetch a penalties array element@>; +last_item: begin + save_cur_chr:=cur_chr; + cur_chr:=subitem; + @<Fetch an item in the current node, if appropriate@>; + cur_chr:=save_cur_chr; + end; +char_given,math_given,omath_given,xmath_given: + scanned_result(m)(int_val); {TH: TODO, doesnt work} othercases @<Complain that |texlib| can't do this; give zero result@> endcases;@/ exit:end; @@ -9770,18 +9148,7 @@ exit:end; @ @<Fetch a character code from some table@>= begin scan_char_num; if m=math_code_base then begin - cur_val1:=get_math_code(cur_val); - if ((cur_val1 div @"1000000)>8) or - (((cur_val1 mod @"1000000) div @"10000)>15) or - ((cur_val1 mod @"10000)>255) then - begin print_err("Extended mathchar used as mathchar"); -@.Bad mathchar@> - help2("A mathchar number must be between 0 and ""7FFF.")@/ - ("I changed this one to zero."); int_error(cur_val1); cur_val1:=0; - end; - cur_val1:=((cur_val1 div @"1000000)*@"1000) + - (((cur_val1 mod @"1000000) div @"10000)*@"100) + - (cur_val1 mod @"10000); + cur_val1:=get_math_code_num(cur_val); scanned_result(cur_val1)(int_val); end else if m=lc_code_base then begin @@ -9806,7 +9173,10 @@ end @ @<Fetch an ext character code from some table@>= begin scan_char_num; -if m=math_code_base then scanned_result(get_math_code(cur_val))(int_val) +if m=math_code_base then begin + cur_val1:=get_math_code_num(cur_val); + scanned_result(cur_val1)(int_val); + end { TH: next two lines should not be possible } else if m<math_code_base then scanned_result(equiv(m+cur_val))(int_val) else scanned_result(eqtb[m+cur_val].int)(int_val); @@ -9832,6 +9202,42 @@ else begin back_input; scan_font_ident; scanned_result(font_id_base+cur_val)(ident_val); end +@ @<Fetch a math font identifier@>= +begin scan_char_num; cur_val1:=fam_fnt(cur_val,m); + scanned_result(cur_val1)(int_val); + end + +@ @<Fetch a math param@>= +begin cur_val1:=cur_chr; get_token; + if cur_cmd<>math_style then + begin print_err("Missing math style, treated as \\displaystyle"); +@.Missing number...@> + help1("A style should have been here; I inserted `\\displaystyle'."); + cur_val:=display_style; + back_error; + end + else + cur_val:=cur_chr; + if cur_val1<math_param_first_mu_glue then begin + if cur_val1=math_param_radical_degree_raise then begin + cur_val1 := get_math_param(cur_val1,cur_chr); + scanned_result(cur_val1)(int_val); + end + else begin + cur_val1 := get_math_param(cur_val1,cur_chr); + scanned_result(cur_val1)(dimen_val); + end; + end + else begin + cur_val1 := get_math_param(cur_val1,cur_chr); + if cur_val1=thin_mu_skip_code then cur_val1:=thin_mu_skip + else if cur_val1=med_mu_skip_code then cur_val1:=med_mu_skip + else if cur_val1=thick_mu_skip_code then cur_val1:=thick_mu_skip; + scanned_result(cur_val1)(mu_val); + end; + end + + @ Users refer to `\.{\\the\\spacefactor}' only in horizontal mode, and to `\.{\\the\\prevdepth}' only in vertical mode; so we put the associated mode in the modifier part of the |set_aux| command. @@ -9873,88 +9279,57 @@ the codes for its extensions: |eTeX_version_code|, \dots\ . @d eTeX_expr=eTeX_mu+1 {first of \eTeX\ codes for expressions} @<Put each...@>= -primitive("spacefactor",set_aux,hmode); +primitive_tex("spacefactor",set_aux,hmode,0); @!@:space_factor_}{\.{\\spacefactor} primitive@> -primitive("prevdepth",set_aux,vmode);@/ +primitive_tex("prevdepth",set_aux,vmode,0);@/ @!@:prev_depth_}{\.{\\prevdepth} primitive@> -primitive("deadcycles",set_page_int,0); +primitive_tex("deadcycles",set_page_int,0,0); @!@:dead_cycles_}{\.{\\deadcycles} primitive@> -primitive("insertpenalties",set_page_int,1); +primitive_tex("insertpenalties",set_page_int,1,0); @!@:insert_penalties_}{\.{\\insertpenalties} primitive@> -primitive("wd",set_box_dimen,width_offset); +primitive_tex("wd",set_box_dimen,width_offset,0); @!@:wd_}{\.{\\wd} primitive@> -primitive("ht",set_box_dimen,height_offset); +primitive_tex("ht",set_box_dimen,height_offset,0); @!@:ht_}{\.{\\ht} primitive@> -primitive("dp",set_box_dimen,depth_offset); +primitive_tex("dp",set_box_dimen,depth_offset,0); @!@:dp_}{\.{\\dp} primitive@> -primitive("lastpenalty",last_item,int_val); +primitive_tex("lastpenalty",last_item,int_val,0); @!@:last_penalty_}{\.{\\lastpenalty} primitive@> -primitive("lastkern",last_item,dimen_val); +primitive_tex("lastkern",last_item,dimen_val,0); @!@:last_kern_}{\.{\\lastkern} primitive@> -primitive("lastskip",last_item,glue_val); +primitive_tex("lastskip",last_item,glue_val,0); @!@:last_skip_}{\.{\\lastskip} primitive@> -primitive("inputlineno",last_item,input_line_no_code); +primitive_tex("inputlineno",last_item,input_line_no_code,0); @!@:input_line_no_}{\.{\\inputlineno} primitive@> -primitive("badness",last_item,badness_code); +primitive_tex("badness",last_item,badness_code,0); @!@:badness_}{\.{\\badness} primitive@> -primitive("pdftexversion",last_item,pdftex_version_code);@/ +primitive_pdftex("pdftexversion",last_item,pdftex_version_code,0);@/ @!@:pdftex_version_}{\.{\\pdftexversion} primitive@> -primitive("luatexversion",last_item,luatex_version_code);@/ +primitive_luatex("luatexversion",last_item,luatex_version_code,0);@/ @!@:luatex_version_}{\.{\\luatexversion} primitive@> -primitive("pdflastobj",last_item,pdf_last_obj_code);@/ +primitive_pdftex("pdflastobj",last_item,pdf_last_obj_code,0);@/ @!@:pdf_last_obj_}{\.{\\pdflastobj} primitive@> -primitive("pdflastxform",last_item,pdf_last_xform_code);@/ +primitive_pdftex("pdflastxform",last_item,pdf_last_xform_code,0);@/ @!@:pdf_last_xform_}{\.{\\pdflastxform} primitive@> -primitive("pdflastximage",last_item,pdf_last_ximage_code);@/ +primitive_pdftex("pdflastximage",last_item,pdf_last_ximage_code,0);@/ @!@:pdf_last_ximage_}{\.{\\pdflastximage} primitive@> -primitive("pdflastximagepages",last_item,pdf_last_ximage_pages_code);@/ +primitive_pdftex("pdflastximagepages",last_item,pdf_last_ximage_pages_code,0);@/ @!@:pdf_last_ximage_pages_}{\.{\\pdflastximagepages} primitive@> -primitive("pdflastannot",last_item,pdf_last_annot_code);@/ +primitive_pdftex("pdflastannot",last_item,pdf_last_annot_code,0);@/ @!@:pdf_last_annot_}{\.{\\pdflastannot} primitive@> -primitive("pdflastxpos",last_item,pdf_last_x_pos_code);@/ +primitive_pdftex("pdflastxpos",last_item,pdf_last_x_pos_code,0);@/ @!@:pdf_last_x_pos_}{\.{\\pdflastxpos} primitive@> -primitive("pdflastypos",last_item,pdf_last_y_pos_code);@/ +primitive_pdftex("pdflastypos",last_item,pdf_last_y_pos_code,0);@/ @!@:pdf_last_y_pos_}{\.{\\pdflastypos} primitive@> -primitive("pdfretval",last_item,pdf_retval_code);@/ +primitive_pdftex("pdfretval",last_item,pdf_retval_code,0);@/ @!@:pdf_retval_}{\.{\\pdfretval} primitive@> -primitive("pdflastximagecolordepth",last_item,pdf_last_ximage_colordepth_code);@/ +primitive_pdftex("pdflastximagecolordepth",last_item,pdf_last_ximage_colordepth_code,0);@/ @!@:pdf_last_ximage_colordepth_}{\.{\\pdflastximagecolordepth} primitive@> -primitive("pdfrandomseed",last_item,random_seed_code); +primitive_pdftex("pdfrandomseed",last_item,random_seed_code,0); @!@:random_seed_}{\.{\\pdfrandomseed} primitive@> -primitive("pdflastlink",last_item,pdf_last_link_code);@/ +primitive_pdftex("pdflastlink",last_item,pdf_last_link_code,0);@/ @!@:pdf_last_link_}{\.{\\pdflastlink} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -set_aux: if chr_code=vmode then print_esc("prevdepth") -@+else print_esc("spacefactor"); -set_page_int: if chr_code=0 then print_esc("deadcycles") -@/@<Cases of |set_page_int| for |print_cmd_chr|@>@/ -@+else print_esc("insertpenalties"); -set_box_dimen: if chr_code=width_offset then print_esc("wd") -else if chr_code=height_offset then print_esc("ht") -else print_esc("dp"); -last_item: case chr_code of - int_val: print_esc("lastpenalty"); - dimen_val: print_esc("lastkern"); - glue_val: print_esc("lastskip"); - input_line_no_code: print_esc("inputlineno"); - @/@<Cases of |last_item| for |print_cmd_chr|@>@/ - pdftex_version_code: print_esc("pdftexversion"); - luatex_version_code: print_esc("luatexversion"); - pdf_last_obj_code: print_esc("pdflastobj"); - pdf_last_xform_code: print_esc("pdflastxform"); - pdf_last_ximage_code: print_esc("pdflastximage"); - pdf_last_ximage_pages_code: print_esc("pdflastximagepages"); - pdf_last_annot_code: print_esc("pdflastannot"); - pdf_last_x_pos_code: print_esc("pdflastxpos"); - pdf_last_y_pos_code: print_esc("pdflastypos"); - pdf_retval_code: print_esc("pdfretval"); - pdf_last_ximage_colordepth_code: print_esc("pdflastximagecolordepth"); - random_seed_code: print_esc("pdfrandomseed"); - pdf_last_link_code: print_esc("pdflastlink"); - othercases print_esc("badness") - endcases; - @ @<Fetch the |space_factor| or the |prev_depth|@>= if abs(mode)<>m then begin print_err("Improper "); print_cmd_chr(set_aux,m); @@ -9968,11 +9343,8 @@ if abs(mode)<>m then if level<>tok_val then scanned_result(0)(dimen_val) else scanned_result(0)(int_val); end -else if m=vmode then - begin cur_val:=prev_depth; cur_val_level:=dimen_val; - end -else begin cur_val:=space_factor; cur_val_level:=int_val; - end +else if m=vmode then scanned_result(prev_depth)(dimen_val) +else scanned_result(space_factor)(int_val) @ @<Fetch the |dead_cycles| or the |insert_penalties|@>= begin if m=0 then cur_val:=dead_cycles @@ -10007,9 +9379,8 @@ else begin nest[nest_ptr]:=cur_list; p:=nest_ptr; end @ @<Fetch the |par_shape| size@>= -begin if m>par_shape_loc then @<Fetch a penalties array element@> -else if par_shape_ptr=null then cur_val:=0 -else cur_val:=vinfo(par_shape_ptr); +begin if par_shape_ptr=null then cur_val:=0 +else cur_val:=vinfo(par_shape_ptr+1); cur_val_level:=int_val; end @@ -10186,6 +9557,9 @@ applications of |scan_int| that have already been made inside of @d dir_prev_end(#)==((#) mod 4) @d dir_prev(#)==(((#)+1) mod 4)=dir_prev_end +@d dir_horizontal(#)==(((#)=dir_L) or ((#)=dir_R)) +@d dir_vertical(#)==(((#)=dir_T) or ((#)=dir_B)) + {box directions} @d dir_TL_=0 @d dir_TR_=1 @@ -10214,43 +9588,11 @@ applications of |scan_int| that have already been made inside of @d dir__BB=14 @d dir__BR=15 -@d is_mirrored(#)==dir_opposite(dir_primary[#])(dir_tertiary[#]) -@d is_rotated(#)==dir_parallel(dir_secondary[#])(dir_tertiary[#]) +@d is_mirrored(#)==(dir_opposite(dir_primary[#])(dir_tertiary[#])) +@d is_rotated(#)==(dir_parallel(dir_secondary[#])(dir_tertiary[#])) @d font_direction(#)==(# mod 16) @d box_direction(#)==(# div 4) -@d scan_single_dir(#)==begin -if scan_keyword("T") then #:=dir_T -else if scan_keyword("L") then #:=dir_L -else if scan_keyword("B") then #:=dir_B -else if scan_keyword("R") then #:=dir_R -else begin - print_err("Bad direction"); cur_val:=0; - goto exit; - end -end - -@<Declare procedures that scan restricted classes of integers@>= -procedure scan_direction; -var d1,d2,d3: integer; -begin -get_x_token; -if cur_cmd=assign_dir then begin - cur_val:=eqtb[cur_chr].int; - goto exit; - end -else back_input; -scan_single_dir(d1); -scan_single_dir(d2); -if dir_parallel(d1)(d2) then begin - print_err("Bad direction"); cur_val:=0; - goto exit; - end; -scan_single_dir(d3); -cur_val:=d1*8+dir_rearrange[d2]*4+d3; -exit: -end; - @ It is nice to have routines that say what they do, so the original |scan_eight_bit_int| is superceded by |scan_register_num| and |scan_mark_num|. It may become split up even further in the future. @@ -10351,12 +9693,6 @@ if (cur_val<0)or(cur_val>@'777777777) then help2("A numeric delimiter code must be between 0 and 2^{27}-1.")@/ ("I changed this one to zero."); int_error(cur_val); cur_val:=0; end; -cur_val1 := (((cur_val mod @"1000) div @"100) * @"10000) + - (cur_val mod @"100); -cur_val := cur_val div @"1000; -cur_val := ((cur_val div @"1000) * @"1000000) + - (((cur_val mod @"1000) div @"100) * @"10000) + - (cur_val mod @"100); end; procedure scan_fifty_one_bit_int; @@ -10430,7 +9766,7 @@ comes into action before any of the basic scanning routines has assigned them a value. @<Set init...@>= -cur_val:=0; cur_val_level:=int_val; radix:=0; cur_order:=0; +cur_val:=0; cur_val_level:=int_val; radix:=0; cur_order:=normal; @ The |scan_int| routine is used also to scan the integer part of a fraction; for example, the `\.3' in `\.{3.14159}' will be found by @@ -10473,10 +9809,10 @@ if cur_tok<cs_token_flag then if cur_cmd=right_brace then incr(align_state) else decr(align_state); end -else if cur_tok<cs_token_flag+null_cs then - cur_val:=cur_tok-cs_token_flag-active_base else begin {the value of a csname in this context is its name} - if single_letter(text(cur_tok-cs_token_flag)) then + if is_active_csname(cur_tok-cs_token_flag) then + cur_val:=active_csname_value(cur_tok-cs_token_flag) + else if single_letter(text(cur_tok-cs_token_flag)) then cur_val:=pool_to_unichar(str_start_macro(text(cur_tok-cs_token_flag))) else cur_val:=too_big_char; @@ -10672,9 +10008,9 @@ if inf then @<Scan for \(f)\.{fil} units; |goto attach_fraction| if found@>; @<Scan for \(u)units that are internal dimensions; |goto attach_sign| with |cur_val| set if found@>; if mu then @<Scan for \(m)\.{mu} units and |goto attach_fraction|@>; -if scan_keyword("true") then @<Adjust \(f)for the magnification ratio@>; +if scan_keyword('true') then @<Adjust \(f)for the magnification ratio@>; @.true@> -if scan_keyword("pt") then goto attach_fraction; {the easy case} +if scan_keyword('pt') then goto attach_fraction; {the easy case} @.pt@> @<Scan for \(a)all other units and adjust |cur_val| and |f| accordingly; |goto done| in the case of scaled points@>; @@ -10689,10 +10025,10 @@ L}' will lead to two error messages (one for each additional keyword Not so for luatex, it just parses the construct in reverse. @<Scan for \(f)\.{fil} units...@>= -if scan_keyword("filll") then begin cur_order:=filll; goto attach_fraction; end -else if scan_keyword("fill") then begin cur_order:=fill; goto attach_fraction; end -else if scan_keyword("fil") then begin cur_order:=fil; goto attach_fraction; end -else if scan_keyword("fi") then begin cur_order:=sfi; goto attach_fraction; end +if scan_keyword('filll') then begin cur_order:=filll; goto attach_fraction; end +else if scan_keyword('fill') then begin cur_order:=fill; goto attach_fraction; end +else if scan_keyword('fil') then begin cur_order:=fil; goto attach_fraction; end +else if scan_keyword('fi') then begin cur_order:=sfi; goto attach_fraction; end @ @<Scan for \(u)units that are internal dimensions...@>= save_cur_val:=cur_val; @@ -10706,11 +10042,11 @@ else begin if mu then v:=cur_val; goto found; end; if mu then goto not_found; -if scan_keyword("em") then v:=(@<The em width for |cur_font|@>) +if scan_keyword('em') then v:=(@<The em width for |cur_font|@>) @.em@> -else if scan_keyword("ex") then v:=(@<The x-height for |cur_font|@>) +else if scan_keyword('ex') then v:=(@<The x-height for |cur_font|@>) @.ex@> -else if scan_keyword("px") then v:=pdf_px_dimen +else if scan_keyword('px') then v:=pdf_px_dimen @.px@> else goto not_found; @<Scan an optional space@>; @@ -10719,7 +10055,7 @@ goto attach_sign; not_found: @ @<Scan for \(m)\.{mu} units and |goto attach_fraction|@>= -if scan_keyword("mu") then goto attach_fraction +if scan_keyword('mu') then goto attach_fraction @.mu@> else begin print_err("Illegal unit of measure ("); print("mu inserted)"); @.Illegal unit of measure@> @@ -10749,36 +10085,37 @@ in {\sl Technische Grundlagen zur Satzherstellung\/} (Bern, 1980). The Didot point has been newly standardized in 1978; it's now exactly $\rm 1\,nd=0.375\,mm$. Conversion uses the equation $0.375=21681/20320/72.27\cdot25.4$. -The new Cicero follows the new Didot point; $\rm 1\,nc=12\,nd$. These -would lead to the ratios $21681/20320$ and $65043/5080$, respectively. +The new Cicero follows the new Didot point; $\rm 1\,nc=12\,nd$. +These would lead to the ratios $21681/20320$ and $65043/5080$, +respectively. The closest approximations supported by the algorithm would be $11183/10481$ and $1370/107$. In order to maintain the -relation $\rm 1\,nc=12\,nd$, we pick the ratio $685/642$ for $\rm nd$, -however. +relation $\rm 1\,nc=12\,nd$, we pick the ratio $685/642$ for +$\rm nd$, however. @d set_conversion_end(#)== denom:=#; end @d set_conversion(#)==@+begin num:=#; set_conversion_end @<Scan for \(a)all other units and adjust |cur_val| and |f|...@>= -if scan_keyword("in") then set_conversion(7227)(100) +if scan_keyword('in') then set_conversion(7227)(100) @.in@> -else if scan_keyword("pc") then set_conversion(12)(1) +else if scan_keyword('pc') then set_conversion(12)(1) @.pc@> -else if scan_keyword("cm") then set_conversion(7227)(254) +else if scan_keyword('cm') then set_conversion(7227)(254) @.cm@> -else if scan_keyword("mm") then set_conversion(7227)(2540) +else if scan_keyword('mm') then set_conversion(7227)(2540) @.mm@> -else if scan_keyword("bp") then set_conversion(7227)(7200) +else if scan_keyword('bp') then set_conversion(7227)(7200) @.bp@> -else if scan_keyword("dd") then set_conversion(1238)(1157) +else if scan_keyword('dd') then set_conversion(1238)(1157) @.dd@> -else if scan_keyword("cc") then set_conversion(14856)(1157) +else if scan_keyword('cc') then set_conversion(14856)(1157) @.cc@> -else if scan_keyword("nd") then set_conversion(685)(642) +else if scan_keyword('nd') then set_conversion(685)(642) @.nd@> -else if scan_keyword("nc") then set_conversion(1370)(107) +else if scan_keyword('nc') then set_conversion(1370)(107) @.nc@> -else if scan_keyword("sp") then goto done +else if scan_keyword('sp') then goto done @.sp@> else @<Complain about unknown unit and |goto done2|@>; cur_val:=xn_over_d(cur_val,num,denom); @@ -10845,12 +10182,12 @@ exit:end; @ @<Create a new glue specification whose width is |cur_val|...@>= q:=new_spec(zero_glue); width(q):=cur_val; -if scan_keyword("plus") then +if scan_keyword('plus') then @.plus@> begin scan_dimen(mu,true,false); stretch(q):=cur_val; stretch_order(q):=cur_order; end; -if scan_keyword("minus") then +if scan_keyword('minus') then @.minus@> begin scan_dimen(mu,true,false); shrink(q):=cur_val; shrink_order(q):=cur_order; @@ -10878,15 +10215,15 @@ else begin height(q):=default_rule; depth(q):=0; rule_dir(q):=text_direction; end; -reswitch: if scan_keyword("width") then +reswitch: if scan_keyword('width') then @.width@> begin scan_normal_dimen; width(q):=cur_val; goto reswitch; end; -if scan_keyword("height") then +if scan_keyword('height') then @.height@> begin scan_normal_dimen; height(q):=cur_val; goto reswitch; end; -if scan_keyword("depth") then +if scan_keyword('depth') then @.depth@> begin scan_normal_dimen; depth(q):=cur_val; goto reswitch; end; @@ -11078,104 +10415,74 @@ such that |job_name_code| remains last. @d pdf_colorstack_init_code = pdftex_first_expand_code + 16 {command code for \.{\\pdfcolorstackinit}} @d luatex_revision_code = pdftex_first_expand_code + 17 {command code for \.{\\luatexrevision}} @d luatex_date_code = pdftex_first_expand_code + 18 {command code for \.{\\luatexdate}} -@d pdftex_convert_codes = pdftex_first_expand_code + 19 {end of \pdfTeX's command codes} +@d expanded_code = pdftex_first_expand_code + 19 {command code for \.{\\luatexdate}} +@d pdftex_convert_codes = pdftex_first_expand_code + 20 {end of \pdfTeX's command codes} @d job_name_code=pdftex_convert_codes {command code for \.{\\jobname}} @<Put each...@>= -primitive("number",convert,number_code);@/ +primitive_tex("number",convert,number_code,0);@/ @!@:number_}{\.{\\number} primitive@> -primitive("romannumeral",convert,roman_numeral_code);@/ +primitive_tex("romannumeral",convert,roman_numeral_code,0);@/ @!@:roman_numeral_}{\.{\\romannumeral} primitive@> -primitive("string",convert,string_code);@/ +primitive_tex("string",convert,string_code,0);@/ @!@:string_}{\.{\\string} primitive@> -primitive("meaning",convert,meaning_code);@/ +primitive_tex("meaning",convert,meaning_code,0);@/ @!@:meaning_}{\.{\\meaning} primitive@> -primitive("eTeXVersion",convert,etex_code);@/ +primitive_etex("eTeXVersion",convert,etex_code,0);@/ @!@:omega_version_}{\.{\\OmegaVersion} primitive@> -primitive("OmegaVersion",convert,omega_code);@/ +primitive_omega("OmegaVersion",convert,omega_code,0);@/ @!@:omega_version_}{\.{\\OmegaVersion} primitive@> -primitive("AlephVersion",convert,aleph_code);@/ +primitive_aleph("AlephVersion",convert,aleph_code,0);@/ @!@:aleph_version_}{\.{\\AlephVersion} primitive@> -primitive("fontname",convert,font_name_code);@/ +primitive_tex("fontname",convert,font_name_code,0);@/ @!@:font_name_}{\.{\\fontname} primitive@> -primitive("pdftexrevision",convert,pdftex_revision_code);@/ +primitive_pdftex("pdftexrevision",convert,pdftex_revision_code,0);@/ @!@:pdftex_revision_}{\.{\\pdftexrevision} primitive@> -primitive("luatexrevision",convert,luatex_revision_code);@/ +primitive_luatex("luatexrevision",convert,luatex_revision_code,0);@/ @!@:luatex_revision_}{\.{\\luatexrevision} primitive@> -primitive("luatexdatestamp",convert,luatex_date_code);@/ +primitive_luatex("luatexdatestamp",convert,luatex_date_code,0);@/ @!@:luatex_date_}{\.{\\luatexdatestamp} primitive@> -primitive("pdftexbanner",convert,pdftex_banner_code);@/ +primitive_pdftex("pdftexbanner",convert,pdftex_banner_code,0);@/ @!@:pdftex_banner_}{\.{\\pdftexbanner} primitive@> -primitive("pdffontname",convert,pdf_font_name_code);@/ +primitive_pdftex("pdffontname",convert,pdf_font_name_code,0);@/ @!@:pdf_font_name_}{\.{\\pdffontname} primitive@> -primitive("pdffontobjnum",convert,pdf_font_objnum_code);@/ +primitive_pdftex("pdffontobjnum",convert,pdf_font_objnum_code,0);@/ @!@:pdf_font_objnum_}{\.{\\pdffontobjnum} primitive@> -primitive("pdffontsize",convert,pdf_font_size_code);@/ +primitive_pdftex("pdffontsize",convert,pdf_font_size_code,0);@/ @!@:pdf_font_size_}{\.{\\pdffontsize} primitive@> -primitive("pdfpageref",convert,pdf_page_ref_code);@/ +primitive_pdftex("pdfpageref",convert,pdf_page_ref_code,0);@/ @!@:pdf_page_ref_}{\.{\\pdfpageref} primitive@> -primitive("leftmarginkern",convert,left_margin_kern_code);@/ +primitive_pdftex("leftmarginkern",convert,left_margin_kern_code,0);@/ @!@:left_margin_kern_}{\.{\\leftmarginkern} primitive@> -primitive("rightmarginkern",convert,right_margin_kern_code);@/ +primitive_pdftex("rightmarginkern",convert,right_margin_kern_code,0);@/ @!@:right_margin_kern_}{\.{\\rightmarginkern} primitive@> -primitive("pdfxformname",convert,pdf_xform_name_code);@/ +primitive_pdftex("pdfxformname",convert,pdf_xform_name_code,0);@/ @!@:pdf_xform_name_}{\.{\\pdfxformname} primitive@> -primitive("pdfcreationdate",convert,pdf_creation_date_code);@/ +primitive_pdftex("pdfcreationdate",convert,pdf_creation_date_code,0);@/ @!@:pdf_creation_date_}{\.{\\pdfcreationdate} primitive@> -primitive("pdfuniformdeviate",convert,uniform_deviate_code);@/ +primitive_pdftex("pdfuniformdeviate",convert,uniform_deviate_code,0);@/ @!@:uniform_deviate_}{\.{\\pdfuniformdeviate} primitive@> -primitive("pdfcolorstackinit",convert,pdf_colorstack_init_code);@/ +primitive_pdftex("pdfcolorstackinit",convert,pdf_colorstack_init_code,0);@/ @!@:pdf_colorstack_init_}{\.{\\pdfcolorstackinit} primitive@> -primitive("pdfnormaldeviate",convert,normal_deviate_code);@/ +primitive_pdftex("pdfnormaldeviate",convert,normal_deviate_code,0);@/ @!@:normal_deviate_}{\.{\\pdfnormaldeviate} primitive@> -primitive("directlua",convert,lua_code);@/ +primitive_core("directlua",convert,lua_code,0);@/ @!@:lua_}{\.{\\directlua} primitive@> -primitive("luaescapestring",convert,lua_escape_string_code);@/ +primitive_luatex("luaescapestring",convert,lua_escape_string_code,0);@/ @!@:lua_}{\.{\\luaescapestring} primitive@> +primitive_pdftex("expanded",convert,expanded_code,0);@/ +@!@:expanded_}{\.{\\expanded} primitive@> @# -primitive("jobname",convert,job_name_code);@/ +primitive_tex("jobname",convert,job_name_code,0);@/ @!@:job_name_}{\.{\\jobname} primitive@> -primitive("formatname",convert,format_name_code);@/ +primitive_luatex("formatname",convert,format_name_code,0);@/ @!@:format_name_}{\.{\\formatname} primitive@> -primitive("pdfinsertht",convert,pdf_insert_ht_code);@/ +primitive_pdftex("pdfinsertht",convert,pdf_insert_ht_code,0);@/ @!@:pdf_insert_ht_}{\.{\\pdfinsertht} primitive@> -primitive("pdfximagebbox",convert,pdf_ximage_bbox_code);@/ +primitive_pdftex("pdfximagebbox",convert,pdf_ximage_bbox_code,0);@/ @!@:pdf_ximage_bbox_}{\.{\\pdfximagebbox} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -convert: case chr_code of - number_code: print_esc("number"); - roman_numeral_code: print_esc("romannumeral"); - string_code: print_esc("string"); - meaning_code: print_esc("meaning"); - etex_code: print_esc("eTeXVersion"); - omega_code: print_esc("OmegaVersion"); - aleph_code: print_esc("AlephVersion"); - font_name_code: print_esc("fontname"); - pdftex_revision_code: print_esc("pdftexrevision"); - luatex_revision_code: print_esc("luatexrevision"); - luatex_date_code: print_esc("luatexdatestamp"); - pdftex_banner_code: print_esc("pdftexbanner"); - pdf_font_name_code: print_esc("pdffontname"); - pdf_font_objnum_code: print_esc("pdffontobjnum"); - pdf_font_size_code: print_esc("pdffontsize"); - pdf_page_ref_code: print_esc("pdfpageref"); - left_margin_kern_code: print_esc("leftmarginkern"); - right_margin_kern_code: print_esc("rightmarginkern"); - pdf_xform_name_code: print_esc("pdfxformname"); - pdf_creation_date_code: print_esc("pdfcreationdate"); - pdf_colorstack_init_code: print_esc("pdfcolorstackinit"); - uniform_deviate_code: print_esc("pdfuniformdeviate"); - normal_deviate_code: print_esc("pdfnormaldeviate"); - pdf_insert_ht_code: print_esc("pdfinsertht"); - pdf_ximage_bbox_code: print_esc("pdfximagebbox"); - lua_code: print_esc("directlua"); - lua_escape_string_code: print_esc("luaescapestring"); - @/@<Cases of |convert| for |print_cmd_chr|@>@/ - othercases print_esc("jobname") - endcases; - @ The procedure |conv_toks| uses |str_toks| to insert the token list for |convert| functions into the scanner; `\.{\\outer}' control sequences are allowed to follow `\.{\\string}' and `\.{\\meaning}'. @@ -11200,6 +10507,7 @@ p, q: pointer; @!j: integer; {second temp integer} @!b:pool_pointer; {base of temporary string} @!s: str_number; {first temp string} +@!sn: integer; {lua chunk name} @!u: str_number; {third temp string} @!junk: pointer; begin @@ -11213,6 +10521,12 @@ selector:=old_setting; junk:=str_toks(b); ins_list(link(temp_token_head)); exit: end; +@ @<Glob...@>= +in_lua_escape:boolean; + +@ @<Set init...@>= +in_lua_escape:=false; + @ @<Scan the argument for command |c|@>= case c of number_code,roman_numeral_code: scan_int; @@ -11262,11 +10576,11 @@ pdf_creation_date_code: job_name_code: if job_name=0 then open_log_file; pdf_colorstack_init_code: begin - bool := scan_keyword("page"); - if scan_keyword("direct") then + bool := scan_keyword('page'); + if scan_keyword('direct') then cur_val := direct_always else - if scan_keyword("page") then + if scan_keyword('page') then cur_val := direct_page else cur_val := set_origin; @@ -11297,54 +10611,77 @@ uniform_deviate_code: scan_int; normal_deviate_code: do_nothing; lua_escape_string_code: begin - u:=0; + u:=0; { check if a string is already being built} if str_start_macro(str_ptr)<pool_ptr then u:=make_string; save_scanner_status := scanner_status; save_def_ref := def_ref; save_warning_index := warning_index; scan_pdf_ext_toks; + bool := in_lua_escape; + in_lua_escape:=true; s := tokens_to_string(def_ref); + in_lua_escape:=bool; delete_token_ref(def_ref); def_ref := save_def_ref; warning_index := save_warning_index; scanner_status := save_scanner_status; junk := lua_str_toks(str_start_macro(s)); - ins_list(link(temp_token_head)); + ins_list(link(temp_token_head)); flush_str(s); - if u<>0 then begin decr(str_ptr); u:=0; end; + if u<>0 then begin decr(str_ptr); u:=0; end; + return; + end; +expanded_code: + begin + save_scanner_status := scanner_status; + save_warning_index := warning_index; + save_def_ref := def_ref; + save_cur_string; + scan_pdf_ext_toks; + warning_index := save_warning_index; + scanner_status := save_scanner_status; + ins_list(link(def_ref)); + def_ref := save_def_ref; + restore_cur_string; return; end; lua_code: begin - u:=0; - { check if a string is already being built} + u:=0; + { Have to check if a string is already being built, because lua code + may call library functions that may call C functions that + themselves use the string pool, like e.g. |maketexstring| } if str_start_macro(str_ptr)<pool_ptr then u:=make_string; save_scanner_status := scanner_status; save_def_ref := def_ref; save_warning_index := warning_index; - scan_register_num; - i := cur_val; + sn:=0; + if scan_keyword('name') then begin + scan_pdf_ext_toks; + sn := def_ref; + end; + @<Parse optional lua state integer, or an instance name to be stored in |sn|@>; scan_pdf_ext_toks; s := def_ref; warning_index := save_warning_index; def_ref := save_def_ref; scanner_status := save_scanner_status; luacstrings:=0; - luatokencall(i,s); + luatokencall(s,sn); delete_token_ref(s); - if u<>0 then begin + if u<>0 then begin if str_ptr=u+1 then decr(str_ptr) else begin {copy old string to the top location} i:=0; - str_room(length(u)); + str_room(length(u)); while i<length(u) do str_pool[pool_ptr+i]:=str_pool[str_start_macro(u)+i]; end; end; - if luacstrings>0 then - lua_string_start; + if luacstrings>0 then + lua_string_start; return; end; pdf_insert_ht_code: scan_register_num; @@ -11360,6 +10697,26 @@ pdf_ximage_bbox_code: begin @<Cases of `Scan the argument for command |c|'@> end {there are no other cases} +@ @<Parse optional lua state...@>= +begin + @<Get the next non-blank non-relax non-call token@>; + back_input; { have to push it back, whatever it is } + if cur_cmd<>left_brace then begin + scan_register_num; + if get_lua_name(cur_val) then + sn:=(cur_val-65536) + else begin + i:=tracing_online; + tracing_online:=1; + begin_diagnostic; + print_nl("Warning: support for multiple lua states has been dropped."); + print_nl(" Please stop using a number after \directlua and \latelua."); + end_diagnostic(true); + tracing_online:=i; + end; + end; +end + @ @<Print the result of command |c|@>= case c of number_code: print_int(cur_val); @@ -11437,12 +10794,15 @@ pdf_insert_ht_code: begin print("pt"); end; pdf_ximage_bbox_code: begin - case j of - 1: print_scaled(epdf_orig_x(i)); - 2: print_scaled(epdf_orig_y(i)); - 3: print_scaled(epdf_orig_x(i) + image_width(i)); - 4: print_scaled(epdf_orig_y(i) + image_height(i)); - endcases; + if is_pdf_image(i) then begin + case j of + 1: print_scaled(epdf_orig_x(i)); + 2: print_scaled(epdf_orig_y(i)); + 3: print_scaled(epdf_orig_x(i) + epdf_xsize(i)); + 4: print_scaled(epdf_orig_y(i) + epdf_ysize(i)); + endcases; + end else + print_scaled(0); print("pt"); end; format_name_code: print(format_name); @@ -11456,24 +10816,49 @@ begin is_convert:=(c=convert); end; -function the_convert_string (c:halfword):str_number; +function the_convert_string (c:halfword;i:integer):str_number; var old_setting:0..max_selector; {saved |selector| setting} - is_known:boolean; + is_known:boolean; begin old_setting:=selector; selector:=new_string; is_known:=true; case c of - etex_code: print(eTeX_version_string); - omega_code: print(Omega_version_string); - aleph_code: print(Aleph_version_string); - pdftex_revision_code: print(pdftex_revision); - luatex_revision_code: print(luatex_revision); - luatex_date_code: print_int(luatex_date_info); - pdftex_banner_code: print(pdftex_banner); - normal_deviate_code: print_int(norm_rand); - format_name_code: print(format_name); - job_name_code: print(job_name); + number_code: print_int(i); + roman_numeral_code: print_roman_int(i); + etex_code: print(eTeX_version_string); + omega_code: print(Omega_version_string); + aleph_code: print(Aleph_version_string); + pdftex_revision_code: print(pdftex_revision); + luatex_revision_code: print(luatex_revision); + luatex_date_code: print_int(luatex_date_info); + pdftex_banner_code: print(pdftex_banner); + normal_deviate_code: print_int(norm_rand); + uniform_deviate_code: print_int(unif_rand(i)); + format_name_code: print(format_name); + job_name_code: print(job_name); + font_name_code: begin + append_string(font_name(i)); + if font_size(i)<>font_dsize(i) then + begin print(" at "); print_scaled(font_size(i)); + print("pt"); + end; + end; + font_identifier_code: print_font_identifier(i); + pdf_page_ref_code: print_int(get_obj(obj_type_page, i, false)); + pdf_xform_name_code: print_int(obj_info(i)); + pdf_font_name_code, pdf_font_objnum_code: begin + set_ff(i); + if c = pdf_font_name_code then + print_int(obj_info(pdf_font_num(ff))) + else + print_int(pdf_font_num(ff)); + end; + pdf_font_size_code: begin + print_scaled(font_size(i)); + print("pt"); + end; + @/@<Cases of `Print the result of command |c|'@>@/ othercases is_known:=false end; @@ -11747,70 +11132,45 @@ We consider now the way \TeX\ handles various kinds of \.{\\if} commands. @d if_primitive_code=21 { `\.{\\ifprimitive}' } @<Put each...@>= -primitive("if",if_test,if_char_code); +primitive_tex("if",if_test,if_char_code,0); @!@:if_char_}{\.{\\if} primitive@> -primitive("ifcat",if_test,if_cat_code); +primitive_tex("ifcat",if_test,if_cat_code,0); @!@:if_cat_code_}{\.{\\ifcat} primitive@> -primitive("ifnum",if_test,if_int_code); +primitive_tex("ifnum",if_test,if_int_code,0); @!@:if_int_}{\.{\\ifnum} primitive@> -primitive("ifdim",if_test,if_dim_code); +primitive_tex("ifdim",if_test,if_dim_code,0); @!@:if_dim_}{\.{\\ifdim} primitive@> -primitive("ifodd",if_test,if_odd_code); +primitive_tex("ifodd",if_test,if_odd_code,0); @!@:if_odd_}{\.{\\ifodd} primitive@> -primitive("ifvmode",if_test,if_vmode_code); +primitive_tex("ifvmode",if_test,if_vmode_code,0); @!@:if_vmode_}{\.{\\ifvmode} primitive@> -primitive("ifhmode",if_test,if_hmode_code); +primitive_tex("ifhmode",if_test,if_hmode_code,0); @!@:if_hmode_}{\.{\\ifhmode} primitive@> -primitive("ifmmode",if_test,if_mmode_code); +primitive_tex("ifmmode",if_test,if_mmode_code,0); @!@:if_mmode_}{\.{\\ifmmode} primitive@> -primitive("ifinner",if_test,if_inner_code); +primitive_tex("ifinner",if_test,if_inner_code,0); @!@:if_inner_}{\.{\\ifinner} primitive@> -primitive("ifvoid",if_test,if_void_code); +primitive_tex("ifvoid",if_test,if_void_code,0); @!@:if_void_}{\.{\\ifvoid} primitive@> -primitive("ifhbox",if_test,if_hbox_code); +primitive_tex("ifhbox",if_test,if_hbox_code,0); @!@:if_hbox_}{\.{\\ifhbox} primitive@> -primitive("ifvbox",if_test,if_vbox_code); +primitive_tex("ifvbox",if_test,if_vbox_code,0); @!@:if_vbox_}{\.{\\ifvbox} primitive@> -primitive("ifx",if_test,ifx_code); +primitive_tex("ifx",if_test,ifx_code,0); @!@:ifx_}{\.{\\ifx} primitive@> -primitive("ifeof",if_test,if_eof_code); +primitive_tex("ifeof",if_test,if_eof_code,0); @!@:if_eof_}{\.{\\ifeof} primitive@> -primitive("iftrue",if_test,if_true_code); +primitive_tex("iftrue",if_test,if_true_code,0); @!@:if_true_}{\.{\\iftrue} primitive@> -primitive("iffalse",if_test,if_false_code); +primitive_tex("iffalse",if_test,if_false_code,0); @!@:if_false_}{\.{\\iffalse} primitive@> -primitive("ifcase",if_test,if_case_code); +primitive_tex("ifcase",if_test,if_case_code,0); @!@:if_case_}{\.{\\ifcase} primitive@> -primitive("ifprimitive",if_test,if_primitive_code); +primitive_luatex("ifprimitive",if_test,if_primitive_code,0); @!@:if_primitive_}{\.{\\ifprimitive} primitive@> -primitive("ifpdfprimitive",if_test,if_primitive_code); +primitive_pdftex("ifpdfprimitive",if_test,if_primitive_code,0); @!@:if_primitive_}{\.{\\ifpdfprimitive} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -if_test: begin if chr_code>=unless_code then print_esc("unless"); -case chr_code mod unless_code of - if_cat_code:print_esc("ifcat"); - if_int_code:print_esc("ifnum"); - if_dim_code:print_esc("ifdim"); - if_odd_code:print_esc("ifodd"); - if_vmode_code:print_esc("ifvmode"); - if_hmode_code:print_esc("ifhmode"); - if_mmode_code:print_esc("ifmmode"); - if_inner_code:print_esc("ifinner"); - if_void_code:print_esc("ifvoid"); - if_hbox_code:print_esc("ifhbox"); - if_vbox_code:print_esc("ifvbox"); - ifx_code:print_esc("ifx"); - if_eof_code:print_esc("ifeof"); - if_true_code:print_esc("iftrue"); - if_false_code:print_esc("iffalse"); - if_case_code:print_esc("ifcase"); - if_primitive_code:print_esc("ifprimitive"); - @/@<Cases of |if_test| for |print_cmd_chr|@>@/ - othercases print_esc("if") - endcases; -end; - @ Conditions can be inside conditions, and this nesting has a stack that is independent of the |save_stack|. @@ -11827,8 +11187,6 @@ Otherwise |cond_ptr| points to a two-word node; the |type|, |subtype|, and |cond_ptr| at the next level, and the second word contains the corresponding |if_line|. -@d if_node==49 -@d if_node_size=2 {number of words in stack entry for conditionals} @d if_limit_subtype(#)==subtype(#+1) @d if_limit_type(#)==type(#+1) @d if_line_field(#)==vlink(#+1) @@ -11847,19 +11205,14 @@ corresponding |if_line|. cond_ptr:=null; if_limit:=normal; cur_if:=0; if_line:=0; @ @<Put each...@>= -primitive("fi",fi_or_else,fi_code); +primitive_tex("fi",fi_or_else,fi_code,0); @!@:fi_}{\.{\\fi} primitive@> text(frozen_fi):="fi"; eqtb[frozen_fi]:=eqtb[cur_val]; -primitive("or",fi_or_else,or_code); +primitive_tex("or",fi_or_else,or_code,0); @!@:or_}{\.{\\or} primitive@> -primitive("else",fi_or_else,else_code); +primitive_tex("else",fi_or_else,else_code,0); @!@:else_}{\.{\\else} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -fi_or_else: if chr_code=fi_code then print_esc("fi") - else if chr_code=or_code then print_esc("or") - else print_esc("else"); - @ When we skip conditional text, we keep track of the line number where skipping began, for use in error messages. @@ -12057,17 +11410,13 @@ else b:=(type(p)=vlist_node); end @ An active character will be treated as category 13 following -\.{\\if\\noexpand} or following \.{\\ifcat\\noexpand}. We use the fact that -active characters have the smallest tokens, among all control sequences. - -The |(biggest_char-number_active_chars)| part is needed because only the -bottom two planes are present as active characters in |eqtb|. +\.{\\if\\noexpand} or following \.{\\ifcat\\noexpand}. @d get_x_token_or_active_char==@t@>@; begin get_x_token; - if cur_cmd=relax then if cur_chr=no_expand_flag then + if cur_cmd=relax then if cur_chr=no_expand_flag then if is_active_csname(cur_cs) then begin cur_cmd:=active_char; - cur_chr:=cur_tok-cs_token_flag-active_base+(biggest_char-number_active_chars); + cur_chr:=active_csname_value(cur_tok-cs_token_flag); end; end @@ -12199,31 +11548,7 @@ System-dependent changes to allow such things should probably be made with reluctance, and only when an entire file name that includes spaces is ``quoted'' somehow. -@ In order to isolate the system-dependent aspects of file names, the -@^system dependencies@> -system-independent parts of \TeX\ are expressed in terms -of three system-dependent -procedures called |begin_name|, |more_name|, and |end_name|. In -essence, if the user-specified characters of the file name are $c_1\ldots c_n$, -the system-independent driver program does the operations -$$|begin_name|;\,|more_name|(c_1);\,\ldots\,;|more_name|(c_n); -\,|end_name|.$$ -These three procedures communicate with each other via global variables. -Afterwards the file name will appear in the string pool as three strings -called |cur_name|\penalty10000\hskip-.05em, -|cur_area|, and |cur_ext|; the latter two are null (i.e., -|""|), unless they were explicitly specified by the user. - -Actually the situation is slightly more complicated, because \TeX\ needs -to know when the file name ends. The |more_name| routine is a function -(with side effects) that returns |true| on the calls |more_name|$(c_1)$, -\dots, |more_name|$(c_{n-1})$. The final call |more_name|$(c_n)$ -returns |false|; or, it returns |true| and the token following $c_n$ is -something like `\.{\\hbox}' (i.e., not a character). In other words, -|more_name| is supposed to return |true| unless it is sure that the -file name has been completely scanned; and |end_name| is supposed to be able -to finish the assembly of |cur_name|, |cur_area|, and |cur_ext| regardless of -whether $|more_name|(c_n)$ returned |true| or |false|. +@ Here are the global values that file names will be scanned into. @<Glob...@>= @!cur_name:str_number; {name of file just scanned} @@ -12261,60 +11586,6 @@ from place to place. @d OMEGA_ocp_area=="OmegaOCPs:" @.OmegaOCPs@> -@ Here now is the first of the system-dependent routines for file name scanning. -@^system dependencies@> - -@p procedure begin_name; -begin area_delimiter:=0; ext_delimiter:=0; -end; - -@ And here's the second. The string pool might change as the file name is -being scanned, since a new \.{\\csname} might be entered; therefore we keep -|area_delimiter| and |ext_delimiter| relative to the beginning of the current -string, instead of assigning an absolute address like |pool_ptr| to them. -@^system dependencies@> - -@p function more_name(@!c:ASCII_code):boolean; -begin if c=" " then more_name:=false -else begin str_room(1); append_char(c); {contribute |c| to the current string} - if (c=">")or(c=":") then - begin area_delimiter:=cur_length; ext_delimiter:=0; - end - else if (c=".")and(ext_delimiter=0) then ext_delimiter:=cur_length; - more_name:=true; - end; -end; - -@ The third. -@^system dependencies@> - -@p procedure end_name; -begin if str_ptr+3>(max_strings+string_offset) then - overflow("number of strings",max_strings-init_str_ptr); -@:TeX capacity exceeded number of strings}{\quad number of strings@> -if area_delimiter=0 then cur_area:="" -else begin cur_area:=str_ptr; - str_start_macro(str_ptr+1):=str_start_macro(str_ptr)+area_delimiter; incr(str_ptr); - end; -if ext_delimiter=0 then - begin cur_ext:=""; cur_name:=make_string; - end -else begin cur_name:=str_ptr; - str_start_macro(str_ptr+1):=str_start_macro(str_ptr)+ext_delimiter-area_delimiter-1; - incr(str_ptr); cur_ext:=make_string; - end; -end; - -@ Conversely, here is a routine that takes three strings and prints a file -name that might have produced them. (The routine is system dependent, because -some operating systems put the file area last instead of first.) -@^system dependencies@> - -@<Basic printing...@>= -procedure print_file_name(@!n,@!a,@!e:integer); -begin slow_print(a); slow_print(n); slow_print(e); -end; - @ Another system-dependent routine is needed to convert three internal \TeX\ strings into the |nameoffile| value that is used to open files. The present code @@ -12346,7 +11617,7 @@ and extensions related to format files. @d format_default_length=20 {length of the |TEX_format_default| string} @d format_area_length=11 {length of its area part} @d format_ext_length=4 {length of its `\.{.fmt}' part} -@d format_extension=".fmt" {the extension, as a \.{WEB} constant} +@d format_extension=='.fmt' {the extension, as a \.{WEB} constant} @<Glob...@>= @!TEX_format_default:packed array[1..format_default_length] of char; @@ -12437,33 +11708,6 @@ we dare not use `|str_room|'. @d b_make_name_string(#)==make_name_string @d w_make_name_string(#)==make_name_string -@p function make_name_string:str_number; -var k:1..file_name_size; {index into |nameoffile|} -begin if (pool_ptr+namelength>pool_size)or(str_ptr=max_strings)or - (cur_length>0) then - make_name_string:="?" -else begin for k:=1 to namelength do append_char(nameoffile[k]); - make_name_string:=make_string; - end; -end; - -@ Now let's consider the ``driver'' -routines by which \TeX\ deals with file names -in a system-independent manner. First comes a procedure that looks for a -file name in the input by calling |get_x_token| for the information. - -@p procedure scan_file_name; -label done; -begin name_in_progress:=true; begin_name; -@<Get the next non-blank non-call...@>; -loop@+begin if (cur_cmd>other_char)or(cur_chr>biggest_char) then {not a character} - begin back_input; goto done; - end; - if not more_name(cur_chr) then goto done; - get_x_token; - end; -done: end_name; name_in_progress:=false; -end; @ The global variable |name_in_progress| is used to prevent recursive use of |scan_file_name|, since the |begin_name| and other procedures @@ -12486,67 +11730,20 @@ and `\.{.fmt}' in the names of \TeX's output files. We have |job_name=0| if and only if the `\.{log}' file has not been opened, except of course for a short time just after |job_name| has become nonzero. -@<Initialize the output...@>= -job_name:=0; name_in_progress:=false; log_opened:=false; - -@ Here is a routine that manufactures the output file names, assuming that -|job_name<>0|. It ignores and changes the current settings of |cur_area| -and |cur_ext|. - @d pack_cur_name==pack_file_name(cur_name,cur_area,cur_ext) -@p procedure pack_job_name(@!s:str_number); {|s = ".log"|, |".dvi"|, or - |format_extension|} -begin cur_area:=""; cur_ext:=s; -cur_name:=job_name; pack_cur_name; -end; - -@ If some trouble arises when \TeX\ tries to open a file, the following -routine calls upon the user to supply another file name. Parameter~|s| -is used in the error message to identify the type of file; parameter~|e| -is the default extension if none is given. Upon exit from the routine, -variables |cur_name|, |cur_area|, |cur_ext|, and |nameoffile| are -ready for another attempt at file opening. - -@p procedure prompt_file_name(@!s,@!e:str_number); -label done; -var k:0..buf_size; {index into |buffer|} -begin if interaction=scroll_mode then wake_up_terminal; -if s="input file name" then print_err("I can't find file `") -@.I can't find file x@> -else print_err("I can't write on file `"); -@.I can't write on file x@> -print_file_name(cur_name,cur_area,cur_ext); print("'."); -if e=".tex" then show_context; -print_nl("Please type another "); print(s); -@.Please type...@> -if interaction<scroll_mode then - fatal_error("*** (job aborted, file error in nonstop mode)"); -@.job aborted, file error...@> -clear_terminal; prompt_input(": "); @<Scan file name in the buffer@>; -if cur_ext="" then cur_ext:=e; -pack_cur_name; -end; - -@ @<Scan file name in the buffer@>= -begin begin_name; k:=first; -while (buffer[k]=" ")and(k<last) do incr(k); -loop@+ begin if k=last then goto done; - if not more_name(buffer[k]) then goto done; - incr(k); - end; -done:end_name; -end +@<Initialize the output...@>= +job_name:=0; name_in_progress:=false; log_opened:=false; @ Here's an example of how these conventions are used. Whenever it is time to ship out a box of stuff, we shall use the macro |ensure_dvi_open|. @d ensure_dvi_open==if output_file_name=0 then begin if job_name=0 then open_log_file; - pack_job_name(".dvi"); + pack_job_name('.dvi'); while not lua_b_open_out(dvi_file) do - prompt_file_name("file name for output",".dvi"); - dvi_file:=name_file_pointer ; + prompt_file_name('file name for output','.dvi'); + dvi_file:=name_file_pointer ; output_file_name:=b_make_name_string(dvi_file); end @@ -12568,7 +11765,7 @@ var old_setting:0..max_selector; {previous |selector| setting} begin old_setting:=selector; if job_name=0 then job_name:="texput"; @.texput@> -pack_job_name(".log"); +pack_job_name('.log'); while not lua_a_open_out(addressof(log_file),0) do @<Try to get a different log file name@>; log_file := name_file_pointer; log_name:=a_make_name_string(log_file); @@ -12582,10 +11779,8 @@ if not callback_defined(start_run_callback) then begin if buffer[l]=end_line_char then decr(l); { TODO: multichar endlinechar} for k:=1 to l do print(buffer[k]); print_ln; {now the transcript file contains the first line of input} - end -else begin - flush_loggable_info; -end; + end; +flush_loggable_info; {should be done always} selector:=old_setting+2; {|log_only| or |term_and_log|} end; @@ -12605,7 +11800,7 @@ this file. @<Try to get a different log file name@>= begin selector:=term_only; -prompt_file_name("transcript file name",".log"); +prompt_file_name('transcript file name','.log'); end @ @<Print the banner...@>= @@ -12625,12 +11820,12 @@ when an `\.{\\input}' command is being processed. label done; var temp_str:str_number; begin scan_file_name; {set |cur_name| to desired file name} -if cur_ext="" then cur_ext:=".tex"; +{|if cur_ext="" then cur_ext:=".tex";|} pack_cur_name; loop@+ begin begin_file_reading; {set up |cur_file| and new level of input} if lua_a_open_in(cur_file,0) then goto done; end_file_reading; {remove the level that didn't work} - prompt_file_name("input file name",".tex"); + prompt_file_name('input file name','.tex'); end; done: cur_file := name_file_pointer; @@ -12651,6 +11846,7 @@ state:=new_line; if name=str_ptr-1 then {we can conserve string pool space now} begin flush_string; name:=cur_name; end; +@<Prepare new file {\sl Sync\TeX} information@>; @<Read the first line of the new file@>; end; @@ -12696,7 +11892,7 @@ create_null_font; font_bytes:=0; @ @<Put each...@>= -primitive("nullfont",set_font,null_font); +primitive_tex("nullfont",set_font,null_font,0); @!@:null_font_}{\.{\\nullfont} primitive@> text(frozen_null_font):="nullfont"; eqtb[frozen_null_font]:=eqtb[cur_val]; @@ -12712,13 +11908,13 @@ procedure scan_font_ident; var f:internal_font_number; @!m:halfword; begin @<Get the next non-blank non-call...@>; -if (cur_cmd=def_font) or (cur_cmd=letterspace_font) then f:=cur_font +if (cur_cmd=def_font) or (cur_cmd=letterspace_font) or (cur_cmd=pdf_copy_font) then f:=cur_font else if cur_cmd=set_font then begin f:=cur_chr; set_font_touched(f,1); end else if cur_cmd=def_family then begin - m:=cur_chr; scan_math_family_int; f:=equiv(m+cur_val); + m:=cur_chr; scan_math_family_int; f:=fam_fnt(cur_val,m); set_font_touched(f,1); end else begin print_err("Missing font identifier"); @@ -12799,14 +11995,22 @@ prints a warning message unless the user has suppressed it. @p procedure char_warning(@!f:internal_font_number;@!c:integer); var old_setting: integer; {saved value of |tracing_online|} + k:0..22; {index to current digit; we assume that $0\L n<16^{22}$} begin if tracing_lost_chars>0 then begin old_setting:=tracing_online; if tracing_lost_chars>1 then tracing_online:=1; begin begin_diagnostic; print_nl("Missing character: There is no "); @.Missing character@> - print(c); print(" ("); - print_int(c); print(") in font "); + print(c); print(" (U+"); + k:=0; + if c<16 then print_char('0'); + if c<256 then print_char('0'); + if c<4096 then print_char('0'); + repeat dig[k]:=c mod 16; c:=c div 16; incr(k); + until c=0; + print_the_digs(k); + print(") in font "); print_font_name(f); print_char("!"); end_diagnostic(false); end; @@ -12877,7 +12081,7 @@ procedure add_ocp_stack(min_index:integer; min_value:scaled); var p:ocp_lstack_index; llstack_no:scaled; counter:integer; - m:scaled; + m:scaled; begin m:=min_value; { TH: whatever this is ..} p:=ocp_list_lstack(holding[min_index]); @@ -13014,7 +12218,7 @@ ocp_info(null_ocp)(offset_ocp_info+4) := 36; {|OTP_STOP|} @ @<Put each...@>= -primitive("nullocp", set_ocp, null_ocp); +primitive_omega("nullocp", set_ocp, null_ocp,0); text(frozen_null_ocp) := "nullocp"; eqtb[frozen_null_ocp] := eqtb[cur_val]; geq_define(ocp_active_number_base, data, 0); @@ -13317,7 +12521,7 @@ ocp_lstackmem_ptr:=1; @ $\Omega$ always knows at least one ocp list, namely the null ocp list. @ @<Put each...@>= -primitive("nullocplist", set_ocp_list, null_ocp_list); +primitive_omega("nullocplist", set_ocp_list, null_ocp_list,0); text(frozen_null_ocp_list) := "nullocplist"; eqtb[frozen_null_ocp_list] := eqtb[cur_val]; @@ -14274,15 +13478,13 @@ dvi_out(font_check_2(f)); dvi_out(font_check_3(f));@/ dvi_four(font_size(f)); dvi_four(font_dsize(f));@/ -dvi_out(strlen(font_area(f))); +dvi_out(0); { |font_area(f)| is unused } dvi_out(strlen(font_name(f))); @<Output the font name whose internal number is |f|@>; end; @ @<Output the font name whose internal number is |f|@>= fa := get_font_name(f); k := 0; -while fa[k]<>0 do begin dvi_out(fa[k]); incr(k); end; -fa := get_font_area(f); k := 0; while fa[k]<>0 do begin dvi_out(fa[k]); incr(k); end @ Versions of \TeX\ intended for small computers might well choose to omit @@ -14343,8 +13545,6 @@ byte number of the \.{DVI} command in question (including the appropriate on the stack; and the |vinfo| field encodes the options for possible change in the \.{DVI} command. -@d movement_node=48 -@d movement_node_size=3 {number of words per entry in the down and right stacks} @d location(#)==vmem(#+1).int {\.{DVI} byte number for a movement command} @<Glob...@>= @@ -14359,16 +13559,13 @@ of motion, and |o| is either |down1| or |right1|. We use the fact that the command codes have convenient arithmetic properties: |y1-down1=w1-right1| and |z1-down1=x1-right1|. -@d dvi_set(#)==oval:=#; ocmd:=set1; out_cmd -@d dvi_put(#)==oval:=#; ocmd:=put1; out_cmd -@d dvi_set_rule_end(#)==dvi_four(#) -@d dvi_set_rule(#)==dvi_out(set_rule); dvi_four(#); dvi_set_rule_end -@d dvi_put_rule_end(#)==dvi_four(#) -@d dvi_put_rule(#)==dvi_out(put_rule); dvi_four(#); dvi_put_rule_end -@d dvi_right(#)==dvi_out(right4); dvi_four(#); -@d dvi_left(#)==dvi_out(right4); dvi_four(-#); -@d dvi_down(#)==dvi_out(down4); dvi_four(#); -@d dvi_up(#)==dvi_out(down4); dvi_four(-#); +@d dvi_set_end(#)==dvi.h := dvi.h + (#); end +@d dvi_set(#)==begin synch_dvi_with_pos; oval:=#; ocmd:=set1; out_cmd; dvi_set_end +@d dvi_put(#)==begin synch_dvi_with_pos; oval:=#; ocmd:=put1; out_cmd; end +@d dvi_set_rule_end(#)==dvi_four(#); dvi.h := dvi.h + (#); end +@d dvi_set_rule(#)==begin synch_dvi_with_pos; dvi_out(set_rule); dvi_four(#); dvi_set_rule_end +@d dvi_put_rule_end(#)==dvi_four(#); end +@d dvi_put_rule(#)==begin synch_dvi_with_pos; dvi_out(put_rule); dvi_four(#); dvi_put_rule_end @p procedure movement(@!w:scaled;@!o:eight_bits); label exit,found,not_found,2,1; @@ -14376,48 +13573,16 @@ var mstate:small_number; {have we seen a |y| or |z|?} @!p,@!q:pointer; {current and top nodes on the stack} @!k:integer; {index into |dvi_buf|, modulo |dvi_buf_size|} begin -case box_direction(dvi_direction) of - dir_TL_: begin - end; - dir_TR_: begin - if o=right1 then negate(w); - end; - dir_LT_: begin - if o=right1 then o:=down1 - else o:=right1; - end; - dir_LB_: begin - if o=right1 then begin - o:=down1; negate(w); - end - else o:=right1; - end; - dir_BL_: begin - if o=down1 then negate(w); - end; - dir_BR_: begin - negate(w); - end; - dir_RT_: begin - if o=right1 then o:=down1 - else begin o:=right1; negate(w); - end; - end; - dir_RB_: begin - if o=right1 then o:=down1 else o:=right1; - negate(w); - end; - end; if false then begin -q:=new_node(movement_node,0); {new node for the top of the stack} -width(q):=w; location(q):=dvi_offset+dvi_ptr; -if o=down1 then - begin vlink(q):=down_ptr; down_ptr:=q; - end -else begin vlink(q):=right_ptr; right_ptr:=q; - end; -@<Look at the other stack entries until deciding what sort of \.{DVI} command - to generate; |goto found| if node |p| is a ``hit''@>; + q:=new_node(movement_node,0); {new node for the top of the stack} + width(q):=w; location(q):=dvi_offset+dvi_ptr; + if o=down1 then + begin vlink(q):=down_ptr; down_ptr:=q; + end + else begin vlink(q):=right_ptr; right_ptr:=q; + end; + @<Look at the other stack entries until deciding what sort of \.{DVI} command + to generate; |goto found| if node |p| is a ``hit''@>; end; @<Generate a |down| or |right| command for |w| and |return|@>; found: @<Generate a |y0| or |z0| command in order to reuse a previous @@ -14593,14 +13758,14 @@ distances are computed in terms of glue together with the depth and height of adjacent boxes, and we want the \.{DVI} file to lump these three quantities together into a single motion. -Therefore, \TeX\ maintains two pairs of global variables: |dvi_h| and |dvi_v| +Therefore, \TeX\ maintains two pairs of global variables: |dvi.h| and |dvi.v| are the |h| and |v| coordinates corresponding to the commands actually -output to the \.{DVI} file, while |cur_h| and |cur_v| are the coordinates +output to the \.{DVI} file, while |cur.h| and |cur.v| are the coordinates corresponding to the current state of the output routines. Coordinate -changes will accumulate in |cur_h| and |cur_v| without being reflected +changes will accumulate in |cur.h| and |cur.v| without being reflected in the output, until such a change becomes necessary or desirable; we -can call the |movement| procedure whenever we want to make |dvi_h=cur_h| -or |dvi_v=cur_v|. +can call the |movement| procedure whenever we want to make |dvi.h=pos.h| +or |dvi.v=pos.v|. The current font reflected in the \.{DVI} output is called |dvi_f|; there is no need for a `\\{cur\_f}' variable. @@ -14608,40 +13773,80 @@ there is no need for a `\\{cur\_f}' variable. The depth of nesting of |hlist_out| and |vlist_out| is called |cur_s|; this is essentially the depth of |push| commands in the \.{DVI} output. -@d synch_h==if cur_h<>dvi_h then - begin movement(cur_h-dvi_h,right1); dvi_h:=cur_h; +@d synch_h==if pos.h <> dvi.h then begin + movement(pos.h - dvi.h, right1); + dvi.h := pos.h; end -@d synch_v==if cur_v<>dvi_v then - begin movement(cur_v-dvi_v,down1); dvi_v:=cur_v; + +@d synch_v==if pos.v <> dvi.v then begin + movement(dvi.v - pos.v, down1); + dvi.v := pos.v; end -@<Glob...@>= -@!dvi_h,@!dvi_v:scaled; {a \.{DVI} reader program thinks we are here} -@!cur_h,@!cur_v:scaled; {\TeX\ thinks we are here} +@d synch_dvi_with_pos==begin + synch_h; synch_v; + end + +@d synch_pos_with_cur==case box_direction(dvi_direction) of + dir_TL_: begin pos.h := box_pos.h + cur.h; pos.v := box_pos.v - cur.v; end; + dir_TR_: begin pos.h := box_pos.h - cur.h; pos.v := box_pos.v - cur.v; end; + dir_BL_: begin pos.h := box_pos.h + cur.h; pos.v := box_pos.v + cur.v; end; + dir_BR_: begin pos.h := box_pos.h - cur.h; pos.v := box_pos.v + cur.v; end; + dir_LT_: begin pos.h := box_pos.h + cur.v; pos.v := box_pos.v - cur.h; end; + dir_RT_: begin pos.h := box_pos.h - cur.v; pos.v := box_pos.v - cur.h; end; + dir_LB_: begin pos.h := box_pos.h + cur.v; pos.v := box_pos.v + cur.h; end; + dir_RB_: begin pos.h := box_pos.h - cur.v; pos.v := box_pos.v + cur.h; end; + end + +@d synch_dvi_with_cur==begin + synch_pos_with_cur; + synch_dvi_with_pos; +end + +@d set_to_zero(#)==begin #.h := 0; #.v := 0; end + +@ @p function synch_p_with_c(cur: scaledpos): scaledpos; +var pos: scaledpos; +begin + synch_pos_with_cur; + synch_p_with_c := pos; +end; + +@ @<Types...@>= +@!scaledpos = record + h, v: scaled; + end; + +@ @<Glob...@>= +@!cur: scaledpos; {\TeX\ position relative to origin of the surrounding box, in box coordinate system} +@!box_pos: scaledpos; {position of box origin in page coordinates} +@!pos: scaledpos; {global position on page, in $\rm sp$, from lower left page corner} +@!dvi: scaledpos; {a \.{DVI} position in page coordinates, in sync with DVI file} @!dvi_f:internal_font_number; {the current font} @!cur_s:integer; {current depth of output box nesting, initially $-1$} @ @<Calculate DVI page dimensions and margins@>= if page_width > 0 then - cur_page_width := page_width + cur_page_size.h := page_width else - cur_page_width := width(p) + 2*(h_offset + one_inch); + case box_direction(dvi_direction) of + dir_TL_, dir_BL_: cur_page_size.h := width(p) + 2 * page_left_offset; + dir_TR_, dir_BR_: cur_page_size.h := width(p) + 2 * page_right_offset; + dir_LT_, dir_LB_: cur_page_size.h := height(p) + depth(p) + 2 * page_left_offset; + dir_RT_, dir_RB_: cur_page_size.h := height(p) + depth(p) + 2 * page_right_offset; + end; if page_height > 0 then - cur_page_height := page_height -else - cur_page_height := height(p) + depth(p) + 2*(v_offset + one_inch); -if page_bottom_offset <> 0 then - cur_bottom_offset := page_bottom_offset -else - cur_bottom_offset := 2*one_inch; -if page_right_offset <> 0 then - cur_right_offset := page_right_offset + cur_page_size.v := page_height else - cur_right_offset := 2*one_inch - + case box_direction(dvi_direction) of + dir_TL_, dir_TR_: cur_page_size.v := height(p) + depth(p) + 2 * page_top_offset; + dir_BL_, dir_BR_: cur_page_size.v := height(p) + depth(p) + 2 * page_bottom_offset; + dir_LT_, dir_RT_: cur_page_size.v := width(p) + 2 * page_top_offset; + dir_LB_, dir_RB_: cur_page_size.v := width(p) + 2 * page_bottom_offset; + end @ @<Initialize variables as |ship_out| begins@>= -dvi_h:=0; dvi_v:=0; cur_h:=0; cur_v:=0; dvi_f:=null_font; +set_to_zero(dvi); set_to_zero(cur); dvi_f:=null_font; @<Calculate DVI page dimensions and margins@>; ensure_dvi_open; if total_pages=0 then @@ -14649,6 +13854,10 @@ if total_pages=0 then @^preamble of \.{DVI} file@> dvi_four(25400000); dvi_four(473628672); {conversion ratio for sp} prepare_mag; dvi_four(mag); {magnification factor is frozen} + if mag<>1000 then + one_true_inch:=xn_over_d(one_hundred_inch,10,mag) + else + one_true_inch:=one_inch; old_setting:=selector; selector:=new_string; print(" LuaTeX output "); print_int(year); print_char("."); print_two(month); print_char("."); print_two(day); @@ -14661,20 +13870,20 @@ if total_pages=0 then @ When |hlist_out| is called, its duty is to output the box represented by the |hlist_node| pointed to by |temp_ptr|. The reference point of that -box has coordinates |(cur_h,cur_v)|. +box has coordinates |(cur.h,cur.v)|. Similarly, when |vlist_out| is called, its duty is to output the box represented by the |vlist_node| pointed to by |temp_ptr|. The reference point of that -box has coordinates |(cur_h,cur_v)|. +box has coordinates |(cur.h,cur.v)|. @^recursion@> @p procedure@?vlist_out; forward; {|hlist_out| and |vlist_out| are mutually recursive} -@ The recursive procedures |hlist_out| and |vlist_out| each have local variables -|save_h| and |save_v| to hold the values of |dvi_h| and |dvi_v| just before -entering a new level of recursion. In effect, the values of |save_h| and -|save_v| on \TeX's run-time stack correspond to the values of |h| and |v| +@ The recursive procedures |hlist_out| and |vlist_out| each have a local variable +|save_dvi| to hold the value of |dvi| just before +entering a new level of recursion. In effect, the value of |save_dvi| +on \TeX's run-time stack corresponds to the values of |h| and |v| that a \.{DVI}-reading program will push onto its coordinate stack. @d move_past=13 {go to this label when advancing past glue or a rule} @@ -14687,18 +13896,19 @@ label move_past, fin_rule, next_p; var base_line: scaled; {the baseline coordinate for this box} c_wd,c_ht,c_dp: scaled; {the real width, height and depth of the character} +w: scaled; { temporary value for directional width calculation } +dir_nest: integer; { for tracking nested direction nodes } edge_v: scaled; edge_h: scaled; effective_horizontal: scaled; basepoint_horizontal: scaled; basepoint_vertical: scaled; -saving_h: scaled; -saving_v: scaled; save_direction: integer; dir_ptr,dir_tmp:pointer; -dvi_dir_h,dvi_dir_ptr,dvi_temp_ptr:integer; @!left_edge: scaled; {the left coordinate for this box} -@!save_h,@!save_v: scaled; {what |dvi_h| and |dvi_v| should pop to} +@!save_h: scaled; {what |cur.h| should pop to} +@!save_dvi: scaledpos; {what |dvi| should pop to} +@!save_box_pos: scaledpos; {what |box_pos| should pop to} @!this_box: pointer; {pointer to containing box} @!g_order: glue_ord; {applicable order of infinity for glue} @!g_sign: normal..shrinking; {selects type of glue} @@ -14711,22 +13921,24 @@ dvi_dir_h,dvi_dir_ptr,dvi_temp_ptr:integer; @!edge:scaled; {right edge of sub-box or leader space} @!glue_temp:real; {glue value before rounding} @!cur_glue:real; {glue seen so far} +@!save_cur_glue:real; { saved version, for direction switch } @!cur_g:scaled; {rounded equivalent of |cur_glue| times the glue ratio} +@!save_cur_g:scaled; { saved version, for direction switch } begin cur_g:=0; cur_glue:=float_constant(0); this_box:=temp_ptr; g_order:=glue_order(this_box); g_sign:=glue_sign(this_box); p:=list_ptr(this_box); +set_to_zero(cur); box_pos:=pos; save_direction:=dvi_direction; dvi_direction:=box_dir(this_box); @<DIR: Initialize |dir_ptr| for |ship_out|@>; -saving_h:=dvi_h; saving_v:=dvi_v; incr(cur_s); if cur_s>0 then dvi_out(push); if cur_s>max_push then max_push:=cur_s; -save_loc:=dvi_offset+dvi_ptr; base_line:=cur_v; left_edge:=cur_h; +save_loc:=dvi_offset+dvi_ptr; base_line:=cur.v; left_edge:=cur.h; +@<Start hlist {\sl Sync\TeX} information record@>; while p<>null do @<Output node |p| for |hlist_out| and move to the next node, - maintaining the condition |cur_v=base_line|@>; -cur_h:=saving_h; cur_v:=saving_v; -synch_h; synch_v; + maintaining the condition |cur.v=base_line|@>; +@<Finish hlist {\sl Sync\TeX} information record@>; prune_movements(save_loc); if cur_s>0 then dvi_pop(save_loc); decr(cur_s); @@ -14758,128 +13970,130 @@ reaching a non-|char_node|. The program uses the fact that |set_char_0=0|. @<Output node |p| for |hlist_out|...@>= if is_char_node(p) then - begin synch_h; synch_v; - repeat f:=font(p); c:=character(p); + begin + repeat + if x_displace(p)<>0 then cur.h := cur.h + x_displace(p); + if y_displace(p)<>0 then cur.v := cur.v - y_displace(p); + synch_pos_with_cur; f:=font(p); c:=character(p); ci := char_info_short(f,c); if f<>dvi_f then @<Change font |dvi_f| to |f|@>; - if is_rotated(dvi_direction) then begin - c_ht:=charinfo_width(ci) div 2; - c_wd:=charinfo_height(ci)+charinfo_depth(ci); - c_dp:=0; - end - else begin - c_ht:=charinfo_height(ci); - c_dp:=charinfo_depth(ci); - c_wd:=charinfo_width(ci); - end; - cur_h:=cur_h+c_wd; + c_ht:=charinfo_height(ci); + c_dp:=charinfo_depth(ci); + c_wd:=charinfo_width(ci); if (font_natural_dir(f)<>-1) then begin case font_direction(dvi_direction) of dir__LT,dir__LB: begin - dvi_set(c); + dvi_set(c)(c_wd); end; dir__RT,dir__RB: begin dvi_put(c); - dvi_left(c_wd); end; - dir__TL,dir__TR: begin + dir__TL,dir__TR,dir__BL,dir__BR: begin + c_wd := c_ht + c_dp; dvi_put(c); - dvi_down(c_wd); end; - dir__BL,dir__BR: begin + dir__LL: begin + pos_right(c_wd); dvi_put(c); - dvi_up(c_wd); end; - dir__LL,dir__LR: begin + dir__RR: begin + pos_left(c_wd); dvi_put(c); - dvi_right(c_wd); end; - dir__RL,dir__RR: begin + dir__LR: begin + dvi_set(c)(c_wd); + end; + dir__RL: begin dvi_put(c); - dvi_left(c_wd); end; - dir__TT,dir__TB: begin + dir__TT: begin + c_wd := c_ht + c_dp; + pos_down(c_wd); dvi_put(c); - dvi_down(c_wd); end; - dir__BT,dir__BB: begin + dir__TB: begin + c_wd := c_ht + c_dp; dvi_put(c); - dvi_up(c_wd); end; - end; + dir__BT: begin + c_wd := c_ht + c_dp; + dvi_put(c); + end; + dir__BB: begin + c_wd := c_ht + c_dp; + pos_up(c_wd); + dvi_put(c); + end; + endcases; end else begin case font_direction(dvi_direction) of dir__LT: begin - dvi_set(c); + dvi_set(c)(c_wd); end; dir__LB: begin - dvi_down(c_ht); - dvi_set(c); - dvi_up(c_ht); + pos_down(c_ht); + dvi_set(c)(c_wd); end; dir__RT: begin - dvi_left(c_wd); + pos_left(c_wd); dvi_put(c); end; dir__RB: begin - dvi_left(c_wd); - dvi_down(c_ht); + pos_down(c_ht); + pos_left(c_wd); dvi_put(c); - dvi_up(c_ht); end; dir__TL: begin - dvi_down(c_wd); - dvi_left(c_ht); + pos_down(c_ht); + pos_left(c_wd); dvi_put(c); - dvi_right(c_ht); + c_wd := c_ht + c_dp; end; dir__TR: begin - dvi_down(c_wd); - dvi_left(c_dp); + pos_down(c_ht); dvi_put(c); - dvi_right(c_dp); + c_wd := c_ht + c_dp; end; dir__BL: begin - dvi_left(c_ht); + pos_left(c_wd); + pos_up(c_dp); dvi_put(c); - dvi_right(c_ht); - dvi_up(c_wd); + c_wd := c_ht + c_dp; end; dir__BR: begin - dvi_left(c_dp); + pos_up(c_dp); dvi_put(c); - dvi_right(c_dp); - dvi_up(c_wd); + c_wd := c_ht + c_dp; end; dir__LL,dir__LR: begin - dvi_down(c_ht); - dvi_put(c); - dvi_up(c_ht); - dvi_right(c_wd); + pos_down((c_ht - c_dp) div 2); + dvi_set(c)(c_wd); end; dir__RL,dir__RR: begin - dvi_left(c_wd); - dvi_down(c_ht); + pos_left(c_wd); + pos_down((c_ht - c_dp) div 2); dvi_put(c); - dvi_up(c_ht); end; dir__TT,dir__TB: begin - dvi_down(c_wd); - dvi_left(c_ht); + pos_down(c_ht); + pos_left(c_wd div 2); dvi_put(c); - dvi_right(c_ht); + c_wd:=c_ht + c_dp; end; dir__BT,dir__BB: begin - dvi_left(c_ht); + pos_up(c_dp); + pos_left(c_wd div 2); dvi_put(c); - dvi_right(c_ht); - dvi_up(c_wd); + c_wd := c_ht + c_dp; end; - end; + endcases; end; + if x_displace(p)<>0 then cur.h := cur.h - x_displace(p); + if y_displace(p)<>0 then cur.v := cur.v + y_displace(p); + cur.h:=cur.h+c_wd; p:=vlink(p); until not is_char_node(p); - dvi_h:=cur_h; + @<Record current point {\sl Sync\TeX} information@>; end else @<Output the non-|char_node| |p| for |hlist_out| and move to the next node@> @@ -14894,8 +14108,8 @@ end @ @<Output the non-|char_node| |p| for |hlist_out|...@>= begin case type(p) of -hlist_node,vlist_node:@<Output a box in an hlist@>; -rule_node: begin +hlist_node_case,vlist_node_case:@<Output a box in an hlist@>; +rule_node_case: begin if not (dir_orthogonal(dir_primary[rule_dir(p)])(dir_primary[dvi_direction])) then begin rule_ht:=height(p); rule_dp:=depth(p); rule_wd:=width(p); @@ -14907,21 +14121,31 @@ rule_node: begin end; goto fin_rule; end; -whatsit_node: @<Output the whatsit node |p| in an hlist@>; -glue_node: @<Move right or output leaders@>; -disc_node: if vlink(no_break(p))<>null then begin +whatsit_node_case: @<Output the whatsit node |p| in an hlist@>; +glue_node_case: @<Move right or output leaders@>; +disc_node_case: if vlink(no_break(p))<>null then begin vlink(tlink(no_break(p))):=vlink(p); q:=vlink(no_break(p)); vlink(no_break(p)):=null; vlink(p):=q; end; -margin_kern_node,kern_node:cur_h:=cur_h+width(p); -math_node:cur_h:=cur_h+surround(p); +margin_kern_node_case:cur.h:=cur.h+width(p); +kern_node_case: begin + @<Record |kern_node| {\sl Sync\TeX} information@>; + cur.h:=cur.h+width(p); +end; +math_node_case: begin + @<Record |math_node| {\sl Sync\TeX} information@>; + cur.h:=cur.h+surround(p); +end; othercases do_nothing endcases;@/ goto next_p; fin_rule: @<Output a rule in an hlist@>; -move_past: cur_h:=cur_h+rule_wd; +move_past: begin + cur.h:=cur.h+rule_wd; + @<Record horizontal |rule_node| or |glue_node| {\sl Sync\TeX} information@>; +end; next_p:p:=vlink(p); end @@ -14938,7 +14162,7 @@ if not (dir_orthogonal(dir_primary[box_dir(p)])(dir_primary[dvi_direction])) end else begin effective_horizontal:=height(p)+depth(p); - if not (is_mirrored(box_dir(p))) then + if not is_mirrored(box_dir(p)) then if dir_eq(dir_primary[box_dir(p)])(dir_secondary[dvi_direction]) then basepoint_horizontal:=height(p) else @@ -14953,20 +14177,25 @@ else begin else basepoint_vertical:= (width(p) div 2); end; -if not (is_mirrored(dvi_direction)) then +if not is_mirrored(dvi_direction) then basepoint_vertical := basepoint_vertical + shift_amount(p) {shift the box `down'} else basepoint_vertical := basepoint_vertical - shift_amount(p); {shift the box `up'} -if list_ptr(p)=null then cur_h:=cur_h + effective_horizontal +if list_ptr(p)=null then begin + @<Record void list {\sl Sync\TeX} information@>; + cur.h:=cur.h + effective_horizontal; + end else begin - temp_ptr:=p; edge:=cur_h; cur_h:=cur_h + basepoint_horizontal; - edge_v:=cur_v; cur_v:=base_line + basepoint_vertical; - synch_h; synch_v; save_h:=dvi_h; save_v:=dvi_v; + temp_ptr:=p; edge:=cur.h; cur.h:=cur.h + basepoint_horizontal; + edge_v:=cur.v; cur.v:=base_line + basepoint_vertical; + synch_dvi_with_cur; save_dvi:=dvi; + save_box_pos:=box_pos; if type(p)=vlist_node then vlist_out@+else hlist_out; - dvi_h:=save_h; dvi_v:=save_v; - cur_h:=edge+effective_horizontal; cur_v:=base_line; + dvi:=save_dvi; + box_pos:=save_box_pos; + cur.h:=edge+effective_horizontal; cur.v:=base_line; end end @@ -14975,46 +14204,42 @@ if is_running(rule_ht) then rule_ht:=height(this_box); if is_running(rule_dp) then rule_dp:=depth(this_box); rule_ht:=rule_ht+rule_dp; {this is the rule thickness} if (rule_ht>0)and(rule_wd>0) then {we don't output empty rules} - begin synch_h; cur_v:=base_line+rule_dp; synch_v; - case font_direction(dvi_direction) of - dir__LT: begin + begin cur.v:=base_line+rule_dp; synch_pos_with_cur; + case box_direction(dvi_direction) of + dir_TL_: begin dvi_set_rule(rule_ht)(rule_wd); end; - dir__LB: begin - dvi_down(rule_ht); + dir_BL_: begin + pos_down(rule_ht); dvi_set_rule(rule_ht)(rule_wd); - dvi_up(rule_ht); end; - dir__RT: begin - dvi_left(rule_wd); + dir_TR_: begin + pos_left(rule_wd); dvi_put_rule(rule_ht)(rule_wd); end; - dir__RB: begin - dvi_left(rule_wd); - dvi_down(rule_ht); + dir_BR_: begin + pos_left(rule_wd); + pos_down(rule_ht); dvi_put_rule(rule_ht)(rule_wd); - dvi_up(rule_ht); end; - dir__TL: begin - dvi_down(rule_wd); - dvi_left(rule_ht); + dir_LT_: begin + pos_down(rule_wd); + pos_left(rule_ht); dvi_set_rule(rule_wd)(rule_ht); end; - dir__TR: begin - dvi_down(rule_wd); + dir_RT_: begin + pos_down(rule_wd); dvi_put_rule(rule_wd)(rule_ht); end; - dir__BL: begin - dvi_left(rule_ht); + dir_LB_: begin + pos_left(rule_ht); dvi_set_rule(rule_wd)(rule_ht); - dvi_up(rule_wd); end; - dir__BR: begin + dir_RB_: begin dvi_put_rule(rule_wd)(rule_ht); - dvi_up(rule_wd); end; end; - cur_v:=base_line; dvi_h:=dvi_h+rule_wd; + cur.v:=base_line; end @ @d billion==float_constant(1000000000) @@ -15061,50 +14286,50 @@ else leader_wd:=height(leader_box)+depth(leader_box); if (leader_wd>0)and(rule_wd>0) then begin rule_wd:=rule_wd+10; {compensate for floating-point rounding} - edge:=cur_h+rule_wd; lx:=0; - @<Let |cur_h| be the position of the first box, and set |leader_wd+lx| + edge:=cur.h+rule_wd; lx:=0; + @<Let |cur.h| be the position of the first box, and set |leader_wd+lx| to the spacing between corresponding parts of boxes@>; - while cur_h+leader_wd<=edge do - @<Output a leader box at |cur_h|, - then advance |cur_h| by |leader_wd+lx|@>; - cur_h:=edge-10; goto next_p; + while cur.h+leader_wd<=edge do + @<Output a leader box at |cur.h|, + then advance |cur.h| by |leader_wd+lx|@>; + cur.h:=edge-10; goto next_p; end; end @ The calculations related to leaders require a bit of care. First, in the -case of |a_leaders| (aligned leaders), we want to move |cur_h| to +case of |a_leaders| (aligned leaders), we want to move |cur.h| to |left_edge| plus the smallest multiple of |leader_wd| for which the result -is not less than the current value of |cur_h|; i.e., |cur_h| should become +is not less than the current value of |cur.h|; i.e., |cur.h| should become $|left_edge|+|leader_wd|\times\lceil -(|cur_h|-|left_edge|)/|leader_wd|\rceil$. The program here should work in +(|cur.h|-|left_edge|)/|leader_wd|\rceil$. The program here should work in all cases even though some implementations of \PASCAL\ give nonstandard -results for the |div| operation when |cur_h| is less than |left_edge|. +results for the |div| operation when |cur.h| is less than |left_edge|. -In the case of |c_leaders| (centered leaders), we want to increase |cur_h| +In the case of |c_leaders| (centered leaders), we want to increase |cur.h| by half of the excess space not occupied by the leaders; and in the -case of |x_leaders| (expanded leaders) we increase |cur_h| +case of |x_leaders| (expanded leaders) we increase |cur.h| by $1/(q+1)$ of this excess space, where $q$ is the number of times the leader box will be replicated. Slight inaccuracies in the division might accumulate; half of this rounding error is placed at each end of the leaders. -@<Let |cur_h| be the position of the first box, ...@>= +@<Let |cur.h| be the position of the first box, ...@>= if subtype(p)=a_leaders then - begin save_h:=cur_h; - cur_h:=left_edge+leader_wd*((cur_h-left_edge)@!div leader_wd); - if cur_h<save_h then cur_h:=cur_h+leader_wd; + begin save_h:=cur.h; + cur.h:=left_edge+leader_wd*((cur.h-left_edge)@!div leader_wd); + if cur.h<save_h then cur.h:=cur.h+leader_wd; end else begin lq:=rule_wd div leader_wd; {the number of box copies} lr:=rule_wd mod leader_wd; {the remaining space} - if subtype(p)=c_leaders then cur_h:=cur_h+(lr div 2) + if subtype(p)=c_leaders then cur.h:=cur.h+(lr div 2) else begin lx:=lr div (lq+1); - cur_h:=cur_h+((lr-(lq-1)*lx) div 2); + cur.h:=cur.h+((lr-(lq-1)*lx) div 2); end; end @ The `\\{synch}' operations here are intended to decrease the number of bytes needed to specify horizontal and vertical motion in the \.{DVI} output. -@<Output a leader box at |cur_h|, ...@>= +@<Output a leader box at |cur.h|, ...@>= begin if not (dir_orthogonal(dir_primary[box_dir(leader_box)])(dir_primary[dvi_direction])) then begin @@ -15115,7 +14340,7 @@ if not (dir_orthogonal(dir_primary[box_dir(leader_box)])(dir_primary[dvi_directi basepoint_horizontal:=0; end else begin - if not (is_mirrored(box_dir(leader_box))) then + if not is_mirrored(box_dir(leader_box)) then if dir_eq(dir_primary[box_dir(leader_box)])(dir_secondary[dvi_direction]) then basepoint_horizontal:=height(leader_box) else @@ -15130,21 +14355,23 @@ else begin else basepoint_vertical:= (width(leader_box) div 2); end; -if not (is_mirrored(dvi_direction)) then +if not is_mirrored(dvi_direction) then basepoint_vertical := basepoint_vertical + shift_amount(leader_box) {shift the box `down'} else basepoint_vertical := basepoint_vertical - shift_amount(leader_box); {shift the box `up'} temp_ptr:=leader_box; -edge_h:=cur_h; cur_h:=cur_h + basepoint_horizontal; -edge_v:=cur_v; cur_v:=base_line + basepoint_vertical; -synch_h; synch_v; save_h:=dvi_h; save_v:=dvi_v; +edge_h:=cur.h; cur.h:=cur.h + basepoint_horizontal; +edge_v:=cur.v; cur.v:=base_line + basepoint_vertical; +synch_dvi_with_cur; save_dvi:=dvi; +save_box_pos:=box_pos; outer_doing_leaders:=doing_leaders; doing_leaders:=true; if type(leader_box)=vlist_node then vlist_out@+else hlist_out; doing_leaders:=outer_doing_leaders; -dvi_h:=save_h; dvi_v:=save_v; -cur_h:=edge_h+leader_wd+lx; cur_v:=base_line; +box_pos:=save_box_pos; +dvi:=save_dvi; +cur.h:=edge_h+leader_wd+lx; cur.v:=base_line; end @ The |vlist_out| routine is similar to |hlist_out|, but a bit simpler. @@ -15153,7 +14380,9 @@ end label move_past, fin_rule, next_p; var left_edge: scaled; {the left coordinate for this box} @!top_edge: scaled; {the top coordinate for this box} -@!save_h,@!save_v: scaled; {what |dvi_h| and |dvi_v| should pop to} +@!save_v: scaled; {what |cur.v| should pop to} +@!save_dvi: scaledpos; {what |dvi| should pop to} +@!save_box_pos: scaledpos; {what |box_pos| should pop to} @!this_box: pointer; {pointer to containing box} @!g_order: glue_ord; {applicable order of infinity for glue} @!g_sign: normal..shrinking; {selects type of glue} @@ -15172,24 +14401,23 @@ var left_edge: scaled; {the left coordinate for this box} @!basepoint_horizontal: scaled; @!basepoint_vertical: scaled; @!edge_v: scaled; -@!saving_v: scaled; -@!saving_h: scaled; begin cur_g:=0; cur_glue:=float_constant(0); this_box:=temp_ptr; g_order:=glue_order(this_box); g_sign:=glue_sign(this_box); p:=list_ptr(this_box); {pdfassert(p<>0);} -saving_v:=dvi_v; saving_h:=dvi_h; +set_to_zero(cur); box_pos:=pos; save_direction:=dvi_direction; dvi_direction:=box_dir(this_box); incr(cur_s); if cur_s>0 then dvi_out(push); if cur_s>max_push then max_push:=cur_s; -save_loc:=dvi_offset+dvi_ptr; left_edge:=cur_h; cur_v:=cur_v-height(this_box); -top_edge:=cur_v; +save_loc:=dvi_offset+dvi_ptr; left_edge:=cur.h; +@<Start vlist {\sl Sync\TeX} information record@>; +cur.v:=cur.v-height(this_box); +top_edge:=cur.v; while p<>null do @<Output node |p| for |vlist_out| and move to the next node, - maintaining the condition |cur_h=left_edge|@>; -cur_v:=saving_v; cur_h:=saving_h; -synch_v; synch_h; + maintaining the condition |cur.h=left_edge|@>; +@<Finish vlist {\sl Sync\TeX} information record@>; prune_movements(save_loc); if cur_s>0 then dvi_pop(save_loc); decr(cur_s); @@ -15205,8 +14433,8 @@ end @ @<Output the non-|char_node| |p| for |vlist_out|@>= begin case type(p) of -hlist_node,vlist_node:@<Output a box in a vlist@>; -rule_node: begin +hlist_node_case,vlist_node_case:@<Output a box in a vlist@>; +rule_node_case: begin if not (dir_orthogonal(dir_primary[rule_dir(p)])(dir_primary[dvi_direction])) then begin rule_ht:=height(p); rule_dp:=depth(p); rule_wd:=width(p); @@ -15218,14 +14446,14 @@ rule_node: begin end; goto fin_rule; end; -whatsit_node: @<Output the whatsit node |p| in a vlist@>; -glue_node: @<Move down or output leaders@>; -kern_node:cur_v:=cur_v+width(p); +whatsit_node_case: @<Output the whatsit node |p| in a vlist@>; +glue_node_case: @<Move down or output leaders@>; +kern_node_case:cur.v:=cur.v+width(p); othercases do_nothing endcases;@/ goto next_p; fin_rule: @<Output a rule in a vlist, |goto next_p|@>; -move_past: cur_v:=cur_v+rule_ht; +move_past: cur.v:=cur.v+rule_ht; end @ The |synch_v| here allows the \.{DVI} output to use one-byte commands @@ -15237,7 +14465,7 @@ begin if not (dir_orthogonal(dir_primary[box_dir(p)])(dir_primary[dvi_direction])) then begin effective_vertical:=height(p)+depth(p); - if (type(p)=hlist_node) and (is_mirrored(box_dir(p))) then + if (type(p)=hlist_node) and is_mirrored(box_dir(p)) then basepoint_vertical:=depth(p) else basepoint_vertical:=height(p); @@ -15248,7 +14476,7 @@ if not (dir_orthogonal(dir_primary[box_dir(p)])(dir_primary[dvi_direction])) end else begin effective_vertical:=width(p); - if not (is_mirrored(box_dir(p))) then + if not is_mirrored(box_dir(p)) then if dir_eq(dir_primary[box_dir(p)])(dir_secondary[dvi_direction]) then basepoint_horizontal:=height(p) else @@ -15266,61 +14494,60 @@ else begin basepoint_horizontal := basepoint_horizontal + shift_amount(p); {shift the box `right'} if list_ptr(p)=null then begin - cur_v:=cur_v+effective_vertical; + cur.v:=cur.v+effective_vertical; + @<Record void list {\sl Sync\TeX} information@>; end else begin - synch_h; synch_v; edge_v:=cur_v; - cur_h:=left_edge + basepoint_horizontal; - cur_v:=cur_v + basepoint_vertical; - synch_h; synch_v; save_h:=dvi_h; save_v:=dvi_v; + edge_v:=cur.v; + cur.h:=left_edge + basepoint_horizontal; + cur.v:=cur.v + basepoint_vertical; + synch_dvi_with_cur; save_dvi:=dvi; + save_box_pos:=box_pos; temp_ptr:=p; if type(p)=vlist_node then vlist_out@+else hlist_out; - dvi_h:=save_h; dvi_v:=save_v; - cur_h:=left_edge; cur_v:=edge_v + effective_vertical; + dvi:=save_dvi; + box_pos:=save_box_pos; + cur.h:=left_edge; cur.v:=edge_v + effective_vertical; end end @ @<Output a rule in a vlist...@>= if is_running(rule_wd) then rule_wd:=width(this_box); rule_ht:=rule_ht+rule_dp; {this is the rule thickness} -cur_v:=cur_v+rule_ht; +cur.v:=cur.v+rule_ht; if (rule_ht>0)and(rule_wd>0) then {we don't output empty rules} - begin synch_h; synch_v; - case font_direction(dvi_direction) of - dir__LT: begin + begin synch_pos_with_cur; + case box_direction(dvi_direction) of + dir_TL_: begin dvi_put_rule(rule_ht)(rule_wd); end; - dir__LB: begin - dvi_down(rule_ht); + dir_BL_: begin + pos_down(rule_ht); dvi_put_rule(rule_ht)(rule_wd); - dvi_up(rule_ht); end; - dir__RT: begin - dvi_left(rule_wd); + dir_TR_: begin + pos_left(rule_wd); dvi_set_rule(rule_ht)(rule_wd); end; - dir__RB: begin - dvi_down(rule_ht); - dvi_left(rule_wd); + dir_BR_: begin + pos_down(rule_ht); + pos_left(rule_wd); dvi_set_rule(rule_ht)(rule_wd); - dvi_up(rule_ht); end; - dir__TL: begin - dvi_down(rule_wd); - dvi_left(rule_ht); + dir_LT_: begin + pos_down(rule_wd); + pos_left(rule_ht); dvi_set_rule(rule_wd)(rule_ht); - dvi_up(rule_wd); end; - dir__TR: begin - dvi_down(rule_wd); + dir_RT_: begin + pos_down(rule_wd); dvi_put_rule(rule_wd)(rule_ht); - dvi_up(rule_wd); end; - dir__BL: begin - dvi_left(rule_ht); + dir_LB_: begin + pos_left(rule_ht); dvi_set_rule(rule_wd)(rule_ht); end; - dir__BR: begin + dir_RB_: begin dvi_put_rule(rule_wd)(rule_ht); end; end; @@ -15363,39 +14590,39 @@ else leader_ht:=width(leader_box); if (leader_ht>0)and(rule_ht>0) then begin rule_ht:=rule_ht+10; {compensate for floating-point rounding} - edge:=cur_v+rule_ht; lx:=0; - @<Let |cur_v| be the position of the first box, and set |leader_ht+lx| + edge:=cur.v+rule_ht; lx:=0; + @<Let |cur.v| be the position of the first box, and set |leader_ht+lx| to the spacing between corresponding parts of boxes@>; - while cur_v+leader_ht<=edge do - @<Output a leader box at |cur_v|, - then advance |cur_v| by |leader_ht+lx|@>; - cur_v:=edge-10; goto next_p; + while cur.v+leader_ht<=edge do + @<Output a leader box at |cur.v|, + then advance |cur.v| by |leader_ht+lx|@>; + cur.v:=edge-10; goto next_p; end; end -@ @<Let |cur_v| be the position of the first box, ...@>= +@ @<Let |cur.v| be the position of the first box, ...@>= if subtype(p)=a_leaders then - begin save_v:=cur_v; - cur_v:=top_edge+leader_ht*((cur_v-top_edge)@!div leader_ht); - if cur_v<save_v then cur_v:=cur_v+leader_ht; + begin save_v:=cur.v; + cur.v:=top_edge+leader_ht*((cur.v-top_edge)@!div leader_ht); + if cur.v<save_v then cur.v:=cur.v+leader_ht; end else begin lq:=rule_ht div leader_ht; {the number of box copies} lr:=rule_ht mod leader_ht; {the remaining space} - if subtype(p)=c_leaders then cur_v:=cur_v+(lr div 2) + if subtype(p)=c_leaders then cur.v:=cur.v+(lr div 2) else begin lx:=lr div (lq+1); - cur_v:=cur_v+((lr-(lq-1)*lx) div 2); + cur.v:=cur.v+((lr-(lq-1)*lx) div 2); end; end -@ When we reach this part of the program, |cur_v| indicates the top of a +@ When we reach this part of the program, |cur.v| indicates the top of a leader box, not its baseline. -@<Output a leader box at |cur_v|, ...@>= +@<Output a leader box at |cur.v|, ...@>= begin if not (dir_orthogonal(dir_primary[box_dir(leader_box)])(dir_primary[dvi_direction])) then begin effective_vertical:=height(leader_box)+depth(leader_box); - if (type(leader_box)=hlist_node) and (is_mirrored(box_dir(leader_box))) then + if (type(leader_box)=hlist_node) and is_mirrored(box_dir(leader_box)) then basepoint_vertical:=depth(leader_box) else basepoint_vertical:=height(leader_box); @@ -15406,7 +14633,7 @@ if not (dir_orthogonal(dir_primary[box_dir(leader_box)])(dir_primary[dvi_directi end else begin effective_vertical:=width(leader_box); - if not (is_mirrored(box_dir(leader_box))) then + if not is_mirrored(box_dir(leader_box)) then if dir_eq(dir_primary[box_dir(leader_box)])(dir_secondary[dvi_direction]) then basepoint_horizontal:=height(leader_box) else @@ -15424,15 +14651,17 @@ else begin basepoint_horizontal := basepoint_horizontal + shift_amount(leader_box); {shift the box `right'} temp_ptr:=leader_box; -cur_h:=left_edge + basepoint_horizontal; -edge_v:=cur_v ; -cur_v:=cur_v + basepoint_vertical; -synch_h; synch_v; save_h:=dvi_h; save_v:=dvi_v; +cur.h:=left_edge + basepoint_horizontal; +edge_v:=cur.v ; +cur.v:=cur.v + basepoint_vertical; +synch_dvi_with_cur; save_dvi:=dvi; +save_box_pos:=box_pos; outer_doing_leaders:=doing_leaders; doing_leaders:=true; if type(leader_box)=vlist_node then vlist_out@+else hlist_out; doing_leaders:=outer_doing_leaders; -dvi_h:=save_h; dvi_v:=save_v; -cur_h:=left_edge; cur_v:=edge_v+leader_ht+lx; +box_pos:=save_box_pos; +dvi:=save_dvi; +cur.h:=left_edge; cur.v:=edge_v+leader_ht+lx; end @ The |hlist_out| and |vlist_out| procedures are now complete, so we are @@ -15447,9 +14676,10 @@ var page_loc:integer; {location of the current |bop|} pre_callback_id:integer; post_callback_id:integer; ret:boolean; -begin -pre_callback_id:=callback_defined(start_page_number_callback); -post_callback_id:=callback_defined(stop_page_number_callback); +begin +@<Start sheet {\sl Sync\TeX} information record@>; +pre_callback_id:=callback_defined(start_page_number_callback); +post_callback_id:=callback_defined(stop_page_number_callback); if (tracing_output>0)and(pre_callback_id=0) then begin print_nl(""); print_ln; print("Completed box being shipped out"); @@ -15480,6 +14710,7 @@ update_terminal; {progress report} @<Flush the box from memory, showing statistics if requested@>; if post_callback_id>0 then ret:=run_callback(post_callback_id,'->'); +@<Finish sheet {\sl Sync\TeX} information record@>; end; @ @<Flush the box from memory, showing statistics if requested@>= @@ -15506,63 +14737,42 @@ page_loc:=dvi_offset+dvi_ptr; dvi_out(bop); for k:=0 to 9 do dvi_four(count(k)); dvi_four(last_bop); last_bop:=page_loc; +{Think in upright page/paper coordinates): First preset |pos.h| and |pos.v| to the DVI origin.} +pos.h := one_true_inch; +pos.v := cur_page_size.v - one_true_inch; +box_pos := pos; dvi := pos; +{Then calculate |cur.h| and |cur.v| within the upright coordinate system +for the DVI origin depending on the |page_direction|.} dvi_direction:=page_direction; case box_direction(dvi_direction) of dir_TL_,dir_LT_: begin + cur.h := page_left_offset; + cur.v := page_top_offset; end; dir_TR_,dir_RT_: begin - dvi_right(cur_page_width-cur_right_offset); - dvi_h:=-cur_right_offset; - end; -dir_RB_,dir_BR_: begin - dvi_right(cur_page_width-cur_right_offset); - dvi_down(cur_page_height-cur_bottom_offset); - dvi_h:=-cur_right_offset; - dvi_v:=-cur_bottom_offset; + cur.h := cur_page_size.h - page_right_offset; + cur.v := page_top_offset; end; dir_BL_,dir_LB_: begin - dvi_down(cur_page_height-cur_bottom_offset); - dvi_v:=-cur_bottom_offset; - end; -end; -cur_h:=h_offset; -cur_v:=height(p)+v_offset; -case box_direction(dvi_direction) of -dir_TL_: begin - dvi_down(cur_v); - dvi_right(cur_h); - end; -dir_TR_: begin - dvi_down(cur_v); - dvi_right(-cur_h); + cur.h := page_left_offset; + cur.v := cur_page_size.v - page_bottom_offset; end; -dir_LT_: begin - dvi_right(cur_v); - dvi_down(cur_h); - end; -dir_LB_: begin - dvi_right(cur_v); - dvi_down(-cur_h); - end; -dir_BL_: begin - dvi_down(-cur_v); - dvi_right(cur_h); - end; -dir_BR_: begin - dvi_down(-cur_v); - dvi_right(-cur_h); - end; -dir_RT_: begin - dvi_right(-cur_v); - dvi_down(cur_h); - end; -dir_RB_: begin - dvi_right(-cur_v); - dvi_down(-cur_h); - end; -end; -dvi_h:=cur_h; -dvi_v:=cur_v; +dir_RB_,dir_BR_: begin + cur.h := cur_page_size.h - page_right_offset; + cur.v := cur_page_size.v - page_bottom_offset; + end; +end; +cur.h := cur.h - one_true_inch; {correct for DVI origin} +cur.v := cur.v - one_true_inch; +{The movement is actually done within the upright page coordinate system.} +dvi_direction := dir_TL_; {only temporarily for this adjustment} +synch_pos_with_cur; box_pos := pos; {keep track on page} +{Then switch to page box coordinate system; do |height(p)| movement.} +dvi_direction := page_direction; +cur.h := 0; +cur.v := height(p); +synch_pos_with_cur; +{Now we are at the point on the page where the origin of the page box should go.} temp_ptr:=p; if type(p)=vlist_node then vlist_out@+else hlist_out; dvi_out(eop); incr(total_pages); cur_s:=-1; @@ -15595,7 +14805,8 @@ if width(p)+h_offset>max_h then max_h:=width(p)+h_offset @ At the end of the program, we must finish things off by writing the post\-amble. If |total_pages=0|, the \.{DVI} file was never opened. -If |total_pages>=65536|, the \.{DVI} file will lie. +If |total_pages>=65536|, the \.{DVI} file will lie. And if +|max_push>=65536|, the user deserves whatever chaos might ensue. An integer variable |k| will be declared for use by this routine. @@ -15684,6 +14895,11 @@ begin get_nullfont := null_font; end; +function get_par_shape_ptr: halfword; +begin + get_par_shape_ptr := par_shape_ptr; +end; + function get_escape_char: integer; begin get_escape_char := escape_char; @@ -15719,6 +14935,7 @@ begin get_tex_dimen := dimen_par(code); end; + function get_x_height(f: internal_font_number): scaled; begin get_x_height := x_height(f); @@ -15760,7 +14977,7 @@ end; function new_dummy_font: internal_font_number; begin - new_dummy_font := read_font_info(null_cs, "dummy", "", -1000, -1); + new_dummy_font := read_font_info(null_cs, "dummy", -1000, -1); end; function get_hash_size: integer; @@ -15778,11 +14995,12 @@ begin get_hash_base:= hash_base; end; -function get_active_base: integer; +function get_font_id_base: integer; begin - get_active_base:= active_base; + get_font_id_base:= font_id_base; end; + function get_cur_font: internal_font_number; begin get_cur_font:= cur_font; @@ -15936,7 +15154,7 @@ end @!pdf_file: byte_file; {the PDF output file} @!pdf_buf: ^real_eight_bits; {pointer to the PDF output buffer or PDF object stream buffer} @!pdf_buf_size: integer; {end of PDF output buffer or PDF object stream buffer} -@!pdf_ptr: integer; {pointer to the first unused byte in the PDF buffer or object stream buffer} +@!pdf_ptr: longinteger; {pointer to the first unused byte in the PDF buffer or object stream buffer} @!pdf_op_buf: ^real_eight_bits; {the PDF output buffer} @!pdf_os_buf: ^real_eight_bits; {the PDF object stream buffer} @!pdf_os_buf_size: integer; {current size of the PDF object stream buffer, grows dynamically} @@ -15949,23 +15167,23 @@ end @!pdf_os_mode: boolean; {true if producing object stream} @!pdf_os_enable: boolean; {true if object streams are globally enabled} @!pdf_os_cur_objnum: integer; {number of current object stream object} -@!pdf_gone: integer; {number of bytes that were flushed to output} -@!pdf_save_offset: integer; {to save |pdf_offset|} +@!pdf_gone: longinteger; {number of bytes that were flushed to output} +@!pdf_save_offset: longinteger; {to save |pdf_offset|} @!zip_write_state: integer; {which state of compression we are in} @!fixed_pdf_minor_version: integer; {fixed minor part of the PDF version} +@!fixed_pdf_minor_version_set: boolean; {flag if the PDF version has been set} @!fixed_pdf_objcompresslevel: integer; {fixed level for activating PDF object streams} -@!pdf_minor_version_written: boolean; {flag if the PDF version has been written} @!fixed_pdfoutput: integer; {fixed output format} @!fixed_pdfoutput_set: boolean; {|fixed_pdfoutput| has been set?} @!fixed_gamma: integer; @!fixed_image_gamma: integer; @!fixed_image_hicolor: boolean; @!fixed_image_apply_gamma: integer; +@!fixed_pdf_draftmode: integer; {fixed \\pdfdraftmode} +@!pdf_page_group_val: integer; @!epochseconds: integer; @!microseconds: integer; -@!fixed_pdf_draftmode: integer; {fixed \\pdfdraftmode} -@!fixed_pdf_draftmode_set: boolean; {|fixed_pdf_draftmode| has been set?} - +@!page_divert_val: integer; @ @<Set init...@>= pdf_gone := 0; @@ -15980,9 +15198,10 @@ pdf_os_buf_size := inf_pdf_os_buf_size; pdf_buf := pdf_op_buf; pdf_seek_write_length := false; zip_write_state := no_zip; -pdf_minor_version_written := false; +fixed_pdf_minor_version_set := false; fixed_pdfoutput_set := false; -fixed_pdf_draftmode_set := false; +pdf_page_group_val := -1; +page_divert_val := 0; @ @p function fix_int(val, min, max: integer): integer; @@ -15996,55 +15215,95 @@ begin end; @ This ensures that |pdfminorversion| is set only before any bytes have -been written to the generated PDF file. Here also the PDF file is opened -by |ensure_pdf_open| and the PDF header is written. +been written to the generated \.{PDF} file. Here also all variables for +\.{PDF} output are initialized, the \.{PDF} file is opened by |ensure_pdf_open|, +and the \.{PDF} header is written. @p procedure check_pdfminorversion; begin - if not pdf_minor_version_written then begin - pdf_minor_version_written := true; - if (pdf_minor_version < 0) or (pdf_minor_version > 9) then begin - print_err("pdfTeX error (illegal pdfminorversion)"); - print_ln; - help2 ("The pdfminorversion must be between 0 and 9.")@/ - ("I changed this to 4."); - int_error (pdf_minor_version); - pdf_minor_version := 4; - end; - fixed_pdf_minor_version := pdf_minor_version; - fixed_gamma := fix_int(pdf_gamma, 0, 1000000); - fixed_image_gamma := fix_int(pdf_image_gamma, 0, 1000000); - fixed_image_hicolor := fix_int(pdf_image_hicolor, 0, 1); - fixed_image_apply_gamma := fix_int(pdf_image_apply_gamma, 0, 1); - fixed_pdf_objcompresslevel := fix_int(pdf_objcompresslevel, 0, 3); - fixed_pdf_draftmode := fix_int(pdf_draftmode, 0, 1); - fixed_replace_font := fix_int(pdf_replace_font, 0, 1); - if (fixed_pdf_minor_version >= 5) and (fixed_pdf_objcompresslevel > 0) then - pdf_os_enable := true - else begin - if fixed_pdf_objcompresslevel > 0 then begin - pdf_warning("Object streams", "\pdfobjcompresslevel > 0 requires \pdfminorversion > 4. Object streams disabled now.", true, true); - fixed_pdf_objcompresslevel := 0; - end; - pdf_os_enable := false; - end; - ensure_pdf_open; - fix_pdfoutput; - pdf_print("%PDF-1."); - pdf_print_int_ln(fixed_pdf_minor_version); - pdf_print("%"); - pdf_out(208); {'P' + 128} - pdf_out(212); {'T' + 128} - pdf_out(197); {'E' + 128} - pdf_out(216); {'X' + 128} - pdf_print_nl; + fix_pdfoutput; + pdfassert(fixed_pdfoutput > 0); + if not fixed_pdf_minor_version_set then begin + fixed_pdf_minor_version_set := true; + @<Initialize variables for \.{PDF} output@>; + @<Write \.{PDF} header@>; end else begin - if fixed_pdf_minor_version <> pdf_minor_version then - pdf_error("setup", - "\pdfminorversion cannot be changed after data is written to the PDF file"); + @<Check that variables for \.{PDF} output are unchanged@>; end; + if fixed_pdf_draftmode <> 0 then begin + pdf_compress_level := 0; {re-fix it, might have been changed inbetween} + fixed_pdf_objcompresslevel := 0; + end; +end; + +@ @<Initialize variables for \.{PDF} output@>= +prepare_mag; +if (pdf_minor_version < 0) or (pdf_minor_version > 9) then begin + print_err("LuaTeX error (illegal pdfminorversion)"); + print_ln; + help2 ("The pdfminorversion must be between 0 and 9.")@/ + ("I changed this to 4."); + int_error (pdf_minor_version); + pdf_minor_version := 4; +end; +fixed_pdf_minor_version := pdf_minor_version; +fixed_decimal_digits := fix_int(pdf_decimal_digits, 0, 4); +fixed_gamma := fix_int(pdf_gamma, 0, 1000000); +fixed_image_gamma := fix_int(pdf_image_gamma, 0, 1000000); +fixed_image_hicolor := fix_int(pdf_image_hicolor, 0, 1); +fixed_image_apply_gamma := fix_int(pdf_image_apply_gamma, 0, 1); +fixed_pdf_objcompresslevel := fix_int(pdf_objcompresslevel, 0, 3); +fixed_pdf_draftmode := fix_int(pdf_draftmode, 0, 1); +fixed_inclusion_copy_font:= fix_int(pdf_inclusion_copy_font, 0, 1); +fixed_replace_font := fix_int(pdf_replace_font, 0, 1); +fixed_pk_resolution := fix_int(pdf_pk_resolution, 72, 8000); +if (fixed_pdf_minor_version >= 5) and (fixed_pdf_objcompresslevel > 0) then + pdf_os_enable := true +else begin + if fixed_pdf_objcompresslevel > 0 then begin + pdf_warning("Object streams", + "\pdfobjcompresslevel > 0 requires \pdfminorversion > 4. Object streams disabled now.", true, true); + fixed_pdf_objcompresslevel := 0; + end; + pdf_os_enable := false; end; +if pdf_pk_resolution = 0 then {if not set from format file or by user} + pdf_pk_resolution := pk_dpi; {take it from \.{texmf.cnf}} +pk_scale_factor := + divide_scaled(72, fixed_pk_resolution, 5 + fixed_decimal_digits); +if not callback_defined(read_pk_file_callback) then begin + if pdf_pk_mode <> null then begin + kpseinitprog('PDFTEX', fixed_pk_resolution, + makecstring(tokens_to_string(pdf_pk_mode)), nil); + flush_string; + end else + kpseinitprog('PDFTEX', fixed_pk_resolution, nil, nil); + if not kpsevarvalue('MKTEXPK') then + kpsesetprogramenabled (kpsepkformat, 1, kpsesrccmdline); + end; +set_job_id(year, month, day, time); +if (pdf_unique_resname > 0) and (pdf_resname_prefix = 0) then + pdf_resname_prefix := get_resname_prefix + +@ @<Check that variables for \.{PDF} output are unchanged@>= +if fixed_pdf_minor_version <> pdf_minor_version then + pdf_error("setup", + "\pdfminorversion cannot be changed after data is written to the PDF file"); +if fixed_pdf_draftmode <> pdf_draftmode then + pdf_error("setup", + "\pdfdraftmode cannot be changed after data is written to the PDF file"); + +@ @<Write \.{PDF} header@>= +ensure_pdf_open; +pdf_print("%PDF-1."); +pdf_print_int_ln(fixed_pdf_minor_version); +pdf_print("%"); +pdf_out(208); {'P' + 128} +pdf_out(212); {'T' + 128} +pdf_out(197); {'E' + 128} +pdf_out(216); {'X' + 128} +pdf_print_nl; @ Checks that we have a name for the generated PDF file and that it's open. @@ -16054,10 +15313,10 @@ begin return; if job_name = 0 then open_log_file; - pack_job_name(".pdf"); - if fixed_pdf_draftmode = 0 then - while not lua_b_open_out(pdf_file) do - prompt_file_name("file name for output",".pdf"); + pack_job_name('.pdf'); + if fixed_pdf_draftmode = 0 then + while not lua_b_open_out(pdf_file) do + prompt_file_name('file name for output','.pdf'); pdf_file:=name_file_pointer; output_file_name := b_make_name_string(pdf_file); end; @@ -16068,8 +15327,10 @@ neccesary. We call |pdf_begin_stream| to begin a stream and |pdf_end_stream| to finish it. The stream contents will be compressed if compression is turn on. @p procedure pdf_flush; {flush out the |pdf_buf|} +var saved_pdf_gone : longinteger; begin if not pdf_os_mode then begin + saved_pdf_gone := pdf_gone; case zip_write_state of no_zip: if pdf_ptr > 0 then begin if fixed_pdf_draftmode = 0 then write_pdf(0, pdf_ptr - 1); @@ -16084,6 +15345,8 @@ begin end; end; pdf_ptr := 0; + if saved_pdf_gone > pdf_gone then + pdf_error("file size", "File size exceeds architectural limits (pdf_gone wraps around)"); end; end; @@ -16093,6 +15356,7 @@ begin pdf_seek_write_length := true; {fill in length at |pdf_end_stream| call} pdf_stream_length_offset := pdf_offset - 11; pdf_stream_length := 0; + pdf_last_byte := 0; if pdf_compress_level > 0 then begin pdf_print_ln("/Filter /FlateDecode"); pdf_print_ln(">>"); @@ -16150,7 +15414,7 @@ end procedure pdf_error(t, p: str_number); begin normalize_selector; - print_err("pdfTeX error"); + print_err("LuaTeX error"); if t <> 0 then begin print(" ("); print(t); @@ -16166,7 +15430,7 @@ begin wake_up_terminal; if prepend_nl then print_ln; - print("pdfTeX warning"); + print("LuaTeX warning"); if t <> 0 then begin print(" ("); print(t); @@ -16175,7 +15439,7 @@ begin print(": "); print(p); if append_nl then print_ln; - if history=spotless then history:=warning_issued; + if history=spotless then history:=warning_issued; end; procedure pdf_os_get_os_buf(s: integer); {check that |s| bytes more @@ -16247,12 +15511,10 @@ accurary. @<Glob...@>= @!one_hundred_inch: scaled; {scaled value corresponds to 100in} @!one_inch: scaled; {scaled value corresponds to 1in (rounded!)} +@!one_true_inch: scaled; {scaled value corresponds to 1truein (rounded!)} @!one_hundred_bp: scaled; {scaled value corresponds to 100bp} @!one_bp: scaled; {scaled value corresponds to 1bp (rounded!)} @!ten_pow: array[0..9] of integer; {$10^0..10^9$} -@!scaled_out: integer; {amount of |scaled| that was taken out in -|divide_scaled|} -@!init_pdf_output: boolean; @ @<Set init...@>= one_hundred_inch := 7227 * 65536; {exact, 473628672} @@ -16262,8 +15524,6 @@ one_bp := (one_hundred_bp + 50) div 100; {rounded to 65782} ten_pow[0] := 1; for i := 1 to 9 do ten_pow[i] := 10*ten_pow[i - 1]; -init_pdf_output := false; - @ The function |divide_scaled| divides |s| by |m| using |dd| decimal digits of precision. It is defined in C because it is a good candidate @@ -16290,51 +15550,7 @@ else round_xn_over_d := -u; end; -@ Next subroutines are needed for controling spacing in PDF page description. -For a given character |c| from a font |f|, -the procedure |adv_char_width| advances |pdf_h| -by {\it about\/} the amount |w|, which is the character width. -But we cannot simply add |w| to |pdf_h|. -Instead we have to bring the required shift into the same raster, -on which also the \.{/Widths} array values, -as they appear in the PDF file, are based. -The |scaled_out| value is the |w| value moved into this raster. -The \.{/Widths} values are used by the PDF reader independently -to update its positions. -So one has to be sure, that calculations are properly synchronized. -Currently the \.{/Widths} array values are output -with one digit after the decimal point, -therefore the raster on which |adv_char_width| is operating -is $1/10000$ of the |pdf_font_size|. - -For PK fonts things are more complicated, -as we have to deal with scaling bitmaps as well. - -@p -procedure adv_char_width(f: internal_font_number; c: integer); {update |pdf_h| -by character width |w| from font |f|} -var w, s_out: scaled; - s: integer; -begin - w := char_width(f,c); - if hasfmentry(f) then begin - if pdf_cur_Tm_a = 1000 then begin - call_func(divide_scaled_n(w, pdf_font_size(f), 10000.0)); - pdf_delta_h := pdf_delta_h + scaled_out; - end - else begin - s := divide_scaled_n(round_xn_over_d(w, 1000, pdf_cur_Tm_a), - pdf_font_size(f), 10000.0); - s_out := round_xn_over_d(round_xn_over_d(pdf_font_size(f), abs(s), 10000), - pdf_cur_Tm_a, 1000); - if s < 0 then - s_out := -s_out; - pdf_delta_h := pdf_delta_h + s_out; - end; - end else - pdf_delta_h := pdf_delta_h + get_pk_char_width(f, w); -end; - +@ @p procedure pdf_print_bp(s: scaled); {print scaled as |bp|} begin pdf_print_real(divide_scaled(s, one_hundred_bp, fixed_decimal_digits + 2), @@ -16351,135 +15567,23 @@ end; @* \[32c] PDF page description. -@d pdf_h_offset == (h_offset + pdf_h_origin) -@d pdf_v_offset == (v_offset + pdf_v_origin) -@d pdf_x(#) == ((#) - pdf_h_offset + one_inch) {convert $x$-coordinate from \.{DVI} to PDF} -@d pdf_y(#) == (cur_page_height - (#) - pdf_v_offset + one_inch) {convert $y$-coordinate from \.{DVI} to PDF} - @<Glob...@>= -@!pdf_f: internal_font_number; {the current font in PDF output page} -@!pdf_h: scaled; {current horizontal coordinate in PDF output page} -@!pdf_v: scaled; {current vertical coordinate in PDF output page} -@!pdf_tj_start_h: scaled; {horizontal coordinate in PDF output page just before \.{TJ} array start} -@!cur_delta_h: scaled; {horizontal |cur_h| offset from |pdf_tj_start_h|} -@!pdf_delta_h: scaled; {horizontal offset from |pdf_tj_start_h|} -@!pdf_origin_h: scaled; {current horizontal origin in PDF output page} -@!pdf_origin_v: scaled; {current vertical origin in PDF output page} -@!pdf_doing_string: boolean; {we are writing string to PDF file?} -@!pdf_doing_text: boolean; {we are writing text section to PDF file?} -@!min_bp_val: scaled; -@!min_font_val: scaled; {(TJ array system)} @!fixed_pk_resolution: integer; @!fixed_decimal_digits: integer; @!fixed_gen_tounicode: integer; +@!fixed_inclusion_copy_font: integer; @!fixed_replace_font: integer; @!pk_scale_factor: integer; @!pdf_output_option: integer; @!pdf_output_value: integer; @!pdf_draftmode_option: integer; @!pdf_draftmode_value: integer; -@!pdf_cur_Tm_a: integer; {value |a| of the current text matrix, i.e., - the current horizontal scaling factor} -@!pdf_cur_Tm_c: integer; {value |c| of the current text matrix, i.e., slant (skew, obliqueness)} -@!pdf_last_f: internal_font_number; {last font in PDF output page} -@!pdf_last_fs: internal_font_number; {last font size in PDF output page} - -@ Following procedures implement low-level subroutines to convert \TeX{} -internal structures to PDF page description. - -@p procedure pdf_set_origin(h, v: scaled); {set the origin to |h|, |v|} -begin - if (abs(h - pdf_origin_h) >= min_bp_val) or - (abs(v - pdf_origin_v) >= min_bp_val) then begin - pdf_print("1 0 0 1 "); - pdf_print_bp(h - pdf_origin_h); - pdf_origin_h := pdf_origin_h + scaled_out; - pdf_out(" "); - pdf_print_bp(pdf_origin_v - v); - pdf_origin_v := pdf_origin_v - scaled_out; - pdf_print_ln(" cm"); - end; - pdf_h := pdf_origin_h; - pdf_tj_start_h := pdf_h; - pdf_v := pdf_origin_v; -end; - -procedure pdf_set_origin_temp(h, v: scaled); {set the origin to |h|, |v| inside group} -begin - if (abs(h - pdf_origin_h) >= min_bp_val) or - (abs(v - pdf_origin_v) >= min_bp_val) then begin - pdf_print("1 0 0 1 "); - pdf_print_bp(h - pdf_origin_h); - pdf_out(" "); - pdf_print_bp(pdf_origin_v - v); - pdf_print_ln(" cm"); - end; -end; - -procedure pdf_end_string; {end the current string} -begin - if pdf_doing_string then begin - pdf_print(")]TJ"); - pdf_doing_string := false; - end; -end; - -procedure pdf_end_string_nl; {end the current string, with new-line} -begin - if pdf_doing_string then begin - pdf_print_ln(")]TJ"); - pdf_doing_string := false; - end; -end; - -procedure pdf_set_textmatrix(v, v_out: scaled; f: internal_font_number); -{set the next starting point to |cur_h|, |cur_v|} -var pdf_new_Tm_a, pdf_new_Tm_c: integer; {values |a| and |c| of the new text matrix} -begin - pdf_out(" "); - if f = pdf_f then begin - pdf_new_Tm_a := pdf_cur_Tm_a; - pdf_new_Tm_c := pdf_cur_Tm_c; - end else begin - if pdf_font_auto_expand(f) then - pdf_new_Tm_a := 1000 + pdf_font_expand_ratio(f) - else - pdf_new_Tm_a := 1000; - pdf_new_Tm_c := 0 * font_slant(f); {don't activate it yet, needs fixing writefont.c etc.} - end; - if (pdf_new_Tm_a <> 1000) or (pdf_cur_Tm_a <> 1000) - or (pdf_new_Tm_c <> 0) or (pdf_cur_Tm_c <> 0) - then begin - pdf_print_real(pdf_new_Tm_a, 3); - pdf_print(" 0 "); - pdf_print_real(pdf_new_Tm_c, 3); - pdf_print(" 1 "); - pdf_print_bp(cur_h - pdf_origin_h); - pdf_h := pdf_origin_h + scaled_out; - pdf_out(" "); - pdf_print_bp(pdf_origin_v - cur_v); - pdf_v := pdf_origin_v - scaled_out; - pdf_print(" Tm"); - pdf_cur_Tm_a := pdf_new_Tm_a; - pdf_cur_Tm_c := pdf_new_Tm_c; - pdfassert(pdf_cur_Tm_a > 0); - end else begin - pdf_print_bp(cur_h - pdf_tj_start_h); {works only for unexpanded fonts} - pdf_h := pdf_tj_start_h + scaled_out; - pdf_out(" "); - pdf_print_real(v, fixed_decimal_digits); {use |v| and |v_out| to avoid duplicate calculation} - pdf_v := pdf_v - v_out; - pdf_print(" Td"); - end; - pdf_tj_start_h := pdf_h; - pdf_delta_h := 0; -end; +@ @p procedure pdf_use_font(f: internal_font_number; fontnum: integer); {mark |f| as a used font; set |font_used(f)|, |pdf_font_size(f)| and |pdf_font_num(f)|} begin - call_func(divide_scaled(font_size(f), one_hundred_bp, 6)); - set_pdf_font_size(f,scaled_out); + set_pdf_font_size(f,font_size(f)); set_font_used(f,true); pdfassert((fontnum > 0) or ((fontnum < 0) and (pdf_font_num(-fontnum) > 0))); set_pdf_font_num(f,fontnum); @@ -16509,7 +15613,7 @@ begin {if |f| is auto expanded then ensure the base font is initialized} if pdf_font_auto_expand(f) and (pdf_font_blink(f) <> null_font) then begin b := pdf_font_blink(f); - {TODO: reinstate this check. disabled because wide fonts font have fmentries} + {TODO: reinstate this check. disabled because wide fonts font have fmentries} if false and (not hasfmentry(b)) then pdf_error("font expansion", "auto expansion is only possible with scalable fonts"); if not font_used(b) then @@ -16548,7 +15652,7 @@ begin pdf_init_font(cur_val); end; -procedure pdf_set_font(f: internal_font_number); +function pdf_set_font(f: internal_font_number): internal_font_number; {set the actual font on PDF page} label found, found1; var p: pointer; @@ -16569,134 +15673,10 @@ begin end; pdf_append_list(f)(pdf_font_list); {|f| not found in |pdf_font_list|, append it now} found: - if (k = pdf_last_f) and (font_size(f) = pdf_last_fs) then - return; - pdf_print("/F"); - pdf_print_int(k); - pdf_print_resname_prefix; - pdf_out(" "); - pdf_print_real(divide_scaled(font_size(f), one_hundred_bp, 6), 4); - pdf_print(" Tf"); - pdf_last_f := k; - pdf_last_fs := font_size(f); -end; - -procedure pdf_begin_text; {begin a text section} -begin - pdf_set_origin(0, cur_page_height); - pdf_print_ln("BT"); - pdf_doing_text := true; - pdf_f := null_font; - pdf_last_f := null_font; - pdf_last_fs := 0; - pdf_doing_string := false; - pdf_cur_Tm_a := 1000; - pdf_cur_Tm_c := 0; + pdf_set_font := k; end; @ @p -procedure pdf_begin_string(f: internal_font_number); {begin to draw a string} -var s_out, v, v_out: scaled; - s: integer; -begin s_out:=0; - if not pdf_doing_text then - pdf_begin_text; - if f <> pdf_f then begin - pdf_end_string; - pdf_set_font(f); - end; - if pdf_cur_Tm_a = 1000 then begin - s := divide_scaled_n(cur_h - (pdf_tj_start_h + pdf_delta_h), pdf_font_size(f), 1000.0); - s_out := scaled_out; - end - else begin - s := divide_scaled_n(round_xn_over_d(cur_h - (pdf_tj_start_h + pdf_delta_h), 1000, - pdf_cur_Tm_a), pdf_font_size(f), 1000.0); - if abs(s) < @'100000 then begin - s_out := round_xn_over_d(round_xn_over_d(pdf_font_size(f), abs(s), 1000), - pdf_cur_Tm_a, 1000); - if s < 0 then - s_out := -s_out; - end; - {no need to calculate |s_out| when |abs(s) >= @'100000|, since the text - matrix will be reset below} - end; - if abs(cur_v - pdf_v) >= min_bp_val then begin - v := divide_scaled(pdf_v - cur_v, one_hundred_bp, - fixed_decimal_digits + 2); - v_out := scaled_out; - end - else begin - v := 0; - v_out := 0; - end; - if (f <> pdf_f) or (v <> 0) or (abs(s) >= @'100000) then begin - pdf_end_string; - pdf_set_textmatrix(v, v_out, f); - pdf_f := f; - s := 0; - end; - if not pdf_doing_string then begin - pdf_print(" ["); - if s = 0 then - pdf_out("("); - end; - if s <> 0 then begin - if pdf_doing_string then - pdf_out(")"); - pdf_print_int(-s); - pdf_out("("); - pdf_delta_h := pdf_delta_h + s_out; - end; - pdf_doing_string := true; -end; - -procedure pdf_end_text; {end a text section} -begin - if pdf_doing_text then begin - pdf_end_string_nl; - pdf_print_ln("ET"); - pdf_doing_text := false; - end; -end; - -procedure pdf_set_rule(x, y, w, h: scaled); {draw a rule} -begin - pdf_end_text; - pdf_print_ln("q"); - if h <= one_bp then begin - pdf_set_origin_temp(x, y - (h + 1)/2); - pdf_print("[]0 d 0 J "); - pdf_print_bp(h); pdf_print(" w 0 0 m "); - pdf_print_bp(w); pdf_print_ln(" 0 l S"); - end - else if w <= one_bp then begin - pdf_set_origin_temp(x + (w + 1)/2, cur_v); - pdf_print("[]0 d 0 J "); - pdf_print_bp(w); pdf_print(" w 0 0 m 0 "); - pdf_print_bp(h); pdf_print_ln(" l S"); - end - else begin - pdf_set_origin_temp(x, y); - pdf_print("0 0 "); - pdf_print_bp(w); pdf_out(" "); - pdf_print_bp(h); pdf_print_ln(" re f"); - end; - pdf_print_ln("Q"); -end; - -procedure pdf_rectangle(left, top, right, bottom: scaled); {output a -rectangle specification to PDF file} -begin - prepare_mag; - pdf_print("/Rect ["); - pdf_print_mag_bp(pdf_x(left)); pdf_out(" "); - pdf_print_mag_bp(pdf_y(bottom)); pdf_out(" "); - pdf_print_mag_bp(pdf_x(right)); pdf_out(" "); - pdf_print_mag_bp(pdf_y(top)); - pdf_print_ln("]"); -end; - procedure literal(s: str_number; literal_mode: integer; warn: boolean); var j: pool_pointer; {current character code position} begin @@ -16723,49 +15703,54 @@ begin end; case literal_mode of set_origin: begin - pdf_end_text; - pdf_set_origin(cur_h, cur_v); + pdf_goto_pagemode; + synch_pos_with_cur; + pdf_set_pos(pos.h, pos.v); end; direct_page: - pdf_end_text; + pdf_goto_pagemode; direct_always: pdf_end_string_nl; othercases confusion("literal1") endcases; - if s>string_offset then + if s>string_offset then while j<str_start_macro(s+1) do begin - pdf_out(str_pool[j]); - incr(j); - end - else - pdf_out(s); + pdf_out(str_pool[j]); + incr(j); + end + else + pdf_out(s); pdf_print_nl; end; -procedure latelua(lua_id: quarterword; s: str_number); -var b, j: pool_pointer; {current character code position} +procedure latelua(s: pointer; r: pointer); +var b: pool_pointer; {current character code position} begin - j:=str_start_macro(s); b := pool_ptr; - luacall(lua_id,(s-string_offset)); - while b<pool_ptr do begin - pdf_out(str_pool[b]); - incr(b); + luacall(s,r); + if b<pool_ptr then begin + pdf_goto_pagemode; + while b<pool_ptr do begin + pdf_out(str_pool[b]); + incr(b); + end; + pdf_print_nl; end; - pdf_print_nl; end; @* \[32d] The cross-reference table. The cross-reference table |obj_tab| is an array of |obj_tab_size| of -|tab_entry|. Each entry contains five integer fields and represents an object +|obj_entry|. Each entry contains five integer fields and represents an object in PDF file whose object number is the index of this entry in |obj_tab|. Objects in |obj_tab| maybe linked into list; objects in such a linked list have the same type. @<Types...@>= @!obj_entry = record@;@/ - int0, int1, int2, int3, int4: integer; + int0, int1: integer; + int2: longinteger; + int3, int4: integer; end; @ The first field contains information representing identifier of this object. @@ -16776,10 +15761,9 @@ The second field of |obj_entry| contains link to the next object in |obj_tab| if this object is linked in a list. The third field holds the byte offset of the object in the output PDF file, -or its byte offset within an object stream. -Objects that have been not written yet have this field set to zero. However -sometimes we have to use this field to store some info before the object is -written out. +or its byte offset within an object stream. As long as the object is not +written, this field is used for flags about the write status of the object; +then it has a negative value. The fourth field holds the object number of the object stream, into which the object is included. @@ -16790,39 +15774,41 @@ well. @d obj_info(#) == obj_tab[#].int0 {information representing identifier of this object} @d obj_link(#) == obj_tab[#].int1 {link to the next entry in linked list} -@d obj_offset(#) == obj_tab[#].int2 {byte offset for this object in PDF output file, or object stream number for this object} +@d obj_offset(#) == obj_tab[#].int2 {negative (flags), or byte offset for this object in PDF output file, or object stream number for this object} @d obj_os_idx(#) == obj_tab[#].int3 {index of this object in object stream} @d obj_aux(#) == obj_tab[#].int4 {auxiliary pointer} -@d is_obj_written(#) == (obj_offset(#) <> 0) + +@d set_obj_fresh(#) == obj_offset(#) := -2 +@d set_obj_scheduled(#) == if intcast(obj_offset(#)) = -2 then obj_offset(#) := -1 +@d is_obj_scheduled(#) == (intcast(obj_offset(#)) > -2) +@d is_obj_written(#) == (intcast(obj_offset(#)) > -1) @# {types of objects} @d obj_type_others == 0 {objects which are not linked in any list} @d obj_type_page == 1 {index of linked list of Page objects} -@d obj_type_pages == 2 {index of linked list of Pages objects} -@d obj_type_font == 3 {index of linked list of Fonts objects} -@d obj_type_outline == 4 {index of linked list of outline objects} -@d obj_type_dest == 5 {index of linked list of destination objects} -@d obj_type_obj == 6 {index of linked list of raw objects} -@d obj_type_xform == 7 {index of linked list of XObject forms} -@d obj_type_ximage == 8 {index of linked list of XObject image} -@d obj_type_thread == 9 {index of linked list of num article threads} +@d obj_type_font == 2 {index of linked list of Fonts objects} +@d obj_type_outline == 3 {index of linked list of outline objects} +@d obj_type_dest == 4 {index of linked list of destination objects} +@d obj_type_obj == 5 {index of linked list of raw objects} +@d obj_type_xform == 6 {index of linked list of XObject forms} +@d obj_type_ximage == 7 {index of linked list of XObject image} +@d obj_type_thread == 8 {index of linked list of num article threads} @d head_tab_max == obj_type_thread {max index of |head_tab|} @# {max number of kids for balanced trees} -@d pages_tree_kids_max == 6 {max number of kids of Pages tree node} @d name_tree_kids_max == 6 {max number of kids of node of name tree for name destinations} @# {when a whatsit node representing annotation is created, words |1..3| are width, height and depth of this annotation; after shipping out words |1..4| are rectangle specification of annotation. For whatsit node representing -destination |pdf_left| and |pdf_top| are used for some types of destinations} +destination |pdf_ann_left| and |pdf_ann_top| are used for some types of destinations} @# {coordinates of destinations/threads/annotations (in whatsit node)} -@d pdf_left(#) == vmem(# + 2).sc -@d pdf_top(#) == vmem(# + 3).sc -@d pdf_right(#) == vmem(# + 4).sc -@d pdf_bottom(#) == vmem(# + 5).sc +@d pdf_ann_left(#) == vmem(# + 2).sc +@d pdf_ann_top(#) == vmem(# + 3).sc +@d pdf_ann_right(#) == vmem(# + 4).sc +@d pdf_ann_bottom(#) == vmem(# + 5).sc @# {dimension of destinations/threads/annotations (in whatsit node)} @d pdf_width(#) == vmem(# + 2).sc @@ -16840,7 +15826,6 @@ destination |pdf_left| and |pdf_top| are used for some types of destinations} @d scan_special == 3 {look into special text} @# {data structure for \.{\\pdfcolorstack}} -@d pdf_colorstack_node_size == 4 @d pdf_colorstack_stack(#) == vlink(#+2) {stack number} @d pdf_colorstack_cmd(#) == vinfo(#+2) {command: set, push, pop, current} @d pdf_colorstack_data(#) == vlink(#+3) {data} @@ -16853,22 +15838,17 @@ destination |pdf_left| and |pdf_top| are used for some types of destinations} @d colorstack_current == 3 @# {data structure for \.{\\pdfsetmatrix}} -@d pdf_setmatrix_node_size == 3 @d pdf_setmatrix_data(#) == vlink(#+2) {data} -@# {data structure for \.{\\pdsave}} -@d pdf_save_node_size == 3 +@# {data structure for \.{\\pdfsave}} @# {data structure for \.{\\pdfrestore}} -@d pdf_restore_node_size == 3 - @# {data structure for \.{\\latelua}} -@d late_lua_data(#) == vlink(#+2) {data} -@d late_lua_reg(#) == vinfo(#+2) {register id} +@d late_lua_data == write_tokens {data} +@d late_lua_name(#) == vlink(#+3) {name} @# {data structure for \.{\\pdfobj} and \.{\\pdfrefobj}} -@d pdf_refobj_node_size == 3 {size of whatsit node representing the raw object} @d pdf_obj_objnum(#) == vinfo(# + 2) {number of the raw object} @d obj_data_ptr == obj_aux {pointer to |pdf_mem|} @d pdfmem_obj_size == 4 {size of memory in |pdf_mem| which |obj_data_ptr| holds} @@ -16881,11 +15861,10 @@ destination |pdf_left| and |pdf_top| are used for some types of destinations} read from an external file?} @# {data structure for \.{\\pdfxform} and \.{\\pdfrefxform}} -@d pdf_refxform_node_size == 6 {size of whatsit node for xform; words 1..3 are - form dimensions} -@d pdf_xform_objnum(#) == vinfo(# + 4) {object number} @d pdfmem_xform_size == 6 {size of memory in |pdf_mem| which |obj_data_ptr| holds} + +@d pdf_xform_objnum(#) == vinfo(# + 4) {object number} @d obj_xform_width(#) == pdf_mem[obj_data_ptr(#) + 0] @d obj_xform_height(#) == pdf_mem[obj_data_ptr(#) + 1] @d obj_xform_depth(#) == pdf_mem[obj_data_ptr(#) + 2] @@ -16897,14 +15876,11 @@ destination |pdf_left| and |pdf_top| are used for some types of destinations} Resources} @# {data structure for \.{\\pdfximage} and \.{\\pdfrefximage}} -@d pdf_refximage_node_size == 6 {size of whatsit node for ximage; words 2..4 - are image dimensions} -@d pdf_ximage_ref(#) == vinfo(# + 5) {image reference number} +@d pdf_ximage_idx(#) == vinfo(# + 5) {image index in array} @# {data structure of annotations; words 1..4 represent the coordinates of the annotation} @d obj_annot_ptr == obj_aux {pointer to corresponding whatsit node} -@d pdf_annot_node_size == 8 {size of whatsit node representing annotation} @d pdf_annot_data(#) == vinfo(# + 6) {raw data of general annotations} @d pdf_link_attr(#) == vinfo(# + 6) {attributes of link annotations} @d pdf_link_action(#) == vlink(# + 6) {pointer to action structure} @@ -16918,8 +15894,6 @@ destination |pdf_left| and |pdf_top| are used for some types of destinations} @d pdf_action_user == 3 {user-defined action} @# {data structure of actions} -@d pdf_action_size == 4 {size of action structure in |mem|} -@d action_node == 45 @d pdf_action_type(#) == type(#+1) {action type} @d pdf_action_named_id(#) == subtype(#+1) {identifier is type of name} @d pdf_action_id(#) == vlink(#+1) {destination/thread name identifier} @@ -16932,9 +15906,8 @@ destination |pdf_left| and |pdf_top| are used for some types of destinations} before all outline entries are defined, so memory allocated for outline entries can't not be deallocated and will stay in memory. For this reason we will store data of outline entries in |pdf_mem| instead of |mem|} - @d pdfmem_outline_size == 8 {size of memory in |pdf_mem| which -|obj_outline_ptr| points to} + |obj_outline_ptr| points to} @d obj_outline_count == obj_info{count of all opened children} @d obj_outline_ptr == obj_aux {pointer to |pdf_mem|} @d obj_outline_title(#) == pdf_mem[obj_outline_ptr(#)] @@ -16959,9 +15932,6 @@ action} @# {data structure of destinations} @d obj_dest_ptr == obj_aux {pointer to |pdf_dest_node|} -@d pdf_dest_node_size == 8 {size of whatsit node for destination; -words |1..4| hold dest dimensions, word |6| identifier type, subtype -and identifier of destination, word |6| the corresponding object number} @d pdf_dest_type(#) == type(# + 6) {type of destination} @d pdf_dest_named_id(#) == subtype(# + 6) {is named identifier?} @d pdf_dest_id(#) == vlink(# + 6) {destination identifier} @@ -16971,7 +15941,6 @@ object} @# {data structure of threads; words 1..4 represent the coordinates of the corners} -@d pdf_thread_node_size == 8 @d pdf_thread_named_id(#) == subtype(# + 6) {is a named identifier} @d pdf_thread_id(#) == vlink(# + 6) {thread identifier} @d pdf_thread_attr(#) == vinfo(# + 7) {attributes of thread} @@ -17010,8 +15979,8 @@ so we can use this field for both} @!pdf_last_pages: integer; {pointer to most recently generated pages object} @!pdf_last_page: integer; {pointer to most recently generated page object} @!pdf_last_stream: integer; {pointer to most recently generated stream} -@!pdf_stream_length: integer; {length of most recently generated stream} -@!pdf_stream_length_offset: integer; {file offset of the last stream length} +@!pdf_stream_length: longinteger; {length of most recently generated stream} +@!pdf_stream_length_offset: longinteger; {file offset of the last stream length} @!pdf_seek_write_length: boolean; {flag whether to seek back and write \.{/Length}} @!pdf_last_byte: integer; {byte most recently written to PDF file; for \.{endstream} in new line} @!pdf_append_list_arg: integer; {for use with |pdf_append_list|} @@ -17085,7 +16054,7 @@ begin incr(sys_obj_ptr); obj_ptr := sys_obj_ptr; obj_info(obj_ptr) := i; - obj_offset(obj_ptr) := 0; + set_obj_fresh(obj_ptr); obj_aux(obj_ptr) := 0; avl_put_obj(obj_ptr, t); if t = obj_type_page then begin @@ -17321,7 +16290,7 @@ end; @ Subroutines to print out various PDF objects -@p procedure pdf_print_fw_int(n, w: integer); {print out an integer with +@p procedure pdf_print_fw_int(n: longinteger; w: integer); {print out an integer with fixed width; used for outputting cross-reference table} var k: integer; {$0\le k\le23$} begin @@ -17335,10 +16304,10 @@ begin end; end; -procedure pdf_out_bytes(n, w: integer); {print out an integer as +procedure pdf_out_bytes(n: longinteger; w: integer); {print out an integer as a number of bytes; used for outputting \.{/XRef} cross-reference stream} var k: integer; -byte: array[0..3] of integer; {digits in a number being output} +byte: array[0..7] of integer; {digits in a number being output} begin k := 0; repeat byte[k] := n mod 256; n := n div 256; incr(k); @@ -17419,15 +16388,101 @@ The |has_packet()| C macro checks for this condition. @ The following code typesets a character to PDF output. -@p procedure output_one_char(ffi:internal_font_number;c:integer); +@p +procedure output_one_char(ffi:internal_font_number;c:integer); +var c_wd,c_ht,c_dp: scaled; {the real width, height and depth of the character} +ci: charinfo_short; +save, save_box_pos: scaledpos; +save_direction: integer; begin - if has_packet(ffi,c) then - do_vf_packet(ffi, c) - else begin - pdf_begin_string(ffi); - pdf_print_char(ffi, c); - adv_char_width(ffi, c); - end; + ci := char_info_short(ffi,c); + c_ht:=charinfo_height(ci); + c_dp:=charinfo_depth(ci); + c_wd:=charinfo_width(ci); + synch_pos_with_cur; + case box_direction(dvi_direction) of + dir_TL_: begin + case font_direction(dvi_direction) of + dir__LL, dir__LR: pos_down((c_ht - c_dp) div 2); + dir__LT: ; + dir__LB: pos_down(c_ht); + endcases; + end; + dir_TR_: begin + pos_left(c_wd); + case font_direction(dvi_direction) of + dir__RL, dir__RR: pos_down((c_ht - c_dp) div 2); + dir__RT: ; + dir__RB: pos_down(c_ht); + endcases; + end; + dir_BL_: begin + case font_direction(dvi_direction) of + dir__LL, dir__LR: pos_down((c_ht - c_dp) div 2); + dir__LT: pos_up(c_dp); + dir__LB: pos_down(c_ht); + endcases; + end; + dir_BR_: begin + pos_left(c_wd); + case font_direction(dvi_direction) of + dir__RL, dir__RR: pos_down((c_ht - c_dp) div 2); + dir__RT: pos_up(c_dp); + dir__RB: pos_down(c_ht); + endcases; + end; + dir_LT_: begin + pos_down(c_ht); + case font_direction(dvi_direction) of + dir__TL: pos_left(c_wd); + dir__TR: ; + dir__TB, dir__TT: pos_left(c_wd div 2); + endcases; + end; + dir_RT_: begin + pos_down(c_ht); + case font_direction(dvi_direction) of + dir__TL: pos_left(c_wd); + dir__TR: ; + dir__TB, dir__TT: pos_left(c_wd div 2); + endcases; + end; + dir_LB_: begin + pos_up(c_dp); + case font_direction(dvi_direction) of + dir__BL: pos_left(c_wd); + dir__BR: ; + dir__BB, dir__BT: pos_left(c_wd div 2); + endcases; + end; + dir_RB_: begin + pos_up(c_dp); + case font_direction(dvi_direction) of + dir__BL: pos_left(c_wd); + dir__BR: ; + dir__BB, dir__BT: pos_left(c_wd div 2); + endcases; + end; + endcases; + if has_packet(ffi,c) then begin + save := cur; + save_box_pos := box_pos; + box_pos := pos; + save_direction := dvi_direction; + dvi_direction := dir_TL_; {local virtual font coordinate system} + set_to_zero(cur); + do_vf_packet(ffi, c); + dvi_direction := save_direction; + box_pos := save_box_pos; + cur := save; + end else + pdf_place_glyph(ffi, c); + case box_direction(dvi_direction) of + dir_TL_, dir_TR_, dir_BL_, dir_BR_: + cur.h := cur.h + c_wd; + dir_LT_, dir_RT_, dir_LB_, dir_RB_: + cur.h := cur.h + c_ht + c_dp; + endcases; end; @ @<Declare procedures that need to be declared forward for \pdfTeX@>= @@ -17438,24 +16493,19 @@ procedure scan_pdf_ext_toks; forward; @ Here come some subroutines to deal with expanded fonts for HZ-algorithm. -@d set_char_and_font(#) == -if is_char_node(#) then begin - c := character(#); - f := font(#); -end +@d non_existent_path == "///..." @p function get_default_hyphen_char:integer; begin - get_default_hyphen_char:=default_hyphen_char; + get_default_hyphen_char:=default_hyphen_char; end; @# function get_default_skew_char:integer; begin - get_default_skew_char:=default_skew_char; + get_default_skew_char:=default_skew_char; end; @# - procedure copy_expand_params(k, f: internal_font_number; e: integer); {set expansion-related parameters for an expanded font |k|, based on the base font |f| and the expansion amount |e|} @@ -17473,7 +16523,9 @@ var k: internal_font_number; begin if fs <> 0 then begin for k := 1 to max_font_id do - if cmp_font_name(k, s) and (font_size(k) = fs) then begin + if (tex_font_area(k) <> non_existent_path) and + cmp_font_name(k, s) and + (font_size(k) = fs) then begin flush_str(s); tfm_lookup := k; return; @@ -17481,8 +16533,9 @@ begin end else begin for k := 1 to max_font_id do - if cmp_font_name(k, s) then begin - flush_string; {|font_name|} + if (tex_font_area(k) <> non_existent_path) and + cmp_font_name(k, s) then begin + flush_string; {|font_name|} flush_str(s); tfm_lookup := k; return; @@ -17504,10 +16557,10 @@ begin if k = null_font then begin if pdf_font_auto_expand(f) then begin k := auto_expand_font(f, e); - font_id_text(k) := font_id_text(f); + font_id_text(k) := font_id_text(f); end else - k := read_font_info(null_cs, s, "", font_size(f), font_natural_dir(f)); + k := read_font_info(null_cs, s, font_size(f), font_natural_dir(f)); end; copy_expand_params(k, f, e); load_expand_font := k; @@ -17579,21 +16632,21 @@ begin end; procedure set_expand_params(f: internal_font_number; auto_expand: boolean; - font_stretch, font_shrink, font_step, expand_ratio: integer); + stretch_limit, shrink_limit, font_step, expand_ratio: integer); {expand a font with given parameters} begin set_pdf_font_step(f, font_step); set_pdf_font_auto_expand(f, auto_expand); - if font_stretch > 0 then - set_pdf_font_stretch(f,get_expand_font(f, font_stretch)); - if font_shrink > 0 then - set_pdf_font_shrink(f, get_expand_font(f, -font_shrink)); + if stretch_limit > 0 then + set_pdf_font_stretch(f,get_expand_font(f, stretch_limit)); + if shrink_limit > 0 then + set_pdf_font_shrink(f, get_expand_font(f, -shrink_limit)); if expand_ratio <> 0 then set_pdf_font_expand_ratio(f,expand_ratio); end; procedure read_expand_font; {read font expansion spec and load expanded font} -var font_shrink, font_stretch, font_step: integer; +var shrink_limit, stretch_limit, font_step: integer; f: internal_font_number; auto_expand: boolean; begin @@ -17603,26 +16656,26 @@ begin if f = null_font then pdf_error("font expansion", "invalid font identifier"); if pdf_font_blink(f) <> null_font then - pdf_error("font expansion", "\pdffontexpand cannot be used this way (the base font has been expanded or letter-spaced)"); + pdf_error("font expansion", "\pdffontexpand cannot be used this way (the base font has been expanded)"); scan_optional_equals; scan_int; - font_stretch := fix_int(cur_val, 0, 1000); + stretch_limit := fix_int(cur_val, 0, 1000); scan_int; - font_shrink := fix_int(cur_val, 0, 500); + shrink_limit := fix_int(cur_val, 0, 500); scan_int; font_step := fix_int(cur_val, 0, 100); if font_step = 0 then pdf_error("font expansion", "invalid step"); - font_stretch := font_stretch - font_stretch mod font_step; - if font_stretch < 0 then - font_stretch := 0; - font_shrink := font_shrink - font_shrink mod font_step; - if font_shrink < 0 then - font_shrink := 0; - if (font_stretch = 0) and (font_shrink = 0) then + stretch_limit := stretch_limit - stretch_limit mod font_step; + if stretch_limit < 0 then + stretch_limit := 0; + shrink_limit := shrink_limit - shrink_limit mod font_step; + if shrink_limit < 0 then + shrink_limit := 0; + if (stretch_limit = 0) and (shrink_limit = 0) then pdf_error("font expansion", "invalid limit(s)"); auto_expand := false; - if scan_keyword("autoexpand") then begin + if scan_keyword('autoexpand') then begin auto_expand := true; @<Scan an optional space@>; end; @@ -17633,42 +16686,41 @@ begin if (pdf_font_step(f) <> 0) then {this font has been expanded, ensure the expansion parameters are identical} begin - if (pdf_font_step(f) <> font_step) or - ((pdf_font_stretch(f) = null_font) and (font_stretch <> 0)) or + if pdf_font_step(f) <> font_step then + pdf_error("font expansion", "font has been expanded with different expansion step"); + + if ((pdf_font_stretch(f) = null_font) and (stretch_limit <> 0)) or ((pdf_font_stretch(f) <> null_font) and - (pdf_font_expand_ratio(pdf_font_stretch(f)) <> font_stretch)) or - ((pdf_font_shrink(f) = null_font) and (font_shrink <> 0)) or + (pdf_font_expand_ratio(pdf_font_stretch(f)) <> stretch_limit)) then + pdf_error("font expansion", "font has been expanded with different stretch limit"); + + if ((pdf_font_shrink(f) = null_font) and (shrink_limit <> 0)) or ((pdf_font_shrink(f) <> null_font) and - (pdf_font_expand_ratio(pdf_font_shrink(f)) <> -font_shrink)) or - (pdf_font_auto_expand(f) <> auto_expand) - then - pdf_error("font expansion", "font has been expanded with different parameters"); + (-pdf_font_expand_ratio(pdf_font_shrink(f)) <> shrink_limit)) then + pdf_error("font expansion", "font has been expanded with different shrink limit"); + + if pdf_font_auto_expand(f) <> auto_expand then + pdf_error("font expansion", "font has been expanded with different auto expansion value"); end else begin if font_used(f) then pdf_warning("font expansion", "font should be expanded before its first use", true, true); - set_expand_params(f, auto_expand, font_stretch, font_shrink, font_step, 0); + set_expand_params(f, auto_expand, stretch_limit, shrink_limit, font_step, 0); if font_type(f) = virtual_font_type then vf_expand_local_fonts(f); end; end; -procedure new_letterspaced_font(a: small_number); +procedure new_letterspaced_font(a: small_number); {letter-space a font by creating a virtual font} var u:pointer; {user's font identifier} @!t:str_number; {name for the frozen font identifier} -@!old_setting:0..max_selector; {holds |selector| setting} @!f, k:internal_font_number; begin get_r_token; u:=cur_cs; - if u>=hash_base then t:=text(u) - else if u=null_cs then t:="FONT" - else begin old_setting:=selector; selector:=new_string; - print("FONT"); print(u-active_base); selector:=old_setting; - @.FONTx@> - str_room(1); t:=make_string; - end; + if u>=hash_base then t:=text(u) else t:="FONT"; +@.FONTx@> define(u,set_font,null_font); scan_optional_equals; scan_font_ident; k := cur_val; scan_int; @@ -17676,6 +16728,22 @@ begin equiv(u):=f; eqtb[font_id_base+f]:=eqtb[u]; font_id_text(f):=t; end; +procedure make_font_copy(a: small_number); +{make a font copy for further use with font expansion} +var u:pointer; {user's font identifier} +@!t:str_number; {name for the frozen font identifier} +@!f, k:internal_font_number; +begin + get_r_token; u:=cur_cs; + if u>=hash_base then t:=text(u) else t:="FONT"; +@.FONTx@> + define(u,set_font,null_font); scan_optional_equals; scan_font_ident; + k := cur_val; + f := copy_font_info(k); + equiv(u):=f; eqtb[font_id_base+f]:=eqtb[u]; font_id_text(f):=t; +end; + + @ We need to hold information about used characters in each font for partial downloading. @@ -17790,7 +16858,8 @@ begin selector:=old_setting; str_room(7); str_pool[pool_ptr] := 0; { make C string for pdfsetmatrix } - pdfsetmatrix(str_start_macro(str_ptr), cur_h, cur_page_height - cur_v); + synch_pos_with_cur; + pdfsetmatrix(str_start_macro(str_ptr), pos); str_room(7); append_char(" "); append_char("0"); @@ -17806,13 +16875,15 @@ end; procedure pdf_out_save; begin - checkpdfsave(cur_h, cur_v); + synch_pos_with_cur; + checkpdfsave(pos); literal("q", set_origin, false); end; procedure pdf_out_restore; begin - checkpdfrestore(cur_h, cur_v); + synch_pos_with_cur; + checkpdfrestore(pos); literal("Q", set_origin, false); end; @@ -17829,15 +16900,12 @@ begin end; procedure do_late_lua(p: pointer); -var old_setting:0..max_selector; {holds print |selector|} - s: str_number; begin - old_setting:=selector; selector:=new_string; - show_token_list(link(late_lua_data(p)),null,pool_size-pool_ptr); - selector:=old_setting; - s := make_string; - latelua(late_lua_reg(p), s); - flush_str(s); + if not doing_leaders then begin + expand_late_lua(p); + latelua(def_ref, late_lua_name(p)); + flush_list(def_ref); + end; end; procedure pdf_print_toks(p: pointer); {print tokens list |p|} @@ -17870,8 +16938,6 @@ end; procedure pdf_hlist_out; {output an |hlist_node| box} label move_past, fin_rule, next_p; var base_line: scaled; {the baseline coordinate for this box} -c_wd,c_ht,c_dp: scaled; - {the real width, height and depth of the character} w: scaled; { temporary value for directional width calculation } dir_nest: integer; { for tracking nested direction nodes } edge_v: scaled; @@ -17879,12 +16945,11 @@ edge_h: scaled; effective_horizontal: scaled; basepoint_horizontal: scaled; basepoint_vertical: scaled; -saving_h: scaled; -saving_v: scaled; save_direction: integer; dvi_ptr,dir_ptr,dir_tmp:pointer; @!left_edge: scaled; {the left coordinate for this box} -@!save_h: scaled; {what |cur_h| should pop to} +@!save_h: scaled; {what |cur.h| should pop to} +@!save_box_pos: scaledpos; {what |box_pos| should pop to} @!this_box: pointer; {pointer to containing box} @!g_order: glue_ord; {applicable order of infinity for glue} @!g_sign: normal..shrinking; {selects type of glue} @@ -17894,6 +16959,7 @@ dvi_ptr,dir_ptr,dir_tmp:pointer; @!lx:scaled; {extra space between leader boxes} @!outer_doing_leaders:boolean; {were we doing leaders?} @!edge:scaled; {right edge of sub-box or leader space} +@!border:scaled; {right edge of sub-box or leader space} @!prev_p:pointer; {one step behind |p|} @!glue_temp:real; {glue value before rounding} @!cur_glue:real; {glue seen so far} @@ -17904,20 +16970,21 @@ dvi_ptr,dir_ptr,dir_tmp:pointer; begin cur_g:=0; cur_glue:=float_constant(0); this_box:=temp_ptr; g_order:=glue_order(this_box); g_sign:=glue_sign(this_box); p:=list_ptr(this_box); +set_to_zero(cur); box_pos:=pos; save_direction:=dvi_direction; dvi_direction:=box_dir(this_box); dvi_ptr:=0; lx:=0; @<DIR: Initialize |dir_ptr| for |ship_out|@>; -saving_h:=cur_h; saving_v:=cur_v; incr(cur_s); -base_line:=cur_v; -left_edge:=cur_h; +base_line:=cur.v; +left_edge:=cur.h; prev_p:=this_box+list_offset; @<Create link annotations for the current hbox if needed@>; +@<Start hlist {\sl Sync\TeX} information record@>; while p<>null do @<Output node |p| for |pdf_hlist_out| and move to the next node, - maintaining the condition |cur_v=base_line|@>; -cur_h:=saving_h; cur_v:=saving_v; + maintaining the condition |cur.v=base_line|@>; +@<Finish hlist {\sl Sync\TeX} information record@>; decr(cur_s); dvi_direction:=save_direction; @<DIR: Reset |dir_ptr|@>; @@ -17932,184 +16999,39 @@ end @ -@d pdf_dvicmd_set(#)==output_one_char(f,#) -@d pdf_dvicmd_put(#)==output_one_char(f,#); cur_h:=cur_h-c_wd -@d pdf_dvicmd_right(#)==cur_h := cur_h + # -@d pdf_dvicmd_left(#)== cur_h := cur_h - # -@d pdf_dvicmd_down(#)== cur_v := cur_v - # -@d pdf_dvicmd_up(#)== cur_v := cur_v + # -@d pdf_dvicmd_h(#)==case box_direction(dvi_direction) of - dir_TL_: begin cur_h := cur_h + #; end; - dir_TR_: begin cur_h := cur_h - #; end; - dir_LT_: begin do_nothing; {if o=right1 then o:=down1 else o:=right1;} end; - dir_LB_: begin do_nothing; {if o=right1 then begin o:=down1; negate(w); end else o:=right1;} end; - dir_BL_: begin do_nothing; {if o=down1 then negate(w); } end; - dir_BR_: begin do_nothing; { negate(w);} end; - dir_RT_: begin do_nothing; {if o=right1 then o:=down1 else begin o:=right1; negate(w); end;} end; - dir_RB_: begin do_nothing; {if o=right1 then o:=down1 else o:=right1; negate(w);} end; - end - +@d pos_right(#) == pos.h := pos.h + (#) +@d pos_left(#) == pos.h := pos.h - (#) +@d pos_up(#) == pos.v := pos.v + (#) +@d pos_down(#) == pos.v := pos.v - (#) @<Output node |p| for |pdf_hlist_out|...@>= begin -if is_char_node(p) then - begin - repeat f:=font(p); c:=character(p); - ci := char_info_short (f,c); - {|writeln('hlist_out: a char node ', c:1 , ' in font ',f:1);|} - if is_valid_char(c) then begin - if is_rotated(dvi_direction) then begin - c_ht:=charinfo_width(ci) div 2; - c_dp:=0; - c_wd:=charinfo_height(ci)+charinfo_depth(ci); - end - else begin - c_ht:=charinfo_height(ci); - c_dp:=charinfo_depth(ci); - c_wd:=charinfo_width(ci); - end; - if (font_natural_dir(f)<>-1) then - case font_direction(dvi_direction) of - dir__LT,dir__LB: begin - if x_displace(p)<>0 then pdf_dvicmd_right(x_displace(p)); - if y_displace(p)<>0 then pdf_dvicmd_up(-y_displace(p)); - pdf_dvicmd_set(c); - if x_displace(p)<>0 then pdf_dvicmd_left(x_displace(p)); - if y_displace(p)<>0 then pdf_dvicmd_down(-y_displace(p)); - end; - dir__RT,dir__RB: begin - if x_displace(p)<>0 then pdf_dvicmd_left(x_displace(p)); - if y_displace(p)<>0 then pdf_dvicmd_up(-y_displace(p)); - pdf_dvicmd_left(c_wd); - pdf_dvicmd_put(c); - if x_displace(p)<>0 then pdf_dvicmd_right(x_displace(p)); - if y_displace(p)<>0 then pdf_dvicmd_down(-y_displace(p)); - end; - dir__TL,dir__TR: begin - pdf_dvicmd_put(c); - pdf_dvicmd_down(c_wd); - end; - dir__BL,dir__BR: begin - pdf_dvicmd_put(c); - pdf_dvicmd_up(c_wd); - end; - dir__LL,dir__LR: begin - pdf_dvicmd_put(c); - pdf_dvicmd_right(c_wd); - end; - dir__RL,dir__RR: begin - pdf_dvicmd_put(c); - pdf_dvicmd_left(c_wd); - end; - dir__TT,dir__TB: begin - pdf_dvicmd_put(c); - pdf_dvicmd_down(c_wd); - end; - dir__BT,dir__BB: begin - pdf_dvicmd_put(c); - pdf_dvicmd_up(c_wd); - end; - end - else - case font_direction(dvi_direction) of - dir__LT: begin - if x_displace(p)<>0 then pdf_dvicmd_right(x_displace(p)); - if y_displace(p)<>0 then pdf_dvicmd_up(-y_displace(p)); - pdf_dvicmd_set(c); - if x_displace(p)<>0 then pdf_dvicmd_left(x_displace(p)); - if y_displace(p)<>0 then pdf_dvicmd_down(-y_displace(p)); - end; - dir__LB: begin - pdf_dvicmd_down(c_ht); - pdf_dvicmd_set(c); - pdf_dvicmd_up(c_ht); - end; - dir__RT: begin - if x_displace(p)<>0 then pdf_dvicmd_left(x_displace(p)); - if y_displace(p)<>0 then pdf_dvicmd_up(-y_displace(p)); - pdf_dvicmd_left(c_wd); - pdf_dvicmd_put(c); - if x_displace(p)<>0 then pdf_dvicmd_right(x_displace(p)); - if y_displace(p)<>0 then pdf_dvicmd_down(-y_displace(p)); - end; - dir__RB: begin - pdf_dvicmd_left(c_wd); - pdf_dvicmd_down(c_ht); - pdf_dvicmd_put(c); - pdf_dvicmd_up(c_ht); - end; - dir__TL: begin - pdf_dvicmd_down(c_wd); - pdf_dvicmd_left(c_ht); - pdf_dvicmd_put(c); - pdf_dvicmd_right(c_ht); - end; - dir__TR: begin - pdf_dvicmd_down(c_wd); - pdf_dvicmd_left(c_dp); - pdf_dvicmd_put(c); - pdf_dvicmd_right(c_dp); - end; - dir__BL: begin - pdf_dvicmd_left(c_ht); - pdf_dvicmd_put(c); - pdf_dvicmd_right(c_ht); - pdf_dvicmd_up(c_wd); - end; - dir__BR: begin - pdf_dvicmd_left(c_dp); - pdf_dvicmd_put(c); - pdf_dvicmd_right(c_dp); - pdf_dvicmd_up(c_wd); - end; - dir__LL,dir__LR: begin - pdf_dvicmd_down(c_ht); - pdf_dvicmd_put(c); - pdf_dvicmd_up(c_ht); - pdf_dvicmd_right(c_wd); - end; - dir__RL,dir__RR: begin - pdf_dvicmd_left(c_wd); - pdf_dvicmd_down(c_ht); - pdf_dvicmd_put(c); - pdf_dvicmd_up(c_ht); - end; - dir__TT,dir__TB: begin - pdf_dvicmd_down(c_wd); - pdf_dvicmd_left(c_ht); - pdf_dvicmd_put(c); - pdf_dvicmd_right(c_ht); - end; - dir__BT,dir__BB: begin - pdf_dvicmd_left(c_ht); - pdf_dvicmd_put(c); - pdf_dvicmd_right(c_ht); - pdf_dvicmd_up(c_wd); - end; - end; - cur_h:=cur_h+c_wd; - end - else - char_warning(f, c); - prev_p:=p; - p:=vlink(p); +if is_char_node(p) then begin + repeat + if x_displace(p)<>0 then cur.h := cur.h + x_displace(p); + if y_displace(p)<>0 then cur.v := cur.v - y_displace(p); + output_one_char(font(p), character(p)); + if x_displace(p)<>0 then cur.h := cur.h - x_displace(p); + if y_displace(p)<>0 then cur.v := cur.v + y_displace(p); + p:=vlink(p); until not is_char_node(p); - end + @<Record current point {\sl Sync\TeX} information@>; +end else @<Output the non-|char_node| |p| for |pdf_hlist_out| and move to the next node@>; end @ @<Output the non-|char_node| |p| for |pdf_hlist_out|...@>= begin case type(p) of -hlist_node,vlist_node:@<(\pdfTeX) Output a box in an hlist@>; -disc_node: if vlink(no_break(p))<>null then begin +hlist_node_case,vlist_node_case:@<(\pdfTeX) Output a box in an hlist@>; +disc_node_case: if vlink(no_break(p))<>null then begin q:=tail_of_list (vlink(no_break(p))); {TODO, this should be a tlink} vlink(q):=vlink(p); q:=vlink(no_break(p)); vlink(no_break(p)):=null; vlink(p):=q; end; -rule_node: begin +rule_node_case: begin if not (dir_orthogonal(dir_primary[rule_dir(p)])(dir_primary[dvi_direction])) then begin rule_ht:=height(p); rule_dp:=depth(p); rule_wd:=width(p); @@ -18121,15 +17043,25 @@ rule_node: begin end; goto fin_rule; end; -whatsit_node: @<Output the whatsit node |p| in |pdf_hlist_out|@>; -glue_node: @<(\pdfTeX) Move right or output leaders@>; -margin_kern_node,kern_node: pdf_dvicmd_h(width(p)); -math_node: pdf_dvicmd_h(surround(p)); +whatsit_node_case: @<Output the whatsit node |p| in |pdf_hlist_out|@>; +glue_node_case: @<(\pdfTeX) Move right or output leaders@>; +margin_kern_node_case: cur.h := cur.h + width(p); +kern_node_case: begin + @<Record |kern_node| {\sl Sync\TeX} information@>; + cur.h := cur.h + width(p); + end; +math_node_case: begin + @<Record |math_node| {\sl Sync\TeX} information@>; + cur.h := cur.h + surround(p); + end; othercases do_nothing endcases;@/ goto next_p; fin_rule: @<(\pdfTeX) Output a rule in an hlist@>; -move_past: pdf_dvicmd_h(rule_wd); +move_past: begin + cur.h := cur.h + rule_wd; + @<Record horizontal |rule_node| or |glue_node| {\sl Sync\TeX} information@>; + end; next_p:prev_p:=p; p:=vlink(p); end @@ -18146,7 +17078,7 @@ if not (dir_orthogonal(dir_primary[box_dir(p)])(dir_primary[dvi_direction])) end else begin effective_horizontal:=height(p)+depth(p); - if not (is_mirrored(box_dir(p))) then + if not is_mirrored(box_dir(p)) then if dir_eq(dir_primary[box_dir(p)])(dir_secondary[dvi_direction]) then basepoint_horizontal:=height(p) else @@ -18161,74 +17093,45 @@ else begin else basepoint_vertical:= (width(p) div 2); end; -if not (is_mirrored(dvi_direction)) then +if not is_mirrored(dvi_direction) then basepoint_vertical := basepoint_vertical + shift_amount(p) {shift the box `down'} else basepoint_vertical := basepoint_vertical - shift_amount(p); {shift the box `up'} -if list_ptr(p)=null then begin pdf_dvicmd_h(effective_horizontal); end +if list_ptr(p)=null then begin + @<Record void list {\sl Sync\TeX} information@>; + cur.h := cur.h + effective_horizontal; + end else begin temp_ptr:=p; - edge:=cur_h; pdf_dvicmd_h(basepoint_horizontal); - edge_v:=cur_v; cur_v:=base_line + basepoint_vertical; + edge:=cur.h; cur.h := cur.h + basepoint_horizontal; + edge_v:=cur.v; cur.v:=base_line + basepoint_vertical; + synch_pos_with_cur; + save_box_pos:=box_pos; if type(p)=vlist_node then pdf_vlist_out@+else pdf_hlist_out; - cur_h:=edge; pdf_dvicmd_h(effective_horizontal); - cur_v:=base_line; + box_pos:=save_box_pos; + cur.h:=edge; cur.h := cur.h + effective_horizontal; + cur.v:=base_line; end end @ @<(\pdfTeX) Output a rule in an hlist@>= if is_running(rule_ht) then rule_ht:=height(this_box); if is_running(rule_dp) then rule_dp:=depth(this_box); -rule_ht:=rule_ht+rule_dp; {this is the rule thickness} -if (rule_ht>0)and(rule_wd>0) then {we don't output empty rules} - begin cur_v:=base_line+rule_dp; - case font_direction(dvi_direction) of - dir__LT: begin - pdf_set_rule(cur_h, cur_v, rule_wd, rule_ht); - end; - dir__LB: begin - pdf_dvicmd_down(rule_ht); - pdf_set_rule(cur_h, cur_v, rule_wd, rule_ht); - pdf_dvicmd_up(rule_ht); - end; - dir__RT: begin - pdf_dvicmd_left(rule_wd); - pdf_set_rule(cur_h, cur_v, rule_wd, rule_ht); - pdf_dvicmd_right(rule_wd); - end; - dir__RB: begin - pdf_dvicmd_left(rule_wd); - pdf_dvicmd_down(rule_ht); - pdf_set_rule(cur_h, cur_v, rule_wd, rule_ht); - pdf_dvicmd_left(rule_wd); - pdf_dvicmd_up(rule_ht); - end; - dir__TL: begin - pdf_dvicmd_down(rule_wd); - pdf_dvicmd_left(rule_ht); - pdf_set_rule(cur_h, cur_v, rule_wd, rule_ht); - end; - dir__TR: begin - pdf_dvicmd_down(rule_wd); - pdf_set_rule(cur_h, cur_v, rule_wd, rule_ht); - pdf_dvicmd_left(rule_ht); - end; - dir__BL: begin - pdf_dvicmd_left(rule_ht); - pdf_set_rule(cur_h, cur_v, rule_wd, rule_ht); - pdf_dvicmd_up(rule_wd); - end; - dir__BR: begin - pdf_set_rule(cur_h, cur_v, rule_wd, rule_ht); - pdf_dvicmd_left(rule_ht); - pdf_dvicmd_up(rule_wd); - end; - end; - {|cur_h:=cur_h+rule_wd;|}{|dir__RT| is corrected elsewhere} - cur_v:=base_line; - end +if ((rule_ht+rule_dp)>0)and(rule_wd>0) then begin {we don't output empty rules} + synch_pos_with_cur; + case box_direction(dvi_direction) of + dir_TL_: pdf_place_rule(pos.h, pos.v - rule_dp, rule_wd, rule_ht + rule_dp); + dir_BL_: pdf_place_rule(pos.h, pos.v - rule_ht, rule_wd, rule_ht + rule_dp); + dir_TR_: pdf_place_rule(pos.h - rule_wd, pos.v - rule_dp, rule_wd, rule_ht + rule_dp); + dir_BR_: pdf_place_rule(pos.h - rule_wd, pos.v - rule_ht, rule_wd, rule_ht + rule_dp); + dir_LT_: pdf_place_rule(pos.h - rule_ht, pos.v - rule_wd, rule_ht + rule_dp, rule_wd); + dir_RT_: pdf_place_rule(pos.h - rule_dp, pos.v - rule_wd, rule_ht + rule_dp, rule_wd); + dir_LB_: pdf_place_rule(pos.h - rule_ht, pos.v, rule_ht + rule_dp, rule_wd); + dir_RB_: pdf_place_rule(pos.h - rule_dp, pos.v, rule_ht + rule_dp, rule_wd); + end; +end @ @<(\pdfTeX) Move right or output leaders@>= begin g:=glue_ptr(p); rule_wd:=width(g)-cur_g; @@ -18266,29 +17169,34 @@ else leader_wd:=height(leader_box)+depth(leader_box); if (leader_wd>0)and(rule_wd>0) then begin - edge:=cur_h+rule_wd; {TODO this double |case| is a hack, and not quite the proper solution, but it produces the correct output for |xleaders| in TRT mode, which is important for KASHIDAH fills.} case box_direction(dvi_direction) of dir_TR_,dir_RT_: begin - edge:=cur_h; - cur_h:=cur_h-rule_wd; + border:=cur.h+leader_wd; + cur.h:=cur.h-rule_wd+leader_wd; + edge:=cur.h-leader_wd; + end; + othercases begin { |dir_TL_,dir_LT_| } + edge:=cur.h+rule_wd; + border:=edge; end; end; - @<Let |cur_h| be the position of the first box, and set |leader_wd+lx| + @<Let |cur.h| be the position of the first box, and set |leader_wd+lx| to the spacing between corresponding parts of boxes@>; - while cur_h+leader_wd<=edge do - @<(\pdfTeX) Output a leader box at |cur_h|, - then advance |cur_h| by |leader_wd+lx|@>; + while cur.h+leader_wd<=border do + @<(\pdfTeX) Output a leader box at |cur.h|, + then advance |cur.h| by |leader_wd+lx|@>; case box_direction(dvi_direction) of - dir_TR_,dir_RT_: cur_h:=cur_h-rule_wd; + dir_TR_,dir_RT_: cur.h:=edge; + dir_TL_,dir_LT_: cur.h:=edge; end; goto next_p; end; end -@ @<(\pdfTeX) Output a leader box at |cur_h|, ...@>= +@ @<(\pdfTeX) Output a leader box at |cur.h|, ...@>= begin if not (dir_orthogonal(dir_primary[box_dir(leader_box)])(dir_primary[dvi_direction])) then begin @@ -18300,7 +17208,7 @@ if not (dir_orthogonal(dir_primary[box_dir(leader_box)])(dir_primary[dvi_directi basepoint_horizontal:=0; end else begin - if not (is_mirrored(box_dir(leader_box))) then + if not is_mirrored(box_dir(leader_box)) then if dir_eq(dir_primary[box_dir(leader_box)])(dir_secondary[dvi_direction]) then basepoint_horizontal:=height(leader_box) else @@ -18315,19 +17223,22 @@ else begin else basepoint_vertical:= (width(leader_box) div 2); end; -if not (is_mirrored(dvi_direction)) then +if not is_mirrored(dvi_direction) then basepoint_vertical := basepoint_vertical + shift_amount(leader_box) {shift the box `down'} else basepoint_vertical := basepoint_vertical - shift_amount(leader_box); {shift the box `up'} temp_ptr:=leader_box; -edge_h:=cur_h; cur_h:=cur_h + basepoint_horizontal; -edge_v:=cur_v; cur_v:=base_line + basepoint_vertical; +edge_h:=cur.h; cur.h:=cur.h + basepoint_horizontal; +edge_v:=cur.v; cur.v:=base_line + basepoint_vertical; +synch_pos_with_cur; +save_box_pos:=box_pos; outer_doing_leaders:=doing_leaders; doing_leaders:=true; if type(leader_box)=vlist_node then pdf_vlist_out@+else pdf_hlist_out; doing_leaders:=outer_doing_leaders; -cur_h:=edge_h+leader_wd+lx; cur_v:=base_line; +box_pos:=save_box_pos; +cur.h:=edge_h+leader_wd+lx; cur.v:=base_line; end @ The |pdf_vlist_out| routine is similar to |pdf_hlist_out|, but a bit simpler. @@ -18335,7 +17246,8 @@ end label move_past, fin_rule, next_p; var left_edge: scaled; {the left coordinate for this box} @!top_edge: scaled; {the top coordinate for this box} -@!save_v: scaled; {what |cur_v| should pop to} +@!save_v: scaled; {what |cur.v| should pop to} +@!save_box_pos: scaledpos; {what |box_pos| should pop to} @!this_box: pointer; {pointer to containing box} @!g_order: glue_ord; {applicable order of infinity for glue} @!g_sign: normal..shrinking; {selects type of glue} @@ -18353,23 +17265,23 @@ var left_edge: scaled; {the left coordinate for this box} @!basepoint_horizontal: scaled; @!basepoint_vertical: scaled; @!edge_v: scaled; -@!saving_v: scaled; -@!saving_h: scaled; begin cur_g:=0; cur_glue:=float_constant(0); this_box:=temp_ptr; g_order:=glue_order(this_box); g_sign:=glue_sign(this_box); p:=list_ptr(this_box); {pdfassert(p<>0);} -saving_v:=cur_v; saving_h:=cur_h; -{|writeln(''); writeln('vlist_out: left edge: ', cur_h:1 , '');|} +set_to_zero(cur); box_pos:=pos; +{|writeln(''); writeln('vlist_out: left edge: ', cur.h:1 , '');|} save_direction:=dvi_direction; dvi_direction:=box_dir(this_box); incr(cur_s); -left_edge:=cur_h; cur_v:=cur_v-height(this_box); top_edge:=cur_v; +left_edge:=cur.h; +@<Start vlist {\sl Sync\TeX} information record@>; +cur.v:=cur.v-height(this_box); top_edge:=cur.v; @<Create thread for the current vbox if needed@>; while p<>null do @<Output node |p| for |pdf_vlist_out| and move to the next node, - maintaining the condition |cur_h=left_edge|@>; -cur_v:=saving_v; cur_h:=saving_h; + maintaining the condition |cur.h=left_edge|@>; +@<Finish vlist {\sl Sync\TeX} information record@>; decr(cur_s); dvi_direction:=save_direction; end; @@ -18388,8 +17300,8 @@ end @ @<Output the non-|char_node| |p| for |pdf_vlist_out|@>= begin case type(p) of -hlist_node,vlist_node:@<(\pdfTeX) Output a box in a vlist@>; -rule_node: begin +hlist_node_case,vlist_node_case:@<(\pdfTeX) Output a box in a vlist@>; +rule_node_case: begin if not (dir_orthogonal(dir_primary[rule_dir(p)])(dir_primary[dvi_direction])) then begin rule_ht:=height(p); rule_dp:=depth(p); rule_wd:=width(p); @@ -18401,14 +17313,14 @@ rule_node: begin end; goto fin_rule; end; -whatsit_node: @<Output the whatsit node |p| in |pdf_vlist_out|@>; -glue_node: @<(\pdfTeX) Move down or output leaders@>; -kern_node:cur_v:=cur_v+width(p); +whatsit_node_case: @<Output the whatsit node |p| in |pdf_vlist_out|@>; +glue_node_case: @<(\pdfTeX) Move down or output leaders@>; +kern_node_case:cur.v := cur.v + width(p); othercases do_nothing endcases;@/ goto next_p; fin_rule: @<(\pdfTeX) Output a rule in a vlist, |goto next_p|@>; -move_past: cur_v:=cur_v+rule_ht; +move_past: cur.v := cur.v + rule_ht; end @ TODO: the direct test to switch between |width(p)| and |-width(p)| @@ -18422,7 +17334,7 @@ begin if not (dir_orthogonal(dir_primary[box_dir(p)])(dir_primary[dvi_direction])) then begin effective_vertical:=height(p)+depth(p); - if (type(p)=hlist_node) and (is_mirrored(box_dir(p))) then + if (type(p)=hlist_node) and is_mirrored(box_dir(p)) then basepoint_vertical:=depth(p) else basepoint_vertical:=height(p); @@ -18437,7 +17349,7 @@ if not (dir_orthogonal(dir_primary[box_dir(p)])(dir_primary[dvi_direction])) end else begin effective_vertical:=width(p); - if not (is_mirrored(box_dir(p))) then + if not is_mirrored(box_dir(p)) then if dir_eq(dir_primary[box_dir(p)])(dir_secondary[dvi_direction]) then basepoint_horizontal:=height(p) else @@ -18454,68 +17366,39 @@ else begin end; basepoint_horizontal := basepoint_horizontal + shift_amount(p); if list_ptr(p)=null then begin - cur_v:=cur_v+effective_vertical; + cur.v:=cur.v+effective_vertical; + @<Record void list {\sl Sync\TeX} information@>; end else begin - edge_v:=cur_v; - cur_h:=left_edge + basepoint_horizontal; - cur_v:=cur_v + basepoint_vertical; + edge_v:=cur.v; + cur.h:=left_edge + basepoint_horizontal; + cur.v:=cur.v + basepoint_vertical; + synch_pos_with_cur; + save_box_pos:=box_pos; temp_ptr:=p; if type(p)=vlist_node then pdf_vlist_out@+else pdf_hlist_out; - cur_h:=left_edge; cur_v:=edge_v + effective_vertical; + box_pos:=save_box_pos; + cur.h:=left_edge; cur.v:=edge_v + effective_vertical; end end @ @<(\pdfTeX) Output a rule in a vlist...@>= if is_running(rule_wd) then rule_wd:=width(this_box); rule_ht:=rule_ht+rule_dp; {this is the rule thickness} -cur_v:=cur_v+rule_ht; -if (rule_ht>0)and(rule_wd>0) then {we don't output empty rules} - begin - case font_direction(dvi_direction) of - dir__LT: begin - pdf_set_rule(cur_h, cur_v, rule_wd, rule_ht); - {|pdf_dvicmd_left(rule_wd);|} - end; - dir__LB: begin - pdf_dvicmd_down(rule_ht); - pdf_set_rule(cur_h, cur_v, rule_wd, rule_ht); - pdf_dvicmd_left(rule_wd); - pdf_dvicmd_up(rule_ht); - end; - dir__RT: begin - pdf_dvicmd_left(rule_wd); - pdf_set_rule(cur_h, cur_v, rule_wd, rule_ht); - pdf_dvicmd_left(rule_wd); - end; - dir__RB: begin - pdf_dvicmd_down(rule_ht); - pdf_dvicmd_left(rule_wd); - pdf_set_rule(cur_h, cur_v, rule_wd, rule_ht); - pdf_dvicmd_up(rule_ht); - end; - dir__TL: begin - pdf_dvicmd_down(rule_wd); - pdf_dvicmd_left(rule_ht); - pdf_set_rule(cur_h, cur_v, rule_wd, rule_ht); - pdf_dvicmd_up(rule_wd); - end; - dir__TR: begin - pdf_dvicmd_down(rule_wd); - pdf_set_rule(cur_h, cur_v, rule_wd, rule_ht); - pdf_dvicmd_left(rule_wd); - pdf_dvicmd_up(rule_wd); - end; - dir__BL: begin - pdf_dvicmd_left(rule_ht); - pdf_set_rule(cur_h, cur_v, rule_wd, rule_ht); - end; - dir__BR: begin - pdf_set_rule(cur_h, cur_v, rule_wd, rule_ht); - pdf_dvicmd_left(rule_wd); - end; - end; +if (rule_ht>0)and(rule_wd>0) then begin {we don't output empty rules} + synch_pos_with_cur; + case box_direction(dvi_direction) of + dir_TL_: pdf_place_rule(pos.h, pos.v - rule_ht, rule_wd, rule_ht); + dir_BL_: pdf_place_rule(pos.h, pos.v, rule_wd, rule_ht); + dir_TR_: pdf_place_rule(pos.h - rule_wd, pos.v - rule_ht, rule_wd, rule_ht); + dir_BR_: pdf_place_rule(pos.h - rule_wd, pos.v, rule_wd, rule_ht); + dir_LT_: pdf_place_rule(pos.h, pos.v - rule_wd, rule_ht, rule_wd); + dir_RT_: pdf_place_rule(pos.h - rule_ht, pos.v - rule_wd, rule_ht, rule_wd); + dir_LB_: pdf_place_rule(pos.h, pos.v, rule_ht, rule_wd); + dir_RB_: pdf_place_rule(pos.h - rule_ht, pos.v, rule_ht, rule_wd); end; + cur.v := cur.v + rule_ht; +end; goto next_p @ @<(\pdfTeX) Move down or output leaders@>= @@ -18551,29 +17434,32 @@ if type(leader_box)=rule_node then leader_ht:=height(leader_box)+depth(leader_box); if (leader_ht>0)and(rule_ht>0) then begin rule_ht:=rule_ht+10; {compensate for floating-point rounding} - edge:=cur_v+rule_ht; lx:=0; - @<Let |cur_v| be the position of the first box, and set |leader_ht+lx| + edge:=cur.v+rule_ht; lx:=0; + @<Let |cur.v| be the position of the first box, and set |leader_ht+lx| to the spacing between corresponding parts of boxes@>; - while cur_v+leader_ht<=edge do - @<(\pdfTeX) Output a leader box at |cur_v|, - then advance |cur_v| by |leader_ht+lx|@>; - cur_v:=edge-10; goto next_p; + while cur.v+leader_ht<=edge do + @<(\pdfTeX) Output a leader box at |cur.v|, + then advance |cur.v| by |leader_ht+lx|@>; + cur.v:=edge-10; goto next_p; end; end -@ @<(\pdfTeX) Output a leader box at |cur_v|, ...@>= -begin cur_h:=left_edge+shift_amount(leader_box); -cur_v:=cur_v+height(leader_box); save_v:=cur_v; +@ @<(\pdfTeX) Output a leader box at |cur.v|, ...@>= +begin cur.h:=left_edge+shift_amount(leader_box); +cur.v:=cur.v+height(leader_box); save_v:=cur.v; +synch_pos_with_cur; +save_box_pos:=box_pos; temp_ptr:=leader_box; outer_doing_leaders:=doing_leaders; doing_leaders:=true; if type(leader_box)=vlist_node then pdf_vlist_out@+else pdf_hlist_out; doing_leaders:=outer_doing_leaders; -cur_h:=left_edge; -cur_v:=save_v-height(leader_box)+leader_ht+lx; +box_pos:=save_box_pos; +cur.h:=left_edge; +cur.v:=save_v-height(leader_box)+leader_ht+lx; end -@ |fix_pdfoutput| freezes |pdfoutput| when something has been written to -the output. +@ |fix_pdfoutput| freezes |fixed_pdfoutput| as soon as anything has been written +to the output file, be it \.{PDF} or \.{DVI}. @p procedure fix_pdfoutput; begin @@ -18584,25 +17470,6 @@ begin else if fixed_pdfoutput <> pdf_output then pdf_error("setup", "\pdfoutput can only be changed before anything is written to the output"); - if fixed_pdfoutput_set then fix_pdf_draftmode; -end; - -@ |fix_pdf_draftmode| freezes |pdfdraftmode| when something has been written to -the output and also switches somes things off when draftmode is on. -@p procedure fix_pdf_draftmode; -begin - if not fixed_pdf_draftmode_set then begin - fixed_pdf_draftmode := pdf_draftmode; - fixed_pdf_draftmode_set := true; - end - else if fixed_pdf_draftmode <> pdf_draftmode then - pdf_error("setup", - "\pdfdraftmode can only be changed before anything is written to the output"); - if fixed_pdf_draftmode_set and fixed_pdf_draftmode > 0 then begin - fixed_pdf_draftmode_set := true; - pdf_compress_level := 0; - fixed_pdf_objcompresslevel := 0; - end; end; @ |pdf_ship_out| is used instead of |ship_out| to shipout a box to PDF @@ -18618,23 +17485,23 @@ save_ximage_list: pointer; {to save |pdf_ximage_list|} save_xform_list: pointer; {to save |pdf_xform_list|} save_image_procset: integer; {to save |pdf_image_procset|} save_text_procset: integer; {to save |pdf_text_procset|} -save_cur_page_height: scaled; {to save |cur_page_height| during flushing pending forms} +save_cur_page_size: scaledpos; {to save |cur_page_size| during flushing pending forms} +form_margin: scaled; pdf_last_resources: integer; {pointer to most recently generated Resources object} pre_callback_id:integer; post_callback_id:integer; ret:boolean; -begin -pre_callback_id:=callback_defined(start_page_number_callback); -post_callback_id:=callback_defined(stop_page_number_callback); +begin +@<Start sheet {\sl Sync\TeX} information record@>; +form_margin := one_bp; +pre_callback_id:=callback_defined(start_page_number_callback); +post_callback_id:=callback_defined(stop_page_number_callback); if (tracing_output>0)and(pre_callback_id=0) then begin print_nl(""); print_ln; print("Completed box being shipped out"); @.Completed box...@> end; -if not init_pdf_output then begin - @<Initialize variables for \.{PDF} output@>; - init_pdf_output := true; -end; +check_pdfminorversion; is_shipping_page := shipping_page; if shipping_page then begin if pre_callback_id>0 then @@ -18651,8 +17518,8 @@ if shipping_page then begin end; update_terminal; end; -if (tracing_output>0)and(post_callback_id=0) then - begin if shipping_page then print_char("]"); +if (tracing_output>0)and(post_callback_id=0)and shipping_page then + begin print_char("]"); begin_diagnostic; show_box(p); end_diagnostic(true); end; @<(\pdfTeX) Ship box |p| out@>; @@ -18663,6 +17530,7 @@ update_terminal; {progress report} @<Flush the box from memory, showing statistics if requested@>; if post_callback_id>0 then ret:=run_callback(post_callback_id,'->'); +@<Finish sheet {\sl Sync\TeX} information record@>; end; @ @<(\pdfTeX) Ship box |p| out@>= @@ -18677,9 +17545,12 @@ cur_s:=-1; done: @ @<Initialize variables as |pdf_ship_out| begins@>= -fix_pdfoutput; -temp_ptr:=p; prepare_mag; +if mag<>1000 then + one_true_inch:=xn_over_d(one_hundred_inch,10,mag) +else + one_true_inch:=one_inch; +temp_ptr:=p; pdf_last_resources := pdf_new_objnum; @<Reset resource lists@>; dvi_direction:=page_direction; @@ -18691,7 +17562,7 @@ if not shipping_page then begin end else begin pdf_last_page := get_obj(obj_type_page, total_pages + 1, 0); - obj_aux(pdf_last_page) := 1; {mark that this page has beed created} + obj_aux(pdf_last_page) := 1; {mark that this page has been created} pdf_new_dict(obj_type_others, 0, 0); pdf_last_stream := obj_ptr; @<Reset PDF mark lists@>; @@ -18715,39 +17586,92 @@ last_thread := null @ @<Calculate PDF page dimensions and margins@>= if is_shipping_page then begin - if page_width > 0 then - cur_page_width := page_width - else - cur_page_width := width(p) + 2 * pdf_h_offset; - if page_height > 0 then - cur_page_height := page_height - else - cur_page_height := height(p) + depth(p) + 2 * pdf_v_offset; - if page_bottom_offset <> 0 then - cur_bottom_offset := page_bottom_offset - else - cur_bottom_offset := one_inch; - if page_right_offset <> 0 then - cur_right_offset := page_right_offset - else - cur_right_offset := one_inch; - cur_h := pdf_h_offset; - cur_v := height(p) + pdf_v_offset; + @<Calculate DVI page dimensions and margins@>; + {Think in upright page/paper coordinates): First preset |pos.h| and |pos.v| to the DVI origin.} + pos.h := pdf_h_origin; + pos.v := cur_page_size.v - pdf_v_origin; + box_pos := pos; + {Then calculate |cur.h| and |cur.v| within the upright coordinate system + for the DVI origin depending on the |page_direction|.} + dvi_direction:=page_direction; case box_direction(dvi_direction) of - dir_TL_,dir_LT_: begin end; - dir_TR_,dir_RT_: begin cur_h:=cur_page_width-cur_right_offset; end; - dir_RB_,dir_BR_: begin cur_h:=cur_page_width-cur_right_offset; cur_v:=-cur_bottom_offset; end; - dir_BL_,dir_LB_: begin cur_v:=-cur_bottom_offset; end; + dir_TL_,dir_LT_: begin + cur.h := page_left_offset; + cur.v := page_top_offset; + end; + dir_TR_,dir_RT_: begin + cur.h := cur_page_size.h - page_right_offset; + cur.v := page_top_offset; + end; + dir_BL_,dir_LB_: begin + cur.h := page_left_offset; + cur.v := cur_page_size.v - page_bottom_offset; + end; + dir_RB_,dir_BR_: begin + cur.h := cur_page_size.h - page_right_offset; + cur.v := cur_page_size.v - page_bottom_offset; + end; end; + cur.h := cur.h - one_true_inch; {correct for DVI origin} + cur.v := cur.v - one_true_inch; + {The movement is actually done within the upright page coordinate system.} + dvi_direction := dir_TL_; {only temporarily for this adjustment} + synch_pos_with_cur; box_pos := pos; {keep track on page} + {Then switch to page box coordinate system; do |height(p)| movement.} + dvi_direction := page_direction; + cur.h := 0; + cur.v := height(p); + synch_pos_with_cur; + {Now we are at the point on the page where the origin of the page box should go.} end else begin - cur_page_width := width(p); - cur_page_height := height(p) + depth(p); - cur_h := 0; - cur_v := height(p); + dvi_direction:=box_dir(p); + case box_direction(dvi_direction) of + dir_TL_,dir_TR_,dir_BL_,dir_BR_: begin + cur_page_size.h := width(p); + cur_page_size.v := height(p) + depth(p); + end; + dir_LT_,dir_RT_,dir_LB_,dir_RB_: begin + cur_page_size.h := height(p) + depth(p); + cur_page_size.v := width(p); + end; + end; + case box_direction(dvi_direction) of + dir_TL_: begin + pos.h := 0; + pos.v := depth(p); + end; + dir_TR_: begin + pos.h := width(p); + pos.v := depth(p); + end; + dir_BL_: begin + pos.h := 0; + pos.v := height(p); + end; + dir_BR_: begin + pos.h := width(p); + pos.v := height(p); + end; + dir_LT_: begin + pos.h := height(p); + pos.v := width(p); + end; + dir_RT_: begin + pos.h := depth(p); + pos.v := width(p); + end; + dir_LB_: begin + pos.h := height(p); + pos.v := 0; + end; + dir_RB_: begin + pos.h := depth(p); + pos.v := 0; + end; + end; end; -pdf_origin_h := 0; -pdf_origin_v := cur_page_height; +pdf_page_init; @ Here we write out the header for Form. @@ -18759,9 +17683,10 @@ if obj_xform_attr(pdf_cur_form) <> null then begin delete_toks(obj_xform_attr(pdf_cur_form)); end; pdf_print("/BBox ["); -pdf_print("0 0 "); -pdf_print_bp(cur_page_width); pdf_out(" "); -pdf_print_bp(cur_page_height); pdf_print_ln("]"); +pdf_print_bp(-form_margin); pdf_print(" "); +pdf_print_bp(-form_margin); pdf_print(" "); +pdf_print_bp(cur_page_size.h + form_margin); pdf_out(" "); +pdf_print_bp(cur_page_size.v + form_margin); pdf_print_ln("]"); pdf_print_ln("/FormType 1"); pdf_print_ln("/Matrix [1 0 0 1 0 0]"); pdf_indirect_ln("Resources", pdf_last_resources) @@ -18801,7 +17726,7 @@ if shipping_page then begin end @ @<Finish stream of page/form contents@>= -pdf_end_text; +pdf_goto_pagemode; pdfshipoutend(shipping_page); pdf_end_stream @@ -18906,26 +17831,26 @@ pdf_print_ln(" ]") @ @<Write out page object@>= pdf_begin_dict(pdf_last_page, 1); +pdf_last_pages := pdf_do_page_divert(pdf_last_page, page_divert_val); pdf_print_ln("/Type /Page"); pdf_indirect_ln("Contents", pdf_last_stream); pdf_indirect_ln("Resources", pdf_last_resources); pdf_print("/MediaBox [0 0 "); -pdf_print_mag_bp(cur_page_width); pdf_out(" "); -pdf_print_mag_bp(cur_page_height); +pdf_print_mag_bp(cur_page_size.h); pdf_out(" "); +pdf_print_mag_bp(cur_page_size.v); pdf_print_ln("]"); if pdf_page_attr <> null then pdf_print_toks_ln(pdf_page_attr); -@<Generate parent pages object@>; +pdf_indirect_ln("Parent", pdf_last_pages); +if pdf_page_group_val > 0 then begin + pdf_print("/Group "); + pdf_print_int(pdf_page_group_val); + pdf_print_ln(" 0 R"); + pdf_page_group_val := -1; +end; @<Generate array of annotations or beads in page@>; pdf_end_dict -@ @<Generate parent pages object@>= -if total_pages mod pages_tree_kids_max = 1 then begin - pdf_create_obj(obj_type_pages, pages_tree_kids_max); - pdf_last_pages := obj_ptr; -end; -pdf_indirect_ln("Parent", pdf_last_pages) - @ @<Generate array of annotations or beads in page@>= if (pdf_annot_list <> null) or (pdf_link_list <> null) then begin pdf_print("/Annots [ "); @@ -18964,7 +17889,7 @@ var s: str_number; file_opened:boolean; k:integer; res:boolean; - fnam: str_number; + fnam: str_number; callback_id:integer; begin s := tokens_to_string(obj_obj_data(n)); @@ -18982,14 +17907,14 @@ begin if obj_obj_is_file(n) > 0 then begin data_size:=0; data_cur:=0; data_buffer:=0; pack_file_name(s,"",""); - callback_id:=callback_defined(find_data_file_callback); - if callback_id>0 then begin - res := run_callback(callback_id,'S->s',stringcast(nameoffile+1),addressof(fnam)); - if (res)and(fnam<>0)and(length(fnam)>0) then begin - @<Fixup |nameoffile| after callback@>; - end; + callback_id:=callback_defined(find_data_file_callback); + if callback_id>0 then begin + res := run_callback(callback_id,'S->s',stringcast(nameoffile+1),addressof(fnam)); + if (res)and(fnam<>0)and(length(fnam)>0) then begin + @<Fixup |nameoffile| after callback@>; + end; end; - callback_id:=callback_defined(read_data_file_callback); + callback_id:=callback_defined(read_data_file_callback); if callback_id>0 then begin file_opened := false; res := run_callback(callback_id,'S->bSd',stringcast(nameoffile+1), @@ -19010,7 +17935,7 @@ begin pdf_out(data_buffer[data_cur]); incr(data_cur); end; - if data_buffer<>0 then libcfree(data_buffer); + if data_buffer<>0 then libcfree(data_buffer); print(">>"); end else if obj_obj_is_stream(n) > 0 then @@ -19037,7 +17962,7 @@ end @ When flushing pending forms we need to save and restore resource lists (|pdf_font_list|, |pdf_obj_list|, |pdf_xform_list| and |pdf_ximage_list|), which are also used by page shipping. -Saving and restoring |cur_page_height| is needed for proper +Saving and restoring |cur_page_size| is needed for proper writing out pending PDF marks. @<Write out pending forms@>= @@ -19048,9 +17973,9 @@ if pdf_xform_list <> null then begin pdf_cur_form := info(k); @<Save resource lists@>; @<Reset resource lists@>; - save_cur_page_height := cur_page_height; + save_cur_page_size := cur_page_size; pdf_ship_out(obj_xform_box(pdf_cur_form), false); - cur_page_height := save_cur_page_height; + cur_page_size := save_cur_page_size; @<Restore resource lists@>; end; k := link(k); @@ -19091,8 +18016,6 @@ if pdf_ximage_list <> null then begin end @ @<Write out pending PDF marks@>= -pdf_origin_h := 0; -pdf_origin_v := cur_page_height; @<Write out PDF annotations@>; @<Write out PDF link annotations@>; @<Write out PDF mark destinations@>; @@ -19106,7 +18029,7 @@ if pdf_annot_list <> null then begin pdf_begin_dict(info(k), 1); pdf_print_ln("/Type /Annot"); pdf_print_toks_ln(pdf_annot_data(i)); - pdf_rectangle(pdf_left(i), pdf_top(i), pdf_right(i), pdf_bottom(i)); + pdf_rectangle(i); pdf_end_dict; k := link(k); end; @@ -19119,14 +18042,13 @@ while k <> null do begin i := obj_annot_ptr(info(k)); pdf_begin_dict(info(k), 1); pdf_print_ln("/Type /Annot"); + if pdf_action_type(pdf_link_action(i)) <> pdf_action_user then + pdf_print_ln("/Subtype /Link"); if pdf_link_attr(i) <> null then pdf_print_toks_ln(pdf_link_attr(i)); - pdf_rectangle(pdf_left(i), pdf_top(i), pdf_right(i), pdf_bottom(i)); - if pdf_action_type(pdf_link_action(i)) <> pdf_action_user - then begin - pdf_print_ln("/Subtype /Link"); + pdf_rectangle(i); + if pdf_action_type(pdf_link_action(i)) <> pdf_action_user then pdf_print("/A "); - end; write_action(pdf_link_action(i)); pdf_end_dict; k := link(k); @@ -19164,8 +18086,8 @@ if pdf_dest_list <> null then begin case pdf_dest_type(i) of pdf_dest_xyz: begin pdf_print("/XYZ "); - pdf_print_mag_bp(pdf_x(pdf_left(i))); pdf_out(" "); - pdf_print_mag_bp(pdf_y(pdf_top(i))); pdf_out(" "); + pdf_print_mag_bp(pdf_ann_left(i)); pdf_out(" "); + pdf_print_mag_bp(pdf_ann_top(i)); pdf_out(" "); if pdf_dest_xyz_zoom(i) = null then pdf_print("null") else begin @@ -19178,21 +18100,21 @@ if pdf_dest_list <> null then begin pdf_print("/Fit"); pdf_dest_fith: begin pdf_print("/FitH "); - pdf_print_mag_bp(pdf_y(pdf_top(i))); + pdf_print_mag_bp(pdf_ann_top(i)); end; pdf_dest_fitv: begin pdf_print("/FitV "); - pdf_print_mag_bp(pdf_x(pdf_left(i))); + pdf_print_mag_bp(pdf_ann_left(i)); end; pdf_dest_fitb: pdf_print("/FitB"); pdf_dest_fitbh: begin pdf_print("/FitBH "); - pdf_print_mag_bp(pdf_y(pdf_top(i))); + pdf_print_mag_bp(pdf_ann_top(i)); end; pdf_dest_fitbv: begin pdf_print("/FitBV "); - pdf_print_mag_bp(pdf_x(pdf_left(i))); + pdf_print_mag_bp(pdf_ann_left(i)); end; pdf_dest_fitr: begin pdf_print("/FitR "); @@ -19213,13 +18135,21 @@ end @ @<Declare procedures needed in |pdf_hlist_out|, |pdf_vlist_out|@>= procedure pdf_print_rect_spec(r: pointer); {prints a rect spec} begin - pdf_print_mag_bp(pdf_x(pdf_left(r))); + pdf_print_mag_bp(pdf_ann_left(r)); pdf_out(" "); - pdf_print_mag_bp(pdf_y(pdf_bottom(r))); + pdf_print_mag_bp(pdf_ann_bottom(r)); pdf_out(" "); - pdf_print_mag_bp(pdf_x(pdf_right(r))); + pdf_print_mag_bp(pdf_ann_right(r)); pdf_out(" "); - pdf_print_mag_bp(pdf_y(pdf_top(r))); + pdf_print_mag_bp(pdf_ann_top(r)); +end; + +procedure pdf_rectangle(r:pointer); {output a rectangle specification to PDF file} +begin + prepare_mag; + pdf_print("/Rect ["); + pdf_print_rect_spec(r); + pdf_print_ln("]"); end; @ @<Write out PDF bead rectangle specifications@>= @@ -19333,31 +18263,6 @@ begin dvi_ship_out(p); end; -@ @<Initialize variables for \.{PDF} output@>= -check_pdfminorversion; -prepare_mag; -fixed_decimal_digits := fix_int(pdf_decimal_digits, 0, 4); -min_bp_val := - divide_scaled(one_hundred_bp, ten_pow[fixed_decimal_digits + 2], 0); -if pdf_pk_resolution = 0 then {if not set from format file or by user} - pdf_pk_resolution := pk_dpi; {take it from \.{texmf.cnf}} -fixed_pk_resolution := fix_int(pdf_pk_resolution, 72, 8000); -pk_scale_factor := - divide_scaled(72, fixed_pk_resolution, 5 + fixed_decimal_digits); -if not callback_defined(read_pk_file_callback) then begin - if pdf_pk_mode <> null then begin - kpseinitprog('PDFTEX', fixed_pk_resolution, - makecstring(tokens_to_string(pdf_pk_mode)), nil); - flush_string; - end else - kpseinitprog('PDFTEX', fixed_pk_resolution, nil, nil); - if not kpsevarvalue('MKTEXPK') then - kpsesetprogramenabled (kpsepkformat, 1, kpsesrccmdline); - end; -set_job_id(year, month, day, time); -if (pdf_unique_resname > 0) and (pdf_resname_prefix = 0) then - pdf_resname_prefix := get_resname_prefix - @ Finishing the PDF output file. The following procedures sort the table of destination names @@ -19413,53 +18318,48 @@ are already written completely to PDF output file. @<Finish the PDF file@>= if total_pages=0 then begin - if callback_id=0 then - print_nl("No pages of output.") + if callback_id=0 then + print_nl("No pages of output.") else - res:=run_callback(callback_id,'->'); - @.No pages of output@> + res:=run_callback(callback_id,'->'); + @.No pages of output@> if pdf_gone > 0 then garbage_warning; end else begin if fixed_pdf_draftmode = 0 then begin - pdf_flush; {to make sure that the output file name has been already - created} - if total_pages mod pages_tree_kids_max <> 0 then - obj_info(pdf_last_pages) := total_pages mod pages_tree_kids_max; - {last pages object may have less than |pages_tree_kids_max| children} - flush_jbig2_page0_objects; {flush page 0 objects from JBIG2 images, if any} - @<Check for non-existing pages@>; - @<Reverse the linked list of Page and Pages objects@>; - @<Check for non-existing destinations@>; - @<Output fonts definition@>; - @<Output pages tree@>; - @<Output outlines@>; - @<Output name tree@>; - @<Output article threads@>; - @<Output the catalog object@>; - pdf_print_info; {last candidate for object stream} - if pdf_os_enable then begin - pdf_os_switch(true); - pdf_os_write_objstream; - pdf_flush; - pdf_os_switch(false); - @<Output the cross-reference stream dictionary@>; + pdf_flush; {to make sure that the output file name has been already created} + flush_jbig2_page0_objects; {flush page 0 objects from JBIG2 images, if any} + @<Check for non-existing pages@>; + @<Check for non-existing destinations@>; + @<Output fonts definition@>; + pdf_last_pages := output_pages_tree; + @<Output outlines@>; + @<Output name tree@>; + @<Output article threads@>; + @<Output the catalog object@>; + pdf_print_info; {last candidate for object stream} + if pdf_os_enable then begin + pdf_os_switch(true); + pdf_os_write_objstream; + pdf_flush; + pdf_os_switch(false); + @<Output the cross-reference stream dictionary@>; + pdf_flush; + end else begin + @<Output the |obj_tab|@>; + end; + @<Output the trailer@>; pdf_flush; - end else begin - @<Output the |obj_tab|@>; - end; - @<Output the trailer@>; - pdf_flush; - if callback_id=0 then begin - print_nl("Output written on "); print_file_name(0, output_file_name, 0); - @.Output written on x@> - print(" ("); print_int(total_pages); print(" page"); - if total_pages<>1 then print_char("s"); - print(", "); print_int(pdf_offset); print(" bytes)."); - end - else - res:=run_callback(callback_id,'->'); + if callback_id=0 then begin + print_nl("Output written on "); print_file_name(0, output_file_name, 0); + @.Output written on x@> + print(" ("); print_int(total_pages); print(" page"); + if total_pages<>1 then print_char("s"); + print(", "); print_int(pdf_offset); print(" bytes)."); + end + else + res:=run_callback(callback_id,'->'); end; libpdffinish; if fixed_pdf_draftmode = 0 then b_close(pdf_file) @@ -19511,27 +18411,6 @@ while obj_aux(k) = 0 do begin end; head_tab[obj_type_page] := k -@ @<Reverse the linked list of Page and Pages objects@>= -k := head_tab[obj_type_page]; -l := 0; -repeat - i := obj_link(k); - obj_link(k) := l; - l := k; - k := i; -until k = 0; -head_tab[obj_type_page] := l; -k := head_tab[obj_type_pages]; -pages_tail := k; -l := 0; -repeat - i := obj_link(k); - obj_link(k) := l; - l := k; - k := i; -until k = 0; -head_tab[obj_type_pages] := l - @ @<Output fonts definition@>= for k := 1 to max_font_id do if font_used(k) and (pdf_font_num(k) < 0) then begin @@ -19550,7 +18429,9 @@ for k := 1 to max_font_id do print_font_identifier(i); print(" and "); print_font_identifier(k); - print(" has conflicting attributes"); print_ln; print_ln; + print(" have conflicting attributes; I will ignore the attributes assigned to "); + print_font_identifier(i); + print_ln; print_ln; end; end; fixed_gen_tounicode := pdf_gen_tounicode; @@ -19563,77 +18444,12 @@ while k <> 0 do begin end; write_fontstuff -@ We will generate in each single step the parents of all Pages/Page objects in -the previous level. These new generated Pages object will create a new level of -Pages tree. We will repeat this until search only one Pages object. This one -will be the Root object. - -@<Output pages tree@>= -a := sys_obj_ptr + 1; {all Pages objects whose children are not Page objects - should have index greater than |a|} -l := head_tab[obj_type_pages]; {|l| is the index of current Pages object - which is being output} -k := head_tab[obj_type_page]; {|k| is the index of current child of |l|} -b := 0; -repeat - i := 0; {counter of Pages object in current level} - c := 0; {first Pages object in previous level} - if obj_link(l) = 0 then - is_root := true {only Pages object; total pages is - not greater than |pages_tree_kids_max|} - else - is_root := false; - repeat - if not is_root then begin - if i mod pages_tree_kids_max = 0 then begin {create a new Pages object - for next level} - pdf_last_pages := pdf_new_objnum; - if c = 0 then - c := pdf_last_pages; - obj_link(pages_tail) := pdf_last_pages; - pages_tail := pdf_last_pages; - obj_link(pdf_last_pages) := 0; - obj_info(pdf_last_pages) := obj_info(l); - end - else - obj_info(pdf_last_pages) := obj_info(pdf_last_pages) + - obj_info(l); - end; - @<Output the current Pages object in this level@>; - incr(i); - l := obj_link(l); - until (l = c); - b := c; - if l = 0 then - goto done; -until false; -done: - -@ @<Output the current Pages object in this level@>= -pdf_begin_dict(l, 1); -pdf_print_ln("/Type /Pages"); -pdf_int_entry_ln("Count", obj_info(l)); -if not is_root then - pdf_indirect_ln("Parent", pdf_last_pages); -pdf_print("/Kids ["); -j := 0; -repeat - pdf_print_int(k); - pdf_print(" 0 R "); - k := obj_link(k); - incr(j); -until ((l < a) and (j = obj_info(l))) or - (k = 0) or ((k = b) and (b <> 0)) or - (j = pages_tree_kids_max); -remove_last_space; -pdf_print_ln("]"); -if k = 0 then begin - k := head_tab[obj_type_pages]; - head_tab[obj_type_pages] := 0; +@ @p +procedure print_pdf_pages_attr; +begin + if pdf_pages_attr <> null then + pdf_print_toks_ln(pdf_pages_attr); end; -if is_root and (pdf_pages_attr <> null) then - pdf_print_toks_ln(pdf_pages_attr); -pdf_end_dict; @ The name tree is very similiar to Pages tree so its construction should be certain from Pages tree construction. For intermediate node |obj_info| will be @@ -19826,7 +18642,7 @@ begin end; @ @<Print the Producer key@>= -pdf_print("/Producer (luaTeX-"); +pdf_print("/Producer (LuaTeX-"); pdf_print_int(luatex_version div 100); pdf_out("."); pdf_print_int(luatex_version mod 100); @@ -19843,21 +18659,25 @@ print_mod_date; @ @<Glob...@>= @!pdftex_banner: str_number; {the complete banner} -@ @<Output the |obj_tab|@>= +@ @<Build a linked list of free objects@>= l := 0; +set_obj_fresh(l); {null object at begin of list of free objects} for k := 1 to sys_obj_ptr do - if obj_offset(k) = 0 then begin + if not is_obj_written(k) then begin obj_link(l) := k; l := k; end; -obj_link(l) := 0; +obj_link(l) := 0 + +@ @<Output the |obj_tab|@>= +@<Build a linked list of free objects@>; pdf_save_offset := pdf_offset; pdf_print_ln("xref"); pdf_print("0 "); pdf_print_int_ln(obj_ptr + 1); pdf_print_fw_int(obj_link(0), 10); pdf_print_ln(" 65535 f "); for k := 1 to obj_ptr do begin - if obj_offset(k) = 0 then begin + if not is_obj_written(k) then begin pdf_print_fw_int(obj_link(k), 10); pdf_print_ln(" 00000 f "); end @@ -19869,21 +18689,15 @@ end @ @<Output the cross-reference stream dictionary@>= pdf_new_dict(obj_type_others, 0, 0); -if obj_offset(sys_obj_ptr) > 16777215 then +if ((obj_offset(sys_obj_ptr)/256) > 16777215) then + xref_offset_width := 5 +else if obj_offset(sys_obj_ptr) > 16777215 then xref_offset_width := 4 else if obj_offset(sys_obj_ptr) > 65535 then xref_offset_width := 3 -else if obj_offset(sys_obj_ptr) > 255 then - xref_offset_width := 2 else - xref_offset_width := 1; -l := 0; -for k := 1 to sys_obj_ptr do - if obj_offset(k) = 0 then begin - obj_link(l) := k; - l := k; - end; -obj_link(l) := 0; + xref_offset_width := 2; +@<Build a linked list of free objects@>; pdf_print_ln("/Type /XRef"); pdf_print("/Index [0 "); pdf_print_int(obj_ptr); @@ -19902,7 +18716,7 @@ print_ID(output_file_name); pdf_print_nl; pdf_begin_stream; for k := 0 to sys_obj_ptr do begin - if obj_offset(k) = 0 then begin {a free object} + if not is_obj_written(k) then begin {a free object} pdf_out(0); pdf_out_bytes(obj_link(k), xref_offset_width); pdf_out(255); @@ -20004,26 +18818,26 @@ attr_list:=attr_list_cache; if three_codes then begin s:=saved(0); continue: - if scan_keyword("attr") then begin + if scan_keyword('attr') then begin scan_register_num; i:=cur_val; scan_optional_equals; scan_int; v:=cur_val; - if (attr_list<>null) and (attr_list=attr_list_cache) then begin + if (attr_list<>null) and (attr_list=attr_list_cache) then begin attr_list:=copy_attribute_list(attr_list_cache); - add_node_attr_ref(attr_list); {will be used once} + add_node_attr_ref(attr_list); {will be used once} end; attr_list:=do_set_attribute(attr_list,i,v); goto continue; end; - if scan_keyword("dir") then begin + if scan_keyword('dir') then begin scan_direction; spec_direction:=cur_val; goto continue; end; end; if attr_list=attr_list_cache then begin add_node_attr_ref(attr_list); end; -if scan_keyword("to") then spec_code:=exactly +if scan_keyword('to') then spec_code:=exactly @.to@> -else if scan_keyword("spread") then spec_code:=additional +else if scan_keyword('spread') then spec_code:=additional @.spread@> else begin spec_code:=additional; cur_val:=0; goto found; @@ -20089,19 +18903,6 @@ location |adjust_tail|. @!last_leftmost_char: pointer; @!last_rightmost_char: pointer; -@ @d cal_margin_kern_var(#) == -begin - character(cp) := character(#); - font(cp) := font(#); - do_subst_font(cp, 1000); - if font(cp) <> font(#) then - margin_kern_stretch := margin_kern_stretch + left_pw(#) - left_pw(cp); - font(cp) := font(#); - do_subst_font(cp, -1000); - if font(cp) <> font(#) then - margin_kern_shrink := margin_kern_shrink + left_pw(cp) - left_pw(#); -end - @ @<Glob...@>= next_char_p:pointer; {pointer to the next char of an implicit kern} prev_char_p:pointer; {pointer to the previous char of an implicit kern} @@ -20122,9 +18923,6 @@ font expansion is being used. We define some constants used when calling @d substituted = 3 {|subtype| of kern nodes that should be substituted} -@d left_pw(#) == char_pw(#, left_side) -@d right_pw(#) == char_pw(#, right_side) - @p function char_stretch(p:halfword): scaled; var k: internal_font_number; dw: scaled; @@ -20234,7 +19032,7 @@ begin else begin {|short_display_n(p, 5);|} pdf_error("font expansion", "invalid node type"); - return; + return; end; f := font(r); ef := get_ef_code(f, character(r)); @@ -20365,7 +19163,7 @@ exit: if (m = cal_expand_ratio) and (font_expand_ratio <> 0) then begin font_expand_ratio := fix_int(font_expand_ratio, -1000, 1000); q := list_ptr(r); - list_ptr(r):=null; flush_node(r); + list_ptr(r):=null; flush_node(r); r:=hpack(q, w, subst_ex_font); end; while dir_ptr<>null do pop_dir_node; @@ -20374,7 +19172,6 @@ end; function filtered_hpack(@!p:pointer;@!qt:pointer;@!w:scaled;@!m:small_number;@!grp:integer):pointer; var q:pointer; - d:integer; { a direction } begin new_hyphenation(p,qt); call_func(new_ligkern(p,qt)); {don't care about the tail in this case} @@ -20398,14 +19195,14 @@ begin while is_char_node(p) do the hbox that will contain~it, then move to the next node@>; if p<>null then begin case type(p) of - hlist_node,vlist_node,rule_node,unset_node: + hlist_node_case,vlist_node_case,rule_node_case,unset_node_case: @<Incorporate box dimensions into the dimensions of the hbox that will contain~it@>; - ins_node,mark_node,adjust_node: begin if adjust_tail<>null then + ins_node_case,mark_node_case,adjust_node_case: begin if adjust_tail<>null then @<Transfer node |p| to the adjustment list@>; end; - whatsit_node:@<Incorporate a whatsit node into an hbox@>; - glue_node:@<Incorporate glue into the horizontal totals@>; - margin_kern_node: begin + whatsit_node_case:@<Incorporate a whatsit node into an hbox@>; + glue_node_case:@<Incorporate glue into the horizontal totals@>; + margin_kern_node_case: begin if m = cal_expand_ratio then begin f := font(margin_char(p)); do_subst_font(margin_char(p), 1000); @@ -20425,7 +19222,7 @@ if p<>null then end; x := x + width(p); end; - kern_node: begin + kern_node_case: begin if subtype(p) = normal then begin if m = cal_expand_ratio then begin font_stretch := font_stretch + kern_stretch(p); @@ -20446,8 +19243,8 @@ if p<>null then end; x := x + width(p); end; - math_node: x:=x+surround(p); - disc_node: + math_node_case: x:=x+surround(p); + disc_node_case: begin if m = subst_ex_font then do_subst_font(p, font_expand_ratio); if vlink(no_break(p))<>null then begin @@ -20476,7 +19273,7 @@ if (type(p)=hlist_node) or (type(p)=vlist_node) then begin if (width(p) div 2)-s>h then h:=(width(p) div 2)-s; if (width(p) div 2)+s>d then d:=(width(p) div 2)+s; end - else if (type(p)=hlist_node) and (is_mirrored(hpack_dir)) then begin + else if (type(p)=hlist_node) and is_mirrored(hpack_dir) then begin x:=x+width(p); s:=shift_amount(p); if depth(p)-s>h then h:=depth(p)-s; @@ -20778,12 +19575,12 @@ end; begin if is_char_node(p) then confusion("vpack") @:this can't happen vpack}{\quad vpack@> else case type(p) of - hlist_node,vlist_node,rule_node,unset_node: + hlist_node_case,vlist_node_case,rule_node_case,unset_node_case: @<Incorporate box dimensions into the dimensions of the vbox that will contain~it@>; - whatsit_node:@<Incorporate a whatsit node into a vbox@>; - glue_node: @<Incorporate glue into the vertical totals@>; - kern_node: begin x:=x+d+width(p); d:=0; + whatsit_node_case:@<Incorporate a whatsit node into a vbox@>; + glue_node_case: @<Incorporate glue into the vertical totals@>; + kern_node_case: begin x:=x+d+width(p); d:=0; end; othercases do_nothing endcases; @@ -20798,7 +19595,7 @@ if (type(p)=hlist_node) or (type(p)=vlist_node) then begin s:=shift_amount(p); if depth(p)+height(p)+s>w then w:=depth(p)+height(p)+s; end - else if (type(p)=hlist_node) and (is_mirrored(box_dir(p))) then begin + else if (type(p)=hlist_node) and is_mirrored(box_dir(p)) then begin x:=x+d+depth(p); d:=height(p); s:=shift_amount(p); if width(p)+s>w then w:=width(p)+s; @@ -20924,10 +19721,10 @@ baselineskip calculation is handled by the |append_to_vlist| routine. @p procedure append_to_vlist(@!b:pointer); var d:scaled; {deficiency of space between baselines} -@!p:pointer; {a new glue specification} -begin if prev_depth>ignore_depth then +@!p:pointer; {a new glue node} +begin if prev_depth>pdf_ignored_dimen then begin - if (type(b)=hlist_node) and (is_mirrored(box_dir(b))) then + if (type(b)=hlist_node) and is_mirrored(box_dir(b)) then d:=width(baseline_skip)-prev_depth-depth(b) else d:=width(baseline_skip)-prev_depth-height(b); @@ -20938,1757 +19735,23 @@ begin if prev_depth>ignore_depth then vlink(tail):=p; tail:=p; end; vlink(tail):=b; tail:=b; -if (type(b)=hlist_node) and (is_mirrored(box_dir(b))) then +if (type(b)=hlist_node) and is_mirrored(box_dir(b)) then prev_depth:=height(b) else prev_depth:=depth(b); end; @* \[34] Data structures for math mode. -When \TeX\ reads a formula that is enclosed between \.\$'s, it constructs an -{\sl mlist}, which is essentially a tree structure representing that -formula. An mlist is a linear sequence of items, but we can regard it as -a tree structure because mlists can appear within mlists. For example, many -of the entries can be subscripted or superscripted, and such ``scripts'' -are mlists in their own right. - -An entire formula is parsed into such a tree before any of the actual -typesetting is done, because the current style of type is usually not -known until the formula has been fully scanned. For example, when the -formula `\.{\$a+b \\over c+d\$}' is being read, there is no way to tell -that `\.{a+b}' will be in script size until `\.{\\over}' has appeared. - -During the scanning process, each element of the mlist being built is -classified as a relation, a binary operator, an open parenthesis, etc., -or as a construct like `\.{\\sqrt}' that must be built up. This classification -appears in the mlist data structure. - -After a formula has been fully scanned, the mlist is converted to an hlist -so that it can be incorporated into the surrounding text. This conversion is -controlled by a recursive procedure that decides all of the appropriate -styles by a ``top-down'' process starting at the outermost level and working -in towards the subformulas. The formula is ultimately pasted together using -combinations of horizontal and vertical boxes, with glue and penalty nodes -inserted as necessary. - -An mlist is represented internally as a linked list consisting chiefly -of ``noads'' (pronounced ``no-adds''), to distinguish them from the somewhat -similar ``nodes'' in hlists and vlists. Certain kinds of ordinary nodes are -allowed to appear in mlists together with the noads; \TeX\ tells the difference -by means of the |type| field, since a noad's |type| is always greater than -that of a node. An mlist does not contain character nodes, hlist nodes, vlist -nodes, math nodes or unset nodes; in particular, each mlist item appears in the -variable-size part of |mem|, so the |type| field is always present. - -@ Each noad is five or more words long. The first word contains the -|type| and |subtype| and |link| fields that are already so familiar to -us; the second contains the attribute list pointer, and the third, -fourth an fifth words are called the noad's |nucleus|, |subscr|, and -|supscr| fields. (This use of a combined attribute list is temporary. -Eventually, each of fields need their own list) - -Consider, for example, the simple formula `\.{\$x\^2\$}', which would be -parsed into an mlist containing a single element called an |ord_noad|. -The |nucleus| of this noad is a representation of `\.x', the |subscr| is -empty, and the |supscr| is a representation of `\.2'. - -The |nucleus|, |subscr|, and |supscr| fields are further broken into -subfields. If |p| points to a noad, and if |q| is one of its principal -fields (e.g., |q=subscr(p)|), there are several possibilities for the -subfields, depending on the |math_type| of |q|. - -\yskip\hang|math_type(q)=math_char| means that |fam(q)| refers to one of -the sixteen font families, and |character(q)| is the number of a character -within a font of that family, as in a character node. - -\yskip\hang|math_type(q)=math_text_char| is similar, but the character is -unsubscripted and unsuperscripted and it is followed immediately by another -character from the same font. (This |math_type| setting appears only -briefly during the processing; it is used to suppress unwanted italic -corrections.) - -\yskip\hang|math_type(q)=empty| indicates a field with no value (the -corresponding attribute of noad |p| is not present). - -\yskip\hang|math_type(q)=sub_box| means that |vinfo(q)| points to a box -node (either an |hlist_node| or a |vlist_node|) that should be used as the -value of the field. The |shift_amount| in the subsidiary box node is the -amount by which that box will be shifted downward. - -\yskip\hang|math_type(q)=sub_mlist| means that |vinfo(q)| points to -an mlist; the mlist must be converted to an hlist in order to obtain -the value of this field. - -\yskip\noindent In the latter case, we might have |vinfo(q)=null|. This -is not the same as |math_type(q)=empty|; for example, `\.{\$P\_\{\}\$}' -and `\.{\$P\$}' produce different results (the former will not have the -``italic correction'' added to the width of |P|, but the ``script skip'' -will be added). - -The definitions of subfields given here are a little wasteful of space, -since a quarterword is being used for the |math_type| although only three -bits would be needed. However, there are hardly ever many noads present at -once, since they are soon converted to nodes that take up even more space, -so we can afford to represent them in whatever way simplifies the -programming. - -I tried exchanging |mcharacter()| and |math_type()| so that a character -could use the full Unicode range, but for some reason that does not work -properly. TH - -@d noad_size=5 {number of words in a normal noad} -@d nucleus(#)==#+2 {the |nucleus| field of a noad} -@d supscr(#)==#+3 {the |supscr| field of a noad} -@d subscr(#)==#+4 {the |subscr| field of a noad} -@d math_type==vlink {a |quarterword| in |mem|} -@d fam(#)==type(#) {a |quarterword| in |mem|} -@d mcharacter(#)==subtype(#) -@d math_char=1 {|math_type| when the attribute is simple} -@d sub_box=2 {|math_type| when the attribute is a box} -@d sub_mlist=3 {|math_type| when the attribute is a formula} -@d math_text_char=4 {|math_type| when italic correction is dubious} - -@ Each portion of a formula is classified as Ord, Op, Bin, Rel, Ope, -Clo, Pun, or Inn, for purposes of spacing and line breaking. An -|ord_noad|, |op_noad|, |bin_noad|, |rel_noad|, |open_noad|, |close_noad|, -|punct_noad|, or |inner_noad| is used to represent portions of the various -types. For example, an `\.=' sign in a formula leads to the creation of a -|rel_noad| whose |nucleus| field is a representation of an equals sign -(usually |fam=0|, |character=@'75|). A formula preceded by \.{\\mathrel} -also results in a |rel_noad|. When a |rel_noad| is followed by an -|op_noad|, say, and possibly separated by one or more ordinary nodes (not -noads), \TeX\ will insert a penalty node (with the current |rel_penalty|) -just after the formula that corresponds to the |rel_noad|, unless there -already was a penalty immediately following; and a ``thick space'' will be -inserted just before the formula that corresponds to the |op_noad|. - -A noad of type |ord_noad|, |op_noad|, \dots, |inner_noad| usually -has a |subtype=normal|. The only exception is that an |op_noad| might -have |subtype=limits| or |no_limits|, if the normal positioning of -limits has been overridden for this operator. - -@d ord_noad=unset_node+3 {|type| of a noad classified Ord} -@d op_noad=ord_noad+1 {|type| of a noad classified Op} -@d bin_noad=ord_noad+2 {|type| of a noad classified Bin} -@d rel_noad=ord_noad+3 {|type| of a noad classified Rel} -@d open_noad=ord_noad+4 {|type| of a noad classified Ope} -@d close_noad=ord_noad+5 {|type| of a noad classified Clo} -@d punct_noad=ord_noad+6 {|type| of a noad classified Pun} -@d inner_noad=ord_noad+7 {|type| of a noad classified Inn} -@d limits=1 {|subtype| of |op_noad| whose scripts are to be above, below} -@d no_limits=2 {|subtype| of |op_noad| whose scripts are to be normal} - -@ A |radical_noad| is five words long; the fifth word is the |left_delimiter| -field, which usually represents a square root sign. - -A |fraction_noad| is six words long; it has a |right_delimiter| field -as well as a |left_delimiter|. - -Delimiter fields are of type |four_quarters|, and they have four subfields -called |small_fam|, |small_char|, |large_fam|, |large_char|. These subfields -represent variable-size delimiters by giving the ``small'' and ``large'' -starting characters, as explained in Chapter~17 of {\sl The \TeX book}. -@:TeXbook}{\sl The \TeX book@> - -A |fraction_noad| is actually quite different from all other noads. Not -only does it have six words, it has |thickness|, |denominator|, and -|numerator| fields instead of |nucleus|, |subscr|, and |supscr|. The -|thickness| is a scaled value that tells how thick to make a fraction -rule; however, the special value |default_code| is used to stand for the -|default_rule_thickness| of the current size. The |numerator| and -|denominator| point to mlists that define a fraction; we always have -$$\hbox{|math_type(numerator)=math_type(denominator)=sub_mlist|}.$$ The -|left_delimiter| and |right_delimiter| fields specify delimiters that will -be placed at the left and right of the fraction. In this way, a -|fraction_noad| is able to represent all of \TeX's operators \.{\\over}, -\.{\\atop}, \.{\\above}, \.{\\overwithdelims}, \.{\\atopwithdelims}, and - \.{\\abovewithdelims}. - -@d left_delimiter(#)==#+5 {first delimiter field of a noad} -@d right_delimiter(#)==#+6 {second delimiter field of a fraction noad} -@d radical_noad=inner_noad+1 {|type| of a noad for square roots} -@d radical_noad_size=6 {number of |mem| words in a radical noad} -@d fraction_noad=radical_noad+1 {|type| of a noad for generalized fractions} -@d fraction_noad_size=7 {number of |mem| words in a fraction noad} -@d small_fam(#)==vmem(#).qqqq.b0 {|fam| for ``small'' delimiter} -@d small_char(#)==vmem(#).qqqq.b1 {|character| for ``small'' delimiter} -@d large_fam(#)==vmem(#).qqqq.b2 {|fam| for ``large'' delimiter} -@d large_char(#)==vmem(#).qqqq.b3 {|character| for ``large'' delimiter} -@d thickness(#)==vmem(#+2).sc {|thickness| field in a fraction noad} -@d default_code==@'10000000000 {denotes |default_rule_thickness|} -@d numerator==supscr {|numerator| field in a fraction noad} -@d denominator==subscr {|denominator| field in a fraction noad} - -@ The global variable |empty_field| is set up for initialization of empty -fields in new noads. Similarly, |null_delimiter| is for the initialization -of delimiter fields. - -@<Glob...@>= -@!empty_field:two_halves; -@!null_delimiter:four_quarters; - -@ @<Set init...@>= -empty_field.rh:=empty; empty_field.lh:=null;@/ -null_delimiter.b0:=0; null_delimiter.b1:=min_quarterword;@/ -null_delimiter.b2:=0; null_delimiter.b3:=min_quarterword; - -@ The |new_noad| function creates an |ord_noad| that is completely null. - -@p function new_noad:pointer; -var p:pointer; -begin p:=new_node(ord_noad,normal); -vmem(nucleus(p)).hh:=empty_field; -vmem(subscr(p)).hh:=empty_field; -vmem(supscr(p)).hh:=empty_field; -new_noad:=p; -end; - -@ A few more kinds of noads will complete the set: An |under_noad| has its -nucleus underlined; an |over_noad| has it overlined. An |accent_noad| places -an accent over its nucleus; the accent character appears as -|fam(accent_chr(p))| and |mcharacter(accent_chr(p))|. A |vcenter_noad| -centers its nucleus vertically with respect to the axis of the formula; -in such noads we always have |math_type(nucleus(p))=sub_box|. - -And finally, we have |left_noad| and |right_noad| types, to implement -\TeX's \.{\\left} and \.{\\right} as well as \eTeX's \.{\\middle}. -The |nucleus| of such noads is -replaced by a |delimiter| field; thus, for example, `\.{\\left(}' produces -a |left_noad| such that |delimiter(p)| holds the family and character -codes for all left parentheses. A |left_noad| never appears in an mlist -except as the first element, and a |right_noad| never appears in an mlist -except as the last element; furthermore, we either have both a |left_noad| -and a |right_noad|, or neither one is present. The |subscr| and |supscr| -fields are always |empty| in a |left_noad| and a |right_noad|. - -@d under_noad=fraction_noad+1 {|type| of a noad for underlining} -@d over_noad=under_noad+1 {|type| of a noad for overlining} -@d accent_noad=over_noad+1 {|type| of a noad for accented subformulas} -@d accent_noad_size=6 {number of |mem| words in an accent noad} -@d accent_chr(#)==#+5 {the |accent_chr| field of an accent noad} -@d vcenter_noad=accent_noad+1 {|type| of a noad for \.{\\vcenter}} -@d left_noad=vcenter_noad+1 {|type| of a noad for \.{\\left}} -@d right_noad=left_noad+1 {|type| of a noad for \.{\\right}} -@d delimiter==nucleus {|delimiter| field in left and right noads} -@d middle_noad==1 {|subtype| of right noad representing \.{\\middle}} -@d scripts_allowed(#)==(type(#)>=ord_noad)and(type(#)<left_noad) - -@ Math formulas can also contain instructions like \.{\\textstyle} that -override \TeX's normal style rules. A |style_node| is inserted into the -data structure to record such instructions; it is three words long, so it -is considered a node instead of a noad. The |subtype| is either |display_style| -or |text_style| or |script_style| or |script_script_style|. The -second and third words of a |style_node| are not used, but they are -present because a |choice_node| is converted to a |style_node|. - -\TeX\ uses even numbers 0, 2, 4, 6 to encode the basic styles -|display_style|, \dots, |script_script_style|, and adds~1 to get the -``cramped'' versions of these styles. This gives a numerical order that -is backwards from the convention of Appendix~G in {\sl The \TeX book\/}; -i.e., a smaller style has a larger numerical value. -@:TeXbook}{\sl The \TeX book@> - -@d style_node=unset_node+1 {|type| of a style node} -@d style_node_size=4 {number of words in a style node} -@d display_style=0 {|subtype| for \.{\\displaystyle}} -@d text_style=2 {|subtype| for \.{\\textstyle}} -@d script_style=4 {|subtype| for \.{\\scriptstyle}} -@d script_script_style=6 {|subtype| for \.{\\scriptscriptstyle}} -@d cramped=1 {add this to an uncramped style if you want to cramp it} - -@p function new_style(@!s:small_number):pointer; {create a style node} -var p:pointer; {the new node} -begin p:=new_node(style_node,s); -new_style:=p; -end; - -@ Finally, the \.{\\mathchoice} primitive creates a |choice_node|, which -has special subfields |display_mlist|, |text_mlist|, |script_mlist|, -and |script_script_mlist| pointing to the mlists for each style. - -@d choice_node=unset_node+2 {|type| of a choice node} -@d display_mlist(#)==vinfo(#+2) {mlist to be used in display style} -@d text_mlist(#)==vlink(#+2) {mlist to be used in text style} -@d script_mlist(#)==vinfo(#+3) {mlist to be used in script style} -@d script_script_mlist(#)==vlink(#+3) {mlist to be used in scriptscript style} -@p function new_choice:pointer; {create a choice node} -var p:pointer; {the new node} -begin p:=new_node(choice_node,0); {the |subtype| is not used} -new_choice:=p; -end; - -@ Let's consider now the previously unwritten part of |show_node_list| -that displays the things that can only be present in mlists; this -program illustrates how to access the data structures just defined. - -In the context of the following program, |p| points to a node or noad that -should be displayed, and the current string contains the ``recursion history'' -that leads to this point. The recursion history consists of a dot for each -outer level in which |p| is subsidiary to some node, or in which |p| is -subsidiary to the |nucleus| field of some noad; the dot is replaced by -`\.\_' or `\.\^' or `\./' or `\.\\' if |p| is descended from the |subscr| -or |supscr| or |denominator| or |numerator| fields of noads. For example, -the current string would be `\.{.\^.\_/}' if |p| points to the |ord_noad| for -|x| in the (ridiculous) formula -`\.{\$\\sqrt\{a\^\{\\mathinner\{b\_\{c\\over x+y\}\}\}\}\$}'. - -@<Cases of |show_node_list| that arise...@>= -style_node:print_style(subtype(p)); -choice_node:@<Display choice node |p|@>; -ord_noad,op_noad,bin_noad,rel_noad,open_noad,close_noad,punct_noad,inner_noad, - radical_noad,over_noad,under_noad,vcenter_noad,accent_noad, - left_noad,right_noad:@<Display normal noad |p|@>; -fraction_noad:@<Display fraction noad |p|@>; - -@ Here are some simple routines used in the display of noads. - -@<Declare procedures needed for displaying the elements of mlists@>= -procedure print_fam_and_char(@!p:pointer); {prints family and character} -begin print_esc("fam"); print_int(fam(p)); print_char(" "); -print(qo(mcharacter(p))); -end; -@# -procedure print_delimiter(@!p:pointer); {prints a delimiter as 24-bit hex value} -{TH: FIX to do: print 48-bit integer where needed!} -var a:integer; {accumulator} -begin a:=small_fam(p)*256+qo(small_char(p)); -a:=a*@"1000+large_fam(p)*256+qo(large_char(p)); -if a<0 then print_int(a) {this should never happen} -else print_hex(a); -end; - -@ The next subroutine will descend to another level of recursion when a -subsidiary mlist needs to be displayed. The parameter |c| indicates what -character is to become part of the recursion history. An empty mlist is -distinguished from a field with |math_type(p)=empty|, because these are -not equivalent (as explained above). -@^recursion@> - -@<Declare procedures needed for displaying...@>= -procedure@?show_info; forward;@t\2@>@?{|show_node_list(vinfo(temp_ptr))|} -procedure print_subsidiary_data(@!p:pointer;@!c:ASCII_code); - {display a noad field} -begin if cur_length>=depth_threshold then - begin if math_type(p)<>empty then print(" []"); - end -else begin append_char(c); {include |c| in the recursion history} - temp_ptr:=p; {prepare for |show_info| if recursion is needed} - case math_type(p) of - math_char: begin print_ln; print_current_string; print_fam_and_char(p); - end; - sub_box: show_info; {recursive call} - sub_mlist: if vinfo(p)=null then - begin print_ln; print_current_string; print("{}"); - end - else show_info; {recursive call} - othercases do_nothing {|empty|} - endcases;@/ - flush_char; {remove |c| from the recursion history} - end; -end; - -@ The inelegant introduction of |show_info| in the code above seems better -than the alternative of using \PASCAL's strange |forward| declaration for a -procedure with parameters. The \PASCAL\ convention about dropping parameters -from a post-|forward| procedure is, frankly, so intolerable to the author -of \TeX\ that he would rather stoop to communication via a global temporary -variable. (A similar stoopidity occurred with respect to |hlist_out| and -|vlist_out| above, and it will occur with respect to |mlist_to_hlist| below.) -@^Knuth, Donald Ervin@> -@:PASCAL}{\PASCAL@> - -@p procedure show_info; {the reader will kindly forgive this} -begin show_node_list(vinfo(temp_ptr)); -end; - -@ @<Declare procedures needed for displaying...@>= -procedure print_style(@!c:integer); -begin case c div 2 of -0: print_esc("displaystyle"); {|display_style=0|} -1: print_esc("textstyle"); {|text_style=2|} -2: print_esc("scriptstyle"); {|script_style=4|} -3: print_esc("scriptscriptstyle"); {|script_script_style=6|} -othercases print("Unknown style!") -endcases; -end; - -@ @<Display choice node |p|@>= -begin print_esc("mathchoice"); -append_char("D"); show_node_list(display_mlist(p)); flush_char; -append_char("T"); show_node_list(text_mlist(p)); flush_char; -append_char("S"); show_node_list(script_mlist(p)); flush_char; -append_char("s"); show_node_list(script_script_mlist(p)); flush_char; -end - -@ @<Display normal noad |p|@>= -begin case type(p) of -ord_noad: print_esc("mathord"); -op_noad: print_esc("mathop"); -bin_noad: print_esc("mathbin"); -rel_noad: print_esc("mathrel"); -open_noad: print_esc("mathopen"); -close_noad: print_esc("mathclose"); -punct_noad: print_esc("mathpunct"); -inner_noad: print_esc("mathinner"); -over_noad: print_esc("overline"); -under_noad: print_esc("underline"); -vcenter_noad: print_esc("vcenter"); -radical_noad: begin - {TH: TODO print oradical where needed and fix otherwise} - print_esc("radical"); print_delimiter(left_delimiter(p)); - end; -accent_noad: begin print_esc("accent"); print_fam_and_char(accent_chr(p)); - end; -left_noad: begin print_esc("left"); print_delimiter(nucleus(p)); - end; -right_noad: begin if subtype(p)=normal then print_esc("right") - else print_esc("middle"); - print_delimiter(nucleus(p)); - end; -end; -if type(p)<left_noad then - begin if subtype(p)<>normal then - if subtype(p)=limits then print_esc("limits") - else print_esc("nolimits"); - print_subsidiary_data(nucleus(p),"."); - end; -print_subsidiary_data(supscr(p),"^"); -print_subsidiary_data(subscr(p),"_"); -end - -@ @<Display fraction noad |p|@>= -begin print_esc("fraction, thickness "); -if thickness(p)=default_code then print("= default") -else print_scaled(thickness(p)); -if (small_fam(left_delimiter(p))<>0)or@+ - (small_char(left_delimiter(p))<>min_quarterword)or@| - (large_fam(left_delimiter(p))<>0)or@| - (large_char(left_delimiter(p))<>min_quarterword) then - begin print(", left-delimiter "); print_delimiter(left_delimiter(p)); - end; -if (small_fam(right_delimiter(p))<>0)or@| - (small_char(right_delimiter(p))<>min_quarterword)or@| - (large_fam(right_delimiter(p))<>0)or@| - (large_char(right_delimiter(p))<>min_quarterword) then - begin print(", right-delimiter "); print_delimiter(right_delimiter(p)); - end; -print_subsidiary_data(numerator(p),"\"); -print_subsidiary_data(denominator(p),"/"); -end +Is done in C. @* \[35] Subroutines for math mode. -In order to convert mlists to hlists, i.e., noads to nodes, we need several -subroutines that are conveniently dealt with now. - -Let us first introduce the macros that make it easy to get at the parameters and -other font information. A size code, which is a multiple of 16, is added to a -family number to get an index into the table of internal font numbers -for each combination of family and size. (Be alert: Size codes get -larger as the type gets smaller.) - -@<Basic printing procedures@>= -procedure print_size(@!s:integer); -begin if s=0 then print_esc("textfont") -else if s=script_size then print_esc("scriptfont") -else print_esc("scriptscriptfont"); -end; - -@ Before an mlist is converted to an hlist, \TeX\ makes sure that -the fonts in family~2 have enough parameters to be math-symbol -fonts, and that the fonts in family~3 have enough parameters to be -math-extension fonts. The math-symbol parameters are referred to by using the -following macros, which take a size code as their parameter; for example, -|num1(cur_size)| gives the value of the |num1| parameter for the current size. -@^parameters for symbols@> -@^font parameters@> - -@d mathsy_end(#)== -@d mathsy(#)==font_param(fam_fnt(2+cur_size),#) mathsy_end -@d math_x_height==mathsy(5) {height of `\.x'} -@d math_quad==mathsy(6) {\.{18mu}} -@d num1==mathsy(8) {numerator shift-up in display styles} -@d num2==mathsy(9) {numerator shift-up in non-display, non-\.{\\atop}} -@d num3==mathsy(10) {numerator shift-up in non-display \.{\\atop}} -@d denom1==mathsy(11) {denominator shift-down in display styles} -@d denom2==mathsy(12) {denominator shift-down in non-display styles} -@d sup1==mathsy(13) {superscript shift-up in uncramped display style} -@d sup2==mathsy(14) {superscript shift-up in uncramped non-display} -@d sup3==mathsy(15) {superscript shift-up in cramped styles} -@d sub1==mathsy(16) {subscript shift-down if superscript is absent} -@d sub2==mathsy(17) {subscript shift-down if superscript is present} -@d sup_drop==mathsy(18) {superscript baseline below top of large box} -@d sub_drop==mathsy(19) {subscript baseline below bottom of large box} -@d delim1==mathsy(20) {size of \.{\\atopwithdelims} delimiters - in display styles} -@d delim2==mathsy(21) {size of \.{\\atopwithdelims} delimiters in non-displays} -@d axis_height==mathsy(22) {height of fraction lines above the baseline} -@d total_mathsy_params=22 - -@ The math-extension parameters have similar macros, but the size code is -omitted (since it is always |cur_size| when we refer to such parameters). -@^parameters for symbols@> -@^font parameters@> - -@d mathex(#)==font_param(fam_fnt(3+cur_size),#) -@d default_rule_thickness==mathex(8) {thickness of \.{\\over} bars} -@d big_op_spacing1==mathex(9) {minimum clearance above a displayed op} -@d big_op_spacing2==mathex(10) {minimum clearance below a displayed op} -@d big_op_spacing3==mathex(11) {minimum baselineskip above displayed op} -@d big_op_spacing4==mathex(12) {minimum baselineskip below displayed op} -@d big_op_spacing5==mathex(13) {padding above and below displayed limits} -@d total_mathex_params=13 - -@ We also need to compute the change in style between mlists and their -subsidiaries. The following macros define the subsidiary style for -an overlined nucleus (|cramped_style|), for a subscript or a superscript -(|sub_style| or |sup_style|), or for a numerator or denominator (|num_style| -or |denom_style|). - -@d cramped_style(#)==2*(# div 2)+cramped {cramp the style} -@d sub_style(#)==2*(# div 4)+script_style+cramped {smaller and cramped} -@d sup_style(#)==2*(# div 4)+script_style+(# mod 2) {smaller} -@d num_style(#)==#+2-2*(# div 6) {smaller unless already script-script} -@d denom_style(#)==2*(# div 2)+cramped+2-2*(# div 6) {smaller, cramped} - -@ When the style changes, the following piece of program computes associated -information: - -@<Set up the values of |cur_size| and |cur_mu|, based on |cur_style|@>= -begin if cur_style<script_style then cur_size:=text_size -else cur_size:=script_size*((cur_style-text_style) div 2); -cur_mu:=x_over_n(math_quad(cur_size),18); -end - -@ Here is a function that returns a pointer to a rule node having a given -thickness |t|. The rule will extend horizontally to the boundary of the vlist -that eventually contains it. - -@p function fraction_rule(@!t:scaled):pointer; - {construct the bar for a fraction} -var p:pointer; {the new node} -begin p:=new_rule; rule_dir(p):=math_direction; -height(p):=t; depth(p):=0; fraction_rule:=p; -end; - -@ The |overbar| function returns a pointer to a vlist box that consists of -a given box |b|, above which has been placed a kern of height |k| under a -fraction rule of thickness |t| under additional space of height |t|. - -@p function overbar(@!b:pointer;@!k,@!t:scaled):pointer; -var p,@!q:pointer; {nodes being constructed} -begin p:=new_kern(k); vlink(p):=b; q:=fraction_rule(t); vlink(q):=p; -p:=new_kern(t); vlink(p):=q; -pack_direction:=math_direction; overbar:=vpack(p,natural); -end; - -@ The |var_delimiter| function, which finds or constructs a sufficiently -large delimiter, is the most interesting of the auxiliary functions that -currently concern us. Given a pointer |d| to a delimiter field in some noad, -together with a size code |s| and a vertical distance |v|, this function -returns a pointer to a box that contains the smallest variant of |d| whose -height plus depth is |v| or more. (And if no variant is large enough, it -returns the largest available variant.) In particular, this routine will -construct arbitrarily large delimiters from extensible components, if -|d| leads to such characters. - -The value returned is a box whose |shift_amount| has been set so that -the box is vertically centered with respect to the axis in the given size. -If a built-up symbol is returned, the height of the box before shifting -will be the height of its topmost component. - -@p@t\4@>@<Declare subprocedures for |var_delimiter|@> -function var_delimiter(@!d:pointer;@!s:integer;@!v:scaled):pointer; -label found,continue; -var b:pointer; {the box that will be constructed} -@!f,@!g: internal_font_number; {best-so-far and tentative font codes} -@!c,@!x,@!y: integer; {best-so-far and tentative character codes} -@!cc: integer; { a temporary character code for extensibles } -@!m,@!n: integer; {the number of extensible pieces} -@!u: scaled; {height-plus-depth of a tentative character} -@!w: scaled; {largest height-plus-depth so far} -@!z: integer; {runs through font family members} -@!large_attempt: boolean; {are we trying the ``large'' variant?} -begin f:=null_font; c:=0; w:=0; large_attempt:=false; -z:=small_fam(d); x:=small_char(d); -loop@+ begin @<Look at the variants of |(z,x)|; set |f| and |c| whenever - a better character is found; |goto found| as soon as a - large enough variant is encountered@>; - if large_attempt then goto found; {there were none large enough} - large_attempt:=true; z:=large_fam(d); x:=large_char(d); - end; -found: if f<>null_font then - @<Make variable |b| point to a box for |(f,c)|@> -else begin b:=new_null_box; - width(b):=null_delimiter_space; {use this width if no delimiter was found} - end; -z:=cur_size; cur_size:=s; -shift_amount(b):=half(height(b)-depth(b)) - axis_height(cur_size); -cur_size:=z; -var_delimiter:=b; -end; - -@ The search process is complicated slightly by the facts that some of the -characters might not be present in some of the fonts, and they might not -be probed in increasing order of height. - -@<Look at the variants of |(z,x)|; set |f| and |c|...@>= -if (z<>0)or(x<>min_quarterword) then - begin z:=z+s+script_size; - repeat z:=z-script_size; g:=fam_fnt(z); - if g<>null_font then - @<Look at the list of characters starting with |x| in - font |g|; set |f| and |c| whenever - a better character is found; |goto found| as soon as a - large enough variant is encountered@>; - until z<script_size; - end - -@ @<Look at the list of characters starting with |x|...@>= -begin y:=x; -if (y>=font_bc(g))and(y<=font_ec(g)) then - begin continue: - if char_exists(g,y) then - begin if char_tag(g,y)=ext_tag then - begin f:=g; c:=y; goto found; - end; - u:=char_height(g,y)+char_depth(g,y); - if u>w then - begin f:=g; c:=y; w:=u; - if u>=v then goto found; - end; - if char_tag(g,y)=list_tag then - begin y:=char_remainder(g,y); goto continue; - end; - end; - end; -end - -@ Here is a subroutine that creates a new box, whose list contains a -single character, and whose width includes the italic correction for -that character. The height or depth of the box will be negative, if -the height or depth of the character is negative; thus, this routine -may deliver a slightly different result than |hpack| would produce. - -@<Declare subprocedures for |var_delimiter|@>= -function char_box(@!f:internal_font_number;@!c:quarterword):pointer; -var @!b,@!p:pointer; {the new box and its character node} -begin -b:=new_null_box; ci:=char_info_short(f,c); -width(b):=charinfo_width(ci)+char_italic(f,c); -height(b):=charinfo_height(ci); depth(b):=charinfo_depth(ci); -p:=new_char(f,c); list_ptr(b):=p; char_box:=b; -end; - -@ When the following code is executed, |char_tag(q)| will be equal to -|ext_tag| if and only if a built-up symbol is supposed to be returned. - -@<Make variable |b| point to a box for |(f,c)|@>= -if char_tag(f,c)=ext_tag then - @<Construct an extensible character in a new box |b|, - using recipe |rem_byte(q)| and font |f|@> -else b:=char_box(f,c) - -@ When we build an extensible character, it's handy to have the -following subroutine, which puts a given character on top -of the characters already in box |b|: - -@<Declare subprocedures for |var_delimiter|@>= -procedure stack_into_box(@!b:pointer;@!f:internal_font_number; - @!c:quarterword); -var p:pointer; {new node placed into |b|} -begin p:=char_box(f,c); vlink(p):=list_ptr(b); list_ptr(b):=p; -height(b):=height(p); -end; - -@ Another handy subroutine computes the height plus depth of -a given character: - -@<Declare subprocedures for |var_delimiter|@>= -function height_plus_depth(@!f:internal_font_number;@!c:quarterword):scaled; -begin -height_plus_depth:=char_height(f,c)+char_depth(f,c); -end; - -@ @<Construct an extensible...@>= -begin b:=new_null_box; -type(b):=vlist_node; -@<Compute the minimum suitable height, |w|, and the corresponding - number of extension steps, |n|; also set |width(b)|@>; -cc:=ext_bot(f,c); -if cc<>min_quarterword then stack_into_box(b,f,cc); -cc:=ext_rep(f,c); -for m:=1 to n do stack_into_box(b,f,cc); -cc:=ext_mid(f,c); -if cc<>min_quarterword then - begin stack_into_box(b,f,cc); cc:=ext_rep(f,c); - for m:=1 to n do stack_into_box(b,f,cc); - end; -cc:=ext_top(f,c); -if cc<>min_quarterword then stack_into_box(b,f,cc); -depth(b):=w-height(b); -end - -@ The width of an extensible character is the width of the repeatable -module. If this module does not have positive height plus depth, -we don't use any copies of it, otherwise we use as few as possible -(in groups of two if there is a middle part). - -@<Compute the minimum suitable height, |w|, and...@>= -cc:=ext_rep(f,c); u:=height_plus_depth(f,cc); -w:=0; width(b):=char_width(f,cc)+char_italic(f,cc);@/ -cc:=ext_bot(f,c);@+if cc<>min_quarterword then w:=w+height_plus_depth(f,cc); -cc:=ext_mid(f,c);@+if cc<>min_quarterword then w:=w+height_plus_depth(f,cc); -cc:=ext_top(f,c);@+if cc<>min_quarterword then w:=w+height_plus_depth(f,cc); -n:=0; -if u>0 then while w<v do - begin w:=w+u; incr(n); - if (ext_mid(f,c))<>min_quarterword then w:=w+u; - end - -@ The next subroutine is much simpler; it is used for numerators and -denominators of fractions as well as for displayed operators and -their limits above and below. It takes a given box~|b| and -changes it so that the new box is centered in a box of width~|w|. -The centering is done by putting \.{\\hss} glue at the left and right -of the list inside |b|, then packaging the new box; thus, the -actual box might not really be centered, if it already contains -infinite glue. - -The given box might contain a single character whose italic correction -has been added to the width of the box; in this case a compensating -kern is inserted. - -@p function rebox(@!b:pointer;@!w:scaled):pointer; -var p,q:pointer; {temporary registers for list manipulation} -@!f:internal_font_number; {font in a one-character box} -@!v:scaled; {width of a character without italic correction} -begin if (width(b)<>w)and(list_ptr(b)<>null) then - begin if type(b)=vlist_node then b:=hpack(b,natural); - p:=list_ptr(b); - if (is_char_node(p))and(vlink(p)=null) then - begin f:=font(p); v:=char_width(f,character(p)); - if v<>width(b) then begin - q:=new_kern(width(b)-v); vlink(p):=q; - end; - end; - list_ptr(b):=null; flush_node(b); - b:=new_glue(ss_glue); vlink(b):=p; - while vlink(p)<>null do p:=vlink(p); - q:=new_glue(ss_glue); vlink(p):=q; - rebox:=hpack(b,w,exactly); - end -else begin width(b):=w; rebox:=b; - end; -end; - -@ Here is a subroutine that creates a new glue specification from another -one that is expressed in `\.{mu}', given the value of the math unit. - -@d mu_mult(#)==nx_plus_y(n,#,xn_over_d(#,f,@'200000)) - -@p function math_glue(@!g:pointer;@!m:scaled):pointer; -var p:pointer; {the new glue specification} -@!n:integer; {integer part of |m|} -@!f:scaled; {fraction part of |m|} -begin n:=x_over_n(m,@'200000); f:=remainder;@/ -if f<0 then - begin decr(n); f:=f+@'200000; - end; -p:=new_node(glue_spec_node,0); -width(p):=mu_mult(width(g)); {convert \.{mu} to \.{pt}} -stretch_order(p):=stretch_order(g); -if stretch_order(p)=normal then stretch(p):=mu_mult(stretch(g)) -else stretch(p):=stretch(g); -shrink_order(p):=shrink_order(g); -if shrink_order(p)=normal then shrink(p):=mu_mult(shrink(g)) -else shrink(p):=shrink(g); -math_glue:=p; -end; - -@ The |math_kern| subroutine removes |mu_glue| from a kern node, given -the value of the math unit. - -@p procedure math_kern(@!p:pointer;@!m:scaled); -var @!n:integer; {integer part of |m|} -@!f:scaled; {fraction part of |m|} -begin if subtype(p)=mu_glue then - begin n:=x_over_n(m,@'200000); f:=remainder;@/ - if f<0 then - begin decr(n); f:=f+@'200000; - end; - width(p):=mu_mult(width(p)); subtype(p):=explicit; - end; -end; -@ Sometimes it is necessary to destroy an mlist. The following -subroutine empties the current list, assuming that |abs(mode)=mmode|. - -@p procedure flush_math; -begin flush_node_list(vlink(head)); flush_node_list(incompleat_noad); -vlink(head):=null; tail:=head; incompleat_noad:=null; -end; +Is one in C. @* \[36] Typesetting math formulas. -\TeX's most important routine for dealing with formulas is called -|mlist_to_hlist|. After a formula has been scanned and represented as an -mlist, this routine converts it to an hlist that can be placed into a box -or incorporated into the text of a paragraph. There are three implicit -parameters, passed in global variables: |cur_mlist| points to the first -node or noad in the given mlist (and it might be |null|); |cur_style| is a -style code; and |mlist_penalties| is |true| if penalty nodes for potential -line breaks are to be inserted into the resulting hlist. After -|mlist_to_hlist| has acted, |vlink(temp_head)| points to the translated hlist. - -Since mlists can be inside mlists, the procedure is recursive. And since this -is not part of \TeX's inner loop, the program has been written in a manner -that stresses compactness over efficiency. -@^recursion@> - -@<Glob...@>= -@!cur_mlist:pointer; {beginning of mlist to be translated} -@!cur_style:integer; {style code at current place in the list} -@!cur_size:integer; {size code corresponding to |cur_style|} -@!cur_mu:scaled; {the math unit width corresponding to |cur_size|} -@!mlist_penalties:boolean; {should |mlist_to_hlist| insert penalties?} - -@ The recursion in |mlist_to_hlist| is due primarily to a subroutine -called |clean_box| that puts a given noad field into a box using a given -math style; |mlist_to_hlist| can call |clean_box|, which can call -|mlist_to_hlist|. -@^recursion@> - -The box returned by |clean_box| is ``clean'' in the -sense that its |shift_amount| is zero. - -@p procedure@?mlist_to_hlist; forward;@t\2@>@/ -function clean_box(@!p:pointer;@!s:integer):pointer; -label found; -var q:pointer; {beginning of a list to be boxed} -@!save_style:integer; {|cur_style| to be restored} -@!x:pointer; {box to be returned} -@!r:pointer; {temporary pointer} -begin -case math_type(p) of -math_char: begin cur_mlist:=new_noad; vmem(nucleus(cur_mlist)):=vmem(p); - end; -sub_box: begin q:=vinfo(p); goto found; - end; -sub_mlist: cur_mlist:=vinfo(p); -othercases begin q:=new_null_box; goto found; - end -endcases;@/ -save_style:=cur_style; cur_style:=s; mlist_penalties:=false;@/ -mlist_to_hlist; q:=vlink(temp_head); {recursive call} -cur_style:=save_style; {restore the style} -@<Set up the values of |cur_size| and |cur_mu|, based on |cur_style|@>; -found: if is_char_node(q)or(q=null) then x:=hpack(q,natural) - else if (vlink(q)=null)and(type(q)<=vlist_node)and(shift_amount(q)=0) then - x:=q {it's already clean} - else x:=hpack(q,natural); -@<Simplify a trivial box@>; -clean_box:=x; -end; - -@ Here we save memory space in a common case. - -@<Simplify a trivial box@>= -q:=list_ptr(x); -if is_char_node(q) then - begin r:=vlink(q); - if r<>null then if vlink(r)=null then if not is_char_node(r) then - if type(r)=kern_node then {unneeded italic correction} - begin flush_node(r); vlink(q):=null; - end; - end - -@ It is convenient to have a procedure that converts a |math_char| -field to an ``unpacked'' form. The |fetch| routine sets |cur_f| and |cur_c| -to the font code and character code of a given noad field. -It also takes care of issuing error messages for -nonexistent characters; in such cases, |char_exists(cur_f,cur_c)| will be |false| -after |fetch| has acted, and the field will also have been reset to |empty|. - -@p procedure fetch(@!a:pointer); {unpack the |math_char| field |a|} -begin cur_c:=mcharacter(a); cur_f:=fam_fnt(fam(a)+cur_size); -if cur_f=null_font then - @<Complain about an undefined family@> -else begin - if not(char_exists(cur_f,cur_c)) then - begin char_warning(cur_f,qo(cur_c)); - math_type(a):=empty; - end; - end; -end; - -@ @<Complain about an undefined family@>= -begin print_err(""); print_size(cur_size); print_char(" "); -print_int(fam(a)); print(" is undefined (character "); -print(qo(cur_c)); print_char(")"); -help4("Somewhere in the math formula just ended, you used the")@/ -("stated character from an undefined font family. For example,")@/ -("plain TeX doesn't allow \it or \sl in subscripts. Proceed,")@/ -("and I'll try to forget that I needed that character."); -error; math_type(a):=empty; -end - -@ The outputs of |fetch| are placed in global variables. - -@<Glob...@>= -@!cur_f:internal_font_number; {the |font| field of a |math_char|} -@!cur_c:quarterword; {the |character| field of a |math_char|} - -@ We need to do a lot of different things, so |mlist_to_hlist| makes two -passes over the given mlist. - -The first pass does most of the processing: It removes ``mu'' spacing from -glue, it recursively evaluates all subsidiary mlists so that only the -top-level mlist remains to be handled, it puts fractions and square roots -and such things into boxes, it attaches subscripts and superscripts, and -it computes the overall height and depth of the top-level mlist so that -the size of delimiters for a |left_noad| and a |right_noad| will be known. -The hlist resulting from each noad is recorded in that noad's |new_hlist| -field, an integer field that replaces the |nucleus| or |thickness|. -@^recursion@> - -The second pass eliminates all noads and inserts the correct glue and -penalties between nodes. - -@d new_hlist(#)==vmem(nucleus(#)).int {the translation of an mlist} - -@ Here is the overall plan of |mlist_to_hlist|, and the list of its -local variables. - -@d done_with_noad=80 {go here when a noad has been fully translated} -@d done_with_node=81 {go here when a node has been fully converted} -@d check_dimensions=82 {go here to update |max_h| and |max_d|} -@d delete_q=83 {go here to delete |q| and move to the next node} - -@p@t\4@>@<Declare math construction procedures@> -procedure mlist_to_hlist; -label reswitch, check_dimensions, done_with_noad, done_with_node, delete_q, - done; -var mlist:pointer; {beginning of the given list} -@!penalties:boolean; {should penalty nodes be inserted?} -@!style:integer; {the given style} -@!save_style:integer; {holds |cur_style| during recursion} -@!q:pointer; {runs through the mlist} -@!r:pointer; {the most recent noad preceding |q|} -@!r_type:integer; {the |type| of noad |r|, or |op_noad| if |r=null|} -@!t:integer; {the effective |type| of noad |q| during the second pass} -@!p,@!x,@!y,@!z: pointer; {temporary registers for list construction} -@!pen:integer; {a penalty to be inserted} -@!s:integer; {the size of a noad to be deleted} -@!max_hl,@!max_d:scaled; {maximum height and depth of the list translated so far} -@!delta:scaled; {offset between subscript and superscript} -begin mlist:=cur_mlist; penalties:=mlist_penalties; -style:=cur_style; {tuck global parameters away as local variables} -q:=mlist; r:=null; r_type:=op_noad; max_hl:=0; max_d:=0; x:=null; p:=null; -@<Set up the values of |cur_size| and |cur_mu|, based on |cur_style|@>; -while q<>null do @<Process node-or-noad |q| as much as possible in preparation - for the second pass of |mlist_to_hlist|, then move to the next - item in the mlist@>; -@<Convert \(a)a final |bin_noad| to an |ord_noad|@>; -@<Make a second pass over the mlist, removing all noads and inserting the - proper spacing and penalties@>; -end; - -@ We use the fact that no character nodes appear in an mlist, hence -the field |type(q)| is always present. - -@<Process node-or-noad...@>= -begin @<Do first-pass processing based on |type(q)|; |goto done_with_noad| - if a noad has been fully processed, |goto check_dimensions| if it - has been translated into |new_hlist(q)|, or |goto done_with_node| - if a node has been fully processed@>; -check_dimensions: z:=hpack(new_hlist(q),natural); -if height(z)>max_hl then max_hl:=height(z); -if depth(z)>max_d then max_d:=depth(z); -list_ptr(z):=null; flush_node(z); -done_with_noad: r:=q; r_type:=type(r); -if r_type=right_noad then - begin r_type:=left_noad; cur_style:=style; @<Set up the values...@>; - end; -done_with_node: q:=vlink(q); -end - -@ One of the things we must do on the first pass is change a |bin_noad| to -an |ord_noad| if the |bin_noad| is not in the context of a binary operator. -The values of |r| and |r_type| make this fairly easy. - -@<Do first-pass processing...@>= -reswitch: delta:=0; -case type(q) of -bin_noad: case r_type of - bin_noad,op_noad,rel_noad,open_noad,punct_noad,left_noad: - begin type(q):=ord_noad; goto reswitch; - end; - othercases do_nothing - endcases; -rel_noad,close_noad,punct_noad,right_noad: begin@t@>@;@/ - @<Convert \(a)a final |bin_noad| to an |ord_noad|@>; - if type(q)=right_noad then goto done_with_noad; - end; -@t\4@>@<Cases for noads that can follow a |bin_noad|@>@; -@t\4@>@<Cases for nodes that can appear in an mlist, after which we - |goto done_with_node|@>@; -othercases confusion("mlist1") -@:this can't happen mlist1}{\quad mlist1@> -endcases;@/ -@<Convert \(n)|nucleus(q)| to an hlist and attach the sub/superscripts@> - -@ @<Convert \(a)a final |bin_noad| to an |ord_noad|@>= -if r_type=bin_noad then type(r):=ord_noad - -@ @<Cases for nodes that can appear in an mlist...@>= -style_node: begin cur_style:=subtype(q); - @<Set up the values of |cur_size| and |cur_mu|, based on |cur_style|@>; - goto done_with_node; - end; -choice_node: @<Change this node to a style node followed by the correct choice, - then |goto done_with_node|@>; -ins_node,mark_node,adjust_node, - whatsit_node,penalty_node,disc_node: goto done_with_node; -rule_node: begin if height(q)>max_hl then max_hl:=height(q); - if depth(q)>max_d then max_d:=depth(q); goto done_with_node; - end; -glue_node: begin @<Convert \(m)math glue to ordinary glue@>; - goto done_with_node; - end; -kern_node: begin math_kern(q,cur_mu); goto done_with_node; - end; - -@ @d choose_mlist(#)==begin p:=#(q); #(q):=null;@+end - -@<Change this node to a style node...@>= -begin case cur_style div 2 of -0: choose_mlist(display_mlist); {|display_style=0|} -1: choose_mlist(text_mlist); {|text_style=2|} -2: choose_mlist(script_mlist); {|script_style=4|} -3: choose_mlist(script_script_mlist); {|script_script_style=6|} -end; {there are no other cases} -flush_node_list(display_mlist(q)); -flush_node_list(text_mlist(q)); -flush_node_list(script_mlist(q)); -flush_node_list(script_script_mlist(q));@/ -type(q):=style_node; subtype(q):=cur_style; width(q):=0; depth(q):=0; -if p<>null then - begin z:=vlink(q); vlink(q):=p; - while vlink(p)<>null do p:=vlink(p); - vlink(p):=z; - end; -goto done_with_node; -end - -@ Conditional math glue (`\.{\\nonscript}') results in a |glue_node| -pointing to |zero_glue|, with |subtype(q)=cond_math_glue|; in such a case -the node following will be eliminated if it is a glue or kern node and if the -current size is different from |text_size|. Unconditional math glue -(`\.{\\muskip}') is converted to normal glue by multiplying the dimensions -by |cur_mu|. -@!@:non_script_}{\.{\\nonscript} primitive@> - -@<Convert \(m)math glue to ordinary glue@>= -if subtype(q)=mu_glue then - begin x:=glue_ptr(q); - y:=math_glue(x,cur_mu); delete_glue_ref(x); glue_ptr(q):=y; - subtype(q):=normal; - end -else if (cur_size<>text_size)and(subtype(q)=cond_math_glue) then - begin p:=vlink(q); - if p<>null then if (type(p)=glue_node)or(type(p)=kern_node) then - begin vlink(q):=vlink(p); vlink(p):=null; flush_node_list(p); - end; - end - -@ @<Cases for noads that can follow a |bin_noad|@>= -left_noad: goto done_with_noad; -fraction_noad: begin make_fraction(q); goto check_dimensions; - end; -op_noad: begin delta:=make_op(q); - if subtype(q)=limits then goto check_dimensions; - end; -ord_noad: make_ord(q); -open_noad,inner_noad: do_nothing; -radical_noad: make_radical(q); -over_noad: make_over(q); -under_noad: make_under(q); -accent_noad: make_math_accent(q); -vcenter_noad: make_vcenter(q); - -@ Most of the actual construction work of |mlist_to_hlist| is done -by procedures with names -like |make_fraction|, |make_radical|, etc. To illustrate -the general setup of such procedures, let's begin with a couple of -simple ones. - -@<Declare math...@>= -procedure make_over(@!q:pointer); -var p:pointer; -begin p:=overbar(clean_box(nucleus(q),cramped_style(cur_style)),@| - 3*default_rule_thickness,default_rule_thickness); -vinfo(nucleus(q)):=p; -math_type(nucleus(q)):=sub_box; -end; - -@ @<Declare math...@>= -procedure make_under(@!q:pointer); -var p,@!x,@!y,@!r: pointer; {temporary registers for box construction} -@!delta:scaled; {overall height plus depth} -begin x:=clean_box(nucleus(q),cur_style); -p:=new_kern(3*default_rule_thickness); vlink(x):=p; -r:=fraction_rule(default_rule_thickness); vlink(p):=r; -pack_direction:=math_direction; y:=vpack(x,natural); -delta:=height(y)+depth(y)+default_rule_thickness; -height(y):=height(x); depth(y):=delta-height(y); -vinfo(nucleus(q)):=y; math_type(nucleus(q)):=sub_box; -end; - -@ @<Declare math...@>= -procedure make_vcenter(@!q:pointer); -var v:pointer; {the box that should be centered vertically} -@!delta:scaled; {its height plus depth} -begin v:=vinfo(nucleus(q)); -if type(v)<>vlist_node then confusion("vcenter"); -@:this can't happen vcenter}{\quad vcenter@> -delta:=height(v)+depth(v); -height(v):=axis_height(cur_size)+half(delta); -depth(v):=delta-height(v); -end; - -@ According to the rules in the \.{DVI} file specifications, we ensure alignment -@^square roots@> -between a square root sign and the rule above its nucleus by assuming that the -baseline of the square-root symbol is the same as the bottom of the rule. The -height of the square-root symbol will be the thickness of the rule, and the -depth of the square-root symbol should exceed or equal the height-plus-depth -of the nucleus plus a certain minimum clearance~|clr|. The symbol will be -placed so that the actual clearance is |clr| plus half the excess. - -@<Declare math...@>= -procedure make_radical(@!q:pointer); -var x,@!y,@!p:pointer; {temporary registers for box construction} -@!delta,@!clr:scaled; {dimensions involved in the calculation} -begin x:=clean_box(nucleus(q),cramped_style(cur_style)); -if cur_style<text_style then {display style} - clr:=default_rule_thickness+(abs(math_x_height(cur_size)) div 4) -else begin clr:=default_rule_thickness; clr:=clr + (abs(clr) div 4); - end; -y:=var_delimiter(left_delimiter(q),cur_size,height(x)+depth(x)+clr+ - default_rule_thickness); -delta:=depth(y)-(height(x)+depth(x)+clr); -if delta>0 then clr:=clr+half(delta); {increase the actual clearance} -shift_amount(y):=-(height(x)+clr); -p:=overbar(x,clr,height(y)); vlink(y):=p; -p:=hpack(y,natural); vinfo(nucleus(q)):=p; -math_type(nucleus(q)):=sub_box; -end; - -@ Slants are not considered when placing accents in math mode. The accenter is -centered over the accentee, and the accent width is treated as zero with -respect to the size of the final box. - -@<Declare math...@>= -procedure make_math_accent(@!q:pointer); -label done; -var p,@!x,@!y:pointer; {temporary registers for box construction} -@!c:quarterword; {accent character} -@!f:internal_font_number; {its font} -@!s:scaled; {amount to skew the accent to the right} -@!h:scaled; {height of character being accented} -@!delta:scaled; {space to remove between accent and accentee} -@!w:scaled; {width of the accentee, not including sub/superscripts} -begin fetch(accent_chr(q)); -if char_exists(cur_f,cur_c) then - begin c:=cur_c; f:=cur_f;@/ - @<Compute the amount of skew@>; - x:=clean_box(nucleus(q),cramped_style(cur_style)); w:=width(x); h:=height(x); - @<Switch to a larger accent if available and appropriate@>; - if h<x_height(f) then delta:=h@+else delta:=x_height(f); - if (math_type(supscr(q))<>empty)or(math_type(subscr(q))<>empty) then - if math_type(nucleus(q))=math_char then - @<Swap the subscript and superscript into box |x|@>; - y:=char_box(f,c); - shift_amount(y):=s+half(w-width(y)); - width(y):=0; p:=new_kern(-delta); vlink(p):=x; vlink(y):=p; - pack_direction:=math_direction; - y:=vpack(y,natural); width(y):=width(x); - if height(y)<h then @<Make the height of box |y| equal to |h|@>; - vinfo(nucleus(q)):=y; - math_type(nucleus(q)):=sub_box; - end; -end; - -@ @<Make the height of box |y|...@>= -begin p:=new_kern(h-height(y)); vlink(p):=list_ptr(y); list_ptr(y):=p; -height(y):=h; -end - -@ @<Switch to a larger accent if available and appropriate@>= -loop@+ begin if char_tag(f,c)<>list_tag then goto done; - y:=char_remainder(f,c); - if not char_exists(f,y) then goto done; - if char_width(f,y)>w then goto done; - c:=y; - end; -done: - -@ @<Compute the amount of skew@>= -s:=0; -if math_type(nucleus(q))=math_char then - begin fetch(nucleus(q)); - s := get_kern(cur_f,cur_c,skew_char(cur_f)); - end - -@ @<Swap the subscript and superscript into box |x|@>= -begin flush_node_list(x); x:=new_noad; -vmem(nucleus(x)):=vmem(nucleus(q)); -vmem(supscr(x)):=vmem(supscr(q)); -vmem(subscr(x)):=vmem(subscr(q));@/ -vmem(supscr(q)).hh:=empty_field; -vmem(subscr(q)).hh:=empty_field;@/ -math_type(nucleus(q)):=sub_mlist; vinfo(nucleus(q)):=x; -x:=clean_box(nucleus(q),cur_style); delta:=delta+height(x)-h; h:=height(x); -end - -@ The |make_fraction| procedure is a bit different because it sets -|new_hlist(q)| directly rather than making a sub-box. - -@<Declare math...@>= -procedure make_fraction(@!q:pointer); -var p,@!v,@!x,@!y,@!z:pointer; {temporary registers for box construction} -@!delta,@!delta1,@!delta2,@!shift_up,@!shift_down,@!clr:scaled; - {dimensions for box calculations} -begin if thickness(q)=default_code then thickness(q):=default_rule_thickness; -@<Create equal-width boxes |x| and |z| for the numerator and denominator, - and compute the default amounts |shift_up| and |shift_down| by which they - are displaced from the baseline@>; -if thickness(q)=0 then @<Adjust \(s)|shift_up| and |shift_down| for the case - of no fraction line@> -else @<Adjust \(s)|shift_up| and |shift_down| for the case of a fraction line@>; -@<Construct a vlist box for the fraction, according to |shift_up| and - |shift_down|@>; -@<Put the \(f)fraction into a box with its delimiters, and make |new_hlist(q)| - point to it@>; -end; - -@ @<Create equal-width boxes |x| and |z| for the numerator and denom...@>= -x:=clean_box(numerator(q),num_style(cur_style)); -z:=clean_box(denominator(q),denom_style(cur_style)); -vinfo(numerator(q)):=null; -vinfo(denominator(q)):=null; -if width(x)<width(z) then x:=rebox(x,width(z)) -else z:=rebox(z,width(x)); -if cur_style<text_style then {display style} - begin shift_up:=num1(cur_size); shift_down:=denom1(cur_size); - end -else begin shift_down:=denom2(cur_size); - if thickness(q)<>0 then shift_up:=num2(cur_size) - else shift_up:=num3(cur_size); - end - -@ The numerator and denominator must be separated by a certain minimum -clearance, called |clr| in the following program. The difference between -|clr| and the actual clearance is |2delta|. - -@<Adjust \(s)|shift_up| and |shift_down| for the case of no fraction line@>= -begin if cur_style<text_style then clr:=7*default_rule_thickness -else clr:=3*default_rule_thickness; -delta:=half(clr-((shift_up-depth(x))-(height(z)-shift_down))); -if delta>0 then - begin shift_up:=shift_up+delta; - shift_down:=shift_down+delta; - end; -end - -@ In the case of a fraction line, the minimum clearance depends on the actual -thickness of the line. - -@<Adjust \(s)|shift_up| and |shift_down| for the case of a fraction line@>= -begin if cur_style<text_style then clr:=3*thickness(q) -else clr:=thickness(q); -delta:=half(thickness(q)); -delta1:=clr-((shift_up-depth(x))-(axis_height(cur_size)+delta)); -delta2:=clr-((axis_height(cur_size)-delta)-(height(z)-shift_down)); -if delta1>0 then shift_up:=shift_up+delta1; -if delta2>0 then shift_down:=shift_down+delta2; -end - -@ @<Construct a vlist box for the fraction...@>= -v:=new_null_box; type(v):=vlist_node; -height(v):=shift_up+height(x); depth(v):=depth(z)+shift_down; -width(v):=width(x); {this also equals |width(z)|} -if thickness(q)=0 then - begin p:=new_kern((shift_up-depth(x))-(height(z)-shift_down)); - vlink(p):=z; - end -else begin y:=fraction_rule(thickness(q));@/ - p:=new_kern((axis_height(cur_size)-delta)-@|(height(z)-shift_down));@/ - vlink(y):=p; vlink(p):=z;@/ - p:=new_kern((shift_up-depth(x))-(axis_height(cur_size)+delta)); - vlink(p):=y; - end; -vlink(x):=p; list_ptr(v):=x - -@ @<Put the \(f)fraction into a box with its delimiters...@>= -if cur_style<text_style then delta:=delim1(cur_size) -else delta:=delim2(cur_size); -x:=var_delimiter(left_delimiter(q), cur_size, delta); vlink(x):=v;@/ -z:=var_delimiter(right_delimiter(q), cur_size, delta); vlink(v):=z;@/ -y:=hpack(x,natural); -new_hlist(q):=y - -@ If the nucleus of an |op_noad| is a single character, it is to be -centered vertically with respect to the axis, after first being enlarged -(via a character list in the font) if we are in display style. The normal -convention for placing displayed limits is to put them above and below the -operator in display style. - -The italic correction is removed from the character if there is a subscript -and the limits are not being displayed. The |make_op| -routine returns the value that should be used as an offset between -subscript and superscript. - -After |make_op| has acted, |subtype(q)| will be |limits| if and only if -the limits have been set above and below the operator. In that case, -|new_hlist(q)| will already contain the desired final box. - -@<Declare math...@>= -function make_op(@!q:pointer):scaled; -var delta:scaled; {offset between subscript and superscript} -@!p,@!v,@!x,@!y,@!z:pointer; {temporary registers for box construction} -@!c:quarterword; {register for character examination} -@!shift_up,@!shift_down:scaled; {dimensions for box calculation} -begin if (subtype(q)=normal)and(cur_style<text_style) then - subtype(q):=limits; -if math_type(nucleus(q))=math_char then - begin fetch(nucleus(q)); - if (cur_style<text_style)and(char_tag(cur_f,cur_c)=list_tag) then {make it larger} - begin c:=char_remainder(cur_f,cur_c); - if char_exists(cur_f,c) then - begin cur_c:=c; mcharacter(nucleus(q)):=c; - end; - end; - delta:=char_italic(cur_f,cur_c); x:=clean_box(nucleus(q),cur_style); - if (math_type(subscr(q))<>empty)and(subtype(q)<>limits) then - width(x):=width(x)-delta; {remove italic correction} - shift_amount(x):=half(height(x)-depth(x)) - axis_height(cur_size); - {center vertically} - math_type(nucleus(q)):=sub_box; vinfo(nucleus(q)):=x; - end -else delta:=0; -if subtype(q)=limits then - @<Construct a box with limits above and below it, skewed by |delta|@>; -make_op:=delta; -end; - -@ The following program builds a vlist box |v| for displayed limits. The -width of the box is not affected by the fact that the limits may be skewed. - -@<Construct a box with limits above and below it...@>= -begin x:=clean_box(supscr(q),sup_style(cur_style)); -y:=clean_box(nucleus(q),cur_style); -z:=clean_box(subscr(q),sub_style(cur_style)); -v:=new_null_box; type(v):=vlist_node; width(v):=width(y); -if width(x)>width(v) then width(v):=width(x); -if width(z)>width(v) then width(v):=width(z); -x:=rebox(x,width(v)); y:=rebox(y,width(v)); z:=rebox(z,width(v));@/ -shift_amount(x):=half(delta); shift_amount(z):=-shift_amount(x); -height(v):=height(y); depth(v):=depth(y); -@<Attach the limits to |y| and adjust |height(v)|, |depth(v)| to - account for their presence@>; -new_hlist(q):=v; -end - -@ We use |shift_up| and |shift_down| in the following program for the -amount of glue between the displayed operator |y| and its limits |x| and -|z|. The vlist inside box |v| will consist of |x| followed by |y| followed -by |z|, with kern nodes for the spaces between and around them. - -@<Attach the limits to |y| and adjust |height(v)|, |depth(v)|...@>= -if math_type(supscr(q))=empty then - begin list_ptr(x):=null; flush_node(x); list_ptr(v):=y; - end -else begin shift_up:=big_op_spacing3-depth(x); - if shift_up<big_op_spacing1 then shift_up:=big_op_spacing1; - p:=new_kern(shift_up); vlink(p):=y; vlink(x):=p;@/ - p:=new_kern(big_op_spacing5); vlink(p):=x; list_ptr(v):=p; - height(v):=height(v)+big_op_spacing5+height(x)+depth(x)+shift_up; - end; -if math_type(subscr(q))=empty then begin list_ptr(z):=null; flush_node(z); end -else begin shift_down:=big_op_spacing4-height(z); - if shift_down<big_op_spacing2 then shift_down:=big_op_spacing2; - p:=new_kern(shift_down); vlink(y):=p; vlink(p):=z;@/ - p:=new_kern(big_op_spacing5); vlink(z):=p; - depth(v):=depth(v)+big_op_spacing5+height(z)+depth(z)+shift_down; - end - -@ A ligature found in a math formula does not create a ligature, because -there is no question of hyphenation afterwards; the ligature will simply be -stored in an ordinary |glyph_node|, after residing in an |ord_noad|. - -The |math_type| is converted to |math_text_char| here if we would not want to -apply an italic correction to the current character unless it belongs -to a math font (i.e., a font with |space=0|). - -No boundary characters enter into these ligatures. - -@<Declare math...@>= -procedure make_ord(@!q:pointer); -label restart,exit; -var a:integer; { the left-side character for lig/kern testing } -@!p,@!r:pointer; {temporary registers for list manipulation} -k:scaled; { a kern } -lig:liginfo; { a ligature } -begin restart:@t@>@;@/ -if math_type(subscr(q))=empty then if math_type(supscr(q))=empty then - if math_type(nucleus(q))=math_char then - begin p:=vlink(q); - if p<>null then if (type(p)>=ord_noad)and(type(p)<=punct_noad) then - if math_type(nucleus(p))=math_char then - if fam(nucleus(p))=fam(nucleus(q)) then - begin math_type(nucleus(q)):=math_text_char; - fetch(nucleus(q)); a:=cur_c; - if (has_kern(cur_f,a))or(has_lig(cur_f,a)) then - begin cur_c:=mcharacter(nucleus(p)); - @<If character |a| has a kern with |cur_c|, attach - the kern after~|q|; or if it has a ligature with |cur_c|, combine - noads |q| and~|p| appropriately; then |return| if the cursor has - moved past a noad, or |goto restart|@>; - end; - end; - end; -exit:end; - -@ Note that a ligature between an |ord_noad| and another kind of noad -is replaced by an |ord_noad|, when the two noads collapse into one. -But we could make a parenthesis (say) change shape when it follows -certain letters. Presumably a font designer will define such -ligatures only when this convention makes sense. - -\chardef\?='174 % vertical line to indicate character retention - -@<If character |a| has a kern with |cur_c|, ...@>= -begin -if disable_lig=0 and has_lig(cur_f,a) then begin - lig:=get_ligature(cur_f,a,cur_c); - if is_valid_ligature(lig) then begin - check_interrupt; {allow a way out of infinite ligature loop} - case lig_type(lig) of - qi(1),qi(5): mcharacter(nucleus(q)):=lig_replacement(lig); {\.{=:\?}, \.{=:\?>}} - qi(2),qi(6): mcharacter(nucleus(p)):=lig_replacement(lig); {\.{\?=:}, \.{\?=:>}} - qi(3),qi(7),qi(11):begin r:=new_noad; {\.{\?=:\?}, \.{\?=:\?>}, \.{\?=:\?>>}} - mcharacter(nucleus(r)):=lig_replacement(lig); - fam(nucleus(r)):=fam(nucleus(q));@/ - vlink(q):=r; vlink(r):=p; - if lig_type(lig)<qi(11) then math_type(nucleus(r)):=math_char - else math_type(nucleus(r)):=math_text_char; {prevent combination} - end; - othercases begin vlink(q):=vlink(p); - mcharacter(nucleus(q)):=lig_replacement(lig); {\.{=:}} - vmem(subscr(q)):=vmem(subscr(p)); vmem(supscr(q)):=vmem(supscr(p));@/ - flush_node(p); - end - endcases; - if lig_type(lig)>qi(3) then return; - math_type(nucleus(q)):=math_char; goto restart; - end; - end; -if disable_kern=0 and has_kern(cur_f,a) then begin - k:=get_kern(cur_f,a,cur_c); - if k<>0 then begin - p:=new_kern(k); vlink(p):=vlink(q); vlink(q):=p; return; - end; - end; -end - -@ When we get to the following part of the program, we have ``fallen through'' -from cases that did not lead to |check_dimensions| or |done_with_noad| or -|done_with_node|. Thus, |q|~points to a noad whose nucleus may need to be -converted to an hlist, and whose subscripts and superscripts need to be -appended if they are present. - -If |nucleus(q)| is not a |math_char|, the variable |delta| is the amount -by which a superscript should be moved right with respect to a subscript -when both are present. -@^subscripts@> -@^superscripts@> - -@<Convert \(n)|nucleus(q)| to an hlist and attach the sub/superscripts@>= -case math_type(nucleus(q)) of -math_char, math_text_char: - @<Create a character node |p| for |nucleus(q)|, possibly followed - by a kern node for the italic correction, and set |delta| to the - italic correction if a subscript is present@>; -empty: p:=null; -sub_box: p:=vinfo(nucleus(q)); -sub_mlist: begin cur_mlist:=vinfo(nucleus(q)); save_style:=cur_style; - mlist_penalties:=false; mlist_to_hlist; {recursive call} -@^recursion@> - cur_style:=save_style; @<Set up the values...@>; - p:=hpack(vlink(temp_head),natural); - end; -othercases confusion("mlist2") -@:this can't happen mlist2}{\quad mlist2@> -endcases;@/ -new_hlist(q):=p; -if (math_type(subscr(q))=empty)and(math_type(supscr(q))=empty) then - goto check_dimensions; -make_scripts(q,delta) - -@ @<Create a character node |p| for |nucleus(q)|...@>= -begin fetch(nucleus(q)); -if char_exists(cur_f,cur_c) then - begin delta:=char_italic(cur_f,cur_c); p:=new_glyph(cur_f,cur_c); - if (math_type(nucleus(q))=math_text_char)and(space(cur_f)<>0) then - delta:=0; {no italic correction in mid-word of text font} - if (math_type(subscr(q))=empty)and(delta<>0) then - begin x:=new_kern(delta); vlink(p):=x; delta:=0; - end; - end -else p:=null; -end - -@ The purpose of |make_scripts(q,delta)| is to attach the subscript and/or -superscript of noad |q| to the list that starts at |new_hlist(q)|, -given that subscript and superscript aren't both empty. The superscript -will appear to the right of the subscript by a given distance |delta|. -We set |shift_down| and |shift_up| to the minimum amounts to shift the -baseline of subscripts and superscripts based on the given nucleus. - -@<Declare math...@>= -procedure make_scripts(@!q:pointer;@!delta:scaled); -var p,@!x,@!y,@!z:pointer; {temporary registers for box construction} -@!shift_up,@!shift_down,@!clr:scaled; {dimensions in the calculation} -@!t:integer; {subsidiary size code} -begin p:=new_hlist(q); -if is_char_node(p) then - begin shift_up:=0; shift_down:=0; - end -else begin z:=hpack(p,natural); - t:=cur_size; - if cur_style<script_style - then cur_size:=script_size@+else cur_size:=script_script_size; - shift_up:=height(z)-sup_drop(cur_size); - shift_down:=depth(z)+sub_drop(cur_size); - cur_size:=t; - list_ptr(z):=null; flush_node(z); - end; -if math_type(supscr(q))=empty then - @<Construct a subscript box |x| when there is no superscript@> -else begin @<Construct a superscript box |x|@>; - if math_type(subscr(q))=empty then shift_amount(x):=-shift_up - else @<Construct a sub/superscript combination box |x|, with the - superscript offset by |delta|@>; - end; -if new_hlist(q)=null then new_hlist(q):=x -else begin p:=new_hlist(q); - while vlink(p)<>null do p:=vlink(p); - vlink(p):=x; - end; -end; - -@ When there is a subscript without a superscript, the top of the subscript -should not exceed the baseline plus four-fifths of the x-height. - -@<Construct a subscript box |x| when there is no superscript@>= -begin x:=clean_box(subscr(q),sub_style(cur_style)); -width(x):=width(x)+script_space; -if shift_down<sub1(cur_size) then shift_down:=sub1(cur_size); -clr:=height(x)-(abs(math_x_height(cur_size)*4) div 5); -if shift_down<clr then shift_down:=clr; -shift_amount(x):=shift_down; -end - -@ The bottom of a superscript should never descend below the baseline plus -one-fourth of the x-height. - -@<Construct a superscript box |x|@>= -begin x:=clean_box(supscr(q),sup_style(cur_style)); -width(x):=width(x)+script_space; -if odd(cur_style) then clr:=sup3(cur_size) -else if cur_style<text_style then clr:=sup1(cur_size) -else clr:=sup2(cur_size); -if shift_up<clr then shift_up:=clr; -clr:=depth(x)+(abs(math_x_height(cur_size)) div 4); -if shift_up<clr then shift_up:=clr; -end - -@ When both subscript and superscript are present, the subscript must be -separated from the superscript by at least four times |default_rule_thickness|. -If this condition would be violated, the subscript moves down, after which -both subscript and superscript move up so that the bottom of the superscript -is at least as high as the baseline plus four-fifths of the x-height. - -@<Construct a sub/superscript combination box |x|...@>= -begin y:=clean_box(subscr(q),sub_style(cur_style)); -width(y):=width(y)+script_space; -if shift_down<sub2(cur_size) then shift_down:=sub2(cur_size); -clr:=4*default_rule_thickness- - ((shift_up-depth(x))-(height(y)-shift_down)); -if clr>0 then - begin shift_down:=shift_down+clr; - clr:=(abs(math_x_height(cur_size)*4) div 5)-(shift_up-depth(x)); - if clr>0 then - begin shift_up:=shift_up+clr; - shift_down:=shift_down-clr; - end; - end; -shift_amount(x):=delta; {superscript is |delta| to the right of the subscript} -p:=new_kern((shift_up-depth(x))-(height(y)-shift_down)); vlink(x):=p; vlink(p):=y; -pack_direction:=math_direction; -x:=vpack(x,natural); shift_amount(x):=shift_down; -end - -@ We have now tied up all the loose ends of the first pass of |mlist_to_hlist|. -The second pass simply goes through and hooks everything together with the -proper glue and penalties. It also handles the |left_noad| and |right_noad| that -might be present, since |max_hl| and |max_d| are now known. Variable |p| points -to a node at the current end of the final hlist. - -@<Make a second pass over the mlist, ...@>= -p:=temp_head; vlink(p):=null; q:=mlist; r_type:=0; cur_style:=style; -@<Set up the values of |cur_size| and |cur_mu|, based on |cur_style|@>; -while q<>null do - begin @<If node |q| is a style node, change the style and |goto delete_q|; - otherwise if it is not a noad, put it into the hlist, - advance |q|, and |goto done|; otherwise set |s| to the size - of noad |q|, set |t| to the associated type (|ord_noad.. - inner_noad|), and set |pen| to the associated penalty@>; - @<Append inter-element spacing based on |r_type| and |t|@>; - @<Append any |new_hlist| entries for |q|, and any appropriate penalties@>; - if type(q)=right_noad then t:=open_noad; - r_type:=t; - delete_q: r:=q; q:=vlink(q); - flush_node(r); {|r| had better be a noad-like thing } - done: end - -@ Just before doing the big |case| switch in the second pass, the program -sets up default values so that most of the branches are short. - -@<If node |q| is a style node, change the style...@>= -t:=ord_noad; s:=noad_size; pen:=inf_penalty; -case type(q) of -op_noad,open_noad,close_noad,punct_noad,inner_noad: t:=type(q); -bin_noad: begin t:=bin_noad; pen:=bin_op_penalty; - end; -rel_noad: begin t:=rel_noad; pen:=rel_penalty; - end; -ord_noad,vcenter_noad,over_noad,under_noad: do_nothing; -radical_noad: s:=radical_noad_size; -accent_noad: s:=accent_noad_size; -fraction_noad: begin t:=inner_noad; s:=fraction_noad_size; - end; -left_noad,right_noad: t:=make_left_right(q,style,max_d,max_hl); -style_node: @<Change the current style and |goto delete_q|@>; -whatsit_node,penalty_node,rule_node,disc_node,adjust_node,ins_node,mark_node, - glue_node,kern_node:@t@>@;@/ - begin vlink(p):=q; p:=q; q:=vlink(q); vlink(p):=null; goto done; - end; -othercases confusion("mlist3") -@:this can't happen mlist3}{\quad mlist3@> -endcases - -@ The |make_left_right| function constructs a left or right delimiter of -the required size and returns the value |open_noad| or |close_noad|. The -|right_noad| and |left_noad| will both be based on the original |style|, -so they will have consistent sizes. - -We use the fact that |right_noad-left_noad=close_noad-open_noad|. - -@<Declare math...@>= -function make_left_right(@!q:pointer;@!style:integer; - @!max_d,@!max_hv:scaled):small_number; -var delta,@!delta1,@!delta2:scaled; {dimensions used in the calculation} -tmp:pointer; -begin cur_style:=style; @<Set up the values...@>; -delta2:=max_d+axis_height(cur_size); -delta1:=max_hv+max_d-delta2; -if delta2>delta1 then delta1:=delta2; {|delta1| is max distance from axis} -delta:=(delta1 div 500)*delimiter_factor; -delta2:=delta1+delta1-delimiter_shortfall; -if delta<delta2 then delta:=delta2; -tmp:=var_delimiter(delimiter(q),cur_size,delta); -new_hlist(q):=tmp; -make_left_right:=type(q)-(left_noad-open_noad); {|open_noad| or |close_noad|} -end; - -@ @<Change the current style and |goto delete_q|@>= -begin cur_style:=subtype(q); s:=style_node_size; -@<Set up the values of |cur_size| and |cur_mu|, based on |cur_style|@>; -goto delete_q; -end - -@ The inter-element spacing in math formulas depends on a $8\times8$ table that -\TeX\ preloads as a 64-digit string. The elements of this string have the -following significance: -$$\vbox{\halign{#\hfil\cr -\.0 means no space;\cr -\.1 means a conditional thin space (\.{\\nonscript\\mskip\\thinmuskip});\cr -\.2 means a thin space (\.{\\mskip\\thinmuskip});\cr -\.3 means a conditional medium space - (\.{\\nonscript\\mskip\\medmuskip});\cr -\.4 means a conditional thick space - (\.{\\nonscript\\mskip\\thickmuskip});\cr -\.* means an impossible case.\cr}}$$ -This is all pretty cryptic, but {\sl The \TeX book\/} explains what is -supposed to happen, and the string makes it happen. -@:TeXbook}{\sl The \TeX book@> - -A global variable |magic_offset| is computed so that if |a| and |b| are -in the range |ord_noad..inner_noad|, then |str_pool[a*8+b+magic_offset]| -is the digit for spacing between noad types |a| and |b|. - -If \PASCAL\ had provided a good way to preload constant arrays, this part of -the program would not have been so strange. -@:PASCAL}{\PASCAL@> - -@d math_spacing=@;@/ -@t\hskip-35pt@> -"0234000122*4000133**3**344*0400400*000000234000111*1111112341011" -@t$ \hskip-35pt$@> - -@<Glob...@>= -@!magic_offset:integer; {used to find inter-element spacing} - -@ @<Compute the magic offset@>= -magic_offset:=str_start_macro(math_spacing)-9*ord_noad - -@ @<Append inter-element spacing based on |r_type| and |t|@>= -if r_type>0 then {not the first noad} - begin case so(str_pool[r_type*8+t+magic_offset]) of - "0": x:=0; - "1": if cur_style<script_style then x:=thin_mu_skip_code@+else x:=0; - "2": x:=thin_mu_skip_code; - "3": if cur_style<script_style then x:=med_mu_skip_code@+else x:=0; - "4": if cur_style<script_style then x:=thick_mu_skip_code@+else x:=0; - othercases confusion("mlist4") -@:this can't happen mlist4}{\quad mlist4@> - endcases; - if x<>0 then - begin y:=math_glue(glue_par(x),cur_mu); - z:=new_glue(y); glue_ref_count(y):=null; vlink(p):=z; p:=z;@/ - subtype(z):=x+1; {store a symbolic subtype} - end; - end - -@ We insert a penalty node after the hlist entries of noad |q| if |pen| -is not an ``infinite'' penalty, and if the node immediately following |q| -is not a penalty node or a |rel_noad| or absent entirely. - -@<Append any |new_hlist| entries for |q|, and any appropriate penalties@>= -if new_hlist(q)<>null then - begin vlink(p):=new_hlist(q); - repeat p:=vlink(p); - until vlink(p)=null; - end; -if penalties then if vlink(q)<>null then if pen<inf_penalty then - begin r_type:=type(vlink(q)); - if r_type<>penalty_node then if r_type<>rel_noad then - begin z:=new_penalty(pen); vlink(p):=z; p:=z; - end; - end +Is done in C. @* \[37] Alignment. It's sort of a miracle whenever \.{\\halign} and \.{\\valign} work, because @@ -22826,7 +19889,6 @@ 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. -@d align_record_node=34 @d u_part(#)==vlink(#+depth_offset) {pointer to \<u_j> token list} @d v_part(#)==vinfo(#+depth_offset) {pointer to \<v_j> token list} @d span_ptr(#)==vinfo(#+1) {column spanning list} @@ -22851,7 +19913,6 @@ when they have to be pushed down, they are stored in 6-word nodes, and |align_ptr| points to the topmost such node. @d preamble==vlink(align_head) {the current preamble list} -@d align_stack_node=47 @<Glob...@>= @!cur_align:pointer; {current position in preamble list} @@ -23000,12 +20061,12 @@ as its command code. @d end_template_token==cs_token_flag+frozen_end_template @<Put each of \TeX's primitives into the hash table@>= -primitive("span",tab_mark,span_code);@/ +primitive_tex("span",tab_mark,span_code,span_code);@/ @!@:span_}{\.{\\span} primitive@> -primitive("cr",car_ret,cr_code); +primitive_tex("cr",car_ret,cr_code,cr_code); @!@:cr_}{\.{\\cr} primitive@> text(frozen_cr):="cr"; eqtb[frozen_cr]:=eqtb[cur_val];@/ -primitive("crcr",car_ret,cr_cr_code); +primitive_tex("crcr",car_ret,cr_cr_code,cr_code); @!@:cr_cr_}{\.{\\crcr} primitive@> text(frozen_end_template):="endtemplate"; text(frozen_endv):="endtemplate"; eq_type(frozen_endv):=endv; equiv(frozen_endv):=null_list; @@ -23013,12 +20074,6 @@ eq_level(frozen_endv):=level_one;@/ eqtb[frozen_end_template]:=eqtb[frozen_endv]; eq_type(frozen_end_template):=end_template; -@ @<Cases of |print_cmd_chr|...@>= -tab_mark: if chr_code=span_code then print_esc("span") - else chr_cmd("alignment tab character "); -car_ret: if chr_code=cr_code then print_esc("cr") - else print_esc("crcr"); - @ 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. @@ -23140,7 +20195,7 @@ entered, so that the columns will generate a list for subsequent packaging. procedure init_span(@!p:pointer); begin push_nest; if mode=-hmode then space_factor:=1000 -else begin prev_depth:=ignore_depth; normal_paragraph; +else begin prev_depth:=pdf_ignored_dimen; normal_paragraph; end; cur_span:=p; end; @@ -23295,8 +20350,6 @@ that column. The code has to make sure that there is room for The |new_span_node| function is defined in |texnodes.c|. -@d span_node==41 -@d span_node_size==3 {number of |mem| words for a span node} @d span_span(#)==vlink(#+1) {that is normally |alink| } @<Initialize the special list heads...@>= @@ -23380,7 +20433,7 @@ 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-1+|min_quarterword|$ in their +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$. @@ -23596,7 +20649,7 @@ program will be deferred until we're more familiar with such operations.) @<Insert the \(c)current list into its environment@>= aux_save:=aux; p:=vlink(head); q:=tail; pop_nest; -if mode=mmode then @<Finish an alignment in a display@> +if mode=mmode then finish_display_alignment(p,q,aux_save) else begin aux:=aux_save; vlink(tail):=p; if p<>null then tail:=q; if mode=vmode then begin check_filter('alignment'); build_page; end; @@ -23623,7 +20676,7 @@ line-breaking problem can be regarded as a special case of the problem of computing the shortest path in an acyclic network. The cited paper includes numerous examples and describes the history of line breaking as it has been practiced by printers through the ages. The present implementation adds two -new ideas to the algorithm of 1980: memory space requirements are considerably +new ideas to the algorithm of 1980: Memory space requirements are considerably reduced by using smaller records for inactive nodes than for active ones, and arithmetic overflow is avoided by using ``delta distances'' instead of keeping track of the total distance from the beginning of the paragraph to the @@ -23670,7 +20723,7 @@ line_break_context := bottom_level; @ In it's complete form, |line_break| is a rather lengthy procedure---sort of a small world unto itself---we must build it up -little by little. Below you see only te general outline. +little by little. Below you see only the general outline. The main task performed here is to move the list from |head| to |temp_head| and go into the enclosing semantic level. We also append @@ -23689,6 +20742,7 @@ Most other processing is delegated to external functions. @p procedure line_break(@!d:boolean); var final_par_glue:pointer; start_of_par:pointer; +callback_id:integer; begin pack_begin_line:=mode_line; {this is for over/underfull box messages} vlink(temp_head):=vlink(head); new_hyphenation(temp_head, tail); @@ -23710,28 +20764,52 @@ else begin end; final_par_glue:=new_param_glue(par_fill_skip_code); couple_nodes(tail,final_par_glue); -if not output_active then - lua_node_filter(pre_linebreak_filter_callback, - line_break_context,temp_head,addressof(tail)); +lua_node_filter(pre_linebreak_filter_callback, + line_break_context,temp_head,addressof(tail)); last_line_fill:=vlink(tail); pop_nest; start_of_par:=tail; -ext_do_line_break(d,pretolerance,tracing_paragraphs,tolerance,emergency_stretch, - looseness,hyphen_penalty,ex_hyphen_penalty, - pdf_adjust_spacing, par_shape_ptr, adj_demerits, - pdf_protrude_chars, line_penalty, last_line_fit, - double_hyphen_demerits, final_hyphen_demerits, - hang_indent, hsize, hang_after, left_skip, right_skip, - pdf_each_line_height,pdf_each_line_depth, - pdf_first_line_height, pdf_last_line_depth, - inter_line_penalties_ptr, inter_line_penalty, - club_penalty, club_penalties_ptr, - display_widow_penalties_ptr,widow_penalties_ptr, - display_widow_penalty, widow_penalty, - broken_penalty, final_par_glue); -if not output_active then - lua_node_filter(post_linebreak_filter_callback, - line_break_context,start_of_par,addressof(tail)); +callback_id:=callback_defined(linebreak_filter_callback); +if callback_id<>0 then begin + callback_id := lua_linebreak_callback(d, temp_head, addressof(tail)); + if callback_id>0 then begin + just_box := tail; + if just_box<>null then + while vlink(just_box)<>null do + just_box := vlink(just_box); + if (just_box=null)or(type(just_box) <> hlist_node) then begin + help3("A linebreaking routine should return a non-empty list of nodes") + ("and the last one of those has to be a \\hbox.") + ("Sorry, I cannot recover from this."); + print_err("Invalid linebreak_filter"); + succumb; + end + end + else begin + if tracing_paragraphs>0 then begin + begin_diagnostic; + print_nl("Lua linebreak_filter failed, reverting to default on line "); print_int(line); + end_diagnostic(true); + end; + end; +end; +if callback_id=0 then begin + ext_do_line_break(d,pretolerance,tracing_paragraphs,tolerance,emergency_stretch, + looseness,hyphen_penalty,ex_hyphen_penalty, + pdf_adjust_spacing, par_shape_ptr, adj_demerits, + pdf_protrude_chars, line_penalty, last_line_fit, + double_hyphen_demerits, final_hyphen_demerits, + hang_indent, hsize, hang_after, left_skip, right_skip, + pdf_each_line_height,pdf_each_line_depth, + pdf_first_line_height, pdf_last_line_depth, + inter_line_penalties_ptr, inter_line_penalty, + club_penalty, club_penalties_ptr, + display_widow_penalties_ptr,widow_penalties_ptr, + display_widow_penalty, widow_penalty, + broken_penalty, final_par_glue, pdf_ignored_dimen); +end; +lua_node_filter(post_linebreak_filter_callback, + line_break_context,start_of_par,addressof(tail)); pack_begin_line:=0; end; @# @@ -23742,13 +20820,7 @@ end; The choice between |check_head_filter| and |check_contrib_filter| is not quite clear to me yet, but it seems that the latter is the better choice. -@d check_head_filter(#)==if (not output_active) and (vlink(head)<>null) then -lua_node_filter_s(buildpage_filter_callback,#,head,addressof(tail)) - -@d check_contrib_filter(#)==if (not output_active) and (vlink(contrib_head)<>null) then -lua_node_filter_s(buildpage_filter_callback,#,contrib_head,addressof(garbage)) - -@d check_filter==check_head_filter +@d check_filter(#)==if not output_active then lua_node_filter_s(buildpage_filter_callback,#) @* \[39] Breaking paragraphs into lines, continued. @@ -23795,6 +20867,21 @@ begin scan_optional_equals; scan_int; set_post_hyphen_char(language,cur_val); end; +@ `\.{\\preexhyphenchar}', sets the |pre_break| character, and +`\.{\\postexhyphenchar}' the |post_break| character. Their +defaults are both zero (nul). + +@p procedure new_pre_exhyphen_char; +begin scan_optional_equals; scan_int; + set_pre_exhyphen_char(language,cur_val); +end; +@# +procedure new_post_exhyphen_char; +begin scan_optional_equals; scan_int; + set_post_exhyphen_char(language,cur_val); +end; + + @* \[43] Initializing the hyphenation tables. None of the trie-related stuff is applicable any more in luatex. @@ -23823,12 +20910,12 @@ var prev_p:pointer; {lags one step behind |p|} begin prev_p:=temp_head; vlink(temp_head):=p; r:=null; while p<>null do case type(p) of - hlist_node,vlist_node,rule_node:@<Insert glue for |split_top_skip| + hlist_node_case,vlist_node_case,rule_node_case:@<Insert glue for |split_top_skip| and set~|p:=null|@>; - whatsit_node,mark_node,ins_node: begin + whatsit_node_case,mark_node_case,ins_node_case: begin prev_p:=p; p:=vlink(prev_p); end; - glue_node,kern_node,penalty_node: begin + glue_node_case,kern_node_case,penalty_node_case: begin q:=p; p:=vlink(q); vlink(q):=null; vlink(prev_p):=p; if s then @@ -23928,19 +21015,19 @@ not_found: if prev_dp>d then @ @<Use node |p| to update the current height and depth measurements...@>= case type(p) of -hlist_node,vlist_node,rule_node: begin@t@>@;@/ +hlist_node_case,vlist_node_case,rule_node_case: begin@t@>@;@/ cur_height:=cur_height+prev_dp+height(p); prev_dp:=depth(p); goto not_found; end; -whatsit_node:@<Process whatsit |p| in |vert_break| loop, |goto not_found|@>; -glue_node: if precedes_break(prev_p) then pi:=0 +whatsit_node_case:@<Process whatsit |p| in |vert_break| loop, |goto not_found|@>; +glue_node_case: if precedes_break(prev_p) then pi:=0 else goto update_heights; -kern_node: begin if vlink(p)=null then t:=penalty_node +kern_node_case: begin if vlink(p)=null then t:=penalty_node else t:=type(vlink(p)); if t=glue_node then pi:=0@+else goto update_heights; end; -penalty_node: pi:=penalty(p); -mark_node,ins_node: goto not_found; +penalty_node_case: pi:=penalty(p); +mark_node_case,ins_node_case: goto not_found; othercases confusion("vertbreak") @:this can't happen vertbreak}{\quad vertbreak@> endcases @@ -24132,8 +21219,8 @@ node $r_j$ is followed by |r@t$_{j+1}$@>=vlink(r@t$_j$@>)|; and if there are each node in this list refers to an insertion number; for example, `\.{\\insert 250}' would correspond to a node whose |subtype| is |qi(250)| (the same as the |subtype| field of the relevant |ins_node|). These |subtype| -fields are in increasing order, and |subtype(page_ins_head)= -qi(255)|, so |page_ins_head| serves as a convenient sentinel +fields are in increasing order, and |subtype(page_ins_head)=65535, so +|page_ins_head| serves as a convenient sentinel at the end of the list. A record is present for each insertion number that appears in the current page. @@ -24160,8 +21247,6 @@ The data structure definitions here use the fact that the |@!height| field appears in the fourth word of a box node. @^data structure assumptions@> -@d inserting_node=37 {an insertion class that has not yet overflowed} -@d split_up_node=38 {an overflowed insertion class} @d broken_ptr(#)==vlink(#+2) {an insertion for this class will break here if anywhere} @d broken_ins(#)==vinfo(#+2) {this insertion might break at |broken_ptr|} @@ -24169,7 +21254,7 @@ appears in the fourth word of a box node. @d best_ins_ptr(#)==vinfo(#+3) {the optimum most recent insertion} @<Initialize the special list heads...@>= -subtype(page_ins_head):=qi(255); +subtype(page_ins_head):=65535; type(page_ins_head):=split_up_node; vlink(page_ins_head):=page_ins_head; @ An array |page_so_far| records the heights and depths of everything @@ -24207,35 +21292,23 @@ all split and floating insertions. @!insert_penalties:integer; {sum of the penalties for held-over insertions} @ @<Put each...@>= -primitive("pagegoal",set_page_dimen,0); +primitive_tex("pagegoal",set_page_dimen,0,0); @!@:page_goal_}{\.{\\pagegoal} primitive@> -primitive("pagetotal",set_page_dimen,1); +primitive_tex("pagetotal",set_page_dimen,1,0); @!@:page_total_}{\.{\\pagetotal} primitive@> -primitive("pagestretch",set_page_dimen,2); +primitive_tex("pagestretch",set_page_dimen,2,0); @!@:page_stretch_}{\.{\\pagestretch} primitive@> -primitive("pagefilstretch",set_page_dimen,3); +primitive_tex("pagefilstretch",set_page_dimen,3,0); @!@:page_fil_stretch_}{\.{\\pagefilstretch} primitive@> -primitive("pagefillstretch",set_page_dimen,4); +primitive_tex("pagefillstretch",set_page_dimen,4,0); @!@:page_fill_stretch_}{\.{\\pagefillstretch} primitive@> -primitive("pagefilllstretch",set_page_dimen,5); +primitive_tex("pagefilllstretch",set_page_dimen,5,0); @!@:page_filll_stretch_}{\.{\\pagefilllstretch} primitive@> -primitive("pageshrink",set_page_dimen,6); +primitive_tex("pageshrink",set_page_dimen,6,0); @!@:page_shrink_}{\.{\\pageshrink} primitive@> -primitive("pagedepth",set_page_dimen,7); +primitive_tex("pagedepth",set_page_dimen,7,0); @!@:page_depth_}{\.{\\pagedepth} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -set_page_dimen: case chr_code of -0: print_esc("pagegoal"); -1: print_esc("pagetotal"); -2: print_esc("pagestretch"); -3: print_esc("pagefilstretch"); -4: print_esc("pagefillstretch"); -5: print_esc("pagefilllstretch"); -6: print_esc("pageshrink"); -othercases print_esc("pagedepth") -endcases; - @ @d print_plus_end(#)==print(#);@+end @d print_plus(#)==if page_so_far[#]<>0 then begin print(" plus "); print_scaled(page_so_far[#]); print_plus_end @@ -24266,7 +21339,9 @@ if page_head<>page_tail then while r<>page_ins_head do begin print_ln; print_esc("insert"); t:=qo(subtype(r)); print_int(t); print(" adds "); - t:=x_over_n(height(r),1000)*count(t); print_scaled(t); + if count(t)=1000 then t:=height(r) + else t:=x_over_n(height(r),1000)*count(t); + print_scaled(t); if type(r)=split_up_node then begin q:=page_head; t:=0; repeat q:=vlink(q); @@ -24344,7 +21419,7 @@ last_glue:=max_halfword; last_penalty:=0; last_kern:=0; last_node_type:=-1; page_depth:=0; page_max_depth:=0 -@ At certain times box 255 is supposed to be void (i.e., |null|), +@ At certain times box \outputbox is supposed to be void (i.e., |null|), or an insertion box is supposed to be ready to accept a vertical list. If not, an error message is printed, and the following subroutine flushes the unwanted contents, reporting them to the user. @@ -24461,23 +21536,23 @@ we know its successor. @<If the current page is empty...@>= case type(p) of -hlist_node,vlist_node,rule_node: if page_contents<box_there then +hlist_node_case,vlist_node_case,rule_node_case: if page_contents<box_there then @<Initialize the current page, insert the \.{\\topskip} glue ahead of |p|, and |goto continue|@> else @<Prepare to move a box or rule node to the current page, then |goto contribute|@>; -whatsit_node: @<Prepare to move whatsit |p| to the current page, +whatsit_node_case: @<Prepare to move whatsit |p| to the current page, then |goto contribute|@>; -glue_node: if page_contents<box_there then goto done1 +glue_node_case: if page_contents<box_there then goto done1 else if precedes_break(page_tail) then pi:=0 else goto update_heights; -kern_node: if page_contents<box_there then goto done1 +kern_node_case: if page_contents<box_there then goto done1 else if vlink(p)=null then return else if type(vlink(p))=glue_node then pi:=0 else goto update_heights; -penalty_node: if page_contents<box_there then goto done1@+else pi:=penalty(p); -mark_node: goto contribute; -ins_node: @<Append an insertion to the current page and |goto contribute|@>; +penalty_node_case: if page_contents<box_there then goto done1@+else pi:=penalty(p); +mark_node_case: goto contribute; +ins_node_case: @<Append an insertion to the current page and |goto contribute|@>; othercases confusion("page") @:this can't happen page}{\quad page@> endcases @@ -24486,7 +21561,7 @@ endcases begin if page_contents=empty then freeze_page_specs(box_there) else page_contents:=box_there; q:=new_skip_param(top_skip_code); {now |temp_ptr=glue_ptr(q)|} -if (type(p)=hlist_node) and (is_mirrored(body_direction)) then begin +if (type(p)=hlist_node) and is_mirrored(body_direction) then begin if width(temp_ptr)>depth(p) then width(temp_ptr):=width(temp_ptr)-depth(p) else width(temp_ptr):=0; end @@ -24499,7 +21574,7 @@ end @ @<Prepare to move a box or rule node to the current page...@>= begin -if (type(p)=hlist_node) and (is_mirrored(body_direction)) then begin +if (type(p)=hlist_node) and is_mirrored(body_direction) then begin page_total:=page_total+page_depth+depth(p); page_depth:=height(p); end @@ -24688,7 +21763,7 @@ end @ When the page builder has looked at as much material as could appear before the next page break, it makes its decision. The break that gave minimum -badness will be used to put a completed ``page'' into box 255, with insertions +badness will be used to put a completed ``page'' into box \.{\\outputbox}, with insertions appended to their other boxes. We also set the values of |top_mark|, |first_mark|, and |bot_mark|. The @@ -24720,7 +21795,7 @@ for i:=0 to biggest_used_mark do begin delete_first_mark(i); end; end; -@<Put the \(o)optimal current page into box 255, update |first_mark| and +@<Put the \(o)optimal current page into box |output_box|, update |first_mark| and |bot_mark|, append insertions to their boxes, and put the remaining nodes back on the contribution list@>; for i:=0 to biggest_used_mark do begin @@ -24747,9 +21822,9 @@ pointer |p| runs through the vlist, with |prev_p| trailing behind; pointer |q| is the tail of a list of insertions that are being held over for a subsequent page. -@<Put the \(o)optimal current page into box 255...@>= +@<Put the \(o)optimal current page into box ...@>= if c=best_page_break then best_page_break:=null; {|c| not yet linked in} -@<Ensure that box 255 is empty before output@>; +@<Ensure that box |output_box| is empty before output@>; insert_penalties:=0; {this will count the number of insertions held over} save_split_top_skip:=split_top_skip; if holding_inserts<=0 then @@ -24767,17 +21842,17 @@ while p<>best_page_break do prev_p:=p; p:=vlink(prev_p); end; split_top_skip:=save_split_top_skip; -@<Break the current page at node |p|, put it in box~255, +@<Break the current page at node |p|, put it in box~|output_box|, and put the remaining nodes on the contribution list@>; @<Delete \(t)the page-insertion nodes@> -@ @<Ensure that box 255 is empty before output@>= -if box(255)<>null then - begin print_err(""); print_esc("box"); print("255 is not void"); -@:box255}{\.{\\box255 is not void}@> - help2("You shouldn't use \box255 except in \output routines.")@/ +@ @<Ensure that box |output_box| is empty before output@>= +if box(output_box)<>null then + begin print_err(""); print_esc("box"); print_int(output_box); print(" is not void"); +@:box\\outputbox}{\.{\\box\\outputbox is not void}@> + help2("You shouldn't use \box\outputbox except in \output routines.")@/ ("Proceed, and I'll discard its present contents."); - box_error(255); + box_error(output_box); end @ @<Update the values of |first_mark| and |bot_mark|@>= @@ -24812,7 +21887,7 @@ if p<>null then save_vbadness:=vbadness; vbadness:=inf_bad; save_vfuzz:=vfuzz; vfuzz:=max_dimen; {inhibit error messages} pack_direction:=body_direction; -box(255):=filtered_vpackage(vlink(page_head),best_size,exactly,page_max_depth,output_group); +box(output_box):=filtered_vpackage(vlink(page_head),best_size,exactly,page_max_depth,output_group); vbadness:=save_vbadness; vfuzz:=save_vfuzz; if last_glue<>max_halfword then delete_glue_ref(last_glue); @<Start a new current page@>; {this sets |last_glue:=max_halfword|} @@ -24912,7 +21987,7 @@ begin if vlink(page_head)<>null then vlink(page_head):=null; page_tail:=page_head; end; flush_node_list(page_disc); page_disc:=null; -ship_out(box(255)); box(255):=null; +ship_out(box(output_box)); box(output_box):=null; end @ @<Explain that too many dead cycles have occurred in a row@>= @@ -24920,14 +21995,14 @@ begin print_err("Output loop---"); print_int(dead_cycles); @.Output loop...@> print(" consecutive dead cycles"); help3("I've concluded that your \output is awry; it never does a")@/ -("\shipout, so I'm shipping \box255 out myself. Next time")@/ +("\shipout, so I'm shipping \box\outputbox out myself. Next time")@/ ("increase \maxdeadcycles if you want me to be more patient!"); error; end @ @<Fire up the user's output routine and |return|@>= begin output_active:=true; incr(dead_cycles); -push_nest; mode:=-vmode; prev_depth:=ignore_depth; mode_line:=-line; +push_nest; mode:=-vmode; prev_depth:=pdf_ignored_dimen; mode_line:=-line; begin_token_list(output_routine,output_text); new_save_level(output_group); normal_paragraph; scan_left_brace; @@ -24943,7 +22018,7 @@ begin if (loc<>null) or @<Recover from an unbalanced output routine@>; end_token_list; {conserve stack space in case more outputs are triggered} end_graf; unsave; output_active:=false; insert_penalties:=0;@/ -@<Ensure that box 255 is empty after output@>; +@<Ensure that box |output_box| is empty after output@>; if tail<>head then {current list goes after heldover insertions} begin vlink(page_tail):=vlink(head); page_tail:=tail; @@ -24955,7 +22030,7 @@ if vlink(page_head)<>null then {and both go before heldover contributions} vlink(page_head):=null; page_tail:=page_head; end; flush_node_list(page_disc); page_disc:=null; -pop_nest; build_page; +pop_nest; check_filter('after_output'); build_page; end @ @<Recover from an unbalanced output routine@>= @@ -24967,15 +22042,15 @@ repeat get_token; until loc=null; end {loops forever if reading from a file, since |null=min_halfword<=0|} -@ @<Ensure that box 255 is empty after output@>= -if box(255)<>null then +@ @<Ensure that box |output_box| is empty after output@>= +if box(output_box)<>null then begin print_err("Output routine didn't use all of "); - print_esc("box"); print_int(255); + print_esc("box"); print_int(output_box); @.Output routine didn't use...@> - help3("Your \output commands should empty \box255,")@/ - ("e.g., by saying `\shipout\box255'.")@/ + help3("Your \output commands should empty \box\outputbox,")@/ + ("e.g., by saying `\shipout\box\outputbox'.")@/ ("Proceed; I'll discard its present contents."); - box_error(255); + box_error(output_box); end @* \[46] The chief executive. @@ -25033,6 +22108,7 @@ label big_switch,reswitch,continue,exit; var@!t,k:integer; {general-purpose temporary variables} p:pointer; {for whatsit nodes and testing whether an auto kern should be inserted} chr_stack:integer; { to temporarily save an |cur_chr| to be appended } +mval:mathcodeval; { to build up an argument to |set_math_char| } begin t:=0; {for -Wall} chr_stack:=-1; if every_job<>null then begin_token_list(every_job,every_job_text); @@ -25059,7 +22135,7 @@ hmode+no_boundary: begin @<Append a |cancel_boundary_node| @>; hmode+char_ghost: begin t:=cur_chr; get_x_token; if (cur_cmd=letter)or(cur_cmd=other_char)or(cur_cmd=char_given)or (cur_cmd=char_num) then begin - p:=new_glyph(cur_font,cur_chr); + p:=new_glyph(cur_font,cur_chr); if t=0 then begin set_is_leftghost(p); end else begin set_is_rightghost(p); end; tail_append(p); @@ -25124,13 +22200,15 @@ if (cur_cmd=letter)or(cur_cmd=other_char)or scan_char_num; cur_chr:=cur_val; end; if (chr_stack=ex_hyphen_char)and(cur_chr<>ex_hyphen_char)and(mode>0) then begin - tail_append(new_disc); subtype(tail):=automatic_disc; + tail:=compound_word_break(tail,cur_lang); + subtype(tail):=automatic_disc; end; goto continue; end else begin if (chr_stack=ex_hyphen_char) and (mode>0) then begin - tail_append(new_disc); subtype(tail):=automatic_disc; + tail:=compound_word_break(tail,cur_lang); + subtype(tail):=automatic_disc; end; chr_stack:=-1; goto reswitch; @@ -25235,6 +22313,7 @@ any_mode(ignore_spaces): begin end; end; vmode+stop: if its_all_over then return; {this is the only way out} +@t\4@>@<Math cases in non-math modes@>; @t\4@>@<Forbidden cases detected in |main_control|@>@+@,any_mode(mac_param): report_illegal_case; @<Math-only cases in non-math modes, or vice versa@>: insert_dollar_sign; @@ -25248,8 +22327,7 @@ mode by mistake. \TeX\ will insert a dollar sign and rescan the current token. @d non_math(#)==vmode+#,hmode+# @<Math-only cases in non-math modes...@>= -non_math(sup_mark), non_math(sub_mark), non_math(math_char_num), -non_math(math_given), non_math(omath_given), +non_math(sup_mark), non_math(sub_mark), non_math(math_comp), non_math(delim_num), non_math(left_right), non_math(above), non_math(radical), non_math(math_style), non_math(math_choice), non_math(vcenter), @@ -25258,6 +22336,36 @@ non_math(mskip), non_math(math_accent), mmode+endv, mmode+par_end, mmode+stop, mmode+vskip, mmode+un_vbox, mmode+valign, mmode+hrule +@ @<Math cases in non-math modes@>= +vmode+math_char_num, vmode+math_given, vmode+omath_given, vmode+xmath_given: begin + back_input; new_graf(true); + end; +hmode+math_char_num: begin + if cur_chr=0 then + mval := scan_mathchar(tex_mathcode) + else if cur_chr=1 then + mval := scan_mathchar(aleph_mathcode) + else if cur_chr=2 then + mval := scan_mathchar(xetex_mathcode) + else + mval := scan_mathchar(xetexnum_mathcode); + math_char_in_text(mval); + end; +hmode+math_given: begin + mval := mathchar_from_integer(cur_chr,tex_mathcode); + math_char_in_text(mval); + end; +hmode+omath_given: begin + mval := mathchar_from_integer(cur_chr,aleph_mathcode); + math_char_in_text(mval); + end; +hmode+xmath_given: begin + mval := mathchar_from_integer(cur_chr,xetex_mathcode); + math_char_in_text(mval); + end + + + @ @<Declare action...@>= procedure insert_dollar_sign; begin back_input; cur_tok:=math_shift_token+"$"; @@ -25317,14 +22425,11 @@ end; endgame, since both of them have `|stop|' as their command code. @<Put each...@>= -primitive("end",stop,0);@/ +primitive_tex("end",stop,0,0);@/ @!@:end_}{\.{\\end} primitive@> -primitive("dump",stop,1);@/ +primitive_tex("dump",stop,1,0);@/ @!@:dump_}{\.{\\dump} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -stop:if chr_code=1 then print_esc("dump")@+else print_esc("end"); - @ We don't want to leave |main_control| immediately when a |stop| command is sensed, because it may be necessary to invoke an \.{\\output} routine several times before things really grind to a halt. (The output routine @@ -25345,7 +22450,7 @@ begin if privileged then width(tail):=hsize; tail_append(new_glue(fill_glue)); tail_append(new_penalty(-@'10000000000));@/ - build_page; {append \.{\\hbox to \\hsize\{\}\\vfill\\penalty-'10000000000}} + check_filter('end'); build_page; {append \.{\\hbox to \\hsize\{\}\\vfill\\penalty-'10000000000}} end; its_all_over:=false; exit:end; @@ -25364,11 +22469,11 @@ is short, since the |scan_rule_spec| routine already does most of what is required; thus, there is no need for a special action procedure. Note that baselineskip calculations are disabled after a rule in vertical -mode, by setting |prev_depth:=ignore_depth|. +mode, by setting |prev_depth:=pdf_ignored_dimen|. @<Cases of |main_control| that build...@>= vmode+hrule,hmode+vrule,mmode+vrule: begin tail_append(scan_rule_spec); - if abs(mode)=vmode then prev_depth:=ignore_depth + if abs(mode)=vmode then prev_depth:=pdf_ignored_dimen else if abs(mode)=hmode then space_factor:=1000; end; @@ -25393,52 +22498,33 @@ The difference is in the value of |cur_chr|. @d mskip_code=5 {identifies \.{\\mskip}} @<Put each...@>= -primitive("hskip",hskip,skip_code);@/ +primitive_tex("hskip",hskip,skip_code,0);@/ @!@:hskip_}{\.{\\hskip} primitive@> -primitive("hfil",hskip,fil_code); +primitive_tex("hfil",hskip,fil_code,0); @!@:hfil_}{\.{\\hfil} primitive@> -primitive("hfill",hskip,fill_code);@/ +primitive_tex("hfill",hskip,fill_code,0);@/ @!@:hfill_}{\.{\\hfill} primitive@> -primitive("hss",hskip,ss_code); +primitive_tex("hss",hskip,ss_code,0); @!@:hss_}{\.{\\hss} primitive@> -primitive("hfilneg",hskip,fil_neg_code);@/ +primitive_tex("hfilneg",hskip,fil_neg_code,0);@/ @!@:hfil_neg_}{\.{\\hfilneg} primitive@> -primitive("vskip",vskip,skip_code);@/ +primitive_tex("vskip",vskip,skip_code,0);@/ @!@:vskip_}{\.{\\vskip} primitive@> -primitive("vfil",vskip,fil_code); +primitive_tex("vfil",vskip,fil_code,0); @!@:vfil_}{\.{\\vfil} primitive@> -primitive("vfill",vskip,fill_code);@/ +primitive_tex("vfill",vskip,fill_code,0);@/ @!@:vfill_}{\.{\\vfill} primitive@> -primitive("vss",vskip,ss_code); +primitive_tex("vss",vskip,ss_code,0); @!@:vss_}{\.{\\vss} primitive@> -primitive("vfilneg",vskip,fil_neg_code);@/ +primitive_tex("vfilneg",vskip,fil_neg_code,0);@/ @!@:vfil_neg_}{\.{\\vfilneg} primitive@> -primitive("mskip",mskip,mskip_code);@/ +primitive_tex("mskip",mskip,mskip_code,0);@/ @!@:mskip_}{\.{\\mskip} primitive@> -primitive("kern",kern,explicit); +primitive_tex("kern",kern,explicit,0); @!@:kern_}{\.{\\kern} primitive@> -primitive("mkern",mkern,mu_glue);@/ +primitive_tex("mkern",mkern,mu_glue,0);@/ @!@:mkern_}{\.{\\mkern} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -hskip: case chr_code of - skip_code:print_esc("hskip"); - fil_code:print_esc("hfil"); - fill_code:print_esc("hfill"); - ss_code:print_esc("hss"); - othercases print_esc("hfilneg") - endcases; -vskip: case chr_code of - skip_code:print_esc("vskip"); - fil_code:print_esc("vfil"); - fill_code:print_esc("vfill"); - ss_code:print_esc("vss"); - othercases print_esc("vfilneg") - endcases; -mskip: print_esc("mskip"); -kern: print_esc("kern"); -mkern: print_esc("mkern"); - @ All the work relating to glue creation has been relegated to the following subroutine. It does not call |build_page|, because it is used in at least one place where that would be a mistake. @@ -25592,7 +22678,8 @@ procedure handle_right_brace; var p,@!q:pointer; {for short-term use} @!d:scaled; {holds |split_max_depth| in |insert_group|} @!f:integer; {holds |floating_penalty| in |insert_group|} -begin case cur_group of +begin p:=null; +case cur_group of simple_group: begin temp_no_whatsits:=no_local_whatsits; temp_no_dirs:=no_local_dirs; @@ -25696,57 +22783,40 @@ where the latter two are used denote \.{\\vbox} and \.{\\hbox}, respectively. @d vtop_code=4 {|chr_code| for `\.{\\vtop}'} @<Put each...@>= -primitive("moveleft",hmove,1); +primitive_tex("moveleft",hmove,1,0); @!@:move_left_}{\.{\\moveleft} primitive@> -primitive("moveright",hmove,0);@/ +primitive_tex("moveright",hmove,0,0);@/ @!@:move_right_}{\.{\\moveright} primitive@> -primitive("raise",vmove,1); +primitive_tex("raise",vmove,1,0); @!@:raise_}{\.{\\raise} primitive@> -primitive("lower",vmove,0); +primitive_tex("lower",vmove,0,0); @!@:lower_}{\.{\\lower} primitive@> @# -primitive("box",make_box,box_code); +primitive_tex("box",make_box,box_code,0); @!@:box_}{\.{\\box} primitive@> -primitive("copy",make_box,copy_code); +primitive_tex("copy",make_box,copy_code,0); @!@:copy_}{\.{\\copy} primitive@> -primitive("lastbox",make_box,last_box_code); +primitive_tex("lastbox",make_box,last_box_code,0); @!@:last_box_}{\.{\\lastbox} primitive@> -primitive("vsplit",make_box,vsplit_code); +primitive_tex("vsplit",make_box,vsplit_code,0); @!@:vsplit_}{\.{\\vsplit} primitive@> -primitive("vtop",make_box,vtop_code);@/ +primitive_tex("vtop",make_box,vtop_code,0);@/ @!@:vtop_}{\.{\\vtop} primitive@> -primitive("vbox",make_box,vtop_code+vmode); +primitive_tex("vbox",make_box,vtop_code+vmode,0); @!@:vbox_}{\.{\\vbox} primitive@> -primitive("hbox",make_box,vtop_code+hmode);@/ +primitive_tex("hbox",make_box,vtop_code+hmode,0);@/ @!@:hbox_}{\.{\\hbox} primitive@> -primitive("shipout",leader_ship,a_leaders-1); {|ship_out_flag=leader_flag-1|} +primitive_tex("shipout",leader_ship,a_leaders-1,0); {|ship_out_flag=leader_flag-1|} @!@:ship_out_}{\.{\\shipout} primitive@> -primitive("leaders",leader_ship,a_leaders); +primitive_tex("leaders",leader_ship,a_leaders,0); @!@:leaders_}{\.{\\leaders} primitive@> -primitive("cleaders",leader_ship,c_leaders); +primitive_tex("cleaders",leader_ship,c_leaders,0); @!@:c_leaders_}{\.{\\cleaders} primitive@> -primitive("xleaders",leader_ship,x_leaders); +primitive_tex("xleaders",leader_ship,x_leaders,0); @!@:x_leaders_}{\.{\\xleaders} primitive@>; -primitive("boxdir",assign_box_dir,0); +primitive_aleph("boxdir",assign_box_dir,0,0); @!@:box_dir}{\.{\\boxdir} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -hmove: if chr_code=1 then print_esc("moveleft")@+else print_esc("moveright"); -vmove: if chr_code=1 then print_esc("raise")@+else print_esc("lower"); -make_box: case chr_code of - box_code: print_esc("box"); - copy_code: print_esc("copy"); - last_box_code: print_esc("lastbox"); - vsplit_code: print_esc("vsplit"); - vtop_code: print_esc("vtop"); - vtop_code+vmode: print_esc("vbox"); - othercases print_esc("hbox") - endcases; -leader_ship: if chr_code=a_leaders then print_esc("leaders") - else if chr_code=c_leaders then print_esc("cleaders") - else if chr_code=x_leaders then print_esc("xleaders") - else print_esc("shipout"); - @ Constructions that require a box are started by calling |scan_box| with a specified context code. The |scan_box| routine verifies that a |make_box| command comes next and then it calls |begin_box|. @@ -25777,7 +22847,6 @@ case can occur only with leaders. @<Declare act...@>= procedure box_end(@!box_context:integer); -var p:pointer; {|ord_noad| for new box in math mode} begin if box_context<box_flag then @<Append box |cur_box| to the current list, shifted by |box_context|@> else if box_context<ship_out_flag then @<Store \(c)|cur_box| in a box register@> @@ -25810,10 +22879,7 @@ begin if cur_box<>null then if mode>0 then begin check_filter('box'); build_page; end; end else begin if abs(mode)=hmode then space_factor:=1000 - else begin p:=new_noad; - math_type(nucleus(p)):=sub_box; - vinfo(nucleus(p)):=cur_box; cur_box:=p; - end; + else cur_box:=new_sub_box(cur_box); vlink(tail):=cur_box; tail:=cur_box; end; end; @@ -25827,8 +22893,7 @@ else geq_define(box_base+box_context-global_box_flag,box_ref,cur_box) @ @<Append a new leader node ...@>= begin @<Get the next non-blank non-relax...@>; if ((cur_cmd=hskip)and(abs(mode)<>vmode))or@| - ((cur_cmd=vskip)and(abs(mode)=vmode))or@| - ((cur_cmd=mskip)and(abs(mode)=mmode)) then + ((cur_cmd=vskip)and(abs(mode)=vmode)) then begin append_glue; subtype(tail):=box_context-(leader_flag-a_leaders); leader_ptr(tail):=cur_box; end @@ -25902,7 +22967,7 @@ done:end @<Split off part of a vertical box, make |cur_box| point to it@>= begin scan_register_num; n:=cur_val; -if not scan_keyword("to") then +if not scan_keyword('to') then @.to@> begin print_err("Missing `to' inserted"); @.Missing `to' inserted@> @@ -25934,7 +22999,7 @@ else begin if k=vmode then scan_spec(vbox_group,true) end; push_nest; mode:=-k; if k=vmode then - begin prev_depth:=ignore_depth; + begin prev_depth:=pdf_ignored_dimen; if every_vbox<>null then begin_token_list(every_vbox,every_vbox_text); end else begin space_factor:=1000; @@ -26015,16 +23080,13 @@ or when the paragraph is explicitly started by `\.{\\quitvmode}', `\.{\\indent}' or `\.{\\noindent}'. @<Put each...@>= -primitive("indent",start_par,1); +primitive_tex("indent",start_par,1,0); @!@:indent_}{\.{\\indent} primitive@> -primitive("noindent",start_par,0); +primitive_tex("noindent",start_par,0,0); @!@:no_indent_}{\.{\\noindent} primitive@> -primitive("quitvmode",start_par,2); +primitive_pdftex("quitvmode",start_par,2,0); @!@:quit_vmode_}{\.{\\quitvmode} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -start_par: if chr_code=0 then print_esc("noindent")@+ else if chr_code=1 then print_esc("indent")@+ else print_esc("quitvmode"); - @ @<Cases of |main_control| that build...@>= vmode+start_par: new_graf(cur_chr>0); vmode+letter,vmode+other_char,vmode+char_num,vmode+char_given, @@ -26041,8 +23103,6 @@ var p,q,dir_graf_tmp:pointer; begin prev_graf:=0; if (mode=vmode)or(head<>tail) then begin tail_append(new_param_glue(par_skip_code)); - if nest_ptr=0 then - check_filter('begin_of_par'); end; push_nest; mode:=hmode; space_factor:=1000; @<LOCAL: Add local paragraph node@>; @@ -26067,7 +23127,7 @@ while vlink(q)<>null do q:=vlink(q); tail:=q; if every_par<>null then begin_token_list(every_par,every_par_text); if nest_ptr=1 then begin - build_page; {put |par_skip| glue on current page} + check_filter('new_graf'); build_page; {put |par_skip| glue on current page} end; end; @@ -26076,13 +23136,11 @@ hmode+start_par,mmode+start_par: if cur_chr<>2 then indent_in_hmode; @ @<Declare act...@>= procedure indent_in_hmode; -var p,@!q:pointer; +var p:pointer; begin if cur_chr>0 then {\.{\\indent}} begin p:=new_null_box; width(p):=par_indent; if abs(mode)=hmode then space_factor:=1000 - else begin q:=new_noad; math_type(nucleus(q)):=sub_box; - vinfo(nucleus(q)):=p; p:=q; - end; + else p:=new_sub_box(p); tail_append(p); end; end; @@ -26098,7 +23156,7 @@ vmode+par_end: begin normal_paragraph; hmode+par_end: begin if align_state<0 then off_save; {this tries to recover from an alignment that didn't end properly} if (mode>0) and (nest[(nest_ptr-1)].mode_field=vmode) then - line_break_context:=bottom_level; + line_break_context:=bottom_level; end_graf; {this takes us to the enclosing mode, if |mode>0|} if mode=vmode then begin check_filter('hmode_par'); build_page; end; end; @@ -26150,23 +23208,23 @@ vmode+vadjust, @ @<Declare act...@>= procedure begin_insert_or_adjust; -begin if cur_cmd=vadjust then cur_val:=255 +begin if cur_cmd=vadjust then cur_val:=output_box else begin scan_register_num; - if cur_val=255 then - begin print_err("You can't "); print_esc("insert"); print_int(255); -@.You can't \\insert255@> - help1("I'm changing to \insert0; box 255 is special."); + if cur_val=output_box then + begin print_err("You can't "); print_esc("insert"); print_int(output_box); +@.You can't \\insert\outputbox@> + help1("I'm changing to \insert0; box \outputbox is special."); error; cur_val:=0; end; end; saved(0) := cur_val; -if (cur_cmd = vadjust) and scan_keyword("pre") then +if (cur_cmd = vadjust) and scan_keyword('pre') then saved(1) := 1 else saved(1) := 0; save_ptr := save_ptr + 2; new_save_level(insert_group); scan_left_brace; normal_paragraph; -push_nest; mode:=-vmode; prev_depth:=ignore_depth; +push_nest; mode:=-vmode; prev_depth:=pdf_ignored_dimen; end; @ @<Cases of |handle...@>= @@ -26174,9 +23232,9 @@ insert_group: begin line_break_context:=insert_group; end_graf; q:=split_top_skip; add_glue_ref(q); d:=split_max_depth; f:=floating_penalty; unsave; save_ptr := save_ptr - 2; - {now |saved(0)| is the insertion number, or 255 for |vadjust|} + {now |saved(0)| is the insertion number, or |output_box| for |vadjust|} p:=vpack(vlink(head),natural); pop_nest; - if saved(0)<>255 then + if saved(0)<>output_box then begin tail_append(new_node(ins_node,saved(0))); height(tail):=height(p)+depth(p); ins_ptr(tail):=list_ptr(p); split_top_ptr(tail):=q; depth(tail):=d; float_cost(tail):=f; @@ -26275,31 +23333,21 @@ begin if (cur_chr<>glue_node)or(last_glue<>max_halfword) then end @ @<Put each...@>= -primitive("unpenalty",remove_item,penalty_node);@/ +primitive_tex("unpenalty",remove_item,penalty_node,0);@/ @!@:un_penalty_}{\.{\\unpenalty} primitive@> -primitive("unkern",remove_item,kern_node);@/ +primitive_tex("unkern",remove_item,kern_node,0);@/ @!@:un_kern_}{\.{\\unkern} primitive@> -primitive("unskip",remove_item,glue_node);@/ +primitive_tex("unskip",remove_item,glue_node,0);@/ @!@:un_skip_}{\.{\\unskip} primitive@> -primitive("unhbox",un_hbox,box_code);@/ +primitive_tex("unhbox",un_hbox,box_code,0);@/ @!@:un_hbox_}{\.{\\unhbox} primitive@> -primitive("unhcopy",un_hbox,copy_code);@/ +primitive_tex("unhcopy",un_hbox,copy_code,0);@/ @!@:un_hcopy_}{\.{\\unhcopy} primitive@> -primitive("unvbox",un_vbox,box_code);@/ +primitive_tex("unvbox",un_vbox,box_code,0);@/ @!@:un_vbox_}{\.{\\unvbox} primitive@> -primitive("unvcopy",un_vbox,copy_code);@/ +primitive_tex("unvcopy",un_vbox,copy_code,0);@/ @!@:un_vcopy_}{\.{\\unvcopy} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -remove_item: if chr_code=glue_node then print_esc("unskip") - else if chr_code=kern_node then print_esc("unkern") - else print_esc("unpenalty"); -un_hbox: if chr_code=copy_code then print_esc("unhcopy") - else print_esc("unhbox"); -un_vbox: if chr_code=copy_code then print_esc("unvcopy") - @<Cases of |un_vbox| for |print_cmd_chr|@>@/ - else print_esc("unvbox"); - @ The |un_hbox| and |un_vbox| commands unwrap one of the |number_regs| current boxes. @<Cases of |main_control| that build...@>= @@ -26373,21 +23421,15 @@ generated by primitive commands. @d explicit_disc=1 @<Put each...@>= -primitive("-",discretionary,explicit_disc); +primitive_tex("-",discretionary,explicit_disc,0); @!@:Single-character primitives -}{\quad\.{\\-}@> -primitive("discretionary",discretionary,discretionary_disc); +primitive_tex("discretionary",discretionary,discretionary_disc,0); @!@:discretionary_}{\.{\\discretionary} primitive@> -primitive("localleftbox",assign_local_box,0); +primitive_omega("localleftbox",assign_local_box,0,0); @!@:assign_local_box}{\.{\\localleftbox} primitive@> -primitive("localrightbox",assign_local_box,1); +primitive_omega("localrightbox",assign_local_box,1,0); @!@:assign_local_box}{\.{\\localrightbox} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -discretionary: if chr_code=explicit_disc then - print_esc("-")@+else print_esc("discretionary"); -assign_local_box: if chr_code=0 then print_esc("localleftbox") - else print_esc("localrightbox"); - @ @<Cases of |main_control| that build...@>= hmode+discretionary,mmode+discretionary: append_discretionary; any_mode(assign_local_box): append_local_box(cur_chr); @@ -26409,9 +23451,9 @@ subtype(tail):=cur_chr; if cur_chr=explicit_disc then begin c:=get_pre_hyphen_char(cur_lang); if c<>0 then begin - vlink(pre_break(tail)):=new_char(cur_font,c); + vlink(pre_break(tail)):=new_char(cur_font,c); alink(vlink(pre_break(tail))):=pre_break(tail); - tlink(pre_break(tail)):=vlink(pre_break(tail)); + tlink(pre_break(tail)):=vlink(pre_break(tail)); end; c:=get_post_hyphen_char(cur_lang); if c<>0 then begin @@ -26516,7 +23558,7 @@ while p<>null do end_diagnostic(true); flush_node_list(p); vlink(q):=null; goto done; end; - q:=p; p:=vlink(q); incr(n); + alink(p):=q; q:=p; p:=vlink(q); incr(n); end; done: @@ -26662,9 +23704,10 @@ Let's take a look at what happens when they are used correctly. @<Cases of |main_control| that build...@>= vmode+halign,hmode+valign:init_align; -mmode+halign: if privileged then +mmode+halign: if privileged then begin if cur_group=math_shift_group then init_align else off_save; + end; vmode+endv,hmode+endv: do_endv; @ An |align_group| code is supposed to remain on the |save_stack| @@ -26717,500 +23760,134 @@ error; end; @* \[48] Building math lists. -The routines that \TeX\ uses to create mlists are similar to those we have -just seen for the generation of hlists and vlists. But it is necessary to -make ``noads'' as well as nodes, so the reader should review the -discussion of math mode data structures before trying to make sense out of -the following program. -Here is a little routine that needs to be done whenever a subformula -is about to be processed. The parameter is a code like |math_group|. - -@<Declare act...@>= -procedure push_math(@!c:group_code); -begin -if math_direction<>text_direction then dir_math_save:=true; -push_nest; mode:=-mmode; incompleat_noad:=null; -@<DIR: |new_save_level| math@>; -end; - -@ We get into math mode from horizontal mode when a `\.\$' (i.e., a -|math_shift| character) is scanned. We must check to see whether this -`\.\$' is immediately followed by another, in case display math mode is -called for. +@ Almost all of this section is now in C, see |math.c|. Let here are just +the definitions of the primitives and the infrastructure hooks into |main_control|, +|print_cmd_chr| and |handle_right_brace|. @<Cases of |main_control| that build...@>= hmode+math_shift:init_math; - -@ @<Declare act...@>= -procedure init_math; -label found,not_found,done; -var w:scaled; {new or partial |pre_display_size|} -@!l:scaled; {new |display_width|} -@!s:scaled; {new |display_indent|} -@!p:pointer; {current node when calculating |pre_display_size|} -@!q:pointer; {glue specification when calculating |pre_display_size|} -@!f:internal_font_number; {font in current |char_node|} -@!n:integer; {scope of paragraph shape specification} -@!v:scaled; {|w| plus possible glue amount} -@!d:scaled; {increment to |v|} -begin get_token; {|get_x_token| would fail on \.{\\ifmmode}\thinspace!} -if (cur_cmd=math_shift)and(mode>0) then @<Go into display math mode@> -else begin back_input; @<Go into ordinary math mode@>; - end; -end; - -@ @<Go into ordinary math mode@>= -begin push_math(math_shift_group); eq_word_define(int_base+cur_fam_code,-1); -if every_math<>null then begin_token_list(every_math,every_math_text); -end - -@ We get into ordinary math mode from display math mode when `\.{\\eqno}' or -`\.{\\leqno}' appears. In such cases |cur_chr| will be 0 or~1, respectively; -the value of |cur_chr| is placed onto |save_stack| for safe keeping. - -@<Cases of |main_control| that build...@>= -mmode+eq_no: if privileged then +mmode+eq_no: if privileged then begin if cur_group=math_shift_group then start_eq_no else off_save; + end; @ @<Put each...@>= -primitive("eqno",eq_no,0); +primitive_tex("eqno",eq_no,0,0); @!@:eq_no_}{\.{\\eqno} primitive@> -primitive("leqno",eq_no,1); +primitive_tex("leqno",eq_no,1,0); @!@:leq_no_}{\.{\\leqno} primitive@> -@ When \TeX\ is in display math mode, |cur_group=math_shift_group|, -so it is not necessary for the |start_eq_no| procedure to test for -this condition. - -@<Declare act...@>= -procedure start_eq_no; -begin saved(0):=cur_chr; incr(save_ptr); -@<Go into ordinary math mode@>; -end; - -@ @<Cases of |print_cmd_chr|...@>= -eq_no:if chr_code=1 then print_esc("leqno")@+else print_esc("eqno"); - @ @<Forbidden...@>=non_math(eq_no), -@ When we enter display math mode, we need to call |line_break| to -process the partial paragraph that has just been interrupted by the -display. Then we can set the proper values of |display_width| and -|display_indent| and |pre_display_size|. - -@<Go into display math mode@>= -begin if head=tail then {`\.{\\noindent\$\$}' or `\.{\$\${ }\$\$}'} - begin pop_nest; w:=-max_dimen; - end -else begin - line_break(true);@/ - @<Calculate the natural width, |w|, by which the characters of the - final line extend to the right of the reference point, - plus two ems; or set |w:=max_dimen| if the non-blank information - on that line is affected by stretching or shrinking@>; - end; -{now we are in vertical mode, working on the list that will contain the display} -@<Calculate the length, |l|, and the shift amount, |s|, of the display lines@>; -push_math(math_shift_group); mode:=mmode; -eq_word_define(int_base+cur_fam_code,-1);@/ -eq_word_define(dimen_base+pre_display_size_code,w); -eq_word_define(dimen_base+display_width_code,l); -eq_word_define(dimen_base+display_indent_code,s); -if every_display<>null then begin_token_list(every_display,every_display_text); -if nest_ptr=1 then begin check_contrib_filter('before_display'); build_page; end; -end - -@ @<Calculate the natural width, |w|, by which...@>= -v:=shift_amount(just_box)+2*quad(cur_font); w:=-max_dimen; -p:=list_ptr(just_box); -while p<>null do - begin @<Let |d| be the natural width of node |p|; - if the node is ``visible,'' |goto found|; - if the node is glue that stretches or shrinks, set |v:=max_dimen|@>; - if v<max_dimen then v:=v+d; - goto not_found; - found: if v<max_dimen then - begin v:=v+d; w:=v; - end - else begin w:=max_dimen; goto done; - end; - not_found: p:=vlink(p); - end; -done: - -@ @<Let |d| be the natural width of node |p|...@>= -if is_char_node(p) then - begin f:=font(p); d:=glyph_width(p); - goto found; - end; -case type(p) of -hlist_node,vlist_node,rule_node: begin d:=width(p); goto found; - end; -margin_kern_node: d:=width(p); -kern_node: d:=width(p); -math_node: d:=surround(p); -glue_node:@<Let |d| be the natural width of this glue; if stretching - or shrinking, set |v:=max_dimen|; |goto found| in the case of leaders@>; -whatsit_node: @<Let |d| be the width of the whatsit |p|@>; -othercases d:=0 -endcases - -@ We need to be careful that |w|, |v|, and |d| do not depend on any |glue_set| -values, since such values are subject to system-dependent rounding. -System-dependent numbers are not allowed to infiltrate parameters like -|pre_display_size|, since \TeX82 is supposed to make the same decisions on all -machines. - -@<Let |d| be the natural width of this glue...@>= -begin q:=glue_ptr(p); d:=width(q); -if glue_sign(just_box)=stretching then - begin if (glue_order(just_box)=stretch_order(q))and@| - (stretch(q)<>0) then - v:=max_dimen; - end -else if glue_sign(just_box)=shrinking then - begin if (glue_order(just_box)=shrink_order(q))and@| - (shrink(q)<>0) then - v:=max_dimen; - end; -if subtype(p)>=a_leaders then goto found; -end - -@ A displayed equation is considered to be three lines long, so we -calculate the length and offset of line number |prev_graf+2|. - -@<Calculate the length, |l|, ...@>= -if par_shape_ptr=null then - if (hang_indent<>0)and@| - (((hang_after>=0)and(prev_graf+2>hang_after))or@| - (prev_graf+1<-hang_after)) then - begin l:=hsize-abs(hang_indent); - if hang_indent>0 then s:=hang_indent@+else s:=0; - end - else begin l:=hsize; s:=0; - end -else begin n:=vinfo(par_shape_ptr); - if prev_graf+2>=n then p:=par_shape_ptr+2*n - else p:=par_shape_ptr+2*(prev_graf+2); - s:=vmem(p-1).sc; l:=vmem(p).sc; - end - -@ Subformulas of math formulas cause a new level of math mode to be entered, -on the semantic nest as well as the save stack. These subformulas arise in -several ways: (1)~A left brace by itself indicates the beginning of a -subformula that will be put into a box, thereby freezing its glue and -preventing line breaks. (2)~A subscript or superscript is treated as a -subformula if it is not a single character; the same applies to -the nucleus of things like \.{\\underline}. (3)~The \.{\\left} primitive -initiates a subformula that will be terminated by a matching \.{\\right}. -The group codes placed on |save_stack| in these three cases are -|math_group|, |math_group|, and |math_left_group|, respectively. - -Here is the code that handles case (1); the other cases are not quite as -trivial, so we shall consider them later. - -@<Cases of |main_control| that build...@>= -mmode+left_brace: begin tail_append(new_noad); - back_input; scan_math(nucleus(tail)); - end; - -@ Recall that the |nucleus|, |subscr|, and |supscr| fields in a noad are -broken down into subfields called |math_type| and either |info| or -|(fam,character)|. The job of |scan_math| is to figure out what to place -in one of these principal fields; it looks at the subformula that -comes next in the input, and places an encoding of that subformula -into a given word of |mem|. - -@d fam_in_range==((cur_fam>=0)and(cur_fam<256)) - -@<Declare act...@>= -@t\4@>@<Declare the function called |fin_mlist|@>@t@>@;@/ - -procedure scan_math(@!p:pointer); -label restart,reswitch,exit; -var c:integer; {math character code} -begin restart:@<Get the next non-blank non-relax...@>; -reswitch:case cur_cmd of -letter,other_char,char_given: begin c:=get_math_code(cur_chr); - if c=@"8000000 then - begin @<Treat |cur_chr| as an active character@>; - goto restart; - end; - end; -char_num: begin scan_char_num; cur_chr:=cur_val; cur_cmd:=char_given; - goto reswitch; - end; -math_char_num: begin - if cur_chr=0 then scan_fifteen_bit_int - else scan_big_fifteen_bit_int; - c:=cur_val; - end; -math_given: begin - c := ((cur_chr div @"1000) * @"1000000) + - (((cur_chr mod @"1000) div @"100) * @"10000) + - (cur_chr mod @"100); - end; -omath_given: begin c:=cur_chr; - end; -delim_num: begin - if cur_chr=0 then scan_twenty_seven_bit_int - else scan_fifty_one_bit_int; - c:=cur_val; - end; -othercases @<Scan a subformula enclosed in braces and |return|@> -endcases;@/ -math_type(p):=math_char; mcharacter(p):=qi(c mod @"10000); -if (c>=var_code)and fam_in_range then fam(p):=cur_fam -else fam(p):=(c div @"10000) mod @"100; -exit:end; - -@ An active character that is an |outer_call| is allowed here. - -@<Treat |cur_chr|...@>= -begin cur_cs:=(cur_chr mod number_active_chars)+active_base; -cur_cmd:=eq_type(cur_cs); cur_chr:=equiv(cur_cs); -x_token; back_input; -end - -@ The pointer |p| is placed on |save_stack| while a complex subformula -is being scanned. - -@<Scan a subformula...@>= -begin back_input; scan_left_brace;@/ -saved(0):=p; incr(save_ptr); push_math(math_group); return; -end - -@ The simplest math formula is, of course, `\.{\${ }\$}', when no noads are -generated. The next simplest cases involve a single character, e.g., -`\.{\$x\$}'. Even though such cases may not seem to be very interesting, -the reader can perhaps understand how happy the author was when `\.{\$x\$}' -was first properly typeset by \TeX. The code in this section was used. -@^Knuth, Donald Ervin@> - -@<Cases of |main_control| that build...@>= +@ @<Cases of |main_control| that build...@>= +mmode+left_brace: math_left_brace; mmode+letter,mmode+other_char,mmode+char_given: set_math_char(get_math_code(cur_chr)); mmode+char_num: begin scan_char_num; cur_chr:=cur_val; set_math_char(get_math_code(cur_chr)); end; mmode+math_char_num: begin - if cur_chr=0 then scan_fifteen_bit_int - else scan_big_fifteen_bit_int; - set_math_char(cur_val); + if cur_chr=0 then + mval := scan_mathchar(tex_mathcode) + else if cur_chr=1 then + mval := scan_mathchar(aleph_mathcode) + else if cur_chr=2 then + mval := scan_mathchar(xetex_mathcode) + else + mval := scan_mathchar(xetexnum_mathcode); + set_math_char(mval); end; mmode+math_given: begin - set_math_char(((cur_chr div @"1000) * @"1000000) + - (((cur_chr mod @"1000) div @"100) * @"10000) + - (cur_chr mod @"100)); + mval := mathchar_from_integer(cur_chr,tex_mathcode); + set_math_char(mval); end; -mmode+omath_given: set_math_char(cur_chr); -mmode+delim_num: begin - if cur_chr=0 then scan_twenty_seven_bit_int - else scan_fifty_one_bit_int; - set_math_char(cur_val); +mmode+omath_given: begin + mval := mathchar_from_integer(cur_chr,aleph_mathcode); + set_math_char(mval); end; - -@ The |set_math_char| procedure creates a new noad appropriate to a given -math code, and appends it to the current mlist. However, if the math code -is sufficiently large, the |cur_chr| is treated as an active character and -nothing is appended. - -@<Declare act...@>= -procedure set_math_char(@!c:integer); -var p:pointer; {the new noad} -begin if c>=@"8000000 then - @<Treat |cur_chr|...@> -else begin p:=new_noad; math_type(nucleus(p)):=math_char; - mcharacter(nucleus(p)):=qi(c mod @"10000); - fam(nucleus(p)):=(c div @"10000) mod @"100; - if c>=var_code then - begin if fam_in_range then fam(nucleus(p)):=cur_fam; - type(p):=ord_noad; - end - else - type(p):=ord_noad+(c div @"1000000); - vlink(tail):=p; tail:=p; +mmode+xmath_given: begin + mval := mathchar_from_integer(cur_chr,xetex_mathcode); + set_math_char(mval); + end; +mmode+delim_num: begin + if cur_chr=0 then + mval := scan_delimiter_as_mathchar(tex_mathcode) + else if cur_chr=1 then + mval := scan_delimiter_as_mathchar(aleph_mathcode) + else + mval := scan_delimiter_as_mathchar(xetex_mathcode); + set_math_char(mval); end; -end; @ Primitive math operators like \.{\\mathop} and \.{\\underline} are given the command code |math_comp|, supplemented by the noad type that they generate. @<Put each...@>= -primitive("mathord",math_comp,ord_noad); +primitive_tex("mathord",math_comp,ord_noad,0); @!@:math_ord_}{\.{\\mathord} primitive@> -primitive("mathop",math_comp,op_noad); +primitive_tex("mathop",math_comp,op_noad,0); @!@:math_op_}{\.{\\mathop} primitive@> -primitive("mathbin",math_comp,bin_noad); +primitive_tex("mathbin",math_comp,bin_noad,0); @!@:math_bin_}{\.{\\mathbin} primitive@> -primitive("mathrel",math_comp,rel_noad); +primitive_tex("mathrel",math_comp,rel_noad,0); @!@:math_rel_}{\.{\\mathrel} primitive@> -primitive("mathopen",math_comp,open_noad); +primitive_tex("mathopen",math_comp,open_noad,0); @!@:math_open_}{\.{\\mathopen} primitive@> -primitive("mathclose",math_comp,close_noad); +primitive_tex("mathclose",math_comp,close_noad,0); @!@:math_close_}{\.{\\mathclose} primitive@> -primitive("mathpunct",math_comp,punct_noad); +primitive_tex("mathpunct",math_comp,punct_noad,0); @!@:math_punct_}{\.{\\mathpunct} primitive@> -primitive("mathinner",math_comp,inner_noad); +primitive_tex("mathinner",math_comp,inner_noad,0); @!@:math_inner_}{\.{\\mathinner} primitive@> -primitive("underline",math_comp,under_noad); +primitive_tex("underline",math_comp,under_noad,0); @!@:underline_}{\.{\\underline} primitive@> -primitive("overline",math_comp,over_noad);@/ +primitive_tex("overline",math_comp,over_noad,0);@/ @!@:overline_}{\.{\\overline} primitive@> -primitive("displaylimits",limit_switch,normal); +primitive_tex("displaylimits",limit_switch,normal,0); @!@:display_limits_}{\.{\\displaylimits} primitive@> -primitive("limits",limit_switch,limits); +primitive_tex("limits",limit_switch,limits,0); @!@:limits_}{\.{\\limits} primitive@> -primitive("nolimits",limit_switch,no_limits); +primitive_tex("nolimits",limit_switch,no_limits,0); @!@:no_limits_}{\.{\\nolimits} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -math_comp: case chr_code of - ord_noad: print_esc("mathord"); - op_noad: print_esc("mathop"); - bin_noad: print_esc("mathbin"); - rel_noad: print_esc("mathrel"); - open_noad: print_esc("mathopen"); - close_noad: print_esc("mathclose"); - punct_noad: print_esc("mathpunct"); - inner_noad: print_esc("mathinner"); - under_noad: print_esc("underline"); - othercases print_esc("overline") - endcases; -limit_switch: if chr_code=limits then print_esc("limits") - else if chr_code=no_limits then print_esc("nolimits") - else print_esc("displaylimits"); - @ @<Cases of |main_control| that build...@>= -mmode+math_comp: begin tail_append(new_noad); - type(tail):=cur_chr; scan_math(nucleus(tail)); - end; +mmode+math_comp: math_math_comp; mmode+limit_switch: math_limit_switch; - -@ @<Declare act...@>= -procedure math_limit_switch; -label exit; -begin if head<>tail then if type(tail)=op_noad then - begin subtype(tail):=cur_chr; return; - end; -print_err("Limit controls must follow a math operator"); -@.Limit controls must follow...@> -help1("I'm ignoring this misplaced \limits or \nolimits command."); error; -exit:end; - -@ Delimiter fields of noads are filled in by the |scan_delimiter| routine. -The first parameter of this procedure is the |mem| address where the -delimiter is to be placed; the second tells if this delimiter follows -\.{\\radical} or not. - -@<Declare act...@>= -procedure scan_delimiter(@!p:pointer;@!r:integer); -begin if r=1 then scan_twenty_seven_bit_int -else if r=2 then scan_fifty_one_bit_int -else begin @<Get the next non-blank non-relax...@>; - case cur_cmd of - letter,other_char: begin - cur_val:=get_del_code_a(cur_chr); cur_val1:=get_del_code_b(cur_chr); - end; - delim_num: if cur_chr=0 then scan_twenty_seven_bit_int - else scan_fifty_one_bit_int; - othercases begin cur_val:=-1; cur_val1:=-1; end; - endcases; - end; -if cur_val<0 then begin @<Report that an invalid delimiter code is being changed - to null; set~|cur_val:=0|@>; - cur_val1:=0; - end; -small_fam(p):=(cur_val div @"10000) mod @"100; -small_char(p):=qi(cur_val mod @"10000); -large_fam(p):=(cur_val1 div @"10000) mod @"100; -large_char(p):=qi(cur_val1 mod @"10000); -end; - -@ @<Report that an invalid delimiter...@>= -begin print_err("Missing delimiter (. inserted)"); -@.Missing delimiter...@> -help6("I was expecting to see something like `(' or `\{' or")@/ - ("`\}' here. If you typed, e.g., `{' instead of `\{', you")@/ - ("should probably delete the `{' by typing `1' now, so that")@/ - ("braces don't get unbalanced. Otherwise just proceed.")@/ - ("Acceptable delimiters are characters whose \delcode is")@/ - ("nonnegative, or you can use `\delimiter <delimiter code>'."); -back_error; cur_val:=0; -end - -@ @<Cases of |main_control| that build...@>= -mmode+radical:math_radical; - -@ @<Declare act...@>= -procedure math_radical; -begin tail_append(new_node(radical_noad,normal)); -vmem(nucleus(tail)).hh:=empty_field; -vmem(subscr(tail)).hh:=empty_field; -vmem(supscr(tail)).hh:=empty_field; -scan_delimiter(left_delimiter(tail),cur_chr+1); -scan_math(nucleus(tail)); -end; - -@ @<Cases of |main_control| that build...@>= +mmode+radical: math_radical; mmode+accent,mmode+math_accent:math_ac; - -@ @<Declare act...@>= -procedure math_ac; -begin if cur_cmd=accent then - @<Complain that the user should have said \.{\\mathaccent}@>; -tail_append(new_node(accent_noad,normal)); -vmem(nucleus(tail)).hh:=empty_field; -vmem(subscr(tail)).hh:=empty_field; -vmem(supscr(tail)).hh:=empty_field; -math_type(accent_chr(tail)):=math_char; -if cur_chr=0 then scan_fifteen_bit_int -else scan_big_fifteen_bit_int; -mcharacter(accent_chr(tail)):=qi(cur_val mod @"1000); -if (cur_val>=var_code)and fam_in_range then fam(accent_chr(tail)):=cur_fam -else fam(accent_chr(tail)):=(cur_val div @"10000) mod @"100; -scan_math(nucleus(tail)); -end; - -@ @<Complain that the user should have said \.{\\mathaccent}@>= -begin print_err("Please use "); print_esc("mathaccent"); -print(" for accents in math mode"); -@.Please use \\mathaccent...@> -help2("I'm changing \accent to \mathaccent here; wish me luck.")@/ - ("(Accents are not the same in formulas as they are in text.)"); -error; -end - -@ @<Cases of |main_control| that build...@>= mmode+vcenter: begin scan_spec(vcenter_group,false); normal_paragraph; - push_nest; mode:=-vmode; prev_depth:=ignore_depth; + push_nest; mode:=-vmode; prev_depth:=pdf_ignored_dimen; if every_vbox<>null then begin_token_list(every_vbox,every_vbox_text); end; @ @<Cases of |handle...@>= vcenter_group: begin line_break_context:=vcenter_group; end_graf; unsave; save_ptr:=save_ptr-2; p:=vpack(vlink(head),saved(1),saved(0)); pop_nest; - tail_append(new_noad); type(tail):=vcenter_noad; - math_type(nucleus(tail)):=sub_box; vinfo(nucleus(tail)):=p; + p:=math_vcenter_group(p); + tail_append(p); end; @ The routine that inserts a |style_node| holds no surprises. @<Put each...@>= -primitive("displaystyle",math_style,display_style); +primitive_tex("displaystyle",math_style,display_style,0); @!@:display_style_}{\.{\\displaystyle} primitive@> -primitive("textstyle",math_style,text_style); +primitive_tex("textstyle",math_style,text_style,0); @!@:text_style_}{\.{\\textstyle} primitive@> -primitive("scriptstyle",math_style,script_style); +primitive_tex("scriptstyle",math_style,script_style,0); @!@:script_style_}{\.{\\scriptstyle} primitive@> -primitive("scriptscriptstyle",math_style,script_script_style); +primitive_tex("scriptscriptstyle",math_style,script_script_style,0); @!@:script_script_style_}{\.{\\scriptscriptstyle} primitive@> - -@ @<Cases of |print_cmd_chr|...@>= -math_style: print_style(chr_code); +primitive_luatex("crampeddisplaystyle",math_style,cramped_display_style,0); +@!@:cramped_display_style_}{\.{\\crampeddisplaystyle} primitive@> +primitive_luatex("crampedtextstyle",math_style,cramped_text_style,0); +@!@:cramped_text_style_}{\.{\\crampedtextstyle} primitive@> +primitive_luatex("crampedscriptstyle",math_style,cramped_script_style,0); +@!@:cramped_script_style_}{\.{\\crampedscriptstyle} primitive@> +primitive_luatex("crampedscriptscriptstyle",math_style,cramped_script_script_style,0); +@!@:cramped_script_script_style_}{\.{\\crampedscriptscriptstyle} primitive@> @ @<Cases of |main_control| that build...@>= mmode+math_style: tail_append(new_style(cur_chr)); @@ -27219,531 +23896,58 @@ mmode+non_script: begin tail_append(new_glue(zero_glue)); end; mmode+math_choice: append_choices; -@ The routine that scans the four mlists of a \.{\\mathchoice} is very -much like the routine that builds discretionary nodes. - -@<Declare act...@>= -procedure append_choices; -begin tail_append(new_choice); incr(save_ptr); saved(-1):=0; -push_math(math_choice_group); scan_left_brace; -end; - @ @<Cases of |handle_right_brace|...@>= math_choice_group: build_choices; -@ @<Declare act...@>= -procedure build_choices; -label exit; -var p:pointer; {the current mlist} -begin @<DIR: |unsave| math@>; p:=fin_mlist(null); -case saved(-1) of -0:display_mlist(tail):=p; -1:text_mlist(tail):=p; -2:script_mlist(tail):=p; -3:begin script_script_mlist(tail):=p; decr(save_ptr); return; - end; -end; {there are no other cases} -incr(saved(-1)); push_math(math_choice_group); scan_left_brace; -exit:end; - -@ Subscripts and superscripts are attached to the previous nucleus by the -@^superscripts@>@^subscripts@> -action procedure called |sub_sup|. We use the facts that |sub_mark=sup_mark+1| -and |subscr(p)=supscr(p)+1|. - -@<Cases of |main_control| that build...@>= +@ @<Cases of |main_control| that build...@>= mmode+sub_mark,mmode+sup_mark: sub_sup; -@ @<Declare act...@>= -procedure sub_sup; -var t:small_number; {type of previous sub/superscript} -@!p:pointer; {field to be filled by |scan_math|} -begin t:=empty; p:=null; -if tail<>head then if scripts_allowed(tail) then - begin p:=supscr(tail)+cur_cmd-sup_mark; {|supscr| or |subscr|} - t:=math_type(p); - end; -if (p=null)or(t<>empty) then @<Insert a dummy noad to be sub/superscripted@>; -scan_math(p); -end; - -@ @<Insert a dummy...@>= -begin tail_append(new_noad); -p:=supscr(tail)+cur_cmd-sup_mark; {|supscr| or |subscr|} -if t<>empty then - begin if cur_cmd=sup_mark then - begin print_err("Double superscript"); -@.Double superscript@> - help1("I treat `x^1^2' essentially like `x^1{}^2'."); - end - else begin print_err("Double subscript"); -@.Double subscript@> - help1("I treat `x_1_2' essentially like `x_1{}_2'."); - end; - error; - end; -end - -@ An operation like `\.{\\over}' causes the current mlist to go into a -state of suspended animation: |incompleat_noad| points to a |fraction_noad| -that contains the mlist-so-far as its numerator, while the denominator -is yet to come. Finally when the mlist is finished, the denominator will -go into the incompleat fraction noad, and that noad will become the -whole formula, unless it is surrounded by `\.{\\left}' and `\.{\\right}' -delimiters. - +@ @d above_code=0 { `\.{\\above}' } @d over_code=1 { `\.{\\over}' } @d atop_code=2 { `\.{\\atop}' } @d delimited_code=3 { `\.{\\abovewithdelims}', etc.} @<Put each...@>= -primitive("above",above,above_code);@/ +primitive_tex("above",above,above_code,0);@/ @!@:above_}{\.{\\above} primitive@> -primitive("over",above,over_code);@/ +primitive_tex("over",above,over_code,0);@/ @!@:over_}{\.{\\over} primitive@> -primitive("atop",above,atop_code);@/ +primitive_tex("atop",above,atop_code,0);@/ @!@:atop_}{\.{\\atop} primitive@> -primitive("abovewithdelims",above,delimited_code+above_code);@/ +primitive_tex("abovewithdelims",above,delimited_code+above_code,0);@/ @!@:above_with_delims_}{\.{\\abovewithdelims} primitive@> -primitive("overwithdelims",above,delimited_code+over_code);@/ +primitive_tex("overwithdelims",above,delimited_code+over_code,0);@/ @!@:over_with_delims_}{\.{\\overwithdelims} primitive@> -primitive("atopwithdelims",above,delimited_code+atop_code); +primitive_tex("atopwithdelims",above,delimited_code+atop_code,0); @!@:atop_with_delims_}{\.{\\atopwithdelims} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -above: case chr_code of - over_code:print_esc("over"); - atop_code:print_esc("atop"); - delimited_code+above_code:print_esc("abovewithdelims"); - delimited_code+over_code:print_esc("overwithdelims"); - delimited_code+atop_code:print_esc("atopwithdelims"); - othercases print_esc("above") - endcases; - @ @<Cases of |main_control| that build...@>= mmode+above: math_fraction; -@ @<Declare act...@>= -procedure math_fraction; -var c:small_number; {the type of generalized fraction we are scanning} -begin c:=cur_chr; -if incompleat_noad<>null then - @<Ignore the fraction operation and complain about this ambiguous case@> -else begin incompleat_noad:=new_node(fraction_noad,normal); - math_type(numerator(incompleat_noad)):=sub_mlist; - vinfo(numerator(incompleat_noad)):=vlink(head); - vmem(denominator(incompleat_noad)).hh:=empty_field; - vmem(left_delimiter(incompleat_noad)).qqqq:=null_delimiter; - vmem(right_delimiter(incompleat_noad)).qqqq:=null_delimiter;@/ - vlink(head):=null; tail:=head; - @<Use code |c| to distinguish between generalized fractions@>; - end; -end; - -@ @<Use code |c|...@>= -if c>=delimited_code then - begin scan_delimiter(left_delimiter(incompleat_noad),false); - scan_delimiter(right_delimiter(incompleat_noad),false); - end; -case c mod delimited_code of -above_code: begin scan_normal_dimen; - thickness(incompleat_noad):=cur_val; - end; -over_code: thickness(incompleat_noad):=default_code; -atop_code: thickness(incompleat_noad):=0; -end {there are no other cases} - -@ @<Ignore the fraction...@>= -begin if c>=delimited_code then - begin scan_delimiter(garbage,false); scan_delimiter(garbage,false); - end; -if c mod delimited_code=above_code then scan_normal_dimen; -print_err("Ambiguous; you need another { and }"); -@.Ambiguous...@> -help3("I'm ignoring this fraction specification, since I don't")@/ - ("know whether a construction like `x \over y \over z'")@/ - ("means `{x \over y} \over z' or `x \over {y \over z}'."); -error; -end - -@ At the end of a math formula or subformula, the |fin_mlist| routine is -called upon to return a pointer to the newly completed mlist, and to -pop the nest back to the enclosing semantic level. The parameter to -|fin_mlist|, if not null, points to a |right_noad| that ends the -current mlist; this |right_noad| has not yet been appended. - -@<Declare the function called |fin_mlist|@>= -function fin_mlist(@!p:pointer):pointer; -var q:pointer; {the mlist to return} -begin if incompleat_noad<>null then @<Compleat the incompleat noad@> -else begin vlink(tail):=p; q:=vlink(head); - end; -pop_nest; fin_mlist:=q; -end; - -@ @<Compleat...@>= -begin math_type(denominator(incompleat_noad)):=sub_mlist; -vinfo(denominator(incompleat_noad)):=vlink(head); -if p=null then q:=incompleat_noad -else begin q:=vinfo(numerator(incompleat_noad)); - if (type(q)<>left_noad)or(delim_ptr=null) then confusion("right"); -@:this can't happen right}{\quad right@> - vinfo(numerator(incompleat_noad)):=vlink(delim_ptr); - vlink(delim_ptr):=incompleat_noad; vlink(incompleat_noad):=p; - end; -end - -@ Now at last we're ready to see what happens when a right brace occurs -in a math formula. Two special cases are simplified here: Braces are effectively -removed when they surround a single Ord without sub/superscripts, or when they -surround an accent that is the nucleus of an Ord atom. - -@<Cases of |handle...@>= -math_group: begin @<DIR: |unsave| math@>; decr(save_ptr);@/ - math_type(saved(0)):=sub_mlist; p:=fin_mlist(null); vinfo(saved(0)):=p; - if p<>null then if vlink(p)=null then - if type(p)=ord_noad then - begin if math_type(subscr(p))=empty then - if math_type(supscr(p))=empty then - begin vmem(saved(0)).hh:=vmem(nucleus(p)).hh; - flush_node(p); - end; - end - else if type(p)=accent_noad then if saved(0)=nucleus(tail) then - if type(tail)=ord_noad then @<Replace the tail of the list by |p|@>; - end; - -@ @<Replace the tail...@>= -begin q:=head; while vlink(q)<>tail do q:=vlink(q); -vlink(q):=p; flush_node(tail); tail:=p; -end +@ @<Cases of |handle...@>= +math_group: close_math_group(p); -@ We have dealt with all constructions of math mode except `\.{\\left}' and -`\.{\\right}', so the picture is completed by the following sections of -the program. +@ @<Put each...@>= -primitive("left",left_right,left_noad); +primitive_tex("left",left_right,left_noad_side,0); @!@:left_}{\.{\\left} primitive@> -primitive("right",left_right,right_noad); +primitive_tex("right",left_right,right_noad_side,0); @!@:right_}{\.{\\right} primitive@> +primitive_tex("middle",left_right,middle_noad_side,0); +@!@:middle_}{\.{\\middle} primitive@> text(frozen_right):="right"; eqtb[frozen_right]:=eqtb[cur_val]; -@ @<Cases of |print_cmd_chr|...@>= -left_right: if chr_code=left_noad then print_esc("left") -@/@<Cases of |left_right| for |print_cmd_chr|@>@/ -else print_esc("right"); - @ @<Cases of |main_control| that build...@>= mmode+left_right: math_left_right; -@ @<Declare act...@>= -procedure math_left_right; -var t:small_number; {|left_noad| or |right_noad|} -@!p:pointer; {new noad} -@!q:pointer; {resulting mlist} -begin t:=cur_chr; -if (t<>left_noad)and(cur_group<>math_left_group) then - @<Try to recover from mismatched \.{\\right}@> -else begin p:=new_noad; type(p):=t; - scan_delimiter(delimiter(p),false); - if t=middle_noad then - begin type(p):=right_noad; subtype(p):=middle_noad; - end; - if t=left_noad then q:=p - else begin q:=fin_mlist(p); - @<DIR: |unsave| math@>; {end of |math_left_group|} - end; - if t<>right_noad then - begin push_math(math_left_group); vlink(head):=q; tail:=p; - delim_ptr:=p; - end - else begin - tail_append(new_noad); type(tail):=inner_noad; - math_type(nucleus(tail)):=sub_mlist; - vinfo(nucleus(tail)):=q; - end; - end; -end; - -@ @<Try to recover from mismatch...@>= -begin if cur_group=math_shift_group then - begin scan_delimiter(garbage,false); - print_err("Extra "); - if t=middle_noad then - begin print_esc("middle"); -@.Extra \\middle.@> - help1("I'm ignoring a \middle that had no matching \left."); - end - else begin print_esc("right"); -@.Extra \\right.@> - help1("I'm ignoring a \right that had no matching \left."); - end; - error; - end -else off_save; -end - @ Here is the only way out of math mode. @<Cases of |main_control| that build...@>= mmode+math_shift: if cur_group=math_shift_group then after_math else off_save; -@ @<Declare act...@>= -procedure after_math; -var l:boolean; {`\.{\\leqno}' instead of `\.{\\eqno}'} -@!danger:boolean; {not enough symbol fonts are present} -@!m:integer; {|mmode| or |-mmode|} -@!p:pointer; {the formula} -@!a:pointer; {box containing equation number} -@<Local variables for finishing a displayed formula@>@; -begin danger:=false; -@<Check that the necessary fonts for math symbols are present; - if not, flush the current math lists and set |danger:=true|@>; -m:=mode; l:=false; p:=fin_mlist(null); {this pops the nest} -if mode=-m then {end of equation number} - begin @<Check that another \.\$ follows@>; - cur_mlist:=p; cur_style:=text_style; mlist_penalties:=false; - mlist_to_hlist; a:=hpack(vlink(temp_head),natural); - @<DIR: |unsave| math@>; - decr(save_ptr); {now |cur_group=math_shift_group|} - if saved(0)=1 then l:=true; - danger:=false; - @<Check that the necessary fonts for math symbols are present; - if not, flush the current math lists and set |danger:=true|@>; - m:=mode; p:=fin_mlist(null); - end -else a:=null; -if m<0 then @<Finish math in text@> -else begin if a=null then @<Check that another \.\$ follows@>; - @<Finish displayed math@>; - end; -end; - -@ @<Check that the necessary fonts...@>= -if (font_params(fam_fnt(2+text_size))<total_mathsy_params)or@| - (font_params(fam_fnt(2+script_size))<total_mathsy_params)or@| - (font_params(fam_fnt(2+script_script_size))<total_mathsy_params) then - begin print_err("Math formula deleted: Insufficient symbol fonts");@/ -@.Math formula deleted...@> - help3("Sorry, but I can't typeset math unless \textfont 2")@/ - ("and \scriptfont 2 and \scriptscriptfont 2 have all")@/ - ("the \fontdimen values needed in math symbol fonts."); - error; flush_math; danger:=true; - end -else if (font_params(fam_fnt(3+text_size))<total_mathex_params)or@| - (font_params(fam_fnt(3+script_size))<total_mathex_params)or@| - (font_params(fam_fnt(3+script_script_size))<total_mathex_params) then - begin print_err("Math formula deleted: Insufficient extension fonts");@/ - help3("Sorry, but I can't typeset math unless \textfont 3")@/ - ("and \scriptfont 3 and \scriptscriptfont 3 have all")@/ - ("the \fontdimen values needed in math extension fonts."); - error; flush_math; danger:=true; - end - -@ The |unsave| is done after everything else here; hence an appearance of -`\.{\\mathsurround}' inside of `\.{\$...\$}' affects the spacing at these -particular \.\$'s. This is consistent with the conventions of -`\.{\$\$...\$\$}', since `\.{\\abovedisplayskip}' inside a display affects the -space above that display. - -@<Finish math in text@> = -begin tail_append(new_math(math_surround,before)); -if dir_math_save then - @<Append a begin direction to the tail of the current list@>; -cur_mlist:=p; cur_style:=text_style; mlist_penalties:=(mode>0); mlist_to_hlist; -vlink(tail):=vlink(temp_head); -while vlink(tail)<>null do tail:=vlink(tail); -if dir_math_save then - @<Append an end direction to the tail of the current list@>; -dir_math_save:=false; -tail_append(new_math(math_surround,after)); -space_factor:=1000; -@<DIR: |unsave| math@>; -end - -@ \TeX\ gets to the following part of the program when the first `\.\$' ending -a display has been scanned. - -@<Check that another \.\$ follows@>= -begin get_x_token; -if cur_cmd<>math_shift then - begin print_err("Display math should end with $$"); -@.Display math...with \$\$@> - help2("The `$' that I just saw supposedly matches a previous `$$'.")@/ - ("So I shall assume that you typed `$$' both times."); - back_error; - end; -end - -@ We have saved the worst for last: The fussiest part of math mode processing -occurs when a displayed formula is being centered and placed with an optional -equation number. - -@<Local variables for finishing...@>= -@!b:pointer; {box containing the equation} -@!w:scaled; {width of the equation} -@!z:scaled; {width of the line} -@!e:scaled; {width of equation number} -@!q:scaled; {width of equation number plus space to separate from equation} -@!d:scaled; {displacement of equation in the line} -@!s:scaled; {move the line right this much} -@!g1,@!g2:small_number; {glue parameter codes for before and after} -@!r:pointer; {kern node used to position the display} -@!t:pointer; {tail of adjustment list} -@!pre_t:pointer; {tail of pre-adjustment list} - -@ At this time |p| points to the mlist for the formula; |a| is either -|null| or it points to a box containing the equation number; and we are in -vertical mode (or internal vertical mode). - -@<Finish displayed math@>= -cur_mlist:=p; cur_style:=display_style; mlist_penalties:=false; -mlist_to_hlist; p:=vlink(temp_head);@/ -adjust_tail:=adjust_head; pre_adjust_tail:=pre_adjust_head; -b:=hpack(p,natural); p:=list_ptr(b); -t:=adjust_tail; adjust_tail:=null;@/ -pre_t:=pre_adjust_tail; pre_adjust_tail:=null;@/ -w:=width(b); z:=display_width; s:=display_indent; -if (a=null)or danger then - begin e:=0; q:=0; - end -else begin e:=width(a); q:=e+math_quad(text_size); - end; -if w+q>z then - @<Squeeze the equation as much as possible; if there is an equation - number that should go on a separate line by itself, - set~|e:=0|@>; -@<Determine the displacement, |d|, of the left edge of the equation, with - respect to the line size |z|, assuming that |l=false|@>; -@<Append the glue or equation number preceding the display@>; -@<Append the display and perhaps also the equation number@>; -@<Append the glue or equation number following the display@>; -resume_after_display - -@ @<Declare act...@>= -procedure resume_after_display; -begin if cur_group<>math_shift_group then confusion("display"); -@:this can't happen display}{\quad display@> -@<DIR: |unsave| math@>; -prev_graf:=prev_graf+3; -push_nest; mode:=hmode; space_factor:=1000; -@<LOCAL: Add local paragraph node@>; -@<Scan an optional space@>; -if nest_ptr=1 then begin check_filter('after_display'); build_page; end; -end; - -@ The user can force the equation number to go on a separate line -by causing its width to be zero. - -@<Squeeze the equation as much as possible...@>= -begin if (e<>0)and((w-total_shrink[normal]+q<=z)or@| - (total_shrink[sfi]<>0)or(total_shrink[fil]<>0)or - (total_shrink[fill]<>0)or(total_shrink[filll]<>0)) then - begin list_ptr(b):=null; flush_node(b); - b:=hpack(p,z-q,exactly); - end -else begin e:=0; - if w>z then - begin - list_ptr(b):=null; flush_node(b); - b:=hpack(p,z,exactly); - end; - end; -w:=width(b); -end - -@ We try first to center the display without regard to the existence of -the equation number. If that would make it too close (where ``too close'' -means that the space between display and equation number is less than the -width of the equation number), we either center it in the remaining space -or move it as far from the equation number as possible. The latter alternative -is taken only if the display begins with glue, since we assume that the -user put glue there to control the spacing precisely. - -@<Determine the displacement, |d|, of the left edge of the equation...@>= -d:=half(z-w); -if (e>0)and(d<2*e) then {too close} - begin d:=half(z-w-e); - if p<>null then if not is_char_node(p) then if type(p)=glue_node then d:=0; - end - -@ If the equation number is set on a line by itself, either before or -after the formula, we append an infinite penalty so that no page break will -separate the display from its number; and we use the same size and -displacement for all three potential lines of the display, even though -`\.{\\parshape}' may specify them differently. - -@<Append the glue or equation number preceding the display@>= -tail_append(new_penalty(pre_display_penalty));@/ -if (d+s<=pre_display_size)or l then {not enough clearance} - begin g1:=above_display_skip_code; g2:=below_display_skip_code; - end -else begin g1:=above_display_short_skip_code; - g2:=below_display_short_skip_code; - end; -if l and(e=0) then {it follows that |type(a)=hlist_node|} - begin shift_amount(a):=s; append_to_vlist(a); - tail_append(new_penalty(inf_penalty)); - end -else tail_append(new_param_glue(g1)) - -@ @<Append the display and perhaps also the equation number@>= -if e<>0 then - begin r:=new_kern(z-w-e-d); - if l then - begin vlink(a):=r; vlink(r):=b; b:=a; d:=0; - end - else begin vlink(b):=r; vlink(r):=a; - end; - b:=hpack(b,natural); - end; -shift_amount(b):=s+d; append_to_vlist(b) - -@ @<Append the glue or equation number following the display@>= -if (a<>null)and(e=0)and not l then - begin tail_append(new_penalty(inf_penalty)); - shift_amount(a):=s+z-width(a); - append_to_vlist(a); - g2:=0; - end; -if t<>adjust_head then {migrating material comes after equation number} - begin vlink(tail):=vlink(adjust_head); tail:=t; - end; -if pre_t<>pre_adjust_head then - begin vlink(tail):=vlink(pre_adjust_head); tail:=pre_t; - end; -tail_append(new_penalty(post_display_penalty)); -if g2>0 then tail_append(new_param_glue(g2)) - -@ When \.{\\halign} appears in a display, the alignment routines operate -essentially as they do in vertical mode. Then the following program is -activated, with |p| and |q| pointing to the beginning and end of the -resulting list, and with |aux_save| holding the |prev_depth| value. - -@<Finish an alignment in a display@>= -begin do_assignments; -if cur_cmd<>math_shift then @<Pontificate about improper alignment in display@> -else @<Check that another \.\$ follows@>; -pop_nest; -tail_append(new_penalty(pre_display_penalty)); -tail_append(new_param_glue(above_display_skip_code)); -vlink(tail):=p; -if p<>null then tail:=q; -tail_append(new_penalty(post_display_penalty)); -tail_append(new_param_glue(below_display_skip_code)); -prev_depth:=aux_save.sc; resume_after_display; -end - -@ @<Pontificate...@>= -begin print_err("Missing $$ inserted"); -@.Missing {\$\$} inserted@> -help2("Displays can use special alignments (like \eqalignno)")@/ - ("only if nothing but the alignment itself is between $$'s."); -back_error; -end @* \[49] Mode-independent processing. The long |main_control| procedure has now been fully specified, except for @@ -27761,31 +23965,21 @@ by adding the corresponding codes. (\PASCAL's |set| operations could also have been used.) @<Put each...@>= -primitive("long",prefix,1); +primitive_tex("long",prefix,1,0); @!@:long_}{\.{\\long} primitive@> -primitive("outer",prefix,2); +primitive_tex("outer",prefix,2,0); @!@:outer_}{\.{\\outer} primitive@> -primitive("global",prefix,4); +primitive_tex("global",prefix,4,0); @!@:global_}{\.{\\global} primitive@> -primitive("def",def,0); +primitive_tex("def",def,0,0); @!@:def_}{\.{\\def} primitive@> -primitive("gdef",def,1); +primitive_tex("gdef",def,1,0); @!@:gdef_}{\.{\\gdef} primitive@> -primitive("edef",def,2); +primitive_tex("edef",def,2,0); @!@:edef_}{\.{\\edef} primitive@> -primitive("xdef",def,3); +primitive_tex("xdef",def,3,0); @!@:xdef_}{\.{\\xdef} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -prefix: if chr_code=1 then print_esc("long") - else if chr_code=2 then print_esc("outer") - @/@<Cases of |prefix| for |print_cmd_chr|@>@/ - else print_esc("global"); -def: if chr_code=0 then print_esc("def") - else if chr_code=1 then print_esc("gdef") - else if chr_code=2 then print_esc("edef") - else print_esc("xdef"); - @ Every prefix, and every command code that might or might not be prefixed, calls the action procedure |prefixed_command|. This routine accumulates a sequence of prefixes until coming to a non-prefix, then it carries out @@ -27807,13 +24001,18 @@ any_mode(set_prev_graf), any_mode(set_page_dimen), any_mode(set_page_int), any_mode(set_box_dimen), -any_mode(set_shape), -any_mode(def_code), -any_mode(extdef_code), +any_mode(set_tex_shape), +any_mode(set_etex_shape), +any_mode(def_char_code), +any_mode(def_del_code), +any_mode(extdef_math_code), +any_mode(extdef_del_code), any_mode(def_family), +any_mode(set_math_param), any_mode(set_font), any_mode(def_font), any_mode(letterspace_font), +any_mode(pdf_copy_font), any_mode(register), any_mode(advance), any_mode(multiply), @@ -27849,6 +24048,7 @@ var a:small_number; {accumulated prefix codes so far} @!p,@!q:pointer; {for temporary short-term use} @!n:integer; {ditto} @!e:boolean; {should a definition be expanded? or was \.{\\let} not done?} +@!mval:mathcodeval; {for handling of \.{\\mathchardef}s} begin a:=0; while cur_cmd=prefix do begin if not odd(a div cur_chr) then a:=a+cur_chr; @@ -27871,7 +24071,7 @@ exit:end; begin print_err("You can't use a prefix with `"); @.You can't use a prefix with x@> print_cmd_chr(cur_cmd,cur_chr); print_char("'"); -help1("I'll pretend you didn't say \long or \outer or \global."); +help1("I'll pretend you didn't say \long or \outer or \global or \protected."); back_error; return; end @@ -27895,10 +24095,6 @@ since the following routines test for the \.{\\global} prefix as follows. @d global==(a>=4) @d define(#)==if global then geq_define(#)@+else eq_define(#) @d word_define(#)==if global then geq_word_define(#)@+else eq_word_define(#) -@d define_math_code(#)==if global - then set_math_code(#,level_one)@+else set_math_code(#,cur_level) -@d define_del_code(#)==if global - then set_del_code(#,level_one)@+else set_del_code(#,cur_level) @d define_lc_code(#)==if global then set_lc_code(#,level_one)@+else set_lc_code(#,cur_level) @d define_uc_code(#)==if global @@ -27907,6 +24103,11 @@ since the following routines test for the \.{\\global} prefix as follows. then set_sf_code(#,level_one)@+else set_sf_code(#,cur_level) @d define_cat_code(#)==if global then set_cat_code(cat_code_table,#,level_one)@+else set_cat_code(cat_code_table,#,cur_level) +@d define_fam_fnt(#)==if global + then def_fam_fnt(#,level_one)@+else def_fam_fnt(#,cur_level) +@d define_math_param(#)==if global + then def_math_param(#,level_one)@+else def_math_param(#,cur_level) + @<Adjust \(f)for the setting of \.{\\globaldefs}@>= if global_defs<>0 then @@ -27952,17 +24153,76 @@ function is_dim_assign(cmd:halfword):boolean; begin is_dim_assign := (cmd=assign_dimen); end; -procedure assign_internal_int(cmd:halfword;value:integer); -var a:small_number; -begin - a:=0; - word_define(cmd,value); -end; -procedure assign_internal_dim(cmd:halfword;value:integer); -var a:small_number; + +@ @<Declare subprocedures for |prefixed_command|@>= +procedure assign_internal_value(a:small_number;p:halfword;cur_val:integer); +var n:halfword; begin - a:=0; - word_define(cmd,value); +if (p>=int_base)and(p<attribute_base) then begin + if p=(int_base+cat_code_table_code) then begin + if valid_catcode_table(cur_val) then begin + if cur_val<>cat_code_table then + word_define(p,cur_val); + end + else begin + print_err("Invalid \catcode table"); + help2("You can only switch to a \catcode table that is initialized") + ("using \savecatcodetable or \initcatcodetable, or to table 0"); + error; + end; + end + else if (p=(int_base+output_box_code)and((cur_val>65535)or(cur_val<0))) then begin + print_err("Invalid \outputbox"); + help1("The value for \outputbox has to be between 0 and 65535."); + error; + end + else if ((p=new_line_char)and((cur_val>127)or(cur_val<0))) then begin + print_err("Invalid \newlinechar"); + help1("The value for \newlinechar has to be between 0 and 127."); + error; + end + else if p=end_line_char then begin + if (cur_val<0)or(cur_val>biggest_char) then + word_define(p,-1) + else + word_define(p,13); + end + else + word_define(p,cur_val); +{If we are defining subparagraph penalty levels while we are +in hmode, then we put out a whatsit immediately, otherwise +we leave it alone. This mechanism might not be sufficiently +powerful, and some other algorithm, searching down the stack, +might be necessary. Good first step.} + if (abs(mode)=hmode) and + ((p=(int_base+local_inter_line_penalty_code)) or + (p=(int_base+local_broken_penalty_code))) then begin + @<LOCAL: Add local paragraph node@>; + eq_word_define(int_base+no_local_whatsits_code,no_local_whatsits+1); + end; + if p=int_base+language_code then word_define(int_base+cur_lang_code,cur_val); + end +else if (p>=dimen_base)and(p<eqtb_size) then begin + if p=(dimen_base+page_left_offset_code) then begin + n:=cur_val - one_inch; + word_define(dimen_base+h_offset_code, n); + end + else if p=(dimen_base+h_offset_code) then begin + n:=cur_val + one_inch; + word_define(dimen_base+page_left_offset_code, n); + end + else if p=(dimen_base+page_top_offset_code) then begin + n:=cur_val - one_inch; + word_define(dimen_base+v_offset_code, n); + end + else if p=(dimen_base+v_offset_code) then begin + n:=cur_val + one_inch; + word_define(dimen_base+page_top_offset_code, n); + end; + word_define(p,cur_val); + end +else + confusion("assign internal value"); end; @@ -27990,14 +24250,11 @@ def: begin if odd(cur_chr)and not global and(global_defs>=0) then a:=a+4; @ Both \.{\\let} and \.{\\futurelet} share the command code |let|. @<Put each...@>= -primitive("let",let,normal);@/ +primitive_tex("let",let,normal,0);@/ @!@:let_}{\.{\\let} primitive@> -primitive("futurelet",let,normal+1);@/ +primitive_tex("futurelet",let,normal+1,0);@/ @!@:future_let_}{\.{\\futurelet} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -let: if chr_code<>normal then print_esc("futurelet")@+else print_esc("let"); - @ @<Assignments@>= let: begin n:=cur_chr; get_r_token; p:=cur_cs; @@ -28026,52 +24283,36 @@ corresponding |chr| is the |eqtb| location of the internal register in question. @d char_def_code=0 {|shorthand_def| for \.{\\chardef}} @d math_char_def_code=1 {|shorthand_def| for \.{\\mathchardef}} @d omath_char_def_code=2 {|shorthand_def| for \.{\\omathchardef}} -@d count_def_code=3 {|shorthand_def| for \.{\\countdef}} -@d attribute_def_code=4 {|shorthand_def| for \.{\\attributedef}} -@d dimen_def_code=5 {|shorthand_def| for \.{\\dimendef}} -@d skip_def_code=6 {|shorthand_def| for \.{\\skipdef}} -@d mu_skip_def_code=7 {|shorthand_def| for \.{\\muskipdef}} -@d toks_def_code=8 {|shorthand_def| for \.{\\toksdef}} +@d xmath_char_def_code=3 {|shorthand_def| for \.{\\Umathchardef}} +@d count_def_code=4 {|shorthand_def| for \.{\\countdef}} +@d attribute_def_code=5 {|shorthand_def| for \.{\\attributedef}} +@d dimen_def_code=6 {|shorthand_def| for \.{\\dimendef}} +@d skip_def_code=7 {|shorthand_def| for \.{\\skipdef}} +@d mu_skip_def_code=8 {|shorthand_def| for \.{\\muskipdef}} +@d toks_def_code=9 {|shorthand_def| for \.{\\toksdef}} @<Put each...@>= -primitive("chardef",shorthand_def,char_def_code);@/ +primitive_tex("chardef",shorthand_def,char_def_code,0);@/ @!@:char_def_}{\.{\\chardef} primitive@> -primitive("mathchardef",shorthand_def,math_char_def_code);@/ +primitive_tex("mathchardef",shorthand_def,math_char_def_code,0);@/ @!@:math_char_def_}{\.{\\mathchardef} primitive@> -primitive("omathchardef",shorthand_def,omath_char_def_code);@/ +primitive_omega("omathchardef",shorthand_def,omath_char_def_code,0);@/ @!@:math_char_def_}{\.{\\omathchardef} primitive@> -primitive("countdef",shorthand_def,count_def_code);@/ +primitive_luatex("Umathchardef",shorthand_def,xmath_char_def_code,0);@/ +@!@:math_char_def_}{\.{\\Umathchardef} primitive@> +primitive_tex("countdef",shorthand_def,count_def_code,0);@/ @!@:count_def_}{\.{\\countdef} primitive@> -primitive("attributedef",shorthand_def,attribute_def_code);@/ +primitive_luatex("attributedef",shorthand_def,attribute_def_code,0);@/ @!@:attribute_def_}{\.{\\attributedef} primitive@> -primitive("dimendef",shorthand_def,dimen_def_code);@/ +primitive_tex("dimendef",shorthand_def,dimen_def_code,0);@/ @!@:dimen_def_}{\.{\\dimendef} primitive@> -primitive("skipdef",shorthand_def,skip_def_code);@/ +primitive_tex("skipdef",shorthand_def,skip_def_code,0);@/ @!@:skip_def_}{\.{\\skipdef} primitive@> -primitive("muskipdef",shorthand_def,mu_skip_def_code);@/ +primitive_tex("muskipdef",shorthand_def,mu_skip_def_code,0);@/ @!@:mu_skip_def_}{\.{\\muskipdef} primitive@> -primitive("toksdef",shorthand_def,toks_def_code);@/ +primitive_tex("toksdef",shorthand_def,toks_def_code,0);@/ @!@:toks_def_}{\.{\\toksdef} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -shorthand_def: case chr_code of - char_def_code: print_esc("chardef"); - math_char_def_code: print_esc("mathchardef"); - omath_char_def_code: print_esc("omathchardef"); - count_def_code: print_esc("countdef"); - attribute_def_code: print_esc("attributedef"); - dimen_def_code: print_esc("dimendef"); - skip_def_code: print_esc("skipdef"); - mu_skip_def_code: print_esc("muskipdef"); - othercases print_esc("toksdef") - endcases; -char_given: begin print_esc("char"); print_hex(chr_code); - end; -math_given: begin print_esc("mathchar"); print_hex(chr_code); - end; -omath_given: begin print_esc("omathchar"); print_hex(chr_code); - end; - @ We temporarily define |p| to be |relax|, so that an occurrence of |p| while scanning the definition will simply stop the scanning instead of producing an ``undefined control sequence'' error or expanding the @@ -28083,12 +24324,21 @@ shorthand_def: begin n:=cur_chr; get_r_token; p:=cur_cs; case n of char_def_code: begin scan_char_num; define(p,char_given,cur_val); end; - math_char_def_code: begin scan_real_fifteen_bit_int; + math_char_def_code: begin + mval:=scan_mathchar(tex_mathcode); + cur_val:=(mval.class_value*16+mval.family_value)*256+mval.character_value; define(p,math_given,cur_val); end; - omath_char_def_code: begin scan_big_fifteen_bit_int; + omath_char_def_code: begin + mval:=scan_mathchar(aleph_mathcode); + cur_val:=(mval.class_value*256+mval.family_value)*65536+mval.character_value; define(p,omath_given,cur_val); end; + xmath_char_def_code: begin + mval:=scan_mathchar(xetex_mathcode); + cur_val:=(mval.class_value+(8*mval.family_value))*(65536*32)+mval.character_value; + define(p,xmath_given,cur_val); + end; othercases begin scan_register_num; case n of count_def_code: define(p,assign_int,count_base+cur_val); @@ -28104,7 +24354,8 @@ shorthand_def: begin n:=cur_chr; get_r_token; p:=cur_cs; @ @<Assignments@>= read_to_cs: begin j:=cur_chr; scan_int; n:=cur_val; - if not scan_keyword("to") then + if not scan_keyword('to') then +@.to@> begin print_err("Missing `to' inserted"); @.Missing `to'...@> help2("You should have said `\read<number> to \cs'.")@/ @@ -28160,45 +24411,8 @@ end @<Assignments@>= assign_int: begin p:=cur_chr; scan_optional_equals; scan_int; - if p=(int_base+cat_code_table_code) then begin - if valid_catcode_table(cur_val) then begin - if cur_val<>cat_code_table then - word_define(p,cur_val); - end - else begin - print_err("Invalid \catcode table"); - help2("You can only switch to a \catcode table that is initialized") - ("using \savecatcodetable or \initcatcodetable, or to table 0"); - error; - end; - end - else if (p=new_line_char)and(cur_val>127) then begin - print_err("Invalid \newlinechar"); - help1("The value for \newlinechar has to be between 0 and 127."); - error; - end - else if p=end_line_char then begin - if (cur_val<0)or(cur_val>biggest_char) then - word_define(p,-1) - else - word_define(p,13); - end - else - word_define(p,cur_val); -{If we are defining subparagraph penalty levels while we are -in hmode, then we put out a whatsit immediately, otherwise -we leave it alone. This mechanism might not be sufficiently -powerful, and some other algorithm, searching down the stack, -might be necessary. Good first step.} - if (abs(mode)=hmode) and - ((p=(int_base+local_inter_line_penalty_code)) or - (p=(int_base+local_broken_penalty_code))) then begin - @<LOCAL: Add local paragraph node@>; - eq_word_define(int_base+no_local_whatsits_code,no_local_whatsits+1); - local_par_bool:=true; - end; - if p=int_base+language_code then word_define(int_base+cur_lang_code,cur_val); - end; + assign_internal_value(a,p,cur_val); + end; assign_attr: begin p:=cur_chr; scan_optional_equals; scan_int; if (p-attribute_base)>max_used_attr then max_used_attr:=(p-attribute_base); attr_list_cache:=cache_disabled; @@ -28207,7 +24421,7 @@ assign_dir: begin @<DIR: Assign direction codes@> end; assign_dimen: begin p:=cur_chr; scan_optional_equals; - scan_normal_dimen; word_define(p,cur_val); + scan_normal_dimen; assign_internal_value(a,p,cur_val); end; assign_glue,assign_mu_glue: begin p:=cur_chr; n:=cur_cmd; scan_optional_equals; if n=assign_mu_glue then scan_glue(mu_val)@+else scan_glue(glue_val); @@ -28231,39 +24445,146 @@ end; and the font families are declared by |def_family|. @<Put each...@>= -primitive("catcode",def_code,cat_code_base); +primitive_tex("catcode",def_char_code,cat_code_base,cat_code_base); @!@:cat_code_}{\.{\\catcode} primitive@> -primitive("mathcode",def_code,math_code_base); +primitive_tex("mathcode",def_char_code,math_code_base,cat_code_base); @!@:math_code_}{\.{\\mathcode} primitive@> -primitive("lccode",def_code,lc_code_base); +primitive_tex("lccode",def_char_code,lc_code_base,cat_code_base); @!@:lc_code_}{\.{\\lccode} primitive@> -primitive("uccode",def_code,uc_code_base); +primitive_tex("uccode",def_char_code,uc_code_base,cat_code_base); @!@:uc_code_}{\.{\\uccode} primitive@> -primitive("sfcode",def_code,sf_code_base); +primitive_tex("sfcode",def_char_code,sf_code_base,cat_code_base); @!@:sf_code_}{\.{\\sfcode} primitive@> -primitive("delcode",def_code,del_code_base); +primitive_tex("delcode",def_del_code,del_code_base,del_code_base); @!@:del_code_}{\.{\\delcode} primitive@> -primitive("textfont",def_family,math_font_base); +primitive_tex("textfont",def_family,text_size,0); @!@:text_font_}{\.{\\textfont} primitive@> -primitive("scriptfont",def_family,math_font_base+script_size); +primitive_tex("scriptfont",def_family,script_size,0); @!@:script_font_}{\.{\\scriptfont} primitive@> -primitive("scriptscriptfont",def_family,math_font_base+script_script_size); +primitive_tex("scriptscriptfont",def_family,script_script_size,0); @!@:script_script_font_}{\.{\\scriptscriptfont} primitive@> -primitive("omathcode",extdef_code,math_code_base); +primitive_luatex("Umathquad", set_math_param, math_param_quad,0); +primitive_luatex("Umathaxis", set_math_param, math_param_axis,0); +primitive_luatex("Umathoperatorsize", set_math_param, math_param_operator_size,0); +primitive_luatex("Umathoverbarkern", set_math_param, math_param_overbar_kern,0); +primitive_luatex("Umathoverbarrule", set_math_param, math_param_overbar_rule,0); +primitive_luatex("Umathoverbarvgap", set_math_param, math_param_overbar_vgap,0); +primitive_luatex("Umathunderbarkern", set_math_param, math_param_underbar_kern,0); +primitive_luatex("Umathunderbarrule", set_math_param, math_param_underbar_rule,0); +primitive_luatex("Umathunderbarvgap", set_math_param, math_param_underbar_vgap,0); +primitive_luatex("Umathradicalkern", set_math_param, math_param_radical_kern,0); +primitive_luatex("Umathradicalrule", set_math_param, math_param_radical_rule,0); +primitive_luatex("Umathradicalvgap", set_math_param, math_param_radical_vgap,0); +primitive_luatex("Umathradicaldegreebefore",set_math_param, math_param_radical_degree_before,0); +primitive_luatex("Umathradicaldegreeafter", set_math_param, math_param_radical_degree_after,0); +primitive_luatex("Umathradicaldegreeraise", set_math_param, math_param_radical_degree_raise,0); +primitive_luatex("Umathstackvgap", set_math_param, math_param_stack_vgap,0); +primitive_luatex("Umathstacknumup", set_math_param, math_param_stack_num_up,0); +primitive_luatex("Umathstackdenomdown", set_math_param, math_param_stack_denom_down,0); +primitive_luatex("Umathfractionrule", set_math_param, math_param_fraction_rule,0); +primitive_luatex("Umathfractionnumvgap", set_math_param, math_param_fraction_num_vgap,0); +primitive_luatex("Umathfractionnumup", set_math_param, math_param_fraction_num_up,0); +primitive_luatex("Umathfractiondenomvgap",set_math_param, math_param_fraction_denom_vgap,0); +primitive_luatex("Umathfractiondenomdown",set_math_param, math_param_fraction_denom_down,0); +primitive_luatex("Umathfractiondelsize", set_math_param, math_param_fraction_del_size,0); +primitive_luatex("Umathlimitabovevgap", set_math_param, math_param_limit_above_vgap,0); +primitive_luatex("Umathlimitabovebgap", set_math_param, math_param_limit_above_bgap,0); +primitive_luatex("Umathlimitabovekern", set_math_param, math_param_limit_above_kern,0); +primitive_luatex("Umathlimitdownvgap", set_math_param, math_param_limit_below_vgap,0); +primitive_luatex("Umathlimitdownbgap", set_math_param, math_param_limit_below_bgap,0); +primitive_luatex("Umathlimitdownkern", set_math_param, math_param_limit_below_kern,0); +primitive_luatex("Umathunderdelimitervgap", set_math_param, math_param_under_delimiter_vgap,0); +primitive_luatex("Umathunderdelimiterbgap", set_math_param, math_param_under_delimiter_bgap,0); +primitive_luatex("Umathoverdelimitervgap",set_math_param, math_param_over_delimiter_vgap,0); +primitive_luatex("Umathoverdelimiterbgap",set_math_param, math_param_over_delimiter_bgap,0); +primitive_luatex("Umathsubshiftdrop", set_math_param, math_param_sub_shift_drop,0); +primitive_luatex("Umathsupshiftdrop", set_math_param, math_param_sup_shift_drop,0); +primitive_luatex("Umathsubshiftdown", set_math_param, math_param_sub_shift_down,0); +primitive_luatex("Umathsubsupshiftdown", set_math_param, math_param_sub_sup_shift_down,0); +primitive_luatex("Umathsubtopmax", set_math_param, math_param_sub_top_max,0); +primitive_luatex("Umathsupshiftup", set_math_param, math_param_sup_shift_up,0); +primitive_luatex("Umathsupbottommin", set_math_param, math_param_sup_bottom_min,0); +primitive_luatex("Umathsupsubbottommax", set_math_param, math_param_sup_sub_bottom_max,0); +primitive_luatex("Umathsubsupvgap", set_math_param, math_param_subsup_vgap,0); +primitive_luatex("Umathspaceafterscript", set_math_param, math_param_space_after_script,0); +primitive_luatex("Umathconnectoroverlapmin", set_math_param, math_param_connector_overlap_min,0); +primitive_luatex("Umathordordspacing", set_math_param, math_param_ord_ord_spacing,0); +primitive_luatex("Umathordopspacing", set_math_param, math_param_ord_op_spacing,0); +primitive_luatex("Umathordbinspacing", set_math_param, math_param_ord_bin_spacing,0); +primitive_luatex("Umathordrelspacing", set_math_param, math_param_ord_rel_spacing,0); +primitive_luatex("Umathordopenspacing", set_math_param, math_param_ord_open_spacing,0); +primitive_luatex("Umathordclosespacing", set_math_param, math_param_ord_close_spacing,0); +primitive_luatex("Umathordpunctspacing", set_math_param, math_param_ord_punct_spacing,0); +primitive_luatex("Umathordinnerspacing", set_math_param, math_param_ord_inner_spacing,0); +primitive_luatex("Umathopordspacing", set_math_param, math_param_op_ord_spacing,0); +primitive_luatex("Umathopopspacing", set_math_param, math_param_op_op_spacing,0); +primitive_luatex("Umathopbinspacing", set_math_param, math_param_op_bin_spacing,0); +primitive_luatex("Umathoprelspacing", set_math_param, math_param_op_rel_spacing,0); +primitive_luatex("Umathopopenspacing", set_math_param, math_param_op_open_spacing,0); +primitive_luatex("Umathopclosespacing", set_math_param, math_param_op_close_spacing,0); +primitive_luatex("Umathoppunctspacing", set_math_param, math_param_op_punct_spacing,0); +primitive_luatex("Umathopinnerspacing", set_math_param, math_param_op_inner_spacing,0); +primitive_luatex("Umathbinordspacing", set_math_param, math_param_bin_ord_spacing,0); +primitive_luatex("Umathbinopspacing", set_math_param, math_param_bin_op_spacing,0); +primitive_luatex("Umathbinbinspacing", set_math_param, math_param_bin_bin_spacing,0); +primitive_luatex("Umathbinrelspacing", set_math_param, math_param_bin_rel_spacing,0); +primitive_luatex("Umathbinopenspacing", set_math_param, math_param_bin_open_spacing,0); +primitive_luatex("Umathbinclosespacing", set_math_param, math_param_bin_close_spacing,0); +primitive_luatex("Umathbinpunctspacing", set_math_param, math_param_bin_punct_spacing,0); +primitive_luatex("Umathbininnerspacing", set_math_param, math_param_bin_inner_spacing,0); +primitive_luatex("Umathrelordspacing", set_math_param, math_param_rel_ord_spacing,0); +primitive_luatex("Umathrelopspacing", set_math_param, math_param_rel_op_spacing,0); +primitive_luatex("Umathrelbinspacing", set_math_param, math_param_rel_bin_spacing,0); +primitive_luatex("Umathrelrelspacing", set_math_param, math_param_rel_rel_spacing,0); +primitive_luatex("Umathrelopenspacing", set_math_param, math_param_rel_open_spacing,0); +primitive_luatex("Umathrelclosespacing", set_math_param, math_param_rel_close_spacing,0); +primitive_luatex("Umathrelpunctspacing", set_math_param, math_param_rel_punct_spacing,0); +primitive_luatex("Umathrelinnerspacing", set_math_param, math_param_rel_inner_spacing,0); +primitive_luatex("Umathopenordspacing", set_math_param, math_param_open_ord_spacing,0); +primitive_luatex("Umathopenopspacing", set_math_param, math_param_open_op_spacing,0); +primitive_luatex("Umathopenbinspacing", set_math_param, math_param_open_bin_spacing,0); +primitive_luatex("Umathopenrelspacing", set_math_param, math_param_open_rel_spacing,0); +primitive_luatex("Umathopenopenspacing", set_math_param, math_param_open_open_spacing,0); +primitive_luatex("Umathopenclosespacing", set_math_param, math_param_open_close_spacing,0); +primitive_luatex("Umathopenpunctspacing", set_math_param, math_param_open_punct_spacing,0); +primitive_luatex("Umathopeninnerspacing", set_math_param, math_param_open_inner_spacing,0); +primitive_luatex("Umathcloseordspacing", set_math_param, math_param_close_ord_spacing,0); +primitive_luatex("Umathcloseopspacing", set_math_param, math_param_close_op_spacing,0); +primitive_luatex("Umathclosebinspacing", set_math_param, math_param_close_bin_spacing,0); +primitive_luatex("Umathcloserelspacing", set_math_param, math_param_close_rel_spacing,0); +primitive_luatex("Umathcloseopenspacing", set_math_param, math_param_close_open_spacing,0); +primitive_luatex("Umathcloseclosespacing",set_math_param, math_param_close_close_spacing,0); +primitive_luatex("Umathclosepunctspacing",set_math_param, math_param_close_punct_spacing,0); +primitive_luatex("Umathcloseinnerspacing",set_math_param, math_param_close_inner_spacing,0); +primitive_luatex("Umathpunctordspacing", set_math_param, math_param_punct_ord_spacing,0); +primitive_luatex("Umathpunctopspacing", set_math_param, math_param_punct_op_spacing,0); +primitive_luatex("Umathpunctbinspacing", set_math_param, math_param_punct_bin_spacing,0); +primitive_luatex("Umathpunctrelspacing", set_math_param, math_param_punct_rel_spacing,0); +primitive_luatex("Umathpunctopenspacing", set_math_param, math_param_punct_open_spacing,0); +primitive_luatex("Umathpunctclosespacing",set_math_param, math_param_punct_close_spacing,0); +primitive_luatex("Umathpunctpunctspacing",set_math_param, math_param_punct_punct_spacing,0); +primitive_luatex("Umathpunctinnerspacing",set_math_param, math_param_punct_inner_spacing,0); +primitive_luatex("Umathinnerordspacing", set_math_param, math_param_inner_ord_spacing,0); +primitive_luatex("Umathinneropspacing", set_math_param, math_param_inner_op_spacing,0); +primitive_luatex("Umathinnerbinspacing", set_math_param, math_param_inner_bin_spacing,0); +primitive_luatex("Umathinnerrelspacing", set_math_param, math_param_inner_rel_spacing,0); +primitive_luatex("Umathinneropenspacing", set_math_param, math_param_inner_open_spacing,0); +primitive_luatex("Umathinnerclosespacing",set_math_param, math_param_inner_close_spacing,0); +primitive_luatex("Umathinnerpunctspacing",set_math_param, math_param_inner_punct_spacing,0); +primitive_luatex("Umathinnerinnerspacing",set_math_param, math_param_inner_inner_spacing,0); +primitive_omega("omathcode",extdef_math_code,math_code_base,math_code_base); @!@:math_code_}{\.{\\omathcode} primitive@> -primitive("odelcode",extdef_code,del_code_base); +primitive_omega("odelcode",extdef_del_code,del_code_base,del_code_base); @!@:del_code_}{\.{\\odelcode} primitive@> +primitive_luatex("Umathcode",extdef_math_code,math_code_base+1,math_code_base); +@!@:math_code_}{\.{\\Umathcode} primitive@> +primitive_luatex("Udelcode",extdef_del_code,del_code_base+1,del_code_base); +@!@:del_code_}{\.{\\Udelcode} primitive@> +primitive_luatex("Umathcodenum",extdef_math_code,math_code_base+2,math_code_base); +@!@:math_code_}{\.{\\Umathcodenum} primitive@> +primitive_luatex("Udelcodenum",extdef_del_code,del_code_base+2,del_code_base); +@!@:del_code_}{\.{\\Udelcodenum} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -def_code: if chr_code=cat_code_base then print_esc("catcode") - else if chr_code=math_code_base then print_esc("mathcode") - else if chr_code=lc_code_base then print_esc("lccode") - else if chr_code=uc_code_base then print_esc("uccode") - else if chr_code=sf_code_base then print_esc("sfcode") - else print_esc("delcode"); -extdef_code: if chr_code=math_code_base then print_esc("omathcode") - else print_esc("odelcode"); -def_family: print_size(chr_code-math_font_base); @ The different types of code values have different legal ranges; the following program is careful to check each case properly. @@ -28280,18 +24601,12 @@ following program is careful to check each case properly. @<Assignments@>= -def_code: begin @<Let |n| be the largest legal code value, based on |cur_chr|@>; +def_char_code,def_del_code: begin + @<Let |n| be the largest legal code value, based on |cur_chr|@>; p:=cur_chr; if cur_chr=math_code_base then begin - scan_char_num; p:= cur_val; - scan_optional_equals; - scan_int; - check_def_code(math_code_base); - if cur_val=@"8000 then cur_val:=@"8000000 - else cur_val:=((cur_val div @"1000) * @"1000000) + - (((cur_val mod @"1000) div @"100) * @"10000) + - (cur_val mod @"100); - define_math_code(p,cur_val); + if global then cur_val1:=level_one else cur_val1:=cur_level; + scan_extdef_math_code(cur_val1,tex_mathcode); end else if cur_chr=lc_code_base then begin scan_char_num; p:= cur_val; @@ -28322,56 +24637,63 @@ def_code: begin @<Let |n| be the largest legal code value, based on |cur_chr|@>; define_cat_code(p,cur_val); end else if cur_chr=del_code_base then begin - scan_char_num; p:= cur_val; - scan_optional_equals; - scan_int; - check_def_code(del_code_base); - cur_val1:=cur_val div @"1000; - cur_val1:=(cur_val1 div @"100)*@"10000 + (cur_val1 mod @"100); - cur_val:=cur_val mod @"1000; - cur_val:=(cur_val div @"100)*@"10000 + (cur_val mod @"100); - define_del_code(p,cur_val1,cur_val); - end; - end; -extdef_code: begin - if cur_chr=del_code_base then begin - p:=cur_chr; scan_char_num; p:=p+cur_val; scan_optional_equals; - scan_int; cur_val1:=cur_val; scan_int; {backwards} - if (cur_val1>@"FFFFFF) or (cur_val>@"FFFFFF) then - begin print_err("Invalid code ("); print_int(cur_val1); print(" "); - print_int(cur_val); - print("), should be at most ""FFFFFF ""FFFFFF"); - help1("I'm going to use 0 instead of that illegal code value.");@/ - error; cur_val1:=0; cur_val:=0; - end; - define_del_code(p,cur_val1,cur_val); - end - else begin - p:=cur_chr; scan_char_num; p:=cur_val; scan_optional_equals; - scan_int; - if (cur_val>@"8000000) then - begin print_err("Invalid code ("); print_int(cur_val); -@.Invalid code@> - print("), should be at most "); print_int(@"8000000); - help1("I'm going to use 0 instead of that illegal code value.");@/ - error; cur_val:=0; - end; - define_math_code(p,cur_val); - end; + if global then cur_val1:=level_one else cur_val1:=cur_level; + scan_extdef_del_code(cur_val1,tex_mathcode); + end; + end; +extdef_math_code, extdef_del_code: begin + if global then cur_val1:=level_one else cur_val1:=cur_level; + if cur_chr=math_code_base then + scan_extdef_math_code(cur_val1,aleph_mathcode) + else if cur_chr=math_code_base+1 then + scan_extdef_math_code(cur_val1,xetex_mathcode) + else if cur_chr=math_code_base+2 then + scan_extdef_math_code(cur_val1,xetexnum_mathcode) + else if cur_chr=del_code_base then + scan_extdef_del_code(cur_val1,aleph_mathcode) + else if cur_chr=del_code_base+1 then + scan_extdef_del_code(cur_val1,xetex_mathcode) + else if cur_chr=del_code_base+2 then + scan_extdef_del_code(cur_val1,xetexnum_mathcode); end; + @ @<Let |n| be the largest...@>= if cur_chr=cat_code_base then n:=max_char_code else if cur_chr=lc_code_base then n:=biggest_char else if cur_chr=uc_code_base then n:=biggest_char -else if cur_chr=math_code_base then n:=@'100000 else if cur_chr=sf_code_base then n:=@'77777 -else if cur_chr=del_code_base then n:=@'77777777 else n:=biggest_char @ @<Assignments@>= -def_family: begin p:=cur_chr; scan_math_family_int; p:=p+cur_val; - scan_optional_equals; scan_font_ident; define(p,data,cur_val); +def_family: begin p:=cur_chr; scan_math_family_int; cur_val1:=cur_val; + scan_optional_equals; scan_font_ident; + define_fam_fnt(cur_val1,p,cur_val); + end; +set_math_param: begin p:=cur_chr; get_token; + if cur_cmd<>math_style then begin + print_err("Missing math style, treated as \displaystyle"); +@.Missing number...@> + help1("A style should have been here; I inserted `\displaystyle'."); + cur_val1:=display_style; + back_error; + end + else + cur_val1:=cur_chr; + scan_optional_equals; + if p<math_param_first_mu_glue then begin + if p=math_param_radical_degree_raise then + scan_int + else + scan_dimen(false, false, false); + end + else begin + scan_glue(mu_val); trap_zero_glue; + if cur_val=thin_mu_skip then cur_val:=thin_mu_skip_code + else if cur_val=med_mu_skip then cur_val:=med_mu_skip_code + else if cur_val=thick_mu_skip then cur_val:=thick_mu_skip_code + end; + define_math_param(p,cur_val1,cur_val); end; @ Next we consider changes to \TeX's numeric registers. @@ -28389,7 +24711,8 @@ var l,@!q,@!r,@!s:pointer; {for list manipulation} begin q:=cur_cmd; @<Compute the register location |l| and its type |p|; but |return| if invalid@>; if q=register then scan_optional_equals -else if scan_keyword("by") then do_nothing; {optional `\.{by}'} +else if scan_keyword('by') then do_nothing; {optional `\.{by}'} +@.by@> arith_error:=false; if q<multiply then @<Compute result of |register| or |advance|, put it in |cur_val|@> @@ -28399,6 +24722,7 @@ if arith_error then @.Arithmetic overflow@> help2("I can't carry out that multiplication or division,")@/ ("since the result is out of range."); + if p>=glue_val then delete_glue_ref(cur_val); error; return; end; if p<glue_val then begin @@ -28406,13 +24730,16 @@ if p<glue_val then begin if (l-attribute_base)>max_used_attr then max_used_attr:=(l-attribute_base); attr_list_cache:=cache_disabled; end; - word_define(l,cur_val); + if (p=int_val) or (p=dimen_val) then + assign_internal_value(a,l,cur_val) + else + word_define(l,cur_val); end else begin trap_zero_glue; define(l,glue_ref,cur_val); end; exit: end; -@ Here we use the fact that the consecutive codes |int_val...mu_val| and +@ Here we use the fact that the consecutive codes |int_val..mu_val| and |assign_int..assign_mu_glue| correspond to each other nicely. @<Compute the register location |l| and its type |p|...@>= @@ -28584,20 +24911,10 @@ end; @ Paragraph shapes are set up in an obvious way. It needs one word more than in \TeX, though. -@d shape_node=54 { storage for shape pointers } - @<Assignments@>= -set_shape: begin q:=cur_chr; scan_optional_equals; scan_int; n:=cur_val; +set_tex_shape: begin q:=cur_chr; scan_optional_equals; scan_int; n:=cur_val; if n<=0 then p:=null - else if q>par_shape_loc then - begin n:=(cur_val div 2)+1; p:=new_node(shape_node,2*n+1+1); vinfo(p+1):=n; - n:=cur_val; vmem(p+2).int:=n; {number of penalties} - for j:=p+3 to p+n+2 do - begin scan_int; vmem(j).int:=cur_val; {penalty values} - end; - if not odd(n) then vmem(p+n+3).int:=0; {unused} - end - else begin p:=new_node(shape_node,2*(n+1)+1); vinfo(p+1):=n; + else begin p:=new_node(shape_node,2*(n+1)+1); vinfo(p+1):=n; for j:=1 to n do begin scan_normal_dimen; vmem(p+2*j).sc:=cur_val; {indentation} @@ -28607,26 +24924,33 @@ set_shape: begin q:=cur_chr; scan_optional_equals; scan_int; n:=cur_val; end; define(q,shape_ref,p); end; +set_etex_shape: begin q:=cur_chr; scan_optional_equals; scan_int; n:=cur_val; + if n<=0 then p:=null + else begin n:=(cur_val div 2)+1; p:=new_node(shape_node,2*n+1+1); vinfo(p+1):=n; + n:=cur_val; vmem(p+2).int:=n; {number of penalties} + for j:=p+3 to p+n+2 do + begin scan_int; vmem(j).int:=cur_val; {penalty values} + end; + if not odd(n) then vmem(p+n+3).int:=0; {unused} + end; + define(q,shape_ref,p); + end; @ New language information data is loaded by the |hyph_data| command. @<Put each...@>= -primitive("hyphenation",hyph_data,0); +primitive_tex("hyphenation",hyph_data,0,0); @!@:hyphenation_}{\.{\\hyphenation} primitive@> -primitive("patterns",hyph_data,1); +primitive_tex("patterns",hyph_data,1,0); @!@:patterns_}{\.{\\patterns} primitive@> -primitive("prehyphenchar",hyph_data,2); +primitive_luatex("prehyphenchar",hyph_data,2,0); @!@:prehyphenchar_}{\.{\\prehyphenchar} primitive@> -primitive("posthyphenchar",hyph_data,3); +primitive_luatex("posthyphenchar",hyph_data,3,0); @!@:posthyphenchar_}{\.{\\posthyphenchar} primitive@> - -@ @<Cases of |print_cmd_chr|...@>= -hyph_data: case cur_chr of - 0: print_esc("hyphenation"); - 1: print_esc("patterns"); - 2: print_esc("prehyphenchar"); - 3: print_esc("posthyphenchar"); - endcases; +primitive_luatex("preexhyphenchar",hyph_data,4,0); +@!@:preexhyphenchar_}{\.{\\preexhyphenchar} primitive@> +primitive_luatex("postexhyphenchar",hyph_data,5,0); +@!@:postexhyphenchar_}{\.{\\postexhyphenchar} primitive@> @ @<Assignments@>= hyph_data: begin @@ -28635,6 +24959,8 @@ hyph_data: begin 1: new_patterns; 2: new_pre_hyphen_char; 3: new_post_hyphen_char; + 4: new_pre_exhyphen_char; + 5: new_post_exhyphen_char; endcases; goto done; end; @@ -28664,158 +24990,38 @@ assign_font_int: begin end; @ @<Put each...@>= -primitive("hyphenchar",assign_font_int,0); +primitive_tex("hyphenchar",assign_font_int,0,0); @!@:hyphen_char_}{\.{\\hyphenchar} primitive@> -primitive("skewchar",assign_font_int,1); +primitive_tex("skewchar",assign_font_int,1,0); @!@:skew_char_}{\.{\\skewchar} primitive@> -primitive("lpcode",assign_font_int,lp_code_base); +primitive_pdftex("lpcode",assign_font_int,lp_code_base,0); @!@:lp_code_}{\.{\\lpcode} primitive@> -primitive("rpcode",assign_font_int,rp_code_base); +primitive_pdftex("rpcode",assign_font_int,rp_code_base,0); @!@:rp_code_}{\.{\\rpcode} primitive@> -primitive("efcode",assign_font_int,ef_code_base); +primitive_pdftex("efcode",assign_font_int,ef_code_base,0); @!@:ef_code_}{\.{\\efcode} primitive@> -primitive("tagcode",assign_font_int,tag_code); +primitive_pdftex("tagcode",assign_font_int,tag_code,0); @!@:tag_code_}{\.{\\tagcode} primitive@> -primitive("pdfnoligatures",assign_font_int,no_lig_code); +primitive_pdftex("pdfnoligatures",assign_font_int,no_lig_code,0); @!@:no_lig_code_}{\.{\\pdfnoligatures} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -assign_font_int: case chr_code of -0: print_esc("hyphenchar"); -1: print_esc("skewchar"); -lp_code_base: print_esc("lpcode"); -rp_code_base: print_esc("rpcode"); -ef_code_base: print_esc("efcode"); -tag_code: print_esc("tagcode"); -no_lig_code: print_esc("pdfnoligatures"); -endcases; - @ Here is where the information for a new font gets loaded. @<Assignments@>= -def_font: def_new_font(a); +def_font: tex_def_font(a); {in C} letterspace_font: new_letterspaced_font(a); - -@ @<Declare subprocedures for |prefixed_command|@>= -procedure def_new_font(@!a:small_number); -var u:pointer; {user's font identifier} -@!s:scaled; {stated ``at'' size, or negative of scaled magnification} -@!f:internal_font_number; {runs through existing fonts} -@!t:str_number; {name for the frozen font identifier} -@!old_setting:0..max_selector; {holds |selector| setting} -@!offset:integer; -@!natural_dir:integer;{the natural direction of the font} -@!flushable_string:str_number; {string not yet referenced} -@!junk:pointer; -begin if job_name=0 then open_log_file; - {avoid confusing \.{texput} with the font name} -@.texput@> -get_r_token; u:=cur_cs; -if u>=hash_base then t:=text(u) -else if u=null_cs then t:="FONT" -else begin old_setting:=selector; selector:=new_string; - print("FONT"); print(u-active_base); selector:=old_setting; -@.FONTx@> - str_room(1); t:=make_string; - end; -define(u,set_font,null_font); scan_optional_equals; -@<Get the next non-blank non-call token@>; -if cur_cmd<>left_brace then begin - back_input; - scan_file_name; - end -else begin - back_input; - junk:=scan_toks(false,true); - old_setting:=selector; selector:=new_string; - token_show(def_ref); selector:=old_setting; - flush_list(def_ref); - str_room(1); - cur_name:=make_string; - cur_ext:=""; - cur_area:=""; - end; -@<Scan the font size specification@>; -name_in_progress:=true; -if scan_keyword("offset") then begin - scan_int; - offset:=cur_val; - if (cur_val<0) then begin - print_err("Illegal offset has been changed to 0"); - help1("The offset must be bigger than 0."); int_error(cur_val); - offset:=0; - end - end -else offset:=0; -if scan_keyword("naturaldir") then begin - scan_direction; - natural_dir:=cur_val; - end -else natural_dir:=-1; -name_in_progress:=false; -if cur_area = "" then - f:=read_font_info(u,cur_name,"",s,natural_dir) -else - f:=read_font_info(u,cur_name,cur_area,s,natural_dir); -equiv(u):=f; eqtb[font_id_base+f]:=eqtb[u]; font_id_text(f):=t; -end; - -@ @<Scan the font size specification@>= -name_in_progress:=true; {this keeps |cur_name| from being changed} -if scan_keyword("at") then @<Put the \(p)(positive) `at' size into |s|@> -@.at@> -else if scan_keyword("scaled") then -@.scaled@> - begin scan_int; s:=-cur_val; - if (cur_val<=0)or(cur_val>32768) then - begin print_err("Illegal magnification has been changed to 1000");@/ -@.Illegal magnification...@> - help1("The magnification ratio must be between 1 and 32768."); - int_error(cur_val); s:=-1000; - end; - end -else s:=-1000; -name_in_progress:=false - -@ @<Put the \(p)(positive) `at' size into |s|@>= -begin scan_normal_dimen; s:=cur_val; -if (s<=0)or(s>=@'1000000000) then - begin print_err("Improper `at' size ("); - print_scaled(s); print("pt), replaced by 10pt"); -@.Improper `at' size...@> - help2("I can only handle fonts at positive sizes that are")@/ - ("less than 2048pt, so I've changed what you said to 10pt."); - error; s:=10*unity; - end; -end - - -@ @<Cases of |print_cmd_chr|...@>= -set_font:begin print("select font "); print_font_name(chr_code); - if font_size(chr_code)<>font_dsize(chr_code) then - begin print(" at "); print_scaled(font_size(chr_code)); - print("pt"); - end; - end; +pdf_copy_font: make_font_copy(a); @ @<Put each...@>= -primitive("batchmode",set_interaction,batch_mode); +primitive_tex("batchmode",set_interaction,batch_mode,0); @!@:batch_mode_}{\.{\\batchmode} primitive@> -primitive("nonstopmode",set_interaction,nonstop_mode); +primitive_tex("nonstopmode",set_interaction,nonstop_mode,0); @!@:nonstop_mode_}{\.{\\nonstopmode} primitive@> -primitive("scrollmode",set_interaction,scroll_mode); +primitive_tex("scrollmode",set_interaction,scroll_mode,0); @!@:scroll_mode_}{\.{\\scrollmode} primitive@> -primitive("errorstopmode",set_interaction,error_stop_mode); +primitive_tex("errorstopmode",set_interaction,error_stop_mode,0); @!@:error_stop_mode_}{\.{\\errorstopmode} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -set_interaction: case chr_code of - batch_mode: print_esc("batchmode"); - nonstop_mode: print_esc("nonstopmode"); - scroll_mode: print_esc("scrollmode"); - othercases print_esc("errorstopmode") - endcases; - @ @<Assignments@>= set_interaction: new_interaction; @@ -28865,15 +25071,11 @@ any_mode(after_group):begin get_token; save_for_after(cur_tok); @ Files for \.{\\read} are opened and closed by the |in_stream| command. @<Put each...@>= -primitive("openin",in_stream,1); +primitive_tex("openin",in_stream,1,0); @!@:open_in_}{\.{\\openin} primitive@> -primitive("closein",in_stream,0); +primitive_tex("closein",in_stream,0,0); @!@:close_in_}{\.{\\closein} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -in_stream: if chr_code=0 then print_esc("closein") - else print_esc("openin"); - @ @<Cases of |main_control| that don't...@>= any_mode(in_stream): open_or_close_in; @@ -28903,15 +25105,11 @@ current mode. any_mode(message):issue_message; @ @<Put each...@>= -primitive("message",message,0); +primitive_tex("message",message,0,0); @!@:message_}{\.{\\message} primitive@> -primitive("errmessage",message,1); +primitive_tex("errmessage",message,1,0); @!@:err_message_}{\.{\\errmessage} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -message: if chr_code=0 then print_esc("message") - else print_esc("errmessage"); - @ @<Declare act...@>= procedure issue_message; var old_setting:0..max_selector; {holds |selector| setting} @@ -28971,15 +25169,11 @@ building a token list and then changing the cases of the letters in it. any_mode(case_shift):shift_case; @ @<Put each...@>= -primitive("lowercase",case_shift,lc_code_base); +primitive_tex("lowercase",case_shift,lc_code_base,lc_code_base); @!@:lowercase_}{\.{\\lowercase} primitive@> -primitive("uppercase",case_shift,uc_code_base); +primitive_tex("uppercase",case_shift,uc_code_base,lc_code_base); @!@:uppercase_}{\.{\\uppercase} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -case_shift:if chr_code=lc_code_base then print_esc("lowercase") - else print_esc("uppercase"); - @ @<Declare act...@>= procedure shift_case; var b:pointer; {|lc_code_base| or |uc_code_base|} @@ -28996,22 +25190,26 @@ back_list(link(def_ref)); free_avail(def_ref); {omit reference count} end; @ When the case of a |chr_code| changes, we don't change the |cmd|. -We also change active characters, using the fact that -|cs_token_flag+active_base| is a multiple of~|string_offset|. -@^data structure assumptions@> +We also change active characters. @<Change the case of the token in |p|, if a change is appropriate@>= t:=info(p); -if t<cs_token_flag+null_cs then - begin +if t<cs_token_flag then begin c:=t mod string_offset; - if b=uc_code_base then begin - i:=get_uc_code(c); - if i<>0 then info(p):=t-c+i; - end - else - begin if get_lc_code(c)<>0 then info(p):=t-c+get_lc_code(c); end; + if b=uc_code_base then + i:=get_uc_code(c) + else + i:=get_lc_code(c); + if i<>0 then info(p):=t-c+i; end +else if is_active_csname(t-cs_token_flag) then begin + c:=active_csname_value(t-cs_token_flag); + if b=uc_code_base then + i:=get_uc_code(c) + else + i:= get_lc_code(c); + if i<>0 then info(p):=active_to_cs(i,true)+cs_token_flag; +end @ We come finally to the last pieces missing from |main_control|, namely the `\.{\\show}' commands that are useful when debugging. @@ -29025,24 +25223,15 @@ any_mode(xray): show_whatever; @d show_lists=3 { \.{\\showlists} } @<Put each...@>= -primitive("show",xray,show_code); +primitive_tex("show",xray,show_code,0); @!@:show_}{\.{\\show} primitive@> -primitive("showbox",xray,show_box_code); +primitive_tex("showbox",xray,show_box_code,0); @!@:show_box_}{\.{\\showbox} primitive@> -primitive("showthe",xray,show_the_code); +primitive_tex("showthe",xray,show_the_code,0); @!@:show_the_}{\.{\\showthe} primitive@> -primitive("showlists",xray,show_lists); +primitive_tex("showlists",xray,show_lists,0); @!@:show_lists_}{\.{\\showlists} primitive@> -@ @<Cases of |print_cmd_chr|...@>= -xray: case chr_code of - show_box_code:print_esc("showbox"); - show_the_code:print_esc("showthe"); - show_lists:print_esc("showlists"); - @<Cases of |xray| for |print_cmd_chr|@>@;@/ - othercases print_esc("show") - endcases; - @ @<Declare act...@>= procedure show_whatever; label common_ending; @@ -29090,18 +25279,6 @@ if cur_cs<>0 then print_meaning; goto common_ending; end -@ @<Cases of |print_cmd_chr|...@>= -undefined_cs: print("undefined"); -call,long_call,outer_call,long_outer_call: begin n:=cmd-call; - if info(link(chr_code))=protected_token then n:=n+4; - if odd(n div 4) then print_esc("protected"); - if odd(n) then print_esc("long"); - if odd(n div 2) then print_esc("outer"); - if n>0 then print_char(" "); - print("macro"); - end; -end_template: print_esc("outer endtemplate"); - @ @<Show the current contents of a box@>= begin scan_register_num; begin_diagnostic; print_nl("> \box"); print_int(cur_val); print_char("="); @@ -29137,7 +25314,7 @@ so that the inverse relation between them is clear. The global variable |format_ident| is a string that is printed right after the |banner| line when \TeX\ is ready to start. For \.{INITEX} this string says simply `\.{(INITEX)}'; for other versions of \TeX\ it says, -for example, `\.{(preloaded format=plain 82.11.19)}', showing the year, +for example, `\.{(preloaded format=plain 1982.11.19)}', showing the year, month, and day that the format file was created. We have |format_ident=0| before \TeX's tables are loaded. @@ -29171,6 +25348,7 @@ begin @<If dumping is not allowed, abort@>; @<Dump the ocp information@>; @<Dump the ocp list information@>; @<Dump the hyphenation tables@>; +@<Dump pdftex data@>; @<Dump a couple more things and the closing check word@>; @<Dump the lua bytecodes@>; @<Close the format file@>; @@ -29204,8 +25382,10 @@ begin @<Undump constants for consistency check@>; @<Undump the ocp information@>; @<Undump the ocp list information@>; @<Undump the hyphenation tables@>; +@<Undump pdftex data@>; @<Undump a couple more things and the closing check word@>; @<Undump the lua bytecodes@>; +prev_depth := pdf_ignored_dimen; load_fmt_file:=true; return; {it worked!} bad_fmt: wake_up_terminal; wterm_ln('(Fatal format file error; I''m stymied)'); @@ -29371,7 +25551,7 @@ format file represents $n+m$ consecutive entries of |eqtb|, with |m| extra copies of $x_n$, namely $(x_1,\ldots,x_n,x_n,\ldots,x_n)$. @<Dump regions 1 to 4 of |eqtb|@>= -k:=active_base; +k:=null_cs; repeat j:=k; while j<int_base-1 do begin if (equiv(j)=equiv(j+1))and(eq_type(j)=eq_type(j+1))and@| @@ -29413,7 +25593,7 @@ k:=j+1; dump_int(k-l); until k>eqtb_size @ @<Undump regions 1 to 6 of |eqtb|@>= -k:=active_base; +k:=null_cs; repeat undump_int(x); if (x<1)or(k+x>eqtb_size+1) then goto bad_fmt; for j:=k to k+x-1 do undump_wd(eqtb[j]); @@ -29430,8 +25610,7 @@ two words, |p| and |hash[p]|. The hash table is, of course, densely packed for |p>=hash_used|, so the remaining entries are output in a~block. @<Dump the hash table@>= -for p:=0 to prim_size do dump_hh(prim[p]); -for p:=0 to prim_size do dump_wd(prim_eqtb[p]); +dump_primitives; dump_int(hash_used); cs_count:=frozen_control_sequence-1-hash_used; for p:=hash_base to hash_used do if text(p)<>0 then begin dump_int(p); dump_hh(hash[p]); incr(cs_count); @@ -29441,8 +25620,7 @@ dump_int(cs_count);@/ print_ln; print_int(cs_count); print(" multiletter control sequences") @ @<Undump the hash table@>= -for p:=0 to prim_size do undump_hh(prim[p]); -for p:=0 to prim_size do undump_wd(prim_eqtb[p]); +undump_primitives; undump(hash_base)(frozen_control_sequence)(hash_used); p:=hash_base-1; repeat undump(p+1)(hash_used)(p); undump_hh(hash[p]); until p=hash_used; @@ -29454,13 +25632,15 @@ dump_int(max_font_id); for k:=0 to max_font_id do @<Dump the array info for internal font number |k|@>; print_ln; print_int(max_font_id); print(" preloaded font"); -if max_font_id<>1 then print_char("s") +if max_font_id<>1 then print_char("s"); +dump_math_data @ @<Undump the font information@>= undump_int(x); set_max_font_id(x); for k:=0 to max_font_id do - @<Undump the array info for internal font number |k|@> + @<Undump the array info for internal font number |k|@>; +undump_math_data @ @<Dump the array info for internal font number |k|@>= begin dump_font(k); @@ -29548,6 +25728,79 @@ dump_language_data @ @<Undump the hyphenation tables@>= undump_language_data +@ Store some of the pdftex data structures in the format. The idea here is +to ensure that any data structures referenced from pdftex-specific whatsit +nodes are retained. For the sake of simplicity and speed, all the filled parts +of |pdf_mem| and |obj_tab| are retained, in the present implementation. We also +retain three of the linked lists that start from |head_tab|, so that it is +possible to, say, load an image in the \.{INITEX} run and then reference it in a +\.{VIRTEX} run that uses the dumped format. + +@<Dump pdftex data@>= +begin +dumpimagemeta; {the image information array } +dump_int(pdf_mem_size); +dump_int(pdf_mem_ptr); +for k:=1 to pdf_mem_ptr-1 do begin + dump_int(pdf_mem[k]); + end; +print_ln; print_int(pdf_mem_ptr-1); print(" words of pdf memory"); +dump_int(obj_tab_size); +dump_int(obj_ptr); +dump_int(sys_obj_ptr); +for k:=1 to sys_obj_ptr do begin + dump_int(obj_tab[k].int0); + dump_int(obj_tab[k].int1); + dump_int(obj_tab[k].int3); + dump_int(obj_tab[k].int4); + end; +print_ln; print_int(sys_obj_ptr); print(" indirect objects"); +dump_int(pdf_obj_count); +dump_int(pdf_xform_count); +dump_int(pdf_ximage_count); +dump_int(head_tab[obj_type_obj]); +dump_int(head_tab[obj_type_xform]); +dump_int(head_tab[obj_type_ximage]); +dump_int(pdf_last_obj); +dump_int(pdf_last_xform); +dump_int(pdf_last_ximage); +end + +@ And restoring the pdftex data structures from the format. The +two function arguments to |undumpimagemeta| have been restored +already in an earlier module. + +@<Undump pdftex data@>= +begin +undumpimagemeta(pdf_minor_version,pdf_inclusion_errorlevel); {the image information array } +undump_int(pdf_mem_size); +pdf_mem := xreallocarray(pdf_mem, integer, pdf_mem_size); +undump_int(pdf_mem_ptr); +for k:=1 to pdf_mem_ptr-1 do begin + undump_int(pdf_mem[k]); + end; +undump_int(obj_tab_size); +undump_int(obj_ptr); +undump_int(sys_obj_ptr); +for k:=1 to sys_obj_ptr do begin + undump_int(obj_tab[k].int0); + undump_int(obj_tab[k].int1); + obj_tab[k].int2 := -1; + undump_int(obj_tab[k].int3); + undump_int(obj_tab[k].int4); + end; +undump_int(pdf_obj_count); +undump_int(pdf_xform_count); +undump_int(pdf_ximage_count); +undump_int(head_tab[obj_type_obj]); +undump_int(head_tab[obj_type_xform]); +undump_int(head_tab[obj_type_ximage]); +undump_int(pdf_last_obj); +undump_int(pdf_last_xform); +undump_int(pdf_last_ximage); +end + + @ This is also done in C @<Dump the lua bytecodes@>= @@ -29583,7 +25836,7 @@ if interaction=batch_mode then selector:=log_only else selector:=term_and_log; pack_job_name(format_extension); while not w_open_out(fmt_file) do - prompt_file_name("format file name",format_extension); + prompt_file_name('format file name',format_extension); print_nl("Beginning to dump on file "); @.Beginning to dump...@> slow_print(w_make_name_string(fmt_file)); flush_string; @@ -29673,6 +25926,7 @@ ready_already:=314159; start_of_TEX: @<Initialize the output routines@>; @<Get the first line of input and prepare to start@>; history:=spotless; {ready to go!} +@<Initialize synctex primitive@> main_control; {come to life} final_cleanup; {prepare for death} end_of_TEX: close_files_and_terminate; @@ -29703,6 +25957,8 @@ end; procedure print_version_banner; begin wterm(banner); +wterm(', build '); +do_write_wterm(luatex_svnversion); end; @@ -29723,52 +25979,54 @@ This program doesn't bother to close the input files that may still be open. @<Last-minute...@>= procedure close_files_and_terminate; label done, done1; -var a, b, c, i, j, k, l: integer; {all-purpose index} - is_root: boolean; {|pdf_last_pages| is root of Pages tree?} +var a, b, i, j, k, l: integer; {all-purpose index} is_names: boolean; {flag for name tree output: is it Names or Kids?} root, outlines, threads, names_tree, dests: integer; xref_offset_width, names_head, names_tail: integer; - callback_id:integer; - res:boolean; + callback_id:integer; + res:boolean; begin callback_id:=callback_defined(stop_run_callback); @<Finish the extensions@>; @!stat if tracing_stats>0 then if callback_id=0 then @<Output statistics about this job@>;@;@+tats@/ wake_up_terminal; -if not fixed_pdfoutput_set then +if not fixed_pdfoutput_set then {else there will be an infinite loop in error case} fix_pdfoutput; if fixed_pdfoutput > 0 then begin if history = fatal_error_stop then begin remove_pdffile; print_err(" ==> Fatal error occurred, no output PDF file produced!") - end + end else begin @<Finish the PDF file@>; - if callback_id=0 then begin - if log_opened then - begin wlog_cr; - wlog_ln('PDF statistics:'); - wlog_ln(' ',obj_ptr:1,' PDF objects out of ',obj_tab_size:1, - ' (max. ',sup_obj_tab_size:1,')'); - if pdf_os_cntr > 0 then begin - wlog(' ',((pdf_os_cntr - 1) * pdf_os_max_objs + pdf_os_objidx + 1):1, - ' compressed objects within ',pdf_os_cntr:1,' object stream'); - if pdf_os_cntr > 1 then - wlog('s'); - wlog_cr; + if callback_id=0 then begin + if log_opened then + begin wlog_cr; + wlog_ln('PDF statistics:'); + wlog_ln(' ',obj_ptr:1,' PDF objects out of ',obj_tab_size:1, + ' (max. ',sup_obj_tab_size:1,')'); + if pdf_os_cntr > 0 then begin + wlog(' ',((pdf_os_cntr - 1) * pdf_os_max_objs + pdf_os_objidx + 1):1, + ' compressed objects within ',pdf_os_cntr:1,' object stream'); + if pdf_os_cntr > 1 then + wlog('s'); + wlog_cr; + end; + wlog_ln(' ',pdf_dest_names_ptr:1,' named destinations out of ',dest_names_size:1, + ' (max. ',sup_dest_names_size:1,')'); + wlog_ln(' ',pdf_mem_ptr:1,' words of extra memory for PDF output out of ',pdf_mem_size:1, + ' (max. ',sup_pdf_mem_size:1,')'); end; - wlog_ln(' ',pdf_dest_names_ptr:1,' named destinations out of ',dest_names_size:1, - ' (max. ',sup_dest_names_size:1,')'); - wlog_ln(' ',pdf_mem_ptr:1,' words of extra memory for PDF output out of ',pdf_mem_size:1, - ' (max. ',sup_pdf_mem_size:1,')'); - end; end; end; end else begin @<Finish the \.{DVI} file@>; end; +@<Close {\sl Sync\TeX} file and write status@>; +free_text_codes; +free_math_codes; if log_opened then begin wlog_cr; selector:=selector-2; if (selector=term_only)and(callback_id=0) then begin @@ -29827,8 +26085,8 @@ while input_ptr>0 do if state=token_list then end_token_list@+else end_file_reading; while open_parens>0 do begin - if tracefilenames then print(" )"); - decr(open_parens); + if tracefilenames then print(" )"); + decr(open_parens); end; if cur_level>level_one then begin print_nl("("); print_esc("end occurred "); @@ -29863,6 +26121,7 @@ if c=1 then delete_split_first_mark(i); delete_split_bot_mark(i); end; for c:=last_box_code to vsplit_code do flush_node_list(disc_ptr[c]); + if last_glue<>max_halfword then delete_glue_ref(last_glue); @<Close the pseudo files@>; store_fmt_file; return;@+tini@/ print_nl("(\dump is performed only by INITEX)"); return; @@ -29907,7 +26166,7 @@ else buffer[limit]:=end_line_char; fix_date_and_time;@/ random_seed :=(microseconds*1000)+(epochseconds mod 1000000);@/ init_randoms(random_seed);@/ -@<Compute the magic offset@>; +initialize_math; @<Initialize the print |selector|...@>; if (loc<limit)and(get_cat_code(cat_code_table,buffer[loc])<>escape) then start_input; {\.{\\input} assumed} @@ -30033,18 +26292,17 @@ case of \.{\\openout}, we need three words and three auxiliary subfields to hold the string numbers for name, area, and extension. @d open_node=0 {|subtype| in whatsits that represent files to \.{\\openout}} -@d open_node_size==4 {number of words in an open/whatsit node} @d write_node=1 {|subtype| in whatsits that represent things to \.{\\write}} -@d write_node_size==3 {number of words in a write/whatsit node} @d close_node=2 {|subtype| in whatsits that represent streams to \.{\\closeout}} -@d close_node_size==3 {number of words in a write/whatsit node} @d special_node=3 {|subtype| in whatsits that represent \.{\\special} things} -@d special_node_size==3 {number of words in a write/whatsit node} -@d dir_node_size=4 {number of words in change direction node} @d dir_dir(#)==vinfo(#+2) {keep the direction to be taken} @d dir_level(#)==vlink(#+2) {the save level at which the direction was defined} @d dir_dvi_ptr(#)==vinfo(#+3) {for reflecting dvi output} @d dir_dvi_h(#)==vlink(#+3) {for reflecting dvi output} +@d dir_box_pos_h(#)==vinfo(#+4) {for reflecting dvi output} +@d dir_box_pos_v(#)==vlink(#+4) {for reflecting dvi output} +@d dir_cur_h(#)==vinfo(#+5) {for reflecting dvi output} +@d dir_cur_v(#)==vlink(#+5) {for reflecting dvi output} @d what_lang(#)==vlink(#+2) {language number, in the range |0..255|} @d what_lhm(#)==type(#+2) {minimum left fragment, in the range |1..63|} @d what_rhm(#)==subtype(#+2) {minimum right fragment, in the range |1..63|} @@ -30132,15 +26390,12 @@ stays the same. @d pdf_annot_node == pdftex_first_extension_code + 7 @d pdf_start_link_node == pdftex_first_extension_code + 8 @d pdf_end_link_node == pdftex_first_extension_code + 9 -@d pdf_end_link_node_size==3 @d pdf_outline_code == pdftex_first_extension_code + 10 @d pdf_dest_node == pdftex_first_extension_code + 11 @d pdf_thread_node == pdftex_first_extension_code + 12 @d pdf_start_thread_node == pdftex_first_extension_code + 13 @d pdf_end_thread_node == pdftex_first_extension_code + 14 -@d pdf_end_thread_node_size==3 @d pdf_save_pos_node == pdftex_first_extension_code + 15 -@d pdf_save_pos_node_size==3 @d pdf_info_code == pdftex_first_extension_code + 16 @d pdf_thread_data_node == pdftex_first_extension_code + 16 @d pdf_catalog_code == pdftex_first_extension_code + 17 @@ -30155,7 +26410,6 @@ stays the same. @d set_random_seed_code == pdftex_first_extension_code + 25 @d pdf_glyph_to_unicode_code == pdftex_first_extension_code + 26 @d late_lua_node == pdftex_first_extension_code + 27 -@d close_lua_node == pdftex_first_extension_code + 28 @d save_cat_code_table_code == pdftex_first_extension_code + 29 @d init_cat_code_table_code == pdftex_first_extension_code + 30 @d pdf_colorstack_node == pdftex_first_extension_code + 31 @@ -30165,94 +26419,95 @@ stays the same. @d pdftex_last_extension_code == pdftex_first_extension_code + 34 @<Put each...@>= -primitive("openout",extension,open_node);@/ +primitive_tex("openout",extension,open_node,0);@/ @!@:open_out_}{\.{\\openout} primitive@> -primitive("write",extension,write_node); write_loc:=cur_val;@/ +primitive_tex("write",extension,write_node,0); write_loc:=cur_val;@/ @!@:write_}{\.{\\write} primitive@> -primitive("closeout",extension,close_node);@/ +primitive_tex("closeout",extension,close_node,0);@/ @!@:close_out_}{\.{\\closeout} primitive@> -primitive("special",extension,special_node);@/ +primitive_tex("special",extension,special_node,0);@/ @!@:special_}{\.{\\special} primitive@> -primitive("immediate",extension,immediate_code);@/ +text(frozen_special):="special"; eqtb[frozen_special]:=eqtb[cur_val];@/ +primitive_tex("immediate",extension,immediate_code,0);@/ @!@:immediate_}{\.{\\immediate} primitive@> -primitive("localinterlinepenalty",assign_int,local_inter_line_penalty_code);@/ -primitive("localbrokenpenalty",assign_int,local_broken_penalty_code);@/ -primitive("pagedir",assign_dir,dir_base+page_direction_code);@/ -primitive("bodydir",assign_dir,dir_base+body_direction_code);@/ -primitive("pardir",assign_dir,dir_base+par_direction_code);@/ -primitive("textdir",assign_dir,dir_base+text_direction_code);@/ -primitive("mathdir",assign_dir,dir_base+math_direction_code);@/ -primitive("pagerightoffset",assign_dimen,dimen_base+page_right_offset_code); -primitive("pagebottomoffset",assign_dimen,dimen_base+page_bottom_offset_code); -primitive("pdfliteral",extension,pdf_literal_node);@/ +primitive_omega("localinterlinepenalty",assign_int,int_base+local_inter_line_penalty_code,int_base);@/ +primitive_omega("localbrokenpenalty",assign_int,int_base+local_broken_penalty_code,int_base);@/ +primitive_omega("pagedir",assign_dir,dir_base+page_direction_code,dir_base);@/ +primitive_omega("bodydir",assign_dir,dir_base+body_direction_code,dir_base);@/ +primitive_omega("pardir",assign_dir,dir_base+par_direction_code,dir_base);@/ +primitive_omega("textdir",assign_dir,dir_base+text_direction_code,dir_base);@/ +primitive_omega("mathdir",assign_dir,dir_base+math_direction_code,dir_base);@/ +primitive_luatex("pageleftoffset",assign_dimen,dimen_base+page_left_offset_code,dimen_base); +primitive_luatex("pagetopoffset",assign_dimen,dimen_base+page_top_offset_code,dimen_base); +primitive_aleph("pagerightoffset",assign_dimen,dimen_base+page_right_offset_code,dimen_base); +primitive_aleph("pagebottomoffset",assign_dimen,dimen_base+page_bottom_offset_code,dimen_base); +primitive_pdftex("pdfliteral",extension,pdf_literal_node,0);@/ @!@:pdf_literal_}{\.{\\pdfliteral} primitive@> -primitive("pdfcolorstack",extension,pdf_colorstack_node);@/ +primitive_pdftex("pdfcolorstack",extension,pdf_colorstack_node,0);@/ @!@:pdf_colorstack_}{\.{\\pdfcolorstack} primitive@> -primitive("pdfsetmatrix",extension,pdf_setmatrix_node);@/ +primitive_pdftex("pdfsetmatrix",extension,pdf_setmatrix_node,0);@/ @!@:pdf_setmatrix_}{\.{\\pdfsetmatrix} primitive@> -primitive("pdfsave",extension,pdf_save_node);@/ +primitive_pdftex("pdfsave",extension,pdf_save_node,0);@/ @!@:pdf_save_}{\.{\\pdfsave} primitive@> -primitive("pdfrestore",extension,pdf_restore_node);@/ +primitive_pdftex("pdfrestore",extension,pdf_restore_node,0);@/ @!@:pdf_restore_}{\.{\\pdfrestore} primitive@> -primitive("pdfobj",extension,pdf_obj_code);@/ +primitive_pdftex("pdfobj",extension,pdf_obj_code,0);@/ @!@:pdf_obj_}{\.{\\pdfobj} primitive@> -primitive("pdfrefobj",extension,pdf_refobj_node);@/ +primitive_pdftex("pdfrefobj",extension,pdf_refobj_node,0);@/ @!@:pdf_refobj_}{\.{\\pdfrefobj} primitive@> -primitive("pdfxform",extension,pdf_xform_code);@/ +primitive_pdftex("pdfxform",extension,pdf_xform_code,0);@/ @!@:pdf_xform_}{\.{\\pdfxform} primitive@> -primitive("pdfrefxform",extension,pdf_refxform_node);@/ +primitive_pdftex("pdfrefxform",extension,pdf_refxform_node,0);@/ @!@:pdf_refxform_}{\.{\\pdfrefxform} primitive@> -primitive("pdfximage",extension,pdf_ximage_code);@/ +primitive_pdftex("pdfximage",extension,pdf_ximage_code,0);@/ @!@:pdf_ximage_}{\.{\\pdfximage} primitive@> -primitive("pdfrefximage",extension,pdf_refximage_node);@/ +primitive_pdftex("pdfrefximage",extension,pdf_refximage_node,0);@/ @!@:pdf_refximage_}{\.{\\pdfrefximage} primitive@> -primitive("pdfannot",extension,pdf_annot_node);@/ +primitive_pdftex("pdfannot",extension,pdf_annot_node,0);@/ @!@:pdf_annot_}{\.{\\pdfannot} primitive@> -primitive("pdfstartlink",extension,pdf_start_link_node);@/ +primitive_pdftex("pdfstartlink",extension,pdf_start_link_node,0);@/ @!@:pdf_start_link_}{\.{\\pdfstartlink} primitive@> -primitive("pdfendlink",extension,pdf_end_link_node);@/ +primitive_pdftex("pdfendlink",extension,pdf_end_link_node,0);@/ @!@:pdf_end_link_}{\.{\\pdfendlink} primitive@> -primitive("pdfoutline",extension,pdf_outline_code);@/ +primitive_pdftex("pdfoutline",extension,pdf_outline_code,0);@/ @!@:pdf_outline_}{\.{\\pdfoutline} primitive@> -primitive("pdfdest",extension,pdf_dest_node);@/ +primitive_pdftex("pdfdest",extension,pdf_dest_node,0);@/ @!@:pdf_dest_}{\.{\\pdfdest} primitive@> -primitive("pdfthread",extension,pdf_thread_node);@/ +primitive_pdftex("pdfthread",extension,pdf_thread_node,0);@/ @!@:pdf_thread_}{\.{\\pdfthread} primitive@> -primitive("pdfstartthread",extension,pdf_start_thread_node);@/ +primitive_pdftex("pdfstartthread",extension,pdf_start_thread_node,0);@/ @!@:pdf_start_thread_}{\.{\\pdfstartthread} primitive@> -primitive("pdfendthread",extension,pdf_end_thread_node);@/ +primitive_pdftex("pdfendthread",extension,pdf_end_thread_node,0);@/ @!@:pdf_end_thread_}{\.{\\pdfendthread} primitive@> -primitive("pdfsavepos",extension,pdf_save_pos_node);@/ +primitive_pdftex("pdfsavepos",extension,pdf_save_pos_node,0);@/ @!@:pdf_save_pos_}{\.{\\pdfsavepos} primitive@> -primitive("pdfinfo",extension,pdf_info_code);@/ +primitive_pdftex("pdfinfo",extension,pdf_info_code,0);@/ @!@:pdf_info_}{\.{\\pdfinfo} primitive@> -primitive("pdfcatalog",extension,pdf_catalog_code);@/ +primitive_pdftex("pdfcatalog",extension,pdf_catalog_code,0);@/ @!@:pdf_catalog_}{\.{\\pdfcatalog} primitive@> -primitive("pdfnames",extension,pdf_names_code);@/ +primitive_pdftex("pdfnames",extension,pdf_names_code,0);@/ @!@:pdf_names_}{\.{\\pdfnames} primitive@> -primitive("pdfincludechars",extension,pdf_include_chars_code);@/ +primitive_pdftex("pdfincludechars",extension,pdf_include_chars_code,0);@/ @!@:pdf_include_chars_}{\.{\\pdfincludechars} primitive@> -primitive("pdffontattr",extension,pdf_font_attr_code);@/ +primitive_pdftex("pdffontattr",extension,pdf_font_attr_code,0);@/ @!@:pdf_font_attr_}{\.{\\pdffontattr} primitive@> -primitive("pdfmapfile",extension,pdf_map_file_code);@/ +primitive_pdftex("pdfmapfile",extension,pdf_map_file_code,0);@/ @!@:pdf_map_file_}{\.{\\pdfmapfile} primitive@> -primitive("pdfmapline",extension,pdf_map_line_code);@/ +primitive_pdftex("pdfmapline",extension,pdf_map_line_code,0);@/ @!@:pdf_map_line_}{\.{\\pdfmapline} primitive@> -primitive("pdftrailer",extension,pdf_trailer_code);@/ +primitive_pdftex("pdftrailer",extension,pdf_trailer_code,0);@/ @!@:pdf_trailer_}{\.{\\pdftrailer} primitive@> -primitive("savecatcodetable",extension,save_cat_code_table_code);@/ +primitive_luatex("savecatcodetable",extension,save_cat_code_table_code,0);@/ @!@:save_cat_code_table_}{\.{\\savecatcodetable} primitive@> -primitive("initcatcodetable",extension,init_cat_code_table_code);@/ +primitive_luatex("initcatcodetable",extension,init_cat_code_table_code,0);@/ @!@:init_cat_code_table_}{\.{\\initcatcodetable} primitive@> -primitive("pdfsetrandomseed",extension,set_random_seed_code);@/ +primitive_pdftex("pdfsetrandomseed",extension,set_random_seed_code,0);@/ @!@:set_random_seed_code}{\.{\\pdfsetrandomseed} primitive@> -primitive("latelua",extension,late_lua_node);@/ +primitive_luatex("latelua",extension,late_lua_node,0);@/ @!@:late_lua_node_}{\.{\\latelua} primitive@> -primitive("closelua",extension,close_lua_node);@/ -@!@:close_lua_node_}{\.{\\closelua} primitive@> -primitive("pdffontexpand",extension,pdf_font_expand_code);@/ +primitive_pdftex("pdffontexpand",extension,pdf_font_expand_code,0);@/ @!@:pdf_font_expand_}{\.{\\pdffontexpand} primitive@> -primitive("pdfglyphtounicode",extension,pdf_glyph_to_unicode_code);@/ +primitive_pdftex("pdfglyphtounicode",extension,pdf_glyph_to_unicode_code,0);@/ @!@:pdf_glyph_to_unicode_}{\.{\\pdfglyphtounicode} primitive@> @ The variable |write_loc| just introduced is used to provide an @@ -30261,52 +26516,6 @@ appropriate error message in case of ``runaway'' write texts. @<Glob...@>= @!write_loc:pointer; {|eqtb| address of \.{\\write}} -@ @<Cases of |print_cmd_chr|...@>= -extension: case chr_code of - open_node:print_esc("openout"); - write_node:print_esc("write"); - close_node:print_esc("closeout"); - special_node:print_esc("special"); - immediate_code:print_esc("immediate"); - pdf_annot_node: print_esc("pdfannot"); - pdf_catalog_code: print_esc("pdfcatalog"); - pdf_dest_node: print_esc("pdfdest"); - pdf_end_link_node: print_esc("pdfendlink"); - pdf_end_thread_node: print_esc("pdfendthread"); - pdf_font_attr_code: print_esc("pdffontattr"); - pdf_font_expand_code: print_esc("pdffontexpand"); - pdf_include_chars_code: print_esc("pdfincludechars"); - pdf_info_code: print_esc("pdfinfo"); - pdf_literal_node: print_esc("pdfliteral"); - pdf_colorstack_node: print_esc("pdfcolorstack"); - pdf_setmatrix_node: print_esc("pdfsetmatrix"); - pdf_save_node: print_esc("pdfsave"); - pdf_restore_node: print_esc("pdfrestore"); - pdf_map_file_code: print_esc("pdfmapfile"); - pdf_map_line_code: print_esc("pdfmapline"); - pdf_names_code: print_esc("pdfnames"); - pdf_obj_code: print_esc("pdfobj"); - pdf_outline_code: print_esc("pdfoutline"); - pdf_refobj_node: print_esc("pdfrefobj"); - pdf_refxform_node: print_esc("pdfrefxform"); - pdf_refximage_node: print_esc("pdfrefximage"); - pdf_save_pos_node: print_esc("pdfsavepos"); - pdf_start_link_node: print_esc("pdfstartlink"); - pdf_start_thread_node: print_esc("pdfstartthread"); - pdf_thread_node: print_esc("pdfthread"); - pdf_trailer_code: print_esc("pdftrailer"); - pdf_xform_code: print_esc("pdfxform"); - pdf_ximage_code: print_esc("pdfximage"); - save_cat_code_table_code: print_esc("savecatcodetable"); - init_cat_code_table_code: print_esc("initcatcodetable"); - set_random_seed_code: print_esc("pdfsetrandomseed"); - pdf_glyph_to_unicode_code: print_esc("pdfglyphtounicode"); - late_lua_node: print_esc("latelua"); - close_lua_node: print_esc("closelua"); - cancel_boundary_node: print_esc("noboundary"); - othercases print("[unknown extension!]") - endcases; - @ When an |extension| command occurs in |main_control|, in any mode, the |do_extension| routine is called. @@ -30318,6 +26527,7 @@ any_mode(extension):do_extension; procedure do_extension; var i,@!j,@!k:integer; {all-purpose integers} @!p,@!q,@!r:pointer; {all-purpose pointers} +@!sn:integer; {a potential lua state name} begin case cur_chr of open_node:@<Implement \.{\\openout}@>; write_node:@<Implement \.{\\write}@>; @@ -30358,7 +26568,6 @@ begin case cur_chr of set_random_seed_code: @<Implement \.{\\pdfsetrandomseed}@>; pdf_glyph_to_unicode_code: @<Implement \.{\\pdfglyphtounicode}@>; late_lua_node: @<Implement \.{\\latelua}@>; - close_lua_node: @<Implement \.{\\closelua}@>; othercases confusion("ext1") @:this can't happen ext1}{\quad ext1@> endcases; @@ -30468,9 +26677,9 @@ end; begin check_pdfoutput("\pdfliteral", true); new_whatsit(pdf_literal_node); - if scan_keyword("direct") then + if scan_keyword('direct') then pdf_literal_mode(tail) := direct_always - else if scan_keyword("page") then + else if scan_keyword('page') then pdf_literal_mode(tail) := direct_page else pdf_literal_mode(tail) := set_origin; @@ -30497,20 +26706,20 @@ begin print_err("Invalid negative color stack number"); @.Invalid negative color stack number@> help2("I'll use default color stack 0 here.")@/ - ("Proceed, with fingers corssed."); + ("Proceed, with fingers crossed."); error; cur_val := 0; end; - if scan_keyword("set") then begin + if scan_keyword('set') then begin i := colorstack_set; end - else if scan_keyword("push") then begin + else if scan_keyword('push') then begin i := colorstack_push; end - else if scan_keyword("pop") then begin + else if scan_keyword('pop') then begin i := colorstack_pop; end - else if scan_keyword("current") then begin + else if scan_keyword('current') then begin i := colorstack_current; end else begin @@ -30520,7 +26729,7 @@ begin new_whatsit(pdf_colorstack_node); pdf_colorstack_stack(tail) := cur_val; pdf_colorstack_cmd(tail) := i; - pdf_colorstack_data(tail) := null; + pdf_colorstack_data(tail) := null; if i <= colorstack_data then begin scan_pdf_ext_toks; pdf_colorstack_data(tail) := def_ref; @@ -30561,20 +26770,17 @@ end begin check_pdfoutput("\latelua", true); new_whatsit(late_lua_node); - scan_register_num; - late_lua_reg(tail) := cur_val; - scan_pdf_ext_toks; + if scan_keyword('name') then begin + scan_pdf_ext_toks; + late_lua_name(tail) := def_ref; + end; + sn:=0; + @<Parse optional lua state...@>; + if sn then late_lua_name(tail) := sn; + call_func(scan_toks(false, false)); late_lua_data(tail) := def_ref; end -@ @<Implement \.{\\closelua}@>= -begin - check_pdfoutput("\closelua", true); - new_whatsit(close_lua_node); - scan_register_num; - late_lua_reg(tail) := cur_val; -end - @ The \.{\\pdfobj} primitive is used to create a ``raw'' object in the PDF output file. The object contents will be hold in memory and will be written out only when the object is referenced by \.{\\pdfrefobj}. When \.{\\pdfobj} @@ -30588,7 +26794,7 @@ end @ @<Implement \.{\\pdfobj}@>= begin check_pdfoutput("\pdfobj", true); - if scan_keyword("reserveobjnum") then begin + if scan_keyword('reserveobjnum') then begin @<Scan an optional space@>; incr(pdf_obj_count); pdf_create_obj(obj_type_obj, pdf_obj_count); @@ -30596,7 +26802,7 @@ begin end else begin k := -1; - if scan_keyword("useobjnum") then begin + if scan_keyword('useobjnum') then begin scan_int; k := cur_val; if (k <= 0) or (k > obj_ptr) or (obj_data_ptr(k) <> 0) then begin @@ -30611,9 +26817,9 @@ begin k := obj_ptr; end; obj_data_ptr(k) := pdf_get_mem(pdfmem_obj_size); - if scan_keyword("stream") then begin + if scan_keyword('stream') then begin obj_obj_is_stream(k) := 1; - if scan_keyword("attr") then begin + if scan_keyword('attr') then begin scan_pdf_ext_toks; obj_obj_stream_attr(k) := def_ref; end @@ -30622,7 +26828,7 @@ begin end else obj_obj_is_stream(k) := 0; - if scan_keyword("file") then + if scan_keyword('file') then obj_obj_is_file(k) := 1 else obj_obj_is_file(k) := 0; @@ -30684,27 +26890,27 @@ begin pdf_create_obj(obj_type_xform, pdf_xform_count); k := obj_ptr; obj_data_ptr(k) := pdf_get_mem(pdfmem_xform_size); - if scan_keyword("attr") then begin + if scan_keyword('attr') then begin scan_pdf_ext_toks; obj_xform_attr(k) := def_ref; end else obj_xform_attr(k) := null; - if scan_keyword("resources") then begin + if scan_keyword('resources') then begin scan_pdf_ext_toks; obj_xform_resources(k) := def_ref; end else obj_xform_resources(k) := null; scan_int; - p:=box(cur_val); + p:=box(cur_val); if p = null then pdf_error("ext1", "\pdfxform cannot be used with a void box"); obj_xform_width(k) := width(p); obj_xform_height(k) := height(p); obj_xform_depth(k) := depth(p); obj_xform_box(k) := p; {save pointer to the box} - box(cur_val):=null; + box(cur_val):=null; pdf_last_xform := k; end @@ -30740,15 +26946,15 @@ warn_pdfpagebox := true; function scan_pdf_box_spec: integer; {scans PDF pagebox specification} begin scan_pdf_box_spec := 0; - if scan_keyword("mediabox") then + if scan_keyword('mediabox') then scan_pdf_box_spec := pdf_box_spec_media - else if scan_keyword("cropbox") then + else if scan_keyword('cropbox') then scan_pdf_box_spec := pdf_box_spec_crop - else if scan_keyword("bleedbox") then + else if scan_keyword('bleedbox') then scan_pdf_box_spec := pdf_box_spec_bleed - else if scan_keyword("trimbox") then + else if scan_keyword('trimbox') then scan_pdf_box_spec := pdf_box_spec_trim - else if scan_keyword("artbox") then + else if scan_keyword('artbox') then scan_pdf_box_spec := pdf_box_spec_art end; @@ -30761,17 +26967,17 @@ begin height(alt_rule) := null_flag; depth(alt_rule) := null_flag; reswitch: - if scan_keyword("width") then begin + if scan_keyword('width') then begin scan_normal_dimen; width(alt_rule) := cur_val; goto reswitch; end; - if scan_keyword("height") then begin + if scan_keyword('height') then begin scan_normal_dimen; height(alt_rule) := cur_val; goto reswitch; end; - if scan_keyword("depth") then begin + if scan_keyword('depth') then begin scan_normal_dimen; depth(alt_rule) := cur_val; goto reswitch; @@ -30780,7 +26986,7 @@ end; procedure scan_image; label reswitch; -var i, k, img_wd, img_ht, img_dp, ref: integer; +var k, img_wd, img_ht, img_dp, ref: integer; named, attr: str_number; s: str_number; page, pagebox, colorspace: integer; @@ -30796,22 +27002,22 @@ begin named := 0; page := 1; colorspace := 0; - if scan_keyword("attr") then begin + if scan_keyword('attr') then begin scan_pdf_ext_toks; attr := tokens_to_string(def_ref); delete_token_ref(def_ref); end; - if scan_keyword("named") then begin + if scan_keyword('named') then begin scan_pdf_ext_toks; named := tokens_to_string(def_ref); delete_token_ref(def_ref); page := 0; end - else if scan_keyword("page") then begin + else if scan_keyword('page') then begin scan_int; page := cur_val; end; - if scan_keyword("colorspace") then begin + if scan_keyword('colorspace') then begin scan_int; colorspace := cur_val; end; @@ -30868,7 +27074,7 @@ begin pdf_check_obj(obj_type_ximage, cur_val); new_whatsit(pdf_refximage_node); j := obj_data_ptr(cur_val); - pdf_ximage_ref(tail) := j; + pdf_ximage_idx(tail) := j; pdf_width(tail) := image_width(j); pdf_height(tail) := image_height(j); pdf_depth(tail) := image_depth(j); @@ -30941,11 +27147,11 @@ var p: integer; begin p := new_node(action_node,0); scan_action := p; - if scan_keyword("user") then + if scan_keyword('user') then pdf_action_type(p) := pdf_action_user - else if scan_keyword("goto") then + else if scan_keyword('goto') then pdf_action_type(p) := pdf_action_goto - else if scan_keyword("thread") then + else if scan_keyword('thread') then pdf_action_type(p) := pdf_action_thread else pdf_error("ext1", "action type missing"); @@ -30954,11 +27160,11 @@ begin pdf_action_tokens(p) := def_ref; return; end; - if scan_keyword("file") then begin + if scan_keyword('file') then begin scan_pdf_ext_toks; pdf_action_file(p) := def_ref; end; - if scan_keyword("page") then begin + if scan_keyword('page') then begin if pdf_action_type(p) <> pdf_action_goto then pdf_error("ext1", "only GoTo action can be used with `page'"); pdf_action_type(p) := pdf_action_page; @@ -30970,12 +27176,12 @@ begin scan_pdf_ext_toks; pdf_action_tokens(p) := def_ref; end - else if scan_keyword("name") then begin + else if scan_keyword('name') then begin scan_pdf_ext_toks; pdf_action_named_id(p) := 1; pdf_action_id(p) := def_ref; end - else if scan_keyword("num") then begin + else if scan_keyword('num') then begin if (pdf_action_type(p) = pdf_action_goto) and (pdf_action_file(p) <> null) then pdf_error("ext1", @@ -30988,10 +27194,10 @@ begin end else pdf_error("ext1", "identifier type missing"); - if scan_keyword("newwindow") then begin + if scan_keyword('newwindow') then begin pdf_action_new_window(p) := 1; @<Scan an optional space@>; end - else if scan_keyword("nonewwindow") then begin + else if scan_keyword('nonewwindow') then begin pdf_action_new_window(p) := 2; @<Scan an optional space@>; end else @@ -31013,7 +27219,7 @@ begin pdf_height(tail) := height(alt_rule); pdf_depth(tail) := depth(alt_rule); if (w = pdf_thread_node) or (w = pdf_start_thread_node) then begin - if scan_keyword("attr") then begin + if scan_keyword('attr') then begin scan_pdf_ext_toks; pdf_thread_attr(tail) := def_ref; end @@ -31028,11 +27234,11 @@ end; @ @<Implement \.{\\pdfannot}@>= begin check_pdfoutput("\pdfannot", true); - if scan_keyword("reserveobjnum") then begin + if scan_keyword('reserveobjnum') then begin pdf_last_annot := pdf_new_objnum; @<Scan an optional space@>; end else begin - if scan_keyword("useobjnum") then begin + if scan_keyword('useobjnum') then begin scan_int; k := cur_val; if (k <= 0) or (k > obj_ptr) or (obj_annot_ptr(k) <> 0) then @@ -31059,8 +27265,8 @@ begin pdf_error("ext1", "\pdfstartlink cannot be used in vertical mode"); k := pdf_new_objnum; new_annot_whatsit(pdf_start_link_node); - pdf_link_attr(tail) := null; - if scan_keyword("attr") then begin + pdf_link_attr(tail) := null; + if scan_keyword('attr') then begin scan_pdf_ext_toks; pdf_link_attr(tail) := def_ref; end; @@ -31096,14 +27302,14 @@ end; @ @<Implement \.{\\pdfoutline}@>= begin check_pdfoutput("\pdfoutline", true); - if scan_keyword("attr") then begin + if scan_keyword('attr') then begin scan_pdf_ext_toks; r := def_ref; end else r := 0; p := scan_action; - if scan_keyword("count") then begin + if scan_keyword('count') then begin scan_int; i := cur_val; end @@ -31198,7 +27404,7 @@ begin check_pdfoutput("\pdfdest", true); q := tail; new_whatsit(pdf_dest_node); - if scan_keyword("num") then begin + if scan_keyword('num') then begin scan_int; if cur_val <= 0 then pdf_error("ext1", "num identifier must be positive"); @@ -31207,16 +27413,16 @@ begin pdf_dest_id(tail) := cur_val; pdf_dest_named_id(tail) := 0; end - else if scan_keyword("name") then begin + else if scan_keyword('name') then begin scan_pdf_ext_toks; pdf_dest_id(tail) := def_ref; pdf_dest_named_id(tail) := 1; end else pdf_error("ext1", "identifier type missing"); - if scan_keyword("xyz") then begin + if scan_keyword('xyz') then begin pdf_dest_type(tail) := pdf_dest_xyz; - if scan_keyword("zoom") then begin + if scan_keyword('zoom') then begin scan_int; if cur_val > max_halfword then pdf_error("ext1", "number too big"); @@ -31225,19 +27431,19 @@ begin else pdf_dest_xyz_zoom(tail) := null; end - else if scan_keyword("fitbh") then + else if scan_keyword('fitbh') then pdf_dest_type(tail) := pdf_dest_fitbh - else if scan_keyword("fitbv") then + else if scan_keyword('fitbv') then pdf_dest_type(tail) := pdf_dest_fitbv - else if scan_keyword("fitb") then + else if scan_keyword('fitb') then pdf_dest_type(tail) := pdf_dest_fitb - else if scan_keyword("fith") then + else if scan_keyword('fith') then pdf_dest_type(tail) := pdf_dest_fith - else if scan_keyword("fitv") then + else if scan_keyword('fitv') then pdf_dest_type(tail) := pdf_dest_fitv - else if scan_keyword("fitr") then + else if scan_keyword('fitr') then pdf_dest_type(tail) := pdf_dest_fitr - else if scan_keyword("fit") then + else if scan_keyword('fit') then pdf_dest_type(tail) := pdf_dest_fit else pdf_error("ext1", "destination type missing"); @@ -31267,7 +27473,7 @@ end @ @<Declare procedures needed in |do_ext...@>= procedure scan_thread_id; begin - if scan_keyword("num") then begin + if scan_keyword('num') then begin scan_int; if cur_val <= 0 then pdf_error("ext1", "num identifier must be positive"); @@ -31276,7 +27482,7 @@ begin pdf_thread_id(tail) := cur_val; pdf_thread_named_id(tail) := 0; end - else if scan_keyword("name") then begin + else if scan_keyword('name') then begin scan_pdf_ext_toks; pdf_thread_id(tail) := def_ref; pdf_thread_named_id(tail) := 1; @@ -31348,7 +27554,7 @@ begin scan_pdf_ext_toks; if pdf_output > 0 then pdf_catalog_toks := concat_tokens(pdf_catalog_toks, def_ref); - if scan_keyword("openaction") then begin + if scan_keyword('openaction') then begin if pdf_catalog_openaction <> 0 then pdf_error("ext1", "duplicate of openaction") else begin @@ -31398,14 +27604,14 @@ end @ @<Implement \.{\\savecatcodetable}@>= begin scan_int; - if (cur_val<0)or(cur_val>@"FFFFFFF) then begin - print_err("Invalid \catcode table"); - help1("All \catcode table ids must be between 0 and 0xFFFFFFF"); - error; + if (cur_val<0)or(cur_val>@"FFFF) then begin + print_err("Invalid \catcode table"); + help1("All \catcode table ids must be between 0 and 0xFFFF"); + error; end else begin if cur_val=cat_code_table then begin print_err("Invalid \catcode table"); - help1("You cannot overwrite the current \catcode table"); + help1("You cannot overwrite the current \catcode table"); error; end else @@ -31416,15 +27622,15 @@ end @ @<Implement \.{\\initcatcodetable}@>= begin scan_int; - if (cur_val<0)or(cur_val>@"FFFFFFF) then begin - print_err("Invalid \catcode table"); - help1("All \catcode table ids must be between 0 and 0xFFFFFFF"); - error; + if (cur_val<0)or(cur_val>@"FFFF) then begin + print_err("Invalid \catcode table"); + help1("All \catcode table ids must be between 0 and 0xFFFF"); + error; end else begin if cur_val=cat_code_table then begin print_err("Invalid \catcode table"); - help1("You cannot overwrite the current \catcode table"); - error; + help1("You cannot overwrite the current \catcode table"); + error; end else initex_cat_codes(cur_val); @@ -31605,27 +27811,6 @@ begin until a = b; end; -@ @<Display <rule spec> for whatsit node created by \pdfTeX@>= -print("("); -print_rule_dimen(pdf_height(p)); -print_char("+"); -print_rule_dimen(pdf_depth(p)); -print(")x"); -print_rule_dimen(pdf_width(p)) - -@ Each new type of node that appears in our data structure must be capable -of being displayed, copied, destroyed, and so on. The routines that we -need for write-oriented whatsits are somewhat like those for mark nodes; -other extensions might, of course, involve more subtlety here. - -@<Basic printing...@>= -procedure print_write_whatsit(@!s:str_number;@!p:pointer); -begin print_esc(s); -if write_stream(p)<16 then print_int(write_stream(p)) -else if write_stream(p)=16 then print_char("*") -@.*\relax@> -else print_char("-"); -end; @ Three extra node types carry information from |main_control|. @@ -31646,237 +27831,10 @@ typesetting engine itself. Each has an id, a type, and a value. The type of the value depends on the |user_node_type| field. @d user_defined_node==cancel_boundary_node+1 -@d user_defined_node_size=4 @d user_node_id(#)==vlink(#+2) @d user_node_type(#)==vinfo(#+2) @d user_node_value(#)==vinfo(#+3) -@ @<Display the whatsit...@>= -case subtype(p) of -open_node:begin print_write_whatsit("openout",p); - print_char("="); print_file_name(open_name(p),open_area(p),open_ext(p)); - end; -write_node:begin print_write_whatsit("write",p); - print_mark(write_tokens(p)); - end; -close_node:print_write_whatsit("closeout",p); -special_node:begin print_esc("special"); - print_mark(write_tokens(p)); - end; -dir_node: - if dir_dir(p)<0 then begin - print_esc("enddir"); print(" "); print_dir(dir_dir(p)+64); - end - else begin - print_esc("begindir"); print(" "); print_dir(dir_dir(p)); - end; -@<LOCAL: print out |local_paragraph| node@>; -pdf_literal_node: begin - print_esc("pdfliteral"); - case pdf_literal_mode(p) of - set_origin: - do_nothing; - direct_page: - print(" page"); - direct_always: - print(" direct"); - othercases confusion("literal2") - endcases; - print_mark(pdf_literal_data(p)); -end; -pdf_colorstack_node: begin - print_esc("pdfcolorstack "); - print_int(pdf_colorstack_stack(p)); - case pdf_colorstack_cmd(p) of - colorstack_set: - print(" set "); - colorstack_push: - print(" push "); - colorstack_pop: - print(" pop"); - colorstack_current: - print(" current"); - othercases confusion("pdfcolorstack") - endcases; - if pdf_colorstack_cmd(p) <= colorstack_data then - print_mark(pdf_colorstack_data(p)); -end; -pdf_setmatrix_node: begin - print_esc("pdfsetmatrix"); - print_mark(pdf_setmatrix_data(p)); -end; -pdf_save_node: begin - print_esc("pdfsave"); -end; -pdf_restore_node: begin - print_esc("pdfrestore"); -end; -cancel_boundary_node: begin - print_esc("noboundary"); -end; -late_lua_node: begin - print_esc("latelua"); - print_int(late_lua_reg(p)); - print_mark(late_lua_data(p)); -end; -close_lua_node: begin - print_esc("closelua"); - print_int(late_lua_reg(p)); -end; -pdf_refobj_node: begin - print_esc("pdfrefobj"); - if obj_obj_is_stream(pdf_obj_objnum(p)) > 0 then begin - if obj_obj_stream_attr(pdf_obj_objnum(p)) <> null then begin - print(" attr"); - print_mark(obj_obj_stream_attr(pdf_obj_objnum(p))); - end; - print(" stream"); - end; - if obj_obj_is_file(pdf_obj_objnum(p)) > 0 then - print(" file"); - print_mark(obj_obj_data(pdf_obj_objnum(p))); -end; -pdf_refxform_node: begin - print_esc("pdfrefxform"); - print("("); - print_scaled(obj_xform_height(pdf_xform_objnum(p))); - print_char("+"); - print_scaled(obj_xform_depth(pdf_xform_objnum(p))); - print(")x"); - print_scaled(obj_xform_width(pdf_xform_objnum(p))); -end; -pdf_refximage_node: begin - print_esc("pdfrefximage"); - print("("); - print_scaled(pdf_height(p)); - print_char("+"); - print_scaled(pdf_depth(p)); - print(")x"); - print_scaled(pdf_width(p)); -end; -pdf_annot_node: begin - print_esc("pdfannot"); - @<Display <rule spec> for whatsit node created by \pdfTeX@>; - print_mark(pdf_annot_data(p)); -end; -pdf_start_link_node: begin - print_esc("pdflink"); - @<Display <rule spec> for whatsit node created by \pdfTeX@>; - if pdf_link_attr(p) <> null then begin - print(" attr"); - print_mark(pdf_link_attr(p)); - end; - print(" action"); - if pdf_action_type(pdf_link_action(p)) = pdf_action_user then begin - print(" user"); - print_mark(pdf_action_tokens(pdf_link_action(p))); - return; - end; - if pdf_action_file(pdf_link_action(p)) <> null then begin - print(" file"); - print_mark(pdf_action_file(pdf_link_action(p))); - end; - case pdf_action_type(pdf_link_action(p)) of - pdf_action_goto: begin - if pdf_action_named_id(pdf_link_action(p)) > 0 then begin - print(" goto name"); - print_mark(pdf_action_id(pdf_link_action(p))); - end - else begin - print(" goto num"); - print_int(pdf_action_id(pdf_link_action(p))) - end; - end; - pdf_action_page: begin - print(" page"); - print_int(pdf_action_id(pdf_link_action(p))); - print_mark(pdf_action_tokens(pdf_link_action(p))); - end; - pdf_action_thread: begin - if pdf_action_named_id(pdf_link_action(p)) > 0 then begin - print(" thread name"); - print_mark(pdf_action_id(pdf_link_action(p))); - end - else begin - print(" thread num"); - print_int(pdf_action_id(pdf_link_action(p))); - end; - end; - othercases pdf_error("displaying", "unknown action type"); - endcases; -end; -pdf_end_link_node: print_esc("pdfendlink"); -pdf_dest_node: begin - print_esc("pdfdest"); - if pdf_dest_named_id(p) > 0 then begin - print(" name"); - print_mark(pdf_dest_id(p)); - end - else begin - print(" num"); - print_int(pdf_dest_id(p)); - end; - print(" "); - case pdf_dest_type(p) of - pdf_dest_xyz: begin - print("xyz"); - if pdf_dest_xyz_zoom(p) <> null then begin - print(" zoom"); - print_int(pdf_dest_xyz_zoom(p)); - end; - end; - pdf_dest_fitbh: print("fitbh"); - pdf_dest_fitbv: print("fitbv"); - pdf_dest_fitb: print("fitb"); - pdf_dest_fith: print("fith"); - pdf_dest_fitv: print("fitv"); - pdf_dest_fitr: begin - print("fitr"); - @<Display <rule spec> for whatsit node created by \pdfTeX@>; - end; - pdf_dest_fit: print("fit"); - othercases print("unknown!"); - endcases; -end; -pdf_thread_node, -pdf_start_thread_node: begin - if subtype(p) = pdf_thread_node then - print_esc("pdfthread") - else - print_esc("pdfstartthread"); - print("("); print_rule_dimen(pdf_height(p)); print_char("+"); - print_rule_dimen(pdf_depth(p)); print(")x"); - print_rule_dimen(pdf_width(p)); - if pdf_thread_attr(p) <> null then begin - print(" attr"); - print_mark(pdf_thread_attr(p)); - end; - if pdf_thread_named_id(p) > 0 then begin - print(" name"); - print_mark(pdf_thread_id(p)); - end - else begin - print(" num"); - print_int(pdf_thread_id(p)); - end; -end; -pdf_end_thread_node: print_esc("pdfendthread"); -pdf_save_pos_node: print_esc("pdfsavepos"); -user_defined_node: begin - print_esc("whatsit"); - print_int(user_node_id(p)); - print_char("="); - case user_node_type(p) of - "a": print("<>"); - "n": begin print("["); show_node_list(user_node_value(p)); print("]"); end; - "s": begin print(""""); print(user_node_value(p)); print(""""); end; - "t": print_mark(user_node_value(p)); - othercases { only d } - print_int(user_node_value(p)); - endcases; - end; -othercases print("whatsit?") -endcases @ @<Incorporate a whatsit node into a vbox@>= if (subtype(p) = pdf_refxform_node) or (subtype(p) = pdf_refximage_node) then @@ -31901,12 +27859,6 @@ end; end; end -@ @<Let |d| be the width of the whatsit |p|@>= -if (subtype(p) = pdf_refxform_node) or (subtype(p) = pdf_refximage_node) then - d := pdf_width(p) -else - d := 0 - @ @<Prepare to move whatsit |p| to the current page, then |goto contribute|@>= begin if (subtype(p) = pdf_refxform_node) or (subtype(p) = pdf_refximage_node) then @@ -31939,7 +27891,7 @@ that actually send out the requested data. Let's do \.{\\special} first procedure special_out(@!p:pointer); var old_setting:0..max_selector; {holds print |selector|} @!k:pool_pointer; {index into |str_pool|} -begin synch_h; synch_v;@/ +begin synch_dvi_with_cur;@/ old_setting:=selector; selector:=new_string; show_token_list(link(write_tokens(p)),null,pool_size-pool_ptr); selector:=old_setting; @@ -31983,6 +27935,13 @@ else begin {write to the terminal if file isn't open} token_show(def_ref); print_ln; flush_list(def_ref); selector:=old_setting; end; +procedure expand_late_lua(@!p:pointer); +var @!old_mode:integer; {saved |mode|} +@!q,@!r:pointer; {temporary variables for list manipulation} +begin @<Expand macros in the token list + and make |link(def_ref)| point to the result@>; +end; + @ The final line of this routine is slightly subtle; at least, the author didn't think about it until getting burnt! There is a used-up token list @@ -32029,18 +27988,20 @@ open_node,write_node,close_node:@<Do some work that has been queued up for \.{\\write}@>; special_node:special_out(p); pdf_save_pos_node: - @<Save current position in DVI mode@>; + @<Save current position@>; local_par_node:do_nothing; cancel_boundary_node: do_nothing; +user_defined_node: do_nothing; othercases confusion("ext4") {TH: those will be pdf extension nodes in dvi mode, most likely} @:this can't happen ext4}{\quad ext4@> endcases; end; -@ @<Save current position in DVI mode@>= +@ @<Save current position@>= begin - pdf_last_x_pos := cur_h + one_inch; - pdf_last_y_pos := cur_page_height - cur_v - one_inch; + synch_pos_with_cur; + pdf_last_x_pos := pos.h; + pdf_last_y_pos := pos.v; end @ We don't implement \.{\\write} inside of leaders. (The reason is that @@ -32060,7 +28021,7 @@ if not doing_leaders then if cur_ext="" then cur_ext:=".tex"; pack_cur_name; while not lua_a_open_out(write_file[j],(j+1)) do - prompt_file_name("output file name",".tex"); + prompt_file_name('output file name','.tex'); write_file[j]:= name_file_pointer; write_open[j]:=true; end; @@ -32081,10 +28042,6 @@ if cur_cmd=extension then begin flush_node_list(tail); tail:=p; vlink(p):=null; end else case cur_chr of - close_lua_node: begin - scan_register_num; - closelua(cur_val); - end; pdf_obj_code: begin do_extension; {scan object and set |pdf_last_obj|} if obj_data_ptr(pdf_last_obj) = 0 then {this object has not been initialized yet} @@ -32118,7 +28075,6 @@ for k:=0 to 15 do if write_open[k] then lua_a_close_out(write_file[k]) @d local_box_right(#)==vlink(#+4) {\.{\\localleftbox}} @d local_box_right_width(#)==vinfo(#+4) @d local_par_dir(#)==vinfo(#+5) -@d local_par_size==6 @<LOCAL: Declare |make_local_par_node|@>= function make_local_par_node:pointer; @@ -32140,51 +28096,18 @@ local_par_dir(p):=par_direction; make_local_par_node:=p; end -@ @<LOCAL: print out |local_paragraph| node@>= -local_par_node: begin - print_esc("whatsit"); - append_char("."); - print_ln; print_current_string; - print_esc("localinterlinepenalty"); print("="); - print_int(local_pen_inter(p)); - print_ln; print_current_string; - print_esc("localbrokenpenalty"); print("="); - print_int(local_pen_broken(p)); - print_ln; print_current_string; - print_esc("localleftbox"); - if local_box_left(p)=null then print("=null") - else begin - append_char("."); - show_node_list(local_box_left(p)); - decr(pool_ptr); - end; - print_ln; print_current_string; - print_esc("localrightbox"); - if local_box_right(p)=null then print("=null") - else begin - append_char("."); - show_node_list(local_box_right(p)); - decr(pool_ptr); - end; - decr(pool_ptr); - end - @ @<LOCAL: Add local paragraph node@>= begin tail_append(make_local_par_node) end @ @<DIR: Assign direction codes@>= case cur_chr of dir_base+page_direction_code: begin - if its_all_over then begin scan_direction; eq_word_define(dir_base+page_direction_code,cur_val); - end; end; dir_base+body_direction_code: begin - if its_all_over then begin scan_direction; eq_word_define(dir_base+body_direction_code,cur_val); - end; end; dir_base+par_direction_code: begin scan_direction; @@ -32239,12 +28162,6 @@ dir_dir(p):=s; dir_dvi_ptr(p):=-1; dir_level(p):=cur_level; new_dir:=p; end -@ @<Append a begin direction to the tail of the current list@>= -tail_append(new_dir(math_direction)) - -@ @<Append an end direction to the tail of the current list@>= -tail_append(new_dir(math_direction-64)) - @ @<DIR: Add local dir node@>= tail_append(new_dir(text_direction)) @@ -32267,26 +28184,6 @@ begin pop_dir_node end -@ @<DIR: |unsave| math@>= -begin -unsave; -decr(save_ptr); -flush_node_list(text_dir_ptr); -text_dir_ptr:=saved(0); -end - -@ @<DIR: |new_save_level| math@>= -begin -saved(0):=text_dir_ptr; -text_dir_ptr:=new_dir(math_direction); -incr(save_ptr); -new_save_level(c); -eq_word_define(dir_base+body_direction_code,math_direction); -eq_word_define(dir_base+par_direction_code,math_direction); -eq_word_define(dir_base+text_direction_code,math_direction); -eq_word_define(int_base+level_local_dir_code,cur_level); -end - @ @<DIR: Adjust |text_dir_ptr| for |scan_spec|@>= begin if spec_direction<>-1 then begin @@ -32328,92 +28225,36 @@ end @ @<Output a reflection instruction if the direction has changed@>= begin -if dir_dir(p)>=0 then - begin synch_h; synch_v; - push_dir_node(p); - if dir_opposite(dir_secondary[dir_dir(dir_ptr)])(dir_secondary[dvi_direction]) - then begin - if (dir_secondary[dvi_direction]=0) or - (dir_secondary[dvi_direction]=2) then - dvi_out(down4) - else - dvi_out(right4); - dir_dvi_ptr(dir_ptr):=dvi_ptr; - dir_dvi_h(dir_ptr):=dvi_h; - dvi_four(0); - cur_h:=0; dvi_h:=0; - end - else begin - dir_dvi_ptr(dir_ptr):=dvi_ptr; - dir_dvi_h(dir_ptr):=dvi_h; - end; - dvi_direction:=dir_dir(dir_ptr); + if dir_dir(p)>=0 then begin + push_dir_node(p); + @<(PDF) Calculate the needed width to the matching |enddir|, and store it in |w|, as + well as in the enddir's |dir_dvi_h|@>; + if (dir_opposite(dir_secondary[dir_dir(dir_ptr)])(dir_secondary[dvi_direction])) + or (dir_eq(dir_secondary[dir_dir(dir_ptr)])(dir_secondary[dvi_direction])) + then begin + dir_cur_h(temp_ptr) := cur.h + w; + if dir_opposite(dir_secondary[dir_dir(dir_ptr)])(dir_secondary[dvi_direction]) then + cur.h := cur.h + w; + end else + dir_cur_h(temp_ptr) := cur.h; + dir_cur_v(temp_ptr) := cur.v; + dir_box_pos_h(temp_ptr) := box_pos.h; + dir_box_pos_v(temp_ptr) := box_pos.v; + synch_pos_with_cur; {no need for |synch_dvi_with_cur|, as there is no DVI grouping} + box_pos := pos; {fake a nested |hlist_out|} + set_to_zero(cur); + dvi_direction:=dir_dir(dir_ptr); end -else begin - dvi_dir_h:=dir_dvi_h(dir_ptr); - dvi_dir_ptr:=dir_dvi_ptr(dir_ptr); - pop_dir_node; - synch_h; synch_v; - if dir_ptr<>null then - dvi_direction:=dir_dir(dir_ptr) - else - dvi_direction:=0; - if dir_opposite(dir_secondary[dir_dir(p)+64])(dir_secondary[dvi_direction]) - then begin - dvi_temp_ptr:=dvi_ptr; - dvi_ptr:=dvi_dir_ptr; - if (dir_secondary[dvi_direction]=0) or - (dir_secondary[dvi_direction]=1) then - dvi_four(dvi_h) - else - dvi_four(-dvi_h); - dvi_ptr:=dvi_temp_ptr; - if (dir_secondary[dvi_direction]=0) or - (dir_secondary[dvi_direction]=2) then - dvi_out(down4) - else - dvi_out(right4); - if (dir_secondary[dvi_direction]=0) or - (dir_secondary[dvi_direction]=1) then - dvi_four(dvi_h) + else begin + pop_dir_node; + box_pos.h := dir_box_pos_h(p); + box_pos.v := dir_box_pos_v(p); + cur.h := dir_cur_h(p); + cur.v := dir_cur_v(p); + if dir_ptr<>null then + dvi_direction:=dir_dir(dir_ptr) else - dvi_four(-dvi_h); - end; - cur_h:=dvi_dir_h+dvi_h; dvi_h:=cur_h; - end -end - -@ Many things regarding output work differently in pdf compared to dvi -output. The easiest way to deal with in-line direction changes in pdf -mode seems to be to move forward to find the needed width of the -reversed section, then skip forward (or backward, depending on your -viewpont) by that distance. - -@<(PDF) Output a reflection instruction if the direction has changed@>= -begin -if dir_dir(p)>=0 then begin - push_dir_node(p); - if dir_opposite(dir_secondary[dir_dir(dir_ptr)])(dir_secondary[dvi_direction]) - then begin - @<(PDF) Calculate the needed width to the matching |enddir|, and store it in |w|, as - well as in the enddir's |dir_dvi_h|@>; - case box_direction(dvi_direction) of - dir_TL_,dir_BL_: pdf_dvicmd_right(w); - dir_TR_,dir_BR_: pdf_dvicmd_left(w); - end; - end; - dvi_direction:=dir_dir(dir_ptr); - end -else begin - pop_dir_node; - if dir_ptr<>null then - dvi_direction:=dir_dir(dir_ptr) - else - dvi_direction:=0; - case box_direction(dvi_direction) of - dir_TL_,dir_BL_: pdf_dvicmd_right(dir_dvi_h(p)); - dir_TR_,dir_BR_: pdf_dvicmd_left(dir_dvi_h(p)); - end; + dvi_direction:=0; end end @@ -32423,7 +28264,34 @@ this segment, it stores the accumulated with in the |dir_dvi_h| field of that end node, so that when that node is found later in the processing, the correct glue correction can be applied. -@<(PDF) Calculate the needed width to the matching |enddir|...@>= +@p +function simple_advance_width(p:halfword):scaled; +var q:halfword; +@!w:scaled; +begin + q:=p; w:=0; + while (q<>null) and (vlink(q)<>null) do begin + q:=vlink(q); + if is_char_node(q) then begin + w:=w+glyph_width(q); + end + else begin + case type(q) of + hlist_node_case,vlist_node_case,rule_node_case, + margin_kern_node_case,kern_node_case: + w:=w+width(q); + disc_node_case: if vlink(no_break(q))<>null then begin + w:=w+simple_advance_width(no_break(q)); + end; + othercases do_nothing; + endcases; + end; + end; + simple_advance_width:=w; +end; + + +@ @<(PDF) Calculate the needed width to the matching |enddir|...@>= begin q:=p; w:=0; save_cur_g:=cur_g; @@ -32433,15 +28301,15 @@ begin {|w:=w-cur_g; cur_glue:=0;|} dir_nest:=1; while (q<>null) and (vlink(q)<>null) do begin - q:=vlink(q); + q:=vlink(q); if is_char_node(q) then begin w:=w+glyph_width(q); {TODO no vertical support for now} end else begin case type(q) of - hlist_node,vlist_node,rule_node, - margin_kern_node,kern_node:w:=w+width(q); - glue_node: begin + hlist_node_case,vlist_node_case,rule_node_case, + margin_kern_node_case,kern_node_case:w:=w+width(q); + glue_node_case: begin g:=glue_ptr(q); w:=w+width(g)-cur_g; if g_sign<>normal then @@ -32460,13 +28328,17 @@ begin end; w:=w+cur_g; end; - math_node: w:=w+surround(q); - whatsit_node: begin + disc_node_case: if vlink(no_break(q))<>null then begin + w:=w+simple_advance_width(no_break(q)); + end; + math_node_case: w:=w+surround(q); + whatsit_node_case: begin if subtype(q)=dir_node then begin if dir_dir(q)>=0 then incr(dir_nest) else decr(dir_nest); if dir_nest=0 then begin dir_dvi_h(q) := w; - q:=null; + temp_ptr := q; + q:=null; end; end else if (subtype(q) = pdf_refxform_node) or @@ -32491,10 +28363,7 @@ dest_name_entry = record end; @ @<Glob...@>= -@!cur_page_width: scaled; {width of page being shipped} -@!cur_page_height: scaled; {height of page being shipped} -@!cur_right_offset: scaled; {horizontal inverted offset of page being shipped} -@!cur_bottom_offset: scaled; {vertical inverted offset of page being shipped} +@!cur_page_size: scaledpos; {width and height of page being shipped} @!pdf_obj_list: pointer; {list of objects in the current page} @!pdf_xform_list: pointer; {list of forms in the current page} @!pdf_ximage_list: pointer; {list of images in the current page} @@ -32621,33 +28490,39 @@ begin d:=0; pdf_print_ln(" >>"); end; -procedure set_rect_dimens(p, parent_box: pointer; x, y, w, h, d, margin: scaled); +procedure set_rect_dimens(p, parent_box: pointer; x, y, wd, ht, dp, margin: scaled); +var ll, ur, pos_ll, pos_ur, tmp: scaledpos; begin - pdf_left(p) := cur_h; - if is_running(w) then - pdf_right(p) := x + width(parent_box) + ll.h := cur.h; + if is_running(dp) then + ll.v := y + depth(parent_box) else - pdf_right(p) := cur_h + w; - if is_running(h) then - pdf_top(p) := y - height(parent_box) + ll.v := cur.v + dp; + if is_running(wd) then + ur.h := x + width(parent_box) else - pdf_top(p) := cur_v - h; - if is_running(d) then - pdf_bottom(p) := y + depth(parent_box) + ur.h := cur.h + wd; + if is_running(ht) then + ur.v := y - height(parent_box) else - pdf_bottom(p) := cur_v + d; + ur.v := cur.v - ht; + pos_ll := synch_p_with_c(ll); + pos_ur := synch_p_with_c(ur); + if pos_ll.h > pos_ur.h then begin + tmp.h := pos_ll.h; pos_ll.h := pos_ur.h; pos_ur.h := tmp.h; end; + if pos_ll.v > pos_ur.v then begin + tmp.v := pos_ll.v; pos_ll.v := pos_ur.v; pos_ur.v := tmp.v; end; if is_shipping_page and matrixused then begin - matrixtransformrect(pdf_left(p), cur_page_height - pdf_bottom(p), - pdf_right(p), cur_page_height - pdf_top(p)); - pdf_left(p) := getllx; - pdf_bottom(p) := cur_page_height - getlly; - pdf_right(p) := geturx; - pdf_top(p) := cur_page_height - getury; + matrixtransformrect(pos_ll.h, pos_ll.v, pos_ur.h, pos_ur.v); + pos_ll.h := getllx; + pos_ll.v := getlly; + pos_ur.h := geturx; + pos_ur.v := getury; end; - pdf_left(p) := pdf_left(p) - margin; - pdf_top(p) := pdf_top(p) - margin; - pdf_right(p) := pdf_right(p) + margin; - pdf_bottom(p) := pdf_bottom(p) + margin; + pdf_ann_left(p) := pos_ll.h - margin; + pdf_ann_bottom(p) := pos_ll.v - margin; + pdf_ann_right(p) := pos_ur.h + margin; + pdf_ann_top(p) := pos_ur.v + margin; end; procedure do_annot(p, parent_box: pointer; x, y: scaled); @@ -32656,13 +28531,16 @@ begin pdf_error("ext4", "annotations cannot be inside an XForm"); if doing_leaders then return; + if is_obj_scheduled(pdf_annot_objnum(p)) then + pdf_annot_objnum(p) := pdf_new_objnum; set_rect_dimens(p, parent_box, x, y, pdf_width(p), pdf_height(p), pdf_depth(p), 0); obj_annot_ptr(pdf_annot_objnum(p)) := p; pdf_append_list(pdf_annot_objnum(p))(pdf_annot_list); + set_obj_scheduled(pdf_annot_objnum(p)); end; -@ To implement nesting link annotations, we need a stack to hold copy of +@ To implement nested link annotations, we need a stack to hold copy of |pdf_start_link_node|'s that are being written out, together with their box nesting level. @@ -32673,7 +28551,7 @@ nesting level. @ @<Types...@>= @!pdf_link_stack_record = record - nesting_level: small_number; + nesting_level: integer; link_node: pointer; {holds a copy of the corresponding |pdf_start_link_node|} ref_link_node: pointer; {points to original |pdf_start_link_node|, or a copy of |link_node| created by |append_link| in @@ -32711,6 +28589,8 @@ begin if not is_shipping_page then pdf_error("ext4", "link annotations cannot be inside an XForm"); pdfassert(type(parent_box) = hlist_node); + if is_obj_scheduled(pdf_link_objnum(p)) then + pdf_link_objnum(p) := pdf_new_objnum; push_link_level(p); set_rect_dimens(p, parent_box, x, y, pdf_width(p), pdf_height(p), pdf_depth(p), @@ -32718,10 +28598,12 @@ begin obj_annot_ptr(pdf_link_objnum(p)) := p; {the reference for the pdf annot object must be set here} pdf_append_list(pdf_link_objnum(p))(pdf_link_list); + set_obj_scheduled(pdf_link_objnum(p)); end; procedure end_link; var p: pointer; +tmp1, tmp2: scaledpos; begin if pdf_link_stack_ptr < 1 then pdf_error("ext4", "pdf_link_stack empty, \pdfendlink used without \pdfstartlink?"); @@ -32734,14 +28616,22 @@ begin if is_running(pdf_width(pdf_link_stack_top.link_node)) then begin p := pdf_link_stack_top.ref_link_node; if is_shipping_page and matrixused then begin - matrixrecalculate(cur_h + pdf_link_margin); - pdf_left(p) := getllx - pdf_link_margin; - pdf_top(p) := cur_page_height - getury - pdf_link_margin; - pdf_right(p) := geturx + pdf_link_margin; - pdf_bottom(p) := cur_page_height - getlly + pdf_link_margin; - end - else - pdf_right(p) := cur_h + pdf_link_margin; + matrixrecalculate(cur.h + pdf_link_margin); + pdf_ann_left(p) := getllx - pdf_link_margin; + pdf_ann_top(p) := cur_page_size.v - getury - pdf_link_margin; + pdf_ann_right(p) := geturx + pdf_link_margin; + pdf_ann_bottom(p) := cur_page_size.v - getlly + pdf_link_margin; + end + else begin + tmp1.h := cur.h; tmp1.v := cur.v; + tmp2 := synch_p_with_c(tmp1); + case box_direction(dvi_direction) of + dir_TL_, dir_BL_: pdf_ann_right(p) := tmp2.h + pdf_link_margin; + dir_TR_, dir_BR_: pdf_ann_left(p) := tmp2.h - pdf_link_margin; + dir_LT_, dir_RT_: pdf_ann_bottom(p) := tmp2.v - pdf_link_margin; + dir_LB_, dir_RB_: pdf_ann_top(p) := tmp2.v + pdf_link_margin; + endcases; + end; end; pop_link_level; end; @@ -32846,11 +28736,20 @@ begin end; procedure end_thread; +var tmp1, tmp2: scaledpos; begin if pdf_thread_level <> cur_s then pdf_error("ext4", "\pdfendthread ended up in different nesting level than \pdfstartthread"); - if is_running(pdf_thread_dp) and (last_thread <> null) then - pdf_bottom(last_thread) := cur_v + pdf_thread_margin; + if is_running(pdf_thread_dp) and (last_thread <> null) then begin + tmp1.h := cur.h; tmp1.v := cur.v; + tmp2 := synch_p_with_c(tmp1); + case box_direction(dvi_direction) of + dir_TL_, dir_TR_: pdf_ann_bottom(last_thread) := tmp2.v - pdf_thread_margin; + dir_BL_, dir_BR_: pdf_ann_top(last_thread) := tmp2.v + pdf_thread_margin; + dir_LT_, dir_LB_: pdf_ann_right(last_thread) := tmp2.h + pdf_thread_margin; + dir_RT_, dir_RB_: pdf_ann_left(last_thread) := tmp2.h - pdf_thread_margin; + endcases; + end; if pdf_last_thread_named_id then delete_token_ref(pdf_last_thread_id); last_thread := null; @@ -32884,6 +28783,7 @@ end; procedure do_dest(p, parent_box: pointer; x, y: scaled); var k: integer; +tmp1, tmp2: scaledpos; begin if not is_shipping_page then pdf_error("ext4", "destinations cannot be inside an XForm"); @@ -32904,8 +28804,10 @@ begin pdf_width(p), pdf_height(p), pdf_depth(p), pdf_dest_margin) else begin - pdf_left(p) := cur_h; - pdf_top(p) := cur_v; + tmp1.h := cur.h; tmp1.v := cur.v; + tmp2 := synch_p_with_c(tmp1); + pdf_ann_left(p) := tmp2.h; + pdf_ann_top(p) := tmp2.v; end; pdf_dest_fith, pdf_dest_fitbh: @@ -32913,16 +28815,22 @@ begin set_rect_dimens(p, parent_box, x, y, pdf_width(p), pdf_height(p), pdf_depth(p), pdf_dest_margin) - else - pdf_top(p) := cur_v; + else begin + tmp1.h := cur.h; tmp1.v := cur.v; + tmp2 := synch_p_with_c(tmp1); + pdf_ann_top(p) := tmp2.v; + end; pdf_dest_fitv, pdf_dest_fitbv: - if matrixused then + if matrixused then set_rect_dimens(p, parent_box, x, y, pdf_width(p), pdf_height(p), pdf_depth(p), pdf_dest_margin) - else - pdf_left(p) := cur_h; + else begin + tmp1.h := cur.h; tmp1.v := cur.v; + tmp2 := synch_p_with_c(tmp1); + pdf_ann_left(p) := tmp2.h; + end; pdf_dest_fit, pdf_dest_fitb: do_nothing; @@ -32933,20 +28841,20 @@ begin endcases; end; -procedure out_form(p: pointer); -var v: scaled; +procedure output_form(p: pointer); begin - pdf_end_text; - pdf_print_ln("q"); + pdf_goto_pagemode; + pdf_place_form(pos.h, pos.v, obj_info(pdf_xform_objnum(p))); if pdf_lookup_list(pdf_xform_list, pdf_xform_objnum(p)) = null then pdf_append_list(pdf_xform_objnum(p))(pdf_xform_list); - v := cur_v + obj_xform_depth(pdf_xform_objnum(p)); - pdf_set_origin_temp(cur_h, v); - pdf_print("/Fm"); - pdf_print_int(obj_info(pdf_xform_objnum(p))); - pdf_print_resname_prefix; - pdf_print_ln(" Do"); - pdf_print_ln("Q"); +end; + +procedure output_image(idx: integer); +begin + pdf_goto_pagemode; + out_image(idx, pos.h, pos.v); + if pdf_lookup_list(pdf_ximage_list, image_objnum(idx)) = null then + pdf_append_list(image_objnum(idx))(pdf_ximage_list); end; @ @<Output the whatsit node |p| in |pdf_vlist_out|@>= @@ -32963,14 +28871,15 @@ pdf_restore_node: pdf_out_restore; late_lua_node: do_late_lua(p); -close_lua_node: - closelua(late_lua_reg(p)); pdf_refobj_node: - pdf_append_list(pdf_obj_objnum(p))(pdf_obj_list); + if not is_obj_scheduled(pdf_obj_objnum(p)) then begin + pdf_append_list(pdf_obj_objnum(p))(pdf_obj_list); + set_obj_scheduled(pdf_obj_objnum(p)); + end; pdf_refxform_node: @<Output a Form node in a vlist@>; pdf_refximage_node: - @<Output a Image node in a vlist@>; + @<Output an Image node in a vlist@>; pdf_annot_node: do_annot(p, this_box, left_edge, top_edge + height(this_box)); pdf_start_link_node: @@ -32985,7 +28894,7 @@ pdf_start_thread_node: pdf_end_thread_node: end_thread; pdf_save_pos_node: - @<Save current position to |pdf_last_x_pos|, |pdf_last_y_pos|@>; + @<Save current position@>; special_node: pdf_special(p); othercases out_what(p); @@ -32994,25 +28903,56 @@ endcases @ @<Glob...@>= @!is_shipping_page: boolean; {set to |shipping_page| when |pdf_ship_out| starts} -@ @<Save current position to |pdf_last_x_pos|, |pdf_last_y_pos|@>= -begin - pdf_last_x_pos := cur_h; - pdf_last_y_pos := cur_page_height - cur_v -end - -@ @<Output a Image node in a vlist@>= -begin cur_v:=cur_v+pdf_height(p)+pdf_depth(p); - cur_h:=left_edge; - out_image(pdf_ximage_ref(p), cur_h-pdf_origin_h, pdf_origin_v-cur_v); - if pdf_lookup_list(pdf_ximage_list, image_objnum(pdf_ximage_ref(p))) = null then - pdf_append_list(image_objnum(pdf_ximage_ref(p)))(pdf_ximage_list); +@ @<Output an Image node in a vlist@>= +begin cur.h:=left_edge; + synch_pos_with_cur; + case box_direction(dvi_direction) of + dir_TL_: begin + pos_down(pdf_height(p)+pdf_depth(p)); + end; + dir_TR_: begin + pos_left(pdf_width(p)); + pos_down(pdf_height(p)+pdf_depth(p)); + end; + dir_BL_: begin + end; + dir_BR_: begin + pos_left(pdf_width(p)); + end; + dir_LT_: begin + pos_down(pdf_width(p)); + end; + dir_RT_: begin + pos_left(pdf_height(p)+pdf_depth(p)); + pos_down(pdf_width(p)); + end; + dir_LB_: begin + end; + dir_RB_: begin + pos_left(pdf_height(p)+pdf_depth(p)); + end; + othercases + endcases; + output_image(pdf_ximage_idx(p)); + cur.v:=cur.v+pdf_height(p)+pdf_depth(p); end @ @<Output a Form node in a vlist@>= -begin cur_v:=cur_v+pdf_height(p); - cur_h:=left_edge; - out_form(p); - cur_v:=cur_v+pdf_depth(p); +begin + cur.h:=left_edge; + synch_pos_with_cur; + case box_direction(dvi_direction) of + dir_TL_: begin + pos_down(pdf_height(p)+pdf_depth(p)); + end; + dir_TR_: begin + pos_left(pdf_width(p)); + pos_down(pdf_height(p)+pdf_depth(p)); + end; + othercases + endcases; + output_form(p); + cur.v:=cur.v+pdf_height(p)+pdf_depth(p); end @ @<Output the whatsit node |p| in |pdf_hlist_out|@>= @@ -33029,14 +28969,15 @@ pdf_restore_node: pdf_out_restore; late_lua_node: do_late_lua(p); -close_lua_node: - closelua(late_lua_reg(p)); pdf_refobj_node: - pdf_append_list(pdf_obj_objnum(p))(pdf_obj_list); + if not is_obj_scheduled(pdf_obj_objnum(p)) then begin + pdf_append_list(pdf_obj_objnum(p))(pdf_obj_list); + set_obj_scheduled(pdf_obj_objnum(p)); + end; pdf_refxform_node: @<Output a Form node in a hlist@>; pdf_refximage_node: - @<Output a Image node in a hlist@>; + @<Output an Image node in a hlist@>; pdf_annot_node: do_annot(p, this_box, left_edge, base_line); pdf_start_link_node: @@ -33052,27 +28993,68 @@ pdf_start_thread_node: pdf_end_thread_node: pdf_error("ext4", "\pdfendthread ended up in hlist"); pdf_save_pos_node: - @<Save current position to |pdf_last_x_pos|, |pdf_last_y_pos|@>; + @<Save current position@>; special_node: pdf_special(p); othercases if subtype(p)<>dir_node then out_what(p) -else @<(PDF) Output a reflection instruction if the direction has changed@>; +else @<Output a reflection instruction if the direction has changed@>; endcases -@ @<Output a Image node in a hlist@>= +@ @<Output an Image node in a hlist@>= begin - cur_v:=base_line+pdf_depth(p); - out_image(pdf_ximage_ref(p), cur_h-pdf_origin_h, pdf_origin_v-cur_v); - if pdf_lookup_list(pdf_ximage_list, image_objnum(pdf_ximage_ref(p))) = null then - pdf_append_list(image_objnum(pdf_ximage_ref(p)))(pdf_ximage_list); - edge:=cur_h+pdf_width(p); cur_h:=edge; cur_v:=base_line; + cur.v:=base_line; + synch_pos_with_cur; + case box_direction(dvi_direction) of + dir_TL_: begin + pos_down(pdf_depth(p)); + end; + dir_TR_: begin + pos_left(pdf_width(p)); + pos_down(pdf_depth(p)); + end; + dir_BL_: begin + pos_down(pdf_height(p)); + end; + dir_BR_: begin + pos_left(pdf_width(p)); + pos_down(pdf_height(p)); + end; + dir_LT_: begin + pos_left(pdf_height(p)); + pos_down(pdf_width(p)); + end; + dir_RT_: begin + pos_left(pdf_depth(p)); + pos_down(pdf_width(p)); + end; + dir_LB_: begin + pos_left(pdf_height(p)); + end; + dir_RB_: begin + pos_left(pdf_depth(p)); + end; + othercases + endcases; + output_image(pdf_ximage_idx(p)); + edge:=cur.h+pdf_width(p); cur.h:=edge; end @ @<Output a Form node in a hlist@>= begin - cur_v:=base_line; - out_form(p); - edge:=cur_h+pdf_width(p); cur_h:=edge; + cur.v:=base_line; + synch_pos_with_cur; + case box_direction(dvi_direction) of + dir_TL_: begin + pos_down(pdf_depth(p)); + end; + dir_TR_: begin + pos_down(pdf_depth(p)); + pos_left(pdf_width(p)); + end; + othercases + endcases; + output_form(p); + edge:=cur.h+pdf_width(p); cur.h:=edge; end @* \[53a] The extended features of \eTeX. @@ -33122,39 +29104,30 @@ that integer. @d Aleph_revision_code=job_name_code+1 {command code for \.{\\Alephrevision}} @d Omega_revision_code=job_name_code+2 {command code for \.{\\Omegarevision}} @d eTeX_revision_code=job_name_code+3 {command code for \.{\\eTeXrevision}} +@d font_identifier_code==job_name_code+4 {command code for \.{tex.fontidentifer} (lua)} @<Generate all \eTeX...@>= -primitive("lastnodetype",last_item,last_node_type_code); +primitive_etex("lastnodetype",last_item,last_node_type_code,0); @!@:last_node_type_}{\.{\\lastnodetype} primitive@> -primitive("Alephversion",last_item,Aleph_version_code); +primitive_aleph("Alephversion",last_item,Aleph_version_code,0); @!@:eTeX_version_}{\.{\\Alephversion} primitive@> -primitive("Omegaversion",last_item,Omega_version_code); +primitive_aleph("Omegaversion",last_item,Omega_version_code,0); @!@:eTeX_version_}{\.{\\Omegaversion} primitive@> -primitive("eTeXversion",last_item,eTeX_version_code); +primitive_etex("eTeXversion",last_item,eTeX_version_code,0); @!@:eTeX_version_}{\.{\\eTeXversion} primitive@> -primitive("Alephminorversion",last_item,Aleph_minor_version_code); +primitive_aleph("Alephminorversion",last_item,Aleph_minor_version_code,0); @!@:eTeX_minor_version_}{\.{\\Alephminorversion} primitive@> -primitive("Omegaminorversion",last_item,Omega_minor_version_code); +primitive_aleph("Omegaminorversion",last_item,Omega_minor_version_code,0); @!@:eTeX_minor_version_}{\.{\\Omegaminorversion} primitive@> -primitive("eTeXminorversion",last_item,eTeX_minor_version_code); +primitive_etex("eTeXminorversion",last_item,eTeX_minor_version_code,0); @!@:eTeX_minor_version_}{\.{\\eTeXminorversion} primitive@> -primitive("Alephrevision",convert,Aleph_revision_code);@/ +primitive_aleph("Alephrevision",convert,Aleph_revision_code,0);@/ @!@:eTeX_revision_}{\.{\\Alephrevision} primitive@> -primitive("Omegarevision",convert,Omega_revision_code);@/ +primitive_aleph("Omegarevision",convert,Omega_revision_code,0);@/ @!@:eTeX_revision_}{\.{\\Omegarevision} primitive@> -primitive("eTeXrevision",convert,eTeX_revision_code);@/ +primitive_etex("eTeXrevision",convert,eTeX_revision_code,0);@/ @!@:eTeX_revision_}{\.{\\eTeXrevision} primitive@> -@ @<Cases of |last_item| for |print_cmd_chr|@>= -last_node_type_code: print_esc("lastnodetype"); -Aleph_version_code: print_esc("Alephversion"); -Omega_version_code: print_esc("Omegaversion"); -eTeX_version_code: print_esc("eTeXversion"); -Aleph_minor_version_code: print_esc("Alephminorversion"); -Omega_minor_version_code: print_esc("Omegaminorversion"); -eTeX_minor_version_code: print_esc("eTeXminorversion"); - - @ @<Cases for fetching an integer value@>= Aleph_version_code: cur_val:=Aleph_version; Omega_version_code: cur_val:=Omega_version; @@ -33163,11 +29136,6 @@ Aleph_minor_version_code: cur_val:=Aleph_minor_version; Omega_minor_version_code: cur_val:=Omega_minor_version; eTeX_minor_version_code: cur_val:=eTeX_minor_version; -@ @<Cases of |convert| for |print_cmd_chr|@>= -Aleph_revision_code: print_esc("Alephrevision"); -Omega_revision_code: print_esc("Omegarevision"); -eTeX_revision_code: print_esc("eTeXrevision"); - @ @<Cases of `Scan the argument for command |c|'@>= Aleph_revision_code: do_nothing; Omega_revision_code: do_nothing; @@ -33182,35 +29150,39 @@ eTeX_revision_code: print(eTeX_revision); equivalents. @<Generate all \eTeX...@>= -primitive("everyeof",assign_toks,every_eof_loc); +primitive_etex("everyeof",assign_toks,every_eof_loc,local_base); @!@:every_eof_}{\.{\\everyeof} primitive@> -primitive("tracingassigns",assign_int,int_base+tracing_assigns_code);@/ +primitive_etex("tracingassigns",assign_int,int_base+tracing_assigns_code,int_base);@/ @!@:tracing_assigns_}{\.{\\tracingassigns} primitive@> -primitive("tracinggroups",assign_int,int_base+tracing_groups_code);@/ +primitive_etex("tracinggroups",assign_int,int_base+tracing_groups_code,int_base);@/ @!@:tracing_groups_}{\.{\\tracinggroups} primitive@> -primitive("tracingifs",assign_int,int_base+tracing_ifs_code);@/ +primitive_etex("tracingifs",assign_int,int_base+tracing_ifs_code,int_base);@/ @!@:tracing_ifs_}{\.{\\tracingifs} primitive@> -primitive("tracingscantokens",assign_int,int_base+tracing_scan_tokens_code);@/ +primitive_etex("tracingscantokens",assign_int,int_base+tracing_scan_tokens_code,int_base);@/ @!@:tracing_scan_tokens_}{\.{\\tracingscantokens} primitive@> -primitive("tracingnesting",assign_int,int_base+tracing_nesting_code);@/ +primitive_etex("tracingnesting",assign_int,int_base+tracing_nesting_code,int_base);@/ @!@:tracing_nesting_}{\.{\\tracingnesting} primitive@> -primitive("predisplaydirection", - assign_int,int_base+pre_display_direction_code);@/ +primitive_etex("predisplaydirection", assign_int,int_base+pre_display_direction_code,int_base);@/ @!@:pre_display_direction_}{\.{\\predisplaydirection} primitive@> -primitive("lastlinefit",assign_int,int_base+last_line_fit_code);@/ +primitive_etex("lastlinefit",assign_int,int_base+last_line_fit_code,int_base);@/ @!@:last_line_fit_}{\.{\\lastlinefit} primitive@> -primitive("savingvdiscards",assign_int,int_base+saving_vdiscards_code);@/ +primitive_etex("savingvdiscards",assign_int,int_base+saving_vdiscards_code,int_base);@/ @!@:saving_vdiscards_}{\.{\\savingvdiscards} primitive@> -primitive("savinghyphcodes",assign_int,int_base+saving_hyph_codes_code);@/ +primitive_etex("savinghyphcodes",assign_int,int_base+saving_hyph_codes_code,int_base);@/ @!@:saving_hyph_codes_}{\.{\\savinghyphcodes} primitive@> -primitive("suppressfontnotfounderror",assign_int,int_base+suppress_fontnotfound_error_code);@/ -@!@:suppress_fontnotfound_error_codes_}{\.{\\suppressfontnotfounderror} primitive@> +primitive_luatex("suppressfontnotfounderror",assign_int,int_base+suppress_fontnotfound_error_code,int_base);@/ +@!@:suppress_fontnotfound_error_code_}{\.{\\suppressfontnotfounderror} primitive@> +primitive_luatex("suppresslongerror",assign_int,int_base+suppress_long_error_code,int_base);@/ +@!@:suppress_long_error_code_}{\.{\\suppresslongerror} primitive@> +primitive_luatex("suppressifcsnameerror",assign_int,int_base+suppress_ifcsname_error_code,int_base);@/ +@!@:suppress_ifcsname_error_code_}{\.{\\suppressifcsnameerror} primitive@> +primitive_luatex("suppressoutererror",assign_int,int_base+suppress_outer_error_code,int_base);@/ +@!@:suppress_outer_error_code_}{\.{\\suppressoutererror} primitive@> +primitive_luatex("synctex",assign_int,int_base+synctex_code,int_base);@/ +@!@:synctex_}{\.{\\synctex} primitive@> @ @d every_eof==equiv(every_eof_loc) -@<Cases of |assign_toks| for |print_cmd_chr|@>= -every_eof_loc: print_esc("everyeof"); - @ @<Cases for |print_param|@>= tracing_assigns_code:print_esc("tracingassigns"); tracing_groups_code:print_esc("tracinggroups"); @@ -33222,6 +29194,9 @@ last_line_fit_code:print_esc("lastlinefit"); saving_vdiscards_code:print_esc("savingvdiscards"); saving_hyph_codes_code:print_esc("savinghyphcodes"); suppress_fontnotfound_error_code:print_esc("suppressfontnotfounderror"); +suppress_long_error_code:print_esc("suppresslongerror"); +suppress_outer_error_code:print_esc("suppressoutererror"); +synctex_code:print_esc("synctex"); @ In order to handle \.{\\everyeof} we need an array |eof_seen| of boolean variables. @@ -33290,15 +29265,11 @@ respectively. @d current_group_type_code=eTeX_int+2 {code for \.{\\currentgrouptype}} @<Generate all \eTeX...@>= -primitive("currentgrouplevel",last_item,current_group_level_code); +primitive_etex("currentgrouplevel",last_item,current_group_level_code,0); @!@:current_group_level_}{\.{\\currentgrouplevel} primitive@> -primitive("currentgrouptype",last_item,current_group_type_code); +primitive_etex("currentgrouptype",last_item,current_group_type_code,0); @!@:current_group_type_}{\.{\\currentgrouptype} primitive@> -@ @<Cases of |last_item| for |print_cmd_chr|@>= -current_group_level_code: print_esc("currentgrouplevel"); -current_group_type_code: print_esc("currentgrouptype"); - @ @<Cases for fetching an integer value@>= current_group_level_code: cur_val:=cur_level-level_one; current_group_type_code: cur_val:=cur_group; @@ -33312,18 +29283,13 @@ and the type and branch of the current conditional. @d current_if_branch_code=eTeX_int+5 {code for \.{\\currentifbranch}} @<Generate all \eTeX...@>= -primitive("currentiflevel",last_item,current_if_level_code); +primitive_etex("currentiflevel",last_item,current_if_level_code,0); @!@:current_if_level_}{\.{\\currentiflevel} primitive@> -primitive("currentiftype",last_item,current_if_type_code); +primitive_etex("currentiftype",last_item,current_if_type_code,0); @!@:current_if_type_}{\.{\\currentiftype} primitive@> -primitive("currentifbranch",last_item,current_if_branch_code); +primitive_etex("currentifbranch",last_item,current_if_branch_code,0); @!@:current_if_branch_}{\.{\\currentifbranch} primitive@> -@ @<Cases of |last_item| for |print_cmd_chr|@>= -current_if_level_code: print_esc("currentiflevel"); -current_if_type_code: print_esc("currentiftype"); -current_if_branch_code: print_esc("currentifbranch"); - @ @<Cases for fetching an integer value@>= current_if_level_code: begin q:=cond_ptr; cur_val:=0; while q<>null do @@ -33348,25 +29314,19 @@ font. @d font_char_ic_code=eTeX_dim+3 {code for \.{\\fontcharic}} @<Generate all \eTeX...@>= -primitive("charwd",last_item,font_char_wd_code); -primitive("fontcharwd",last_item,font_char_wd_code); +primitive_omega("charwd",last_item,font_char_wd_code,0); +primitive_etex("fontcharwd",last_item,font_char_wd_code,0); @!@:font_char_wd_}{\.{\\fontcharwd} primitive@> -primitive("charht",last_item,font_char_ht_code); -primitive("fontcharht",last_item,font_char_ht_code); +primitive_omega("charht",last_item,font_char_ht_code,0); +primitive_etex("fontcharht",last_item,font_char_ht_code,0); @!@:font_char_ht_}{\.{\\fontcharht} primitive@> -primitive("chardp",last_item,font_char_dp_code); -primitive("fontchardp",last_item,font_char_dp_code); +primitive_omega("chardp",last_item,font_char_dp_code,0); +primitive_etex("fontchardp",last_item,font_char_dp_code,0); @!@:font_char_dp_}{\.{\\fontchardp} primitive@> -primitive("charic",last_item,font_char_ic_code); -primitive("fontcharic",last_item,font_char_ic_code); +primitive_omega("charit",last_item,font_char_ic_code,0); +primitive_etex("fontcharic",last_item,font_char_ic_code,0); @!@:font_char_ic_}{\.{\\fontcharic} primitive@> -@ @<Cases of |last_item| for |print_cmd_chr|@>= -font_char_wd_code: print_esc("fontcharwd"); -font_char_ht_code: print_esc("fontcharht"); -font_char_dp_code: print_esc("fontchardp"); -font_char_ic_code: print_esc("fontcharic"); - @ @<Cases for fetching a dimension value@>= font_char_wd_code, font_char_ht_code, @@ -33393,18 +29353,13 @@ commands return the indent and length parameters of the current @d par_shape_dimen_code=eTeX_dim+6 {code for \.{\\parshapedimen}} @<Generate all \eTeX...@>= -primitive("parshapelength",last_item,par_shape_length_code); +primitive_etex("parshapelength",last_item,par_shape_length_code,0); @!@:par_shape_length_}{\.{\\parshapelength} primitive@> -primitive("parshapeindent",last_item,par_shape_indent_code); +primitive_etex("parshapeindent",last_item,par_shape_indent_code,0); @!@:par_shape_indent_}{\.{\\parshapeindent} primitive@> -primitive("parshapedimen",last_item,par_shape_dimen_code); +primitive_etex("parshapedimen",last_item,par_shape_dimen_code,0); @!@:par_shape_dimen_}{\.{\\parshapedimen} primitive@> -@ @<Cases of |last_item| for |print_cmd_chr|@>= -par_shape_length_code: print_esc("parshapelength"); -par_shape_indent_code: print_esc("parshapeindent"); -par_shape_dimen_code: print_esc("parshapedimen"); - @ @<Cases for fetching a dimension value@>= par_shape_length_code, par_shape_indent_code, @@ -33413,8 +29368,8 @@ par_shape_dimen_code: begin q:=cur_chr-par_shape_length_code; scan_int; else begin if q=2 then begin q:=cur_val mod 2; cur_val:=(cur_val+q)div 2; end; - if cur_val>vinfo(par_shape_ptr) then cur_val:=vinfo(par_shape_ptr); - cur_val:=vmem(par_shape_ptr+2*cur_val-q).sc; + if cur_val>vinfo(par_shape_ptr+1) then cur_val:=vinfo(par_shape_ptr+1); + cur_val:=vmem(par_shape_ptr+2*cur_val-q+1).sc; end; cur_val_level:=dimen_val; end; @@ -33425,12 +29380,9 @@ levels. @d show_groups=4 { \.{\\showgroups} } @<Generate all \eTeX...@>= -primitive("showgroups",xray,show_groups); +primitive_etex("showgroups",xray,show_groups,0); @!@:show_groups_}{\.{\\showgroups} primitive@> -@ @<Cases of |xray| for |print_cmd_chr|@>= -show_groups:print_esc("showgroups"); - @ @<Cases for |show_whatever|@>= show_groups: begin begin_diagnostic; show_save_groups; end; @@ -33498,7 +29450,7 @@ loop@+begin print_nl("### "); print_group(true); goto found2; end; insert_group: - begin if saved(-2)=255 then print_esc("vadjust") + begin if saved(-2)=output_box then print_esc("vadjust") else begin print_esc("insert"); print_int(saved(-2)); end; goto found2; @@ -33515,7 +29467,7 @@ loop@+begin print_nl("### "); print_group(true); print_char("$"); goto found; end; math_left_group: - begin if type(nest[p+1].eTeX_aux_field)=left_noad then print_esc("left") + begin if subtype(nest[p+1].eTeX_aux_field)=left_noad_side then print_esc("left") else print_esc("middle"); goto found; end; @@ -33596,12 +29548,9 @@ end; @d show_tokens=5 { \.{\\showtokens} , must be odd! } @<Generate all \eTeX...@>= -primitive("showtokens",xray,show_tokens); +primitive_etex("showtokens",xray,show_tokens,0); @!@:show_tokens_}{\.{\\showtokens} primitive@> -@ @<Cases of |xray| for |print_cmd_chr|@>= -show_tokens:print_esc("showtokens"); - @ The \.{\\unexpanded} primitive prevents expansion of tokens much as the result from \.{\\the} applied to a token variable. The \.{\\detokenize} primitive converts a token list into a list of @@ -33611,15 +29560,11 @@ use the fact that the command modifiers for \.{\\unexpanded} and are even. @<Generate all \eTeX...@>= -primitive("unexpanded",the,1);@/ +primitive_etex("unexpanded",the,1,0);@/ @!@:unexpanded_}{\.{\\unexpanded} primitive@> -primitive("detokenize",the,show_tokens);@/ +primitive_etex("detokenize",the,show_tokens,0);@/ @!@:detokenize_}{\.{\\detokenize} primitive@> -@ @<Cases of |the| for |print_cmd_chr|@>= -else if chr_code=1 then print_esc("unexpanded") -else print_esc("detokenize") - @ @<Handle \.{\\unexpanded} or \.{\\detokenize} and |return|@>= if odd(cur_chr) then begin c:=cur_chr; scan_general_text; @@ -33637,12 +29582,9 @@ if odd(cur_chr) then @d show_ifs=6 { \.{\\showifs} } @<Generate all \eTeX...@>= -primitive("showifs",xray,show_ifs); +primitive_etex("showifs",xray,show_ifs,0); @!@:show_ifs_}{\.{\\showifs} primitive@> -@ @<Cases of |xray| for |print_cmd_chr|@>= -show_ifs:print_esc("showifs"); - @ @d print_if_line(#)==if #<>0 then begin print(" entered on line "); print_int(#); @@ -33669,12 +29611,9 @@ show_ifs: begin begin_diagnostic; print_nl(""); print_ln; interaction mode. @<Generate all \eTeX...@>= -primitive("interactionmode",set_page_int,2); +primitive_etex("interactionmode",set_page_int,2,0); @!@:interaction_mode_}{\.{\\interactionmode} primitive@> -@ @<Cases of |set_page_int| for |print_cmd_chr|@>= -else if chr_code=2 then print_esc("interactionmode") - @ @<Cases for `Fetch the |dead_cycles| or the |insert_penalties|'@>= else if m=2 then cur_val:=interaction @@ -33694,29 +29633,15 @@ else if c=2 then end; end -@ The |middle| feature of \eTeX\ allows one ore several \.{\\middle} -delimiters to appear between \.{\\left} and \.{\\right}. - -@<Generate all \eTeX...@>= -primitive("middle",left_right,middle_noad); -@!@:middle_}{\.{\\middle} primitive@> - -@ @<Cases of |left_right| for |print_cmd_chr|@>= -else if chr_code=middle_noad then print_esc("middle") - @ The |scan_tokens| feature of \eTeX\ defines the \.{\\scantokens} primitive. @<Generate all \eTeX...@>= -primitive("scantokens",input,2); +primitive_etex("scantokens",input,2,0); @!@:scan_tokens_}{\.{\\scantokens} primitive@> -primitive("scantextokens",input,3); +primitive_luatex("scantextokens",input,3,0); @!@:scan_tex_tokens_}{\.{\\scantextokens} primitive@> -@ @<Cases of |input| for |print_cmd_chr|@>= -else if chr_code=2 then print_esc("scantokens") -else if chr_code=3 then print_esc("scantextokens") - @ @<Cases for |input|@>= else if cur_chr=2 then pseudo_start else if cur_chr=3 then begin pseudo_start; name := 19; end @@ -33783,7 +29708,10 @@ if tracing_scan_tokens>0 then else if (term_offset>0)or(file_offset>0) then print_char(" "); name:=20; print("( "); incr(open_parens); update_terminal; end -else name:=18 +else begin + name:=18; + @<Prepare pseudo file {\sl Sync\TeX} information@>; +end @ Here we read a line from the current pseudo file into |buffer|. @@ -33819,7 +29747,7 @@ end; @<Declare \eTeX\ procedures for tr...@>= procedure pseudo_close; {close the top level pseudo file} -var p,@!q: pointer; +var p: pointer; begin p:=vlink(pseudo_files); flush_node(pseudo_files); pseudo_files:=p; @@ -33829,12 +29757,9 @@ end; while pseudo_files<>null do pseudo_close; {flush pseudo files} @ @<Generate all \eTeX...@>= -primitive("readline",read_to_cs,1);@/ +primitive_etex("readline",read_to_cs,1,0);@/ @!@:read_line_}{\.{\\readline} primitive@> -@ @<Cases of |read| for |print_cmd_chr|@>= -else print_esc("readline") - @ @<Handle \.{\\readline} and |goto done|@>= if j=1 then begin while loc<=limit do {current line not yet finished} @@ -33857,36 +29782,25 @@ if j=1 then @d if_abs_dim_code=23 { `\.{\\ifabsdim}' } @<Generate all \eTeX...@>= -primitive("unless",expand_after,1);@/ +primitive_etex("unless",expand_after,1,0);@/ @!@:unless_}{\.{\\unless} primitive@> -primitive("ifdefined",if_test,if_def_code); +primitive_etex("ifdefined",if_test,if_def_code,0); @!@:if_defined_}{\.{\\ifdefined} primitive@> -primitive("ifcsname",if_test,if_cs_code); +primitive_etex("ifcsname",if_test,if_cs_code,0); @!@:if_cs_name_}{\.{\\ifcsname} primitive@> -primitive("iffontchar",if_test,if_font_char_code); +primitive_etex("iffontchar",if_test,if_font_char_code,0); @!@:if_font_char_}{\.{\\iffontchar} primitive@> -primitive("ifincsname",if_test,if_in_csname_code); +primitive_pdftex("ifincsname",if_test,if_in_csname_code,0); @!@:if_in_csname_}{\.{\\ifincsname} primitive@> -primitive("ifabsnum",if_test,if_abs_num_code); +primitive_luatex("ifabsnum",if_test,if_abs_num_code,0); @!@:if_abs_num_}{\.{\\ifabsnum} primitive@> -primitive("ifabsdim",if_test,if_abs_dim_code); +primitive_luatex("ifabsdim",if_test,if_abs_dim_code,0); @!@:if_abs_dim_}{\.{\\ifabsdim} primitive@> -primitive("ifpdfabsnum",if_test,if_abs_num_code); +primitive_pdftex("ifpdfabsnum",if_test,if_abs_num_code,0); @!@:if_abs_num_}{\.{\\ifpdfabsnum} primitive@> -primitive("ifpdfabsdim",if_test,if_abs_dim_code); +primitive_pdftex("ifpdfabsdim",if_test,if_abs_dim_code,0); @!@:if_abs_dim_}{\.{\\ifpdfabsdim} primitive@> -@ @<Cases of |expandafter| for |print_cmd_chr|@>= -else print_esc("unless") - -@ @<Cases of |if_test| for |print_cmd_chr|@>= -if_def_code:print_esc("ifdefined"); -if_cs_code:print_esc("ifcsname"); -if_font_char_code:print_esc("iffontchar"); -if_in_csname_code:print_esc("ifincsname"); -if_abs_num_code:print_esc("ifabsnum"); -if_abs_dim_code:print_esc("ifabsdim"); - @ The result of a boolean condition is reversed when the conditional is preceded by \.{\\unless}. @@ -33926,10 +29840,22 @@ if_cs_code:begin n:=get_avail; p:=n; {head of the list of characters} repeat get_x_token; if cur_cs=0 then store_new_token(cur_tok); until cur_cs<>0; - if cur_cmd<>end_cs_name then @<Complain about missing \.{\\endcsname}@>; - @<Look up the characters of list |n| in the hash table, and set |cur_cs|@>; + if cur_cmd<>end_cs_name then begin + if suppress_ifcsname_error then begin + repeat get_x_token; + until cur_cmd=end_cs_name; + end + else begin + @<Complain about missing \.{\\endcsname}@>; + @<Look up the characters of list |n| in the hash table, and set |cur_cs|@>; + b:=(eq_type(cur_cs)<>undefined_cs); + end; + end + else begin + @<Look up the characters of list |n| in the hash table, and set |cur_cs|@>; + b:=(eq_type(cur_cs)<>undefined_cs); + end; flush_list(n); - b:=(eq_type(cur_cs)<>undefined_cs); end; @ @<Look up the characters of list |n| in the hash table...@>= @@ -34002,12 +29928,9 @@ expansions when lists of expanded tokens are built, e.g., for \.{\\edef} or during \.{\\write}. @<Generate all \eTeX...@>= -primitive("protected",prefix,8); +primitive_etex("protected",prefix,8,0); @!@:protected_}{\.{\\protected} primitive@> -@ @<Cases of |prefix| for |print_cmd_chr|@>= -else if chr_code=8 then print_esc("protected") - @ The |get_x_or_protected| procedure is like |get_x_token| except that protected macros are not expanded. @@ -34138,21 +30061,15 @@ end; @ Here are the additional \eTeX\ primitives for expressions. @<Generate all \eTeX...@>= -primitive("numexpr",last_item,eTeX_expr-int_val+int_val); +primitive_etex("numexpr",last_item,eTeX_expr-int_val+int_val,0); @!@:num_expr_}{\.{\\numexpr} primitive@> -primitive("dimexpr",last_item,eTeX_expr-int_val+dimen_val); +primitive_etex("dimexpr",last_item,eTeX_expr-int_val+dimen_val,0); @!@:dim_expr_}{\.{\\dimexpr} primitive@> -primitive("glueexpr",last_item,eTeX_expr-int_val+glue_val); +primitive_etex("glueexpr",last_item,eTeX_expr-int_val+glue_val,0); @!@:glue_expr_}{\.{\\glueexpr} primitive@> -primitive("muexpr",last_item,eTeX_expr-int_val+mu_val); +primitive_etex("muexpr",last_item,eTeX_expr-int_val+mu_val,0); @!@:mu_expr_}{\.{\\muexpr} primitive@> -@ @<Cases of |last_item| for |print_cmd_chr|@>= -eTeX_expr-int_val+int_val: print_esc("numexpr"); -eTeX_expr-int_val+dimen_val: print_esc("dimexpr"); -eTeX_expr-int_val+glue_val: print_esc("glueexpr"); -eTeX_expr-int_val+mu_val: print_esc("muexpr"); - @ This code for reducing |cur_val_level| and\slash or negating the result is similar to the one for all the other cases of |scan_something_internal|, with the difference that |scan_expr| has @@ -34305,7 +30222,6 @@ expression so far and |r| is the state of its evaluation; |t| is the term so far and |s| is the state of its evaluation; finally |n| is the numerator for a combined multiplication and division, if any. -@d expr_node=39 { stack entry for subexpressions} @d expr_type(#)==type(#+1) @d expr_state(#)==subtype(#+1) @d expr_e_field(#)==vlink(#+1) {saved expression so far} @@ -34562,21 +30478,15 @@ and their orders of ``infinity'' of a glue specification. @d glue_shrink_code=eTeX_dim+8 {code for \.{\\glueshrink}} @<Generate all \eTeX...@>= -primitive("gluestretchorder",last_item,glue_stretch_order_code); +primitive_etex("gluestretchorder",last_item,glue_stretch_order_code,0); @!@:glue_stretch_order_}{\.{\\gluestretchorder} primitive@> -primitive("glueshrinkorder",last_item,glue_shrink_order_code); +primitive_etex("glueshrinkorder",last_item,glue_shrink_order_code,0); @!@:glue_shrink_order_}{\.{\\glueshrinkorder} primitive@> -primitive("gluestretch",last_item,glue_stretch_code); +primitive_etex("gluestretch",last_item,glue_stretch_code,0); @!@:glue_stretch_}{\.{\\gluestretch} primitive@> -primitive("glueshrink",last_item,glue_shrink_code); +primitive_etex("glueshrink",last_item,glue_shrink_code,0); @!@:glue_shrink_}{\.{\\glueshrink} primitive@> -@ @<Cases of |last_item| for |print_cmd_chr|@>= -glue_stretch_order_code: print_esc("gluestretchorder"); -glue_shrink_order_code: print_esc("glueshrinkorder"); -glue_stretch_code: print_esc("gluestretch"); -glue_shrink_code: print_esc("glueshrink"); - @ @<Cases for fetching an integer value@>= glue_stretch_order_code, glue_shrink_order_code: begin scan_normal_glue; q:=cur_val; @@ -34601,15 +30511,11 @@ into normal glue and vice versa; they allow to manipulate math glue with @d glue_to_mu_code=eTeX_mu {code for \.{\\gluetomu}} @<Generate all \eTeX...@>= -primitive("mutoglue",last_item,mu_to_glue_code); +primitive_etex("mutoglue",last_item,mu_to_glue_code,0); @!@:mu_to_glue_}{\.{\\mutoglue} primitive@> -primitive("gluetomu",last_item,glue_to_mu_code); +primitive_etex("gluetomu",last_item,glue_to_mu_code,0); @!@:glue_to_mu_}{\.{\\gluetomu} primitive@> -@ @<Cases of |last_item| for |print_cmd_chr|@>= -mu_to_glue_code: print_esc("mutoglue"); -glue_to_mu_code: print_esc("gluetomu"); - @ @<Cases for fetching a glue value@>= mu_to_glue_code: scan_mu_glue; @@ -34640,15 +30546,11 @@ distinguished by their |chr_code| values |last_box_code| and |copy_code|. @<Generate all \eTeX...@>= -primitive("pagediscards",un_vbox,last_box_code);@/ +primitive_etex("pagediscards",un_vbox,last_box_code,0);@/ @!@:page_discards_}{\.{\\pagediscards} primitive@> -primitive("splitdiscards",un_vbox,vsplit_code);@/ +primitive_etex("splitdiscards",un_vbox,vsplit_code,0);@/ @!@:split_discards_}{\.{\\splitdiscards} primitive@> -@ @<Cases of |un_vbox| for |print_cmd_chr|@>= -else if chr_code=last_box_code then print_esc("pagediscards") -else if chr_code=vsplit_code then print_esc("splitdiscards") - @ @<Handle saved items and |goto done|@>= begin vlink(tail):=disc_ptr[cur_chr]; disc_ptr[cur_chr]:=null; goto done; @@ -34664,27 +30566,22 @@ penalty values to be used instead of the corresponding single values. @d display_widow_penalties_ptr==equiv(display_widow_penalties_loc) @<Generate all \eTeX...@>= -primitive("interlinepenalties",set_shape,inter_line_penalties_loc);@/ +primitive_etex("interlinepenalties",set_etex_shape,inter_line_penalties_loc,etex_pen_base);@/ @!@:inter_line_penalties_}{\.{\\interlinepenalties} primitive@> -primitive("clubpenalties",set_shape,club_penalties_loc);@/ +primitive_etex("clubpenalties",set_etex_shape,club_penalties_loc,etex_pen_base);@/ @!@:club_penalties_}{\.{\\clubpenalties} primitive@> -primitive("widowpenalties",set_shape,widow_penalties_loc);@/ +primitive_etex("widowpenalties",set_etex_shape,widow_penalties_loc,etex_pen_base);@/ @!@:widow_penalties_}{\.{\\widowpenalties} primitive@> -primitive("displaywidowpenalties",set_shape,display_widow_penalties_loc);@/ +primitive_etex("displaywidowpenalties",set_etex_shape,display_widow_penalties_loc,etex_pen_base);@/ @!@:display_widow_penalties_}{\.{\\displaywidowpenalties} primitive@> -@ @<Cases of |set_shape| for |print_cmd_chr|@>= -inter_line_penalties_loc: print_esc("interlinepenalties"); -club_penalties_loc: print_esc("clubpenalties"); -widow_penalties_loc: print_esc("widowpenalties"); -display_widow_penalties_loc: print_esc("displaywidowpenalties"); - @ @<Fetch a penalties array element@>= begin scan_int; if (equiv(m)=null)or(cur_val<0) then cur_val:=0 else begin if cur_val>penalty(equiv(m)) then cur_val:=penalty(equiv(m)); cur_val:=penalty(equiv(m)+cur_val); end; +cur_val_level:=int_val; end @ This is needed to get the relative order of the marks code correct @@ -34715,11 +30612,28 @@ end; function set_tex_dimen_register (j:integer;v:scaled):integer; var a:small_number; begin {return non-nil for error} -a:=0; +if global_defs>0 then a:=4 else a:=0; word_define(j+scaled_base,v); set_tex_dimen_register := 0; end; +function get_tex_skip_register (j:integer):halfword; +begin + get_tex_skip_register := skip(j); +end; + +function set_tex_skip_register (j:integer;v:halfword):integer; +var a:small_number; +begin {return non-nil for error} + if global_defs>0 then a:=4 else a:=0; + if type(v) <> glue_spec_node then + set_tex_skip_register := 1 + else begin + word_define(j+skip_base,v); + set_tex_skip_register := 0; + end; +end; + function get_tex_count_register (j:integer):scaled; begin get_tex_count_register := count(j); @@ -34728,9 +30642,9 @@ end; function set_tex_count_register (j:integer;v:scaled):integer; var a:small_number; begin {return non-nil for error} -a:=0; -word_define(j+count_base,v); -set_tex_count_register := 0; + if global_defs>0 then a:=4 else a:=0; + word_define(j+count_base,v); + set_tex_count_register := 0; end; function get_tex_attribute_register (j:integer):scaled; @@ -34741,7 +30655,9 @@ end; function set_tex_attribute_register (j:integer;v:scaled):integer; var a:small_number; begin {return non-nil for error} -a:=0; +if global_defs>0 then a:=4 else a:=0; +if (j)>max_used_attr then max_used_attr:=(j); +attr_list_cache:=cache_disabled; word_define(j+attribute_base,v); set_tex_attribute_register := 0; end; @@ -34751,7 +30667,7 @@ var s:str_number; begin s:=""; if toks(j) <> min_halfword then begin - s := tokens_to_string(toks(j)); + s := tokens_to_string(toks(j)); end; get_tex_toks_register := s; end; @@ -34770,7 +30686,7 @@ begin pool_ptr := s_pool_ptr; token_ref_count(ref) := 0; link(ref) := link(temp_token_head); - a:=0; + if global_defs>0 then a:=4 else a:=0; define(j+toks_base,call,ref); flush_str(s); end; @@ -34783,8 +30699,8 @@ end; function set_tex_box_register (j:integer;v:scaled):integer; var a:small_number; begin {return non-nil for error} -a:=0; -eq_define(j+box_base,box_ref,v); +if global_defs>0 then a:=4 else a:=0; +define(j+box_base,box_ref,v); set_tex_box_register := 0; end; @@ -34851,12 +30767,12 @@ end; function get_cur_v: integer; begin - get_cur_v := cur_page_height - cur_v; + get_cur_v := cur_page_size.v - cur.v; end; function get_cur_h: integer; begin - get_cur_h := cur_h; + get_cur_h := cur.h; end; @* \[54] $\Omega$ changes. @@ -35067,22 +30983,25 @@ state:=mid_line; start:=first; last:=start; loc:=start; +line_catcode_table:=DEFAULT_CAT_TABLE; line_partial:=false; for otp_counter:=1 to otp_output_end do begin { convert back to utf-8 } - t := otp_output_buf[otp_counter]; - if otp_counter < otp_output_end then - if ((t>=@"D800) and (t<@"DC00)) then - if (otp_output_buf[otp_counter+1]>=@"DC00) - and (otp_output_buf[otp_counter+1]<@"E000) then begin - incr(otp_counter); - t := (t-@"D800) * @"400 + (otp_output_buf[otp_counter]-@"DC00) + @"10000; - end - else if ((t>=@"DC00) and (t<@"E000)) then - if (otp_output_buf[otp_counter+1]>=@"D800) - and (otp_output_buf[otp_counter+1]<@"DC00) then begin - incr(otp_counter); - t := (otp_output_buf[otp_counter]-@"D800) * @"400 + (t-@"DC00) + @"10000; - end; + t := otp_output_buf[otp_counter]; + if otp_counter < otp_output_end then begin + if ((t>=@"D800) and (t<@"DC00)) then begin + if (otp_output_buf[otp_counter+1]>=@"DC00) + and (otp_output_buf[otp_counter+1]<@"E000) then begin + incr(otp_counter); + t := (t-@"D800) * @"400 + (otp_output_buf[otp_counter]-@"DC00) + @"10000; + end + else if ((t>=@"DC00) and (t<@"E000)) then + if (otp_output_buf[otp_counter+1]>=@"D800) + and (otp_output_buf[otp_counter+1]<@"DC00) then begin + incr(otp_counter); + t := (otp_output_buf[otp_counter]-@"D800) * @"400 + (t-@"DC00) + @"10000; + end; + end; + end; if t <= @"7F then buffer[last]:= t else if t<=@"7FF then begin @@ -35092,7 +31011,7 @@ for otp_counter:=1 to otp_output_end do begin @<Report overflow of the input buffer, and abort@>; buffer[last]:=@"80 + t mod @"40; end - else if t<=@"FFFF then begin + else if t<=@"FFFF then begin buffer[last]:=@"E0 + t div @"1000; incr(last); if last=buf_size-2 then @@ -35550,38 +31469,19 @@ end end @ @<Put each...@>= -primitive("ocp", def_ocp, 0); -primitive("externalocp", def_ocp, 1); -primitive("ocplist", def_ocp_list, 0); -primitive("pushocplist", push_ocp_list, 0); -primitive("popocplist", pop_ocp_list, 0); -primitive("clearocplists", clear_ocp_lists, 0); -primitive("addbeforeocplist", ocp_list_op, add_before_op); -primitive("addafterocplist", ocp_list_op, add_after_op); -primitive("removebeforeocplist", ocp_list_op, remove_before_op); -primitive("removeafterocplist", ocp_list_op, remove_after_op); -primitive("ocptracelevel", ocp_trace_level, 0); +primitive_omega("ocp", def_ocp, 0,0); +primitive_omega("externalocp", def_ocp, 1,0); +primitive_omega("ocplist", def_ocp_list, 0,0); +primitive_omega("pushocplist", push_ocp_list, 0,0); +primitive_omega("popocplist", pop_ocp_list, 0,0); +primitive_omega("clearocplists", clear_ocp_lists, 0,0); +primitive_omega("addbeforeocplist", ocp_list_op, add_before_op,0); +primitive_omega("addafterocplist", ocp_list_op, add_after_op,0); +primitive_omega("removebeforeocplist", ocp_list_op, remove_before_op,0); +primitive_omega("removeafterocplist", ocp_list_op, remove_after_op,0); +primitive_omega("ocptracelevel", ocp_trace_level, 0,0); equiv(ocp_trace_level_base):=0; -@ @<Cases of |print_cmd_chr|...@>= -set_ocp: begin - print("select ocp "); - slow_print(ocp_name(chr_code)); - end; -def_ocp: if cur_chr=0 then print_esc("ocp") - else print_esc("externalocp"); -set_ocp_list: print("select ocp list "); -def_ocp_list: print_esc("ocplist"); -push_ocp_list: print_esc("pushocplist"); -pop_ocp_list: print_esc("popocplist"); -clear_ocp_lists: print_esc("clearocplists"); -ocp_list_op: - if chr_code=add_before_op then print_esc("addbeforeocplist") - else if chr_code=add_after_op then print_esc("addafterocplist") - else if chr_code=remove_before_op then print_esc("removebeforeocplist") - else {|chr_code|=|remove_after_op|} print_esc("removeafterocplist"); -ocp_trace_level: print_esc("ocptracelevel"); - @ @<Assignments@>= set_ocp: begin print_err("To use ocps, use the "); print_esc("pushocplist"); @@ -35611,7 +31511,6 @@ label common_ending; var u:pointer; {user's ocp identifier} @!f:internal_ocp_number; {runs through existing ocps} @!t:str_number; {name for the frozen ocp identifier} -@!old_setting:0..max_selector; {holds |selector| setting} @!flushable_string:str_number; {string not yet referenced} @!external_ocp:boolean; {external binary file} begin if job_name=0 then open_log_file; @@ -35620,13 +31519,7 @@ begin if job_name=0 then open_log_file; if cur_chr=1 then external_ocp:=true else external_ocp:=false; get_r_token; u:=cur_cs; -if u>=hash_base then t:=text(u) -else if u=null_cs then t:="OCP" -else begin old_setting:=selector; selector:=new_string; - print("OCP"); print(u-active_base); selector:=old_setting; -@.OCPx@> - str_room(1); t:=make_string; - end; +if u>=hash_base then t:=text(u) else t:="OCP"; define(u,set_ocp,null_ocp); scan_optional_equals; scan_file_name; @<If this ocp has already been loaded, set |f| to the internal ocp number and |goto common_ending|@>; @@ -35659,18 +31552,11 @@ procedure new_ocp_list(@!a:small_number); var u:pointer; {user's ocp list identifier} @!f:internal_ocp_list_number; {runs through existing ocp lists} @!t:str_number; {name for the frozen ocp list identifier} -@!old_setting:0..max_selector; {holds |selector| setting} begin if job_name=0 then open_log_file; {avoid confusing \.{texput} with the ocp list name} @.texput@> get_r_token; u:=cur_cs; -if u>=hash_base then t:=text(u) -else if u=null_cs then t:="OCPLIST" -else begin old_setting:=selector; selector:=new_string; - print("OCPLIST"); print(u-active_base); selector:=old_setting; -@.OCPx@> - str_room(1); t:=make_string; - end; +if u>=hash_base then t:=text(u) else t:="OCPLIST"; define(u,set_ocp_list,null_ocp_list); scan_optional_equals; f:=read_ocp_list; equiv(u) := f; eqtb[ocp_list_id_base+f] := eqtb[u]; @@ -35744,6 +31630,203 @@ define(ocp_active_max_ptr_base, data, active_max_ptr); end; +@* \[54/SyncTeX] The {\sl Synchronize \TeX nology}. +This section is devoted to the {\sl Synchronize \TeX nology} +- or simply {\sl Sync\TeX} - used to synchronize between input and output. +This section explains how synchronization basics are implemented. +Before we enter into more technical details, +let us recall in a few words what is synchronization. + +\TeX\ typesetting system clearly separates the input and the output material, +and synchronization will provide a new link between both that can help +text editors and viewers to work together. +More precisely, forwards synchronization is the ability, +given a location in the input source file, +to find what is the corresponding place in the output. +Backwards synchronization just performs the opposite: +given a location in the output, +retrieve the corresponding material in the input source file. + +For better code management and maintainance, we adopt a naming convention. +Throughout this program, code related to the {\sl Synchronize \TeX nology} is tagged +with the ``{\sl synctex}'' key word. Any code extract where {\sl Sync\TeX} plays +its part, either explicitly or implicitly, (should) contain the string ``{\sl synctex}''. +This naming convention also holds for external files. +Moreover, all the code related to {\sl Sync\TeX} is gathered in this section, +except the definitions. + +@ Enabling synchronization should be performed from the command line, +|synctexoption| is used for that purpose. +This global integer variable is declared here but it is not used here. +This is just a placeholder where the command line controller will put +the {\sl Sync\TeX} related options, and the {\sl Sync\TeX} controller will read them. + +@ @<Glob...@>= +@!synctexoption:integer; + +@ A convenient primitive is provided: +\.{\\synctex=1} in the input source file enables synchronization whereas +\.{\\synctex=0} disables it. +Its memory address is |synctex_code|. +It is initialized by the {\sl Sync\TeX} controller to the command-line option if given. +The controller may filter some reserved bits. + +@ In order to give the {\sl Sync\TeX} controller read and write access to +the contents of the \.{\\synctex} primitive, we declare |synctexoffset|, +such that |mem[synctexoffset]| and \.{\\synctex} correspond to +the same memory storage. |synctexoffset| is initialized to +the correct value when quite everything is initialized. + +@ @<Glob...@>= +@!synctexoffset:integer; {holds the true value of |synctex_code|} + +@ @<Initialize whatever...@>= +synctexoffset:=int_base+synctex_code; + +@ @<Initialize synctex primitive@>= +synctex_init_command; + +@ Synchronization is achieved with the help of an auxiliary file named +`\.{{\sl jobname}.synctex}' ({\sl jobname} is the contents of the +\.{\\jobname} macro), where a {\sl Sync\TeX} controller implemented +in the external |synctex.c| file will store geometrical information. +This {\sl Sync\TeX} controller will take care of every technical details +concerning the {\sl Sync\TeX} file, we will only focus on the messages +the controller will receive from the \TeX\ program. + +The most accurate synchronization information should allow to map +any character of the input source file to the corresponding location +in the output, if relevant. +Ideally, the synchronization information of the input material consists of +the file name, the line and column numbers of every character. +The synchronization information in the output is simply the page number and +either point coordinates, or box dimensions and position. +The problem is that the mapping between these informations is only known at +ship out time, which means that we must keep track of the input +synchronization information until the pages ship out. + +As \TeX\ only knows about file names and line numbers, +but forgets the column numbers, we only consider a +restricted input synchronization information called {\sl Sync\TeX\ information}. +It consists of a unique file name identifier, the {\sl Sync\TeX\ file tag}, +and the line number. + +Keeping track of such information, +should be different whether characters or nodes are involved. +Actually, only certain nodes are involved in {\sl Sync\TeX}, +we call them {\sl synchronized nodes}. +Synchronized nodes store the {\sl Sync\TeX} information in their last two words: +the first one contains a {\sl Sync\TeX\ file tag} uniquely identifying +the input file, and the second one contains the current line number, +as returned by the \.{\\inputlineno} primitive. +The |synctex_field_size| macro contains the necessary size to store +the {\sl Sync\TeX} information in a node. + +When declaring the size of a new node, it is recommanded to use the following +convention: if the node is synchronized, use a definition similar to +|my_synchronized_node_size|={\sl xxx}+|synctex_field_size|. +Moreover, one should expect that the {\sl Sync\TeX} information is always stored +in the last two words of a synchronized node. + +@ By default, every node with a sufficiently big size is initialized +at creation time in the |get_node| routine with the current +{\sl Sync\TeX} information, whether or not the node is synchronized. +One purpose is to set this information very early in order to minimize code +dependencies, including forthcoming extensions. +Another purpose is to avoid the assumption that every node type has a dedicated getter, +where initialization should take place. Actually, it appears that some nodes are created +using directly the |get_node| routine and not the dedicated constructor. +And finally, initializing the node at only one place is less error prone. + +@ Instead of storing the input file name, it is better to store just an identifier. +Each time \TeX\ opens a new file, it notifies the {\sl Sync\TeX} controller with +a |synctex_start_input| message. +This controller will create a new {\sl Sync\TeX} file tag and +will update the current input state record accordingly. +If the input comes from the terminal or a pseudo file, the |synctex_tag| is set to 0. +It results in automatically disabling synchronization for material +input from the terminal or pseudo files. + +@ @<Prepare new file {\sl Sync\TeX} information@>= +synctex_start_input; {Give control to the {\sl Sync\TeX} controller} + +@ @<Prepare terminal input {\sl Sync\TeX} information@>= +synctex_tag:=0; + +@ @<Prepare pseudo file {\sl Sync\TeX} information@>= +synctex_tag:=0; + +@ @<Close {\sl Sync\TeX} file and write status@>= +synctex_terminate(log_opened); {Let the {\sl Sync\TeX} controller close its files.} + +@ Synchronized nodes are boxes, math, kern and glue nodes. +Other nodes should be synchronized too, in particular math noads. +\TeX\ assumes that math, kern and glue nodes have the same size, +this is why both are synchronized. +{\sl In fine}, only horizontal lists are really used in {\sl Sync\TeX}, +but all box nodes are considered the same with respect to synchronization, +because a box node type is allowed to change at execution time. + +The next sections are the various messages sent to the {\sl Sync\TeX} controller. +The argument is either the box or the node currently shipped out. +The vertical boxes are not recorded, but the code is available for clients. + +@ @<Start sheet {\sl Sync\TeX} information record@>= +pdf_output_value:=pdf_output; {{\sl Sync\TeX}: we assume that |pdf_output| is properly set up} +synctex_sheet(mag); + +@ @<Finish sheet {\sl Sync\TeX} information record@>= +synctex_teehs; + +@ @<Start vlist {\sl Sync\TeX} information record@>= +synctex_vlist(this_box); + +@ @<Finish vlist {\sl Sync\TeX} information record@>= +synctex_tsilv(this_box); + +@ @<Start hlist {\sl Sync\TeX} information record@>= +synctex_hlist(this_box); + +@ @<Finish hlist {\sl Sync\TeX} information record@>= +synctex_tsilh(this_box); + +@ @<Record void list {\sl Sync\TeX} information@>= + if type(p)=vlist_node then begin + synctex_void_vlist(p,this_box); + end + else begin + synctex_void_hlist(p,this_box); + end; + +@ @<Record current point {\sl Sync\TeX} information@>= +synctex_current; + +@ @<Record horizontal |rule_node| or |glue_node| {\sl Sync\TeX} information@>= +synctex_horizontal_rule_or_glue(p,this_box); + +@ @<Record |kern_node| {\sl Sync\TeX} information@>= +synctex_kern(p,this_box); + +@ @<Record |math_node| {\sl Sync\TeX} information@>= +synctex_math(p,this_box); + + +@ {\sl Nota Bene:} +The {\sl Sync\TeX} code is very close to the memory model. +It is not connected to any other part of the code, +except for memory management. It is possible to neutralize the {\sl Sync\TeX} code +rather simply. The first step is to define a null |synctex_field_size|. +The second step is to comment out the code in ``Initialize bigger nodes...'' and every +``Copy ... {\sl Sync\TeX} information''. +The last step will be to comment out the |synctex_tag_field| related code in the +definition of |synctex_tag| and the various ``Prepare ... {\sl Sync\TeX} information''. +Then all the remaining code should be just harmless. +The resulting program would behave exactly the same as if absolutely no {\sl Sync\TeX} +related code was there, including memory management. +Of course, all this assumes that {\sl Sync\TeX} is turned off from the command line. +@^synctex@> +@^synchronization@> + @* \[54] System-dependent changes. This section should be replaced, if necessary, by any special modifications of the program |