diff options
Diffstat (limited to 'Master/texmf-doc/doc/english/knuth/errata/tex82.bug')
-rw-r--r-- | Master/texmf-doc/doc/english/knuth/errata/tex82.bug | 9094 |
1 files changed, 0 insertions, 9094 deletions
diff --git a/Master/texmf-doc/doc/english/knuth/errata/tex82.bug b/Master/texmf-doc/doc/english/knuth/errata/tex82.bug deleted file mode 100644 index 607ffff358d..00000000000 --- a/Master/texmf-doc/doc/english/knuth/errata/tex82.bug +++ /dev/null @@ -1,9094 +0,0 @@ -This file has been updated periodically ever since TeX82 was born; -it has been summarized in "The errors of TeX," Software Practice & -Experience, July 1989. Entries are in chronological order; -thus the most recent news (including all bugfixes made since -that article was published) appears at the bottom of the file. - -[Add 519 to these entry numbers to get the corresponding number in -the published article. The article also translates all module -numbers to their final form; what you are about to read is -"authentic source material" from the early days before TeX converged.] - -------------------------------------------------------------------------------- - -First updates to the TeX82 listing published in September, 1982. -(These changes were included in the original Version 0 of TeX, but they -were discovered after the listing went to press.) - -1. Module 943, line 6 (bug discovered 9/28) -change "if cur_cmd=char_num then" to - if (cur_cmd=letter) or (cur_cmd=other_char) then r:=qi(cur_chr) - else if cur_cmd=char_num then - -2. "pause" changed to "pausing" and "pause_code" to "pausing code", throughout. - -3. Module 719, lines 8 and 11 (bug discovered 9/28) -insert "rule_save:=overfull_rule; overfull_rule:=0;" after "save_ptr-2;" -insert "overfull_rule:=rule_save;" before "q:=p+list_offset;" -and insert a declaration of "overfull_rule: scaled" in module 716. - -4. Module 1128, lines 6 and following (bug discovered 9/28) -change "while n<>0 do" to "loop" -change "goto done" to - begin scan_left_brace; new_save_level(false_group); - goto done; - end -change "... return 1130>;" to - ... return 1130> - else if n=0 then - begin new_save_level(case_group); goto done; - end; -and change "done: ... (false_group);" to "done:". - -5. Module 182, line 10 (suggestion by DRF on 9/30) -change "0.0" to "?.?" - -6. Module 682, new definition of math_spacing (decision of 10/2) -"0234000122*4000133**3**344*0400400*000000234000111*4111112341011" - -7. Module 684, new code for case "4" (decision of 10/2) -"4": if cur_style<script_style then x:=thick_mu_skip_code else x:=0; -[Also in module 682 line 7, say "...a conditional thick space (\nonscript..."] - -8. Module 11, trie_size changed from 7000 to 8000 because of new -improved (but longer) hyphenation patterns (10/4) - -9. Module 453, forgot to change this when 454 changed (noted by DRF 10/6) -format_default_length=20 (not 22) -format_area_length=11 (not 13) - -Changes to TEX.WEB made after Version 0 was released in October, 1982. - -Since copies of TEX.WEB are not supposed to be edited, there are -two ways to make your version of TeX bug-free: - 1. Get a new copy of TEX.WEB. - 2. Put the corrections into your change file(s). -Some people will find (1) easier than (2), except the main TeX sources at -SCORE won't be updated quite as fast as the sources at SAIL (which have to -be translated into ascii before they are sent to the outside world). -Actually (2) will be quite easy, unless the list of changes becomes quite -long, so it is the recommended procedure. In case (2) it would be useful -to include a comment like "this is fix number xx" (using the numbering -scheme in this file), so that the change could readily be deleted at some -future time. - -10. Module 857 line -5 (bug discovered 10/8/82 by HWT) -change it to: if h>0 then decr(h) else h:=trie_op_hash_size; - -11. Module 457 line 3 (typo discovered 10/9/82) -change `\.!' to `\.\&' - -12. Module 1245 line 8 (bug fixed 10/9/82, discovered by MMD) -insert the following between "begin" and "if": -if format_ident<>0 then initialize; {erase preloaded format} - -** Version 0.1 incorporates the above changes. - -13. This is an extension to the language, put in to satisfy people who -objected to the fact that \write (and \openout and \closeout) only -caused action after being deferred to the next \shipout. Some applications -call for immediate output, hence a new feature: \immediate followed by -\openout or \write or \closeout causes the output action to take place -without delay. For example, \immediate\write{x} is equivalent to -\shipout\vbox{\write{x}} except that the latter also puts an empty -page into the DVI file. - -The extension requires the following new code: -13a. Insert `\immediate' after `\closeout' in module 1248. -13b. Define immediate_code=4 and include the following in module 1252: - primitive("immediate",extension,immediate_code); -13c. Include the following in module 1254: - immediate_code:print_esc("immediate"); -13d. And, in module 1256: - immediate_code:@<Implement \.{\\immediate}@>; -13e. Finally, there's a new module inserted after old module 1280. -Here is the WEB coding for this module: - -@ The presence of `\.{\\immediate}' causes the |do_extension| procedure -to descend to one level of recursion. Nothing happens unless \.{\\immediate} -is followed by `\.{\\openout}', `\.{\\write}', or `\.{\\closeout}'. -@^recursion@> - -@<Implement \.{\\immediate}@>= -begin get_nc_token; -if (cur_cmd=extension)and(cur_chr<=close_node) then - begin p:=tail; do_extension; {append a whatsit node} - out_what(tail); {do the action immediately} - flush_node_list(tail); tail:=p; link(p):=null; - end -else back_input; -end; - -** Version 0.2 incorporates the above changes. - -14. Like change 11, this one doesn't affect the program, it just improves -the documentation: Insert the following definitions in module 106: -define set_glue_ratio_zero(#) == #:=0.0 {assign representation of zero ratio} -define set_glue_ratio_one(#) == #:=1.0 {assign representation of unit ratio} - -These macros are now introduced in a dozen or so future modules, thereby -eliminating most of the system-dependent changes needed elsewhere for ratios. -(Note: I also changed 0 to 0.0 in two places of module 182, where a glue_ratio -comparision was being made.) - -15. Change of module 576 (discovered by HWT, 10/14/82) -"hd:quarterword" should be "hd:eight_bits". -(The same error occurs in module 522, but in that module the remedy is -simply to delete the declaration of hd, since this variable is no longer used.) - -16. A most embarrassing bug (discovered by DRF, 10/14/82) -Replace module 531 by: - -@ A mild optimization of the output is performed by the |dvi_pop| -routine, which issues a |pop| unless it is possible to cancel a -`|push| |pop|' pair. The parameter to |dvi_pop| is the byte address -following the old |push| that matches the new |pop|. - -@p procedure dvi_pop(@!l:integer); -begin if (l=dvi_offset+dvi_ptr)and(dvi_ptr>0) then decr(dvi_ptr) -else dvi_out(pop); -end; - -Now we need to make a few changes to subsequent modules: -16a. In 549, after "incr(cur_s)", insert - if cur_s>0 then dvi_out(push); -and before "decr(cur_s)", insert - if cur_s>0 then dvi_pop(save_loc); - -16b. Delete "dvi_out(push);" and "dvi_pop;" from modules 553, 558, 562, 567. - -16c. Change module 559 just as in 16a. - -17. Module 605, line 6 (discovered 10/15/82) -The test should be "prev_depth>ignore_depth" - -** Version 0.3 incorporates the above changes. - -18. Module 11 (noticed by WLS, 10/16/82) -Delete the definition of align_size (it's harmless but never used) - -19. (This change and the next cause major changes to the TRIP output; -file TRIP.LOG and its relatives are being kept up to date on area [tug,dek].) -The change avoids error messages when vpackage is called during output. -Such messages can occur when there was no error, because the page is being -boxed without the \skip glue from its insertions; so they should be omitted. -The user who really wants such messages can still get them by saying -"\setbox255=\vbox to 1ht255{\unbox255}". -In module 903, insert the followng before the declaration of "wait": - save_vbadness:integer; {saved value of |vbadness|} - save_vfuzz: scaled; {saved value of |vfuzz|} -Then in module 924, insert - save_vbadness:=vbadness; vbadness:=inf_bad; - save_vfuzz:=vfuzz; vfuzz:=max_dimen; {inhibit error messages} -before the call on vpackage, and - vbadness:=save_vbadness; vfuzz:=save_vfuzz; -after. - -20. Module 917 computes |page_size| improperly. (Noticed 10/21/82) -Delete the statement "page_so_far[1]:=page_so_far[1]+width(q);" -and change the preceding statement to: - page_size:=page_size-h-width(q); -(The comment about page_so_far in the first paragraph of module 895 is -correct; I mistakenly introduced a bug in module 917 some months after -writing the first draft of the code, believing that I was making the -algorithm more elegant or something.) - -** Version 0.4 incorporates the above changes. - -21. Since TeX82 applied to (the "woven" documentation) TEX.TEX uses -about 11500 words of variable-size memory, I'm increasing hi_mem_size -(in module 12) from 12000 to 13000. Actually, I recommend using considerably -larger values for mem_max and hi_mem_size, whenever possible. - -22. Addition of the \boxmaxdepth parameter (10/22/82): -This involves renumbering hfuzz_code through dimen_pars, in module 234, -to numbers 9 through 18; inserting the lines - @d box_max_depth_code=8 {maximum depth of explicit vboxes} - @d box_max_depth==dimen_par(box_max_depth_code) - box_max_depth_code:print_esc("boxmaxdepth"); -to module 234 and - primitive("boxmaxdepth",assign_dimen,box_max_depth_code); -to module 235; and changing the call on vpack in module 996 to - vpackage(link(head),saved(2),saved(1),box_max_depth); - -** Version 0.5 incorporates the above changes. - -23. Module 1224, line 4 (bug found by GMK/HWT on 10/26/82) -change "(k+x>eqtb_size)" to "(k+x>eqtb_size+1)" - -24. Module 247, line 13 (bug found 10/26/82) -(bug was reflected in TRIP.LOG but not noticed) -change "ch_code(p)" to "ch_code(p-single_base)" - -25. Module 670, line 18 (bug found 10/27/82) -interchange the statements "fetch(...)" and "math_type(...):=..." -(since the fetch routine sometimes has a side-effect of changing math_type) -A major change (Version 0.6) made on October 28: -The following list of changes counts as "number 26" on the list. -Fonts now have identifiers instead of code numbers; the "\:" primitive -has disappeared; and there are associated new features for "\the". - -a. In module 11, delete bad_font_code. -b. In modules 170 and 172, delete print_esc(":"), and change - `print_int(font_code' to `sprint_cs(font_ident'. -c. In module 205, the comment for set_font is revised. -d. In module 217, there are now five locations for control sequences - that are perpetually defined; undefined_control_sequence - is therefore defined to be frozen_control_sequence+5. -e. In module 248, sprint_cs is now included among <Basic printing procedures>. -f. Delete the primitive ":" in modules 250 and 251. -g. Add to module 376: <Declare procedures that scan font-related stuff> -h. In module 377, seven levels are now distinguished; we define - font_val=4, ident_val=5, tok_val=6. -i. In module 380, delete the previous cases for def_family and set_font, - and the following takes the place of case assign_toks: - assign_toks,def_family,set_font,def_font: <Fetch a token list or - font number or font identifier, provided that level=tok_val>; -j. Module 382 (which now has a new name) has this new ending: - else if cur_cmd=assign_toks then scanned_result(equiv(m))(tok_val) - else <Fetch a font number or a font identifier> -k. Module 389 becomes - <Fetch a font number or a font identifier>= - if cur_cmd=set_font then scanned_result(cur_chr)(font_val) - else if cur_cmd=def_font then - scanned_result(font_ident[cur_font])(ident_val) - else begin scan_four_bit_int; - scanned_result(font_ident[equiv(m+cur_val)])(ident_val); - end -l. In module 393, the relation `<>tok_val' becomes `<=mu_val'. -m. In module 426, the relation `=tok_val' becomes '>=ident_val'. - Also add a new case to the case statement: - font_val: begin print(font_name[cur_val]); - if font_size[cur_val]<>font_dsize[cur_val] then - begin print(" at "); print_scaled(font_size[cur_val]); - print("pt"); - end; - end; -n. The body of module 427 becomes: - begin p:=temp_head; link(p):=null; - if cur_val_level=ident_val then store_new_token(cs_token_flag+cur_val) - else if cur_val<>null then - begin r:=link(cur_val); {do not copy the reference count} - while r<>null do - begin store_new_token(info(r)); r:=link(r); - end; - end; - the_toks:=p; - end -o. In module 480, delete user_font_code; there's a new comment: - When the user defines \font\f, say, TeX assigns an internal number - to the user's font \f. For example, if this internal number is 13, - we will have font_ident[13]=p and equiv(p)=13, where p is the eqtb - location of the control sequence \f. -p. In module 481, delete the declaration of font_number, and - replace the declaration of font_code by - font_ident:array[internal_font_number] of pointer; -q. New stuff in module 483 (also delete references to font_number, font_code): - define bad_font_ident=frozen_control_sequence+4 {denotes a null font} - font_name[undefined_font]:="nullfont"; - font_ident[undefined_font]:=bad_font_ident; - text(bad_font_ident):="nullfont"; eq_level(bad_font_ident):=level_one; - eq_type(bad_font_ident):=set_font; - equiv(bad_font_ident):=undefined_font; -r. In module 490, parameter u is new of type pointer, and the - read_font_info subroutine is changed to a function that - returns an internal_font_number. There's a new local variable - g:internal_font_namber; {the number to return} - and we set g:=undefined_font immediately upon entering read_font_info. - Also set read_font_info:=g just before exiting. -s. In module 491, print_int(u) becomes sprint_cs(u). -t. Delete the statements involving font_code and font_number in module 506, - and set g:=f at the end of that module. -u. The body of module 507 becomes: - <Declare procedures that scan font-related stuff>= - procedure scan_font_ident; - var f:internal_font_number; - begin <Get the next non-blank non-call...>; - if cur_cmd=set_font then f:=cur_chr - else begin print_nl("! Missing font identifier"); - help2("I was looking for a control sequence whose") - ("current meaning has been defined by \font."); - back_error; f:=undefined_font; - end; - end; -v. New beginning of module 508: - The following routine is used to implement `\texinfo f n'. - The boolean parameter writing is set true if the calling program - intends to change the parameter value. - <Declare procedures that scan font-related stuff>= -and "scan_font_number" is changed to "scan_font_ident". -w. In module 509, "print_int(font_code" becomes "sprint_cs(font_ident". - Also "font code is defined" becomes "\font is loaded" in the help. -x. In module 940, the first line of help is changed to - "You have to specify a font identifier," -y. The set_font case in module 1138 reduces to - set_font: define(cur_font_loc,data,cur_chr); -z. In module 1153, delete all the complicated stuff starting with "scan_int" - and substitute simply this: - scan_font_ident; define(p,data,cur_val); - end; -aa. Change new_font to new_font(a) in module 1169, and add parameter - (a:small_number) - in module 1170. Also add the label common_ending, and declare - variable u to have type pointer. The code beginning with "scan_int" - is changed to the following: - get_token; - if cs_ptr=0 then - <Complain about the missing control sequence and return>; - u:=cs_ptr; scan_optional_equals; scan_file_name; - <Scan the ``at'' size specification>; - <If this font has already been loaded, set f to the internal - font number and goto common_ending>; - f:=read_font_info(u,cur_name,cur_area,s); - common_ending: define(u,set_font,f); font_ident[f]:=u; - exit:end; -bb. New module 1172: - When the user gives a new identifier to a font that was previously - loaded, the new value becomes the font_ident of record. - Font names `xyz' and `XYZ' are considered to be different. - <If this font has already been loaded...>= - for f:=font_base+1 to font_ptr do - if [the test previously in module 1174] then goto common_ending -cc. New module 1173: - <Complain about the missing control sequence and return>= - begin print_nl("! A font identifier must be a control sequence"); - help2("You should say, e.g., `\font\f=fontfilename'.") - ("(I'm going to ignore the \font command you just gave.)"); - back_error; return; - end -dd. New module 1174: - <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; -ee. Delete the comment at the beginning of module 1227, and delete the - loop for k:=0 to bad_font_code-1, and delete dump_int(undefined_font). -ff. Delete the repeat loop in module 1228. -gg. Change font_code to font_ident in module 1229, and change - print_int(font_code to sprint_int(font_ident. -hh. In module 1230, - begin undump(single_base)(undefined_control_sequence)(font_ident[k]); - undump_qqqq(font_check[k]); [and continue as before] - -The changes above have been incorporated into Version 0.6. -The ill-fated Version 0.7 - -27. (Here's a change that I retracted shortly after making it, since I -discovered that the source was flaky after all; and I also found a reliable -source [NBS Circular 570] confirming my original information. I include -the note here only for historical purposes...) - -"After years of searching, I've finally found a definitive definition of -the printer's point; and (unfortunately) my previous conjecture was wrong. -The truth is that 83pc=35cm, exactly; so I am changing TeX to conform. -This means some changes in the comments of modules 101 and 517, and the -following changes to the program: - -"27a. In modules 547 and 571, the appropriate DVI numbers are now: - dvi_four(109375); dvi_four(2039808); {conversion ratio for sp} -"27b. The guts of module 418 become: - if scan_keyword("in") then set_conversion(63246)(875) - else if scan_keyword("pc") then set_conversion(12)(1) - else if scan_keyword("cm") then set_conversion(996)(35) - else if scan_keyword("mm") then set_conversion(498)(175) - else if scan_keyword("bp") then set_conversion(10541)(10500) - else if scan_keyword("dd") then set_conversion(996)(931) - else if scan_keyword("cc") then set_conversion(11952)(931) - else..." - -*** Version 0.7 of TeX incorporated the changes above (82/10/30); -this version was withdrawn on 82/11/2. -Changes subsequent to Version 0.6 - -28. The experience with #27 did lead me to one improvement, thanks -to Chuck Bigelow, with respect to Didot points. (11/4/82) -Add the following comment to module 418: - According to the definitions here, $\rm2660\,dd\approx1000.33297\,mm$; - this agrees well with the value $\rm1000.333/,mm$ cited by Bosshard - in {\sl Technische Grundlagen zur Satzherstellung\/} (Bern, 1980). -And change two lines of the code there as follows: - else if scan_keyword("dd") then set_conversion(1238)(1157) - else if scan_keyword("cc") then set_conversion(14856)(1157) - -29. The new font material is made more robust by ensuring that \the\font -always returns a pointer to a control sequence whose command code is -set_font. (Change 11/4/82) - -29a. The code changed in 26aa is changed again, to the following: - <If the next token isn't a control sequence, issue a complaint and - return; otherwise set u:=cs_ptr, and set hash_used to the - location of a ``frozen'' copy of the new font identifier>; - define(u,set_font,undefined_font); - scan_optional_equals; scan_file_name; - <Scan the ``at'' size specification>; - <If this font has already been loaded, set f to the internal - font number and goto common_ending>; - f:=read_font_info(u,cur_name,cur_area,s); - common_ending: equiv(u):=f; geq_define(hash_used,set_font,f); - font_ident[f]:=hash_used; - exit:end; -29b. Instead of 26cc, here's the new module 1173: - We reserve a special control sequence for the font identifier; - this one cannot be redefined by the user, so it is safe to - return it as a value of \the\font. - <If the next token isn't a control sequence...>= - get_token; - if cs_ptr<hash_base then - begin print_nl( - "! A font identifier must be a multiletter control sequence"); - help2("You should say, e.g., `\font\ffn=fontfilename'.") - ("(I'm going to ignore the \font command you just gave.)"); - back_error; return; - end; - repeat if hash_is_full then overflow("hash size",hash_size); - decr(hash_used); - until text(hash_used)=0; {search for an empty location in hash} - u:=cs_ptr; text(hash_used):=text(u); {copy the name} - stat incr(cs_count); tats - -30. Module 993, replace lines 5 to 7 (11/5/82): -else begin if k=vmode then new_save_level(vbox_group) - else begin new_save_level(vtop_group); k:=vmode; - end; - if looseness<>0 then eq_word_define(int_base+looseness_code,0); - if hanging_indent<>0 then - eq_word_define(dimen_base+hanging_indent_code,0); - if par_shape_ptr<>null then eq_define(par_shape_loc,shape_ref,null); - end; - -31. Module 403, replace line 5 (11/6/82): -if cur_tok<cs_token_flag then - begin cur_val:=cur_chr; - if cur_cmd<=right_brace then - if cur_cmd=right_brace then incr(align_state) - else decr(align_state); - end - -32. Improvements to error recovery for bad alignments (11/6/82): -In module 1039, replace "begin align_error; goto reswitch; end" by "align_error" -In module 1040, delete "cur_cmd:=left_brace;" and "cur_cmd:=right_brace;" - and change "error" to "back_error" -In module 1041, delete "cur_cmd:=relax;" - -33. More power to \let (11/8/82): -33a. Module 1141 becomes: - <Assignments>+= - let: begin get_token; - if cs_ptr<>0 then <Carry out the \let operation> - else begin print_nl - ("! You can use \let only with control sequences"); - help2("I'm not \let-ting anything change here,") - ("since I can only do things like `\let\a=b'."); - back_error; - end; - end; -33b. Module 1142 becomes: - <Carry out the \let...>= - begin p:=cs_ptr; - repeat get_token; - until cur_cmd<>spacer; - if cur_tok=other_token+"=" then - begin get_token; - if cur_cmd=spacer then get_token; - end; - if cur_cmd>=call then add_token_ref(cur_chr); - define(p,cur_cmd,cur_chr); - end - -34. This change helps you see an undefined control sequence -in certain unusual cases (discovered by JDH, 11/8/82): -Add the clause "(base_ptr=input_ptr) or" to module 294, line 2. - -35. Here's an improvement in the formula for demerits; previously -more weight was given to minimizing bad spacing on lines with penalties, -so that (slightly loose hyphenated line)(OK line) was considered worse -than (OK hyphenated line)(quite loose line). (fixed 11/8/82) -Change lines 2--7 of module 772 to the following: - d:=line_penalty+b; d:=d*d; - if pi<>0 then - if pi>0 then d:=d+pi*pi - else if pi>eject_penalty then d:=d-pi*pi; - -36. Minor change to save buffer space in non-INITEX (11/10/82): -Enclose the declaration of pool_file in module 50 by init...tini. - -37. Minor improvement in format for the context of error messages (11/13/82): -37a. Module 289, type "inserted" split into "backed_up=3", "inserted=4" -and the other type numbers increase: "macro=5", etc. -37b. In module 296, backed_up: if loc=null then print_nl("<recently read>") - else print_nl("<to be read again> "); - inserted: print_nl("<inserted text> "); -37c. Minor changes to comments in modules 289 and 293. -37d. Change "inserted" to "backed_up" in module 294. -37e. Add definition "back_list(#)==begin_token_list(#,backed_up)" in module 305. -37f. In module 306, first test should be ">=backed_up", second "<=inserted". -37g. Change ins_list to back_list in modules 307, 318, 375, 1195. -37h. Add definition to module 308: - ins_error==begin back_error; token_type:=inserted; end -37i. Change back_error to ins_error in modules 362, 1040, 1046. -37j. Change "<to be read again>" to "<inserted text>" in module 973 help. - -38. Module 407, the error message is changed (11/11/82) to: -"! Missing number, treated as zero". - -39. Fix anomaly when hbadness or vbadness is small (11/11/82): -Module 593, line 2, "if (-x-total_shrink[normal]>hfuzz) or (hbadness<100)" -Module 603, line 2, "if (-x-total_shrink[normal]>vfuzz) or (vbadness<100)" - -40. Added the \tokens primitive (11/13/82): -In module 223, defined tokens_loc and tokens (analogous to every_par). -In module 225, defined the primitive. -In module 1146, changed the comment to include tokens_loc as a possibility. - -41. Change get_nc_token to get_token in module 374 (11/13/82). -(In particular \def\foo{...}\foo won't say "undefined c.s." now!) -(This change later retracted during debugging; it was found that -"endv" aborts the job, so this cure was worse than the disease. Then -it was re-established as part of the major change to conditionals, -because endv needed to be more robust anyway.) - -42. In module 699, we make \span expand in a preamble (11/13/82). -Change lines -7 through -3 to: - begin get_nc_token; goto reswitch; - end; - -43. Modules 321 and 322 have been altered for better efficiency (11/12/82) -and better exposition; the three conditions of module 322 are now -in separate if tests. - -44. Frozen control sequences are now unredefinable. (11/16/82) -A new procedure get_r_token has been introduced to give uniform error -messages for \def, \let, \read, \font, \mathchardef, and to make them -incapable of changing the frozen equivalents. - -Incidentally, get_nc_token is changed to get_x_token; and ch_code -becomes cat_code. -A major change (Version 0.8) made on November 14--16: -Conditional statements are taken from semantics to syntax. - -This change, which counts as number 45 on the list, made it necessary -to renumber the modules. And it was such a drastic change, the -differences can only be sketched here, using the old module numbers -for reference. A variety of other things were cleaned up because this -change made it more natural for them to be handled differently. - -45a. Module 158, inserted a permanently empty token list called null_list. -45b. Module 204, deleted if_test, case_branch, else_code, convert; - inserted end_cs_name. -45c. Module 206, inserted if_test, fi_or_else, cs_name, convert, and - end_template (the latter comes after long_outer_call). -45d. Module 217, there are now nine frozen control sequences; also null_cs. -45e. Modules 247 and 248, must be able to print a null control sequence. -45f. Module 268 (leave_transparent_group) disappears; comments in the - previous modules also are appropriately simplified. -45g. Module 273, delete endv_token. -45h. Modules 277 and 278, delete references to endv (it no longer appears). -45i. After module 281, a procedure show_cur_cmd_chr takes the - code for tracing commands from module 937. -45j. Module 317 now forbids \outer control sequences when skipping, - and inserts \fi in front of them, for error recovery. -45k. Module 334 now uses null_cs if carriage-return is an escape. -45l. Module 343 no longer has endv test. -45m. Module 344, major extensions to expand_calls make it several modules - longer. It saves global variables like cur_val. It changes - end_template to endv. It processes cs_name and convert. - It processes if_test by calling the "conditional" procedure. - It processes fi_or_else by checking their legality, and (if legal) - updating the if stack. -45n. Module 373 (pass_block) disappears. -45o. After module 400, radix and cur_val and cur_val_level are initialized. -45p. Module 428 changes so that conv_toks is a procedure rather than a - function; this procedure is invoked by expand_calls. -45q. Modules 436 and 1032, delete reference to conv_toks. -45r. After module 443, the entire part 48 moves to this part of the program, - and the parts are renumbered accordingly. \case is changed to - \ifcase, and it resides under the if_test command. - New routines are inserted to maintain a linked stack that records - the current state of conditionals. There's a procedure - pass_text that skips text while looking for \fi or \else or \or - on level zero with respect to \if...\fi nesting. The previous - routines for skip control via handle_right_brace are eliminated, - and the new ones are somewhat simpler. The new \ifcat is mostly - combined with the old \if; they no longer ignore spaces. - The scanner_status is set to normal while processing \ifx. - \ifx will consider \a to equal 0 after \let\a=0. -45s. Modules 701, 707: endv_token is replaced by a token for a frozen - control sequence whose command code end_template makes it behave - like an outer_call. After expand_calls, it is converted to another - frozen control sequence, whose command code is endv. This two-step - facilitates error recovery, instead of giving a fatal error stop. -45t. Module 874, remove "pass_block(1); goto done". -45u. After module 1047, routine for end_cs_name prints an error message. -45v. Module 1049, get_nc_token becomes get_token. (else $\ifmmode fails) -45w. Module 1202 gets another case (end_template). -45x. Module 1243, new warning is printed if the if stack isn't empty. -Changes after version 0.8 - -46. Declare c : ascii_code in module 825 (noted by DRF, 11/21/82) - -47. Module 776 lines 4-6 (suggested by DRF, 11/21/82) -threshold:=pretolerance; -if threshold>=0 then - begin stat if tracing_stats>2 then - begin begin_diagnostic; print_nl("@@firstpass"); - end; tats - second_pass:=false; - end -else begin threshold:=tolerance; second_pass:=true; - end; - -48. Protection for DVI files (added 11/16/82) -Replace lines 2 and 3 of module 570 by: - <Update the values of max_h and max_v; but if the page is too large, - goto done>; -Move the statement "dead_cycles:=0" from module 570 to module 568. -Declare "label done;" in module 568. -And add the following new module after 570: - -@ Sometimes the user will generate a huge page because other error messages -are being ignored. Such pages are not output to the \.{dvi} file, since they -may confuse the printing software. - -@<Update the values of |max_h| and |max_v|; but if the page is too large...@>= -if (height(p)>max_dimen)or(depth(p)>max_dimen)or(width(p)>max_dimen) then - begin print_nl("! Huge page cannot be shipped out"); - help2("The page just created is more than 18 feet tall or")@/ - ("more than 18 feet wide, so I suspect something went wrong."); - error; - if tracing_output=0 then - begin begin_diagnostic; - print_nl("The following box has been deleted:"); - show_box(p); - end_diagnostic(true); - end; - goto done; - end; -if height(p)+depth(p)>max_v then max_v:=height(p)+depth(p); -if width(p)>max_h then max_h:=width(p) - -49. New features \everymath and \everydisplay (12/2/82). -Make changes analogous to those for "\tokens" (see change 40). -Put the following just before the end of module 1050: - if every_math<>null then begin_token_list(every_math,every_math_text); -And put the following just before the end of module 1056: - if every_display<>null then - begin_token_list(every_display,every_display_text); - -50. New feature \futurelet (12/2/82): -Module 1141 changes again. (Also, "let" and "futurelet" share cmd code "let".) -let: begin n:=cur_chr; - get_r_token; p:=cs_ptr; - if n=normal then - begin repeat get_token; - until cur_cmd<>spacer; - if cur_tok=other_token+"=" then - begin get_token; - if cur_cmd=spacer then get_token; - end; - end - else begin get_token; q:=cur_tok; get_token; back_input; - cur_tok:=q; back_input; {look ahead, then back up} - end; {|back_input| doesn't affect |cur_cmd|, |cur_chr|} -and continue with "if cur_cmd>=call", as before. - -*** The changes above have been incorporated into version 0.9 of TeX. -Changes after version 0.9 - -51. new \endinput primitive (suggested by FY, 12/7/82): -\input and \endinput both use the same command code. The cases in module -955 are deleted and replaced by those in module 965 (which disappears), -because \input is now allowed in any mode. The code for any_mode(input) -is "if cur_chr=0 then start_input else force_eof:=true", and it moves from -module 952 to just before module 1197. The global variable force_eof -is initially false, and module 340 becomes (after first:=start;) - if not force_eof then - begin if input_ln.... else force_eof:=true; - end; - if force_eof then begin print_char(")"); force_eof:=false;... - -52. Module 1005, line 4 (12/8/82) -change "if align_state<0" to "if (mode<0)or(align_state<0)" -(This avoids embarrassing case where TeX says "type a command or say \end" -but when you type \end it says "You can't use \end in restricted horiz mode".) - -53. Patch to the new code for \csname (12/21/82) -After eq_type(cs_ptr):=relax, also say equiv(cs_ptr):=256. -(This corrects a bug that would appear only if \csname occurs right -after a file name.) - -54. Change 47 introduced a bug when tracingonline=0 (12/20/82) -when omitting firstpass, also do "if tracing_stats>2 then begin_diagnostic;" - -55. \hskip -1pt plus 2pt was parsed as \hskip -(1pt plus 2pt)! (12/20/82) -In module 421, before line -4, insert the following: - if negative then - begin cur_val:=-cur_val; negative:=false; - end; -But then realize that "negative" is always false on line -2; simplify. - -56. Cosmetic change to paragraph statistics (12/23/82) -tight_fit..very_loose_fit codes have been renumbered very_loose_fit..tight_fit. - -57. Module 729 changes to make TeX language more consistent (12/23/82): -else if type(tail)<>glue_node then tail_append(new_penalty(inf_penalty)) -else begin type(tail):=penalty_node; delete_glue_ref(glue_ptr(tail)); - flush_node_list(leader_ptr(tail)); penalty(tail):=inf_penalty; - -58. Commas are allowed as alternates to radix points. (12/23/82) -define continental_point_token=other_token+"," {decimal point, Eurostyle} -in module 400, and insert the following twice in 409: - if cur_tok=continental_point_token then cur_tok:=point_token; - -59. \hangindent becomes a normal parameter. (12/23/82) -This simplifies the code in obvious ways; for example, module 1148 disappears. -The command code hang_indent goes away too; what was previously called -hanging_indent is then renamed hang_indent. - -60. \prevgraf becomes accessible. (12/23/82) -This involves renaming the "after" field "pg_field" in the nest array; -making a new command code set_prev_graf; -including the following loop into scan_the: - nest[nest_ptr]:=cur_list; p:=nest_ptr; - while abs(nest[p].mode_field)<>vmode do decr(p); - scanned_result(nest[p].pg_field)(int_val); -and including the following active procedure for any_mode(set_prev_graf): - procedure change_prev_graf; - var p:0..nest_size; {index into |nest|} - begin nest[nest_ptr]:=cur_list; p:=nest_ptr; - while abs(nest[p].mode_field)<>vmode do decr(p); - scan_optional_equals; scan_int; - if cur_val<0 then - begin print_nl("! Bad \prevgraf"); - help1("I allow only nonnegative values here."); - int_error(cur_val); - end - else begin nest[p].pg_field:=cur_val; cur_list:=nest[nest_ptr]; - end; - end; - -61. \clubpenalty is split off from \widowpenalty. (12/23/82) - -62. Bad bug in module 1005 (12/24/82) -(must not go to reswitch if \par is a macro!) -Instead of setting cur_cmd and cur_chr and goto reswitch, just back_input -and set token_type:=inserted. - -63. \openin not to prompt if file not present (12/25/82) -Change lines -4 and -3 of module 1183 to: - if a_open_in(read_file[n]) then read_open[n]:=just_open - else read_open[n]:=closed; - -64. New \jobname primitive (12/25/82) -It is added to the "convert" command in the obvious way. -In conv_toks, the relevant code is - if job_name=0 then open_log_file -before "selector" is changed and - print(job_name) -after. - -65. Better error recovery for math-only things (12/25/82): -In module 952, don't goto reswitch after insert_dollar_sign. -In module 954, first back_input, then set cur_tok, and -don't bother to set cur_chr or cur_cmd; ins_error instead of back_error. - -66. Module 1163, line 3, insert "scan_optional_equals" (12/25/82). -Also make \the\parshape allowed. - -67. The location where an \if begins is stacked (12/26/82) -so that a better error message can be given for \end while \if is incomplete. -This means two-word nodes instead of one-word nodes in the if stack. - -68. Change 30 is extended to \insert, \vadjust, \valign, \output (12/26/82) -The one-time-only paragraph parameters are now cleared by a -subroutine called normal_paragraph; hang_after is also set to 1. -The essential change being made now is to call normal_paragraph in modules -704, 932, 1009, and 1076. - -69. \pagetotal and \pagegoal are added (12/27/82) -The changes are analogous to, but simpler than, those for \prevgraf. - -70. Tracing of page-optimization calculations (12/27/82) -A bunch of print commands are added to modules 897, 914, and 918, -activated if tracing_pages>0. Also, \tracingparagraphs is separated -from \tracingstats. - -**** The changes above have been incorporated into version 0.91 of TeX - -71. The build_page procedure is broken in two parts (Dec 31, 1982) -by making module 919 into a procedure called fire_up. - -72. \ifeven1\else is made legal by introducing if_code (Dec 31, 1982) -This improves part of the code in change 45; if_limit has a specific -value that recovers automatically from a former syntax error. - -73. Improvement to alignments when columns don't occur (Dec 31, 1982) -Delete module 711; and where it was used in module 708, say this: - begin fin_col:=true; return; - end; -Also, in module 717, replace the statement "width(q):=0" by -"<Nullify width(q) and the tabskip glue following the current column>" -where that new module has the following code: - begin width(q):=0; r:=link(q); s:=glue_ptr(r); - if s<>zero_glue then - begin add_glue_rel(zero_glue); delete_glue_ref(s); - glue_ptr(r):=zero_glue; - end; - end - -74. Better error message in overfull alignment (Dec 31, 1982) -In module 717, don't set both height and width; set the height zero. -Then in module 719, switch width to height if necessary. (People didn't -understand the previous error messages, and I couldn't blame them.) - -*** The changes above have been incorporated into version 0.92 of TeX82 -*** (which was the last version of 1982, completed 11:59pm on December 31) -The first changes after 1982 - -75. Modules 961 and 962 should be one module. (Jan 3, 1983) -Also, the absolute constant 100 is replaced, and the test becomes - if ((page_head=page_tail)and(head=tail)and(dead_cycles=0))or - (dead_cycles>max_dead_cycles) then - -76. Surprise bug: module 1010. (Jan 3, 1983) -The case "if head<>tail" needs an else clause: else pop_nest. -Also remove the "<Scan an optional space>" in that module. - -77. Improvement to change 22 (Jan 4, 1983) -In module 996, use box_max_depth from inside the \vbox: - @!d:scaled; {maximum depth} - begin d:=box_max_depth; unsave;... vpackage(...,d); - -78. \groupbegin and \groupend changed to \begingroup and \endgroup (Jan 4, 83) - -79. \deadcycles made accessible (Jan 4, 83) - -80. New calculations for split insertions (Jan 4, 83) -In module 918, we now work with natural width, and add in the page depth too: -The line "else w:=x_over_n..." is changed to - else begin w:=page_goal-page_total-page_depth; - if count(n)<>1000 then w:=x_over_n(w,count(n))*1000; - end; -(Note that cur_page_height and cur_page_depth and page_size have been -renamed page_total, page_depth, and page_goal, in accordance with new syntax.) - -*** The changes above have been incorporated into Version 0.93 - -81. Old bug finally unearthed by PHY (Jan 6, 1983) -insert "incompleat_node:=null;" after "push_nest;" in module 1097. - -82. Extension of change 69: \pageshrink, etc. added (Jan 6, 1983) - -83. \floatingpenalty and \insertpenalties added (Jan 6, 1983) -Also, the insertion nodes now have a new format, so that the values of -\floatingpenalty, \splittopskip, and \splitmaxdepth can be stored with -each insertion; this requires the obvious changes in several places: -a) Module 136, ins_node has fields float,depth,height,ins_ptr,split_top_ptr -b) Module 184, these fields are displayed -c) Module 198, ins_node case, also delete_glue_ref(split_top_ptr(p)) -d) Module 202, ins_node case, also add_glue_ref(split_top_ptr(p)) -e) Modules 226-228, new integer parameter \floatingpenalty -f) Module 883, add parameter d to vert_break subroutine -g) Module 885, use d instead of split_max_depth -h) Module 890, argument split_max_depth to call of vert_break -i) Module 894, change width to height (better name) -j) Module 900, initialize insert_penalties here, not in 901 -k) Module 914, cost to be awful_bad if insert_penalties>=10000 -l) Module 916, add float(p) to insert_penalties if type(r)<>inserting -m) Module 916, subtract page_depth from delta -n) Module 918, subtract page_shrink from delta -o) Module 918, argument depth(p) to call of vert_break -p) Module 921, insert_penalties:=0, save split_top_skip before calling 925 -q) Module 921, restore split_top_skip before calling 924 -r) Module 928, set split_top_skip:=split_top_ptr(p) before prune_page_top -s) Module 929, after q:=p, incr(insert_penalties) -t) Module 929, before free_node, delete_glue_ref(split_top_ptr(p)) -u) Module 933, clear insert_penalties before calling 934 -v) Module 978, more local variables needed -w) Module 1010, build the newfangled ins_node - -84. Scanner goes to new_line when <return> is category 13 (Jan 7, 1983) -Insert state:=new_line in module 323 just before the reference to module 339; -and delete "state:=new_line;" from modules 328 and 330 (and their names). - -85. Distinguish between user \kern and font \kern (Jan 9, 1983) -The nontrivial parts of this are to change "type(s)<>kern_node" to -"(type(s)<>kern_node)or(subtype(s)<>normal)" in modules 809 and 810; -and to say "kern_node: if subtype(s)=explicit then goto done4" in module 812. -The \kern primitive now has "explicit" instead of "normal" in 967. - -86. "ignorespace" becomes "ignorespaces" (Jan 9, 1983) - -87. Don't omit a blank space after \def, \message, \mark, etc. (Jan 9, 1983) -<Scan an optional space> is removed from modules 431, 848, 874. -"info(r):=space_token;" and "link(r):=get_avail; r:=link(r);" removed from 1278. - -*** The above changes appear in Version 0.94. -Version 0.95 - -88. New active characters in math mode (Jan 12, 1983) -In module 1062, add a label "restart" and change lines -3 and -2 as follows: -fam(p):=(c div 256) mod 16; -if c>=var_code then - if fam(p)<8 then fam(p):=cur_fam - else begin <Convert c to an active character whose equivalent is - ready to be scanned next>; goto restart; - end; -In module 1064, the body of the procedure becomes -begin if c>='4000 then <Convert c ...> else <the former body>; end -And there's a new module: -<Convert c...>= -begin cs_ptr:=(c mod 128)+active_base; -cur_cmd:=eq_type(cs_ptr); cur_chr:=equiv(cs_ptr); x_token; back_input; -end - -89. Surprise bug: $1-$ treated the - as binary (Jan 15, 1983) -New module <Convert a final bin_noad to an ord_noad>= - if r_type=bin_noad then type(r):=ord_noad -is called in module 649 before the call of 678, and in module 651 -in the place where that code already appears. - -90. Another oversight (Jan 15, 1983) -Add "space_factor:=1000;" after "push_nest" in modules 1027, 1029 - -91. And a more embarrassing one (Jan 16, 1983) -I forgot "spotless:=false;" at the beginning of the procedure in module 80. -But while fixing this, I decided to make it more general since IBMers want -a return code at the end of the job. So there's a history variable that has -four values: spotless, warning_issued, error_message_issued, fatal_error_stop. -a) module 75: declare history, define spotless etc. -b) module 76: initialize history:=spotless -c) module 80: if history<error_mess... then history:=error_mess... -d) 80 and 90: history:=fatal_error_stop before jump_out -e) 92: if history<error_message_issued then -f) 232: if history=spotless then history:=warning_issued -g) 1243: if history=warning_issued then print_nl("(see the log...)") - -92. "This can't happen" could happen, so there's new error recovery (Jan 16, 83) -In module 933, replace the call on confusion by a call of the following module: - @ @<Recover from an unbalanced output routine@>= - begin print_nl("! Unbalanced \output routine"); - help2("Your sneaky output routine has fewer real {'s than }'s.")@/ - ("I can't handle that very well; good luck."); error; - repeat get_token; - until loc=null; - end -In module 1278, replace the call on confusion by a call of: - @ @<Recover from an unbalanced write command@>= - begin print_nl("! Unbalanced \write command"); - help2("On this page there's a \write with fewer real {'s than }'s.")@/ - ("I can't handle that very well; good luck."); error; - repeat get_token; - until cur_tok=end_write_token; - end - -93. String overflow clobbered the log file (Jan 18, 1983) -Also, "confusion" before log file open would cause problems. Also start_input -calling open_log_file calling prompt_file_name calling fatal_error! -To fix these anomalies, open_log_file no longer calls prompt_file_name, -if interaction<scrollmode; instead, it terminates after printing what went -wrong. Also, the fatal_error and overflow and confusion procedures call -the following new subroutine: -procedure normalize_selector; -begin if job_name>0 then selector:=term_and_log else selector:=term_only; -if interaction=batch_mode then decr(selector); -if job_name=0 then open_log_file; -end; - -94. \ifeof\fi loops infinitely (Jan 18, discovered by Lamport) -Change 72 converted such a \fi to <space>\fi. Now it is converted to \relax\fi. - -95. \limitswitch changed to \displaylimits et al. (Jan 18, 1983) -[Incidentally, this fixes a bug in the former positioning of \int\limitswitch] -a) module 608: subtype of Op can be normal, limits, or no_limits. -b) 620: display the subtype if not normal -c) 667: new logic decides limits before looking at the operand (and the operand - is now called the nucleus); the italic correction is removed only if - it should not be put back -d) 1069: subtype(tail):=cur_chr - -96. Minor changes to math in unusual cases (Jan 19, 1983) -a:delete "if height(y)<=0 then height(y):=default_rule_thickness" in module 658 -b:move "if thickness(q)=default..." from module 664 to module 661 -c:delete module 1081, that error message isn't worth the bother -d:in module 1062, char_num case, c:=math_code(cur_val) (if cur_val<128) -e:in module 1064, a similar change - -97. Bad spacing from change 6 is corrected (Jan 19, 1983) -underline, overline, radical, vcenter, and accent noads now revert to type -Ord instead of type Inner. -{...} produces type Ord also. -There's a new primitive \mathinner. -The new_noad function now produces an ord_noad (change its calls accordingly). -And the default is changed in module 679 to t:=ord_noad; the fraction_noad -case sets t:=inner_noad, and the (inner_noad,ord_noad) cases swap places. - -98. New \mathchoice primitive (Jan 19, 1983) -a) module 204: new command -b) 254: math_choice_group -c) 614: style node three words long, so a choice node can be converted to it -d) 614a: choice node has four subfields: display_mlist, text_mlits, etc. -e) 1081a: routines to build a choice_node like 1027-1029 build discretionaries - -99. \input moves to syntax from semantics (Jan 19, 1983) -a) 204, 206: renumber commands -b) When input is to be expanded, if name_in_progress then insert_relax -c) 459,464: name_in_pr:=true; begin_name;...end_name; name_in_pr:=false; -d) 406,461: declare name_in_progress, a global boolean initially false - -100. \chardef joins \mathchardef (Jan 19, 1983) -a) 204: math_only becomes math_given; add new command char_given -b) 205: new command char_def -c) 250,251: new primitive char_def -d) 380: char_given,math_given yield integer after \the -e) 401: char_given,math_given yield integer in context of integer -f) 936,943: char_given treated like other_char -g) 1062,1064: same, if cur_chr<128, else assume math_code(x)=x -h) 1143,1144: char_def is analogous to math_char_def - -101. \unbox becomes \unhbox,\unvbox; also add \unhcopy (Jan 19, 1983) -Module 1020 changes in the obvious way. - -102. \spacefactor, \pagetotal, etc. move to prefixed_command (Jan 20, 1983) - -103. \hrule in horizontal mode, \vrule in vertical mode: switch modes (Jan 20) - -104. \globaldefs parameter, affects prefixed_command (Jan 20, 1983) - -105. After looking at frequency counts, some optimizations made (Jan 21, 1983) -a) "fast_get_avail" and "fast_store_new_token" introduced to speed up the loops -in modules 360 and 431. -b) some procedure call overhead eliminated in begin_token_list, end_token_list, -back_input, and flush_node_list. -c) a few if tests changed from "if a and b then" to "if a then if b then". - -106. Changes for space efficiency in math constructions (Jan 22, 1983) -a) In module 1102, mlist_penalties:=(mode>0) -b) The following code is inserted before "free_node" in module 639 (rebox): - if (is_char_node(p))and(link(p)=null) then - begin f:=font(p); v:=char_width(f)(char_info(f)(character(p))); - if v<>width(b) then link(p):=new_kern(width(b)-v); - end; -c) A new module is called just before clean_box exits: -<Simplify a trivial box>= -q:=list_ptr(x); -if is_char_node(q) then - begin r:=link(q); - if r<>null then if link(r)=null then if type(r)=kern_node then - begin free_node(r,small_node_size); link(q):=null; - end; - end - -107. Oversight in rebox routine (module 639) corrected (Jan 22, 1983) -if type(b)=vlist_node then b:=hpack(b,natural); - -108. Module 217 clobbers eqtb[bad_font_ident] set in change 26q (Jan 22, 1983) -Decided to fix this by making \nullfont a primitive. -This means the procedure missing_font can be deleted, and the test for -undefined font can be removed from the inner loop. -(This reflects a rather dramatic change from TeX80, where -a missing font was a fatal "Whoa" error!) -Note: I thought I could delete module 646, but realized that it still provides -a useful error message. The dump/undump routines (cf. change 26ee) now -dump the null_font information too, as its parameters can be changed. - -109. End of program now lists all incomplete \ifs (Jan 24, 1983) - -110. Alignment preamble setup to allow \halign\lb (Jan 29, 1983) -The statement "align_state:=-1000000;" is inserted near the beginning -of module 695 (and the comment about align_state=-999999 is deleted). -The constant -999999 is changed to -1000000 in modules 700 and 701. - -111. Forgot to test is_char_node(r) (Jan 30, 1983) -in the <Simplify a trivial box> code of change 106c. -By coincidence, this was caught since somebody used font number 11 -in the second character of a list of length 2! - -112. Improved format for stats at end of run (suggested by DRF, Jan 30, 1983) -Module 1242 changes; nothing subtle. - -**** The changes above have been incorporated into version 0.95 -Version 0.96 - -113. space after one-symbol control sequences NOT to be ignored unless -the catcode of that symbol is letter or spacer. (Jan 30, 1983) -The name of module 334 changes slightly; the state is set based -on cat_code(cur_chr), shortly after label start_cs. -A new variable cat is introduced and set to cat_code(cur_chr) in modules -334 and 336. - -114. trailing spaces removed on all lines of input (Jan 30, 1983) -last_nonblank is added to input_ln routine (module 31) - -115. mmode+accent gives error but assumes math_accent (Feb 3, 1983) -This goes into math_ac procedure (module 1075); module 1035 is eliminated. - -116. \iftrue and \iffalse (Feb 5, 1983) -Simple addition of two new conditions. - -117. Bad calculation of size for \left and \right (Feb 6, 1983) -In module 680, the first assignment to delta should be - delta:=(delta1 div 500)*delimiter_factor. - -118. \delimitershortfall (new name) replaces \delimiterlimit. (Feb 12) - -119. \abovewithdelims.. to be equivalent to \above (Feb 12) -Module 1089 revised so that the delimiters are scanned before the dimension. - -120. Remove the kludgy math codes introduced in change 88 (Feb 12) -\fam becomes a normal integer parameter -and \mathcode stored with min_halfword added -and \mathcode allowed to be 32768 -and current family is substituted only when it's in range. -Also the initialization of mathcode for letters now specifies family 1. -(This implies a dozen or so obvious revisions.) - -121. Bug in module 1152: max spacefactor is 32767 (Feb 12) -also module 1013 gets a restricted range - -122. Octal output to be replaced by hexadecimal. (Feb 14) - -123. Forgot to include char_given in module 1037, re change 100 (Feb 14) - -124. vmode+valign,hmode+halign made legal transitions (Feb 17) - -125. \tracingrestores (Feb 18) -This involves a lot of new, rather tedious code that's interspersed with the -eqtb definitions (the body of a procedure called show_eqtb). - -126. New error message for hmode+hrule in -hmode. (Feb 25) -head_for_vmode now suggests \leaders in this case. [improves change 103] - -127. under/overfull boxes in alignment: Better message. (Feb 27) -par_begin_line becomes pack_begin_line, and it is set (negative) in -module 719, read in modules 590 and 601. - -128. New \xcr feature. (suggested by Lamport comments, Mar 4) -align_peek (module 702) ignores it, otherwise it acts like ordinary \cr. - -129. In stats, subtract out TeX's own string requirements (Mar 4) -(cf. change 112) -init_pool_ptr and init_str_ptr variables added in obvious way -(declared in module 39, set in module 1240, used in module 1242) - -130. \everyhbox and \everyvbox. (Mar 6) -The modifications are obvious; for example, module 1076 gets the statement - if every_vbox<>null then begin_token_list(every_vbox,every_vbox_text); -and a similar pair of statements goes into module 993. - -131. Precaution in module 1105 error recovery (March 9, 1983) -Change the first test to "if (a=null)or danger", in order to -avoid accessing math_quad when the symbol fonts aren't known to be present. - -132. Installed float and unfloat to aid portability (suggested by HWT, 3/7/83) - -133. \dispskip becomes \abovedisplayskip and \belowdisplayskip (3/9/83) -Also \dispaskip becomes \abovedisplayshortskip; \dispbskip similar. - -134. \romannumeral separated from \number (suggested by FY, March 10) -Obvious changes; print_roman_int now accepts negative input but gives -no output in such cases (the test in module 68 becomes "if n<=0 then return"). - -135. scan_keyword to ignore leading spaces (Mar 12) -In module 375, change "else begin" to -"else if (cur_cmd<>spacer)or(p<>backup_head) then begin". - -136. Update to change 112 (Mar 14) -Module 1242 now uses write and write_ln directly (saves space and time). - -137. Another change to page-break cost (suggested by Lamport, March 16) -Cf. change 83k above; the relevant lines of module 914 now read - if b<awful_bad then - if pi<=eject_penalty then c:=pi - else if b<inf_bad then c:=b+pi+insert_penalties - else c:=deplorable - else c:=b; - if insert_penalties>=10000 then c:=awful_bad; -and a similar change (but without insert_penalties) occurs in module 887. - -**** The changes above have been incorporated into version 0.96 (March 16, 1983) -Version 0.97 - -138. \everyjob (suggested by FY, March 18) -Module 936: main_control inserts every_job as its first action. - -139. Improved printout of macro definitions (March 19) -In module 278, simply treat left_brace like right_brace. -(This corresponds to the way the manual describes parameter matching.) - -140. Omit blanks as non-delimited parameters (March 19) -In module 360, replace - else store_new_token(cur_tok); -by - else @<Store the current token, but |goto continue| if it is - a blank space that would become an undelimited parameter@>; -Then define @<Store the current token...@> to be: -begin if cur_tok=space_token then - if info(r)<=end_match_token then - if info(r)>=match_token then goto continue; -store_new_token(cur_tok); -end - -141. Minor patch in module 386, catches mu_glue (March 21) -begin cur_val:=zero_glue; cur_val_level:=glue_val; -if not is_char_node(tail)and(mode<>0) then - begin if type(tail)=glue_node then - begin cur_val:=glue_ptr(tail); - if subtype(tail)=mu_glue then cur_val_level:=mu_val; - end; - end -else if (mode=vmode)and(tail=head)and(last_page_glue<>max_halfword) then - cur_val:=last_page_glue; -end - -142. Patch in module 699, \span expands only one level (March 21) -(See previous change #42.) The "get_x_token" in the code -while (cur_chr=span_code)and(cur_cmd=tab_mark) do get_x_token; -should be replaced by: - begin get_token; - if cur_cmd>max_command then - begin expand_calls; get_token; - end; - end - -143. Single # in \tokens, \message, etc. (March 22) -(The previous rule was really bad in connection with \uppercase, -or with \write when #'s had to be given four times!) -Module 437 should be prefaced with "if macro_def then". -And get_token should become get_x_token there, if xpand is true. - -144. Keyword "to" required in \read. (March 22) -This will avoid the common error of a missing space before the \cs. -Also the stream number can be out of range, for terminal input. -The stream number in a \write can be out of range too, for terminal output. -Modules 1145 and 1258 and 1280, etc., change in the obvious ways. - -145. \ifeven<countnumber> replaced by \ifodd<number> (March 26) -This makes the language more consistent. - -146. Big surprise bug relating to \if\if aabc\fi (March 26) -(related to change 45; the possibility that cur_if might not be the -correct one when the conditional is evaluated was discovered today) -The main change is to add the change_if_limit procedure, and to add -the variable save_cond_ptr and the code that now depends on it. - -147. \if and \ifcat should tolerate primitives (March 28) - -148. "absent" becomes "void", a better word (March 28) - -149. Module 990: \lastbox to clear the shift_amount (March 28) -since I don't want to figure out what it means in all cases (\vsplit, etc) - -150. print_err("...") takes the place of print_nl("! ...") (DRF, March 29) -And wake_up_terminal is introduced in module 34, and used in modules -37, 70, 341, 441, 457, 463, 1210, 1240, 1246. - -151. \halign extended to periodic preambles (April 1) -Modules 688--690: cur_loop introduced, stacked/unstacked -Module 695: cur_loop initialized -Module 700: cur_loop set up -Module 708--709: cur_loop used and advanced - -152. \leaders to align by the smallest enclosing box. (April 1) -Module 549: new local variable left_edge, initialized to cur_h -Module 557: cur_h:=left_edge+leader_wd*((cur_h-left_edge) div leader_wd) -Module 559: new local variable top_edge, initialized to cur_v-height(this_box) -Module 566: analogous to 557 - -153. hyphenation after whatsits is OK (April 1) -In module 809, skip past whatsits - -154. \par in vertical mode should build_page (April 2) -vmode+par_end moves from 952 to 1005 - -155. Clear aux to zero in module 703 (April 2) - -156. Digits will switch families (April 4) -(initialize their math codes differently in module 225) - -157. Refinement to correction 83m (April 7) -the test for not splitting should be - if ((h<=0)or(h<=delta))and(height(p)+height(r)<=dimen(n)) then - -158. (re 128) \xcr renamed to \crcr, at Lamport's request. (April 8) - -159. Better error recovery in runaway preamble (April 11) -Module 319, aligning: set align_state:=-1000000 - -160. \read to get balanced braces (April 12) -Module 440 changed to look more like 431. -Module 443 gives error message if the \read goes off end of file. -Module 319 removes \outer from forbidden control sequence that is \read. - -161. Bug found by Jim Sterken (April 14) -Module 798 can make q a char_node, so module 794 needs this patch: - if not is_char_node(q) then -to be inserted just before "if (type(q)=math_node)..." - -162. \uppercase and \lowercase to apply to all characters (April 15) -module 1196 changes; also I put active_base before single_base in eqtb - -**** The changes above have been incorporated into version 0.97 (April 16, 1983) -**** except the part of 144 about \read-1 was forgotten and put in 0.98 later -Version 0.98 - -163. change small_number to 0..65 in module 814 (found by DRF, April 17) - -164. improved error recovery in module 1166 (suggested by DRF, April 17) -after error: repeat get_token; until cur_cmd=right_brace; {flush the patterns} - -165. improved \read from terminal (suggested by Todd Allen at Yale, May 1) -I had forgotten to implement the extended stream numbers in change 144. -Also, the prompt is now omitted if n<0. - -166. \write n writes only to the log file, if n<0. (May 18) - -167. Unified syntax for parameters and registers. (May 18) -a) Command code changes: def_font moved to before prefix; - register eliminated; set_register renamed register and - moved (with adv_register...div_register) to before prefix; - min_internal and max_internal defined. -b) scan_the renamed scan_something_internal, and it acts on cur_tok. -c) scan_int, scan_dimen, scan_glue simplified accordingly; instead of - testing for cur_cmd=the or cur_cmd=register, they now test - cur_cmd versus min_internal and max_internal. -d) ins_the is removed. -e) \minusthe is removed. Consequently "the_toks" needs no parameter. - -168. new parameters \hoffset, \voffset (May 18) - -169. \everycr (suggested by Spivak, installed May 24) - -170. \countdef, \dimendef, etc. (suggested by DRF long ago, installed May 25) -Straightforward change to internal representation of assign_int and similar -commands, so that the chr part is now a pointer to the eqtb location. - -171. \advance, \multiply, \divide (suggested by FY, installed May 25) - -172. \hyphenchar (May 25) -A new command assign_font_int is introduced, and incorporated into -scan_something_internal and prefixed_command in the usual way. -The hyphen_char array entries are initialized in modules 483 and 506, -allocated in 482, used in modules 809 [is hyphenation to be suppressed?], -828 [insert the hyphen character], 946 [insert discretionary node -following hyphen], 1027 [implementation of \-]. -hyphen_char[k] is dumped and undumped in modules 1229 and 1230. - -173. \skewchar (May 25) -Loaded and fetched with the same command code as \hyphenchar. -Module 659 gets a dozen more lines of program, to compute the skew. - -174. \noexpand (May 25) -This involves: introduction of no_expand and dont_expand command codes; -frozen_dont_expand as an internal marker; small change to get_next -when that marker is sensed; change to processing of \if and \ifcat; -implementation of no_expand in the expand_calls subroutine. -I also changed the name of expand_calls to "expand". - -175. \meaning (May 25) -This adds one case to the "convert" command. -print_meaning is a new subroutine, using code that was in show_whatever. - -176. "dm" and "vu" are out, ".5\hsize" is in (May 25) -Straightforward changes to module 416. - -177. \texinfo f n becomes \fontdimen n f (May 25) - -178. \afterassignment (suggested by ARK, May 27) - -179. \chardef\xx=5\xx shouldn't say that \xx is undefined (May 27) - -180. \relax to be ignored like spaces in math mode (May 28) -and in a few other places: <Get next non-blank non-relax non-call token> -is now used in modules 379, 988, 994, 1062, 1070, 1134, 1179 -(i.e., scan_left_brace, scan_box, scan_math, scan_delimiter, prefixed_command, -do_assignments, and just after \leaders). - -181. improve \mathaccent wrt sub/superscripts (sugg by HWT, May 30) - -182. its_all_over: remove dead_cycles>max_dead_cycles (May 30) -Modules 961 and 962 are combined and simplified. - -*** The changes above were installed into version 0.98 on May 31, 1983 *** -Version 0.99 - -183. \mark and \insert and \vadjust allowed in restricted hmode (Jun 3) -also in math; this is a comparatively big change -[at present, \mark in a display causes TeX to crash with "can't happen"!] -modules 652 and 679: mark_node,ins_node,adjust_node now permitted -modules 576 and 578: t becomes a global variable adjust_tail -modules 802 and 1110: new calling sequence to get the adjustments -modules 254, 986, 993, 995, 996: adjusted_hbox_group for the new kind of hbox -modules 698--690: cur_head and cur_tail added to alignment stack -modules 703, 712, 715: adjustments gathered and appended during \halign - -184. \ht, \wd, and \dp (Jun 6) - -185. When displaying noads, use ^ and _ instead of ( and [ (Jun 6) - -186. A..F in hex constants could be otherchar as well as letter (Jun 6) - -187. Remove <scan optional space> from module 417 (Jun 7) -(it was redundant code) - -188. \mkern .5\thinmuskip and \mkern\thinmuskip should be legal (Jun 7) - -189. 2.5\space\space\dimen0 should work (Jun 7) -previously it worked after "plus" or "minus" only! - -190. <font identifier> to allow also \font for current font (Jun 7) -"if cur_cmd=def_font then f:=cur_font else" added to module 507 - -191. \gdef not to be global when \globaldefs<0 (Jun 7) -"and (global_defs>=0)" added to module 1139 - -192. \advance\spaceskip by-\spaceskip should yield zero_glue (Jun 7) -the procedure trap_zero_glue is culled from module 1147 - -193. \show should work with any token (Jun 7) - -194. \tokens to become 256 registers (Jun 8) -\toks and \toksdef added in the straightforward way -(this affects mainly eqtb, scan_something_internal, prefixed_command) - -195. allow \indent in math mode (Jun 8) -also, \valign in math mode to give missing $ error -modules 1001 and 1043 disappear; 1004 is generalized slightly. - -196. remove redundant code (Jun 8) -In module 1044, there's no need to check cur_group and call off_save. -Similarly in module 1053. - -197. new_write_whatsit shouldn't allow \openout-1, \closeout-1 (Jun 8) -(simple change to module 1258) - -198. \lastbox should give error in math mode (Jun 8) -(simple change to module 990) - -199. \leaders not followed by proper glue should be back_error (Jun 9) -[I made the change; TRIP should test this error message!] - -200. Module 702, correction to beginning of \noalign (Jun 9) -if mode=-vmode then normal_paragraph; - -201. After alphabetic constant, expand the optional space (Jun 10) - -202. Set space_factor:=1000 after rule or constructing an accent (Jun 12) -That's in modules 964 and 1036. - -203. blunder in module 783 (caught by Jim Sterken, fixed Jun 14) -disc_width:=0 needs to be set before testing if s=null -(A real bug that existed since the beginning! It showed up on page 37 - of the September 1982 TRIP manual; my hand-checking was incomplete...) - -204. Change to optional spaces after <dimen> (Jun 14) -The optional space will now be analogous to that after <number>. - -205. Fix conflict between \output and \everydisplay (Jun 14) -In change 49, I should have inserted every_display before calling build_page. - -206. Overflow errors to be consistent with statistics reporting (Jun 17) -(See change 129.) - -207. \tracing switches to be all positive vs nonpositive (Jun 17) - -*** The changes above were installed into version 0.99 on June 19, 1983 *** -Version 0.999 - -208. \catcode`\%=14 to be done by INITEX (Jun 20) - -209. \par in vmode to clear parshape etc. (Jun 21) -Module 1005, which contains vmode+par_end, now calls normal_paragraph. - -210. Improvement to change 39 (Jun 21) -Module 593, overfull_rule not appended if solely due to hbadness - -211. Alignment bug allows glue_set to be less than -1! (Jun 21) -Modules 723 and 724 need to be patched. - -212. Correction to change 134 (found by Debby Clark, Jun 22) -Module 68: n to be declared integer, not nonnegative_integer. - -213. "by" to be optional (suggested by Lamport, Jun 22) -Module 1158 disappears - -214. Module 1235, slight change in format_ident message (Jun 24) - -215. New measures needed to thwart trickery (Jun 25) -Glue set values computed by \span could have been brought into -TeX's registers via, e.g., \valign and \vsplit; so the -"kern" idea of module 722 is insufficient and should be abandoned. -Extra boxes and glue are added; this has additional virtue -of perfect accuracy in alignment of vertical rules. -The main change is to introduce a new module after 722, in which s and t -are updated for spans, and to eliminate the "equivalent kern" code from 719 -(the corresponding glue calculations are now done in the new module). - -216. leaders to affect height/width of their boxes (Jun 25) -Module 583 splits into two parts (one for hpack, one for vpack). - -217. \unskip permitted a little more often (Jun 28) -Module 1018 reports error only if last_page_glue<max_halfword. - -218. {\bf A} in math: not to make a box (Jul 1) -Module 1093 changes as follows: info(saved(0)):=fin_mlist(null) becomes -p:=fin_mlist(null); info(saved(0)):=p; if <simple case> then <simplify>. - -219. "scaled" feature added to \font input. - -220. \mathaccent still not working right? (Jul 2) -Change 181, I forgot to correct delta when box x changed. - -221. Remove confusion possible on file of length 1 (found by Lamport) -Correction suggested by DRF, July 2: introduce bypass_eoln - -222. Allow things like ^^b. (July 4) -This simplifies modules 332 and 335; also affects 48 and 49. -And (surprise) 58. - -223. \escapechar \defaulthyphenchar \defaultskewchar \endlinechar (July 4) -to make TeX less dependent on the character set -A lot of error messages are now broken up so that they use print_esc - -224. erstat added for file opening/closing (by DRF, July 7) -That's module 27. - -225. \tracingpages output to show total glue too (July 11) -Added a procedure called print_page_totals, used also by show_activities. -Broke modules 214 and 896 into two modules each. - -226. Guard against insertion into an hbox (July 11) -A new procedure ensure_vbox is called in modules 917 and 925. - -227. <tokenvar>=<tokenvar> allowed (July 11) - -228. \errhelp parameter added (July 11) - -229. get_preamble_token should look at global_defs (July 11) -Module 699 is patched. - -*** The above changes installed in preliminary version 0.999 on July 12, 1983, -but I decided later in the day to do a few more things: - -230. \string, \noexpand, \meaning to allow \outer (Todd Allen, July 12) - -231. \the to be an expandable control sequence (July 12) -Several things in the language are cleaned up: -a) \the\tenrm replaced by \fontname\tenrm [\fontname<font>] -b) when expanding edef, etc., result of \the still expanded only only level -c) expansion after \def not inhibited, since \noexpand is now present -d) \the\the disallowed. - -232. \unhbox and \unhcopy allowed in math mode if the box is void (July 12) -Module 1020 is extended to handle this case. - -233. Value of default_rule was incorrectly rounded (July 16) -Module 424: default_rule=26214 {.39999 pt} - -234. \mathaccent still not right! (July 16) -I need to make the final height the max of (height of accented letter w/o -superscript, height of unaccented letter w superscript). - -235. \newlinechar parameter (July 16) -simple change to print subroutine - -236. boxes and rules to be allowed in discretionaries (sugg by HP man, July 16) -in fact this simply requires omitting of the prohibition (in module 1031) -and a few more cases equivalent to kern_node in modules 754, 755, 784. - -237. \tracingcommands to show all expandable tokens (July 16) - -238. \char to be allowed in \hyphenation list (July 16) -Module 848 changes in the obvious way. - -239. \aftergroup (July 16) -A new save_type. - -240. Curtail running dimensions inside alignments (sugg by ARK, July 16) -Module 720. - -241. Strange pattern data could cause PASCAL error (found July 17) -Put "if hc[1]=127 then hyf[0]:=0;" at beginning of module 878. - -242. hc codes for hyphenation are one lower (July 17) -e.g., hc[...]:=lc_code(...)-1. This makes code 127 impossible to match. - -243. whatsits also allowed after hyphenatable words (July 17) -Module 812. - -244. \/ makes an explicit kern (July 17) -"subtype(tail):=explicit" in module 1023. - -*** Version 0.999 installed July 17, 1983. -But later in the day I decided to do a few more things: - -245. Lowercase letters allowed in file names (July 18) -In module 452, omit the conversion to uppercase. - -246. "No output file" becomes "No pages of output." (July 18) -Module 571. - -247. QRS on error leads to confirmation message (sugg by ARK, July 18) -Module 84. - -*** The real version 0.999 finally installed July 18. -* Version 1.0 - -(Changes made after the Version 0.999 listing of TeX82) -(Henceforth the "final" module numbers are used) - -248. Module 1215, allow space in \read n to \cs (by FY, July 25, 1983) -@x patch in get_r_token routine -begin restart: get_token; -@y -begin restart: repeat get_token; -until cur_tok<>space_token; -@z - -249. Module 498, we must stack the current if type (FY, July 27) -@x patch in conditional routine -begin @<Push the condition stack@>;@+save_cond_ptr:=cond_ptr;@/ -@y -@!this_if:small_number; {type of this conditional} -begin @<Push the condition stack@>;@+save_cond_ptr:=cond_ptr;this_if:=cur_chr;@/ -@z -Also replace cur_if by this_if in modules 501, 503, 506. The following -patches do only what is necessary to make things work: -@x - print_cmd_chr(if_test,cur_if); -@y - print_cmd_chr(if_test,this_if); -@z -@x -if cur_if=if_int_code then scan_int@+else scan_normal_dimen; -@y -if this_if=if_int_code then scan_int@+else scan_normal_dimen; -@z -@x -if cur_if=if_char_code then b:=(n=cur_chr)@+else b:=(m=cur_cmd); -@y -if this_if=if_char_code then b:=(n=cur_chr)@+else b:=(m=cur_cmd); -@z - -250. Module 507, \ifx need not put a control sequence in hash table (July 29) -@x -get_token; n:=cs_ptr; p:=cur_cmd; q:=cur_chr; -get_token; if cur_cmd<>p then b:=false -@y -get_next; n:=cs_ptr; p:=cur_cmd; q:=cur_chr; -get_next; if cur_cmd<>p then b:=false -@z - -251. Module 86, message is lost (noticed by HWT, July 31) -@x -print("..."); print_ln; return; -@y -print("..."); print_ln; update_terminal; return; -@z - -252. Don't put empty at end of \input file! (Aug 1) -[This simplifies the rules and the program, and also gets around a bug -that occurred at the end of files with \endlinechar<0.] -@x Module 362: -@ An empty line is inserted at the end of the file, if the last line -wasn't already empty, because |input_ln| sets |last:=first| when -it discovers an |eof|. -@^empty line at end of file@> - -@<Read next line of file into |buffer|, or - |goto restart| if the file has ended@>= -begin incr(line); first:=start; -if not force_eof then - begin if input_ln(cur_file,true) then {not end of file} - firm_up_the_line {this sets |limit|} - else if limit<>start then firm_up_the_line - {if |pausing|, the user can add more lines} - else force_eof:=true; -@y -@ @<Read next line of file into |buffer|, or - |goto restart| if the file has ended@>= -begin incr(line); first:=start; -if not force_eof then - begin if input_ln(cur_file,true) then {not end of file} - firm_up_the_line {this sets |limit|} - else force_eof:=true; -@z - -*** The changes above went into Version 0.9999, which was widely distributed - -253. Ridiculous blunder made in change 146 (found by FY, August 16) -@x Correction to module 497 -else loop@+begin q:=cond_ptr; - if link(q)=p then - begin type(p):=l; return; - end; - if q=null then confusion("if"); -@:this can't happen if}{\quad if@> - q:=link(q); -@y -else begin q:=cond_ptr; - loop@+ begin if q=null then confusion("if"); -@:this can't happen if}{\quad if@> - if link(q)=p then - begin type(q):=l; return; - end; - q:=link(q); - end; -@z - -254. Minor amendment to stat(s) printing (cf. change 129) (August 16) -@x in module 1334 - wlog_ln(' ',str_ptr-init_str_ptr:1,' strings out of ', - max_strings-init_str_ptr:1);@/ -@y - wlog(' ',str_ptr-init_str_ptr:1,' string'); - if str_ptr<>init_str_ptr+1 then wlog('s'); - wlog_ln(' out of ', -@z - -255. Bug in \xleader computations (found by FY, August 18) -@x in module 592 -@!lq,@!lr:integer; {quantities used in calculations for leaders} -@y -@!lq,@!lr,@!lx:integer; {quantities used in calculations for leaders} -@z -@x in module 626 - begin edge:=cur_h+rule_wd; - @<Let |cur_h| be the position of the first box, and set |leader_wd| - 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|@>; -@y - begin 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|@>; -@z -@x in module 627 - leader_wd:=leader_wd+lx; -@y -@z -@x in module 628 -cur_h:=save_h+leader_wd; -@y -cur_h:=save_h+leader_wd+lx; -@z -@x in module 635 - begin edge:=cur_v+rule_ht; - @<Let |cur_v| be the position of the first box, and set |leader_ht| - 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|@>; -@y - begin 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|@>; -@z -@x in module 636 - leader_ht:=leader_ht+lx; -@y -@z -@x in module 637 -cur_v:=save_v-height(leader_box)+leader_ht; -@y -cur_v:=save_v-height(leader_box)+leader_ht+lx; -@z -Also insert the following in modules 619 and 629: -@!lx:scaled; {extra space between leader boxes} - -256. \/ should apply to ligatures! (August 20) -@x in module 1113 -var f:internal_font_number; {the font in the |char_node|} -begin if is_char_node(tail)and(tail<>head) then - begin f:=font(tail); - tail_append(new_kern(char_italic(f)(char_info(f)(character(tail))))); -@y -label exit; -var p:pointer; {|char_node| at the tail of the current list} -@!f:internal_font_number; {the font in the |char_node|} -begin if tail<>head then - begin if is_char_node(tail) then p:=tail - else if type(tail)=ligature_node then p:=lig_char(tail) - else return; - f:=font(p); - tail_append(new_kern(char_italic(f)(char_info(f)(character(p))))); -@z -@x later in that same module -end; -@y -exit: end; -@z - -257. Another debugging hack. (August 27) -@x module 1339 -15: begin font_in_short_display:=null_font; short_display(n); - end; -@y -15: begin font_in_short_display:=null_font; short_display(n); - end; -16: panicking:=not panicking; -@z - -258. Redundant code eliminated (August 27) -Module 531 needn't set and reset name_in_progress [but it's harmless]. - -259. Bug: \input shouldn't occur during font size spec (Spivak; fixed August 27) -@x module 1258 -@ @<Scan the font size specification@>= -@y -@ @<Scan the font size specification@>= -name_in_progress:=true; {this keeps |cur_name| from being changed} -@z -@x module 1258 -else s:=-1000 -@y -else s:=-1000; -name_in_progress:=false -@z - -260. \ifhbox and \ifvbox introduced. (August 27) -@x module 487 -@d ifx_code=10 { `\.{\\ifx}' } -@d if_eof_code=11 { `\.{\\ifeof}' } -@d if_true_code=12 { `\.{\\iftrue}' } -@d if_false_code=13 { `\.{\\iffalse}' } -@d if_case_code=14 { `\.{\\ifcase}' } -@y -@d if_hbox_code=10 { `\.{\\ifhbox}' } -@d if_vbox_code=11 { `\.{\\ifvbox}' } -@d ifx_code=12 { `\.{\\ifx}' } -@d if_eof_code=13 { `\.{\\ifeof}' } -@d if_true_code=14 { `\.{\\iftrue}' } -@d if_false_code=15 { `\.{\\iffalse}' } -@d if_case_code=16 { `\.{\\ifcase}' } -@z -@x -primitive("ifx",if_test,ifx_code); -@y -primitive("ifhbox",if_test,if_hbox_code); -@!@:if_hbox_}{\.{\\ifhbox} primitive@> -primitive("ifvbox",if_test,if_vbox_code); -@!@:if_vbox_}{\.{\\ifvbox} primitive@> -primitive("ifx",if_test,ifx_code); -@z -@x module 488 - ifx_code:print_esc("ifx"); -@y - if_hbox_code:print_esc("ifhbox"); - if_vbox_code:print_esc("ifvbox"); - ifx_code:print_esc("ifx"); -@z -@x module 501 -if_void_code: @<Test if a box is void@>; -@y -if_void_code, if_hbox_code, if_vbox_code: @<Test box register status@>; -@z -@x module 505 -@ @<Test if a box is void@>= -begin scan_eight_bit_int; b:=(box(cur_val)=null); -end -@y -@ @<Test box register status@>= -begin scan_eight_bit_int; p:=box(cur_val); -if this_if=if_void_code then b:=(p=null) -else if p=null then b:=false -else if this_if=if_hbox_code then b:=(type(p)=hlist_node) -else b:=(type(p)=vlist_node); -end - -261. Serious data structure error (found by Todd Allen, August 29) -@x module 478 (an error introduced in change 231) - q:=the_toks; link(p):=link(temp_head); p:=q; -@y - q:=the_toks; - if link(temp_head)<>null then - begin link(p):=link(temp_head); p:=q; - end; -@z - -262. Minor patch for efficiency (August 29) -@x module 466 - begin store_new_token(info(r)); r:=link(r); -@y - begin fast_store_new_token(info(r)); r:=link(r); -@z - -263. Minor patch to error message (August 29) -@module 579 - print(" has "); print_int(font_params[f]); - print(" fontdimen parameters"); -@.Font x has n fontdimen...@> -@y - print(" has only "); print_int(font_params[f]); - print(" fontdimen parameters"); -@.Font x has only...@> -@z - -*** The changes above comprise version 0.99999, used only at SAIL (August 29) - -264. funny blank spaces are showable (August 30) -@x module 298 -spacer: print("blank space"); -@y -spacer: chr_cmd("blank space "); -@z - -265. \newlinechar [change 235] should affect print_char too (August 31) -@x module 58 -procedure print_char(@!c:ascii_code); {prints a single character} -begin case selector of -term_and_log: begin wterm(xchr[c]); write(log_file,xchr[c]); - incr(term_offset); incr(file_offset); - if term_offset=max_print_line then - begin wterm_cr; term_offset:=0; - end; - if file_offset=max_print_line then - begin wlog_cr; file_offset:=0; - end; - end; -log_only: begin write(log_file,xchr[c]); incr(file_offset); - if file_offset=max_print_line then print_ln; - end; -term_only: begin wterm(xchr[c]); incr(term_offset); - if term_offset=max_print_line then print_ln; - end; -no_print: do_nothing; -pseudo: if tally<trick_count then trick_buf[tally mod error_line]:=c; -new_string: begin if pool_ptr<pool_size then append_char(c); - end; {drop characters if the string space is full} -othercases write(write_file[selector],xchr[c]) -endcases;@/ -incr(tally); -end; -@y -procedure print_char(@!s:ascii_code); {prints a single character} -label exit; -begin if @<Character |s| is the current new-line character@> then - if selector<pseudo then - begin print_ln; return; - end; -case selector of -term_and_log: begin wterm(xchr[s]); wlog(xchr[s]); - incr(term_offset); incr(file_offset); - if term_offset=max_print_line then - begin wterm_cr; term_offset:=0; - end; - if file_offset=max_print_line then - begin wlog_cr; file_offset:=0; - end; - end; -log_only: begin wlog(xchr[s]); incr(file_offset); - if file_offset=max_print_line then print_ln; - end; -term_only: begin wterm(xchr[s]); incr(term_offset); - if term_offset=max_print_line then print_ln; - end; -no_print: do_nothing; -pseudo: if tally<trick_count then trick_buf[tally mod error_line]:=s; -new_string: begin if pool_ptr<pool_size then append_char(s); - end; {drop characters if the string space is full} -othercases write(write_file[selector],xchr[s]) -endcases;@/ -incr(tally); -exit:end; - -266. \lastkern,\lastpenalty,\unkern,\unpenalty (September 4) -@x module 208 -@d unskip=25 {nullify glue ( \.{\\unskip} )} -@y -@d remove_item=25 {nullify last item ( \.{\\unpenalty}, - \.{\\unkern}, \.{\\unskip} )} -@z -@x module 208 -@d last_skip=69 {most recent glue ( \.{\\lastskip} )} -@y -@d last_item=69 {most recent item ( \.{\\lastpenalty}, - \.{\\lastkern}, \.{\\lastskip} )} -@z -@x module 265 -primitive("lastskip",last_skip,0);@/ -@!@:last_skip_}{\.{\\lastskip} primitive@> -@y -@z -@x module 265 -primitive("the",the,0); -@!@:the_}{\.{\\the} primitive@> -primitive("toks",toks_register,0); -@!@:toks_}{\.{\\toks} primitive@> -primitive("unskip",unskip,0);@/ -@!@:unskip_}{\.{\\unskip} primitive@> -@y -primitive("the",the,0);@/ -@!@:the_}{\.{\\the} primitive@> -primitive("toks",toks_register,0);@/ -@!@:toks_}{\.{\\toks} primitive@> -@z -@x module 266 -last_skip: print_esc("lastskip"); -@y -@z -@x module 266 -unskip: print_esc("unskip"); -@y -@z -@x module 413 -last_skip: @<Fetch the glue in the current node, if any@>; -@y -last_item: @<Fetch an item in the current node, if appropriate@>; -@z -@x module 416 [I also changed the comment] -primitive("dp",set_box_dimen,depth_offset); -@!@:dp_}{\.{\\dp} primitive@> -@y -primitive("dp",set_box_dimen,depth_offset); -@!@:dp_}{\.{\\dp} primitive@> -primitive("lastpenalty",last_item,int_val); -@!@:last_penalty_}{\.{\\lastpenalty} primitive@> -primitive("lastkern",last_item,dimen_val); -@!@:last_kern_}{\.{\\lastkern} primitive@> -primitive("lastskip",last_item,glue_val); -@!@:last_skip_}{\.{\\lastskip} primitive@> -@z -@x module 417 -else print_esc("dp"); -@y -else print_esc("dp"); -last_item: if chr_code=int_val then print_esc("lastpenalty") -else if chr_code=dimen_val then print_esc("lastkern") -else print_esc("lastskip"); -@z -@x module 424 -@ Here is where \.{\\lastskip} is implemented. The reference count will be -updated later. -@:last_skip_}{\.{\\lastskip} primitive@> - -@<Fetch the glue in the current node, if any@>= -begin cur_val:=zero_glue; cur_val_level:=glue_val; -if not is_char_node(tail)and(mode<>0) then - begin if type(tail)=glue_node then - begin cur_val:=glue_ptr(tail); - if subtype(tail)=mu_glue then cur_val_level:=mu_val; - end; - end -else if (mode=vmode)and(tail=head)and(last_page_glue<>max_halfword) then - cur_val:=last_page_glue; -end -@y -@ Here is where \.{\\lastpenalty}, \.{\\lastkern}, and \.{\\lastskip} are -implemented. The reference count for \.{\\lastskip} will be updated later. - -@<Fetch an item in the current node...@>= -begin if cur_chr=glue_val then cur_val:=zero_glue@+else cur_val:=0; -cur_val_level:=cur_chr; -if not is_char_node(tail)and(mode<>0) then - case cur_chr of - int_val: if type(tail)=penalty_node then cur_val:=penalty(tail); - dimen_val: if type(tail)=kern_node then cur_val:=width(tail); - glue_val: if type(tail)=glue_node then - begin cur_val:=glue_ptr(tail); - if subtype(tail)=mu_glue then cur_val_level:=mu_val; - end; - end {there are no other cases} -else if (mode=vmode)and(tail=head) then - case cur_chr of - int_val: cur_val:=last_penalty; - dimen_val: cur_val:=last_kern; - glue_val: if last_glue<>max_halfword then cur_val:=last_glue; - end; {there are no other cases} -end -@z -@x module 982 [also the comment changes] -@!last_page_glue:pointer; {used to implement \.{\\lastskip}} -@y -@!last_glue:pointer; {used to implement \.{\\lastskip}} -@!last_penalty:integer; {used to implement \.{\\lastpenalty}} -@!last_kern:scaled; {used to implement \.{\\lastkern}} -@z -@x module 991 -last_page_glue:=max_halfword; -@y -last_glue:=max_halfword; last_penalty:=0; last_kern:=0; -@z -@x module 994 -@<Update the value of |last_page_glue|@>; -@y -@<Update the values of |last_glue|, |last_penalty|, and |last_kern|@>; -@z -@x module 996 -@ @<Update the value of |last_page_glue|@>= -if last_page_glue<>max_halfword then delete_glue_ref(last_page_glue); -if type(p)=glue_node then - begin last_page_glue:=glue_ptr(p); add_glue_ref(last_page_glue); - end -else last_page_glue:=max_halfword -@y -@ @<Update the values of |last_glue|...@>= -if last_glue<>max_halfword then delete_glue_ref(last_glue); -last_penalty:=0; last_kern:=0; -if type(p)=glue_node then - begin last_glue:=glue_ptr(p); add_glue_ref(last_glue); - end -else begin last_glue:=max_halfword; - if type(p)=penalty_node then last_penalty:=penalty(p) - else if type(p)=kern_node then last_kern:=width(p); - end -@z -@x module 1017 -if last_page_glue<>max_halfword then delete_glue_ref(last_page_glue); -@<Start a new current page@>; {this sets |last_page_glue:=max_halfword|} -@y -if last_glue<>max_halfword then delete_glue_ref(last_glue); -@<Start a new current page@>; {this sets |last_glue:=max_halfword|} -@z -@x module 1048 -vmode+vmove,hmode+hmove,mmode+hmove,any_mode(last_skip), -@y -vmode+vmove,hmode+hmove,mmode+hmove,any_mode(last_item), -@z -@x module 1104 -any_mode(unskip): delete_skip; -@y -any_mode(remove_item): delete_last; -@z -@x module 1105 -procedure delete_skip; -var p:pointer; {runs through the current list} -begin if (mode=vmode)and(tail=head) then - @<Apologize for inability to do \.{\\unskip} now, - unless the previous node was not glue@> -else begin if not is_char_node(tail) then if type(tail)=glue_node then -@y -procedure delete_last; -var p:pointer; {runs through the current list} -begin if (mode=vmode)and(tail=head) then - @<Apologize for inability to do the operation now, - unless \.{\\unskip} follows non-glue@> -else begin if not is_char_node(tail) then if type(tail)=cur_chr then -@z -@x module 1106 -@ @<Apologize for inability to do \.{\\unskip}...@>= -begin if last_page_glue<>max_halfword then - begin you_cant; - help2("Sorry...I'm usually unable to take things from the current")@/ - ("page. Try `I\vskip-\lastskip' instead."); error; -@y -@ @<Apologize for inability to do the operation...@>= -begin if (cur_chr<>glue_node)or(last_glue<>max_halfword) then - begin you_cant; - help2("Sorry...I'm usually unable to take things from the current")@/ - ("page. Try `I\vskip-\lastskip' instead."); - if cur_chr=kern_node then help_line[0]:= - ("page. Try `I\kern-\lastkern' instead.") - else if cur_chr<>glue_node then help_line[0]:=@| - ("page. Perhaps you can make the output routine do it."); - error; -@z -@x module 1107 -primitive("unhbox",un_hbox,box_code);@/ -@y -primitive("unpenalty",remove_item,penalty_node);@/ -@!@:un_penalty_}{\.{\\unpenalty} primitive@> -primitive("unkern",remove_item,kern_node);@/ -@!@:un_kern_}{\.{\\unkern} primitive@> -primitive("unskip",remove_item,glue_node);@/ -@!@:un_skip_}{\.{\\unskip} primitive@> -primitive("unhbox",un_hbox,box_code);@/ -@z -@x module 1108 -un_hbox: if chr_code=copy_code then print_esc("unhcopy") -@y -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") -@z - -*** The above changes installed in version 0.999999 (September 5, 1983) - -267. Undo change 29: it was overkill and not needed (Sep 17) -@x module 1257 -label exit, common_ending; -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} -begin if job_name=0 then open_log_file; - {avoid confusing \.{texput} with the font name} -@<If the next token isn't a suitable control sequence, issue a complaint - and |return|; otherwise set |u:=cs_ptr|, and set |hash_used| to the - location of a ``frozen'' copy of the new font identifier@>; -define(u,set_font,null_font); scan_optional_equals; scan_file_name; -@<Scan the font size specification@>; -@<If this font has already been loaded, set |f| to the internal - font number and |goto common_ending|@>; -f:=read_font_info(u,cur_name,cur_area,s); -common_ending: equiv(u):=f; geq_define(hash_used,set_font,f); -font_ident[f]:=hash_used; -exit:end; -@y -label common_ending; -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} -begin if job_name=0 then open_log_file; - {avoid confusing \.{texput} with the font name} -get_r_token; u:=cs_ptr; -define(u,set_font,null_font); scan_optional_equals; scan_file_name; -@<Scan the font size specification@>; -@<If this font has already been loaded, set |f| to the internal - font number and |goto common_ending|@>; -f:=read_font_info(u,cur_name,cur_area,s); -common_ending: equiv(u):=f; font_ident[f]:=u; -end; -@z -@x module 1260 -@ We reserve a special control sequence for the font identifier; this one -cannot be redefined by the user, so it is safe to return it as a value of -\.{\\the\\font}. - -@<If the next token isn't a suitable control sequence...@>= -get_r_token; -if cs_ptr<hash_base then - begin print_err("A font identifier must be a multiletter control sequence"); -@.A font identifier...@> - help2("You should say, e.g., `\font\ffn=fontfilename'.")@/ - ("(I'm going to ignore the \font command you just gave.)"); - back_error; return; - end; -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|} -u:=cs_ptr; text(hash_used):=text(u); {copy the name} -@!stat incr(cs_count);@+tats@;@/ -@y -@z -Note: Since module 1260 has disappeared, module 1258 has been split into two. - -268. Minor change to diagnostic output format (September 18) -@x module 211 [print_mode] - 2:print("displayed math"); -@y - 2:print("display math"); -@z - -269. Kerns inserted for accents must be explicit (September 20) -@x module 1123 -@!p,@!q: pointer; {character and box nodes} -@y -@!p,@!q,@!r:pointer; {character, box, and kern nodes} -@z -@x module 1125 -link(tail):=new_kern(delta); link(link(tail)):=p; -link(p):=new_kern(-a-delta); tail:=link(p); p:=q; -@y -r:=new_kern(delta); subtype(r):=explicit; link(tail):=r; link(r):=p; -tail:=new_kern(-a-delta); subtype(tail):=explicit; link(p):=tail; p:=q; -@z - -270. "log" changed to "transcript" in a few output messages (Sep 26) -@x module 535 -prompt_file_name("log file name",".log"); -@y -prompt_file_name("transcript file name",".log"); -@z -@x module 1293 - ("lists on your terminal as well as on the log file."); -@y - ("lists on your terminal as well as in the transcript file."); -@z -@x module 1335 - print_nl("(see the log file for additional information)"); -@.see the log file...@> -@y - print_nl("(see the transcript file for additional information)"); -@.see the transcript file...@> -@z - -271. Uninitialized variable bug (found by Bernd Schulze, 1 Oct 83) -@x module 944 - begin if trie_op_ptr>=max_quarterword-1 then {overflow} - begin trie_op_ptr:=max_quarterword; - new_trie_op:=min_quarterword; return; -@y we allow one more trie op (OK since trie_op_hash_size is big enough) - begin if trie_op_ptr=max_quarterword then {overflow} - begin new_trie_op:=min_quarterword; return; -@z - -272. Spaces at end of lines ignored also in TEX.POOL (by DRF, 14 Oct 83) -@x module 52 - begin if eoln(pool_file) then bad_pool('! TEX.POOL line too short.'); -@.TEX.POOL line too short@> - read(pool_file,m); append_char(xord[m]); -@y - begin if eoln(pool_file) then m:=' '@+else read(pool_file,m); - append_char(xord[m]); -@z - -273. |history| updates (by DRF, 14 Oct 83) -@x module 77 -deletions_allowed:=true; history:=spotless; error_count:=0; -@y -deletions_allowed:=true; error_count:=0; {|history| is initialized elsewhere} -@z -@x module 1332 -@p begin {@!|start_here|} -@y -@p begin {@!|start_here|} -history:=fatal_error_stop; {in case we quit during initialization} -@z -@x ibid. -main_control; {come to life} -@y -history:=spotless; {ready to go!} -main_control; {come to life} -@z - -274. improved "runaway" messages (suggested by FY, October 18) -@x module 305 (the introductory comment is changed too) -@d aligning=4 {|scanner_status| when reading an alignment preamble} - -@<Glob...@>= -@!scanner_status : normal..aligning; {can a subfile end now?} -@y -@d aligning=4 {|scanner_status| when reading an alignment preamble} -@d absorbing=5 {|scanner_status| when reading a balanced text} - -@<Glob...@>= -@!scanner_status : normal..absorbing; {can a subfile end now?} -@z -@x module 306 (string space is also now conserved slightly) - defining: begin print("definition?"); p:=def_ref; - end; - matching: begin print("argument?"); p:=temp_head; - end; - aligning: begin print("preamble?"); p:=hold_head; - end; - end; {there are no other cases} - print_ln; show_token_list(link(p),null,error_line-10); -@y - defining: begin print("definition"); p:=def_ref; - end; - matching: begin print("argument"); p:=temp_head; - end; - aligning: begin print("preamble"); p:=hold_head; - end; - absorbing: begin print("text"); p:=def_ref; - end; - end; {there are no other cases} - print_char("?");print_ln; show_token_list(link(p),null,error_line-10); -@x module 339 (I also changed the module name) -end; {there are no other cases} -@y -absorbing:begin print("text"); info(p):=right_brace_token+"}"; - end; -end; {there are no other cases} -@z -@x module 473 -begin scanner_status:=defining; warning_index:=cs_ptr; -def_ref:=get_avail; info(def_ref):=null; -@y -begin if macro_def then scanner_status:=defining -@+else scanner_status:=absorbing; -warning_index:=cs_ptr; def_ref:=get_avail; info(def_ref):=null; -@z - -275. similar, but this corrects a real bug (found by FY, October 18) -@x module 1226 - cs_ptr:=q; - @<Get the next non-blank non-relax non-call token@>; - if cur_cmd<>left_brace then @<If the righthand side is a token parameter - or token register, finish the assignment and |goto done|@>; - back_input; q:=scan_toks(false,false); -@y - @<Get the next non-blank non-relax non-call token@>; - if cur_cmd<>left_brace then @<If the righthand side is a token parameter - or token register, finish the assignment and |goto done|@>; - back_input; cs_ptr:=q; q:=scan_toks(false,false); -@z - -276. Change #119 should have changed module 1090 too (by Barry Smith, Oct 24) -@x module 1183 [which was module 1090 at the time of change 119] -begin if c mod delimited_code=above_code then scan_normal_dimen; -if c>=delimited_code then - begin scan_delimiter(garbage,false); scan_delimiter(garbage,false); - end; -@y -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; -@z - -277. Changes for efficiency, based on empirical frequency data (Nov 9) -@x module 45 [since the result is true almost always] -begin j:=str_start[s]; result:=false; -while j<str_start[s+1] do - begin if str_pool[j]<>buffer[k] then goto not_found; -@y -begin j:=str_start[s]; -while j<str_start[s+1] do - begin if str_pool[j]<>buffer[k] then - begin result:=false; goto not_found; - end; -@z -@x module 380 [many compilers don't handle "while true do" very well] -label done; -begin loop begin get_next; -@^inner loop@> - if cur_cmd<=max_command then goto done; - if cur_cmd>=call then - if cur_cmd<end_template then macro_call - else begin cs_ptr:=frozen_endv; cur_cmd:=endv; - goto done; {|cur_chr=null_list|} - end - else expand; - end; -@y -label restart,done; -begin restart: get_next; -@^inner loop@> -if cur_cmd<=max_command then goto done; -if cur_cmd>=call then - if cur_cmd<end_template then macro_call - else begin cs_ptr:=frozen_endv; cur_cmd:=endv; - goto done; {|cur_chr=null_list|} - end -else expand; -goto restart; -@z -@x module 829 [preparation for change to module 852] -label exit,done,continue,deactivate; -@y -label exit,done,done1,continue,deactivate; -@z -@x module 830 [ditto] -@!save_link:pointer; {temporarily holds value of |link(cur_p)|} -@y -@!save_link:pointer; {temporarily holds value of |link(cur_p)|} -@!shortfall:scaled; {used in badness calculations} -@z -@x modue 851 [ditto] -if cur_active_width[1]<line_width then -@y -shortfall:=line_width-cur_active_width[1]; {we're this much too short} -if shortfall>0 then -@z -@x module 852 [avoid calling |badness| in most common case] -else begin b:=badness(line_width-cur_active_width[1],cur_active_width[2]); -@y -else begin if shortfall>7230584 then if cur_active_width[2]<1663497 then - begin b:=inf_bad; fit_class:=very_loose_fit; goto done1; - end; - b:=badness(shortfall,cur_active_width[2]); -@z -@x module 852, continued - else fit_class:=decent_fit; -@y - else fit_class:=decent_fit; - done1: -@z -@x module 853 [using |shortfall|, since we now have it] -begin if cur_active_width[1]-line_width>cur_active_width[6] then - b:=inf_bad+1 -else b:=badness(cur_active_width[1]-line_width,cur_active_width[6]); -@y -begin if -shortfall>cur_active_width[6] then b:=inf_bad+1 -else b:=badness(-shortfall,cur_active_width[6]); -@z - -278. Forgotten |error| call (noticed by Gabi Kuper, December 3, 1983) -@x module 500 - help1("I'm ignoring this; it doesn't match any \if."); -@y - help1("I'm ignoring this; it doesn't match any \if."); - error; -@z - -*** Version 1.0 released on December 3, 1983 incorporates all of the above. -Version 1.1 - -279. Problem with change 267 (found by Mike Urban, received 2 Feb 84) -(I had overlooked many problems, e.g. `{\font\a=x \global\a}\the\font' -and `\font\a=x \font\b=x \let\b=\undefined \the\a', etc. -The remedy involves removal of the font_ident array, so there's a -sprinkling of corrections in lots of modules. But basically the change -is quite conservative, so it shouldn't spawn any new bugs (it says here).) - -@x module 174 (removing a reference to |font_ident|) - else sprint_cs(font_ident[font(p)]); -@y - else @<Print the font identifier for |font(p)|@>; -@z -@x module 176 (removing a reference to |font_ident|) - else sprint_cs(font_ident[font(p)]); -@y - else @<Print the font identifier for |font(p)|@>; -@z -@x module 222 (redefining and expanding the `frozen' area) -@d frozen_null_font=frozen_control_sequence+9 {permanent `\.{\\nullfont}'} -@d frozen_dont_expand=frozen_control_sequence+10 - {permanent `\.{\\notexpanded:}'} -@d undefined_control_sequence=frozen_control_sequence+11 {dummy location} -@y -@d frozen_dont_expand=frozen_control_sequence+9 - {permanent `\.{\\notexpanded:}'} -@d frozen_null_font=frozen_control_sequence+10 - {permanent `\.{\\nullfont}'} -@d font_id_base=frozen_null_font-font_base - {begins table of 257 permanent font identifiers} -@d undefined_control_sequence=frozen_null_font+257 {dummy location} -@z -@x module 234 (removing a reference to |font_ident|, awkwardly) -print_char("="); sprint_cs(font_ident[equiv(n)]); -@y -print_char("=");@/ -print_esc(hash[font_id_base+equiv(n)].rh); - {that's |text(font_id_base+equiv(n))|} -@z -@x module 256 (adding a new macro, font_id_text) -@d hash_is_full == (hash_used=hash_base) {test if all positions are occupied} -@y -@d hash_is_full == (hash_used=hash_base) {test if all positions are occupied} -@d font_id_text(#) == text(font_id_base+#) {a frozen font identifier's name} -@z -@x module 262 (relaxing a former restriction) -else if (text(p)<128)or(text(p)>=str_ptr) then print_esc("NONEXISTENT.") -@y -else if (text(p)<0)or(text(p)>=str_ptr) then print_esc("NONEXISTENT.") -@z -@x module 267 (pick up the changes from 174 and 176) -@!@^Single-character primitives@> -@y -@!@^Single-character primitives@> - -Meanwhile, this is a convenient place to catch up on something we were unable -to do before the hash table was defined: - -@<Print the font identifier for |font(p)|@>= -print_esc(font_id_text(font(p))) -@z -@x module 415 (removing another reference to font_ident) - scanned_result(font_ident[cur_val])(ident_val); -@y - scanned_result(font_id_base+cur_val)(ident_val); -@z -@x module 548 (change to the comment only) -to the user's font~\.{\\f}. For example, if this internal number is 13, -we will have |font_ident[13]=p| and |equiv(p)=13|, where |p| is the |eqtb| -location of the control sequence~\.{\\f}. -@y -to the user's font~\.{\\f}. Adding this number to |font_id_base| gives the -|eqtb| location of a ``frozen'' control sequence that will always select -the font. -@z -@x module 549 (deleting the declaration of font_ident) -@!font_ident:array[internal_font_number] of pointer; {the most recent user - font identifier corresponding to an internal font number} -@y -@z -@x module 552 (deleting an unnecessary initialization of font_ident) -font_ident[null_font]:=frozen_null_font; -@y -@z -@x module 579 (removing another reference to font_ident) - begin print_err("Font "); sprint_cs(font_ident[f]); -@y - begin print_err("Font "); print_esc(font_id_text(f)); -@z -@x module 1257 (this is the real change!) -begin if job_name=0 then open_log_file; - {avoid confusing \.{texput} with the font name} -get_r_token; u:=cs_ptr; -define(u,set_font,null_font); scan_optional_equals; scan_file_name; -@<Scan the font size specification@>; -@<If this font has already been loaded, set |f| to the internal - font number and |goto common_ending|@>; -f:=read_font_info(u,cur_name,cur_area,s); -common_ending: equiv(u):=f; font_ident[f]:=u; -@y -@!t:str_number; {name for the frozen font identifier} -@!old_setting:0..max_selector; {holds |selector| setting} -begin if job_name=0 then open_log_file; - {avoid confusing \.{texput} with the font name} -get_r_token; u:=cs_ptr; -if u>=hash_base then t:=text(u) -else if u>=single_base then - if u=null_cs then t:="FONT"@+else t:=u-single_base -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; scan_file_name; -@<Scan the font size specification@>; -@<If this font has already been loaded, set |f| to the internal - font number and |goto common_ending|@>; -f:=read_font_info(u,cur_name,cur_area,s); -common_ending: equiv(u):=f; eqtb[font_id_base+f]:=eqtb[u]; font_id_text(f):=t; -@z -@x module 1260 (change to the comment only) -the new value becomes the |font_ident| of record. Font names `\.{xyz}' and -@y -the new name becomes the font identifier of record. Font names `\.{xyz}' and -@z -@x module 1322 (no need to dump font_ident) -begin dump_int(font_ident[k]); -dump_qqqq(font_check[k]); -@y -begin dump_qqqq(font_check[k]); -@z -@x module 1322 (or to print from it) -print_nl("\font"); sprint_cs(font_ident[k]); print_char("="); -@y -print_nl("\font"); print_esc(font_id_text(k)); print_char("="); -@z -@x module 1323 (or to undump it) -begin undump(active_base)(undefined_control_sequence)(font_ident[k]); -undump_qqqq(font_check[k]);@/ -@y -begin undump_qqqq(font_check[k]);@/ -@z - -280. Double interrupt possibility (found by Clint Cuzzo, received 9 Feb 84) -@x module 1031 -if interrupt>0 then if OK_to_interrupt then - begin back_input; pause_for_instructions; goto big_switch; -@y -if interrupt<>0 then if OK_to_interrupt then - begin back_input; check_interrupt; goto big_switch; -@z - -281. Improve spacing in $(A,<)$. (12 Feb 84) -@x module 764 -"0234000122*4000133**3**344*0400400*000000234000111*4111112341011" -@y -"0234000122*4000133**3**344*0400400*000000234000111*1111112341011" -@z - -282. Bad goto! (diagnosis by Clint Cuzzo and George O'Connor, recd 13 Feb 84) -@x module 344 (here we simply change the name of module 346) -any_state_plus(invalid_char): @<Decry the invalid character and - |goto switch|@>; -@y -any_state_plus(invalid_char): @<Decry the invalid character and - |goto restart|@>; -@z -@x module 346 (because clear_for_error_prompt might make state=token_list) -goto switch; -@y -goto restart; -@z - -283. String pool economy (suggested by DRF, 13 Feb 84) -@x module 537 -@<Read the first line of the new file@>; -@y -if name=str_ptr-1 then {we can conserve string pool space now} - begin flush_string; name:=cur_name; - end; -@<Read the first line of the new file@>; -@z - -284. Nicer scaled output (suggested by METAFONT development, 26 Feb 84) -@x module 103 -be reproduced exactly. [{\sl Proof:\/} If round$(x)=\lfloor -x+{1\over2}\rfloor$ and if $\alpha<1$, it is not difficult to verify that -round$(\alpha\,\hbox{round}( \alpha^{-1}n))=n$ for all integers |n|. In -our case $\alpha=2^{16}/10^5$.] - -@p procedure print_scaled(@!s:scaled); {prints scaled real, rounded to five - digits} -begin if s<0 then - begin print_char("-"); negate(s); {print the sign, if negative} - end; -print_int(s div unity); {print the integer part} -s:=((s mod unity) * 3125 + 1024) div 2048; - {now |0<=s<100000| is the fraction part} -print_char("."); -repeat print_char("0"+(s div 10000)); s:=10*(s mod 10000); -until s=0; -end; -@y -be reproduced exactly; the ``simplest'' such decimal number is output, -but there is always at least one digit following the decimal point. - -The invariant relation in the \&{repeat} loop is that a sequence of -decimal digits yet to be printed will yield the original number if and only if -they form a fraction~$f$ in the range $s-\delta\L10\cdot2^{16}f<s$. -We can stop if and only if $f=0$ satisfies this condition; the loop will -terminate before $s$ can possibly become zero. - -@p procedure print_scaled(@!s:scaled); {prints scaled real, rounded to five - digits} -var delta:scaled; {amount of allowable inaccuracy} -begin if s<0 then - begin print_char("-"); negate(s); {print the sign, if negative} - end; -print_int(s div unity); {print the integer part} -print_char("."); -s:=10*(s mod unity)+5; delta:=10; -repeat if delta>unity then s:=s+@'100000-(delta div 2); {round the last digit} -print_char("0"+(s div unity)); s:=10*(s mod unity); delta:=delta*10; -until s<=delta; -end; -@z - -*** Those six changes account for version 1.1 (February 29, 1984). -*** And we put the following change in too, at the last minute: - -285. ".00000762939453126pt" didn't round correctly! (March 2, 1984) -@x module 452 - if k<16 then {digits for |k>=16| cannot affect the result} -@y (Note, I also changed the comment in module 102: 16 -> 17) - if k<17 then {digits for |k>=17| cannot affect the result} -@z - -*** Note: I changed "cs_ptr" to "cur_cs", since the name change is more -indicative of the fact that this variable makes a trio with cur_cmd -and cur_chr. The TEX.WEB source changed 78 times, as a result, but -none of the author's change files were affected. -(But note: "save_cs_ptr" was not changed to "save_cur_cs", because -of a name conflict.) - -*** And the following two were slipped in at the last second: - -286. loophole permitted get_next recursion (March 16, 1984) -@x module 336 - begin @<Back up an outer control sequence so that it can be reread@>; -@y - begin deletions_allowed:=false; - @<Back up an outer control sequence so that it can be reread@>; -@z -@x ibid - end; -@y - deletions_allowed:=true; - end; -@z [the changes to deletions_allowed in module 338 can now be removed] - -287. terminal not open when the program starts bad (March 24, 1984) -@x module 1332 -initialize; {set global variables to their starting values} -@<Check the ``constant'' values...@>@; -if bad>0 then - begin wake_up_terminal; - wterm('Ouch---my internal constants have been', - ' clobbered!---case ',bad:1); -@.Ouch...clobbered@> - goto final_end; - end; -@y -@<Check the ``constant'' values...@>@; -if bad>0 then - begin t_open_out; - wterm('Ouch---my internal constants have been', - ' clobbered!---case ',bad:1); -@.Ouch...clobbered@> - goto final_end; - end; -initialize; {set global variables to their starting values} -@z - -*** Note: "Cosmetic" changes were also made in module 363 ("print_ln" -moved to after "wake_up_terminal") and in some commentary. - -*** Another last-minute correction: -288. \patterns{xxx...xxxdxxxdxxx} anomaly found by JRD (Mar 27, 1984) -@x module 962 -else begin hyf[k]:=cur_chr-"0"; digit_sensed:=true; -@y -else begin hyf[k]:=cur_chr-"0"; - if k<63 then digit_sensed:=true; -@z - -*** Yoicks, yet ANOTHER: -289. a whole case of copy_node_list forgotten (Apr 11, 1984) -@x module 206 -othercases confusion("copying") -@y -adjust_node: begin r:=get_node(small_node_size); - adjust_ptr(r):=copy_node_list(adjust_ptr(p)); - end; {|words=1=small_node_size-1|} -othercases confusion("copying") -@z - -*** And "finally"... -290. uninitialized variables could be accessed (found by Nick Briggs, June 11) -@x module 552 -font_size[null_font]:=0; font_dsize[null_font]:=0; -@y -font_size[null_font]:=0; font_dsize[null_font]:=0; -char_base[null_font]:=0; width_base[null_font]:=0; -height_base[null_font]:=0; depth_base[null_font]:=0; -italic_base[null_font]:=0; lig_kern_base[null_font]:=0; -kern_base[null_font]:=0; exten_base[null_font]:=0; -@z (actual values are immaterial except for debugging safeguards) - -291. same, cf. modules 355 and 389 (Nick Briggs, June 11) -@x module 331 -scanner_status:=normal; first:=1; -@y -for first:=0 to buf_size do buffer[first]:=0; -scanner_status:=normal; warning_index:=null; first:=1; -@z (error was harmless except that it might trigger debugging checks) - -292. missing ligature/kern (found by JRD, June 21) -@x module 1036 - if (cur_cmd=letter)or(cur_cmd=other_char) then r:=qi(cur_chr) -@y - if (cur_cmd=letter)or(cur_cmd=other_char)or(cur_cmd=char_given) then - r:=qi(cur_chr) -@z - -293. quarterword constraint is made explicit (July 4) -@x module 111 -if (buf_size>max_halfword) then bad:=18; -@y -if buf_size>max_halfword then bad:=18; -if max_quarterword-min_quarterword<255 then bad:=19; -@z - -294. trivial optimization made for consistency with MF (July 7) -@x module 363 -if (pausing>0)and(interaction>nonstop_mode) then -@y -if pausing>0 then if interaction>nonstop_mode then -@z - -295. \tracingmacros>1 for more diagnostics (July 8) -@x module 323 - if t=macro then param_start:=param_ptr@+else loc:=link(p); -@y - if t=macro then param_start:=param_ptr - else begin loc:=link(p); - if tracing_macros>1 then - begin begin_diagnostic; print_nl(""); - case t of - mark_text:print_esc("mark"); - write_text:print_esc("write"); - othercases print_cmd_chr(assign_toks,t-output_text+output_routine_loc) - endcases;@/ - print("->"); token_show(p); end_diagnostic(false); - end; - end; -@z - -*** The changes above were incorporated in Version 1.1, released July 9, 1984. -Version 1.2 - -296. "see the transcript file" on offline show commands. (July 27, 1984) -@x module 1293 -@ @d show_error==@;@/ - if interaction<error_stop_mode then - begin help0; decr(error_count); - end - else if tracing_online>0 then - begin@t@>@;@/ - help3("This isn't an error message; I'm just \showing something.") - @t\4\4@>@/ - ("Type `I\show...' to show more (e.g., \show\cs,")@/ - ("\showthe\count10, \showbox255, \showlists)."); - end - else begin@t@>@;@/ - help5("This isn't an error message; I'm just \showing something.") - @t\4\4@>@/ - ("Type `I\show...' to show more (e.g., \show\cs,")@/ - ("\showthe\count10, \showbox255, \showlists).")@/ - ("And type `I\tracingonline=1\show...' to show boxes and")@/ - ("lists on your terminal as well as in the transcript file."); - end; - error - -@<Declare act...@>= -procedure show_whatever; -var p:pointer; {tail of a token list to show} -begin case cur_chr of -show_code: @<Show the current meaning of a token@>; -show_box_code: @<Show the current contents of a box@>; -show_the_code: @<Show the current value of some parameter or register@>; -othercases @<Show the current semantic nest@> -endcases; -end; -@y -@ @<Declare act...@>= -procedure show_whatever; -label common_ending; -var p:pointer; {tail of a token list to show} -begin case cur_chr of -show_lists: begin begin_diagnostic; show_activities; - end; -show_box_code: @<Show the current contents of a box@>; -show_code: @<Show the current meaning of a token, then |goto common_ending|@>; -othercases @<Show the current value of some parameter or register, - then |goto common_ending|@> -endcases;@/ -@<Complete a potentially long \.{\\show} command@>; -common_ending: if interaction<error_stop_mode then - begin help0; decr(error_count); - end -else if tracing_online>0 then - begin@t@>@;@/ - help3("This isn't an error message; I'm just \showing something.")@/ - ("Type `I\show...' to show more (e.g., \show\cs,")@/ - ("\showthe\count10, \showbox255, \showlists)."); - end -else begin@t@>@;@/ - help5("This isn't an error message; I'm just \showing something.") - ("Type `I\show...' to show more (e.g., \show\cs,")@/ - ("\showthe\count10, \showbox255, \showlists).")@/ - ("And type `I\tracingonline=1\show...' to show boxes and")@/ - ("lists on your terminal as well as in the transcript file."); - end; -error; -end; -@z -@x module 1294 -@ @<Show the current meaning of a token@>= -begin get_token; print_nl("> "); -if cur_cs<>0 then - begin sprint_cs(cur_cs); print_char("="); - end; -print_meaning; show_error; -@y -@ @<Show the current meaning of a token...@>= -begin get_token; print_nl("> "); -if cur_cs<>0 then - begin sprint_cs(cur_cs); print_char("="); - end; -print_meaning; goto common_ending; -@z -@x module 1296 -end_diagnostic(true); -print_err("OK"); -@.OK@> -show_error; -@y -@z -@x module 1297 -flush_list(link(temp_head)); show_error; -@y -flush_list(link(temp_head)); goto common_ending; -@z -@x module 1298 -@ @<Show the current semantic nest@>= -begin begin_diagnostic; show_activities; end_diagnostic(true); -print_err("OK"); -show_error; -@.OK@> -end -@y -@ @<Complete a potentially long \.{\\show} command@>= -end_diagnostic(true); print_err("OK"); -@.OK@> -if selector=term_and_log then if tracing_online<=0 then - begin selector:=term_only; print(" (see the transcript file)"); - selector:=term_and_log; - end -@z - -297. allow `0' in response to error prompts (October 20, 1984) -@x module 84 -"1","2","3","4","5","6","7","8","9": if deletions_allowed then -@y -"0","1","2","3","4","5","6","7","8","9": if deletions_allowed then -@z -Versions 1.3 and 1.4 - -298. Dirty PASCAL (two quarterword 0's were read as a halfword) (25 Nov 84) -@x module 846 -print(" -> @@@@"); print_int(serial(prev_break(passive))); -@y -print(" -> @@@@"); -if prev_break(passive)=null then print_char("0") -else print_int(serial(prev_break(passive))); -@z - -299. Ditto! (25 Nov 84) -@x module 934 -label reswitch, exit, found, not_found; -@y -label reswitch, exit, found, not_found, done; -@z -@x module 939 -while info(p)>n-3 do {eliminate hyphens \TeX\ doesn't like} - begin q:=link(p); free_avail(p); p:=q; - end; -@<Insert the \(p)pair |(s,p)| into the exception table@>; -@y -loop@+ begin if p=null then goto done; - if info(p)<n-2 then goto done; - q:=link(p); free_avail(p); p:=q; {eliminate hyphens that \TeX\ doesn't like} - end; -done: @<Insert the \(p)pair |(s,p)| into the exception table@>; -@z - -300. Major change to memory management (25 Nov 84) -[The following changes have two main merits: (1) TeX should run faster on -virtual-memory systems when the jobs are small; (2) it should be possible -to use the same production version of TeX both for jobs with lots of macros -and few boxes as well as for jobs with lots of boxes and few macros, because -the boundary line between the two types of storage is now chosen dynamically.] -[The user is unaffected, except that there's only one "memory size" overflow -error now instead of two.] -[The TRIP test is now changed slightly: The correct settings of memory -size parameters are now mem_min=mem_bot=1, mem_top=mem_max=3000.] - -@x module 11 -@!mem_max=30000; {greatest index in \TeX's internal |mem| array; - must be strictly less than |max_halfword|} -@y -@!mem_max=30000; {greatest index in \TeX's internal |mem| array; - must be strictly less than |max_halfword|; - must be equal to |mem_top| in \.{INITEX}, otherwise |>=mem_top|} -@!mem_min=0; {smallest index in \TeX's internal |mem| array; - must be |min_halfword| or more; - must be equal to |mem_bot| in \.{INITEX}, otherwise |<=mem_bot|} -@z -@x module 12 -@d mem_base=0 {smallest index in the |mem| array; must not be less - than |min_halfword|} -@d hi_mem_base=13000 {smallest index in the single-word area of |mem|; - must be substantially larger than |mem_base| and smaller than |mem_max|} -@y -@d mem_bot=0 {smallest index in the |mem| array dumped by \.{INITEX}; - must not be less than |mem_min|} -@d mem_top==30000 {largest index in the |mem| array dumped by \.{INITEX}; - must be substantially larger than |mem_bot| - and not greater than |mem_max|} -@z -@x module 12 - about |(mem_max-hi_mem_base)/6|, but 2100 is already quite generous} -@y - about |(mem_max-mem_min)/10|, but 2100 is already quite generous} -@z -@x module 14 -if (hi_mem_base<mem_base+100)or(hi_mem_base+100>mem_max) then bad:=4; -@y -if mem_bot+1100>mem_top then bad:=4; -@z -@x module 111 -if (min_quarterword>0)or(max_quarterword<127) then bad:=11; -@y -init if (mem_min<>mem_bot)or(mem_max<>mem_top) then bad:=10;@+tini@;@/ -if (mem_min>mem_bot)or(mem_max<mem_top) then bad:=10; -if (min_quarterword>0)or(max_quarterword<127) then bad:=11; -@z -@x module 111 -if (mem_base<min_halfword)or(mem_max>=max_halfword) then bad:=14; -@y -if (mem_min<min_halfword)or(mem_max>=max_halfword) then bad:=14; -@z -@x module 115 -value represents a null pointer. - -@d pointer==halfword {a flag or a location in |mem| or |eqtb|} -@d null==mem_base {the null pointer} -@y -value represents a null pointer. \TeX\ does not assume that |mem[null]| exists. - -@d pointer==halfword {a flag or a location in |mem| or |eqtb|} -@d null==min_halfword {the null pointer} -@z -@x module 116 -@ The |mem| array is divided once and for all into two regions that are -allocated separately. Locations less than |hi_mem_base| are used for storing -@y -@ The |mem| array is divided into two regions that are allocated separately, -but the dividing line between these two regions is not fixed; they grow -together until finding their ``natural'' size in a particular job. -Locations less than or equal to |lo_mem_max| are used for storing -@z -@x module 116 -relevant size when a node is freed. The remaining region of |mem| is -allocated in single words using a conventional \.{AVAIL} stack. - -Incidentally, it would be feasible to construct implementations of \TeX\ that -are based on 16-bit words instead of 32-bit words, for machines having -comparatively small memories. In such cases it might be desirable to have -two parallel arrays for the upper part of memory, called say \\{mem\_link}|[p]| -and \\{mem\_info}|[p]|, -since the single-word region in the present implementation -consists entirely of |memory_word| items of type |two_halves|. -@^small computers@> -@y -relevant size when a node is freed. Locations greater than or equal to -|hi_mem_min| are used for storing one-word records; a conventional -\.{AVAIL} stack is used for allocation in this region. - -Locations of |mem| between |mem_bot| and |mem_top| may be dumped as part -of preloaded format files, by the \.{INITEX} preprocessor. -@.INITEX@> -Production versions of \TeX\ may extend the memory at both ends in order to -provide more space; locations between |mem_min| and |mem_bot| are always -used for variable-size nodes, and locations between |mem_top| and |mem_max| -are always used for single-word nodes. - -The key pointers that govern |mem| allocation have a prescribed order: -$$\hbox{|null<=mem_min<=mem_bot<lo_mem_max< - hi_mem_min<mem_top<=mem_end<=mem_max|.}$$ -@z -@x module 116 -@!mem : array[mem_base..mem_max] of memory_word; {the big dynamic storage area} -@y -@!mem : array[mem_min..mem_max] of memory_word; {the big dynamic storage area} -@!lo_mem_max : pointer; {the largest location of variable-size memory in use} -@!hi_mem_min : pointer; {the smallest location of one-word memory in use} -@z -@x module 117 -@!max_var_used : integer; {how much memory was in use} -@y -@z -@x module 118 -occur between |hi_mem_base| and |mem_end|, inclusive, are of type -@y -occur between |hi_mem_min| and |mem_end|, inclusive, are of type -@z -@x module 120 -else begin runaway; {if memory is exhausted, display possible runaway text} - overflow("macro memory size",mem_max+1-hi_mem_base); - {quit; all one-word nodes are busy} -@:TeX capacity exceeded macro memory size}{\quad macro memory size@> - end; -@y -else begin decr(hi_mem_min); p:=hi_mem_min; - if hi_mem_min<=lo_mem_max then - begin runaway; {if memory is exhausted, display possible runaway text} - overflow("main memory size",mem_max+1-mem_min); - {quit; all one-word nodes are busy} -@:TeX capacity exceeded main memory size}{\quad main memory size@> - end; - end; -@z -@x module 125 -label found,exit; -@y -label found,exit,restart; -@z -@x module 125 -begin p:=rover; {start at some free node in the ring} -@y -begin restart: p:=rover; {start at some free node in the ring} -@z -@x module 125 -overflow("box memory size",hi_mem_base-mem_base); - {sorry, nothing satisfactory is left} -@:TeX capacity exceeded box memory size}{\quad box memory size@> -found: link(r):=null; {this node is now nonempty} -@!stat var_used:=var_used+s; {maintain usage statistics} -if var_used>max_var_used then max_var_used:=var_used; -@y -if lo_mem_max+2<hi_mem_min then - @<Grow more variable-size memory and |goto restart|@>; -overflow("main memory size",mem_max+1-mem_min); - {sorry, nothing satisfactory is left} -@:TeX capacity exceeded main memory size}{\quad main memory size@> -found: link(r):=null; {this node is now nonempty} -@!stat var_used:=var_used+s; {maintain usage statistics} -@z -@x modules 126--127 -@ Empirical tests show that the routine in this section performs a -|remove_node| operation about 0.75 times per allocation, on the average, -after which it finds that |r>p+1| about 95\% of the time. - -@<Try to allocate...@>= -q:=p+node_size(p); {find the physical successor} -@^inner loop@> -while is_empty(q) do @<Merge node |p| with node |q|@>; -r:=q-s; -if r>p+1 then @<Allocate from the top of node |p| and |goto found|@>; -if r=p then if ((rlink(p)<>rover) or (llink(p)<>rover)) then - @<Allocate entire node |p| and |goto found|@>; -node_size(p):=q-p {reset the size in case it grew} - -@ @<Merge node |p| with node |q|@>= -begin t:=rlink(q); -@^inner loop@> -if q=rover then rover:=t; -llink(t):=llink(q); rlink(llink(q)):=t;@/ -q:=q+node_size(q); -end -@y -@ The lower part of |mem| grows by 1000 words at a time, unless -we are very close to going under. When it grows, we simply link -a new node into the available-space list. This method of controlled -growth helps to keep the |mem| usage consecutive when \TeX\ is -implemented on ``virtual memory'' systems. -@^virtual memory@> - -@<Grow more variable-size memory and |goto restart|@>= -begin if lo_mem_max+1000<hi_mem_min then t:=lo_mem_max+1000 -else t:=(lo_mem_max+hi_mem_min+2) div 2; {|lo_mem_max+2<=t<hi_mem_min|} -p:=llink(rover); q:=lo_mem_max; rlink(p):=q; llink(rover):=q;@/ -rlink(q):=rover; llink(q):=p; link(q):=empty_flag; node_size(q):=t-lo_mem_max;@/ -lo_mem_max:=t; link(lo_mem_max):=null; info(lo_mem_max):=null; -rover:=q; goto restart; -end - -@ Empirical tests show that the routine in this section performs a -node-merging operation about 0.75 times per allocation, on the average, -after which it finds that |r>p+1| about 95\% of the time. - -@<Try to allocate...@>= -q:=p+node_size(p); {find the physical successor} -@^inner loop@> -while is_empty(q) do {merge node |p| with node |q|} - begin t:=rlink(q); - if q=rover then rover:=t; - llink(t):=llink(q); rlink(llink(q)):=t;@/ - q:=q+node_size(q); - end; -r:=q-s; -if r>p+1 then @<Allocate from the top of node |p| and |goto found|@>; -if r=p then if ((rlink(p)<>rover) or (llink(p)<>rover)) then - @<Allocate entire node |p| and |goto found|@>; -node_size(p):=q-p {reset the size in case it grew} -@z -% module 129 no longer refers to remove_node; I don't recall when it changed! -@x module 134 -@d is_char_node(#) == (#>hi_mem_base) -@y -@d is_char_node(#) == (#>=hi_mem_min) -@z -@x module 162 -example, locations |mem_base| to |mem_base+3| are always used to store the -specification 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. Dynamic allocation of variable-size -nodes is restricted to locations |first_mem| through |(hi_mem_base-1)|, -and single-word nodes are dynamically allocated in locations |second_mem| -through |mem_max|, inclusive. It is harmless to let |lig_trick|, |garbage|, -and |backup_head| share the same location of |mem|. - -@d zero_glue==mem_base {specification for \.{0pt plus 0pt minus 0pt}} -@y -example, locations |mem_bot| to |mem_bot+3| are always used to store the -specification 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. Static variable-size nodes appear -in locations |mem_bot| through |lo_mem_stat_max|, and static single-word nodes -appear in locations |hi_mem_stat_min| through |mem_top|, inclusive. It is -harmless to let |lig_trick|, |garbage|, and |backup_head| share the same -location of |mem|. - -@d zero_glue==mem_bot {specification for \.{0pt plus 0pt minus 0pt}} -@z -@x module 162 -@d first_mem==fil_neg_glue+glue_spec_size {first dynamically allocatable word - in the variable-size |mem|} -@# -@d page_ins_head==hi_mem_base {list of insertion data for current page} -@d contrib_head==hi_mem_base+1 {vlist of items not yet on current page} -@d page_head==hi_mem_base+2 {vlist for current page} -@d temp_head==hi_mem_base+3 {head of a temporary list of some kind} -@d hold_head==hi_mem_base+4 {head of a temporary list of another kind} -@d adjust_head==hi_mem_base+5 {head of adjustment list returned by |hpack|} -@d active==hi_mem_base+6 {head of active list in |line_break|, needs two words} -@d align_head==hi_mem_base+8 {head of preamble list for alignments} -@d end_span==hi_mem_base+9 {tail of spanned-width lists} -@d omit_template==hi_mem_base+10 {a constant token list} -@d null_list==hi_mem_base+11 {permanently empty list} -@d lig_trick==hi_mem_base+12 {a ligature masquerading as a |char_node|} -@d garbage==hi_mem_base+12 {used for scrap information} -@d backup_head==hi_mem_base+13 {head of token list built by |scan_keyword|} -@d second_mem==hi_mem_base+14 {first dynamically allocatable word in - the one-word |mem|} -@y -@d lo_mem_stat_max==fil_neg_glue+glue_spec_size-1 {largest statically - allocated word in the variable-size |mem|} -@# -@d page_ins_head==mem_top {list of insertion data for current page} -@d contrib_head==mem_top-1 {vlist of items not yet on current page} -@d page_head==mem_top-2 {vlist for current page} -@d temp_head==mem_top-3 {head of a temporary list of some kind} -@d hold_head==mem_top-4 {head of a temporary list of another kind} -@d adjust_head==mem_top-5 {head of adjustment list returned by |hpack|} -@d active==mem_top-6 {head of active list in |line_break|, needs two words} -@d align_head==mem_top-8 {head of preamble list for alignments} -@d end_span==mem_top-9 {tail of spanned-width lists} -@d omit_template==mem_top-10 {a constant token list} -@d null_list==mem_top-11 {permanently empty list} -@d lig_trick==mem_top-12 {a ligature masquerading as a |char_node|} -@d garbage==mem_top-12 {used for scrap information} -@d backup_head==mem_top-13 {head of token list built by |scan_keyword|} -@d hi_mem_stat_min==mem_top-13 {smallest statically allocated word in - the one-word |mem|} -@z -@x module 164 -for k:=mem_base+1 to first_mem-1 do mem[k].sc:=0; - {all glue dimensions are zeroed} -@^data structure assumptions@> -k:=mem_base;@+while k<first_mem do {set first words of glue specifications} -@y -for k:=mem_bot+1 to lo_mem_stat_max do mem[k].sc:=0; - {all glue dimensions are zeroed} -@^data structure assumptions@> -k:=mem_bot;@+while k<=lo_mem_stat_max do - {set first words of glue specifications} -@z -@x module 164 -rover:=first_mem; link(rover):=empty_flag; {now initialize the dynamic memory} -node_size(rover):=hi_mem_base-rover; {which is one big available node} -llink(rover):=rover; rlink(rover):=rover;@/ -link(hi_mem_base):=null; info(hi_mem_base):=null; -for k:=hi_mem_base+1 to second_mem-1 do - mem[k]:=mem[hi_mem_base];{clear list heads} -@<Initialize the special list heads and constant nodes@>; -avail:=null; mem_end:=second_mem-1; {initialize the one-word memory} -var_used:=first_mem-mem_base; dyn_used:=second_mem-hi_mem_base; -max_var_used:=var_used; {initialize statistics} -@y -rover:=lo_mem_stat_max+1; -link(rover):=empty_flag; {now initialize the dynamic memory} -node_size(rover):=1000; {which is a 1000-word available node} -llink(rover):=rover; rlink(rover):=rover;@/ -lo_mem_max:=rover+1000; link(lo_mem_max):=null; info(lo_mem_max):=null;@/ -for k:=hi_mem_stat_min to mem_top do - mem[k]:=mem[lo_mem_max]; {clear list heads} -@<Initialize the special list heads and constant nodes@>; -avail:=null; mem_end:=mem_top; -hi_mem_min:=hi_mem_stat_min; {initialize the one-word memory} -var_used:=lo_mem_stat_max+1-mem_bot; dyn_used:=mem_top+1-hi_mem_stat_min; - {initialize statistics} -@z -@x module 165 -@t\hskip1em@>@!was_mem_end: pointer; {previous |mem_end|} -@y -@t\hskip1em@>@!was_mem_end,@!was_lo_max,@!was_hi_min: pointer; - {previous |mem_end|, |lo_mem_max|,and |hi_mem_min|} -@z -@x module 166 -@!debug was_mem_end:=mem_base; {indicate that everything was previously free} -@y -@!debug was_mem_end:=mem_min; {indicate that everything was previously free} -was_lo_max:=mem_min; was_hi_min:=mem_max; -@z -@x module 167 -begin for p:=mem_base to mem_end do free[p]:=false; {you can probably - do this faster} -@y -begin for p:=mem_min to lo_mem_max do free[p]:=false; {you can probably - do this faster} -for p:=hi_mem_min to mem_end do free[p]:=false; {ditto} -@z -@x module 167 -for p:=0 to mem_end do was_free[p]:=free[p]; {|was_free:=free| might be faster} -was_mem_end:=mem_end; -@y -for p:=mem_min to lo_mem_max do was_free[p]:=free[p]; -for p:=hi_mem_min to mem_end do was_free[p]:=free[p]; - {|was_free:=free| might be faster} -was_mem_end:=mem_end; was_lo_max:=lo_mem_max; was_hi_min:=hi_mem_min; -@z -@x module 168 - begin if (p>mem_end)or(p<second_mem) then clobbered:=true -@y - begin if (p>mem_end)or(p<hi_mem_min) then clobbered:=true -@z -@x module 169 -repeat if (p>=hi_mem_base)or(p<first_mem) then clobbered:=true - else if (rlink(p)>=hi_mem_base)or(rlink(p)<first_mem) then clobbered:=true - else if not(is_empty(p))or(node_size(p)<2)or@| - (p+node_size(p)>hi_mem_base)or@| (llink(rlink(p))<>p) then clobbered:=true; -@y -repeat if (p>=lo_mem_max)or(p<mem_min) then clobbered:=true - else if (rlink(p)>=lo_mem_max)or(rlink(p)<mem_min) then clobbered:=true - else if not(is_empty(p))or(node_size(p)<2)or@| - (p+node_size(p)>lo_mem_max)or@| (llink(rlink(p))<>p) then clobbered:=true; -@z -@x module 170 -p:=mem_base; -while p<=hi_mem_base do {node |p| should not be empty} -@y -p:=mem_min; -while p<=lo_mem_max do {node |p| should not be empty} -@z -@x module 170 - while (p<=hi_mem_base) and not free[p] do incr(p); - while (p<=hi_mem_base) and free[p] do incr(p); -@y - while (p<=lo_mem_max) and not free[p] do incr(p); - while (p<=lo_mem_max) and free[p] do incr(p); -@z -@x module 171 -for p:=mem_base to mem_end do - if not free[p] and ((p>was_mem_end) or was_free[p]) then -@y -for p:=mem_min to lo_mem_max do - if not free[p] and ((p>was_lo_max) or was_free[p]) then - begin print_char(" "); print_int(p); - end; -for p:=hi_mem_min to mem_end do - if not free[p] and - ((p<was_hi_min) or (p>was_mem_end) or was_free[p]) then -@z -@x module 172 -begin for q:=mem_base to mem_end do -@y -begin for q:=mem_min to lo_mem_max do -@z -@x module 172 -@<Search |eqtb| for equivalents equal to |p|@>; -@y -for q:=hi_mem_min to mem_end do - begin if link(q)=p then - begin print_nl("LINK("); print_int(q); print_char(")"); - end; - if info(q)=p then - begin print_nl("INFO("); print_int(q); print_char(")"); - end; - end; -@<Search |eqtb| for equivalents equal to |p|@>; -@z -@x module 176 -if (p<hi_mem_base)or(p>mem_end) then print_esc("CLOBBERED.") -@y -if (p<hi_mem_min)or(p>mem_end) then print_esc("CLOBBERED.") -@z -@x module 178 -begin if (p<mem_base)or(p>=hi_mem_base) then print_char("*") -@y -begin if (p<mem_min)or(p>=lo_mem_max) then print_char("*") -@z -@x module 293 -if (p<hi_mem_base) or (p>mem_end) then -@y -if (p<hi_mem_min) or (p>mem_end) then -@z -@x module 639 - print_int(dyn_used); print("; max so far: "); - print_int(max_var_used); print_char("&"); - print_int(mem_end+1-hi_mem_base); print_ln; -@y - print_int(dyn_used); print("; still untouched: "); - print_int(hi_mem_min-lo_mem_max-1); print_ln; -@z -@x module 857 -begin save_link:=link(cur_p); {this is OK even if |cur_p=null|} -link(cur_p):=null; print_nl(""); short_display(link(printed_node)); -link(cur_p):=save_link; printed_node:=cur_p; -@y -begin print_nl(""); -if cur_p=null then short_display(link(printed_node)) -else begin save_link:=link(cur_p); - link(cur_p):=null; print_nl(""); short_display(link(printed_node)); - link(cur_p):=save_link; - end; -printed_node:=cur_p; -@z -@x module 1249 -if 2*max_halfword<hi_mem_base-mem_base then bad:=41; -@y -if 2*max_halfword<mem_top-mem_min then bad:=41; -@z -@x module 1307 -dump_int(hi_mem_base);@/ -@y -dump_int(mem_bot);@/ -dump_int(mem_top);@/ -@z -@x module 1308 -if x<>hi_mem_base then goto bad_fmt; -@y -if x<>mem_bot then goto bad_fmt; -undump_int(x); -if x<>mem_top then goto bad_fmt; -@z -@x module 1311 -dump_int(rover); -p:=mem_base; q:=rover; x:=0; -@y -dump_int(lo_mem_max); dump_int(rover); -p:=mem_bot; q:=rover; x:=0; -@z -@x module 1311 -var_used:=var_used+hi_mem_base-p; dyn_used:=mem_end+1-hi_mem_base;@/ -dump_int(mem_end); dump_int(avail); -for k:=p to mem_end do dump_wd(mem[k]); -x:=x+mem_end+1-p; -@y -var_used:=var_used+lo_mem_max-p; dyn_used:=mem_end+1-hi_mem_min;@/ -for k:=p to lo_mem_max do dump_wd(mem[k]); -x:=x+lo_mem_max+1-p; -dump_int(hi_mem_min); dump_int(avail); -for k:=hi_mem_min to mem_end do dump_wd(mem[k]); -x:=x+mem_end+1-hi_mem_min; -@z -@x module 1312 -undump(min_halfword)(hi_mem_base)(rover); -p:=mem_base; q:=rover; x:=0; -repeat for k:=p to q+1 do undump_wd(mem[k]); -p:=q+node_size(q); -if (p>hi_mem_base)or((q>=rlink(q))and(rlink(q)<>rover)) then goto bad_fmt; -q:=rlink(q); -until q=rover; -undump_size(hi_mem_base)(mem_max)('mem max')(mem_end); -undump(null)(mem_end)(avail); -for k:=p to mem_end do undump_wd(mem[k]); -undump_int(var_used); undump_int(dyn_used); -max_var_used:=var_used -@y -undump(lo_mem_stat_max+1000)(hi_mem_stat_min-1)(lo_mem_max); -undump(lo_mem_stat_max+1)(lo_mem_max)(rover); -p:=mem_bot; q:=rover; x:=0; -repeat for k:=p to q+1 do undump_wd(mem[k]); -p:=q+node_size(q); -if (p>lo_mem_max)or((q>=rlink(q))and(rlink(q)<>rover)) then goto bad_fmt; -q:=rlink(q); -until q=rover; -for k:=p to lo_mem_max do undump_wd(mem[k]); -if mem_min<mem_bot-2 then {make more low memory available} - begin p:=llink(rover); q:=mem_min+1; - link(mem_min):=null; info(mem_min):=null; {we don't use the bottom word} - rlink(p):=q; llink(rover):=q;@/ - rlink(q):=rover; llink(q):=p; link(q):=empty_flag; - node_size(q):=mem_bot-q; - end; -undump(lo_mem_max+1)(hi_mem_stat_min)(hi_mem_min); -undump(null)(mem_top)(avail); mem_end:=mem_top; -for k:=hi_mem_min to mem_end do undump_wd(mem[k]); -undump_int(var_used); undump_int(dyn_used) -@z -@x module 1323 -undump(min_halfword)(hi_mem_base)(font_glue[k]); -@y -undump(min_halfword)(lo_mem_max)(font_glue[k]); -@z -@x module 1334 - wlog_ln(' ',max_var_used:1,'&',mem_end+1-hi_mem_base:1,@| - ' words of memory out of ', - hi_mem_base-mem_base:1,'&',mem_max+1-hi_mem_base:1);@/ -@y - wlog_ln(' ',lo_mem_max-mem_min+mem_end-hi_mem_min+2:1,@| - ' words of memory out of ',mem_end+1-mem_min:1);@/ -@z that's the end of change number 300! - -301. node_size field could overflow if low mem was too large (Dec 20, 1984) -[This bug existed from the beginning, if hi_mem_base-first_mem>max_halfword!] -@x module 111 -if (mem_min<min_halfword)or(mem_max>=max_halfword) then bad:=14; -@y -if (mem_min<min_halfword)or(mem_max>=max_halfword)or@| - (mem_bot-mem_min>max_halfword+1) then bad:=14; -@z -@x module 125 -@!t:pointer; {temporary register} -@y -@!t:integer; {temporary register} -@z -@x module 125 -if lo_mem_max+2<hi_mem_min then -@y -if lo_mem_max+2<hi_mem_min then if lo_mem_max+2<=mem_bot+max_halfword then -@z -@x module 126 -rlink(q):=rover; llink(q):=p; link(q):=empty_flag; node_size(q):=t-lo_mem_max;@/ -@y -if t>mem_bot+max_halfword then t:=mem_bot+max_halfword; -rlink(q):=rover; llink(q):=p; link(q):=empty_flag; node_size(q):=t-lo_mem_max;@/ -@z - -302. Improvement to missing-format-file error (DRF, 5 Jan 85) -@x module 524 -var j:0..buf_size; {the first space after the file name} -begin if buffer[loc]="&" then - begin incr(loc); j:=loc; buffer[last]:=" "; - while buffer[j]<>" " do incr(j); - pack_buffered_name(0,loc,j-1); {try first without the system file area} - if w_open_in(fmt_file) then - begin loc:=j; goto found; - end;@/ - pack_buffered_name(format_area_length,loc,j-1); - {now try the system format file area} - if w_open_in(fmt_file) then - begin loc:=j; goto found; - end; - wake_up_terminal; - wterm_ln('Sorry, I can''t find that format;',' will try PLAIN.'); -@.Sorry, I can't find...@> - end; - {now pull out all the stops: try for the system \.{PLAIN} file} -pack_buffered_name(format_default_length-format_ext_length,1,0); -if not w_open_in(fmt_file) then - begin wake_up_terminal; - wterm_ln('I can''t find the PLAIN format file!'); -@.I can't find PLAIN...@> -@.PLAIN@> - open_fmt_file:=false; return; - end; -found:open_fmt_file:=true; -@y -var j:0..buf_size; {the first space after the format file name} -begin j:=loc; -if buffer[loc]="&" then - begin incr(loc); j:=loc; buffer[last]:=" "; - while buffer[j]<>" " do incr(j); - pack_buffered_name(0,loc,j-1); {try first without the system file area} - if w_open_in(fmt_file) then goto found; - pack_buffered_name(format_area_length,loc,j-1); - {now try the system format file area} - if w_open_in(fmt_file) then goto found; - wake_up_terminal; - wterm_ln('Sorry, I can''t find that format;',' will try PLAIN.'); -@.Sorry, I can't find...@> - update_terminal; - end; - {now pull out all the stops: try for the system \.{PLAIN} file} -pack_buffered_name(format_default_length-format_ext_length,1,0); -if not w_open_in(fmt_file) then - begin wake_up_terminal; - wterm_ln('I can''t find the PLAIN format file!'); -@.I can't find PLAIN...@> -@.PLAIN@> - open_fmt_file:=false; return; - end; -found:loc:=j; open_fmt_file:=true; -@z - -303. Welcoming message appears sooner (DRF, Jan 7) -@x module 61 -else begin print(format_ident); print_ln; - end; -@y -else begin print(format_ident); print_ln; - end; -update_terminal; -@z - -304. Minor change to help message in "confusion" (Jan 23) -@x module 95 - help2("One of your earlier faux pas has wounded me deeply,")@/ - ("so I'm barely conscious. Please fix it and try again."); -@y - help2("One of your faux pas seems to have wounded me deeply...")@/ - ("in fact, I'm barely conscious. Please fix it and try again."); -@z - -305. Improved logic for `(see the transcript file...)' (Jan 23) -@x module 245 -if history=spotless then history:=warning_issued; -if (tracing_online<=0)and(selector=term_and_log) then decr(selector); -@y -if (tracing_online<=0)and(selector=term_and_log) then - begin decr(selector); - if history=spotless then history:=warning_issued; - end; -@z - -306. Change 291 violated standard PASCAL (CET1, Feb 18) -@x module 331 -for first:=0 to buf_size do buffer[first]:=0; -@y since some procedures `threaten' |first| globally [BS/6192 sec 6.8.3.9] -first:=buf_size; repeat buffer[first]:=0; decr(first); until first=0; -@z - -307. Nonexistent character could be output via ligature hyphenation (April 11) -@x module 582 (slight inefficiency removed while correcting this) -begin if (font_bc[f]<=c)and(font_ec[f]>=c) then -@y -begin if font_bc[f]<=c then if font_ec[f]>=c then -@z -@x module 892 (likewise) -@!hu:array[1..63] of ASCII_code; {like |hc|, before conversion to lowercase} -@y -@!hu:array[1..63] of ASCII_code; {like |hc|, before conversion to lowercase} -@!hyf_char:integer; {hyphen character of the relevant font} -@z -@x module 896 (likewise) -done2: if hyphen_char[hf]<0 then goto done1; -if hyphen_char[hf]>255 then goto done1; -@y -done2: hyf_char:=hyphen_char[hf]; -if hyf_char<0 then goto done1; -if hyf_char>255 then goto done1; -@z -@x module 912 and another local variable -@!c:ASCII_code; {character temporarily replaced by a hyphen} -@y -@!c:ASCII_code; {character temporarily replaced by a hyphen} -@!hyf_node:pointer; {the hyphen, if it exists} -@z -@x module 915 (this is the real bugfix) -minor_tail:=null; c:=hu[i+1]; hu[i+1]:=hyphen_char[hf]; -repeat l:=reconstitute(l+1,i+1); -if minor_tail=null then pre_break(r):=link(hold_head) -else link(minor_tail):=link(hold_head); -minor_tail:=link(hold_head); -if link(minor_tail)<>null then minor_tail:=link(minor_tail); -until l>i; -hu[i+1]:=c; {restore the character in the hyphen position} -decr(l); hyf[l]:=0 -@y -minor_tail:=null; hyf_node:=new_character(hf,hyf_char); -if hyf_node<>null then - begin incr(i); c:=hu[i]; hu[i]:=hyf_char; - end; -repeat l:=reconstitute(l+1,i); -if minor_tail=null then pre_break(r):=link(hold_head) -else link(minor_tail):=link(hold_head); -minor_tail:=link(hold_head); -if link(minor_tail)<>null then minor_tail:=link(minor_tail); -until l=i; -if hyf_node<>null then - begin hu[i]:=c; {restore the character in the hyphen position} - free_avail(hyf_node); decr(i); l:=i; - end; -hyf[i]:=0 -@z -@x module 918 -begin r:=new_disc; pre_break(r):=new_character(hf,hyphen_char[hf]); -@y -begin r:=new_disc; pre_break(r):=new_character(hf,hyf_char); -@z - -308. Improper memory usage computed by INITEX in change 300. (DRF, April 15) -@x module 162 -@d hi_mem_stat_min==mem_top-13 {smallest statically allocated word in - the one-word |mem|} -@y -@d hi_mem_stat_min==mem_top-13 {smallest statically allocated word in - the one-word |mem|} -@d hi_mem_stat_usage=14 {the number of one-word nodes always present} -@z -@x module 164 (text macro without parentheses strikes again!) -var_used:=lo_mem_stat_max+1-mem_bot; dyn_used:=mem_top+1-hi_mem_stat_min; -@y -var_used:=lo_mem_stat_max+1-mem_bot; dyn_used:=hi_mem_stat_usage; -@z - -309. A faster |flush_list| routine for the inner loop. (DRF, April 16) -@x module 123 -var q:pointer; {the successor of node |p|} -begin while p<>null do - begin q:=link(p); free_avail(p); p:=q; - end; -@y -var @!q,@!r:pointer; {list traversers} -begin if p<>null then - begin r:=p; - repeat q:=r; r:=link(r); @!stat decr(dyn_used);@+tats@/ - until r=null; {now |q| is the last node on the list} - link(q):=avail; avail:=p; - end; -@z - -310. Kern for accent positioning could disappear after a line break (April 17) -(Change 269 fixed only part of the problem!) -@x module 155 -@d explicit=1 {|subtype| of kern nodes from \.{\\kern} and \.{\\/} and accents} -@y -@d explicit=1 {|subtype| of kern nodes from \.{\\kern} and \.{\\/}} -@d acc_kern=2 {|subtype| of kern nodes from accents} -@z -@x module 191 -if subtype(p)<=explicit then - begin print_esc("kern"); - if subtype(p)=explicit then print_char(" "); - print_scaled(width(p)); -@y -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@> -@z -@x module 837 - math_node,kern_node: break_width[1]:=break_width[1]-width(s); -@y - math_node,kern_node: if subtype(s)=acc_kern then goto done - else break_width[1]:=break_width[1]-width(s); -@z -@x module 879 - if non_discardable(q) then goto done1; -@y - if non_discardable(q) then goto done1; - if subtype(q)=acc_kern then if type(q)=kern_node then goto done1; -@z -@x module 1125 -r:=new_kern(delta); subtype(r):=explicit; link(tail):=r; link(r):=p; -tail:=new_kern(-a-delta); subtype(tail):=explicit; link(p):=tail; p:=q; -@y -r:=new_kern(delta); subtype(r):=acc_kern; link(tail):=r; link(r):=p; -tail:=new_kern(-a-delta); subtype(tail):=acc_kern; link(p):=tail; p:=q; -@z - -311. \lastbox and \unkern must not remove discretionary replacements (April 18) -(Change 236 introduced this bug!) -@x module 1079 -label exit; -var p:pointer; {runs through the current list} -@y -label exit, done; -var @!p,@!q:pointer; {run through the current list} -@!m:quarterword; {the length of a replacement list} -@z -@x modules 1080 and 1081 - @<Apologize for inability to do \.{\\lastbox} now@> -else begin if not is_char_node(tail) then - if (type(tail)=hlist_node)or(type(tail)=vlist_node) then - begin p:=head; cur_box:=tail; shift_amount(cur_box):=0; - while link(p)<>tail do p:=link(p); - tail:=p; link(p):=null; - end; - end; -end - -@ @<Apologize for inability to do \.{\\lastbox} now@>= -begin you_cant; -help2("Sorry...I'm usually unable to take things from the current")@/ - ("page. This \lastbox will therefore be void."); error; -end -@y - begin you_cant; - help2("Sorry...I usually can't take things from the current page.")@/ - ("This \lastbox will therefore be void."); error; - end -else begin if not is_char_node(tail) then - if (type(tail)=hlist_node)or(type(tail)=vlist_node) then - @<Remove the last box, unless it's part of a discretionary@>; - end; -end - -@ @<Remove the last box...@>= -begin q:=head; -repeat p:=q; -if not is_char_node(q) then if type(q)=disc_node then - begin for m:=1 to replace_count(q) do p:=link(p); - if p=tail then goto done; - end; -q:=link(p); -until q=tail; -cur_box:=tail; shift_amount(cur_box):=0; -tail:=p; link(p):=null; -done: end -@z -@x module 1105 -var p:pointer; {runs through the current list} -@y -label exit; -var @!p,@!q:pointer; {run through the current list} -@!m:quarterword; {the length of a replacement list} -@z -@x module 1105 - begin p:=head; - while link(p)<>tail do p:=link(p); - link(p):=null; flush_node_list(tail); tail:=p; - end; - end; -end; -@y - begin q:=head; - repeat p:=q; - if not is_char_node(q) then if type(q)=disc_node then - begin for m:=1 to replace_count(q) do p:=link(p); - if p=tail then return; - end; - q:=link(p); - until q=tail; - link(p):=null; flush_node_list(tail); tail:=p; - end; - end; -exit:end; -@z -@x module 1106 - help2("Sorry...I'm usually unable to take things from the current")@/ - ("page. Try `I\vskip-\lastskip' instead."); - if cur_chr=kern_node then help_line[0]:= - ("page. Try `I\kern-\lastkern' instead.") - else if cur_chr<>glue_node then help_line[0]:=@| - ("page. Perhaps you can make the output routine do it."); -@y - help2("Sorry...I usually can't take things from the current page.")@/ - ("Try `I\vskip-\lastskip' instead."); - if cur_chr=kern_node then help_line[0]:= - ("Try `I\kern-\lastkern' instead.") - else if cur_chr<>glue_node then help_line[0]:=@| - ("Perhaps you can make the output routine do it."); -@z -@x module 1120 -if n<128 then replace_count(tail):=n -@y -if n<=max_quarterword then replace_count(tail):=n -@z - - -*** Note by DEK, 18 Apr 1985 -(The code for version 1.3 has been published by Addison-Wesley under the -title "TeX: The Program". It was phototypeset on our APS, but does not -contain changes > 300. Some of those changes have been made in versions -of TeX called 1.3; but the exact definition of version 1.3 is somewhat -vague. Version 1.4 was released on April 18, 1985, after -making change 311. At present I believe Version 1.4 will be identical -to Version 2.0 except perhaps for things like index entries in the -documentation and slightly revised help messages. Version 2.0 will -coincide with the publication of Volume 1 of Computers and Typesetting, -which will come out when METAFONT and Computer Modern are both finished.) -Version 1.5 -312. if nonstandard area specified, don't try TEX_area too. (DRF, 26 Apr 85) -@x module 537 - pack_file_name(cur_name,TEX_area,cur_ext); - if a_open_in(cur_file) then goto done; -@y - if cur_area="" then - begin pack_file_name(cur_name,TEX_area,cur_ext); - if a_open_in(cur_file) then goto done; - end; -@z - -313. length of \write need no longer be limited (cf 235). (NBT, 30 Apr 85) -@x module 1370 -show_token_list(link(def_ref),null,buf_size-10); print_ln; -@y -show_token_list(link(def_ref),null,10000000); print_ln; -@z - -314. bug introduced in #300, just lucky it didn't cause trouble (CET1, 8 May 85) -@x module 162 -@d active==mem_top-6 {head of active list in |line_break|, needs two words} -@y -@d active==mem_top-7 {head of active list in |line_break|, needs two words} -@z - -315. Missing eoln after last typeout (Gropp, 11 May 85) -@x module 1332 - wterm('Ouch---my internal constants have been', -@y - wterm_ln('Ouch---my internal constants have been', -@z - -316. Redundancy (CET1, 17 May 85) -[Change 287 was apparently introduced because of a faulty assumption, -although its change to the calling of "initialize" was valid.] -@x module 1332 - begin t_open_out; - wterm_ln('Ouch---my internal constants have been', - ' clobbered!---case ',bad:1); -@y - begin wterm_ln('Ouch---my internal constants have been clobbered!', - '---case ',bad:1); -@z - -317. batchmode to see if log file couldn't be opened (DRF, 22 May 85) -@x module 92 -if interaction=batch_mode then decr(selector); -if job_name=0 then open_log_file; -@y -if job_name=0 then open_log_file; -if interaction=batch_mode then decr(selector); -@z - -318. If the string pool overflows while reading the command line... (22 May 85) -[This bug was first found in METAFONT, when it could occur more easily] -@x module 525 -begin str_room(name_length); -for k:=1 to name_length do append_char(xord[name_of_file[k]]); -make_name_string:=make_string; -@y -begin if (pool_ptr+name_length>pool_size)or(str_ptr=max_strings) then - make_name_string:="?" -else begin for k:=1 to name_length do append_char(xord[name_of_file[k]]); - make_name_string:=make_string; - end; -@z - -319. Bug in \edef\foo{\iffalse\fi\the\toks0} (found by Dan Brotsky, 7 Aug 85) -@x module 478 - if cur_cmd<>the then goto done2; - q:=the_toks; - if link(temp_head)<>null then - begin link(p):=link(temp_head); p:=q; - end; -@y - if cur_cmd<=max_command then goto done2; - if cur_cmd<>the then expand - else begin q:=the_toks; - if link(temp_head)<>null then - begin link(p):=link(temp_head); p:=q; - end; - end; -@z - -*** Version 1.5 was released on August 7, 1985. - -320. Lowercase `plain' for consistency with the manual -@x module 521 -TEX_format_default:='TeXformats:PLAIN.fmt'; -@.TeXformats@> -@.PLAIN@> -@y -TEX_format_default:='TeXformats:plain.fmt'; -@.TeXformats@> -@.plain@> -@z (index entries also changed to lowercase in modules 524, 1331) - -321. Terminal woken up by \show and \showthe (November 27, 1985) -@x module 1294 -begin get_token; print_nl("> "); -@y -begin get_token; -if interaction=error_stop_mode then wake_up_terminal; -print_nl("> "); -@z -@x module 1297 -begin p:=the_toks; print_nl("> "); token_show(temp_head); -@y -begin p:=the_toks; -if interaction=error_stop_mode then wake_up_terminal; -print_nl("> "); token_show(temp_head); -@z -Changes subsequent to `Version 2.0' as published in C&T, Volume B: - -322. Trivial change to a help message. -@x module 1283 - ("Pretend that you're Hercule Poirot, examine all clues,")@/ -@y - ("Pretend that you're Hercule Poirot: Examine all clues,")@/ -@z - -323. Precaution since |index| can be as high as |max_in_open|. (DRF) -@x module 14 -if hash_prime>hash_size then bad:=5; -@y -if hash_prime>hash_size then bad:=5; -if max_in_open>=128 then bad:=6; -@z - -324. \kern clobbered at end of pre-break list in discretionary break. -@x module 881 - |disc_break:=true|@>; - if not is_char_node(q) then - if (type(q)=math_node)or(type(q)=kern_node) then width(q):=0; -@y - |disc_break:=true|@> - else if (type(q)=math_node)or(type(q)=kern_node) then width(q):=0; -@z - -325. width after discretionary didn't take account of discarded nodes. -@x module 830 (slight redefinition) -@!t:quarterword; {replacement count, if |cur_p| is a discretionary node} -@y -@!t:integer; {node count, if |cur_p| is a discretionary node} -@z -@x module 837 (slight rearrangement) -if (break_type=unhyphenated)or(cur_p=null) then - begin s:=cur_p; - while s<>null do - begin if is_char_node(s) then goto done; - case type(s) of - glue_node:@<Subtract glue from |break_width|@>; - penalty_node: do_nothing; - math_node,kern_node: if subtype(s)=acc_kern then goto done - else break_width[1]:=break_width[1]-width(s); - othercases goto done - endcases;@/ - s:=link(s); - end; - end -else @<Compute the discretionary |break_width| values@>; -@y -s:=cur_p; -if break_type>unhyphenated then if cur_p<>null then - @<Compute the discretionary |break_width| values@>; -while s<>null do - begin if is_char_node(s) then goto done; - case type(s) of - glue_node:@<Subtract glue from |break_width|@>; - penalty_node: do_nothing; - math_node,kern_node: if subtype(s)=acc_kern then goto done - else break_width[1]:=break_width[1]-width(s); - othercases goto done - endcases;@/ - s:=link(s); - end; -@z -@x module 840 (this is the main change to fix the bug) -begin t:=replace_count(cur_p); s:=cur_p; -while t>0 do - begin decr(t); s:=link(s); - @<Subtract the width of node |s| from |break_width|@>; - end; -s:=post_break(cur_p); -while s<>null do - begin @<Add the width of node |s| to |break_width|@>; -@y -begin t:=replace_count(cur_p); v:=cur_p; s:=post_break(cur_p); -while t>0 do - begin decr(t); v:=link(v); - @<Subtract the width of node |v| from |break_width|@>; - end; -while s<>null do - begin @<Add the width of node |s| to |break_width| and increase |t|, - unless it's discardable@>; -@z -@x module 840, continued -break_width[1]:=break_width[1]+disc_width; -@y -break_width[1]:=break_width[1]+disc_width; -if t=0 then s:=link(v); {more nodes may also be discardable after the break} -@z -@x module 841 (here we just change |s| to |v|) -@<Subtract the width of node |s|...@>= -if is_char_node(s) then - begin f:=font(s); - break_width[1]:=break_width[1]-char_width(f)(char_info(f)(character(s))); - end -else case type(s) of - ligature_node: begin f:=font(lig_char(s));@/ - break_width[1]:=@|break_width[1]- - char_width(f)(char_info(f)(character(lig_char(s)))); - end; - hlist_node,vlist_node,rule_node,kern_node: - break_width[1]:=break_width[1]-width(s); -@y -@<Subtract the width of node |v|...@>= -if is_char_node(v) then - begin f:=font(v); - break_width[1]:=break_width[1]-char_width(f)(char_info(f)(character(v))); - end -else case type(v) of - ligature_node: begin f:=font(lig_char(v));@/ - break_width[1]:=@|break_width[1]- - char_width(f)(char_info(f)(character(lig_char(v)))); - end; - hlist_node,vlist_node,rule_node,kern_node: - break_width[1]:=break_width[1]-width(v); -@z -@x module 842 - hlist_node,vlist_node,rule_node,kern_node: - break_width[1]:=break_width[1]+width(s); - othercases confusion("disc2") -@:this can't happen disc2}{\quad disc2@> - endcases -@y - hlist_node,vlist_node,rule_node:break_width[1]:=break_width[1]+width(s); - kern_node: if (t=0)and(subtype(s)<>acc_kern) then t:=-1 {discardable} - else break_width[1]:=break_width[1]+width(s); - othercases confusion("disc2") -@:this can't happen disc2}{\quad disc2@> - endcases; -incr(t) -@z - -*** Version 2.1 was released on January 26, 1987. - -326. Removal of redundant code (found by Pat Monardo, 5 Feb 87) -@x module 1224 [this change need not be made, since it has no effect] - char_def_code: define(p,char_given,cur_val); - math_char_def_code: define(p,math_given,cur_val); -@y the cases cannot occur, so we simply don't list them -@z - -327. More robustness is needed when debugging (Ronaldo Am\'a, 14 Apr 87) -@x module 174 -begin while p>null do -@y maybe mem_min>null (but nodes shouldn't be put in location mem_min exactly) -begin while p>mem_min do -@z -@x module 182 -@p procedure show_node_list(@!p:pointer); {prints a node list symbolically} -@y -@p procedure show_node_list(@!p:integer); {prints a node list symbolically} -@z -@x module 182, continued -while p>null do -@y -while p>mem_min do -@z - -328. Storage allocation can be more elegant and efficient (4/21/87) -@x module 127 -if r=p then if ((rlink(p)<>rover) or (llink(p)<>rover)) then -@y -if r=p then if rlink(p)<>p then -@z - -329. Miscalculation of empty-line condition (April 22, 1987) -@x module 360 - begin if limit=start then {previous line was empty} -@y - begin if (end_line_char<0)or(end_line_char>127) then incr(limit); - if limit=start then {previous line was empty} -@z - -330. A case where we don't have to assume system bookkeeping (April 28, 1987) -@x module 560 -done: b_close(tfm_file); read_font_info:=g; -@y [suggested by Jim Sterken] -done: if file_opened then b_close(tfm_file); -read_font_info:=g; -@z [this was not a bug, according to the comment in module 28] - -331. jump_out must fix unfinished output (Found by Klaus Gunterman, 3 Aug 87) -@x module 593 -doing_leaders:=false; dead_cycles:=0; -@y -doing_leaders:=false; dead_cycles:=0; cur_s:=-1; -@z -@x module 617 -cur_s:=-1; ensure_dvi_open; -@y -ensure_dvi_open; -@z -@x module 640 -dvi_out(eop); incr(total_pages); -@y -dvi_out(eop); incr(total_pages); cur_s:=-1; -@z -@x module 642 -if total_pages=0 then print_nl("No pages of output.") -@y -while cur_s>-1 do - begin if cur_s>0 then dvi_out(pop) - else begin dvi_out(eop); incr(total_pages); - end; - decr(cur_s); - end; -if total_pages=0 then print_nl("No pages of output.") -@z - -332. \hangindent=1pt$$\halign{...\cr\noalign{\hrule}}$$ problem (19 Aug 87) -@x module 805 -q:=link(head); -@y -q:=link(head); s:=head; -@z -@x module 805, continued - q:=link(q); -@y - s:=q; q:=link(q); -@z -@x module 806 -if is_running(depth(q)) then depth(q):=depth(p); -@y -if is_running(depth(q)) then depth(q):=depth(p); -if o<>0 then - begin r:=link(q); link(q):=null; q:=hpack(q,natural); - shift_amount(q):=o; link(q):=r; link(s):=q; - end; -@z - -333. \hskip 0pt plus 1fil\ifdim problem (found by Alan Guth, 20 Aug 87) -@x module 366 -@!cvl_backup,@!radix_backup:small_number; {to save |cur_val_level| and |radix|} -@y -@!cvl_backup,@!radix_backup,@!co_backup:small_number; - {to save |cur_val_level|, etc.} -@z -@x -backup_backup:=link(backup_head); -@y -co_backup:=cur_order; backup_backup:=link(backup_head); -@z -@x -link(backup_head):=backup_backup; -@y -cur_order:=co_backup; link(backup_head):=backup_backup; -@z - -334. leaders too sensitive near exact multiples (M. F. Bridgland, 9 Nov 87) -@x module 626 - begin edge:=cur_h+rule_wd; lx:=0; -@y - begin rule_wd:=rule_wd+10; {compensate for floating-point rounding} - edge:=cur_h+rule_wd; lx:=0; -@z -@x ibid - cur_h:=edge; goto next_p; -@y - cur_h:=edge-10; goto next_p; -@z -@x module 635 - begin edge:=cur_v+rule_ht; lx:=0; -@y - begin rule_ht:=rule_ht+10; {compensate for floating-point rounding} - edge:=cur_v+rule_ht; lx:=0; -@z -@x ibid - cur_v:=edge; goto next_p; -@y - cur_v:=edge-10; goto next_p; -@z - -335. Glitch in fixed-point multiplication of negatives (W.G. Sullivan, 17Nov87) -@x module 572 -begin alpha:=16*z; beta:=16; -while z>=@'40000000 do - begin z:=z div 2; beta:=beta div 2; - end; -@y -begin alpha:=16; -while z>=@'40000000 do - begin z:=z div 2; alpha:=alpha+alpha; - end; -beta:=256 div alpha; alpha:=alpha*z; -@z - -336. If there are no \patterns and some \lccode is 1 (Breitenlohner, 12Dec87) -@x module 952 -trie_link(0):=0; trie_char(0):=0; trie_op(0):=0; -@y -trie_link(0):=0; trie_char(0):=0; trie_op(0):=min_quarterword; -@z - -337. \csname might encounter undefined_cs in a group (Chris Thompson, 23Dec87) -@x module 372 - begin eqtb[cur_cs]:=eqtb[frozen_relax]; -@y - begin eq_define(cur_cs,relax,256); -@z - -338. \outer\def\a0{}\a\a shows temp_head list garbage (Silvio Levy, 20Apr88) -@x module 391 -repeat if (info(r)>match_token+127)or(info(r)<match_token) then s:=null -else begin match_chr:=info(r)-match_token; s:=link(r); r:=s; - p:=temp_head; link(p):=null; m:=0; -@y -repeat link(temp_head):=null; -if (info(r)>match_token+127)or(info(r)<match_token) then s:=null -else begin match_chr:=info(r)-match_token; s:=link(r); r:=s; - p:=temp_head; m:=0; -@z - -339. \def\\#1{}\input a\\\z failed (Robert Messer, 24Apr88) -@x module 259 -var h:integer; {hash code} -@y -var h:integer; {hash code} -@!d:integer; {number of characters in incomplete current string} -@z -@x module 260 -str_room(l); -for k:=j to j+l-1 do append_char(buffer[k]); -text(p):=make_string; -@y -str_room(l); d:=cur_length; -while pool_ptr>str_start[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; -@z - -340. Make patterns work when trie_min=0 (Peter Breitenlohner, 10May88) -@x module 951 -trie_max:=128; trie_min:=128; trie_link(0):=1; trie_taken[0]:=false; -@y -trie_max:=128; trie_min:=128; trie_link(0):=1; trie_taken[0]:=false; -trie_link(trie_size):=0; trie_back(0):=trie_size; {wrap around} -@z -@x module 953 -begin c:=trie_c[p]; {we have |c>0|} -if c<trie_min then trie_min:=c; -z:=trie_link(trie_min-1); {get the first conceivably good hole} -@y -begin c:=trie_c[p]; -if c<trie_min then trie_min:=c; -if trie_min=0 then z:=trie_link(trie_size) -else z:=trie_link(trie_min-1); {get the first conceivably good hole} -@z -@x module 966 -r:=0; {finally, we will zero out the holes} -@y -r:=trie_size; {finally, we will zero out the holes} -@z - -341. Avoid possible trie_pointer out of range (24May88) -@x module 923 -hc[0]:=127; hc[hn+1]:=127; hc[hn+2]:=256; {insert delimiters} -@y -hc[0]:=127; hc[hn+1]:=127; hc[hn+2]:=128; {insert delimiters} -@z - -342. \input a\romannumeral1 etc.; similar to bug 339. (25May88) -@x module 464 -@p function str_toks:pointer; {changes the current string to a token list} -@y -@p function str_toks(@!b:pool_pointer):pointer; - {changes the string |str_pool[b..pool_ptr]| to a token list} -@z -@x module 464, continued -p:=temp_head; link(p):=null; k:=str_start[str_ptr]; -@y -p:=temp_head; link(p):=null; k:=b; -@z -@x module 464, concluded -pool_ptr:=str_start[str_ptr]; str_toks:=p; -@y -pool_ptr:=b; str_toks:=p; -@z -@x module 465 -begin get_x_token; scan_something_internal(tok_val,false); -if cur_val_level>=ident_val then @<Copy the token list@> -else begin old_setting:=selector; selector:=new_string; -@y -@!b:pool_pointer; {base of temporary string} -begin get_x_token; scan_something_internal(tok_val,false); -if cur_val_level>=ident_val then @<Copy the token list@> -else begin old_setting:=selector; selector:=new_string; b:=pool_ptr; -@z -@x module 465, continued - selector:=old_setting; the_toks:=str_toks; -@y - selector:=old_setting; the_toks:=str_toks(b); -@z -@x module 470 -begin c:=cur_chr; @<Scan the argument for command |c|@>; -old_setting:=selector; selector:=new_string; -@<Print the result of command |c|@>; -selector:=old_setting; link(garbage):=str_toks; ins_list(link(temp_head)); -@y -@!b:pool_pointer; {base of temporary string} -begin c:=cur_chr; @<Scan the argument for command |c|@>; -old_setting:=selector; selector:=new_string; b:=pool_ptr; -@<Print the result of command |c|@>; -selector:=old_setting; link(garbage):=str_toks(b); ins_list(link(temp_head)); -@z - -343. **\input\romannumeral6 confusion bypassed (25May88) -@x module 525 -begin if (pool_ptr+name_length>pool_size)or(str_ptr=max_strings) then -@y -begin if (pool_ptr+name_length>pool_size)or(str_ptr=max_strings)or - (cur_length>0) then -@z - -344. Avoid negative dividend rounding upward (Chris Thompson, fixed 19Jun88) -@x module 126 -else t:=(lo_mem_max+hi_mem_min+2) div 2; {|lo_mem_max+2<=t<hi_mem_min|} -@y -else t:=lo_mem_max+1+(hi_mem_min-lo_mem_max)div 2; {|lo_mem_max+2<=t<hi_mem_min|} -@z - -345. Better strategy when near memory overflow (Chris Thompson) -@x module 126 -begin if lo_mem_max+1000<hi_mem_min then t:=lo_mem_max+1000 -@y -begin if hi_mem_min-lo_mem_max>=1998 then t:=lo_mem_max+1000 -@z - -346. An omission from change 333 (Tsunetoshi Hayashi, reported 20June88) -@x module 439 -cur_val:=0; cur_val_level:=int_val; radix:=0; -@y -cur_val:=0; cur_val_level:=int_val; radix:=0; cur_order:=0; -@z - -347. Avoid fatal_error after terminal eof (Tim Morgan, reported 25Oct88) -@x module 71 [serious problem occurred if this was called in open_log_file] -if not input_ln(term_in,true) then fatal_error("End of file on the terminal!"); -@y -if not input_ln(term_in,true) then t_open_in; -@z - -348. Force terminal output when open_log_file aborts (6Nov88) -@x module 535 - begin print_err("I can't write on file `"); -@y - begin selector:=term_only; print_err("I can't write on file `"); -@z - -349. By popular request, undo #347 and fix the bug a more complex way. -@x module 71 [this undoes change #347] -if not input_ln(term_in,true) then t_open_in; -@y -if not input_ln(term_in,true) then fatal_error("End of file on the terminal!"); -@z -@x module 92 [now we get to the new stuff] -begin if job_name>0 then selector:=term_and_log -@y -begin if log_opened then selector:=term_and_log -@z -@x module 93 - error; -@y - if log_opened then error; -@z -@x module 527 -@!job_name:str_number; {principal file name} -@y -@!job_name:str_number; {principal file name} -@!log_opened:boolean; {has the transcript file been opened?} -@z -@x module 528 -@<Initialize the output...@>=job_name:=0; name_in_progress:=false; -@y -@<Initialize the output...@>= -job_name:=0; name_in_progress:=false; log_opened:=false; -@z -@x module 534 -selector:=log_only; -@y -selector:=log_only; log_opened:=true; -@z -@x module 535 -begin if interaction<scroll_mode then {bypass |fatal_error|} - begin selector:=term_only; 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("'.");@/ - job_name:=0; history:=fatal_error_stop; jump_out; - end; {abort the program without a log file} -@y -begin selector:=term_only; -@z -@x module 1265 [this change is optional, but it's a slight improvement] -if job_name<>0 then selector:=selector+2; -@y -if log_opened then selector:=selector+2; -@z -@x module 1333 -if job_name>0 then -@y -if log_opened then -@z -@x module 1334 -if job_name>0 then {the log file is open} -@y -if log_opened then -@z - -350. Forgotten update in error recovery (Breitenlohner, 20 Jan 89) -@x module 976 - glue_ptr(p):=r; -@y - glue_ptr(p):=r; q:=r; -@z -@x module 1004 - glue_ptr(p):=r; -@y - glue_ptr(p):=r; q:=r; -@z - -351. Avoid error \aftergroup\relax\dump (Mittelbach&Schoepf, 17 Feb 89) -@x module 280 -begin check_full_save_stack; -save_type(save_ptr):=insert_token; save_level(save_ptr):=level_zero; -save_index(save_ptr):=t; incr(save_ptr); -@y -begin if cur_level>level_one then - begin check_full_save_stack; - save_type(save_ptr):=insert_token; save_level(save_ptr):=level_zero; - save_index(save_ptr):=t; incr(save_ptr); - end; -@z - -352. Cosmetic change to validate comment in 115 (Breitenlohner, 20 Mar 89) -@x module 791 -begin q:=link(cur_align); -if (cur_align=null)or(q=null) then confusion("endv"); -@y -begin if cur_align=null then confusion("endv"); -q:=link(cur_align);@+if q=null then confusion("endv"); -@z - -353. $$\begingroup\halign{#\cr}$$ caused confusion (Mittelbach, 7 Jun 89) -@x module 1130 -mmode+halign: if privileged then init_align; -@y -mmode+halign: if privileged then - if cur_group=math_shift_group then init_align - else off_save; -@z - -354. Conflict in global array dig with .5\ifdim.6 (Mittelbach, 20 Jun 89) -@x module 450 -@!k:small_number; {number of digits in a decimal fraction} -@y -@!k,@!kk:small_number; {number of digits in a decimal fraction} -@!p,@!q:pointer; {top of decimal digit stack} -@z -@x module 452 -begin k:=0; get_token; {|point_token| is being re-scanned} -loop@+ begin get_x_token; - if (cur_tok>zero_token+9)or(cur_tok<zero_token) then goto done1; - if k<17 then {digits for |k>=17| cannot affect the result} - begin dig[k]:=cur_tok-zero_token; incr(k); - end; - end; -done1: f:=round_decimals(k); -@y -begin k:=0; p:=null; get_token; {|point_token| is being re-scanned} -loop@+ begin get_x_token; - if (cur_tok>zero_token+9)or(cur_tok<zero_token) then goto done1; - if k<17 then {digits for |k>=17| cannot affect the result} - begin q:=get_avail; link(q):=p; info(q):=cur_tok-zero_token; - p:=q; incr(k); - end; - end; -done1: for kk:=k downto 1 do - begin dig[kk-1]:=info(p); q:=p; p:=link(p); free_avail(q); - end; -f:=round_decimals(k); -@z - -355. String startup problems (Wayne Sullivan, 17 Jul 89) -@x module 31 (Warning: This affects most change files!) - overflow("buffer size",buf_size); -@:TeX capacity exceeded buffer size}{\quad buffer size@> -@y - @<Report overflow of the input buffer, and abort@>; -@z -@x module 35 -consist of the remainder of the command line, after the part that invoked -\TeX. -@y -consist of the remainder of the command line, after the part that invoked -\TeX. - -The first line is special also because it may be read before \TeX\ has -input a format file. In such cases, normal error messages cannot yet -be given. The following code uses concepts that will be explained later. - -@<Report overflow of the input buffer, and abort@>= -if format_ident=0 then - begin write_ln(term_out,'Buffer size exceeded!'); goto final_end; -@.Buffer size exceeded@> - end -else begin cur_input.loc_field:=first; cur_input.limit_field:=last-1; - overflow("buffer size",buf_size); -@:TeX capacity exceeded buffer size}{\quad buffer size@> - end -@z -@x module 1310 -k:=pool_ptr-4; undump_four_ASCII -@y -k:=pool_ptr-4; undump_four_ASCII; -init_str_ptr:=str_ptr; init_pool_ptr:=pool_ptr -@z -@x module 1332 -tini@/ -@y -init_str_ptr:=str_ptr; init_pool_ptr:=pool_ptr; fix_date_and_time; -tini@/ -@z -@x module 1332 -init_str_ptr:=str_ptr; init_pool_ptr:=pool_ptr;@/ -@y -@z - -356. Allow integer products to be 31 bits long (Mittelbach, 16 Aug 89) -@x module 105 -@p function nx_plus_y(@!n:integer;@!x,@!y:scaled):scaled; -begin if n<0 then - begin negate(x); negate(n); - end; -if n=0 then nx_plus_y:=y -else if ((x<=(@'7777777777-y) div n)and(-x<=(@'7777777777+y) div n)) then - nx_plus_y:=n*x+y -else begin arith_error:=true; nx_plus_y:=0; - end; -end; -@y -@d nx_plus_y(#)==mult_and_add(#,@'7777777777) -@d mult_integers(#)==mult_and_add(#,0,@'17777777777) - -@p function mult_and_add(@!n:integer;@!x,@!y,@!max_answer:scaled):scaled; -begin if n<0 then - begin negate(x); negate(n); - end; -if n=0 then mult_and_add:=y -else if ((x<=(max_answer-y) div n)and(-x<=(max_answer+y) div n)) then - mult_and_add:=n*x+y -else begin arith_error:=true; mult_and_add:=0; - end; -end; -@z -@x module 1240 - if q=multiply then cur_val:=nx_plus_y(eqtb[l].int,cur_val,0) -@y - if q=multiply then - if p=int_val then cur_val:=mult_integers(eqtb[l].int,cur_val) - else cur_val:=nx_plus_y(eqtb[l].int,cur_val,0) -@z - -357. Raise the maximum number of tokens normally shown (pointed out by -John Lavagnino in TeXhax on 19 May 89; corrected on 31 Aug 89). -@x module 295 -begin if p<>null then show_token_list(link(p),null,1000); -@y -begin if p<>null then show_token_list(link(p),null,10000000); -@z -@x module 1370 (this part of the change is cosmetic only) -show_token_list(link(def_ref),null,10000000); print_ln; -@y -token_show(def_ref); print_ln; -@z - -358. Like 353, but with $$\begingroup\eqno$$ (Mittelbach, 25 Jul 89) -@x module 1140 -mmode+eq_no: if privileged then start_eq_no; -@y -mmode+eq_no: if privileged then - if cur_group=math_shift_group then start_eq_no - else off_save; -@z - -359. Major extension to 8-bit character input. (These changes, and a few that -follow, were discussed during the 10th TUG meeting and installed during -the week of 10 Sep 1989. They bring the implementation of TeX82 up to date with -international developments and experience, and I believe they mark the -final development of this program into a completely stable system.) -Several changes to the documentation (not the program) are omitted here. -@x module 18 -@!ASCII_code=0..127; {seven-bit numbers} -@y -@!ASCII_code=0..255; {eight-bit numbers} -@z -@x module 19 -@d last_text_char=127 {ordinal number of the largest element of |text_char|} - -@<Local variables for init...@>= -@!i:0..last_text_char; -@y -@d last_text_char=255 {ordinal number of the largest element of |text_char|} - -@<Local variables for init...@>= -@!i:integer; -@z -@x module 21 -xchr[0]:=' '; xchr[@'177]:=' '; - {ASCII codes 0 and |@'177| do not appear in text} -@y -@z -@x module 23 -for i:=1 to @'37 do xchr[i]:=' '; -@y changing ' ' to chr(i) here will allow all 8-bit characters to get in -for i:=0 to @'37 do xchr[i]:=' '; -for i:=@'177 to @'377 do xchr[i]:=' '; -@z -@x module 24 -for i:=1 to @'176 do xord[xchr[i]]:=i; -@y -for i:=@'200 to @'377 do xord[xchr[i]]:=i; -for i:=0 to @'176 do xord[xchr[i]]:=i; -@z -@x module 38 -@<Types...@>= -@!pool_pointer = 0..pool_size; {for variables that point into |str_pool|} -@!str_number = 0..max_strings; {for variables that point into |str_start|} - -@ @<Glob...@>= -@!str_pool:packed array[pool_pointer] of ASCII_code; {the characters} -@y [OK to make si(#)==#-128 and so(#)==#+128 (without parens) in change files] -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. - -@d si(#) == # {convert from |ASCII_code| to |packed_ASCII_code|} -@d so(#) == # {convert from |packed_ASCII_code| to |ASCII_code|} - -@<Types...@>= -@!pool_pointer = 0..pool_size; {for variables that point into |str_pool|} -@!str_number = 0..max_strings; {for variables that point into |str_start|} -@!packed_ASCII_code = 0..255; {elements of |str_pool| array} - -@ @<Glob...@>= -@!str_pool:packed array[pool_pointer] of packed_ASCII_code; {the characters} -@z -@x module 42 -begin str_pool[pool_ptr]:=#; incr(pool_ptr); -@y -begin str_pool[pool_ptr]:=si(#); incr(pool_ptr); -@z -@x module 45 - begin if str_pool[j]<>buffer[k] then -@y - begin if so(str_pool[j])<>buffer[k] then -@z -@x module 47 -var k,@!l:0..127; {small indices or counters} -@y -var k,@!l:0..255; {small indices or counters} -@z -@x module 47 -@<Make the first 128 strings@>; -@y -@<Make the first 256 strings@>; -@z -@x module 48 -@ @<Make the first 128...@>= -for k:=0 to 127 do - begin if (@<Character |k| cannot be printed@>) then - begin append_char("^"); append_char("^"); - if k<@'100 then append_char(k+@'100) - else append_char(k-@'100); -@y -@ @d app_lc_hex(#)==l:=#; - if l<10 then append_char(l+"0)@+else append_char(l-10+"a") - -@<Make the first 256...@>= -for k:=0 to 255 do - begin if (@<Character |k| cannot be printed@>) then - begin append_char("^"); append_char("^"); - if k<@'100 then append_char(k+@'100) - else if k<@'200 then append_char(k-@'100) - else begin app_lc_hex(k div 16); app_lc_hex(k mod 16); - end; -@z -@x module 59 - begin print_char(str_pool[j]); incr(j); -@y - begin print_char(so(str_pool[j])); incr(j); -@z -@x modules 59 and 60 -else if s<128 then -@y -else if s<256 then -@z -@x module 60 - begin print(str_pool[j]); incr(j); -@y - begin print(so(str_pool[j])); incr(j); -@z -@x module 63 -if c>=0 then if c<128 then print(c); -@y -if c>=0 then if c<256 then print(c); -@z -@x module 68 -@ In certain situations, \TeX\ prints either a standard visible ASCII -character or its hexadecimal ASCII code. - -@p procedure print_ASCII(@!c:integer); {prints a character or its code} -begin if (c>=0) and (c<=127) then print(c) -else begin print_char("["); - if c<0 then print_int(c)@+else print_hex(c); - print_char("]"); - end; -end; -@y -@ Old versions of \TeX\ needed a procedure called |print_ASCII| whose function -is now subsumed by |print|. We retain the old name here as a possible aid to -future software arch\ae ologists. - -@d print_ASCII == print -@z -@x module 69 - begin print_char(str_pool[j]); n:=n-v; - end; - if n<=0 then return; {nonpositive input produces no output} - k:=j+2; u:=v div (str_pool[k-1]-"0"); - if str_pool[k-1]="2" then - begin k:=k+2; u:=u div (str_pool[k-1]-"0"); - end; - if n+u>=v then - begin print_char(str_pool[k]); n:=n+u; - end - else begin j:=j+2; v:=v div (str_pool[j-1]-"0"); -@y - begin print_char(so(str_pool[j])); n:=n-v; - end; - if n<=0 then return; {nonpositive input produces no output} - k:=j+2; u:=v div (so(str_pool[k-1])-"0"); - if str_pool[k-1]=si("2") then - begin k:=k+2; u:=u div (so(str_pool[k-1])-"0"); - end; - if n+u>=v then - begin print_char(so(str_pool[k])); n:=n+u; - end - else begin j:=j+2; v:=v div (so(str_pool[j-1])-"0"); -@z -@x module 70 - begin print_char(str_pool[j]); incr(j); -@y - begin print_char(so(str_pool[j])); incr(j); -@z -@x module 222 -@d single_base=active_base+128 {equivalents of one-letter control sequences} -@d null_cs=single_base+128 {equivalent of \.{\\csname\\endcsname}} -@y -@d single_base=active_base+256 {equivalents of one-character control sequences} -@d null_cs=single_base+256 {equivalent of \.{\\csname\\endcsname}} -@z -@x module 230 - {table of 128 command codes (the ``catcodes'')} -@d lc_code_base=cat_code_base+128 {table of 128 lowercase mappings} -@d uc_code_base=lc_code_base+128 {table of 128 uppercase mappings} -@d sf_code_base=uc_code_base+128 {table of 128 spacefactor mappings} -@d math_code_base=sf_code_base+128 {table of 128 math mode mappings} -@d int_base=math_code_base+128 {beginning of region 5} -@y - {table of 256 command codes (the ``catcodes'')} -@d lc_code_base=cat_code_base+256 {table of 256 lowercase mappings} -@d uc_code_base=lc_code_base+256 {table of 256 uppercase mappings} -@d sf_code_base=uc_code_base+256 {table of 256 spacefactor mappings} -@d math_code_base=sf_code_base+256 {table of 256 math mode mappings} -@d int_base=math_code_base+256 {beginning of region 5} -@z -@x module 232 -for k:=0 to 127 do -@y -for k:=0 to 255 do -@z -@x module 236 -@d del_code_base=count_base+256 {128 delimiter code mappings} -@d dimen_base=del_code_base+128 {beginning of region 6} -@y -@d del_code_base=count_base+256 {256 delimiter code mappings} -@d dimen_base=del_code_base+256 {beginning of region 6} -@z -@x module 240 -for k:=0 to 127 do del_code(k):=-1; -@y -for k:=0 to 255 do del_code(k):=-1; -@z -@x module 264 -begin if s<128 then cur_val:=s+single_base -@y -begin if s<256 then cur_val:=s+single_base -@z -@x ibid - for j:=0 to l-1 do buffer[j]:=str_pool[k+j]; -@y - for j:=0 to l-1 do buffer[j]:=so(str_pool[k+j]); -@z -@x module 289 -@d cs_token_flag==@'10000 {amount added to the |eqtb| location in a - token that stands for a control sequence; is a multiple of~256} -@y -@d cs_token_flag==@'7777 {amount added to the |eqtb| location in a - token that stands for a control sequence; is a multiple of~256, less~1} -@z -@x module 293 - if (info(p)<0)or(c>127) then print_esc("BAD.") -@y - if info(p)<0 then print_esc("BAD.") -@z -@x module 341 -@!cat:0..15; {|cat_code(cur_chr)|, usually} -@y -@!cat:0..15; {|cat_code(cur_chr)|, usually} -@!c,@!cc:ASCII_code; {constituents of a possible expanded code} -@!d:2..3; {number of excess characters in an expanded code} -@z -@x module 352 -@<If this |sup_mark| starts a control character...@>= -begin if (cur_chr=buffer[loc])and(loc<limit) then - begin if buffer[loc+1]<@'100 then cur_chr:=buffer[loc+1]+@'100 - else cur_chr:=buffer[loc+1]-@'100; - loc:=loc+2; goto reswitch; - end; -@y -@ Notice that a code like \.{\^\^8} becomes \.x if not followed by a hex digit. - -@d is_hex(#)==(((#>="0")and(#<="9"))or((#>="a")and(#<="f"))) -@d hex_to_cur_chr== - if c<="9" then cur_chr:=c-"0" @+else cur_chr:=c-"a"+10; - if cc<="9" then cur_chr:=16*cur_chr+cc-"0" - else cur_chr:=16*cur_chr+cc-"a"+10 - -@<If this |sup_mark| starts an expanded character...@>= -begin if cur_chr=buffer[loc] then if loc<limit then - begin c:=buffer[loc+1]; @+if c<@'200 then {yes we have an expanded char} - begin loc:=loc+2; - if is_hex(c) then if loc<=limit then - begin cc:=buffer[loc]; @+if is_hex(cc) then - begin incr(loc); hex_to_cur_chr; goto reswitch; - end; - end; - if c<@'100 then cur_chr:=c+@'100 @+else cur_chr:=c-@'100; - goto reswitch; - end; - end; -@z -@x module 355 - begin cur_chr:=buffer[k+1]; - if cur_chr<@'100 then buffer[k-1]:=cur_chr+@'100 - else buffer[k-1]:=cur_chr-@'100; - limit:=limit-2; first:=first-2; - while k<=limit do - begin buffer[k]:=buffer[k+2]; incr(k); - end; - goto start_cs; - end; -@y -begin c:=buffer[k+1]; @+if c<@'200 then {yes, one is indeed present} - begin d:=2; - if is_hex(c) then @+if k+2<=limit then - begin cc:=buffer[k+2]; @+if is_hex(cc) then incr(d); - end; - if d>2 then - begin hex_to_cur_chr; buffer[k-1]:=cur_chr; - end - else if c<@'100 then buffer[k-1]:=c+@'100 - else buffer[k-1]:=c-@'100; - limit:=limit-d; first:=first-d; - while k<=limit do - begin buffer[k]:=buffer[k+d]; incr(k); - end; - goto start_cs; - end; - end; -@z -@x module 360 -There is one more branch. -@y -There is one more branch. - -@d end_line_char_inactive == (end_line_char<0)or(end_line_char>255) -@z -@x ibid - if (end_line_char<0)or(end_line_char>127) then decr(limit) -@y - if end_line_char_inactive then decr(limit) -@z -@x modules 362 and 483 and 538 and 1337 -if (end_line_char<0)or(end_line_char>127) then decr(limit) -@y -if end_line_char_inactive then decr(limit) -@z -@x module 391 -if (info(r)>match_token+127)or(info(r)<match_token) then s:=null -@y -if (info(r)>match_token+255)or(info(r)<match_token) then s:=null -@z -@x module 407 - ((cur_chr=str_pool[k])or(cur_chr=str_pool[k]-"a"+"A")) then -@y - ((cur_chr=so(str_pool[k]))or(cur_chr=so(str_pool[k])-"a"+"A")) then -@z -@x module 414 -begin scan_seven_bit_int; -@y -begin scan_char_num; -@z -@x module 432 -|scan_something_internal|: - -@<Declare procedures that scan restricted classes of integers@>= -procedure scan_seven_bit_int; -begin scan_int; -if (cur_val<0)or(cur_val>127) then - begin print_err("Bad character code"); -@.Bad character code@> - help2("The numeric code for a character must be between 0 and 127.")@/ - ("I changed this one to zero."); int_error(cur_val); cur_val:=0; - end; -end; -@y -|scan_something_internal|. -@z (and I'll interchange modules 434 and 435) -@x module 442 -if cur_val>127 then -@y -if cur_val>255 then -@z -@x module 464 - begin t:=str_pool[k]; -@y - begin t:=so(str_pool[k]); -@z -@x module 506 (correction needed twice) -if (cur_cmd>active_char)or(cur_chr>127) then -@y -if (cur_cmd>active_char)or(cur_chr>255) then -@z -@x module 519 -for j:=str_start[a] to str_start[a+1]-1 do append_to_name(str_pool[j]); -for j:=str_start[n] to str_start[n+1]-1 do append_to_name(str_pool[j]); -for j:=str_start[e] to str_start[e+1]-1 do append_to_name(str_pool[j]); -@y -for j:=str_start[a] to str_start[a+1]-1 do append_to_name(so(str_pool[j])); -for j:=str_start[n] to str_start[n+1]-1 do append_to_name(so(str_pool[j])); -for j:=str_start[e] to str_start[e+1]-1 do append_to_name(so(str_pool[j])); -@z -@x module 526 -if (cur_cmd>active_char)or(cur_chr>127) then -@y -if (cur_cmd>active_char)or(cur_chr>255) then -@z -@x module 603 (change to be made twice) - dvi_out(str_pool[k]); -@y - dvi_out(so(str_pool[k])); -@z -@x module 617 - for s:=str_start[str_ptr] to pool_ptr-1 do dvi_out(str_pool[s]); -@y - for s:=str_start[str_ptr] to pool_ptr-1 do dvi_out(so(str_pool[s])); -@z -@x module 766 - begin case str_pool[r_type*8+t+magic_offset] of -@y - begin case so(str_pool[r_type*8+t+magic_offset]) of -@z -@x module 780 -@d span_code=128 {distinct from any character} -@d cr_code=129 {distinct from |span_code| and from any character} -@y -@d span_code=256 {distinct from any character} -@d cr_code=257 {distinct from |span_code| and from any character} -@z -@x module 815 -label done,done1,done2,done3,done4; -@y -label done,done1,done2,done3,done4,continue; -@z -@x module 896 - else if (type(s)=kern_node)and(subtype(s)=normal) then c:=128 - else if type(s)=whatsit_node then c:=128 - else goto done1; - if c<128 then if lc_code(c)<>0 then - if (lc_code(c)=c)or(uc_hyph>0) then goto done2 - else goto done1; - s:=link(s); -@y - else if (type(s)=kern_node)and(subtype(s)=normal) then goto continue - else if type(s)=whatsit_node then goto continue - else goto done1; - if lc_code(c)<>0 then - if (lc_code(c)=c)or(uc_hyph>0) then goto done2 - else goto done1; -continue: s:=link(s); -@z -@x module 897 - if c>=128 then goto done3; - if (lc_code(c)=0)or(hn=63) then goto done3; - hb:=s; incr(hn); hu[hn]:=c; hc[hn]:=lc_code(c)-1; -@y - if lc_code(c)=0 then goto done3; - if hn=63 then goto done3; - hb:=s; incr(hn); hu[hn]:=c; hc[hn]:=lc_code(c); -@z -@x module 898 -if c>=128 then goto done3; -if (lc_code(c)=0)or(j=63) then goto done3; -incr(j); hu[j]:=c; hc[j]:=lc_code(c)-1;@/ -@y -if lc_code(c)=0 then goto done3; -if j=63 then goto done3; -incr(j); hu[j]:=c; hc[j]:=lc_code(c);@/ -@z -@x module 923 -hc[0]:=127; hc[hn+1]:=127; hc[hn+2]:=128; {insert delimiters} -@y -hc[0]:=0; hc[hn+1]:=0; hc[hn+2]:=256; {insert delimiters} -@z -@x ibid - while hc[l]=trie_char(z) do -@y - while hc[l]=qo(trie_char(z)) do -@z -@x module 931 - repeat if str_pool[u]<hc[j] then goto not_found; - if str_pool[u]>hc[j] then goto done; -@y - repeat if so(str_pool[u])<hc[j] then goto not_found; - if so(str_pool[u])>hc[j] then goto done; -@z -@x module 937 -else begin if (cur_chr>127)or(lc_code(cur_chr)=0) then -@y -else begin if lc_code(cur_chr)=0 then -@z -@x ibid - begin incr(n); hc[n]:=lc_code(cur_chr)-1; -@y - begin incr(n); hc[n]:=lc_code(cur_chr); -@z -@x module 945 -@!init @!trie_c:packed array[trie_pointer] of ASCII_code; {characters to match} -@y -@!init @!trie_c:packed array[trie_pointer] of packed_ASCII_code; - {characters to match} -@z -% In modules 951--954, change "127" to "255" and "128" to "256" -@x module 952 -trie_link(0):=0; trie_char(0):=0; trie_op(0):=min_quarterword; -@y -trie_link(0):=0; trie_char(0):=min_quarterword; trie_op(0):=min_quarterword; -@z -@x module 953 -begin c:=trie_c[p]; -@y -begin c:=so(trie_c[p]); -@z -@x module 955 - begin if trie_link(h+trie_c[q])=0 then goto not_found; -@y - begin if trie_link(h+so(trie_c[q]))=0 then goto not_found; -@z -@x module 956 -repeat z:=h+trie_c[q]; trie_back(trie_link(z)):=trie_back(z); -@y -repeat z:=h+so(trie_c[q]); trie_back(trie_link(z)):=trie_back(z); -@z -@x module 959 - begin q:=trie_l[p]; c:=trie_c[p]; - trie_link(z+c):=trie_ref[q]; trie_char(z+c):=c; trie_op(z+c):=trie_o[p]; -@y - begin q:=trie_l[p]; c:=so(trie_c[p]); - trie_link(z+c):=trie_ref[q]; trie_char(z+c):=qi(c); trie_op(z+c):=trie_o[p]; -@z -@x module 962 - begin if cur_chr="." then cur_chr:=128 {edge-of-word delimiter} - else begin cur_chr:=lc_code(cur_chr); - if cur_chr=0 then - begin print_err("Nonletter"); -@.Nonletter@> - help1("(See Appendix H.)"); error; cur_chr:=128; - end; - end; - if k<63 then - begin incr(k); hc[k]:=cur_chr-1; hyf[k]:=0; digit_sensed:=false; - end; - end -else begin hyf[k]:=cur_chr-"0"; - if k<63 then digit_sensed:=true; - end -@y - begin if cur_chr="." then cur_chr:=0 {edge-of-word delimiter} - else begin cur_chr:=lc_code(cur_chr); - if cur_chr=0 then - begin print_err("Nonletter"); -@.Nonletter@> - help1("(See Appendix H.)"); error; - end; - end; - if k<63 then - begin incr(k); hc[k]:=cur_chr; hyf[k]:=0; digit_sensed:=false; - end; - end - else if k<63 then - begin hyf[k]:=cur_chr-"0"; digit_sensed:=true; - end; - end -@z -@x module 963 - while (p>0)and(c>trie_c[p]) do -@y - while (p>0)and(c>so(trie_c[p])) do -@z -@x ibid - if (p=0)or(c<trie_c[p]) then -@y - if (p=0)or(c<so(trie_c[p])) then -@z -@x module 964 -trie_c[p]:=c; trie_o[p]:=min_quarterword; -@y -trie_c[p]:=si(c); trie_o[p]:=min_quarterword; -@z -@x module 965 -if hc[1]=127 then hyf[0]:=0; -if hc[k]=127 then hyf[k]:=0; -@y -if hc[1]=0 then hyf[0]:=0; -if hc[k]=0 then hyf[k]:=0; -@z -@x module 966 -h.rh:=0; h.b0:=min_quarterword; h.b1:=0; {|trie_link:=0|, - |trie_op:=min_quarterword|, |trie_char:=0|} -@y -h.rh:=0; h.b0:=min_quarterword; h.b1:=min_quarterword; {|trie_link:=0|, - |trie_op:=min_quarterword|, |trie_char:=qi(0)|} -@z -@x module 1034 -if c<128 then -@y -@z -@x ibid -else space_factor:=1000 -@y -@z -@x module 1151 -letter,other_char,char_given: if cur_chr>=128 then c:=cur_chr - else begin c:=ho(math_code(cur_chr)); -@y -letter,other_char,char_given: begin c:=ho(math_code(cur_chr)); -@z -@x module 1154 -mmode+letter,mmode+other_char,mmode+char_given: if cur_chr<128 then - set_math_char(ho(math_code(cur_chr))) - else set_math_char(cur_chr); -mmode+char_num: begin scan_char_num; cur_chr:=cur_val; - if cur_chr<128 then set_math_char(ho(math_code(cur_chr))) - else set_math_char(cur_chr); -@y -mmode+letter,mmode+other_char,mmode+char_given: - set_math_char(ho(math_code(cur_chr))); -mmode+char_num: begin scan_char_num; cur_chr:=cur_val; - set_math_char(ho(math_code(cur_chr))); -@z -@x module 1232 - p:=cur_chr; scan_seven_bit_int; p:=p+cur_val; scan_optional_equals; -@y - p:=cur_chr; scan_char_num; p:=p+cur_val; scan_optional_equals; -@z -@x module 1233 -else n:=127 -@y -else n:=255 -@z -@x module 1289 - begin if t>=cs_token_flag then t:=t-active_base; - c:=t mod 256; - if c<128 then if equiv(b+c)<>0 then t:=256*(t div 256)+equiv(b+c); - if t>=cs_token_flag then info(p):=t+active_base - else info(p):=t; -@y - begin c:=t mod 256; - if equiv(b+c)<>0 then info(p):=t-c+equiv(b+c); -@z -@x module 1309 - w.b0:=str_pool[k]; w.b1:=str_pool[k+1]; - w.b2:=str_pool[k+2]; w.b3:=str_pool[k+3]; -@y [often qi(so(x))=x, but not e.g. when "quarterwords" are two bytes] - w.b0:=qi(so(str_pool[k])); w.b1:=qi(so(str_pool[k+1])); - w.b2:=qi(so(str_pool[k+2])); w.b3:=qi(so(str_pool[k+3])); -@z -@x module 1310 - str_pool[k]:=w.b0; str_pool[k+1]:=w.b1; - str_pool[k+2]:=w.b2; str_pool[k+3]:=w.b3 -@y - str_pool[k]:=si(qo(w.b0)); str_pool[k+1]:=si(qo(w.b1)); - str_pool[k+2]:=si(qo(w.b2)); str_pool[k+3]:=si(qo(w.b3)) -@z -@x module 1368 -for k:=str_start[str_ptr] to pool_ptr-1 do dvi_out(str_pool[k]); -@y -for k:=str_start[str_ptr] to pool_ptr-1 do dvi_out(so(str_pool[k])); -@z - -360. Major change to allow multiple hyphenation tables. -I've combined this with the code for a minor change: -361. New parameters \lefthyphenmin and \righthyphenmin. -@x module 11 (affects most change files!) -@!trie_size=8000; {space for hyphenation patterns; should be larger for - \.{INITEX} than it is in production versions of \TeX} -@y -@!trie_size=8000; {space for hyphenation patterns; should be larger for - \.{INITEX} than it is in production versions of \TeX} -@!trie_op_size=500; {space for ``opcodes'' in the hyphenation patterns} -@z -@x module 212 -known as |space_factor|; it holds the current space factor used in spacing -calculations. In math mode, |aux| is also known as |incompleat_noad|; if -@y -known as |space_factor| and |clang|; it holds the current space factor used in -spacing calculations, and the current language used for hyphenation. -(The value of |clang| is undefined in restricted horizontal mode.) -In math mode, |aux| is also known as |incompleat_noad|; if -@z -@x ibid - @!pg_field,@!aux_field,@!ml_field: integer; -@y - @!pg_field,@!ml_field: integer; - @!aux_field: memory_word; -@z -@x module 213 -@d prev_depth==aux {the name of |aux| in vertical mode} -@d space_factor==aux {the name of |aux| in horizontal mode} -@d incompleat_noad==aux {the name of |aux| in math mode} -@y -@d prev_depth==aux.sc {the name of |aux| in vertical mode} -@d space_factor==aux.hh.lh {part of |aux| in horizontal mode} -@d clang==aux.hh.rh {the other part of |aux| in horizontal mode} -@d incompleat_noad==aux.int {the name of |aux| in math mode} -@z -@x module 218 -@!a:integer; {auxiliary} -@y -@!a:memory_word; {auxiliary} -@z -@x module 219 - if a<=ignore_depth then print("ignored") - else print_scaled(a); - if nest[p].pg_field<>0 then - begin print(", prevgraf "); - print_int(nest[p].pg_field); print(" line"); - if nest[p].pg_field<>1 then print_char("s"); - end; - end; -1: begin print_nl("spacefactor "); print_int(a); - end; -2: if a<>null then - begin print("this will be denominator of:"); show_box(a); -@y - if a.sc<=ignore_depth then print("ignored") - else print_scaled(a.sc); - if nest[p].pg_field<>0 then - begin print(", prevgraf "); - print_int(nest[p].pg_field); print(" line"); - if nest[p].pg_field<>1 then print_char("s"); - end; - end; -1: begin print_nl("spacefactor "); print_int(a.hh.lh); - if m>0 then if a.hh.rh>0 then - begin print(", current language "); print_int(a.hh.rh); - end; - end; -2: if a.int<>null then - begin print("this will be denominator of:"); show_box(a.int); -@z -@x modules 236--238 -@d int_pars=50 {total number of integer parameters} -@y -@d language_code=50 {current hyphenation table} -@d left_hyphen_min_code=51 {minimum left hyphenation fragment size} -@d right_hyphen_min_code=52 {minimum right hyphenation fragment size} -@d int_pars=53 {total number of integer parameters} -@z and define/print these new parameters appropriately (mimicking new_line_char) -@x module 418 -else begin cur_val:=aux; - if m=vmode then cur_val_level:=dimen_val@+else cur_val_level:=int_val; - end -@y -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 -@z -@x module 775 - begin mode:=-vmode; prev_depth:=nest[nest_ptr-2].aux_field; -@y - begin mode:=-vmode; prev_depth:=nest[nest_ptr-2].aux_field.sc; -@z -@x module 786 -begin push_nest; mode:=(-hmode-vmode)-mode; aux:=0; -@y -begin push_nest; mode:=(-hmode-vmode)-mode; -if mode=-hmode then space_factor:=0 @+else prev_depth:=0; -@z -@x module 863 -loop@+ begin @<Create an active breakpoint representing the beginning of - the paragraph@>; -@y -loop@+ begin if threshold>inf_bad then threshold:=inf_bad; - if second_pass then @<Initialize for hyphenating a paragraph@>; - @<Create an active breakpoint representing the beginning of the paragraph@>; -@z -@x module 891 -passes on only about 5 per cent of the paragraphs. -@y -passes on only about 5 per cent of the paragraphs. - -@<Initialize for hyphenating...@>= -begin @!init if trie_not_ready then init_trie; @+tini@;@/ -l_hyf:=left_hyphen_min-1;@+if l_hyf<0 then l_hyf:=0; -r_hyf:=right_hyphen_min-1;@+if r_hyf<0 then r_hyf:=0; -min_hyf:=l_hyf+r_hyf+2; cur_lang:=0; -end -@z -@x module 892 -@!hyf_char:integer; {hyphen character of the relevant font} -@y -@!hyf_char:integer; {hyphen character of the relevant font} -@!cur_lang:ASCII_code; {current hyphenation table of interest} -@!l_hyf,@!r_hyf,@!min_hyf:integer; {limits on fragment sizes} -@z -@x module 894 -begin s:=link(cur_p); -@y -begin if min_hyf>63 then goto done1; -s:=link(cur_p); -@z -@x module 896 - else if type(s)=whatsit_node then goto continue -@y - else if type(s)=whatsit_node then - begin @<Advance \(p)past a whatsit node in the \(p)pre-hyphenation loop@>; - goto continue; - end -@z -@x module 899 (title of this module also changes appropriately) -if hn<5 then goto done1; -@y -if hn<min_hyf then goto done1; -@z -@x module 902 -for j:=2 to hn-3 do if odd(hyf[j]) then goto found1; -@y -for j:=l_hyf+1 to hn-r_hyf-1 do if odd(hyf[j]) then goto found1; -@z -@x module 920 -$p_1\ldots p_k$ by setting |@t$z_1$@>:=@t$p_1$@>| and then, for |1<i<=k|, -@y -$p_1\ldots p_k$ by letting $z_0$ be one greater than the relevant language index -and then, for |1<=i<=k|, -@z -@x ibid -the letters in |hc[(l-k+1)..l@,]|, we perform all of the required operations -for this pattern by carrying out the following little program: Set -|v:=trie_op(@t$z_k$@>)|. Then set |hyf[l-hyf_distance[v]]:=@tmax@>( -hyf[l-hyf_distance[v]], hyf_num[v])|, and |v:=hyf_next[v]|; repeat, if -necessary, until |v=min_quarterword|. -@y -the letters in |hc[(l-k+1)..l@,]| of language |t|, -we perform all of the required operations -for this pattern by carrying out the following little program: Set -|v:=trie_op(@t$z_k$@>)|. Then set |v:=v+op_start[t]|, -|hyf[l-hyf_distance[v]]:=@tmax@>(hyf[l-hyf_distance[v]], hyf_num[v])|, -and |v:=hyf_next[v]|; repeat, if necessary, until |v=min_quarterword|. -@z -@x module 921 -@!hyf_distance:array[quarterword] of small_number; {position |k-j| of $n_j$} -@!hyf_num:array[quarterword] of small_number; {value of $n_j$} -@!hyf_next:array[quarterword] of quarterword; {continuation of this |trie_op|} -@y -@!hyf_distance:array[1..trie_op_size] of small_number; {position |k-j| of $n_j$} -@!hyf_num:array[1..trie_op_size] of small_number; {value of $n_j$} -@!hyf_next:array[1..trie_op_size] of quarterword; {continuation code} -@!op_start:array[ASCII_code] of 0..trie_op_size; {offset for current language} -@z -@x module 922 -@!v:quarterword; {an index into |hyf_distance|, etc.} -@y -@!v:integer; {an index into |hyf_distance|, etc.} -@z -@x module 923 -for j:=0 to hn-2 do - begin z:=hc[j]; l:=j; -@y -if trie_char(cur_lang+1)<>qi(cur_lang) then return; {no patterns for |cur_lang|} -for j:=0 to hn-r_hyf do - begin z:=trie_link(cur_lang+1)+hc[j]; l:=j; -@z -@x ibid -found: hyf[1]:=0; hyf[hn-2]:=0; hyf[hn-1]:=0; hyf[hn]:=0 -@y -found: for j:=0 to l_hyf do hyf[j]:=0; -for j:=0 to r_hyf do hyf[hn-j]:=0 -@z -@x module 924 -repeat i:=l-hyf_distance[v]; -@y -repeat v:=v+op_start[cur_lang]; i:=l-hyf_distance[v]; -@z -@x module 930 -h:=hc[1]; -@y -h:=hc[1]; incr(hn); hc[hn]:=cur_lang; -@z -@x ibid -not_found: -@y -not_found: decr(hn) -@z -@x module 931 - goto found; -@y - decr(hn); goto found; -@z -@x module 934 -@p procedure new_hyph_exceptions; {enters new exceptions} -label reswitch, exit, found, not_found, done; -@y -@d set_cur_lang==if language<=0 then cur_lang:=0 - else if language>255 then cur_lang:=0 - else cur_lang:=language - -@p procedure new_hyph_exceptions; {enters new exceptions} -label reswitch, exit, found, not_found; -@z -@x ibid -begin scan_left_brace; {a left brace must follow \.{\\hyphenation}} -@y -begin scan_left_brace; {a left brace must follow \.{\\hyphenation}} -set_cur_lang; -@z -@x module 935 - spacer,right_brace: begin if n>4 then @<Enter a hyphenation exception@>; -@y - spacer,right_brace: begin if n>1 then @<Enter a hyphenation exception@>; -@z -@x module 938 -begin if n>1 then -@y -begin if n<63 then -@z -@x module 939 -begin str_room(n); h:=0; -@y -begin incr(n); hc[n]:=cur_lang; str_room(n); h:=0; -@z -@x ibid -loop@+ begin if p=null then goto done; - if info(p)<n-2 then goto done; - q:=link(p); free_avail(p); p:=q; {eliminate hyphens that \TeX\ doesn't like} - end; -done: @<Insert the \(p)pair |(s,p)| into the exception table@>; -@y -@<Insert the \(p)pair |(s,p)| into the exception table@>; -@z -@x module 942 -@p@!init @<Declare procedures for preprocessing hyphenation patterns@>@; -@y -@<Declare subprocedures for |line_break|@>= -@!init @<Declare procedures for preprocessing hyphenation patterns@>@; -@z -@x module 943 -@d quarterword_diff=max_quarterword-min_quarterword -@d trie_op_hash_size=quarterword_diff+quarterword_diff {double} - -@<Glob...@>= -@!init@! trie_op_hash:array[0..trie_op_hash_size] of quarterword; - {trie op codes for triples} -tini@;@/ -@t\hskip1em@>@!trie_op_ptr:quarterword; {highest |trie_op| assigned} -@y -@<Glob...@>= -@!init@! trie_op_hash:array[-trie_op_size..trie_op_size] of 0..trie_op_size; - {trie op codes for quadruples} -@!trie_used:array[ASCII_code] of quarterword; - {largest opcode used so far for this language} -@!trie_op_lang:array[1..trie_op_size] of ASCII_code; - {language part of a hashed quadruple} -@!trie_op_val:array[1..trie_op_size] of quarterword; - {opcode corresponding to a hashed quadruple} -@!trie_op_ptr:0..trie_op_size; {number of stored ops so far} -tini -@z -@x module 944 should be entirely replaced -@y by the following code: -@ It's tempting to remove the |overflow| stops in the following procedure; -|new_trie_op| could return |min_quarterword| (thereby simply ignoring -part of a hyphenation pattern) instead of aborting the job. However, that would -lead to different hyphenation results on different installations of \TeX\ -using the same patterns. The |overflow| stops are necessary for portability -of patterns. - -@<Declare procedures for preprocessing hyph...@>= -function new_trie_op(@!d,@!n:small_number;@!v:quarterword):quarterword; -label exit; -var h:-trie_op_size..trie_op_size; {trial hash location} -@!u:quarterword; {trial op code} -@!l:0..trie_op_size; {pointer to stored data} -begin h:=abs(n+313*d+361*v+1009*cur_lang) mod (trie_op_size+trie_op_size) - - trie_op_size; -loop@+ begin l:=trie_op_hash[h]; - if l=0 then {empty position found for a new op} - begin if trie_op_ptr=trie_op_size then - overflow("pattern memory ops",trie_op_size); - u:=trie_used[cur_lang]; - if u=max_quarterword then - overflow("pattern memory ops per language", - max_quarterword-min_quarterword); - incr(trie_op_ptr); incr(u); trie_used[cur_lang]:=u; - hyf_distance[trie_op_ptr]:=d; - hyf_num[trie_op_ptr]:=n; hyf_next[trie_op_ptr]:=v; - trie_op_lang[trie_op_ptr]:=cur_lang; trie_op_hash[h]:=trie_op_ptr; - trie_op_val[trie_op_ptr]:=u; new_trie_op:=u; return; - end; - if (hyf_distance[l]=d)and(hyf_num[l]=n)and(hyf_next[l]=v) - and(trie_op_lang[l]=cur_lang) then - begin new_trie_op:=trie_op_val[l]; return; - end; - if h>-trie_op_size then decr(h)@+else h:=trie_op_size; - end; -exit:end; -@z -@x module 945: move the code from this module into 946, and introduce new code: -@y -@ After |new_trie_op| has compressed the necessary opcode information, -plenty of information is available to unscramble the data into the -final form needed by our hyphenation algorithm. - -@<Sort the hyphenation op tables into proper order@>= -op_start[0]:=-min_quarterword; -for j:=1 to 255 do op_start[j]:=op_start[j-1]+qo(trie_used[j-1]); -for j:=1 to trie_op_ptr do - trie_op_hash[j]:=op_start[trie_op_lang[j]]+trie_op_val[j]; {destination} -for j:=1 to trie_op_ptr do while trie_op_hash[j]>j do - begin k:=trie_op_hash[j];@/ - t:=hyf_distance[k]; hyf_distance[k]:=hyf_distance[j]; hyf_distance[j]:=t;@/ - t:=hyf_num[k]; hyf_num[k]:=hyf_num[j]; hyf_num[j]:=t;@/ - t:=hyf_next[k]; hyf_next[k]:=hyf_next[j]; hyf_next[j]:=t;@/ - trie_op_hash[j]:=trie_op_hash[k]; trie_op_hash[k]:=k; - end -@z -@x module 949: Move this code to just after the new module 945! -mentioned so far, let's write a procedure that does the initialization. - -@<Declare procedures for preprocessing hyph...@>= -procedure init_pattern_memory; {gets ready to build a linked trie} -var h:0..trie_op_hash_size; {an index into |trie_op_hash|} -@!p:trie_pointer; {an index into |trie_hash|} -begin for h:=0 to trie_op_hash_size do trie_op_hash[h]:=min_quarterword; -trie_op_ptr:=min_quarterword; trie_root:=0; trie_c[0]:=0; trie_ptr:=0; -for p:=0 to trie_size do trie_hash[p]:=0; -end; -@y -mentioned so far, let's write down the code that gets them started. - -@<Initialize table entries...@>= -for k:=-trie_op_size to trie_op_size do trie_op_hash[k]:=0; -for k:=0 to 255 do trie_used[k]:=min_quarterword; -trie_op_ptr:=0; -@z -@x module 950 -@t\hskip1em@>@!trie_min:trie_pointer; - {all locations |<=trie_min| are vacant in |trie|} -tini@;@/ -@t\hskip1em@>@!trie_max:trie_pointer; {largest location used in |trie|} -@y -@t\hskip10pt@>@!trie_min:array[ASCII_code] of trie_pointer; - {the first possible slot for each character} -@t\hskip10pt@>@!trie_max:trie_pointer; {largest location used in |trie|} -@t\hskip10pt@>@!trie_not_ready:boolean; {is the trie still in linked form?} -tini -@z -@x modules 951 and 952 -@ Here is how these data structures are initialized. - -@<Declare procedures for preprocessing hyph...@>= -procedure init_trie_memory; {gets ready to pack into |trie|} -var p:trie_pointer; {index into |trie_ref|, |trie|, |trie_taken|} -begin for p:=0 to trie_ptr do trie_ref[p]:=0; -trie_max:=256; trie_min:=256; trie_link(0):=1; trie_taken[0]:=false; -trie_link(trie_size):=0; trie_back(0):=trie_size; {wrap around} -for p:=1 to 256 do - begin trie_back(p):=p-1; trie_link(p):=p+1; trie_taken[p]:=false; - end; -end; - -@ Each time \.{\\patterns} appears, it overrides any patterns that were -entered earlier, so the arrays are not initialized until \TeX\ sees -\.{\\patterns}. However, some of the global variables must be -initialized when \.{INITEX} is loaded, in case the user never mentions -any \.{\\patterns}. - -@<Initialize table entries...@>= -trie_op_ptr:=min_quarterword;@/ -trie_link(0):=0; trie_char(0):=min_quarterword; trie_op(0):=min_quarterword; -for k:=1 to 255 do trie[k]:=trie[0]; -trie_max:=255; -@y -@ Each time \.{\\patterns} appears, it contributes further patterns to -the future trie, which will be built only when hyphenation is attempted or -when a format file is dumped. The boolean variable |trie_not_ready| -will change to |false| when the trie is compressed; this will disable -further patterns. - -@<Initialize table entries...@>= -trie_not_ready:=true; trie_root:=0; trie_c[0]:=si(0); trie_ptr:=0; - -@ Here is how the trie-compression data structures are initialized. -If storage is tight, it would be possible to overlap |trie_op_hash|, -|trie_op_lang|, and |trie_op_val| with |trie|, |trie_hash|, and |trie_taken|, -because we finish with the former just before we need the latter. - -@<Get ready to compress the trie@>= -@<Sort the hyphenation...@>; -for p:=0 to trie_size do trie_hash[p]:=0; -trie_root:=compress_trie(trie_root); {identify equivalent subtries} -for p:=0 to trie_ptr do trie_ref[p]:=0; -for p:=0 to 255 do trie_min[p]:=p+1; -trie_link(0):=1; trie_max:=0 -@z -@x module 953 -begin c:=so(trie_c[p]); -if c<trie_min then trie_min:=c; -if trie_min=0 then z:=trie_link(trie_size) -else z:=trie_link(trie_min-1); {get the first conceivably good hole} -loop@+ begin if z<c then goto not_found; - h:=z-c;@/ -@y -@!l,@!r:trie_pointer; {left and right neighbors} -@!ll:1..256; {upper limit of |trie_min| updating} -begin c:=so(trie_c[p]); -z:=trie_min[c]; {get the first conceivably good hole} -loop@+ begin h:=z-c;@/ -@z -@x module 956 -repeat z:=h+so(trie_c[q]); trie_back(trie_link(z)):=trie_back(z); -trie_link(trie_back(z)):=trie_link(z); trie_link(z):=0; q:=trie_r[q]; -@y -repeat z:=h+so(trie_c[q]); l:=trie_back(z); r:=trie_link(z); -trie_back(r):=l; trie_link(l):=r; trie_link(z):=0; -if l<256 then - begin if z<256 then ll:=z @+else ll:=256; - repeat trie_min[l]:=r; incr(l); - until l=ll; - end; -q:=trie_r[q]; -@z -@x module 958 is entirely replaced -@y by the following new code: -@ When the whole trie has been allocated into the sequential table, we -must go through it once again so that |trie| contains the correct -information. Null pointers in the linked trie will be represented by the -value~0, which properly implements an ``empty'' family. - -@<Move the data into |trie|@>= -h.rh:=0; h.b0:=min_quarterword; h.b1:=min_quarterword; {|trie_link:=0|, - |trie_op:=min_quarterword|, |trie_char:=qi(0)|} -if trie_root=0 then {no patterns were given} - begin for r:=0 to 256 do trie[r]:=h; - trie_max:=256; - end -else begin trie_fix(trie_root); {this fixes the non-holes in |trie|} - r:=0; {now we will zero out all the holes} - repeat s:=trie_link(r); trie[r]:=h; r:=s; - until r>trie_max; - end; -trie_char(0):=qi("?"); {make |trie_char(c)<>c| for all |c|} -@z -@x module 960 -@!r,@!s:trie_pointer; {used to clean up the packed |trie|} -@!h:two_halves; {template used to zero out |trie|'s holes} -begin scan_left_brace; {a left brace must follow \.{\\patterns}} -init_pattern_memory;@/ -@<Enter all of the patterns into a linked trie, until coming to a right - brace@>; -trie_root:=compress_trie(trie_root); {compress the trie} -@<Pack the trie@>; -end; -@y -begin if trie_not_ready then - begin set_cur_lang; scan_left_brace; {a left brace must follow \.{\\patterns}} - @<Enter all of the patterns into a linked trie, until coming to a right - brace@>; - end -else begin print_err("Too late for "); print_esc("patterns"); - help1("All patterns must be given before typesetting begins."); - error; link(garbage):=scan_toks(false,false); flush_list(def_ref); - end; -end; -@z -@x module 963 -q:=0; -while l<k do - begin incr(l); c:=hc[l]; p:=trie_l[q]; first_child:=true; -@y -q:=0; hc[0]:=cur_lang; -while l<=k do - begin c:=hc[l]; incr(l); p:=trie_l[q]; first_child:=true; -@z -@x module 966 now says that the first call ``takes'' location 1, -@y and the Pascal code in this module is entirely replaced by the following: -@<Declare procedures for preprocessing hyphenation patterns@>= -procedure init_trie; -var @!p:trie_pointer; {pointer for initialization} -@!j,@!k,@!t:integer; {all-purpose registers for initialization} -@!r,@!s:trie_pointer; {used to clean up the packed |trie|} -@!h:two_halves; {template used to zero out |trie|'s holes} -begin @<Get ready to compress the trie@>; -if trie_root<>0 then - begin first_fit(trie_root); trie_pack(trie_root); - end; -@<Move the data into |trie|@>; -trie_not_ready:=false; -end; -@z -@x module 1033 gets new code before main_loop_1 -@y -if mode>0 then if language<>clang then fix_language; -@z -@x modules 1091 and 1200 -push_nest; mode:=hmode; space_factor:=1000; -@y -push_nest; mode:=hmode; space_factor:=1000; clang:=0; -@z -@x module 1324 -for k:=0 to trie_max do dump_hh(trie[k]); -dump_int(trie_op_ptr); -for k:=min_quarterword+1 to trie_op_ptr do - begin dump_int(hyf_distance[k]); - dump_int(hyf_num[k]); - dump_int(hyf_next[k]); - end; -print_ln; print_int(hyph_count); print(" hyphenation exception"); -if hyph_count<>1 then print_char("s"); -print_nl("Hyphenation trie of length "); print_int(trie_max); -@.Hyphenation trie...@> -print(" has "); print_int(qo(trie_op_ptr)); print(" op"); -if trie_op_ptr<>min_quarterword+1 then print_char("s") -@y -print_ln; print_int(hyph_count); print(" hyphenation exception"); -if hyph_count<>1 then print_char("s"); -if trie_not_ready then init_trie; -dump_int(trie_max); -for k:=0 to trie_max do dump_hh(trie[k]); -dump_int(trie_op_ptr); -for k:=1 to trie_op_ptr do - begin dump_int(hyf_distance[k]); - dump_int(hyf_num[k]); - dump_int(hyf_next[k]); - end; -print_nl("Hyphenation trie of length "); print_int(trie_max); -@.Hyphenation trie...@> -print(" has "); print_int(trie_op_ptr); print(" op"); -if trie_op_ptr<>1 then print_char("s"); -print(" out of "); print_int(trie_op_size); -for k:=255 downto 0 do if trie_used[k]>min_quarterword then - begin print_nl(" "); print_int(qo(trie_used[k])); - print(" for language "); print_int(k); - dump_int(k); dump_int(qo(trie_used[k])); - end -@z -@x module 1325 -undump_size(0)(trie_size)('trie size')(trie_max); -for k:=0 to trie_max do undump_hh(trie[k]); -undump(min_quarterword)(max_quarterword)(trie_op_ptr); -for k:=min_quarterword+1 to trie_op_ptr do - begin undump(0)(63)(hyf_distance[k]); {a |small_number|} - undump(0)(63)(hyf_num[k]); - undump(min_quarterword)(max_quarterword)(hyf_next[k]); - end -@y -undump_size(0)(trie_size)('trie size')(j); {|trie_max|} -for k:=0 to j do undump_hh(trie[k]); -undump_size(0)(trie_op_size)('trie op size')(j); {|trie_op_ptr|} -for k:=1 to j do - begin undump(0)(63)(hyf_distance[k]); {a |small_number|} - undump(0)(63)(hyf_num[k]); - undump(min_quarterword)(max_quarterword)(hyf_next[k]); - end; -k:=256; -while j>0 do - begin undump(0)(k-1)(k); undump(1)(j)(x); j:=j-x; op_start[k]:=qo(j); - end; -@!init trie_not_ready:=false @+tini -@z -@x module 1341 gets two new definitions -@y -@d language_node=4 {|subtype| in whatsits that change the current language} -@d stored_language(#)==mem[#+1].int {language number, in the range |0..255|} -@z -@x module 1344 gets a new definition and a new Pascal statement -@y -@d set_language_code=5 {command modifier for \.{\\setlanguage}} -primitive("setlanguage",extension,set_language_code);@/ -@!@:set_language_}{\.{\\setlanguage} primitive@> -@z -@x module 1346 gets a new case -@y - set_language_code:print_esc("setlanguage"); -@z -@x module 1348 gets a new case -@y -set_language_code:@<Implement \.{\\setlanguage}@>; -@z -@x module 1356 gets a new case -@y -language_node:begin print_esc("setlanguage"); - print_int(stored_language(p)); - end; -@z -% in modules 1357 and 1358, change "close_node" to "close_node,language_node". -@x module 1362 becomes two modules -@ @<Advance \(p)past a whatsit node in the |line_break| loop@>=do_nothing -@y -@ @<Advance \(p)past a whatsit node in the \(l)|line_break| loop@>= -if subtype(cur_p)=language_node then cur_lang:=stored_language(cur_p) - -@ @<Advance \(p)past a whatsit node in the \(p)pre-hyphenation loop@>= -if subtype(s)=language_node then cur_lang:=stored_language(s) -@z and old module 1367 is moved to just before the old module 1378 -@x module 1373 gets a new case -@y -language_node:do_nothing; -@z -@x new modules before the system-dependent changes (i.e. before the old 1376) -@y -@ @<Implement \.{\\setlanguage}@>= -if abs(mode)<>hmode then report_illegal_case -else begin new_whatsit(language_node,small_node_size); - scan_int; - if cur_val<=0 then clang:=0 - else if cur_val>255 then clang:=0 - else clang:=cur_val; - stored_language(tail):=clang; - end - -@ Finally, we need a subroutine that comes into play when a character of -a non-|clang| language is being appended to the current paragraph. - -@<Declare action...@>= -procedure fix_language; -var @!l:ASCII_code; {the new current language} -begin if language<=0 then l:=0 -else if language>255 then l:=0 -else l:=language; -if l<>clang then - begin new_whatsit(language_node,small_node_size); - stored_language(tail):=l; clang:=l; - end; -end; -@z - -362. Major extension to ligature capability. -@x module 143 -a linked list of character nodes for those characters. -@y -a linked list of character nodes for all original characters that have been -deleted. (This list might be empty if the characters that generated the -ligature were retained in other nodes.) - -The |subtype| field is 0, plus 2 and/or 1 if the original source of the -ligature included implicit left and/or right boundaries. -@z -@x in module 144 add the following procedure to the existing code -@y -function new_lig_item(@!c:quarterword):pointer; -var p:pointer; {the new node} -begin p:=get_node(small_node_size); character(p):=c; lig_ptr(p):=null; -new_lig_item:=p; -end; -@z -@x module 193 -font_in_short_display:=font(lig_char(p)); -short_display(lig_ptr(p)); print_char(")"); -@y -if subtype(p)>1 then print_char("|"); -font_in_short_display:=font(lig_char(p)); short_display(lig_ptr(p)); -if odd(subtype(p)) then print_char("|"); -print_char(")"); -end -@z -@x modules 208 and 209 -@d radical=65 {square root and similar signs ( \.{\\radical} )} -@y -@d no_boundary=65 {suppress boundary ligatures ( \.{\\noboundary} )} -@d radical=66 {square root and similar signs ( \.{\\radical} )} -@z and so on, adding 1 to each definition until getting to max_command=100 -@x module 265 gets a new statement -@y -primitive("noboundary",no_boundary,0);@/ -@!@:no_boundary_}{\.{\\noboundary} primitive@> -@z -@x module 266 gets a new case -@y -no_boundary:print_esc("noboundary"); -@z -@x module 545 is entirely replaced -@y by the following new specifications: -@ The |lig_kern| array contains instructions in a simple programming language -that explains what to do for special letter pairs. Each word in this array is a -|@!lig_kern_command| of four bytes. - -\yskip\hang first byte: |skip_byte|, indicates that this is the final program - step if the byte is 128 or more, otherwise the next step is obtained by - skipping this number of intervening steps.\par -\hang second byte: |next_char|, ``if |next_char| follows the current character, - then perform the operation and stop, otherwise continue.''\par -\hang third byte: |op_byte|, indicates a ligature step if less than~128, - a kern step otherwise.\par -\hang fourth byte: |remainder|.\par -\yskip\noindent -In a kern step, an -additional space equal to |kern[256*(op_byte-128)+remainder]| is inserted -between the current character and |next_char|. This amount is -often negative, so that the characters are brought closer together -by kerning; but it might be positive. - -There are eight kinds of ligature steps, having |op_byte| codes $4a+2b+c$ where -$0\le a\le b+c$ and $0\le b,c\le1$. The character whose code is -|remainder| is inserted between the current character and |next_char|; -then the current character is deleted if $b=0$, and |next_char| is -deleted if $c=0$; then we pass over $a$~characters to reach the next -current character (which may have a ligature/kerning program of its own). - -If the very first instruction of the |lig_kern| array has |skip_byte=255|, -the |next_char| byte is the so-called right boundary character of this font; -the value of |next_char| need not lie between |bc| and~|ec|. -If the very last instruction of the |lig_kern| array has |skip_byte=255|, -there is a special ligature/kerning program for a left boundary character, -beginning at location |256*op_byte+remainder|. -The interpretation is that \TeX\ puts implicit boundary characters -before and after each consecutive string of characters from the same font. -These implicit characters do not appear in the output, but they can affect -ligatures and kerning. - -If the very first instruction of a character's |lig_kern| program has -|skip_byte>128|, the program actually begins in location -|256*op_byte+remainder|. This feature allows access to large |lig_kern| -arrays, because the first instruction must otherwise -appear in a location |<=255|. - -Any instruction with |skip_byte>128| in the |lig_kern| array must have -|256*op_byte+remainder<nl|. If such an instruction is encountered during -normal program execution, it denotes an unconditional halt; no ligature -command is performed. - -@d stop_flag=qi(128) {value indicating `\.{STOP}' in a lig/kern program} -@d kern_flag=qi(128) {op code for a kern step} -@d skip_byte(#)==#.b0 -@d next_char(#)==#.b1 -@d op_byte(#)==#.b2 -@d rem_byte(#)==#.b3 -@z -@x module 549 -@<Glob...@>= -@y -@d non_char==qi(256) {a |halfword| code that can't match a real character} -@d non_address==font_mem_size {a spurious |font_index|} - -@<Glob...@>= -@z -@x module 548 gets a new type definition -@y -@!font_index=0..font_mem_size; -@z -@x module 549 - {current \.{\\skewchar} values} -@y - {current \.{\\skewchar} values} -@!bchar_label:array[internal_font_number] of font_index; - {start of |lig_kern| program for left boundary character, - |non_address| if there is none} -@!font_bchar:array[internal_font_number] of min_quarterword..non_char; - {right boundary character, |non_char| if there is none} -@!font_false_bchar:array[internal_font_number] of min_quarterword..non_char; - {|font_bchar| if it doesn't exist in the font, otherwise |non_char|} -@z -@x module 557 -@d char_kern_end(#)==rem_byte(#)].sc -@y NOTE: Optimize kern_base_offset in your change file! It's a constant. -@d char_kern_end(#)==256*op_byte(#)+rem_byte(#)].sc -@d kern_base_offset==256*(kern_flag) -@d lig_kern_restart_end(#)==256*op_byte(#)+rem_byte(#)+32768-kern_base_offset -@d lig_kern_restart(#)==lig_kern_base[#]+lig_kern_restart_end -@z -@x module 560 -@!z:scaled; {the design size or the ``at'' size} -@y -@!bch_label:integer; {left boundary start location, or infinity} -@!bchar:0..256; {right boundary character, or 256} -@!z:scaled; {the design size or the ``at'' size} -@z -@x module 566 -kern_base[f]:=lig_kern_base[f]+nl; -exten_base[f]:=kern_base[f]+nk; -@y -kern_base[f]:=lig_kern_base[f]+nl-kern_base_offset; -exten_base[f]:=kern_base[f]+kern_base_offset+nk; -@z -@x module 573: The entire module is replaced -@y by the following code. -@ @d check_existence(#)==@t@>@;@/ - begin check_byte_range(#); - qw:=char_info(f)(#); {N.B.: not |qi(#)|} - if not char_exists(qw) then abort; - end - -@<Read ligature/kern program@>= -bch_label:=@'77777; bchar:=256; -if nl>0 then - begin for k:=lig_kern_base[f] to kern_base[f]+kern_base_offset-1 do - begin store_four_quarters(font_info[k].qqqq); - if a>128 then - begin if 256*c+d>=nl then abort; - if a=255 then if k=lig_kern_base[f] then bchar:=b; - end - else begin if b<>bchar then check_existence(b); - if c<128 then check_existence(d) {check ligature} - else if 256*(c-128)+d>=nk then abort; {check kern} - if a<128 then if k-lig_kern_base[f]+a+1>=nl then abort; - end; - end; - if a=255 then bch_label:=256*c+d; - end; -for k:=kern_base[f]+kern_base_offset to exten_base[f]-1 do - store_scaled(font_info[k].sc); -@z -@x module 574 (actually a bugfix) - if a<>0 then check_byte_range(a); - if b<>0 then check_byte_range(b); - if c<>0 then check_byte_range(c); - check_byte_range(d); -@y - if a<>0 then check_existence(a); - if b<>0 then check_existence(b); - if c<>0 then check_existence(c); - check_existence(d); -@z -@x module 576 -font_name[f]:=nom; -@y -if bch_label<nl then bchar_label[f]:=bch_label+lig_kern_base[f] -else bchar_label[f]:=non_address; -font_bchar[f]:=qi(bchar); -font_false_bchar[f]:=qi(bchar); -if bchar<=ec then if bchar>=bc then - begin qw:=char_info(f)(bchar); {N.B.: not |qi(bchar)|} - if char_exists(qw) then font_false_bchar[f]:=non_char; - end; -font_name[f]:=nom; -@z -@x module 708 (slight but optional optimization) -continue: if (qo(y)>=font_bc[g])and(qo(y)<=font_ec[g]) then - begin q:=char_info(g)(y); -@y -if (qo(y)>=font_bc[g])and(qo(y)<=font_ec[g]) then - begin continue: q:=char_info(g)(y); -@z -@x module 740 (another bugfix) - i:=char_info(f)(y); -@y - i:=char_info(f)(y); - if not char_exists(i) then goto done; -@z -@x module 741 - repeat cur_i:=font_info[a].qqqq; - if qo(next_char(cur_i))=skew_char[cur_f] then - begin if op_bit(cur_i)>=kern_flag then - s:=char_kern(cur_f)(cur_i); - goto done1; - end; - incr(a); - until stop_bit(cur_i)>=stop_flag; -@y - cur_i:=font_info[a].qqqq; - if skip_byte(cur_i)>stop_flag then - begin a:=256*(qo(op_byte(cur_i)))+rem_byte(cur_i); - cur_i:=font_info[a].qqqq; - end; - loop begin if qo(next_char(cur_i))=skew_char[cur_f] then - begin if op_byte(cur_i)>=kern_flag then - if skip_byte(cur_i)<=stop_flag then s:=char_kern(cur_f)(cur_i); - goto done1; - end; - if skip_byte(cur_i)>=stop_flag then goto done1 - else a:=a+qo(skip_byte(cur_i))+1; - cur_i:=font_info[a].qqqq; - end; -@z -@x module 749 (yet another bugfix of the same type!) -@!p,@!v,@!x,@!y,@!z:pointer; {temporary registers for box construction} -@y -@!p,@!v,@!x,@!y,@!z:pointer; {temporary registers for box construction} -@!c:quarterword;@+@!i:four_quarters; {registers for character examination} -@z -@x ibid - begin cur_c:=rem_byte(cur_i); character(nucleus(q)):=cur_c; - cur_i:=char_info(cur_f)(cur_c); -@y - begin c:=rem_byte(cur_i); i:=char_info(cur_f)(c); - if char_exists(i) then - begin cur_c:=c; cur_i:=i; character(nucleus(q)):=c; - end; -@z -@x module 752 -@!p:pointer; {temporary register for list manipulation} -@y -@!p,@!r:pointer; {temporary registers for list manipulation} -@z -@x ibid - repeat cur_i:=font_info[a].qqqq;@/ - @<If instruction |cur_i| is a kern with |cur_c|, - attach the kern after |q| and |return|; - or if it is a ligature with |cur_c|, combine - noads |q| and |p| and |goto restart|@>; - incr(a); - until stop_bit(cur_i)>=stop_flag; -@y - cur_i:=font_info[a].qqqq; - if skip_byte(cur_i)>stop_flag then - begin a:=lig_kern_restart(cur_f)(cur_i); - cur_i:=font_info[a].qqqq; - end; - loop@+ begin @<If instruction |cur_i| is a kern with |cur_c|, attach - the kern after~|q|; or if it is a ligature with |cur_c|, combine - noads |q| and~|p| appropriately; then |return| if the cursor has - moved past a noad, or |goto restart|@>; - if skip_byte(cur_i)>=stop_flag then return; - a:=a+qo(skip_byte(cur_i))+1; - cur_i:=font_info[a].qqqq; - end; -@z -@x The entire code of module 753 is revised -@y and should be replaced by the following: -@ 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 instruction |cur_i| is a kern with |cur_c|, ...@>= -if next_char(cur_i)=cur_c then if skip_byte(cur_i)<=stop_flag then - if op_byte(cur_i)>=kern_flag then - begin p:=new_kern(char_kern(cur_f)(cur_i)); - link(p):=link(q); link(q):=p; return; - end - else begin check_interrupt; {allow a way out of infinite ligature loop} - case op_byte(cur_i) of - qi(1),qi(5): character(nucleus(q)):=rem_byte(cur_i); {\.{=:\?}, \.{=:\?>}} - qi(2),qi(6): character(nucleus(p)):=rem_byte(cur_i); {\.{\?=:}, \.{\?=:>}} - qi(3),qi(7),qi(11):begin r:=new_noad; {\.{\?=:\?}, \.{\?=:\?>}, \.{\?=:\?>>}} - character(nucleus(r)):=rem_byte(cur_i); - fam(nucleus(r)):=fam(nucleus(q));@/ - link(q):=r; link(r):=p; - if op_byte(cur_i)<qi(11) then math_type(nucleus(r)):=math_char - else math_type(nucleus(r)):=math_text_char; {prevent combination} - end; - othercases begin link(q):=link(p); - character(nucleus(q)):=rem_byte(cur_i); {\.{=:}} - mem[subscr(q)]:=mem[subscr(p)]; mem[supscr(q)]:=mem[supscr(p)];@/ - free_node(p,noad_size); - end - endcases; - if op_byte(cur_i)>qi(3) then return; - math_type(nucleus(q)):=math_char; goto restart; - end -@z -@x module 862 -@!q,@!r,@!s:pointer; {miscellaneous nodes of temporary interest} -@y -@!q,@!r,@!s,@!prev_s:pointer; {miscellaneous nodes of temporary interest} -@z -@x module 892 -nodes $p_a$ and~$p_b$ in the description above are placed into variables -@y -nodes $p_{a-1}$ and~$p_b$ in the description above are placed into variables -@z -@x ibid -@!hc:array[0..65] of halfword; {word to be hyphenated} -@y -@!hc:array[0..65] of 0..256; {word to be hyphenated} -@z -@x ibid -@!hu:array[1..63] of ASCII_code; {like |hc|, before conversion to lowercase} -@y -@!hu:array[0..63] of 0..256; {like |hc|, before conversion to lowercase} -@z -@x module 894 -s:=link(cur_p); -@y -prev_s:=cur_p; s:=link(prev_s); -@z -@x module 895 -label done,found,not_found,found1,exit; -@y -label common_ending,done,found,found1,not_found,not_found+1,exit; -@z -@x module 896 - else if type(s)=ligature_node then - begin q:=lig_ptr(s); c:=qo(character(q)); hf:=font(q); - end -@y - else if type(s)=ligature_node then - if lig_ptr(s)=null then goto continue - else begin q:=lig_ptr(s); c:=qo(character(q)); hf:=font(q); - end -@z -@x ibid -continue: s:=link(s); -@y -continue: prev_s:=s; s:=link(prev_s); -@z -@x ibid -ha:=s -@y -ha:=prev_s -@z -@x module 898 -begin j:=hn; q:=lig_ptr(s); -if font(q)<>hf then goto done3; -repeat c:=qo(character(q)); -if lc_code(c)=0 then goto done3; -if j=63 then goto done3; -incr(j); hu[j]:=c; hc[j]:=lc_code(c);@/ -q:=link(q); -until q=null; -@y -begin if font(lig_char(s))<>hf then goto done3; -j:=hn; q:=lig_ptr(s); -while q>null do - begin c:=qo(character(q)); - if lc_code(c)=0 then goto done3; - if j=63 then goto done3; - incr(j); hu[j]:=c; hc[j]:=lc_code(c);@/ - q:=link(q); - end; -@z -@x module 900 gets three new global variables -@y -@!init_list:pointer; {list of punctuation characters preceding the word} -@!init_lig:boolean; {does |init_list| represent a ligature?} -@!init_lft:boolean; {if so, did the ligature involve a left boundary?} -@z -@x module 901 -@!q,@!r,@!s:pointer; {temporary registers for list manipulation} -@y -@!p,@!q,@!r,@!s:pointer; {temporary registers for list manipulation} -@!bchar:halfword; {right boundary character of hyphenated word, or |non_char|} -@z -@x module 903 should be entirely replaced -@y by the following: -@ If hyphens are in fact going to be inserted, \TeX\ first deletes the -subsequence of nodes between |ha| and~|hb|. An attempt is made to -preserve the effect that implicit boundary characters and punctuation marks -had on ligatures inside the hyphenated word, by storing a left boundary or -preceding character in |hu[0]| and by storing a possible right boundary -in |bchar|. We set |j:=0| if |hu[0]| is to be part of the reconstruction; -otherwise |j:=1|. -The variable |s| will point to the tail of the current hlist, and -|q| will point to the node following |hb|, so that -things can be hooked up after we reconstitute the hyphenated word. - -@<Replace nodes |ha..hb| by a sequence of nodes...@>= -q:=link(hb); link(hb):=null; r:=link(ha); link(ha):=null; bchar:=non_char; -if type(hb)=ligature_node then if odd(subtype(hb)) then - bchar:=font_bchar[hf]; -if is_char_node(ha) then - begin init_list:=ha; init_lig:=false; hu[0]:=qo(character(ha)); - end -else if type(ha)=ligature_node then - begin init_list:=lig_ptr(ha); init_lig:=true; init_lft:=(subtype(ha)>1); - hu[0]:=qo(character(lig_char(ha))); - if init_list=null then if init_lft then - begin hu[0]:=256; init_lig:=false; - end; {in this case a ligature will be reconstructed from scratch} - free_node(ha,small_node_size); - end -else goto not_found+1; {no punctuation found} -s:=cur_p; {we have |cur_p<>ha| because |type(cur_p)=glue_node|} -while link(s)<>ha do s:=link(s); -j:=0; goto common_ending; -not_found+1: j:=1; s:=ha; init_list:=null; -if not is_char_node(r) then if type(r)=ligature_node then - if subtype(r)>1 then - begin j:=0; hu[0]:=256; init_lig:=false; - end; -common_ending: flush_node_list(r); -@<Reconstitute nodes for the hyphenated word, inserting discretionary hyphens@>; -flush_list(init_list) -@z -@x modules 905--911 are entirely replaced -@y by the following new code: -Still further complications arise in the presence of ligatures that do not -delete the original characters. When punctuation precedes the word being -hyphenated, \TeX's method is not perfect under all possible scenarios, -because punctuation marks and letters can propagate information back and forth. -For example, suppose the original pre-hyphenation pair -\.{*a} changes to \.{*y} via a \.{\?=:} ligature, which changes to \.{xy} -via a \.{=:\?} ligature; if $p_{a-1}=\.x$ and $p_a=\.y$, the reconstitution -procedure isn't smart enough to obtain \.{xy} again. In such cases the -font designer should include a ligature that goes from \.{xa} to \.{xy}. - -@ The processing is facilitated by a subroutine called |reconstitute|. Given -a string of characters $x_j\ldots x_n$, there is a smallest index $m\ge j$ -such that the ``translation'' of $x_j\ldots x_n$ by ligatures and kerning -has the form $y_1\ldots y_t$ followed by the translation of $x_{m+1}\ldots x_n$, -where $y_1\ldots y_t$ is some nonempty sequence of character, ligature, and -kern nodes. We call $x_j\ldots x_m$ a ``cut prefix'' of $x_j\ldots x_n$. -For example, if $x_1x_2x_3=\.{fly}$, and if the font contains `fl' as a -ligature and a kern between `fl' and `y', then $m=2$, $y=2$, and $y_1$ will -be a ligature node for `fl' followed by an appropriate kern node~$y_2$. -In the most common case, $x_j$~forms no ligature with $x_{j+1}$ and we -simply have $m=j$, $y_1=x_j$. If $m<n$ we can repeat the procedure on -$x_{m+1}\ldots x_n$ until the entire translation has been found. - -The |reconstitute| function returns the integer $m$ and puts the nodes -$y_1\ldots y_t$ into a linked list starting at |link(hold_head)|, -getting the input $x_j\ldots x_n$ from the |hu| array. If $x_j=256$, -we consider $x_j$ to be an implicit left boundary character; in this -case |j| must be strictly less than~|n|. There is a -parameter |bchar|, which is either 256 or an implicit right boundary character -assumed to be present just following~$x_n$. (The value |hu[n+1]| is never -explicitly examined, but the algorithm imagines that |bchar| is there.) - -If there exists an index |k| in the range $j\le k\le m$ such that |hyf[k]| -is odd and such that the result of reconstitute would have been different -if $x_{k+1}$ had been |hchar|, then |reconstitute| sets |hyphen_passed| -to the smallest such~|k|. Otherwise it sets |hyphen_passed| to zero. - -A special convention is used in the case |j=0|: Then we assume that the -translation of |hu[0]| appears in a special list of charnodes starting at -|init_list|; moreover, if |init_lig| is |true|, then |hu[0]| will be -a ligature character, involving a left boundary if |init_lft| is |true|. -This facility is provided for cases when a hyphenated -word is preceded by punctuation (like single or double quotes) that might -affect the translation of the beginning of the word. - -@<Glob...@>= -@!hyphen_passed:small_number; {first hyphen in a ligature, if any} - -@ @<Declare the function called |reconstitute|@>= -function reconstitute(@!j,@!n:small_number;@!bchar,@!hchar:halfword): - small_number; -label continue,done; -var @!p:pointer; {temporary register for list manipulation} -@!t:pointer; {a node being appended to} -@!q:four_quarters; {character information or a lig/kern instruction} -@!cur_rh:halfword; {hyphen character for ligature testing} -@!test_char:halfword; {hyphen or other character for ligature testing} -@!w:scaled; {amount of kerning} -@!k:font_index; {position of current lig/kern instruction} -begin hyphen_passed:=0; t:=hold_head; w:=0; link(hold_head):=null; - {at this point |ligature_present=lft_hit=rt_hit=false|} -@<Set up data structures with the cursor following position |j|@>; -continue:@<If there's a ligature or kern at the cursor position, update the data - structures, possibly advancing~|j|; continue until the cursor moves@>; -@<Append a ligature and/or kern to the translation; - |goto continue| if the stack of inserted ligatures is nonempty@>; -reconstitute:=j; -end; - -@ The reconstitution procedure shares many of the global data structures -by which \TeX\ has processed the words before they were hyphenated. -There is an implied ``cursor'' between characters |cur_l| and |cur_r|; -these characters will be tested for possible ligature activity. If -|ligature_present| then |cur_l| is a ligature character formed from the -original characters following |cur_q| in the current translation list. -There is a ``ligature stack'' between the cursor and character |j+1|, -consisting of pseudo-ligature nodes linked together by their |link| fields. -This stack is normally empty unless a ligature command has created a new -character that will need to be processed later. A pseudo-ligature is -a special node having a |character| field that represents a potential -ligature and a |lig_ptr| field that points to a |char_node| or is |null|. -We have -$$|cur_r|=\cases{|character(lig_stack)|,&if |lig_stack>null|;\cr - |qi(hu[j+1])|,&if |lig_stack=null| and |j<n|;\cr - bchar,&if |lig_stack=null| and |j=n|.\cr}$$ - -@<Glob...@>= -@!cur_l,@!cur_r:halfword; {characters before and after the cursor} -@!cur_q:pointer; {where a ligature should be detached} -@!lig_stack:pointer; {unfinished business to the right of the cursor} -@!ligature_present:boolean; {should a ligature node be made for |cur_l|?} -@!lft_hit,@!rt_hit:boolean; {did we hit a ligature with a boundary character?} - -@ @d append_charnode_to_t(#)== begin link(t):=get_avail; t:=link(t); - font(t):=hf; character(t):=#; - end -@d set_cur_r==begin if j<n then cur_r:=qi(hu[j+1])@+else cur_r:=bchar; - if odd(hyf[j]) then cur_rh:=hchar@+else cur_rh:=non_char; - end - -@<Set up data structures with the cursor following position |j|@>= -cur_l:=qi(hu[j]); cur_q:=t; -if j=0 then - begin ligature_present:=init_lig; p:=init_list; - if ligature_present then lft_hit:=init_lft; - while p>null do - begin append_charnode_to_t(character(p)); p:=link(p); - end; - end -else if cur_l<non_char then append_charnode_to_t(cur_l); -lig_stack:=null; set_cur_r - -@ We may want to look at the lig/kern program twice, once for a hyphen -and once for a normal letter. (The hyphen might appear after the letter -in the program, so we'd better not try to look for both at once.) - -@<If there's a ligature or kern at the cursor position, update...@>= -if cur_l=non_char then - begin k:=bchar_label[hf]; - if k=non_address then goto done@+else q:=font_info[k].qqqq; - end -else begin q:=char_info(hf)(cur_l); - if char_tag(q)<>lig_tag then goto done; - k:=lig_kern_start(hf)(q); q:=font_info[k].qqqq; - if skip_byte(q)>stop_flag then - begin k:=lig_kern_restart(hf)(q); q:=font_info[k].qqqq; - end; - end; {now |k| is the starting address of the lig/kern program} -if cur_rh<non_char then test_char:=cur_rh@+else test_char:=cur_r; -loop@+begin if next_char(q)=test_char then if skip_byte(q)<=stop_flag then - if cur_rh<non_char then - begin hyphen_passed:=j; hchar:=non_char; cur_rh:=non_char; - goto continue; - end - else begin if hchar<non_char then if odd(hyf[j]) then - begin hyphen_passed:=j; hchar:=non_char; - end; - if op_byte(q)<kern_flag then - @<Carry out a ligature replacement, updating the cursor structure - and possibly advancing~|j|; |goto continue| if the cursor doesn't - advance, otherwise |goto done|@>; - w:=char_kern(hf)(q); goto done; {this kern will be inserted below} - end; - if skip_byte(q)>=stop_flag then - if cur_rh=non_char then goto done - else begin cur_rh:=non_char; goto continue; - end; - k:=k+qo(skip_byte(q))+1; q:=font_info[k].qqqq; - end; -done: - -@ @d wrap_lig(#)==if ligature_present then - begin p:=new_ligature(hf,cur_l,link(cur_q)); - if lft_hit then - begin subtype(p):=2; lft_hit:=false; - end; - if # then if lig_stack=null then - begin incr(subtype(p)); rt_hit:=false; - end; - link(cur_q):=p; t:=p; ligature_present:=false; - end -@d pop_lig_stack==begin if lig_ptr(lig_stack)>null then - begin link(t):=lig_ptr(lig_stack); {this is a charnode for |hu[j+1]|} - t:=link(t); incr(j); - end; - p:=lig_stack; lig_stack:=link(p); free_node(p,small_node_size); - if lig_stack=null then set_cur_r@+else cur_r:=character(lig_stack); - end {if |lig_stack| isn't |null| we have |cur_rh=non_char|} - -@<Append a ligature and/or kern to the translation...@>= -wrap_lig(rt_hit); -if w<>0 then - begin link(t):=new_kern(w); t:=link(t); w:=0; - end; -if lig_stack>null then - begin cur_q:=t; cur_l:=character(lig_stack); ligature_present:=true; - pop_lig_stack; goto continue; - end - -@ @<Carry out a ligature replacement, updating the cursor structure...@>= -begin if cur_l=non_char then lft_hit:=true; -if j=n then if lig_stack=null then rt_hit:=true; -check_interrupt; {allow a way out in case there's an infinite ligature loop} -case op_byte(q) of -qi(1),qi(5):begin cur_l:=rem_byte(q); {\.{=:\?}, \.{=:\?>}} - ligature_present:=true; - end; -qi(2),qi(6):begin cur_r:=rem_byte(q); {\.{\?=:}. \.{\?=:>}} - if lig_stack>null then character(lig_stack):=cur_r - else begin lig_stack:=new_lig_item(cur_r); - if j=n then bchar:=non_char - else begin p:=get_avail; lig_ptr(lig_stack):=p; - character(p):=qi(hu[j+1]); font(p):=hf; - end; - end; - end; -qi(3):begin cur_r:=rem_byte(q); {\.{\?=:\?}} - p:=lig_stack; lig_stack:=new_lig_item(cur_r); link(lig_stack):=p; - end; -qi(7),qi(11):begin wrap_lig(false); {\.{\?=:\?>}, \.{\?=:\?>>}} - cur_q:=t; cur_l:=rem_byte(q); ligature_present:=true; - end; -othercases begin cur_l:=rem_byte(q); ligature_present:=true; {\.{=:}} - if lig_stack>null then pop_lig_stack - else if j=n then goto done - else begin append_charnode_to_t(cur_r); incr(j); set_cur_r; - end; - end -endcases; -if op_byte(q)>qi(4) then if op_byte(q)<>qi(7) then goto done; -goto continue; -end -@z -@x module 912 -@!c:ASCII_code; {character temporarily replaced by a hyphen} -@y -@!c:ASCII_code; {character temporarily replaced by a hyphen} -@!c_loc:0..63; {where that character came from} -@!r_count:integer; {replacement count for discretionary} -@z -@x modules 913--918 are to be completely replaced -@y by the following code: -@ When the following code is performed, |hyf[0]| and |hyf[hn]| will be zero. - -@<Reconstitute nodes for the hyphenated word...@>= -repeat l:=j; j:=reconstitute(j,hn,bchar,qi(hyf_char))+1; -if hyphen_passed=0 then - begin link(s):=link(hold_head); - while link(s)>null do s:=link(s); - if odd(hyf[j-1]) then - begin l:=j; hyphen_passed:=j-1; link(hold_head):=null; - end; - end; -if hyphen_passed>0 then - @<Create and append a discretionary node as an alternative to the - unhyphenated word, and continue to develop both branches until they - become equivalent@>; -until j>hn; -link(s):=q - -@ @d advance_major_tail==begin major_tail:=link(major_tail); incr(r_count); - end - -@<Create and append a discretionary node as an alternative...@>= -begin r:=get_node(small_node_size); -link(r):=link(hold_head); type(r):=disc_node; -major_tail:=r; r_count:=0; -while link(major_tail)>null do advance_major_tail; -i:=hyphen_passed; -@<Put the \(c)characters |hu[l..i]| and a hyphen into |pre_break(r)|@>; -@<Put the \(c)characters |hu[i+1..@,]| into |post_break(r)|, appending to this - list and to |major_tail| until synchronization has been achieved@>; -@<Move pointer |s| to the end of the current list, and set |replace_count(r)| - appropriately@>; -end - -@ The new hyphen might combine with the previous character via ligature -or kern. At this point we have |l-1<=i<=j| and |i<hn|. - -@<Put the \(c)characters |hu[l..i]| and a hyphen into |pre_break(r)|@>= -minor_tail:=null; pre_break(r):=null; hyf_node:=new_character(hf,hyf_char); -if hyf_node<>null then - begin incr(i); c:=hu[i]; hu[i]:=hyf_char; free_avail(hyf_node); - end; -while l<=i do - begin l:=reconstitute(l,i,font_bchar[hf],non_char)+1; - if link(hold_head)>null then - begin if minor_tail=null then pre_break(r):=link(hold_head) - else link(minor_tail):=link(hold_head); - minor_tail:=link(hold_head); - while link(minor_tail)>null do minor_tail:=link(minor_tail); - end; - end; -if hyf_node<>null then - begin hu[i]:=c; {restore the character in the hyphen position} - l:=i; decr(i); - end - -@ The synchronization algorithm begins with |l=i+1<=j|. - -@<Put the \(c)characters |hu[i+1..@,]| into |post_break(r)|...@>= -minor_tail:=null; post_break(r):=null; c_loc:=0; -if bchar_label[hf]<non_address then {put left boundary at beginning of new line} - begin decr(l); c:=hu[l]; c_loc:=l; hu[l]:=256; - end; -while l<j do - begin repeat l:=reconstitute(l,hn,bchar,non_char)+1; - if c_loc>0 then - begin hu[c_loc]:=c; c_loc:=0; - end; - if link(hold_head)>null then - begin if minor_tail=null then post_break(r):=link(hold_head) - else link(minor_tail):=link(hold_head); - minor_tail:=link(hold_head); - while link(minor_tail)>null do minor_tail:=link(minor_tail); - end; - until l>=j; - while l>j do - @<Append characters of |hu[j..@,]| to |major_tail|, advancing~|j|@>; - end - -@ @<Append characters of |hu[j..@,]|...@>= -begin j:=reconstitute(j,hn,bchar,non_char)+1; -link(major_tail):=link(hold_head); -while link(major_tail)>null do advance_major_tail; -end - -@ Ligature insertion can cause a word to grow exponentially in size. Therefore -we must test the size of |r_count| here, even though the hyphenated text -was at most 63 characters long. - -@<Move pointer |s| to the end of the current list...@>= -if r_count>127 then {we have to forget the discretionary hyphen} - begin link(s):=link(r); link(r):=null; flush_node_list(r); - end -else begin link(s):=r; replace_count(r):=r_count; - end; -s:=major_tail -@z -@x module 1030 -@d main_loop=70 {go here to typeset |cur_chr| in the current font} -@d main_loop_1=71 {like |main_loop|, but |(f,c)| = current font and char} -@d main_loop_2=72 {like |main_loop_1|, but |c| is known to be in range} -@d main_loop_3=73 {like |main_loop_2|, but several variables are set up} -@d append_normal_space=74 {go here to append a normal space between words} -@y -@d main_loop=70 {go here to typeset a string of consecutive characters} -@d main_loop_wrapup=80 {go here to finish a character or ligature} -@d main_loop_move=90 {go here to advance the ligature cursor} -@d main_loop_move_lig=95 {same, when advancing past a generated ligature} -@d main_loop_lookahead=100 {go here to bring in another character, if any} -@d main_lig_loop=110 {go here to check for ligatures or kerning} -@d append_normal_space=120 {go here to append a normal space between words} -@z -@x ibid -label big_switch,reswitch,main_loop,main_loop_1,main_loop_2,main_loop_3, -@y -label big_switch,reswitch,main_loop,main_loop_wrapup, - main_loop_move,main_loop_move+1,main_loop_move+2,main_loop_move_lig, - main_loop_lookahead,main_loop_lookahead+1, - main_lig_loop,main_lig_loop+1,main_lig_loop+2, -@z -@x ibid -@<Local variables for the inner loop of |main_control|@>@; -@y -@z -@x ibid -hmode+char_num: begin scan_char_num; cur_chr:=cur_val; goto main_loop; - end; -@y -hmode+char_num: begin scan_char_num; cur_chr:=cur_val; goto main_loop;@+end; -hmode+no_boundary: begin get_x_token; - if (cur_cmd=letter)or(cur_cmd=other_char)or(cur_cmd=char_given)or - (cur_cmd=char_num) then cancel_boundary:=true; - goto reswitch; - end; -@z -@x modules 1032--1040 are all to be replaced -@y by the following code: -@ The following part of the program was first written in a structured -manner, according to the philosophy that ``premature optimization is -the root of all evil.'' Then it was rearranged into pieces of -spaghetti so that the most common actions could proceed with little or -no redundancy. - -The original unoptimized form of this algorithm resembles the -|reconstitute| procedure, which was described earlier in connection with -hyphenation. Again we have an implied ``cursor`` between characters -|cur_l| and |cur_r|. The main difference is that the |lig_stack| can now -contain a charnode as well as pseudo-ligatures; that stack is now -usually nonempty, because the next character of input (if any) has been -appended to it. In |main_control| we have -$$|cur_r|=\cases{|character(lig_stack)|,&if |lig_stack>null|;\cr - |font_bchar[cur_font]|,&otherwise.\cr}$$ -Several additional global variables are needed. - -@<Glob...@>= -@!main_f:internal_font_number; {the current font} -@!main_i:four_quarters; {character information bytes for |cur_l|} -@!main_j:four_quarters; {ligature/kern command} -@!main_k:font_index; {index into |font_info|} -@!main_p:pointer; {temporary register for list manipulation} -@!main_s:integer; {space factor value} -@!bchar:halfword; {right boundary character of current font, or |non_char|} -@!false_bchar:halfword; {nonexistent character matching |bchar|, or |non_char|} -@!cancel_boundary:boolean; {should the left boundary be ignored?} -@!ins_disc:boolean; {should we insert a discretionary node?} - -@ The boolean variables of the main loop are normally false, and always reset -to false before the loop is left. That saves us the extra work of initializing -each time. - -@<Set init...@>= -ligature_present:=false; cancel_boundary:=false; lft_hit:=false; rt_hit:=false; -ins_disc:=false; - -@ We leave |space_factor| unchanged if |sf_code(cur_chr)=0|; otherwise we -set it to |sf_code(cur_chr)|, except that the space factor never changes -from a value less than 1000 to a value exceeding 1000. The most common -case is |sf_code(cur_chr)=1000|, so we want that case to be fast. - -The overall structure of the main loop is presented here. Some program labels -are inside the individual sections. - -@d adjust_space_factor==@t@>@;@/ - main_s:=sf_code(cur_chr); - if main_s=1000 then space_factor:=1000 - else if main_s<1000 then - begin if main_s>0 then space_factor:=main_s; - end - else if space_factor<1000 then space_factor:=1000 - else space_factor:=main_s - -@<Append character |cur_chr|...@>= -adjust_space_factor;@/ -main_f:=cur_font; -bchar:=font_bchar[main_f]; false_bchar:=font_false_bchar[main_f]; -if mode>0 then if language<>clang then fix_language; -fast_get_avail(lig_stack); font(lig_stack):=main_f; cur_l:=qi(cur_chr); -character(lig_stack):=cur_l;@/ -cur_q:=tail; -if cancel_boundary then - begin cancel_boundary:=false; main_k:=non_address; - end -else main_k:=bchar_label[main_f]; -if main_k=non_address then goto main_loop_move+2; {no left boundary processing} -cur_r:=cur_l; cur_l:=non_char; -goto main_lig_loop+1; {begin with cursor after left boundary} -@# -main_loop_wrapup:@<Make a ligature node, if |ligature_present|; - insert a null discretionary, if appropriate@>; -main_loop_move:@<If the cursor is immediately followed by the right boundary, - |goto reswitch|; if it's followed by an invalid character, |goto big_switch|; - otherwise move the cursor one step to the right and |goto main_lig_loop|@>; -main_loop_lookahead:@<Look ahead for another character, or leave |lig_stack| - empty if there's none there@>; -main_lig_loop:@<If there's a ligature/kern command relevant to |cur_l| and - |cur_r|, adjust the text appropriately; exit to |main_loop_wrapup|@>; -main_loop_move_lig:@<Move the cursor past a pseudo-ligature, then - |goto main_loop_lookahead| or |main_lig_loop|@> - -@ If the current horizontal list is empty, the reference to |character(tail)| -here is not strictly legal, since |tail| will be a node freshly returned by -|get_avail|. But this should cause no problem on most implementations, and we -do want the inner loop to be fast. -@^dirty Pascal@> - -A discretionary break is not inserted for an explicit hyphen when we are in -restricted horizontal mode. In particular, this avoids putting discretionary -nodes inside of other discretionaries. - -@d pack_lig(#)== {the parameter is either |rt_hit| or |false|} - begin main_p:=new_ligature(main_f,cur_l,link(cur_q)); - if lft_hit then - begin subtype(main_p):=2; lft_hit:=false; - end; - if # then if lig_stack=null then - begin incr(subtype(main_p)); rt_hit:=false; - end; - link(cur_q):=main_p; tail:=main_p; ligature_present:=false; - end - -@d wrapup(#)==if cur_l<non_char then - begin if character(tail)=qi(hyphen_char[main_f]) then if link(cur_q)>null then - ins_disc:=true; - if ligature_present then pack_lig(#); - if ins_disc then - begin ins_disc:=false; - if mode>0 then tail_append(new_disc); - end; - end - -@<Make a ligature node, if |ligature_present|;...@>= -wrapup(rt_hit) - -@ @<If the cursor is immediately followed by the right boundary...@>= -if lig_stack=null then goto reswitch; -cur_q:=tail; cur_l:=cur_r; {or |character(lig_stack)|} -main_loop_move+1:if not is_char_node(lig_stack) then goto main_loop_move_lig; -main_loop_move+2:if(cur_chr<font_bc[main_f])or(cur_chr>font_ec[main_f]) then - begin char_warning(main_f,cur_chr); free_avail(lig_stack); goto big_switch; - end; -main_i:=char_info(main_f)(cur_l); -if not char_exists(main_i) then - begin char_warning(main_f,cur_chr); free_avail(lig_stack); goto big_switch; - end; -tail_append(lig_stack) {|main_loop_lookahead| is next} - -@ Here we are at |main_loop_move_lig|. -When we begin this code we have |cur_l=character(lig_stack)| and |cur_q=tail|. - -@<Move the cursor past a pseudo-ligature...@>= -main_p:=lig_ptr(lig_stack); -if main_p>null then tail_append(main_p); -temp_ptr:=lig_stack; lig_stack:=link(temp_ptr); -free_node(temp_ptr,small_node_size); -main_i:=char_info(main_f)(cur_l); ligature_present:=true; -if lig_stack=null then - if main_p>null then goto main_loop_lookahead - else cur_r:=bchar -else cur_r:=character(lig_stack); -goto main_lig_loop - -@ The result of \.{\\char} can participate in a ligature or kern, so we must -look ahead for it. - -@<Look ahead for another character...@>= -get_next; {set only |cur_cmd| and |cur_chr|, for speed} -if cur_cmd=letter then goto main_loop_lookahead+1; -if cur_cmd=other_char then goto main_loop_lookahead+1; -if cur_cmd=char_given then goto main_loop_lookahead+1; -x_token; {now expand and set |cur_cmd|, |cur_chr|, |cur_tok|} -if cur_cmd=letter then goto main_loop_lookahead+1; -if cur_cmd=other_char then goto main_loop_lookahead+1; -if cur_cmd=char_given then goto main_loop_lookahead+1; -if cur_cmd=char_num then - begin scan_char_num; cur_chr:=cur_val; goto main_loop_lookahead+1; - end; -if cur_cmd=no_boundary then bchar:=non_char; -cur_r:=bchar; lig_stack:=null; goto main_lig_loop; -main_loop_lookahead+1: adjust_space_factor; -fast_get_avail(lig_stack); font(lig_stack):=main_f; -cur_r:=qi(cur_chr); character(lig_stack):=cur_r; -if cur_r=false_bchar then cur_r:=non_char {this prevents spurious ligatures} - -@ Even though comparatively few characters have a lig/kern program, several -of the instructions here count as part of \TeX's inner loop, since a -potentially long sequential search must be performed. For example, tests with -Computer Modern Roman showed that about 40 per cent of all characters -actually encountered in practice had a lig/kern program, and that about four -lig/kern commands were investigated for every such character. - -At the beginning of this code we have |main_i=char_info(main_f)(cur_l)|. - -@<If there's a ligature/kern command...@>= -if char_tag(main_i)<>lig_tag then goto main_loop_wrapup; -main_k:=lig_kern_start(main_f)(main_i); main_j:=font_info[main_k].qqqq; -if skip_byte(main_j)<=stop_flag then goto main_lig_loop+2; -main_k:=lig_kern_restart(main_f)(main_j); -main_lig_loop+1:main_j:=font_info[main_k].qqqq; -main_lig_loop+2:if next_char(main_j)=cur_r then - if skip_byte(main_j)<=stop_flag then - @<Do ligature or kern command, returning to |main_lig_loop| - or |main_loop_wrapup| or |main_loop_move|@>; -if skip_byte(main_j)=qi(0) then incr(main_k) -else begin if skip_byte(main_j)>=stop_flag then goto main_loop_wrapup; - main_k:=main_k+qo(skip_byte(main_j))+1; - end; -goto main_lig_loop+1 - -@ When a ligature or kern instruction matches a character, we know from -|read_font_info| that the character exists in the font, even though we -haven't verified its existence in the normal way. - -This section could be made into a subroutine, if the code inside -|main_control| needs to be shortened. - -\chardef\?='174 % vertical line to indicate character retention - -@<Do ligature or kern command...@>= -begin if op_byte(main_j)>=kern_flag then - begin wrapup(rt_hit); - tail_append(new_kern(char_kern(main_f)(main_j))); goto main_loop_move; - end; -if cur_l=non_char then lft_hit:=true -else if lig_stack=null then rt_hit:=true; -check_interrupt; {allow a way out in case there's an infinite ligature loop} -case op_byte(main_j) of -qi(1),qi(5):begin cur_l:=rem_byte(main_j); {\.{=:\?}, \.{=:\?>}} - main_i:=char_info(main_f)(cur_l); ligature_present:=true; - end; -qi(2),qi(6):begin cur_r:=rem_byte(main_j); {\.{\?=:}, \.{\?=:>}} - if lig_stack=null then {right boundary character is being consumed} - begin lig_stack:=new_lig_item(cur_r); bchar:=non_char; - end - else if is_char_node(lig_stack) then {|link(lig_stack)=null|} - begin main_p:=lig_stack; lig_stack:=new_lig_item(cur_r); - lig_ptr(lig_stack):=main_p; - end - else character(lig_stack):=cur_r; - end; -qi(3):begin cur_r:=rem_byte(main_j); {\.{\?=:\?}} - main_p:=lig_stack; lig_stack:=new_lig_item(cur_r); - link(lig_stack):=main_p; - end; -qi(7),qi(11):begin wrapup(false); {\.{\?=:\?>}, \.{\?=:\?>>}} - cur_q:=tail; cur_l:=rem_byte(main_j); - main_i:=char_info(main_f)(cur_l); ligature_present:=true; - end; -othercases begin cur_l:=rem_byte(main_j); ligature_present:=true; {\.{=:}} - if lig_stack=null then goto main_loop_wrapup - else goto main_loop_move+1; - end -endcases; -if op_byte(main_j)>qi(4) then - if op_byte(main_j)<>qi(7) then goto main_loop_wrapup; -if cur_l<non_char then goto main_lig_loop; -main_k:=bchar_label[main_f]; goto main_lig_loop+1; -end -@z -% HINTS for making main_control shorter if you need to conserve space: -% (1) make pack_lig(#) a procedure call instead of a macro call -% (2) make the code of @<Do ligature...@> a function that returns one of -% four values; you goto a label based on the value returned. -@x module 1042 -begin p:=font_glue[cur_font]; -if p=null then - begin f:=cur_font; p:=new_spec(zero_glue); k:=param_base[f]+space_code; - width(p):=font_info[k].sc; {that's |space(f)|} - stretch(p):=font_info[k+1].sc; {and |space_stretch(f)|} - shrink(p):=font_info[k+2].sc; {and |space_shrink(f)|} - font_glue[f]:=p; -@y -begin main_p:=font_glue[cur_font]; -if main_p=null then - begin main_p:=new_spec(zero_glue); main_k:=param_base[cur_font]+space_code; - width(main_p):=font_info[main_k].sc; {that's |space(cur_font)|} - stretch(main_p):=font_info[main_k+1].sc; {and |space_stretch(cur_font)|} - shrink(main_p):=font_info[main_k+2].sc; {and |space_shrink(cur_font)|} - font_glue[cur_font]:=main_p; -@z -@x module 1045 -any_mode(relax),vmode+spacer,mmode+spacer,mmode+no_boundary:do_nothing; -@y -any_mode(relax),vmode+spacer,mmode+spacer:do_nothing; -@z -@x module 1090 - vmode+ex_space:@t@>@;@/ -@y - vmode+ex_space,vmode+no_boundary:@t@>@;@/ -@z -@x module 1322 -dump_int(font_glue[k]);@/ -@y -dump_int(font_glue[k]);@/ -dump_int(bchar_label[k]); -dump_int(font_bchar[k]); -dump_int(font_false_bchar[k]);@/ -@z -@x module 1323 -undump(min_halfword)(lo_mem_max)(font_glue[k]);@/ -@y -undump(min_halfword)(lo_mem_max)(font_glue[k]);@/ -undump(0)(font_mem_size)(bchar_label[k]); -undump(min_quarterword)(non_char)(font_bchar[k]); -undump(min_quarterword)(non_char)(font_false_bchar[k]); -@z - -363. New \inputlineno feature desired by Spivak -@x module 416 gets a new definition and a new statement -@y -@d input_line_no_code=glue_val+1 {code for \.{\\inputlineno}} -primitive("inputlineno",last_item,input_line_no_code); -@!@:input_line_no_}{\.{\\inputlineno} primitive@> -@z and module 417 changes in the obvious way -@x module 424 gets new code at the beginning -@y -if cur_chr>glue_val then - begin cur_val:=line; cur_val_level:=int_val; - end -else -@z - -364. New feature \holdinginserts suggested by Mittelbach. -@x modules 236--238 get a new integer parameter -@d int_pars=53 {total number of integer parameters} -@y -@d holding_inserts_code=53 {do not remove insertion nodes from \.{\\box255}} -@d int_pars=54 {total number of integer parameters} -@z and appropriate further lines are added to match all the other parameters -@x module 1014 -@<Prepare all the boxes involved in insertions to act as queues@>; -q:=hold_head; link(q):=null; prev_p:=page_head; p:=link(prev_p); -while p<>best_page_break do - begin if type(p)=ins_node then @<Either insert the material - specified by node |p| into the appropriate box, or - hold it for the next page; also delete node |p| from - the current page@> -@y -if holding_inserts<=0 then - @<Prepare all the boxes involved in insertions to act as queues@>; -q:=hold_head; link(q):=null; prev_p:=page_head; p:=link(prev_p); -while p<>best_page_break do - begin if type(p)=ins_node then - begin if holding_inserts<=0 then - @<Either insert the material specified by node |p| into the - appropriate box, or hold it for the next page; - also delete node |p| from the current page@>; - end -@z -% also insert begin...end around the Pascal code of module 1018 - -365. New \badness feature (which I'd been resisting for years) -@x module 416 gets a new definition and a new statement -@y -@d badness_code=glue_val+2 {code for \.{\\badness}} -primitive("badness",last_item,badness_code); -@!@:badness_}{\.{\\badness} primitive@> -@z and module 417 changes in the obvious way -@x module 424 (the new code just added in #363) - begin cur_val:=line; cur_val_level:=int_val; -@y - begin if cur_chr=input_line_no_code then cur_val:=line - else cur_val:=last_badness; {|cur_chr=badness_code|} - cur_val_level:=int_val; -@z -@x module 646 gets a new global variable -@y -@!last_badness:integer; {badness of the most recently packaged box} -@z -@x module 648 -@ @<Set init...@>=adjust_tail:=null; -@y -@ @<Set init...@>=adjust_tail:=null; last_badness:=0; -@z -@x modules 649 and 668 -@!b:integer; {badness of the new box} -begin r:=get_node(box_node_size); type(r):=hlist_node; -@y (except it's vlist_node in 668) -begin last_badness:=0; r:=get_node(box_node_size); type(r):=hlist_node; -@z (except it's vlist_node in 668) -% change b to last_badness in modules 660&674 (4 times), 667&678 (3 times) -@x modules 658 and 673 -if (hbadness<inf_bad)and(o=normal)and(list_ptr(r)<>null) then -@y (except it's vbadness in 673) -if o=normal then if list_ptr(r)<>null then -@z -@x modules 664 and 676 - begin set_glue_ratio_one(glue_set(r)); {this is the maximum shrinkage} -@y - begin last_badness:=1000000; - set_glue_ratio_one(glue_set(r)); {use the maximum shrinkage} -@z -@x ibid -else if (hbadness<100)and(o=normal)and(list_ptr(r)<>null) then -@y (except it's vbadness in 676) -else if o=normal then if list_ptr(r)<>null then -@z - -366. New \emergencystretch feature -@x modules 247--248 get a new dimen parameter -@d dimen_pars=20 {total number of dimension parameters} -@y -@d emergency_stretch_code=20 {reduces badnesses on final pass of line-breaking} -@d dimen_pars=21 {total number of dimension parameters} -@z and appropriate further lines are added to match all the other parameters -@x module 828 -@!second_pass:boolean; {is this our second attempt to break this paragraph?} -@y -@!second_pass:boolean; {is this our second attempt to break this paragraph?} -@!final_pass:boolean; {is this our final attempt to break this paragraph?} -@z -% change second_pass to final_pass in modules 854 and 873 -@x module 863 - second_pass:=false; - end -else begin threshold:=tolerance; second_pass:=true; -@y - second_pass:=false; final_pass:=false; - end -else begin threshold:=tolerance; second_pass:=true; - final_pass:=(emergency_stretch<=0); -@z -@x ibid - @!stat if tracing_paragraphs>0 then print_nl("@@secondpass");@;@+tats@/ - threshold:=tolerance; second_pass:=true; {if at first you don't - succeed, \dots} -@y - if not second_pass then - begin@!stat if tracing_paragraphs>0 then print_nl("@@secondpass");@;@+tats@/ - threshold:=tolerance; second_pass:=true; final_pass:=(emergency_stretch<=0); - end {if at first you don't succeed, \dots} - else begin @!stat if tracing_paragraphs>0 then - print_nl("@@finalpass");@;@+tats@/ - background[2]:=background[2]+emergency_stretch; final_pass:=true; - end; -@z - -367. New \errorcontextlines feature suggested by a TUG participant -@x modules 236--238 get a new integer parameter -@d int_pars=54 {total number of integer parameters} -@y -@d error_context_lines_code=54 {maximum intermediate line pairs shown} -@d int_pars=55 {total number of integer parameters} -@z and appropriate further lines are added to match all the other parameters -@x module 311 -@<Local variables for formatting calculations@>@/ -begin base_ptr:=input_ptr; input_stack[base_ptr]:=cur_input; - {store current state} -loop@+begin cur_input:=input_stack[base_ptr]; {enter into the context} - @<Display the current context@>; - if (state<>token_list) then - if (name>17) or (base_ptr=0) then goto done; -@y -@!nn:integer; {number of contexts shown so far, less one} -@!bottom_line:boolean; {have we reached the final context to be shown?} -@<Local variables for formatting calculations@>@/ -begin base_ptr:=input_ptr; input_stack[base_ptr]:=cur_input; - {store current state} -nn:=-1; bottom_line:=false; -loop@+begin cur_input:=input_stack[base_ptr]; {enter into the context} - if (state<>token_list) then - if (name>17) or (base_ptr=0) then bottom_line:=true; - if (base_ptr=input_ptr)or bottom_line or(nn<error_context_lines) then - @<Display the current context@> - else if nn=error_context_lines then - begin print_nl("..."); incr(nn); {omitted if |error_context_lines<0|} - end; - if bottom_line then goto done; -@z -% also insert begin...end around the Pascal code of module 312 -% and add the statement "incr(nn)" to that module - -368. char_warning inside hyphenation could clobber old_setting -@x module 863 -done: @!stat if tracing_paragraphs>0 then end_diagnostic(true);@;@+tats@/ -@y -done: @!stat if tracing_paragraphs>0 then - begin end_diagnostic(true); normalize_selector; - end;@+tats@/ -@z - -369. Make ".fmt" more easily switchable (Don Hosek). -@x module 520 gets a new definition -@y -@d format_extension=".fmt" {the extension, as a \.{WEB} constant} -@z now replace ".fmt" by format_extension in modules 529 and 1328. - -370. Possible range check on weird nullfont (Breitenlohner, 16 Oct 89). -@x module 565 -if (bc>ec+1)or(ec>255) then abort; -@y -if (bc>ec+1)or(ec>255) then abort; -if bc>255 then {|bc=256| and |ec=255|} - begin bc:=1; ec:=0; - end; -@z - -371. Prevent save_stack conflicts, e.g. in {\hbox\expandafter{\csname - \endcsname}} (found by Sullivan). -@x module 645 -@p procedure scan_spec; {scans a box specification and left brace} -label found; -begin if scan_keyword("to") then saved(0):=exactly -@.to@> -else if scan_keyword("spread") then saved(0):=additional -@.spread@> -else begin saved(0):=additional; saved(1):=0; - goto found; - end; -scan_normal_dimen; saved(1):=cur_val; -found: save_ptr:=save_ptr+2; scan_left_brace; -@y -@p procedure scan_spec(@!c:group_code;@!three_codes:boolean); - {scans a box specification and left brace} -label found; -var @!s:integer; {temporarily saved value} -@!spec_code:exactly..additional; -begin if three_codes then s:=saved(0); -if scan_keyword("to") then spec_code:=exactly -@.to@> -else if scan_keyword("spread") then spec_code:=additional -@.spread@> -else begin spec_code:=additional; cur_val:=0; - goto found; - end; -scan_normal_dimen; -found: if three_codes then - begin saved(0):=s; incr(save_ptr); - end; -saved(0):=spec_code; saved(1):=cur_val; save_ptr:=save_ptr+2; -new_save_level(c); scan_left_brace; -@z -@x module 774 -scan_spec; new_save_level(align_group);@/ -@y -scan_spec(align_group,false);@/ -@z -@x module 1073 - if t=0 then saved(0):=cur_val@+else saved(0):=-cur_val; - scan_box; - end; -any_mode(leader_ship): begin saved(0):=leader_flag-a_leaders+cur_chr; scan_box; - end; -any_mode(make_box): begin saved(0):=0; begin_box; - end; -@y - if t=0 then scan_box(cur_val)@+else scan_box(-cur_val); - end; -any_mode(leader_ship): scan_box(leader_flag-a_leaders+cur_chr); -any_mode(make_box): begin_box(0); -@z -@x module 1075 -procedure box_end; -var p:pointer; {|ord_noad| for new box in math mode} -begin if saved(0)<box_flag then @<Append box |cur_box| to the current list, - shifted by |saved(0)|@> -else if saved(0)<ship_out_flag then @<Store \(c)|cur_box| in a box register@> -else if cur_box<>null then - if saved(0)>ship_out_flag then @<Append a new leader node that - uses |cur_box|@> -@y -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@> -else if cur_box<>null then - if box_context>ship_out_flag then @<Append a new leader node that - uses |cur_box|@> -@z -@x module 1076 - begin shift_amount(cur_box):=saved(0); -@y - begin shift_amount(cur_box):=box_context; -@z -@x module 1077 -if saved(0)<box_flag+256 then - eq_define(box_base-box_flag+saved(0),box_ref,cur_box) -else geq_define(box_base-box_flag-256+saved(0),box_ref,cur_box) -@y -if box_context<box_flag+256 then - eq_define(box_base-box_flag+box_context,box_ref,cur_box) -else geq_define(box_base-box_flag-256+box_context,box_ref,cur_box) -@z -@x module 1078 - begin append_glue; subtype(tail):=saved(0)-(leader_flag-a_leaders); -@y - begin append_glue; subtype(tail):=box_context-(leader_flag-a_leaders); -@z -@x module 1079 -procedure begin_box; -@y -procedure begin_box(@!box_context:integer); -@z -@x ibid -box_end; {in simple cases, we use the box immediately} -@y -box_end(box_context); {in simple cases, we use the box immediately} -@z -@x module 1083 -incr(save_ptr); scan_spec; -if k=hmode then - if (saved(-3)<box_flag)and(abs(mode)=vmode) then - new_save_level(adjusted_hbox_group) - else new_save_level(hbox_group) -else begin if k=vmode then new_save_level(vbox_group) - else begin new_save_level(vtop_group); k:=vmode; -@y -saved(0):=box_context; -if k=hmode then - if (box_context<box_flag)and(abs(mode)=vmode) then - scan_spec(adjusted_hbox_group,true) - else scan_spec(hbox_group,true) -else begin if k=vmode then scan_spec(vbox_group,true) - else begin scan_spec(vtop_group,true); k:=vmode; -@z -@x module 1084 -procedure scan_box; {the next input should specify a box or perhaps a rule} -begin @<Get the next non-blank non-relax...@>; -if cur_cmd=make_box then begin_box -else if (saved(0)>=leader_flag)and((cur_cmd=hrule)or(cur_cmd=vrule)) then - begin cur_box:=scan_rule_spec; box_end; -@y -procedure scan_box(@!box_context:integer); - {the next input should specify a box or perhaps a rule} -begin @<Get the next non-blank non-relax...@>; -if cur_cmd=make_box then begin_box(box_context) -else if (box_context>=leader_flag)and((cur_cmd=hrule)or(cur_cmd=vrule)) then - begin cur_box:=scan_rule_spec; box_end(box_context); -@z -@x module 1086 -pop_nest; box_end; -@y -pop_nest; box_end(saved(0)); -@z -@x module 1117 -else begin incr(save_ptr); saved(-1):=0; scan_left_brace; - new_save_level(disc_group); push_nest; mode:=-hmode; space_factor:=1000; -@y -else begin incr(save_ptr); saved(-1):=0; new_save_level(disc_group); - scan_left_brace; push_nest; mode:=-hmode; space_factor:=1000; -@z -@x module 1119 -incr(saved(-1)); scan_left_brace; new_save_level(disc_group); -@y -incr(saved(-1)); new_save_level(disc_group); scan_left_brace; -@z -@x module 1167 -mmode+vcenter: begin scan_spec; new_save_level(vcenter_group); normal_paragraph; -@y -mmode+vcenter: begin scan_spec(vcenter_group,false); normal_paragraph; -@z -@x module 1172 -scan_left_brace; push_math(math_choice_group); -@y -push_math(math_choice_group); scan_left_brace; -@z -@x module 1174 -incr(saved(-1)); scan_left_brace; push_math(math_choice_group); -@y -incr(saved(-1)); push_math(math_choice_group); scan_left_brace; -@z -@x module 1241 - if global then saved(0):=box_flag+256+cur_val - else saved(0):=box_flag+cur_val; - scan_optional_equals; scan_box; -@y - if global then n:=256+cur_val@+else n:=cur_val; - scan_optional_equals; scan_box(box_flag+n); -@z - -372. Bugfix 339 didn't go far enough (found by Sch\"opf and Mittelbach). -@x module 516 [NOTE: THIS AFFECTS ALMOST ALL CHANGE FILES!] -@ And here's the second. -@^system dependencies@> - -@p function more_name(@!c:ASCII_code):boolean; -begin if c=" " then more_name:=false -else begin if (c=">")or(c=":") then - begin area_delimiter:=pool_ptr; ext_delimiter:=0; - end - else if (c=".")and(ext_delimiter=0) then ext_delimiter:=pool_ptr; - str_room(1); append_char(c); {contribute |c| to the current string} -@y -@ 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; -@z -@x module 517 [NOTE: THIS DOES TOO, AND SO DOES THE NEXT!] -else begin cur_area:=str_ptr; incr(str_ptr); - str_start[str_ptr]:=area_delimiter+1; -@y -else begin cur_area:=str_ptr; - str_start[str_ptr+1]:=str_start[str_ptr]+area_delimiter; incr(str_ptr); -@z -@x ibid -else begin cur_name:=str_ptr; incr(str_ptr); - str_start[str_ptr]:=ext_delimiter; cur_ext:=make_string; -@y -else begin cur_name:=str_ptr; - str_start[str_ptr+1]:=str_start[str_ptr]+ext_delimiter-area_delimiter-1; - incr(str_ptr); cur_ext:=make_string; -@z - -373. Allow multiple hyphenmins in the same paragraph (Mike Ferguson). -@x module 212, two new fields for list_state_record -@y - @!lhm_field,@!rhm_field: quarterword; -@z -@x module 213, two new macros to access those fields -@y -@d lhmin==cur_list.lhm_field {\.{\\lefthyphenmin} at start of paragraph} -@d rhmin==cur_list.rhm_field {\.{\\righthyphenmin} at start of paragraph} -@z -@x module 215, two new initializations -@y -lhmin:=0; rhmin:=0; -@z -@x module 218 - if nest[p].ml_field<0 then print(" (\output routine)"); -@y - if m=hmode then@+if(nest[p].lhm_field<>2)or(nest[p].rhm_field<>3)then - begin print(" (hyphenmin "); print_int(nest[p].lhm_field); print_char(","); - print_int(nest[p].rhm_field); print_char(")"); - end; - if nest[p].ml_field<0 then print(" (\output routine)"); -@z -@x module 891 -l_hyf:=left_hyphen_min-1;@+if l_hyf<0 then l_hyf:=0; -r_hyf:=right_hyphen_min-1;@+if r_hyf<0 then r_hyf:=0; -min_hyf:=l_hyf+r_hyf+2; cur_lang:=0; -@y -l_hyf:=lhmin; r_hyf:=rhmin; cur_lang:=0; -@z -@x module 892 -@!l_hyf,@!r_hyf,@!min_hyf:integer; {limits on fragment sizes} -@y -@!l_hyf,@!r_hyf:integer; {limits on fragment sizes} -@z -@x module 894 -begin if min_hyf>63 then goto done1; -prev_s:=cur_p; s:=link(prev_s); -if s<>null then - begin @<Skip to node |ha|, or |goto done1| if no hyphenation - should be attempted@>; - @<Skip to node |hb|, putting letters into |hu| and |hc|@>; - @<Check that the nodes following |hb| permit hyphenation and that at least - |min_hyf| letters have been found, otherwise |goto done1|@>; -@y -begin prev_s:=cur_p; s:=link(prev_s); -if s<>null then - begin @<Skip to node |ha|, or |goto done1| if no hyphenation - should be attempted@>; - if l_hyf+r_hyf>63 then goto done1; - @<Skip to node |hb|, putting letters into |hu| and |hc|@>; - @<Check that the nodes following |hb| permit hyphenation and that at least - |l_hyf+r_hyf| letters have been found, otherwise |goto done1|@>; -@z -@x module 899 -if hn<min_hyf then goto done1; -@y -if hn<l_hyf+r_hyf then goto done1; -@z -@x module 902 -for j:=l_hyf+1 to hn-r_hyf-1 do if odd(hyf[j]) then goto found1; -@y -for j:=l_hyf to hn-r_hyf do if odd(hyf[j]) then goto found1; -@z -@x module 923 -for j:=0 to hn-r_hyf do -@y -for j:=0 to hn-r_hyf+1 do -@z -@x ibid -found: for j:=0 to l_hyf do hyf[j]:=0; -for j:=0 to r_hyf do hyf[hn-j]:=0 -@y -found: for j:=0 to l_hyf-1 do hyf[j]:=0; -for j:=0 to r_hyf-1 do hyf[hn-j]:=0 -@z -@x module 1091 begins with a new subroutine -@y -function norm_min(@!h:integer):small_number; -begin if h<=0 then norm_min:=1@+else if h>=63 then norm_min:=63@+ -else norm_min:=h; -end; -@z -@x module 1091 then uses the new subroutine -push_nest; mode:=hmode; space_factor:=1000; clang:=0; -@y -lhmin:=norm_min(left_hyphen_min); rhmin:=norm_min(right_hyphen_min); -push_nest; mode:=hmode; space_factor:=1000; clang:=0; -@z -@x module 1341 -@d stored_language(#)==mem[#+1].int {language number, in the range |0..255|} -@y -@d what_lang(#)==link(#+1) {language number, in the range |0..255|} -@d what_lhm(#)==type(#+1) {minimum left fragment, in the range |1..63|} -@d what_rhm(#)==subtype(#+1) {minimum right fragment, in the range |1..63|} -@z -@x module 1356 - print_int(stored_language(p)); -@y - print_int(what_lang(p)); print(" (hyphenmin "); - print_int(what_lhm(p)); print_char(","); - print_int(what_rhm(p)); print_char(")"); -@z -@x modules 1362 and 1363 -@ @<Advance \(p)past a whatsit node in the \(l)|line_break| loop@>= -if subtype(cur_p)=language_node then cur_lang:=stored_language(cur_p) - -@ @<Advance \(p)past a whatsit node in the \(p)pre-hyphenation loop@>= -if subtype(s)=language_node then cur_lang:=stored_language(s) -@y -@ @d adv_past(#)==@+if subtype(#)=language_node then - begin cur_lang:=what_lang(#); l_hyf:=what_lhm(#); r_hyf:=what_rhm(#);@+end - -@<Advance \(p)past a whatsit node in the \(l)|line_break| loop@>=@+ -adv_past(cur_p) - -@ @<Advance \(p)past a whatsit node in the \(p)pre-hyphenation loop@>=@+ -adv_past(s) -@z -@x module 1376 - stored_language(tail):=l; clang:=l; -@y - what_lang(tail):=l; clang:=l;@/ - what_lhm(tail):=norm_min(left_hyphen_min); - what_rhm(tail):=norm_min(right_hyphen_min); -@z -@x module 1377 - stored_language(tail):=clang; -@y - what_lang(tail):=clang; - what_lhm(tail):=norm_min(left_hyphen_min); - what_rhm(tail):=norm_min(right_hyphen_min); -@z - -374. Make \par and end_template definitely non-character (Marc van Leeuwen) -@x module 14 gets a new line -@y -if mem_top<256+11 then bad:=7; {we will want |null_list>255|} -@z -@x module 334 -primitive("par",par_end,0); par_loc:=cur_val; par_token:=cs_token_flag+par_loc; -@y -primitive("par",par_end,256); {cf. |scan_file_name|} -par_loc:=cur_val; par_token:=cs_token_flag+par_loc; -@z - -375. Alignments must be more robust to prevent crashes (Marc van Leeuwen) -@x module 324 -else if token_type=u_template then align_state:=0; -@y -else if token_type=u_template then - if align_state>500000 then align_state:=0 - else fatal_error("(interwoven alignment preambles are not allowed)"); -@.interwoven alignment preambles...@> -@z -@x module 782 -if (cur_cmd=assign_glue)and(cur_chr=glue_base+tab_skip_code) then -@y -if cur_cmd=endv then - fatal_error("(interwoven alignment preambles are not allowed)"); -@.interwoven alignment preambles...@> -if (cur_cmd=assign_glue)and(cur_chr=glue_base+tab_skip_code) then -@z -@x module 791 -p:=link(q); -@y -if align_state<500000 then - fatal_error("(interwoven alignment preambles are not allowed)"); -@.interwoven alignment preambles...@> -p:=link(q); -@z - -376. Avoid kern removal in discretionary breaks (Marc van Leeuwen) -@x module 815 -label done,done1,done2,done3,done4,continue; -@y -label done,done1,done2,done3,done4,done5,continue; -@z -@x module 866 -glue_node: begin @<If node |cur_p| is a legal breakpoint, call |try_break|@>; - @<Update the active widths by including the glue in |glue_ptr(cur_p)|@>; -@y -glue_node: begin @<If node |cur_p| is a legal breakpoint, call |try_break|; - then update the active widths by including the glue in |glue_ptr(cur_p)|@>; -@z -@x ibid -disc_node: @<Try to break after a discretionary fragment@>; -@y -disc_node: @<Try to break after a discretionary fragment, then |goto done5|@>; -@z -@x ibid -end -@y -done5:end -@z -Combine modules 868 and 869 into a single module, with a semicolon between. -@x module 870 (which becomes module 869) gets ... in its title -@y and the following new code just before its final "end": -r:=replace_count(cur_p); s:=link(cur_p); -while r>0 do - begin @<Add the width of node |s| to |act_width|@>; - decr(r); s:=link(s); - end; -prev_p:=cur_p; cur_p:=s; goto done5; -@z -@x Now module 871 becomes 870, and we add a new (very similar) module 871: -@y -@ @<Add the width of node |s| to |act_width|@>= -if is_char_node(s) then - begin f:=font(s); - act_width:=act_width+char_width(f)(char_info(f)(character(s))); - end -else case type(s) of - ligature_node: begin f:=font(lig_char(s)); - act_width:=act_width+ - char_width(f)(char_info(f)(character(lig_char(s)))); - end; - hlist_node,vlist_node,rule_node,kern_node: - act_width:=act_width+width(s); - othercases confusion("disc4") -@:this can't happen disc4}{\quad disc4@> - endcases -@z -@x module 877 -@!disc_break:boolean; {was the current break at a discretionary node?} -@y -@!disc_break:boolean; {was the current break at a discretionary node?} -@!post_disc_break:boolean; {and did it have a nonempty post-break part?} -@z -@x ibid -if cur_p<>null then @<Prune unwanted nodes at the beginning of the next line@>; -@y -if cur_p<>null then if not post_disc_break then - @<Prune unwanted nodes at the beginning of the next line@>; -@z -@x module 881 -q:=cur_break(cur_p); disc_break:=false; -@y -q:=cur_break(cur_p); disc_break:=false; post_disc_break:=false; -@z -@x module 883 - if not is_char_node(s) then if next_break(cur_p)<>null then - if cur_break(next_break(cur_p))=s then s:=r; -@y that subtle bug is no longer possible so we can remove the code -@z -@x module 884 -link(s):=r; r:=post_break(q); post_break(q):=null; -@y -link(s):=r; r:=post_break(q); post_break(q):=null; post_disc_break:=true; -@z - -377. Pick up a few discretionary hyphens that were lost because of -the new (cautious) algorithm. -@x module 914 -@ @d advance_major_tail==begin major_tail:=link(major_tail); incr(r_count); - end - -@<Create and append a discretionary node as an alternative...@>= -begin r:=get_node(small_node_size); -@y -@ In this repeat loop we will insert another discretionary if |hyf[j-1]| is -odd, after both branches of the previous discretionary end at position |j-1|. -Strictly speaking, we aren't justified in doing this, because we don't know -that a hyphen after |j-1| is truly independent of those branches. But in almost -all applications we would rather not lose a potentially valuable hyphenation -point. (Consider the word `difficult', where the letter `c' is in position |j|.) - -@d advance_major_tail==begin major_tail:=link(major_tail); incr(r_count); - end - -@<Create and append a discretionary node as an alternative...@>= -repeat r:=get_node(small_node_size); -@z -@x ibid -i:=hyphen_passed; -@y -i:=hyphen_passed; hyf[i]:=0; -@z -@x ibid -end -@y -hyphen_passed:=j-1; link(hold_head):=null; -until not odd(hyf[j-1]) -@z - -378. Undumped trie must also be dumpable again (Breitenlohner, 11 Dec 89) -@x module 1325 -undump_size(0)(trie_size)('trie size')(j); {|trie_max|} -for k:=0 to j do undump_hh(trie[k]); -undump_size(0)(trie_op_size)('trie op size')(j); {|trie_op_ptr|} -@y -undump_size(0)(trie_size)('trie size')(j); @+init trie_max:=j;@+tini -for k:=0 to j do undump_hh(trie[k]); -undump_size(0)(trie_op_size)('trie op size')(j); @+init trie_op_ptr:=j;@+tini -@z -@x ibid -k:=256; -while j>0 do - begin undump(0)(k-1)(k); undump(1)(j)(x); j:=j-x; op_start[k]:=qo(j); -@y -init for k:=0 to 255 do trie_used[k]:=min_quarterword;@+tini -k:=256; -while j>0 do - begin undump(0)(k-1)(k); undump(1)(j)(x);@+init trie_used[k]:=qi(x);@+tini - j:=j-x; op_start[k]:=qo(j); -@z - -379. Allow output routine to access page totals. (Suggested by Frank -Mittelbach and Chris Rowley, December 1989) -@x module 421 -begin if page_contents=empty then -@y -begin if (page_contents=empty) and (not output_active) then -@z - -380. Slightly more robust recovery and detection of \output anomalies. -(Suggested by Chris Thompson, provoked by George Russell, January 1990) -@x module 1026 -begin if loc<>null then @<Recover from an unbalanced output routine@>; -@y -begin if (loc<>null) or - ((token_type<>output_text)and(token_type<>backed_up)) then - @<Recover from an unbalanced output routine@>; -@z -@x module 1027 -help2("Your sneaky output routine has fewer real {'s than }'s.")@/ -@y -help2("Your sneaky output routine has problematic {'s and/or }'s.")@/ -@z - -381. \eqno\aftergroup*$$ should yield * after the $$ (Michael Downes, 29 Jan 90) -@x module 1194 - begin cur_mlist:=p; cur_style:=text_style; mlist_penalties:=false; -@y - begin @<Check that another \.\$ follows@>; - cur_mlist:=p; cur_style:=text_style; mlist_penalties:=false; -@z -@x ibid -else begin @<Check that another \.\$ follows@>; -@y -else begin if a=null then @<Check that another \.\$ follows@>; -@z - -382. Missed a case in the 8-bit change (Wayne Sullivan, 1 Feb 1990) -@x module 360 - begin if (end_line_char<0)or(end_line_char>127) then incr(limit); -@y - begin if end_line_char_inactive then incr(limit); -@z - -383. Linebreaking needs to be more robust when total demerits get -very high (Frank Mittelbach, 22 Feb 1990) -@x module 830 -@!artificial_badness:boolean; {has |b| been forced to zero?} -@y -@!artificial_demerits:boolean; {has |d| been forced to zero?} -@z -@x module 833 (this change is cosmetic only) -@!minimal_demerits:array[very_loose_fit..tight_fit] of scaled; {best total - demerits known for current line class and position, given the fitness} -@!minimum_demerits:scaled; {best total demerits known for current line class -@y -@!minimal_demerits:array[very_loose_fit..tight_fit] of integer; {best total - demerits known for current line class and position, given the fitness} -@!minimum_demerits:integer; {best total demerits known for current line class -@z -@x module 836 here we want to ensure that total_demerits < awful_bad -minimum_demerits:=minimum_demerits+abs(adj_demerits); -@y -if abs(adj_demerits)>=awful_bad-minimum_demerits then - minimum_demerits:=awful_bad-1 -else minimum_demerits:=minimum_demerits+abs(adj_demerits); -@z -@x module 851 -begin @!stat artificial_badness:=false;@+tats@/ -@y -begin artificial_demerits:=false;@/ -@z -@x module 854 - begin b:=0; {set badness zero, this break is forced} - @!stat artificial_badness:=true;@+tats - end -@y - artificial_demerits:=true {set demerits zero, this break is forced} -@z -@x module 855 -@<Compute the demerits, |d|, from |r| to |cur_p|@>; -@y -if artificial_demerits then d:=0 -else @<Compute the demerits, |d|, from |r| to |cur_p|@>; -@z -@x module 856 -if artificial_badness then print_char("*")@+else print_int(b); -@.*\relax@> -print(" p="); print_int(pi); -print(" d="); print_int(d); -@y -if b>inf_bad then print_char("*")@+else print_int(b); -@.*\relax@> -print(" p="); print_int(pi); print(" d="); -if artificial_demerits then print_char("*")@+else print_int(d); -@z -@x module 859 -d:=line_penalty+b; d:=d*d; -@y -begin d:=line_penalty+b; -if abs(d)>=10000 then d:=100000000@+else d:=d*d; -@z -@x ibid -if abs(fit_class-fitness(r))>1 then d:=d+adj_demerits -@y -if abs(fit_class-fitness(r))>1 then d:=d+adj_demerits; -end -@z - -384. Math fonts may disappear outside of \eqno (Marc van Leeuwen). -@x module 1194 - if danger then flush_math; -@y - danger:=false; - @<Check that the necessary fonts for math symbols are present; - if not, flush the current math lists and set |danger:=true|@>; -@z - -385. Forgot to rule out charnode when testing for node type (Marc van Leeuwen). -@x module 805 - begin if type(q)=unset_node then - @<Set the unset box |q| and the unset boxes in it@> - else if type(q)=rule_node then - @<Make the running dimensions in rule |q| extend to the - boundaries of the alignment@>; -@y - begin if not is_char_node(q) then - if type(q)=unset_node then - @<Set the unset box |q| and the unset boxes in it@> - else if type(q)=rule_node then - @<Make the running dimensions in rule |q| extend to the - boundaries of the alignment@>; -@z -@x module 903 -if type(hb)=ligature_node then if odd(subtype(hb)) then -@y -if not is_char_node(hb) then - if type(hb)=ligature_node then if odd(subtype(hb)) then -@z -@x module 1202 - if p<>null then if type(p)=glue_node then d:=0; -@y - if p<>null then if not is_char_node(p) then if type(p)=glue_node then d:=0; -@z - -386. Don't change the font of punctuation before a hyphenated word - (Scott Allendorf, reported 7 Mar 90) -@x module 895 -label common_ending,done,found,found1,not_found,not_found+1,exit; -@y -label common_ending,done,found,found1,found2,not_found,exit; -@z -@x module 903 -if is_char_node(ha) then - begin init_list:=ha; init_lig:=false; hu[0]:=qo(character(ha)); - end -else if type(ha)=ligature_node then - begin init_list:=lig_ptr(ha); init_lig:=true; init_lft:=(subtype(ha)>1); - hu[0]:=qo(character(lig_char(ha))); - if init_list=null then if init_lft then - begin hu[0]:=256; init_lig:=false; - end; {in this case a ligature will be reconstructed from scratch} - free_node(ha,small_node_size); - end -else goto not_found+1; {no punctuation found} -s:=cur_p; {we have |cur_p<>ha| because |type(cur_p)=glue_node|} -while link(s)<>ha do s:=link(s); -j:=0; goto common_ending; -not_found+1: j:=1; s:=ha; init_list:=null; -if not is_char_node(r) then if type(r)=ligature_node then - if subtype(r)>1 then - begin j:=0; hu[0]:=256; init_lig:=false; - end; -@y -if is_char_node(ha) then - if font(ha)<>hf then goto found2 - else begin init_list:=ha; init_lig:=false; hu[0]:=qo(character(ha)); - end -else if type(ha)=ligature_node then - if font(lig_char(ha))<>hf then goto found2 - else begin init_list:=lig_ptr(ha); init_lig:=true; init_lft:=(subtype(ha)>1); - hu[0]:=qo(character(lig_char(ha))); - if init_list=null then if init_lft then - begin hu[0]:=256; init_lig:=false; - end; {in this case a ligature will be reconstructed from scratch} - free_node(ha,small_node_size); - end -else begin {no punctuation found; look for left boundary} - if not is_char_node(r) then if type(r)=ligature_node then - if subtype(r)>1 then goto found2; - j:=1; s:=ha; init_list:=null; goto common_ending; - end; -s:=cur_p; {we have |cur_p<>ha| because |type(cur_p)=glue_node|} -while link(s)<>ha do s:=link(s); -j:=0; goto common_ending; -found2: s:=ha; j:=0; hu[0]:=256; init_lig:=false; init_list:=null; -@z - -387. Balance the parens showing on the terminal (for Lispers). -@x module 304 -@!in_open : 0..max_in_open; {the number of lines in the buffer, less one} -@y -@!in_open : 0..max_in_open; {the number of lines in the buffer, less one} -@!open_parens : 0..max_in_open; {the number of open text files} -@z -@x module 331 -in_open:=0; max_buf_stack:=0; -@y -in_open:=0; open_parens:=0; max_buf_stack:=0; -@z -@x module 362 - begin print_char(")"); force_eof:=false; - update_terminal; {show user that file has been read} -@y - begin print_char(")"); decr(open_parens); - update_terminal; {show user that file has been read} - force_eof:=false; -@z -@x module 537 -print_char("("); print(name); update_terminal; state:=new_line; -@y -print_char("("); incr(open_parens); print(name); update_terminal; -state:=new_line; -@z -@x module 1334 -if job_name=0 then open_log_file; -@y -if job_name=0 then open_log_file; -while open_parens>0 do - begin print(" )"); decr(open_parens); - end; -@z - -388. Optimize \ifx\p\q after \let\p=\q (Marc van Leeuwen says that - AmS-TeX uses this a lot). -@x module 508 - while (p<>null)and(q<>null) do - if info(p)<>info(q) then p:=null - else begin p:=link(p); q:=link(q); - end; -b:=((p=null)and(q=null)); -@y -if p=q then b:=true -else begin while (p<>null)and(q<>null) do - if info(p)<>info(q) then p:=null - else begin p:=link(p); q:=link(q); - end; - b:=((p=null)and(q=null)); - end; -@z -@x module 538 (while we're at it, might as well optimize this too) -begin if not input_ln(cur_file,false) then do_nothing; -@y -begin if input_ln(cur_file,false) then do_nothing; -@z -@x module 1020 (and this) -else begin wait:=false; s:=ins_ptr(p); - link(last_ins_ptr(r)):=s; s:=last_ins_ptr(r); -@y -else begin wait:=false; s:=last_ins_ptr(r); link(s):=ins_ptr(p); -@z - -389. Treat migration properly in displays (Marc van Leeuwen). -@x module 1199 (a bad bug that really has bitten) -adjust_tail:=adjust_head; b:=hpack(p,natural); -@y -adjust_tail:=adjust_head; b:=hpack(p,natural); p:=list_ptr(b); -@z -@x module 1204 -shift_amount(b):=s+d; append_to_vlist(b); -if t<>adjust_head then - begin link(tail):=link(adjust_head); tail:=t; - end -@y -shift_amount(b):=s+d; append_to_vlist(b) -@z -@x module 1205 - tail_append(new_penalty(post_display_penalty)); - end -else begin tail_append(new_penalty(post_display_penalty)); - tail_append(new_param_glue(g2)); - end -@y - g2:=0; - end; -if t<>adjust_head then {migrating material comes after equation number} - begin link(tail):=link(adjust_head); tail:=t; - end; -tail_append(new_penalty(post_display_penalty)); -if g2>0 then tail_append(new_param_glue(g2)) -@z - ------------Here I draw the line with respect to further changes - -390. Uninitialized nullfont parameters (found by Lance Carnes, 11 May 90). -@x module 552 -hyphen_char[null_font]:="-"; skew_char[null_font]:=-1; -@y -hyphen_char[null_font]:="-"; skew_char[null_font]:=-1; -bchar_label[null_font]:=non_address; -font_bchar[null_font]:=non_char; font_false_bchar[null_font]:=non_char; -@z - -391. Disable \write{\the\prevgraf} (B. Jackowski, July 1990). -@x module 422 -begin nest[nest_ptr]:=cur_list; p:=nest_ptr; -while abs(nest[p].mode_field)<>vmode do decr(p); -scanned_result(nest[p].pg_field)(int_val); -end -@y -if mode=0 then scanned_result(0)(int_val) {|prev_graf=0| within \.{\\write}} -else begin nest[nest_ptr]:=cur_list; p:=nest_ptr; - while abs(nest[p].mode_field)<>vmode do decr(p); - scanned_result(nest[p].pg_field)(int_val); - end -@z - -392. Report correct line number when buffer overflows (George Russell). -@x module 538 -begin if input_ln(cur_file,false) then do_nothing; -firm_up_the_line; -if end_line_char_inactive then decr(limit) -else buffer[limit]:=end_line_char; -first:=limit+1; loc:=start; line:=1; -@y -begin line:=1; -if input_ln(cur_file,false) then do_nothing; -firm_up_the_line; -if end_line_char_inactive then decr(limit) -else buffer[limit]:=end_line_char; -first:=limit+1; loc:=start; -@z - -------------- -Note: When making change 376, I forgot to delete the redundant -code in module 883, and I should also have changed the name of that -module. These cosmetic changes (and some changes to the comments) -were made in version 3.14, in addition to the following two changes. -------------- - -393. Show unprintable characters in font id's (Wayne Sullivan, Dec 1990) -@x module 63 -print(s); -@y -slow_print(s); -@z -@x module 262 can now be spruced up -else begin print_esc(""); slow_print(text(p)); -@y -else begin print_esc(text(p)); -@z -@x and module 263 likewise -else begin print_esc(""); slow_print(text(p)); - end; -@y -else print_esc(text(p)); -@z - -394. Avoid range check if total_pages>65535 (Eberhard Mattes, Dec 1990) -@x module 642 - dvi_out(total_pages div 256); dvi_out(total_pages mod 256);@/ -@y - dvi_out((total_pages div 256) mod 256); dvi_out(total_pages mod 256);@/ -@z - -395. Less confusing error message (18 Sep 91) -@x module 436 - begin print_err("Bad math code"); -@.Bad math code@> - help2("A numeric math code must be between 0 and 32767.")@/ -@y (because a \mathcode can be 32768, but not a \mathchar) - begin print_err("Bad mathchar"); -@.Bad mathchar@> - help2("A mathchar number must be between 0 and 32767.")@/ -@z - -396. Internal strings should not be expanded even if unprintable; -i.e., selector=new_string => print(c)==print_char(c), print(s)==slow_print(s). -This change completes what I began with number 393 (18 Sep 91). -@x modules 59 and 60 (same change to both) - else if (@<Character |s| is the current new-line character@>) then - if selector<pseudo then - begin print_ln; return; - end; -@y - else if selector>pseudo then - begin print_char(s); return; {internal strings are not expanded} - end - else if (@<Character |s| is the current new-line character@>) then - if selector<pseudo then - begin print_ln; return; - end; -@z -@x module 61 -else begin print(format_ident); print_ln; -@y -else begin slow_print(format_ident); print_ln; -@z -@x module 84 - print(input_stack[base_ptr].name_field); -@y - slow_print(input_stack[base_ptr].name_field); -@z -@x module 518 -begin print(a); print(n); print(e); -@y -begin slow_print(a); slow_print(n); slow_print(e); -@z -@x module 536 -print(format_ident); print(" "); -@y -slow_print(format_ident); print(" "); -@z -@x module 537 -print_char("("); incr(open_parens); print(name); update_terminal; -@y -print_char("("); incr(open_parens); slow_print(name); update_terminal; -@z -@x module 581 - print(font_name[f]); print_char("!"); end_diagnostic(false); -@y - slow_print(font_name[f]); print_char("!"); end_diagnostic(false); -@z -@x module 642 - print_nl("Output written on "); print(output_file_name); -@y - print_nl("Output written on "); slow_print(output_file_name); -@z -@x module 1261 -set_font:begin print("select font "); print(font_name[chr_code]); -@y -set_font:begin print("select font "); slow_print(font_name[chr_code]); -@z -@x module 1280 -print(s); update_terminal; -@y -slow_print(s); update_terminal; -@z -@x module 1283 -begin print_err(s); -@y -begin print_err(""); slow_print(s); -@z -@x module 1328 -print(w_make_name_string(fmt_file)); flush_string; -print_nl(format_ident) -@y -slow_print(w_make_name_string(fmt_file)); flush_string; -print_nl(""); slow_print(format_ident) -@z -@x module 1333 - print(log_name); print_char("."); -@y - slow_print(log_name); print_char("."); -@z -@x module 1339 -10: print(n); -@y -10: slow_print(n); -@z - -397. Retain more right context for reconstructing ligatures (19 Sep 91) -@x module 892 -@!l_hyf,@!r_hyf:integer; {limits on fragment sizes} -@y -@!l_hyf,@!r_hyf:integer; {limits on fragment sizes} -@!hyf_bchar:halfword; {boundary character after $c_n$} -@z -@x module 897 - c:=qo(character(s)); -@y - hyf_bchar:=character(s); c:=qo(hyf_bchar); -@z -@x module 897 again - s:=link(s); -@y - s:=link(s); hyf_bchar:=non_char; -@z -@x module 898 -j:=hn; q:=lig_ptr(s); -@y -j:=hn; q:=lig_ptr(s);@+if q>null then hyf_bchar:=character(q); -@z -@x module 903 -q:=link(hb); link(hb):=null; r:=link(ha); link(ha):=null; bchar:=non_char; -@y -q:=link(hb); link(hb):=null; r:=link(ha); link(ha):=null; bchar:=hyf_bchar; -@z - -398. Patch the previous code, which could cause double kerning (CET1, 29 Sep 91) -@x module 897 - hb:=s; incr(hn); hu[hn]:=c; hc[hn]:=lc_code(c); - end - else if type(s)=ligature_node then - @<Move the characters of a ligature node to |hu| and |hc|; - but |goto done3| if they are not all letters@> - else if (type(s)<>kern_node)or(subtype(s)<>normal) then goto done3; - s:=link(s); hyf_bchar:=non_char; -@y - hb:=s; incr(hn); hu[hn]:=c; hc[hn]:=lc_code(c); hyf_bchar:=non_char; - end - else if type(s)=ligature_node then - @<Move the characters of a ligature node to |hu| and |hc|; - but |goto done3| if they are not all letters@> - else if (type(s)=kern_node)and(subtype(s)=normal) then hb:=s - else goto done3; - s:=link(s); -@z -@x module 898 -hb:=s; hn:=j; -@y -hb:=s; hn:=j; -if odd(subtype(s)) then hyf_bchar:=font_bchar[hf]@+else hyf_bchar:=non_char; -@z -@x module 903 -if not is_char_node(hb) then - if type(hb)=ligature_node then if odd(subtype(hb)) then - bchar:=font_bchar[hf]; -@y -@z - -399. Disallow \setbox in do_assignments (problem found by Robert Hunt, Nov 91) -@x module 76 -@!deletions_allowed:boolean; {is it safe for |error| to call |get_token|?} -@y -@!deletions_allowed:boolean; {is it safe for |error| to call |get_token|?} -@!set_box_allowed:boolean; {is it safe to do a \.{\\setbox} assignment?} -@z -@x module 77 -deletions_allowed:=true; error_count:=0; {|history| is initialized elsewhere} -@y -deletions_allowed:=true; set_box_allowed:=true; -error_count:=0; {|history| is initialized elsewhere} -@z -@x module 1241 - scan_optional_equals; scan_box(box_flag+n); -@y - if set_box_allowed then scan_box(box_flag+n) - else begin print_err("Improper "); print_esc("setbox"); -@.Improper \\setbox@> - help2("Sorry, \setbox is not allowed after \halign in a display,")@/ - ("or between \accent and an accented character."); error; - end; -@z -@x module 1270 - prefixed_command; -@y - set_box_allowed:=false; prefixed_command; set_box_allowed:=true; -@z - -400. Defend against negative cur_mu (Wayne Sullivan, Nov 91) -@x module 716 -begin n:=x_over_n(m,@'200000); f:=remainder;@/ -@y -begin n:=x_over_n(m,@'200000); f:=remainder;@/ -if f<0 then - begin decr(n); f:=f+@'200000; - end; -@z -@x module 717 - begin n:=x_over_n(m,@'200000); f:=remainder;@/ -@y - begin n:=x_over_n(m,@'200000); f:=remainder;@/ - if f<0 then - begin decr(n); f:=f+@'200000; - end; -@z - -401. Defend against `|}{|' in |\read| (Michael Downes). -@x module 483 - store_new_token(cur_tok); -@y - if align_state<1000000 then {unmatched `\.\}' aborts the line} - begin repeat get_token; until cur_tok=0; - align_state:=1000000; goto done; - end; - store_new_token(cur_tok); -@z - -402. Economize string storage under multiple \font defs (B. Jackowski) -@x module 1257 -@!old_setting:0..max_selector; {holds |selector| setting} -@y -@!old_setting:0..max_selector; {holds |selector| setting} -@!flushable_string:str_number; {string not yet referenced} -@z -@x module 1260 -for f:=font_base+1 to font_ptr do - if str_eq_str(font_name[f],cur_name)and str_eq_str(font_area[f],cur_area) then - begin if s>0 then -@y -flushable_string:=str_ptr-1; -for f:=font_base+1 to font_ptr do - if str_eq_str(font_name[f],cur_name)and str_eq_str(font_area[f],cur_area) then - begin if cur_name=flushable_string then - begin flush_string; cur_name:=font_name[f]; - end; - if s>0 then -@z - -403. Don't look for \newlinechar within unprintable chars (B. Raichle, Nov 91) -@x module 59 -var j:pool_pointer; {current character code position} -@y -var j:pool_pointer; {current character code position} -@!nl:integer; {new-line character to restore} -@z -@x - else if selector>pseudo then - begin print_char(s); return; {internal strings are not expanded} - end - else if (@<Character |s| is the current new-line character@>) then - if selector<pseudo then - begin print_ln; return; - end; -@y - else begin if selector>pseudo then - begin print_char(s); return; {internal strings are not expanded} - end; - if (@<Character |s| is the current new-line character@>) then - if selector<pseudo then - begin print_ln; return; - end; - nl:=new_line_char; new_line_char:=-1; - {temporarily disable new-line character} - j:=str_start[s]; - while j<str_start[s+1] do - begin print_char(so(str_pool[j])); incr(j); - end; - new_line_char:=nl; return; - end; -@z -@x module 60 -label exit; -var j:pool_pointer; {current character code position} -begin if s>=str_ptr then s:="???" {this can't happen} -@.???@> -else if s<256 then - if s<0 then s:="???" {can't happen} - else if selector>pseudo then - begin print_char(s); return; {internal strings are not expanded} - end - else if (@<Character |s| is the current new-line character@>) then - if selector<pseudo then - begin print_ln; return; - end; -j:=str_start[s]; -while j<str_start[s+1] do - begin print(so(str_pool[j])); incr(j); - end; -exit:end; -label exit; -var j:pool_pointer; {current character code position} -begin if s>=str_ptr then s:="???" {this can't happen} -@.???@> -else if s<256 then - if s<0 then s:="???" {can't happen} - else if selector>pseudo then - begin print_char(s); return; {internal strings are not expanded} - end - else if (@<Character |s| is the current new-line character@>) then - if selector<pseudo then - begin print_ln; return; - end; -j:=str_start[s]; -while j<str_start[s+1] do - begin print(so(str_pool[j])); incr(j); - end; -exit:end; -@y -var j:pool_pointer; {current character code position} -begin if (s>=str_ptr) or (s<256) then print(s) -else begin j:=str_start[s]; - while j<str_start[s+1] do - begin print(so(str_pool[j])); incr(j); - end; - end; -end; -@z - -404. False boundary character logic was incorrect (found by Eberhard - Mattes and Bernd Raichle, 6 Feb 92) -@x module 1036 -cur_q:=tail; cur_l:=cur_r; {or |character(lig_stack)|} -@y the following is needed since cur_r might have been changed to non_char -cur_q:=tail; cur_l:=character(lig_stack); -@z - -405. New paragraph and resume-after-display should continue current - \language (Sch\"opf and Thompson, 17 July 92) -@@@ Undo the changes to modules 212, 213, 215 in change number 373. -@x module 218 - if m=hmode then@+if(nest[p].lhm_field<>2)or(nest[p].rhm_field<>3)then - begin print(" (hyphenmin "); print_int(nest[p].lhm_field); print_char(","); - print_int(nest[p].rhm_field); print_char(")"); - end; -@y - if m=hmode then if (nest[p].pg_field <> @'40600000) then - begin print(" (language"); print_int(nest[p].pg_field mod @'200000); - print(":hyphenmin"); print_int(nest[p].pg_field div @'20000000); - print_char(","); print_int((nest[p].pg_field div @'200000) mod @'100); - print_char(")"); - end; -@z -@x module 816 -pop_nest; -@y prev_graf now carries the language parameters at start of horizontal mode -init_cur_lang:=prev_graf mod @'200000; -init_l_hyf:=prev_graf div @'20000000; -init_r_hyf:=(prev_graf div @'200000) mod @'100; -pop_nest; -@z -@x module 891 -l_hyf:=lhmin; r_hyf:=rhmin; cur_lang:=0; -@y -cur_lang:=init_cur_lang; l_hyf:=init_l_hyf; r_hyf:=init_r_hyf; -@z -@x module 892 -@!cur_lang:ASCII_code; {current hyphenation table of interest} -@!l_hyf,@!r_hyf:integer; {limits on fragment sizes} -@y -@!cur_lang,@!init_cur_lang:ASCII_code; {current hyphenation table of interest} -@!l_hyf,@!r_hyf,@!init_l_hyf,@!init_r_hyf:integer; {limits on fragment sizes} -@z -@x module 1091 -lhmin:=norm_min(left_hyphen_min); rhmin:=norm_min(right_hyphen_min); -push_nest; mode:=hmode; space_factor:=1000; clang:=0;@/ -@y -push_nest; mode:=hmode; space_factor:=1000; set_cur_lang; clang:=cur_lang; -prev_graf:=(norm_min(left_hyphen_min)*@'100+norm_min(right_hyphen_min)) - *@'200000+cur_lang; -@z -@x module 1200 -push_nest; mode:=hmode; space_factor:=1000; clang:=0; -@y -push_nest; mode:=hmode; space_factor:=1000; set_cur_lang; clang:=cur_lang; -prev_graf:=(norm_min(left_hyphen_min)*@'100+norm_min(right_hyphen_min)) - *@'200000+cur_lang; -@z - -406. Avoid (harmless) range errors (Philip Taylor and CET1, 17 Dec 92). -@x module 934 -var n:small_number; {length of current word} -@!j:small_number; {an index into |hc|} -@y -var n:0..64; {length of current word; not always a |small_number|} -@!j:0..64; {an index into |hc|} -@z -@x module 960 -var k,@!l:small_number; {indices into |hc| and |hyf|} -@y -var k,@!l:0..64; {indices into |hc| and |hyf|; - not always in |small_number| range} -@z - -407. Kerns inserted via boundary chars should not disappear (William E. Baxter, - 25 Feb 93) -@x module 837 -Kern nodes for accents are treated specially: They do not -disappear at a line break. -@y -Kern nodes do not disappear at a line break unless they are |explicit|. -@z -@x ibid - math_node,kern_node: if subtype(s)=acc_kern then goto done - else break_width[1]:=break_width[1]-width(s); -@y - math_node: break_width[1]:=break_width[1]-width(s); - kern_node: if subtype(s)<>explicit then goto done - else break_width[1]:=break_width[1]-width(s); -@z -@x module 839 -plus $l_1$, so the length from |cur_p| to |cur_p| should be $\gamma+l_0+l_1-l$, -minus the length of nodes that will be discarded after the discretionary break. -@y (this change and the next two should have been made long ago, with #376!) -plus $l_1$, so the length from |cur_p| to |cur_p| should be $\gamma+l_0+l_1-l$. -If the post-break text of the discretionary is empty, a break may also -discard~|q|; in that unusual case we subtract the length of~|q| and any -other nodes that will be discarded after the discretionary break. -@z -@x module 840 - begin @<Add the width of node |s| to |break_width| and increase |t|, - unless it's discardable@>; - s:=link(s); - end; -break_width[1]:=break_width[1]+disc_width; -if t=0 then s:=link(v); {more nodes may also be discardable after the break} -@y - begin @<Add the width of node |s| to |break_width|@>; - s:=link(s); - end; -break_width[1]:=break_width[1]+disc_width; -if post_break(cur_p)=null then s:=link(v); - {nodes may be discardable after the break} -@z -@x module 842 (which now has a new title) - hlist_node,vlist_node,rule_node:break_width[1]:=break_width[1]+width(s); - kern_node: if (t=0)and(subtype(s)<>acc_kern) then t:=-1 {discardable} - othercases confusion("disc2") -@:this can't happen disc2}{\quad disc2@> - endcases; -incr(t) -@y - hlist_node,vlist_node,rule_node,kern_node: - break_width[1]:=break_width[1]+width(s); - othercases confusion("disc2") -@:this can't happen disc2}{\quad disc2@> - endcases -@z -@x module 866 -kern_node: kern_break; -@y -kern_node: if subtype(cur_p)=explicit then kern_break - else act_width:=act_width+width(cur_p); -@z -@x module 868 - else if precedes_break(prev_p) then try_break(0,unhyphenated); -@y - else if precedes_break(prev_p) then try_break(0,unhyphenated) - else if (type(prev_p)=kern_node)and(subtype(prev_p)<>explicit) then - try_break(0,unhyphenated); -@z -@x module 879 - if subtype(q)=acc_kern then if type(q)=kern_node then goto done1; -@y - if type(q)=kern_node then if subtype(q)<>explicit then goto done1; -@z - -408. Prevent boundary kern from disappearing after hyphenation (25 Feb 93) -@x module 897 - else if (type(s)=kern_node)and(subtype(s)=normal) then hb:=s -@y - else if (type(s)=kern_node)and(subtype(s)=normal) then - begin hb:=s; - hyf_bchar:=font_bchar[hf]; - end -@z - -409. Avoid potential future bug [P Breitenlohner] (26 Jun 93) -@x module 628 [shift_amount(leader_box)=0 now but maybe not in extensions] -dvi_v:=save_v; dvi_h:=save_h; cur_v:=save_v; -@y -dvi_v:=save_v; dvi_h:=save_h; cur_v:=base_line; -@z -@x module 637 -dvi_v:=save_v; dvi_h:=save_h; cur_h:=save_h; -@y -dvi_v:=save_v; dvi_h:=save_h; cur_h:=left_edge; -@z - -410. Mustn't let |non-address| depend on |font_mem_size| -@x module 549 -@d non_address==font_mem_size {a spurious |font_index|} -@y -@d non_address=0 {a spurious |bchar_label|} -@z -@x module 916 -if bchar_label[hf]<non_address then {put left boundary at beginning of new line} -@y -if bchar_label[hf]<>non_address then {put left boundary at beginning of new line} -@z -@x module 1323, this will detect obsolete format files -undump(0)(font_mem_size)(bchar_label[k]); -@y -undump(0)(fmem_ptr-1)(bchar_label[k]); -@z - -411. Allow large |font_mem_size|, many font parameters. -@x module 549 -@!font_params:array[internal_font_number] of halfword; {how many font -@y -@!font_params:array[internal_font_number] of font_index; {how many font -@z - -412. Math kerns are explicit; this matters, after change 405 (W Carlip, Sep 94) -@x module 717 - width(p):=mu_mult(width(p)); subtype(p):=normal; -@y - width(p):=mu_mult(width(p)); subtype(p):=explicit; -@z - -413. Avoid overflow on real-to-integer conversion -@x module 619 -@!edge:scaled; {left edge of sub-box, or right edge of leader space} -@y -@!edge:scaled; {left edge of sub-box, or right edge of leader space} -@!glue_temp:real; {glue value before rounding} -@z -@x module 625 -@ @<Move right or output leaders@>= -begin g:=glue_ptr(p); rule_wd:=width(g); -if g_sign<>normal then - begin if g_sign=stretching then - begin if stretch_order(g)=g_order then - rule_wd:=rule_wd+round(float(glue_set(this_box))*stretch(g)); -@^real multiplication@> - end - else begin if shrink_order(g)=g_order then - rule_wd:=rule_wd-round(float(glue_set(this_box))*shrink(g)); -@y -@ @d vet_glue(#)== glue_temp:=#; - if glue_temp>float_constant(1000000000) then - glue_temp:=float_constant(1000000000) - else if glue_temp<-float_constant(1000000000) then - glue_temp:=-float_constant(1000000000) - -@<Move right or output leaders@>= -begin g:=glue_ptr(p); rule_wd:=width(g); -if g_sign<>normal then - begin if g_sign=stretching then - begin if stretch_order(g)=g_order then - begin vet_glue(float(glue_set(this_box))*stretch(g)); -@^real multiplication@> - rule_wd:=rule_wd+round(glue_temp); - end; - end - else if shrink_order(g)=g_order then - begin vet_glue(float(glue_set(this_box))*shrink(g)); - rule_wd:=rule_wd-round(glue_temp); -@z -@x module 629 -@!edge:scaled; {bottom boundary of leader space} -@y -@!edge:scaled; {bottom boundary of leader space} -@!glue_temp:real; {glue value before rounding} -@z -@x module 634 - rule_ht:=rule_ht+round(float(glue_set(this_box))*stretch(g)); -@^real multiplication@> - end - else begin if shrink_order(g)=g_order then - rule_ht:=rule_ht-round(float(glue_set(this_box))*shrink(g)); -@y - begin vet_glue(float(glue_set(this_box))*stretch(g)); -@^real multiplication@> - rule_ht:=rule_ht+round(glue_temp); - end; - end - else if shrink_order(g)=g_order then - begin vet_glue(float(glue_set(this_box))*shrink(g)); - rule_ht:=rule_ht-round(glue_temp); -@z - -414. final cleanup should not retain spurious reference counts (20 Mar 95) -@x module 1335 -while open_parens>0 do -@y -while input_ptr>0 do - if state=token_list then end_token_list@+else end_file_reading; -while open_parens>0 do -@z -@x module 1335, continued - cur_if:=subtype(cond_ptr); cond_ptr:=link(cond_ptr); -@y - cur_if:=subtype(cond_ptr); temp_ptr:=cond_ptr; - cond_ptr:=link(cond_ptr); free_node(temp_ptr,if_node_size); -@z -@x module 1335, concluded - begin @!init store_fmt_file; return;@+tini@/ -@y - begin @!init for c:=top_mark_code to split_bot_mark_code do - if cur_mark[c]<>null then delete_token_ref(cur_mark[c]); - store_fmt_file; return;@+tini@/ -@z - -415. we need not raise hassles about two-digit years (23 Nov 98) -@x module 1328 -print_int(year mod 100); print_char("."); -@y -print_int(year); print_char("."); -@z - -416. \xleaders often drops the final box (Hiroshi Nakashima, 12 July 99) -@x modules 627 and 636 - else begin lx:=(2*lr+lq+1) div (2*lq+2); {round|(lr/(lq+1))|} -@y - else begin lx:=lr div (lq+1); -@z - -417. disallow 100000 unbalanced }s outside of alignment (Ralf Roth, 30 Aug 01) -@x module 789 -to another alignment is being scanned. - -@<Insert the \(v)\<v_j>...@>= -begin if scanner_status=aligning then -@y -to another alignment is being scanned, or when no alignment preamble is active. - -@<Insert the \(v)\<v_j>...@>= -begin if (scanner_status=aligning) or (cur_align=null) then -@z - -418. don't allow end-template except at end of template (Roth, 30 Aug 01) -@x module 325 -while (state=token_list)and(loc=null) do end_token_list; {conserve stack space} -@y -while (state=token_list)and(loc=null)and(token_type<>v_template) do - end_token_list; {conserve stack space} -@z -@x module 390 -while (state=token_list)and(loc=null) do end_token_list; {conserve stack space} -@y -while (state=token_list)and(loc=null)and(token_type<>v_template) do - end_token_list; {conserve stack space} -@z -@x module 1131 -during an entire alignment, until |fin_align| removes it. - -@<Declare act...@>= -procedure do_endv; -begin if cur_group=align_group then -@y -during an entire alignment, until |fin_align| removes it. - -A devious user might force an |endv| command to occur just about anywhere; -we must defeat such hacks. - -@<Declare act...@>= -procedure do_endv; -begin base_ptr:=input_ptr; input_stack[base_ptr]:=cur_input; -while (input_stack[base_ptr].index_field<>v_template) and - (input_stack[base_ptr].loc_field=null) and - (input_stack[base_ptr].state_field=token_list) do decr(base_ptr); -if (input_stack[base_ptr].index_field<>v_template) or - (input_stack[base_ptr].loc_field<>null) or - (input_stack[base_ptr].state_field<>token_list) then - fatal_error("(interwoven alignment preambles are not allowed)"); -@.interwoven alignment preambles...@> - if cur_group=align_group then -@z - -419. Improve rounding of glue during output. -@x module 3 -@!@^dirty \PASCAL@> -@y -@!@^dirty \PASCAL@> - -Incidentally, \PASCAL's standard |round| function can be problematical, -because it disagrees with the IEEE floating-point standard. -Many implementors have -therefore chosen to substitute their own home-grown rounding procedure. -@z -@x module 619 -begin this_box:=temp_ptr; g_order:=glue_order(this_box); -@y -@!cur_glue:real; {glue seen so far} -@!cur_g:scaled; {rounded equivalent of |cur_glue| times the glue ratio} -begin cur_g:=0; cur_glue:=float_constant(0); -this_box:=temp_ptr; g_order:=glue_order(this_box); -@z -@x module 625 -begin g:=glue_ptr(p); rule_wd:=width(g); -if g_sign<>normal then - begin if g_sign=stretching then - begin if stretch_order(g)=g_order then - begin vet_glue(float(glue_set(this_box))*stretch(g)); -@^real multiplication@> - rule_wd:=rule_wd+round(glue_temp); - end; - end - else if shrink_order(g)=g_order then - begin vet_glue(float(glue_set(this_box))*shrink(g)); - rule_wd:=rule_wd-round(glue_temp); - end; - end; -@y -begin g:=glue_ptr(p); rule_wd:=width(g)-cur_g; -if g_sign<>normal then - begin if g_sign=stretching then - begin if stretch_order(g)=g_order then - begin cur_glue:=cur_glue+stretch(g); - vet_glue(float(glue_set(this_box))*cur_glue); -@^real multiplication@> - cur_g:=round(glue_temp); - end; - end - else if shrink_order(g)=g_order then - begin cur_glue:=cur_glue-shrink(g); - vet_glue(float(glue_set(this_box))*cur_glue); - cur_g:=round(glue_temp); - end; - end; -rule_wd:=rule_wd+cur_g; -@z -@x module 629 -begin this_box:=temp_ptr; g_order:=glue_order(this_box); -@y -@!cur_glue:real; {glue seen so far} -@!cur_g:scaled; {rounded equivalent of |cur_glue| times the glue ratio} -begin cur_g:=0; cur_glue:=float_constant(0); -this_box:=temp_ptr; g_order:=glue_order(this_box); -@z -@x module 634 -begin g:=glue_ptr(p); rule_ht:=width(g); -if g_sign<>normal then - begin if g_sign=stretching then - begin if stretch_order(g)=g_order then - begin vet_glue(float(glue_set(this_box))*stretch(g)); -@^real multiplication@> - rule_ht:=rule_ht+round(glue_temp); - end; - end - else if shrink_order(g)=g_order then - begin vet_glue(float(glue_set(this_box))*shrink(g)); - rule_ht:=rule_ht-round(glue_temp); - end; - end; -@y -begin g:=glue_ptr(p); rule_ht:=width(g)-cur_g; -if g_sign<>normal then - begin if g_sign=stretching then - begin if stretch_order(g)=g_order then - begin cur_glue:=cur_glue+stretch(g); - vet_glue(float(glue_set(this_box))*cur_glue); -@^real multiplication@> - cur_g:=round(glue_temp); - end; - end - else if shrink_order(g)=g_order then - begin cur_glue:=cur_glue-shrink(g); - vet_glue(float(glue_set(this_box))*cur_glue); - cur_g:=round(glue_temp); - end; - end; -rule_ht:=rule_ht+cur_g; -@z - -420. Error recovery hindered by missing goto statement (reported by -David Fuchs, September 2007) - -@x module 395 -incr(align_state); long_state:=call; cur_tok:=par_token; ins_error; -@y -incr(align_state); long_state:=call; cur_tok:=par_token; ins_error; -goto continue; -@z - -421. Slight improvement to inner loop speed also eliminates a case -of "dirty Pascal" - -@x module 1035 - begin if character(tail)=qi(hyphen_char[main_f]) then if link(cur_q)>null then -@y - begin if link(cur_q)>null then - if character(tail)=qi(hyphen_char[main_f]) then ins_disc:=true; -@z - -422. Amendment to bugfix 414 (reported by David Fuchs, September 2007) - -@x module 1335 - store_fmt_file; return;@+tini@/ -@y - if last_glue<>max_halfword then delete_glue_ref(last_glue); - store_fmt_file; return;@+tini@/ -@z - -423. Remove leaking glue reference after error (DRF, September 2007) - -@x module 1236 - help2("I can't carry out that multiplication or division,")@/ - ("since the result is out of range."); -@y - 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); -@z - -424. Leaders with muglue is henceforth disallowed (indeed, David Fuchs -observed that it has ever worked, except in 180pt fonts!) - -@x module 1078 -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 -@y -if ((cur_cmd=hskip)and(abs(mode)<>vmode))or@| - ((cur_cmd=vskip)and(abs(mode)=vmode)) then -@z - -425. An optimization suggested by Fuchs that I couldn't resist, because -it improves the inner loop whenever the last letter of a word -has a lig/kern program. Also another twiddle for the inner loop. - -@x module 1039 -if char_tag(main_i)<>lig_tag then goto main_loop_wrapup; -@y -if char_tag(main_i)<>lig_tag then goto main_loop_wrapup; -if cur_r=non_char then goto main_loop_wrapup; -@z -@x module 1036 -tail_append(lig_stack) {|main_loop_lookahead| is next} -@y -link(tail):=lig_stack; tail:=lig_stack {|main_loop_lookahead| is next} -@z - -426. For robustness, enforce a restriction checked by TFtoPL (suggested -by DRF) - -@x module 365 -if lf<>6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np then abort; -@y -if lf<>6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np then abort; -if (nw=0)or(nh=0)or(nd=0)or(ni=0) then abort; -@z - -427. Tell more precisely the effective size of 1:1 insertions (DEK, 27 Feb 08) - -@x module 986 - t:=x_over_n(height(r),1000)*count(t); print_scaled(t); -@y - if count(t)=1000 then t:=height(r) - else t:=x_over_n(height(r),1000)*count(t); - print_scaled(t); -@z - ------------ -999. The absolutely final change (to be made after my death) -@x module 2 -@d banner=='This is TeX, Version 3.141592' {printed when \TeX\ starts} -@y -@d banner=='This is TeX, Version $\pi$' {printed when \TeX\ starts} -@z -When this change is made, the corresponding line should be changed in -Volume B, and also on page 23 of The TeXbook. -My last will and testament for TeX is that no further changes be made -under any circumstances. Improved systems should not be called simply `TeX'; -that name, unqualified, should refer only to the program for which I have -taken personal responsibility. -- Don Knuth - -* Possibly nice ideas that will not be implemented - -. classes of marks analogous to classes of insertions - -. \showcontext to show the current location without stopping for error - -. \show commands to be less like errors - -. \everyeof to insert tokens before an \input file ends - (strange example: \everyeof{\noexpand} will allow things - like \xdef\a{\input foo}!) - -. generalize \leftskip and \rightskip to token lists (problems with - displayed math then) - -. generalize \widowline and \clubline to go further into a paragraph - -. \lastbox to remove and box a charnode if one is there - -. \lastbox to set a new quantity \lastboxshift, to preserve info now lost - -. \posttolerance for third pass of line breaking - -* Design errors that are too late to fix - -. additional parameters should be in symbol fonts to govern the space between - rules and text in \over, \sqrt, etc. - -. multilingual typesetting doesn't work properly when the \lccode changes - within a paragraph - -. large accents cannot be brought close to small letters in math mode - -. \hyphenation is not sensitive to \language - -* Bad ideas that will not be implemented - -. several people want to be able to remove arbitrary elements of lists, - but that must never be done because some of those elements (e.g. kerns - for accents) depend on floating point arithmetic - -. if anybody wants letter spacing desperately they should put it in their own - private version (e.g. generalize the hpack routine) and NOT call it TeX. |