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_style0 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:@; 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@> @= 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 . f. Delete the primitive ":" in modules 250 and 251. g. Add to module 376: 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: ; 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 k. Module 389 becomes = 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: = procedure scan_font_ident; var f:internal_font_number; begin ; 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. = 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 ; u:=cs_ptr; scan_optional_equals; scan_file_name; ; ; 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. = for f:=font_base+1 to font_ptr do if [the test previously in module 1174] then goto common_ending cc. New module 1173: = 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: = 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: ; define(u,set_font,undefined_font); scan_optional_equals; scan_file_name; ; ; 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. = get_token; if cs_ptr0 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+= let: begin get_token; if cs_ptr<>0 then 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: = 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("") else print_nl(" "); inserted: print_nl(" "); 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 "" 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: ; 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. @= 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 "" 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 "" 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 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) 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 ; goto restart; end; In module 1064, the body of the procedure becomes begin if c>='4000 then else ; end And there's a new module: = 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 = 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= 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: @ @= 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 interaction0 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 \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: = 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 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=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 @; Then define @ 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 replaced by \ifodd (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: 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 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. 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 (Jun 14) The optional space will now be analogous to that after . 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 then . 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. = 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] 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 @;@+save_cond_ptr:=cond_ptr;@/ @y @!this_if:small_number; {type of this conditional} begin @;@+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@> @= 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 @ @= 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,@!lx:integer; {quantities used in calculations for leaders} @y @!lq,@!lr:integer; {quantities used in calculations for leaders} @z @x in module 626 begin edge:=cur_h+rule_wd; @; while cur_h+leader_wd<=edge do @; @y begin edge:=cur_h+rule_wd; lx:=0; @; while cur_h+leader_wd<=edge do @; @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; @; while cur_v+leader_ht<=edge do @; @y begin edge:=cur_v+rule_ht; lx:=0; @; while cur_v+leader_ht<=edge do @; @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 @ @= @y @ @= 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: @; @y if_void_code, if_hbox_code, if_vbox_code: @; @z @x module 505 @ @= begin scan_eight_bit_int; b:=(box(cur_val)=null); end @y @ @= 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 then if selector @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: @; @y last_item: @; @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@> @= 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. @= 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 @; @y @; @z @x module 996 @ @= 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 @ @= 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); @; {this sets |last_page_glue:=max_halfword|} @y if last_glue<>max_halfword then delete_glue_ref(last_glue); @; {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 @ 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 @ else begin if not is_char_node(tail) then if type(tail)=cur_chr then @z @x module 1106 @ @= 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 @ @= 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} @; define(u,set_font,null_font); scan_optional_equals; scan_file_name; @; @; 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; @; @; 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}. @= get_r_token; if cs_ptr 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} @= @!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} @= @!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; @; if cur_cmd<>left_brace then @; back_input; q:=scan_toks(false,false); @y @; if cur_cmd<>left_brace then @; 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 jbuffer[k] then goto not_found; @y begin j:=str_start[s]; while jbuffer[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 if cur_cmd<=max_command then goto done; if cur_cmd>=call then if cur_cmd0 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. The final corrections 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 @; @z @x module 176 (removing a reference to |font_ident|) else sprint_cs(font_ident[font(p)]); @y else @; @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_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; @; @; 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; @; @; 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): @; @y any_state_plus(invalid_char): @; @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 @; @y if name=str_ptr-1 then {we can conserve string pool space now} begin flush_string; name:=cur_name; end; @; @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}funity 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 @; @y begin deletions_allowed:=false; @; @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} @@; 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 @@; 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. * Possibly nice ideas that will not be implemented . Classes of marks analogous to classes of insertions . \badness n, the badness of \box n . A way to copy the current page before its insertions have been removed