summaryrefslogtreecommitdiff
path: root/info/digests/tex-implementors/023
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /info/digests/tex-implementors/023
Initial commit
Diffstat (limited to 'info/digests/tex-implementors/023')
-rw-r--r--info/digests/tex-implementors/0231229
1 files changed, 1229 insertions, 0 deletions
diff --git a/info/digests/tex-implementors/023 b/info/digests/tex-implementors/023
new file mode 100644
index 0000000000..ecd29551b0
--- /dev/null
+++ b/info/digests/tex-implementors/023
@@ -0,0 +1,1229 @@
+Date: 13 Mar 89 Message No: 023
+
+To: TeX implementors and distributors
+
+From: Barbara Beeton
+
+Subject: Updates to TEX82.BUG, MF84.BUG
+
+
+The last message was sent to this list two months ago, and though some
+additional activity has occurred, I've been delayed in reporting it.
+In fact, I'm not sure that what is included here is the latest news,
+not having seen my paper mail for more than a week, and Don Knuth is no
+longer corresponding with anyone electronically. (I'm preparing this
+message from home, having returned from a standards meeting accompanied
+by a cold germ.)
+
+When last I heard from Don, he reported that though a few "trivial" (his
+word) bugs had been detected, there was nothing he considered serious
+enough to delay his release of TeX 3.0 on the Ides of March -- two days
+hence. So, barring the discovery of something of which I'm not aware, I
+expect that by the end of this week there will be a new version of TEX.MF
+at labrea, with a few inconsequential changes from version 2.993. I will
+try to send the information as soon as possible, but I am facing a couple
+of deadlines at the Math Society, and for the next week I have promised
+to go into seclusion (the AMS thinks it's a vacation) to help prepare the
+data for a 10-volume index to TUGboat.
+
+Enclosed are updates to the files TEX82.BUG and MF84.BUG. Owing to the
+quantity of this material and the proximity of the Ides of March, lists
+of differences between the new and old WEB files will be sent separately.
+
+
+########################################################################
+
+Updates to TEX82.BUG
+
+% note change in comment on #339; the change code remains the same
+
+339. \def\\#1{}\input a\\\z failed (Robert Messer, 24Apr88)
+ ...
+
+373. Allow multiple hyphenmins in the same paragraph (Mike Ferguson).
+@x module 212, two new fields for list_state_record
+@y
+ @!lhm_field,@!rhm_field: quarterword;
+@z
+@x module 213, two new macros to access those fields
+@y
+@d lhmin==cur_list.lhm_field {\.{\\lefthyphenmin} at start of paragraph}
+@d rhmin==cur_list.rhm_field {\.{\\righthyphenmin} at start of paragraph}
+@z
+@x module 215, two new initializations
+@y
+lhmin:=0; rhmin:=0;
+@z
+@x module 218
+ if nest[p].ml_field<0 then print(" (\output routine)");
+@y
+ if m=hmode then@+if(nest[p].lhm_field<>2)or(nest[p].rhm_field<>3)then
+ begin print(" (hyphenmin "); print_int(nest[p].lhm_field); print_char(",");
+ print_int(nest[p].rhm_field); print_char(")");
+ end;
+ if nest[p].ml_field<0 then print(" (\output routine)");
+@z
+@x module 891
+l_hyf:=left_hyphen_min-1;@+if l_hyf<0 then l_hyf:=0;
+r_hyf:=right_hyphen_min-1;@+if r_hyf<0 then r_hyf:=0;
+min_hyf:=l_hyf+r_hyf+2; cur_lang:=0;
+@y
+l_hyf:=lhmin; r_hyf:=rhmin; cur_lang:=0;
+@z
+@x module 892
+@!l_hyf,@!r_hyf,@!min_hyf:integer; {limits on fragment sizes}
+@y
+@!l_hyf,@!r_hyf:integer; {limits on fragment sizes}
+@z
+@x module 894
+begin if min_hyf>63 then goto done1;
+prev_s:=cur_p; s:=link(prev_s);
+if s<>null then
+ begin @<Skip to node |ha|, or |goto done1| if no hyphenation
+ should be attempted@>;
+ @<Skip to node |hb|, putting letters into |hu| and |hc|@>;
+ @<Check that the nodes following |hb| permit hyphenation and that at least
+ |min_hyf| letters have been found, otherwise |goto done1|@>;
+@y
+begin prev_s:=cur_p; s:=link(prev_s);
+if s<>null then
+ begin @<Skip to node |ha|, or |goto done1| if no hyphenation
+ should be attempted@>;
+ if l_hyf+r_hyf>63 then goto done1;
+ @<Skip to node |hb|, putting letters into |hu| and |hc|@>;
+ @<Check that the nodes following |hb| permit hyphenation and that at least
+ |l_hyf+r_hyf| letters have been found, otherwise |goto done1|@>;
+@z
+@x module 899
+if hn<min_hyf then goto done1;
+@y
+if hn<l_hyf+r_hyf then goto done1;
+@z
+@x module 902
+for j:=l_hyf+1 to hn-r_hyf-1 do if odd(hyf[j]) then goto found1;
+@y
+for j:=l_hyf to hn-r_hyf do if odd(hyf[j]) then goto found1;
+@z
+@x module 923
+for j:=0 to hn-r_hyf do
+@y
+for j:=0 to hn-r_hyf+1 do
+@z
+@x ibid
+found: for j:=0 to l_hyf do hyf[j]:=0;
+for j:=0 to r_hyf do hyf[hn-j]:=0
+@y
+found: for j:=0 to l_hyf-1 do hyf[j]:=0;
+for j:=0 to r_hyf-1 do hyf[hn-j]:=0
+@z
+@x module 1091 begins with a new subroutine
+@y
+function norm_min(@!h:integer):small_number;
+begin if h<=0 then norm_min:=1@+else if h>=63 then norm_min:=63@+
+else norm_min:=h;
+end;
+@z
+@x module 1091 then uses the new subroutine
+push_nest; mode:=hmode; space_factor:=1000; clang:=0;
+@y
+lhmin:=norm_min(left_hyphen_min); rhmin:=norm_min(right_hyphen_min);
+push_nest; mode:=hmode; space_factor:=1000; clang:=0;
+@z
+@x module 1341
+@d stored_language(#)==mem[#+1].int {language number, in the range |0..255|}
+@y
+@d what_lang(#)==link(#+1) {language number, in the range |0..255|}
+@d what_lhm(#)==type(#+1) {minimum left fragment, in the range |1..63|}
+@d what_rhm(#)==subtype(#+1) {minimum right fragment, in the range |1..63|}
+@z
+@x module 1356
+ print_int(stored_language(p));
+@y
+ print_int(what_lang(p)); print(" (hyphenmin ");
+ print_int(what_lhm(p)); print_char(",");
+ print_int(what_rhm(p)); print_char(")");
+@z
+@x modules 1362 and 1363
+@ @<Advance \(p)past a whatsit node in the \(l)|line_break| loop@>=
+if subtype(cur_p)=language_node then cur_lang:=stored_language(cur_p)
+
+@ @<Advance \(p)past a whatsit node in the \(p)pre-hyphenation loop@>=
+if subtype(s)=language_node then cur_lang:=stored_language(s)
+@y
+@ @d adv_past(#)==@+if subtype(#)=language_node then
+ begin cur_lang:=what_lang(#); l_hyf:=what_lhm(#); r_hyf:=what_rhm(#);@+end
+
+@<Advance \(p)past a whatsit node in the \(l)|line_break| loop@>=@+
+adv_past(cur_p)
+
+@ @<Advance \(p)past a whatsit node in the \(p)pre-hyphenation loop@>=@+
+adv_past(s)
+@z
+@x module 1376
+ stored_language(tail):=l; clang:=l;
+@y
+ what_lang(tail):=l; clang:=l;@/
+ what_lhm(tail):=norm_min(left_hyphen_min);
+ what_rhm(tail):=norm_min(right_hyphen_min);
+@z
+@x module 1377
+ stored_language(tail):=clang;
+@y
+ what_lang(tail):=clang;
+ what_lhm(tail):=norm_min(left_hyphen_min);
+ what_rhm(tail):=norm_min(right_hyphen_min);
+@z
+
+374. Make \par and end_template definitely non-character (Marc van Leeuwen)
+@x module 14 gets a new line
+@y
+if mem_top<256+11 then bad:=7; {we will want |null_list>255|}
+@z
+@x module 334
+primitive("par",par_end,0); par_loc:=cur_val; par_token:=cs_token_flag+par_loc;
+@y
+primitive("par",par_end,256); {cf. |scan_file_name|}
+par_loc:=cur_val; par_token:=cs_token_flag+par_loc;
+@z
+
+375. Alignments must be more robust to prevent crashes (Marc van Leeuwen)
+@x module 324
+else if token_type=u_template then align_state:=0;
+@y
+else if token_type=u_template then
+ if align_state>500000 then align_state:=0
+ else fatal_error("(interwoven alignment preambles are not allowed)");
+@.interwoven alignment preambles...@>
+@z
+@x module 782
+if (cur_cmd=assign_glue)and(cur_chr=glue_base+tab_skip_code) then
+@y
+if cur_cmd=endv then
+ fatal_error("(interwoven alignment preambles are not allowed)");
+@.interwoven alignment preambles...@>
+if (cur_cmd=assign_glue)and(cur_chr=glue_base+tab_skip_code) then
+@z
+@x module 791
+p:=link(q);
+@y
+if align_state<500000 then
+ fatal_error("(interwoven alignment preambles are not allowed)");
+@.interwoven alignment preambles...@>
+p:=link(q);
+@z
+
+376. Avoid kern removal in discretionary breaks (Marc van Leeuwen)
+@x module 815
+label done,done1,done2,done3,done4,continue;
+@y
+label done,done1,done2,done3,done4,done5,continue;
+@z
+@x module 866
+glue_node: begin @<If node |cur_p| is a legal breakpoint, call |try_break|@>;
+ @<Update the active widths by including the glue in |glue_ptr(cur_p)|@>;
+@y
+glue_node: begin @<If node |cur_p| is a legal breakpoint, call |try_break|;
+ then update the active widths by including the glue in |glue_ptr(cur_p)|@>;
+@z
+@x ibid
+disc_node: @<Try to break after a discretionary fragment@>;
+@y
+disc_node: @<Try to break after a discretionary fragment, then |goto done5|@>;
+@z
+@x ibid
+end
+@y
+done5:end
+@z
+Combine modules 868 and 869 into a single module, with a semicolon between.
+@x module 870 (which becomes module 869) gets ... in its title
+@y and the following new code just before its final "end":
+r:=replace_count(cur_p); s:=link(cur_p);
+while r>0 do
+ begin @<Add the width of node |s| to |act_width|@>;
+ decr(r); s:=link(s);
+ end;
+prev_p:=cur_p; cur_p:=s; goto done5;
+@z
+@x Now module 871 becomes 870, and we add a new (very similar) module 871:
+@y
+@ @<Add the width of node |s| to |act_width|@>=
+if is_char_node(s) then
+ begin f:=font(s);
+ act_width:=act_width+char_width(f)(char_info(f)(character(s)));
+ end
+else case type(s) of
+ ligature_node: begin f:=font(lig_char(s));
+ act_width:=act_width+
+ char_width(f)(char_info(f)(character(lig_char(s))));
+ end;
+ hlist_node,vlist_node,rule_node,kern_node:
+ act_width:=act_width+width(s);
+ othercases confusion("disc4")
+@:this can't happen disc4}{\quad disc4@>
+ endcases
+@z
+@x module 877
+@!disc_break:boolean; {was the current break at a discretionary node?}
+@y
+@!disc_break:boolean; {was the current break at a discretionary node?}
+@!post_disc_break:boolean; {and did it have a nonempty post-break part?}
+@z
+@x ibid
+if cur_p<>null then @<Prune unwanted nodes at the beginning of the next line@>;
+@y
+if cur_p<>null then if not post_disc_break then
+ @<Prune unwanted nodes at the beginning of the next line@>;
+@z
+@x module 881
+q:=cur_break(cur_p); disc_break:=false;
+@y
+q:=cur_break(cur_p); disc_break:=false; post_disc_break:=false;
+@z
+@x module 883
+ if not is_char_node(s) then if next_break(cur_p)<>null then
+ if cur_break(next_break(cur_p))=s then s:=r;
+@y that subtle bug is no longer possible so we can remove the code
+@z
+@x module 884
+link(s):=r; r:=post_break(q); post_break(q):=null;
+@y
+link(s):=r; r:=post_break(q); post_break(q):=null; post_disc_break:=true;
+@z
+
+377. Pick up a few discretionary hyphens that were lost because of
+the new (cautious) algorithm.
+@x module 914
+@ @d advance_major_tail==begin major_tail:=link(major_tail); incr(r_count);
+ end
+
+@<Create and append a discretionary node as an alternative...@>=
+begin r:=get_node(small_node_size);
+@y
+@ In this repeat loop we will insert another discretionary if |hyf[j-1]| is
+odd, after both branches of the previous discretionary end at position |j-1|.
+Strictly speaking, we aren't justified in doing this, because we don't know
+that a hyphen after |j-1| is truly independent of those branches. But in almost
+all applications we would rather not lose a potentially valuable hyphenation
+point. (Consider the word `difficult', where the letter `c' is in position |j|.)
+
+@d advance_major_tail==begin major_tail:=link(major_tail); incr(r_count);
+ end
+
+@<Create and append a discretionary node as an alternative...@>=
+repeat r:=get_node(small_node_size);
+@z
+@x ibid
+i:=hyphen_passed;
+@y
+i:=hyphen_passed; hyf[i]:=0;
+@z
+@x ibid
+end
+@y
+hyphen_passed:=j-1; link(hold_head):=null;
+until not odd(hyf[j-1])
+@z
+
+378. Undumped trie must also be dumpable again (Breitenlohner, 11 Dec 89)
+@x module 1325
+undump_size(0)(trie_size)('trie size')(j); {|trie_max|}
+for k:=0 to j do undump_hh(trie[k]);
+undump_size(0)(trie_op_size)('trie op size')(j); {|trie_op_ptr|}
+@y
+undump_size(0)(trie_size)('trie size')(j); @+init trie_max:=j;@+tini
+for k:=0 to j do undump_hh(trie[k]);
+undump_size(0)(trie_op_size)('trie op size')(j); @+init trie_op_ptr:=j;@+tini
+@z
+@x ibid
+k:=256;
+while j>0 do
+ begin undump(0)(k-1)(k); undump(1)(j)(x); j:=j-x; op_start[k]:=qo(j);
+@y
+init for k:=0 to 255 do trie_used[k]:=min_quarterword;@+tini
+k:=256;
+while j>0 do
+ begin undump(0)(k-1)(k); undump(1)(j)(x);@+init trie_used[k]:=qi(x);@+tini
+ j:=j-x; op_start[k]:=qo(j);
+@z
+
+379. Allow output routine to access page totals. (Suggested by Frank
+Mittelbach and Chris Rowley, December 1989)
+@x module 421
+begin if page_contents=empty then
+@y
+begin if (page_contents=empty) and (not output_active) then
+@z
+
+380. (I sincerely hope that there won't be any more)
+
+
+########################################################################
+
+Updates to MF84.BUG
+
+% The following text has been added at the top of the file; the last
+% two lines of this block correspond to the first two lines of the
+% old file, with some changes.
+
+This file has been updated periodically ever since METAFONT84 was born.
+What you are about to read is "authentic source material" from the
+early days before the program converged. Module numbers on the first
+entries may bear little relation to those in Volume D.
+
+Entries are in chronological order; thus the most recent news appears
+at the bottom of the file.
+
+-------------------------------------------------------------------------------
+
+(rough list of all bugs found in MF after it passed syntax check)
+Starting with Version -100.0: [Mar 27, first run, about 00:30]
+
+ ####################
+
+% New material.
+
+547. String startup problems corresponding to TeX change 355 (17 Jul 89)
+@x module 30 (Warning: This affects most change files!)
+ overflow("buffer size",buf_size);
+@:METAFONT capacity exceeded buffer size}{\quad buffer size@>
+@y
+ @<Report overflow of the input buffer, and abort@>;
+@z
+@x module 34
+consist of the remainder of the command line, after the part that invoked \MF.
+@y
+consist of the remainder of the command line, after the part that invoked \MF.
+
+The first line is special also because it may be read before \MF\ has
+input a base file. In such cases, normal error messages cannot yet
+be given. The following code uses concepts that will be explained later.
+
+@<Report overflow of the input buffer, and abort@>=
+if base_ident=0 then
+ begin write_ln(term_out,'Buffer size exceeded!'); goto final_end;
+@.Buffer size exceeded@>
+ end
+else begin cur_input.loc_field:=first; cur_input.limit_field:=last-1;
+ overflow("buffer size",buf_size);
+@:METAFONT capacity exceeded buffer size}{\quad buffer size@>
+ end
+@z
+@x module 1193
+k:=pool_ptr-4; undump_four_ASCII
+@y
+k:=pool_ptr-4; undump_four_ASCII;
+init_str_ptr:=str_ptr; init_pool_ptr:=pool_ptr;@/
+max_str_ptr:=str_ptr; max_pool_ptr:=pool_ptr
+@z
+@x module 1204
+tini@/
+@y
+init_str_ptr:=str_ptr; init_pool_ptr:=pool_ptr;@/
+max_str_ptr:=str_ptr; max_pool_ptr:=pool_ptr; fix_date_and_time;
+tini@/
+@z
+@x module 1204
+init_str_ptr:=str_ptr; init_pool_ptr:=pool_ptr;@/
+max_str_ptr:=str_ptr; max_pool_ptr:=pool_ptr;@/
+@y
+@z
+
+548. Major changes to allow 8-bit input, cf. TeX82 #359 (11 Sep 89).
+@x module 18
+@!ASCII_code=0..127; {seven-bit numbers}
+@y
+@!ASCII_code=0..255; {eight-bit numbers}
+@z
+@x module 19
+@d last_text_char=127 {ordinal number of the largest element of |text_char|}
+
+@<Local variables for init...@>=
+@!i:0..last_text_char;
+@y
+@d last_text_char=255 {ordinal number of the largest element of |text_char|}
+
+@<Local variables for init...@>=
+@!i:integer;
+@z
+@x module 21
+xchr[0]:=' '; xchr[@'177]:=' ';
+ {ASCII codes 0 and |@'177| do not appear in text}
+@y
+@z
+@x module 22
+for i:=1 to @'37 do xchr[i]:=' ';
+@y changing ' ' to chr(i) here will allow all 8-bit characters to get in
+for i:=0 to @'37 do xchr[i]:=' ';
+for i:=@'177 to @'377 do xchr[i]:=' ';
+@z
+@x module 23
+for i:=1 to @'176 do xord[xchr[i]]:=i;
+@y
+for i:=@'200 to @'377 do xord[xchr[i]]:=i;
+for i:=0 to @'176 do xord[xchr[i]]:=i;
+@z
+@x module 37
+@<Types...@>=
+@!pool_pointer = 0..pool_size; {for variables that point into |str_pool|}
+@!str_number = 0..max_strings; {for variables that point into |str_start|}
+
+@ @<Glob...@>=
+@!str_pool:packed array[pool_pointer] of ASCII_code; {the characters}
+@y [OK to make si(#)==#-128 and so(#)==#+128 (without parens) in change files]
+Some \PASCAL\ compilers won't pack integers into a single byte unless the
+integers lie in the range |-128..127|. To accommodate such systems
+we access the string pool only via macros that can easily be redefined.
+
+@d si(#) == # {convert from |ASCII_code| to |packed_ASCII_code|}
+@d so(#) == # {convert from |packed_ASCII_code| to |ASCII_code|}
+
+@<Types...@>=
+@!pool_pointer = 0..pool_size; {for variables that point into |str_pool|}
+@!str_number = 0..max_strings; {for variables that point into |str_start|}
+@!packed_ASCII_code = 0..255; {elements of |str_pool| array}
+
+@ @<Glob...@>=
+@!str_pool:packed array[pool_pointer] of packed_ASCII_code; {the characters}
+@z
+@x module 41
+begin str_pool[pool_ptr]:=#; incr(pool_ptr);
+@y
+begin str_pool[pool_ptr]:=si(#); incr(pool_ptr);
+@z
+@x module 45
+ begin if str_pool[j]<>buffer[k] then
+@y
+ begin if so(str_pool[j])<>buffer[k] then
+@z
+@x module 47
+var k,@!l:0..127; {small indices or counters}
+@y
+var k,@!l:0..255; {small indices or counters}
+@z
+@x module 47
+@<Make the first 128 strings@>;
+@y
+@<Make the first 256 strings@>;
+@z
+@x module 48
+@ @<Make the first 128...@>=
+for k:=0 to 127 do
+ begin if (@<Character |k| cannot be printed@>) then
+ begin append_char("^"); append_char("^");
+ if k<@'100 then append_char(k+@'100)
+ else append_char(k-@'100);
+@y
+@ @d app_lc_hex(#)==l:=#;
+ if l<10 then append_char(l+"0)@+else append_char(l-10+"a")
+
+@<Make the first 256...@>=
+for k:=0 to 255 do
+ begin if (@<Character |k| cannot be printed@>) then
+ begin append_char("^"); append_char("^");
+ if k<@'100 then append_char(k+@'100)
+ else if k<@'200 then append_char(k-@'100)
+ else begin app_lc_hex(k div 16); app_lc_hex(k mod 16);
+ end;
+@z
+@x module 59
+ begin print_char(str_pool[j]); incr(j);
+@y
+ begin print_char(so(str_pool[j])); incr(j);
+@z
+@x module 60
+ begin print(str_pool[j]); incr(j);
+@y
+ begin print(so(str_pool[j])); incr(j);
+@z
+@x module 85
+ begin if str_pool[j]<>"%" then print(str_pool[j])
+ else if j+1=str_start[err_help+1] then print_ln
+ else if str_pool[j+1]<>"%" then print_ln
+@y
+ begin if str_pool[j]<>si("%") then print(so(str_pool[j]))
+ else if j+1=str_start[err_help+1] then print_ln
+ else if str_pool[j+1]<>si("%") then print_ln
+@z
+@x module 199
+char_class[127]:=invalid_class;
+@y
+for k:=127 to 255 do char_class[k]:=invalid_class;
+@z
+@x module 200
+@d hash_is_full == (hash_used=1) {test if all positions are occupied}
+@d eq_type(#) == eqtb[#].lh {the current ``meaning'' of a symbolic token}
+@d equiv(#) == eqtb[#].rh {parametric part of a token's meaning}
+@d hash_base=129 {hashing actually starts here}
+@y [incidentally I fixed a bug re hash overflow here]
+@d eq_type(#) == eqtb[#].lh {the current ``meaning'' of a symbolic token}
+@d equiv(#) == eqtb[#].rh {parametric part of a token's meaning}
+@d hash_base=257 {hashing actually starts here}
+@d hash_is_full == (hash_used=hash_base) {are all positions occupied?}
+@z
+@x module 210
+for j:=0 to l-1 do buffer[j]:=str_pool[k+j];
+cur_sym:=id_lookup(0,l);@/
+if s>=128 then {we don't want to have the string twice}
+@y
+for j:=0 to l-1 do buffer[j]:=so(str_pool[k+j]);
+cur_sym:=id_lookup(0,l);@/
+if s>=256 then {we don't want to have the string twice}
+@z
+@x module 223
+begin c:=char_class[str_pool[str_start[r]]];
+@y
+begin c:=char_class[so(str_pool[str_start[r]])];
+@z
+@x module 717
+ begin buffer[first]:=str_pool[j]; incr(j); incr(first);
+@y
+ begin buffer[first]:=so(str_pool[j]); incr(j); incr(first);
+@z
+@x module 774
+for j:=str_start[a] to str_start[a+1]-1 do append_to_name(str_pool[j]);
+for j:=str_start[n] to str_start[n+1]-1 do append_to_name(str_pool[j]);
+for j:=str_start[e] to str_start[e+1]-1 do append_to_name(str_pool[j]);
+@y
+for j:=str_start[a] to str_start[a+1]-1 do append_to_name(so(str_pool[j]));
+for j:=str_start[n] to str_start[n+1]-1 do append_to_name(so(str_pool[j]));
+for j:=str_start[e] to str_start[e+1]-1 do append_to_name(so(str_pool[j]));
+@z
+@x module 912
+ else begin cur_exp:=round_unscaled(cur_exp) mod 128; cur_type:=string_type;
+ if cur_exp<0 then cur_exp:=cur_exp+128;
+@y
+ else begin cur_exp:=round_unscaled(cur_exp) mod 256; cur_type:=string_type;
+ if cur_exp<0 then cur_exp:=cur_exp+256;
+@z
+@x module 913
+ else n:=str_pool[str_start[cur_exp]]
+@y
+ else n:=so(str_pool[str_start[cur_exp]])
+@z
+@x ibid
+ begin m:=str_pool[k];
+@y
+ begin m:=so(str_pool[k]);
+@z
+@x module 976
+for k:=str_start[a] to str_start[a+1]-1 do append_char(str_pool[k]);
+for k:=str_start[b] to str_start[b+1]-1 do append_char(str_pool[k]);
+@y
+for k:=str_start[a] to str_start[a+1]-1 do append_char(so(str_pool[k]));
+for k:=str_start[b] to str_start[b+1]-1 do append_char(so(str_pool[k]));
+@z
+@x module 977
+ for k:=str_start[s]+b-1 downto str_start[s]+a do append_char(str_pool[k])
+else for k:=str_start[s]+a to str_start[s]+b-1 do append_char(str_pool[k]);
+@y
+ for k:=str_start[s]+b-1 downto str_start[s]+a do append_char(so(str_pool[k]))
+else for k:=str_start[s]+a to str_start[s]+b-1 do append_char(so(str_pool[k]));
+@z
+@x module 1103
+ begin c:=str_pool[str_start[cur_exp]]; goto found;
+@y
+ begin c:=so(str_pool[str_start[cur_exp]]); goto found;
+@z
+@x module 1160
+ for k:=str_start[s] to str_start[s+1]-1 do gf_out(str_pool[k]);
+ end;
+if t<>0 then for k:=str_start[t] to str_start[t+1]-1 do gf_out(str_pool[k]);
+@y
+ for k:=str_start[s] to str_start[s+1]-1 do gf_out(so(str_pool[k]));
+ end;
+if t<>0 then for k:=str_start[t] to str_start[t+1]-1 do gf_out(so(str_pool[k]));
+@z
+@x module 1192
+ w.b0:=str_pool[k]; w.b1:=str_pool[k+1];
+ w.b2:=str_pool[k+2]; w.b3:=str_pool[k+3];
+@y [often qi(so(x))=x, but not e.g. when "quarterwords" are two bytes]
+ w.b0:=qi(so(str_pool[k])); w.b1:=qi(so(str_pool[k+1]));
+ w.b2:=qi(so(str_pool[k+2])); w.b3:=qi(so(str_pool[k+3]));
+@z
+@x module 1193
+ str_pool[k]:=w.b0; str_pool[k+1]:=w.b1;
+ str_pool[k+2]:=w.b2; str_pool[k+3]:=w.b3
+@y
+ str_pool[k]:=si(qo(w.b0)); str_pool[k+1]:=si(qo(w.b1));
+ str_pool[k+2]:=si(qo(w.b2)); str_pool[k+3]:=si(qo(w.b3))
+@z
+
+549. Make ".base" more easily switchable (see TeX82 log #369).
+@x module 775 gets a new definition
+@y
+@d base_extension=".base" {the extension, as a \.{WEB} constant}
+@z now replace ".base" by base_extension in modules 784 and 1200.
+
+550. "This can't happen" happened because of nonmonotonic rounding
+ (bug found by Mark Eklof, fixed 7 Oct 89)
+@x module 411
+left_x(r):=x_coord(r);
+@y
+left_x(r):=x_coord(r);
+if right_x(p)>x_coord(r) then right_x(p):=x_coord(r);
+ {we always have |x_coord(p)<=right_x(p)|}
+@z
+@x ibid
+else if x_coord(r)>dest_x then x_coord(r):=dest_x;
+@y
+else begin if x_coord(r)>dest_x then
+ begin x_coord(r):=dest_x; left_x(r):=-x_coord(r); right_x(r):=x_coord(r);
+ end;
+ if left_x(q)>dest_x then left_x(q):=dest_x
+ else if left_x(q)<x_coord(r) then left_x(q):=x_coord(r);
+ end;
+@z
+@x module 412
+left_x(s):=x_coord(s);
+negate(x_coord(s)); right_x(s):=x_coord(s);
+negate(left_x(q));
+@y
+left_x(s):=x_coord(s); {now |x_coord(r)=right_x(r)<=left_x(s)|}
+if left_x(q)<dest_x then left_x(q):=-dest_x
+else if left_x(q)>x_coord(s) then left_x(q):=-x_coord(s)
+else negate(left_x(q));
+negate(x_coord(s)); right_x(s):=x_coord(s);
+@z
+@x module 415
+if x_coord(r)>dest_x then x_coord(r):=dest_x
+else if x_coord(r)<x_coord(pp) then x_coord(r):=x_coord(pp);
+if y_coord(r)<y_coord(pp) then y_coord(r):=y_coord(pp);
+left_y(r):=y_coord(r);
+@y
+if y_coord(r)<y_coord(pp) then y_coord(r):=y_coord(pp);
+left_y(r):=y_coord(r);
+if right_y(pp)>y_coord(r) then right_y(pp):=y_coord(r);
+ {we always have |y_coord(pp)<=right_y(pp)|}
+@z
+@x ibid
+else if y_coord(r)>dest_y then y_coord(r):=dest_y;
+@y
+else begin if y_coord(r)>dest_y then
+ begin y_coord(r):=dest_y; left_y(r):=-y_coord(r); right_y(r):=y_coord(r);
+ end;
+ if left_y(qq)>dest_y then left_y(qq):=dest_y
+ else if left_y(qq)<y_coord(r) then left_y(qq):=y_coord(r);
+ end;
+@z
+@x module 416
+if x_coord(s)>dest_x then x_coord(s):=dest_x
+else if x_coord(s)<x_coord(r) then x_coord(s):=x_coord(r);
+if y_coord(s)<dest_y then y_coord(s):=dest_y;
+if y_coord(s)<y_coord(r) then y_coord(s):=y_coord(r);
+right_type(s):=right_type(pp);
+left_y(s):=y_coord(s);
+negate(y_coord(s)); right_y(s):=y_coord(s);
+negate(left_y(qq));
+@y
+if y_coord(s)<dest_y then y_coord(s):=dest_y;
+if y_coord(s)<y_coord(r) then y_coord(s):=y_coord(r);
+right_type(s):=right_type(pp);
+left_y(s):=y_coord(s); {now |y_coord(r)=right_y(r)<=left_y(s)|}
+if left_y(qq)<dest_y then left_y(qq):=-dest_y
+else if left_y(qq)>y_coord(s) then left_y(qq):=-y_coord(s)
+else negate(left_y(qq));
+negate(y_coord(s)); right_y(s):=y_coord(s);
+@z
+@x module 424
+if y_coord(r)>dest_y then y_coord(r):=dest_y
+else if y_coord(r)<y_coord(p) then y_coord(r):=y_coord(p);
+if x_coord(r)<x_coord(p) then x_coord(r):=x_coord(p);
+left_x(r):=x_coord(r);@/
+y_coord(r):=y_coord(r)+x_coord(r); negate(x_coord(r));@/
+right_x(r):=x_coord(r); right_y(r):=right_y(r)-right_x(r);@/
+left_y(q):=left_y(q)+left_x(q); negate(left_x(q));@/
+dest_y:=dest_y+dest_x; negate(dest_x);
+@y
+if x_coord(p)+y_coord(r)>dest_x+dest_y then
+ begin y_coord(r):=dest_x+dest_y-x_coord(p);
+ if left_y(r)>y_coord(r) then
+ begin left_y(r):=y_coord(r);
+ if right_y(p)>y_coord(r) then right_y(p):=y_coord(r);
+ end;
+ end;
+if x_coord(r)<x_coord(p) then x_coord(r):=x_coord(p)
+else if x_coord(r)+y_coord(r)>dest_x+dest_y then
+ x_coord(r):=dest_x+dest_y-y_coord(r);
+left_x(r):=x_coord(r);
+if right_x(p)>x_coord(r) then right_x(p):=x_coord(r);
+ {we always have |x_coord(p)<=right_x(p)|}
+y_coord(r):=y_coord(r)+x_coord(r); right_y(r):=right_y(r)+x_coord(r);@/
+negate(x_coord(r)); right_x(r):=x_coord(r);@/
+left_y(q):=left_y(q)+left_x(q); negate(left_x(q));@/
+dest_y:=dest_y+dest_x; negate(dest_x);
+if right_y(r)>dest_y then right_y(r):=dest_y;
+if left_y(q)>dest_y then left_y(q):=dest_y
+else if left_y(q)<y_coord(r) then left_y(q):=y_coord(r);
+if right_y(r)>left_y(q) then right_y(r):=left_y(q);
+@z
+@x ibid
+else if x_coord(r)>dest_x then x_coord(r):=dest_x
+@y
+else begin if x_coord(r)>dest_x then
+ begin x_coord(r):=dest_x; left_x(r):=-x_coord(r); right_x(r):=x_coord(r);
+ end;
+ if left_x(q)>dest_x then left_x(q):=dest_x
+ else if left_x(q)<x_coord(r) then left_x(q):=x_coord(r);
+ end;
+@z
+@x module 425 is entirely replace
+@y by the following code:
+@ @<Subdivide the cubic a second time with respect to $x'-y'$@>=
+begin split_cubic(r,t,dest_x,dest_y); s:=link(r);@/
+if x_coord(r)+y_coord(s)>dest_x+dest_y then
+ begin y_coord(s):=dest_x+dest_y-x_coord(r);
+ if left_y(s)>y_coord(s) then
+ begin left_y(s):=y_coord(s);
+ if right_y(r)>y_coord(s) then right_y(r):=y_coord(s);
+ end;
+ end;
+if x_coord(s)+y_coord(s)>dest_x+dest_y then x_coord(s):=dest_x+dest_y-y_coord(s)
+else begin if x_coord(s)<dest_x then x_coord(s):=dest_x;
+ if x_coord(s)<x_coord(r) then x_coord(s):=x_coord(r);
+ end;
+right_type(s):=right_type(p);
+left_x(s):=x_coord(s); {now |x_coord(r)=right_x(r)<=left_x(s)|}
+if left_x(q)<dest_x then
+ begin left_y(q):=left_y(q)+dest_x; left_x(q):=-dest_x;@+end
+else if left_x(q)>x_coord(s) then
+ begin left_y(q):=left_y(q)+x_coord(s); left_x(q):=-x_coord(s);@+end
+else begin left_y(q):=left_y(q)+left_x(q); negate(left_x(q));@+end;
+y_coord(s):=y_coord(s)+x_coord(s); right_y(s):=right_y(s)+x_coord(s);@/
+negate(x_coord(s)); right_x(s):=x_coord(s);@/
+dest_y:=dest_y+dest_x;
+if right_y(s)>dest_y then right_y(s):=dest_y;
+if left_y(q)>dest_y then left_y(q):=dest_y
+else if left_y(q)<y_coord(s) then left_y(q):=y_coord(s);
+if right_y(s)>left_y(q) then right_y(s):=left_y(q);
+end
+@z
+
+551. Major change for extended ligatures.
+@x module 11 (this may affect change files)
+@!lig_table_size=300; {maximum number of ligature/kern steps}
+@y
+@!lig_table_size=5000; {maximum number of ligature/kern steps, must be
+ at least 255 and at most 32510}
+@!max_kerns=500; {maximum number of distinct kern amounts}
+@z
+@x module 14 gets a new line of code
+@y
+if(lig_table_size<255)or(lig_table_size>32510)then bad:=7;
+@z
+@x module 186
+@d lig_kern_token=76 {the operators `\&{kern}' and `\.{=:}'}
+@d assignment=77 {the operator `\.{:=}'}
+@d colon=78 {the operator `\.:'}
+@#
+@d comma=79 {the operator `\.,'}
+@d end_of_statement==cur_cmd>comma
+@d semicolon=80 {the operator `\.;', must be |comma+1|}
+@d end_group=81 {end a group (\&{endgroup}), must be |semicolon+1|}
+@d stop=82 {end a job (\&{end}, \&{dump}), must be |end_group+1|}
+@y
+@d lig_kern_token=76
+ {the operators `\&{kern}' and `\.{=:}' and `\.{=:\char'174}, etc.}
+@d assignment=77 {the operator `\.{:=}'}
+@d skip_to=78 {the operation `\&{skipto}'}
+@d bchar_label=79 {the operator `\.{\char'174\char'174:}'}
+@d double_colon=80 {the operator `\.{::}'}
+@d colon=81 {the operator `\.:'}
+@#
+@d comma=82 {the operator `\.,', must be |colon+1|}
+@d end_of_statement==cur_cmd>comma
+@d semicolon=83 {the operator `\.;', must be |comma+1|}
+@d end_group=84 {end a group (\&{endgroup}), must be |semicolon+1|}
+@d stop=85 {end a job (\&{end}, \&{dump}), must be |end_group+1|}
+@z
+@x module 190
+@d max_given_internal=warning_check
+@y
+@d boundary_char=41 {the right boundary character for ligatures}
+@d max_given_internal=41
+@z
+@x module 192 gets two new lines of code
+@y
+primitive("boundarychar",internal_quantity,boundary_char);@/
+@!@:boundary_char_}{\&{boundarychar} primitive@>
+@z
+@x and module 193 gets one too
+@y
+int_name[boundary_char]:="boundarychar";
+@z
+@x and module 211 gets several
+@y (to be inserted in appropriate places)
+primitive("::",double_colon,0);
+@!@::: }{\.{::} primitive@>
+primitive("||:",bchar_label,0);
+@!@:::: }{\.{\char'174\char'174:} primitive@>
+primitive("skipto",skip_to,0);@/
+@!@:skip_to_}{\&{skipto} primitive@>
+@z
+@x as does module 212
+@y
+bchar_label:print("||:");
+double_colon:print("::");
+skip_to:print("skipto");
+@z
+@x module 1093 has new text (see TeX change 362 for module 545) and also this:
+@d stop_bit(#)==lig_kern[#].b0
+@d next_char(#)==lig_kern[#].b1
+@d op_bit(#)==lig_kern[#].b2
+@y
+@d skip_byte(#)==lig_kern[#].b0
+@d next_char(#)==lig_kern[#].b1
+@d op_byte(#)==lig_kern[#].b2
+@z
+@x module 1096 gets a new definition
+@y
+@d undefined_label==lig_table_size {an undefined local label}
+@z
+@x ...and some changed declarations
+@!char_remainder:array[eight_bits] of eight_bits; {the |remainder| byte}
+@!header_byte:array[1..header_size] of -1..255;
+ {bytes of the \.{TFM} header, or $-1$ if unset}
+@!lig_kern:array[0..lig_table_size] of four_quarters; {the ligature/kern table}
+@!nl:0..lig_table_size; {the number of ligature/kern steps so far}
+@!kern:array[eight_bits] of scaled; {distinct kerning amounts}
+@!nk:0..256; {the number of distinct kerns so far}
+@y
+@!char_remainder:array[eight_bits] of 0..lig_table_size; {the |remainder| byte}
+@!header_byte:array[1..header_size] of -1..255;
+ {bytes of the \.{TFM} header, or $-1$ if unset}
+@!lig_kern:array[0..lig_table_size] of four_quarters; {the ligature/kern table}
+@!nl:0..32767-256; {the number of ligature/kern steps so far}
+@!kern:array[0..max_kerns] of scaled; {distinct kerning amounts}
+@!nk:0..max_kerns; {the number of distinct kerns so far}
+@z
+@x ...and some new declarations
+@y
+@!skip_table:array[eight_bits] of 0..lig_table_size; {local label status}
+@!lk_started:boolean; {has there been a lig/kern step in this command yet?}
+@!bchar:integer; {right boundary character}
+@!bch_label:0..lig_table_size; {left boundary starting location}
+@!ll,@!lll:0..lig_table_size; {registers used for lig/kern processing}
+@!label_loc:array[0..256] of -1..lig_table_size; {lig/kern starting addresses}
+@!label_char:array[1..256] of eight_bits; {characters for |label_loc|}
+@!label_ptr:0..256; {highest position occupied in |label_loc|}
+@z
+@x module 1097
+ end;
+for k:=1 to header_size do header_byte[k]:=-1;
+bc:=255; ec:=0; nl:=0; nk:=0; ne:=0; np:=0;
+@y
+ skip_table[k]:=undefined_label;
+ end;
+for k:=1 to header_size do header_byte[k]:=-1;
+bc:=255; ec:=0; nl:=0; nk:=0; ne:=0; np:=0;@/
+internal[boundary_char]:=-unity;
+bch_label:=undefined_label;@/
+label_loc[0]:=-1; label_ptr:=0;
+@z
+@x module 1104
+procedure set_tag(@!c:eight_bits;@!t:small_number;@!r:eight_bits);
+begin if char_tag[c]=no_tag then
+ begin char_tag[c]:=t; char_remainder[c]:=r;
+@y
+procedure set_tag(@!c:halfword;@!t:small_number;@!r:halfword);
+begin if char_tag[c]=no_tag then
+ begin char_tag[c]:=t; char_remainder[c]:=r;
+ if t=lig_tag then
+ begin incr(label_ptr); label_loc[label_ptr]:=r; label_char[label_ptr]:=c;
+ end;
+@z
+@x module 1105
+if (c>" ")and(c<128) then print(c)
+@y
+if (c>" ")and(c<127) then print(c)
+else if c=256 then print("||")
+@z
+@x module 1106
+label continue;
+var @!c,@!cc:eight_bits; {character codes}
+@!k:0..256; {index into the |kern| array}
+@y
+label continue,done;
+var @!c,@!cc:0..256; {character codes}
+@!k:0..max_kerns; {index into the |kern| array}
+@z
+% also the previous code of module 1107 is inserted into 1106
+@x modules 1107--1111 are completely replaced
+@y by the following new code:
+@ @<Store a list of ligature/kern steps@>=
+begin lk_started:=false;
+continue: get_x_next;
+if(cur_cmd=skip_to)and lk_started then
+ @<Process a |skip_to| command and |goto done|@>;
+if cur_cmd=bchar_label then
+ begin c:=256; cur_cmd:=colon;@+end
+else begin back_input; c:=get_code;@+end;
+if(cur_cmd=colon)or(cur_cmd=double_colon)then
+ @<Record a label in a lig/kern subprogram and |goto continue|@>;
+if cur_cmd=lig_kern_token then @<Compile a ligature/kern command@>
+else begin print_err("Illegal ligtable step");
+@.Illegal ligtable step@>
+ help1("I was looking for `=:' or `kern' here.");
+ back_error; next_char(nl):=qi(0); op_byte(nl):=qi(0); rem_byte(nl):=qi(0);@/
+ skip_byte(nl):=stop_flag+1; {this specifies an unconditional stop}
+ end;
+if nl=lig_table_size then overflow("ligtable size",lig_table_size);
+@:METAFONT capacity exceeded ligtable size}{\quad ligtable size@>
+incr(nl);
+if cur_cmd=comma then goto continue;
+if skip_byte(nl-1)<stop_flag then skip_byte(nl-1):=stop_flag;
+done:end
+
+@ @<Put each...@>=
+primitive("=:",lig_kern_token,0);
+@!@:=:_}{\.{=:} primitive@>
+primitive("=:|",lig_kern_token,1);
+@!@:=:/_}{\.{=:\char'174} primitive@>
+primitive("=:|>",lig_kern_token,5);
+@!@:=:/>_}{\.{=:\char'174>} primitive@>
+primitive("|=:",lig_kern_token,2);
+@!@:=:/_}{\.{\char'174=:} primitive@>
+primitive("|=:>",lig_kern_token,6);
+@!@:=:/>_}{\.{\char'174=:>} primitive@>
+primitive("|=:|",lig_kern_token,3);
+@!@:=:/_}{\.{\char'174=:\char'174} primitive@>
+primitive("|=:|>",lig_kern_token,7);
+@!@:=:/>_}{\.{\char'174=:\char'174>} primitive@>
+primitive("|=:|>>",lig_kern_token,11);
+@!@:=:/>_}{\.{\char'174=:\char'174>>} primitive@>
+primitive("kern",lig_kern_token,128);
+@!@:kern_}{\&{kern} primitive@>
+
+@ @<Cases of |print_cmd...@>=
+lig_kern_token: case m of
+0:print("=:");
+1:print("=:|");
+2:print("|=:");
+3:print("|=:|");
+5:print("=:|>");
+6:print("|=:>");
+7:print("|=:|>");
+11:print("|=:|>>");
+othercases print("kern")
+endcases;
+
+@ Local labels are implemented by maintaining the |skip_table| array,
+where |skip_table[c]| is either |undefined_label| or the address of the
+most recent lig/kern instruction that skips to local label~|c|. In the
+latter case, the |skip_byte| in that instruction will (temporarily)
+be zero if there were no prior skips to this label, or it will be the
+distance to the prior skip.
+
+We may need to cancel skips that span more than 127 lig/kern steps.
+
+@d cancel_skips(#)==ll:=#;
+ repeat lll:=qo(skip_byte(ll)); skip_byte(ll):=stop_flag; ll:=ll-lll;
+ until lll=0
+@d skip_error(#)==begin print_err("Too far to skip");
+@.Too far to skip@>
+ help1("At most 127 lig/kern steps can separate skipto1 from 1::.");
+ error; cancel_skips(#);
+ end
+
+@<Process a |skip_to| command and |goto done|@>=
+begin c:=get_code;
+if nl-skip_table[c]>128 then {|skip_table[c]<<nl<=undefined_label|}
+ begin skip_error(skip_table[c]); skip_table[c]:=undefined_label;
+ end;
+if skip_table[c]=undefined_label then skip_byte(nl-1):=qi(0)
+else skip_byte(nl-1):=qi(nl-skip_table[c]-1);
+skip_table[c]:=nl-1; goto done;
+end
+
+@ @<Record a label in a lig/kern subprogram and |goto continue|@>=
+begin if cur_cmd=colon then
+ if c=256 then bch_label:=nl
+ else set_tag(c,lig_tag,nl)
+else if skip_table[c]<undefined_label then
+ begin ll:=skip_table[c]; skip_table[c]:=undefined_label;
+ repeat lll:=qo(skip_byte(ll));
+ if nl-ll>128 then
+ begin skip_error(ll); goto continue;
+ end;
+ skip_byte(ll):=qi(nl-ll-1); ll:=ll-lll;
+ until lll=0;
+ end;
+goto continue;
+end
+@x module 1112
+next_char(nl):=qi(c); op_bit(nl):=qi(cur_mod); stop_bit(nl):=qi(0);
+if cur_mod=0 then rem_byte(nl):=qi(get_code)
+@y
+begin next_char(nl):=qi(c); skip_byte(nl):=qi(0);
+if cur_mod<128 then {ligature op}
+ begin op_byte(nl):=qi(cur_mod); rem_byte(nl):=qi(get_code);
+ end
+@z
+@x ibid
+ begin if nk=256 then overflow("kern",256);
+@:METAFONT capacity exceeded kern}{\quad kern@>
+ incr(nk);
+ end;
+ rem_byte(nl):=qi(k);
+ end
+@y
+ begin if nk=max_kerns then overflow("kern",max_kerns);
+@:METAFONT capacity exceeded kern}{\quad kern@>
+ incr(nk);
+ end;
+ op_byte(nl):=kern_flag+(k div 256);
+ rem_byte(nl):=qi((k mod 256));
+ end;
+lk_started:=true;
+end
+@z
+@x module 1135
+tfm_two(6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np);
+ {this is the total number of file words that will be output}
+tfm_two(lh); tfm_two(bc); tfm_two(ec); tfm_two(nw); tfm_two(nh);
+tfm_two(nd); tfm_two(ni); tfm_two(nl); tfm_two(nk); tfm_two(ne); tfm_two(np);
+@y
+@<Compute the ligature/kern program offset and implant the
+ left boundary label@>;
+tfm_two(6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+lk_offset+nk+ne+np);
+ {this is the total number of file words that will be output}
+tfm_two(lh); tfm_two(bc); tfm_two(ec); tfm_two(nw); tfm_two(nh);
+tfm_two(nd); tfm_two(ni); tfm_two(nl+lk_offset); tfm_two(nk); tfm_two(ne);
+tfm_two(np);
+@z
+% modules 1137&1138 are combined into a single module
+% and so are modules 1140--1141, to make room for two new modules.
+@x module 1136 is moved to after old module 1141
+@y and changed to the following code:
+@ @<Log the subfile sizes of the \.{TFM} file@>=
+if bch_label<undefined_label then decr(nl);
+wlog_ln('(You used ',nw:1,'w,',@| nh:1,'h,',@| nd:1,'d,',@| ni:1,'i,',@|
+ nl:1,'l,',@| nk:1,'k,',@| ne:1,'e,',@|
+ np:1,'p metric file positions');
+wlog_ln(' out of ',@| '256w,16h,16d,64i,',@|
+ lig_table_size:1,'l,',max_kerns:1,'k,256e,',@|
+ max_font_dimen:1,'p)');
+end
+@z
+@x module 1139 is completely replaced
+@y by the following three modules:
+@ We need to output special instructions at the beginning of the
+|lig_kern| array in order to specify the right boundary character
+and/or to handle starting addresses that exceed 255. The |label_loc|
+and |label_char| arrays have been set up to record all the
+starting addesses; we have $-1=|label_loc|[0]<|label_loc|[1]\le\cdots
+\le|label_loc|[|label_ptr]|$.
+
+@<Compute the ligature/kern program offset...@>=
+bchar:=round_unscaled(internal[boundary_char]);
+if(bchar<0)or(bchar>255)then
+ begin bchar:=-1; lk_started:=false; lk_offset:=0;@+end
+else begin lk_started:=true; lk_offset:=1;@+end;
+@<Find the minimum |lk_offset| and adjust all remainders@>;
+if bch_label<undefined_label then
+ begin skip_byte(nl):=qi(255); next_char(nl):=qi(0);
+ op_byte(nl):=qi(((bch_label+lk_offset)div 256));
+ rem_byte(nl):=qi(((bch_label+lk_offset)mod 256));
+ incr(nl); {possibly |nl=lig_table_size+1|}
+ end
+
+@ @<Find the minimum |lk_offset|...@>=
+k:=label_ptr; {pointer to the largest unallocated label}
+if label_loc[k]+lk_offset>255 then
+ begin lk_offset:=0; lk_started:=false; {location 0 can do double duty}
+ repeat char_remainder[label_char[k]]:=lk_offset;
+ while label_loc[k-1]=label_loc[k] do
+ begin decr(k); char_remainder[label_char[k]]:=lk_offset;
+ end;
+ incr(lk_offset); decr(k);
+ until lk_offset+label_loc[k]<256;
+ {N.B.: |lk_offset=256| satisfies this when |k=0|}
+ end;
+if lk_offset>0 then
+ while k>0 do
+ begin char_remainder[label_char[k]]
+ :=char_remainder[label_char[k]]+lk_offset;
+ decr(k);
+ end
+
+@ @<Output the ligature/kern program@>=
+for k:=0 to 255 do if skip_table[k]<undefined_label then
+ begin print_nl("(local label "); print_int(k); print(":: was missing)");
+@.local label l:: was missing@>
+ cancel_skips(skip_table[k]);
+ end;
+if lk_started then {|lk_offset=1| for the special |bchar|}
+ begin tfm_out(255); tfm_out(bchar); tfm_two(0);
+ end
+else for k:=1 to lk_offset do {output the redirection specs}
+ begin ll:=label_loc[label_ptr];
+ if bchar<0 then
+ begin tfm_out(254); tfm_out(0);
+ end
+ else begin tfm_out(255); tfm_out(bchar);
+ end;
+ tfm_two(ll+lk_offset);
+ repeat decr(label_ptr);
+ until label_loc[label_ptr]<ll;
+ end;
+for k:=0 to nl-1 do tfm_qqqq(lig_kern[k]);
+for k:=0 to nk-1 do tfm_four(dimen_out(kern[k]))
+@z
+@x module 1205 gets a new declaration
+@y
+@!lk_offset:0..256; {extra words inserted at beginning of |lig_kern| array}
+@z
+
+552. Improved the covering/shortening routines. (18 Dec 89)
+@x module 1119 gets a new global variable
+@y
+@!excess:halfword; {the list is this much too long}
+@z
+@x module 1120 gives it a value
+begin if min_cover(0)<=m then threshold:=0
+@y
+begin excess:=min_cover(0)-m;
+if excess<=0 then threshold:=0
+@z
+@x and module 1122 uses it
+begin repeat p:=link(p); info(p):=m;
+@y
+begin repeat p:=link(p); info(p):=m;
+decr(excess);@+if excess=0 then d:=0;
+@z
+@x and module 1122 also avoids overflow/ambiguous halving
+v:=half(l+value(p));
+@y
+v:=l+half(value(p)-l);
+@z
+
+553. (Change made by Joe Weening as per message from DEK.)
+@x module 1119
+@!excess:halfword; {the list is this much too long}
+@y
+@!excess:integer; {the list is this much too long}
+@z
+
+554. (I sincerely hope that there won't be any more)
+
+
+########################################################################
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Character code reference
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% Upper case letters: ABCDEFGHIJKLMNOPQRSTUVWXYZ
+% Lower case letters: abcdefghijklmnopqrstuvwxyz
+% Digits: 0123456789
+% Square, curly, angle braces, parentheses: [] {} <> ()
+% Backslash, slash, vertical bar: \ / |
+% Punctuation: . ? ! , : ;
+% Underscore, hyphen, equals sign: _ - =
+% Quotes--right left double: ' ` "
+%"at", "number" "dollar", "percent", "and": @ # $ % &
+% "hat", "star", "plus", "tilde": ^ * + ~
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+[ end of message 023 ]