OSDN Git Service

removed web2c version of PUTeX.
[putex/putex.git] / src / putex / putex400.ch
1 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 %%%
3 %%%  WEB Change File for PUTeX (CJK version)
4 %%%  Modified and patched version for TeX Live
5 %%%
6 %%%  Copyright (C) 1997-2004 Chey-Woei Tsay <cwtsay@pu.edu.tw>
7 %%%  Copyright (C) 2013-2014 Clerk Ma      <clerkma@gmail.com>
8 %%%
9 %%%  This is the change file of PUTeX.
10 %%%
11 %%%  PUTeX is a free software; you can redistribute it and/or
12 %%%  modify it under the terms of the GNU General Public License as
13 %%%  published by the Free Software Foundation; either version 3, or (at
14 %%%  your option) any later version.
15 %%%
16 %%%  PUTeX is distributed in the hope that it will be useful, but
17 %%%  WITHOUT ANY WARRANTY; without even the implied warranty of
18 %%%  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 %%%  General Public License for more details.
20 %%%
21 %%%  You should have received a copy of the GNU General Public License
22 %%%  along with TeX Live; if not, write to the Free Software
23 %%%  Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
24 %%%  USA.
25 %%%
26 %%%
27 %%%  Version 4.0
28 %%%     add \PUXcatcode command to set catcodes of dbcs characters.
29 %%%     remove print_dbchar (58, 59, 70, 318, print_chinese_int)
30 %%% 
31 %%%  Version 4.0-web2c
32 %%%     removed the MikTeX part.
33 %%%  
34 %%%
35 %%%  TO DO:
36 %%%  new_character(582), make_accent(1123), char_box, rebox
37 %%%  mathmode: be awear of print_ASCII
38 %%%  check '(cat_code(buffer[loc])<>escape)' in section 1337
39 %%%
40 %%%  \PUXsetcfacehook -- set cface hook macro that is called when switched to the cface
41 %%%  \PUXsetcfonthook -- set cfont hook macro that is called when switched to the cfont
42 %%%
43 %%%  see section 224 for cspace skip and cespace skip
44 %%%
45 %%%  New Indices:
46 %%%     @^Input Encoding Dependencies@>
47 %%%     @^Modified for handling DBCS characters@>
48 %%%     @^CJK Fonts Extension@>
49
50 @x
51 \def\gglob{20, 26} % this should be the next two sections of "<Global...>"
52 @y
53 \def\gglob{20, 26} % this should be the next two sections of "<Global...>"
54 \def\PUTeX{PU\TeX}
55 \def\putexadd{\hskip -0.5in putex -- add -- }
56 \def\putexmod{\hskip -0.5in putex -- mod -- }
57 \def\putexend{\hskip -0.5in putex -- end -- }
58 @z
59
60 @x
61 @d banner==TeX_banner
62 @d banner_k==TeX_banner_k
63 @y
64 @d PUTeX_version_string=='-5.0' {current \PUTeX\ version}
65 @#
66 @d PUTeX_banner=='This is PUTeX, Version 3.1415926',PUTeX_version_string
67 @d PUTeX_banner_k==PUTeX_banner
68   {printed when \PUTeX\ starts}
69 @#
70 @d banner==PUTeX_banner
71 @d banner_k==PUTeX_banner_k
72 @z
73
74 @x
75 @t\4@>@<Error handling procedures@>@/
76 @y
77 @t\4@>@<Error handling procedures@>@/
78 @t\4@>@<PUTeX routines that will be used by TeX routines@>@/
79 @#
80 { end -- putex}
81 @z
82
83 @x
84 xchr[@'40]:=' ';
85 @y
86 @#@t\putexadd@>@#
87 for k := 0 to 255 do xchr[k] := k;
88 @#@t\putexend@>@#
89 xchr[@'40]:=' ';
90 @z
91
92 @x
93 The |append_char| macro, defined here, does not check to see if the
94 value of |pool_ptr| has gotten too high; this test is supposed to be
95 made before |append_char| is used. There is also a |flush_char|
96 @y
97 The |append_char| and |append_wchar| macros, defined here, do not check to see if the
98 value of |pool_ptr| has gotten too high; this test is supposed to be
99 made before |append_char| (or |append_wchar|) is used. There is also a |flush_char|
100 @z
101
102 @x
103 @d append_char(#) == {put |ASCII_code| \# at the end of |str_pool|}
104 begin str_pool[pool_ptr]:=si(#); incr(pool_ptr);
105 end
106 @y
107 @d append_char(#) == {put |ASCII_code| \# at the end of |str_pool|}
108 begin str_pool[pool_ptr]:=si(#); incr(pool_ptr);
109 end
110 @#@t\putexadd@>
111 @d append_wchar(#) == {TCW: put a double-byte char \# at the end of |str_pool|}
112 begin str_pool[pool_ptr]:=# div 256; str_pool[pool_ptr+1]:=# mod 256;
113 pool_ptr:=pool_ptr+2;
114 end
115 @#@t\putexend@>
116 @z
117
118 @x
119 using the |xchr| array to map it into an external character compatible with
120 |input_ln|. All printing comes through |print_ln| or |print_char|.
121 @y
122 using the |xchr| array to map it into an external character compatible with
123 |input_ln|. All printing comes through |print_ln|, |print_char|, or |print_wchar|.
124
125 TCW: The |print_wchar| macro is used to print one DBCS character. 
126
127 @d print_wchar(#)==begin print_char((#) div 256); print_char((#) mod 256) end {TCW}
128 @z
129
130 @x
131 @d character == subtype {the character code in a |char_node|}
132 @y
133 @d character == subtype {the character code in a |char_node|}
134 @d is_wchar_node(#) == (character(#)>255)
135 @d is_wchar(#) == ((#)>255)
136 @z
137
138 %% parallel kanji font, when typesetting kanjis, we need a match table.
139 @x
140 @!font_in_short_display:integer; {an internal font number}
141 @y
142 @!font_in_short_display:integer; {an internal font number}
143 @!cfont_in_short_display:integer; {TCW: an internal CJK font number}
144 @z
145
146 @x
147 sort of ``complicated'' are indicated only by printing `\.{[]}'.
148 @y
149 sort of ``complicated'' are indicated only by printing `\.{[]}'.@^CJK Fonts Extension@>
150 @z
151
152 @x
153       begin if font(p)<>font_in_short_display then
154         begin if (font(p)>font_max) then
155           print_char("*")
156 @.*\relax@>
157         else @<Print the font identifier for |font(p)|@>;
158         print_char(" "); font_in_short_display:=font(p);
159         end;
160       print_ASCII(qo(character(p)));
161       end;
162 @y
163       begin if font(p)<>font_in_short_display and font(p)<>cfont_in_short_display then
164         begin if (font(p)>cfont_max) then
165           print_char("*")
166 @.*\relax@>
167         else @<Print the font identifier for |font(p)|@>;
168         print_char(" ");
169         if font(p) <= font_max then
170           font_in_short_display:=font(p)
171         else
172           cfont_in_short_display:=font(p);
173         end;
174       if is_wchar_node(p) then
175         print_wchar(character(p))
176       else
177         print_ASCII(qo(character(p)));
178       end;
179 @z
180
181 @x
182 its reference count, and one to print a rule dimension.
183 @y
184 its reference count, and one to print a rule dimension.@^CJK Fonts Extension@>
185 @z
186
187 @x
188 else  begin if (font(p)>font_max) then print_char("*")
189 @y
190 else  begin if (font(p)>cfont_max) then print_char("*")
191 @z
192
193 @x
194   print_char(" "); print_ASCII(qo(character(p)));
195 @y
196   print_char(" ");
197   if is_wchar_node(p) then
198     print_wchar(character(p))
199   else
200     print_ASCII(qo(character(p)));
201 @z
202
203 %% for kinsoku
204 @x
205 @d max_char_code=15 {largest catcode for individual characters}
206 @y
207 @d max_char_code=15 {largest catcode for individual characters}
208 @d boundary_normal=0 {CJK characters can be in any positions of lines}
209 @d tail_forbidden=1 {CJK characters can't be put in the head of lines}
210 @d head_forbidden=2 {CJK characters can't be put in the tail of lines}
211 @d max_type_code=2 {largest boundary code for CJK characters}
212 @d set_type_code_end(#) == # end
213 @d set_type_code(#) == begin
214     type_code(#) := set_type_code_end
215 @z
216
217 @x
218 @ The next codes are special; they all relate to mode-independent
219 assignment of values to \TeX's internal registers or tables.
220 Codes that are |max_internal| or less represent internal quantities
221 that might be expanded by `\.{\\the}'.
222 @y
223 @ The next codes are special; they all relate to mode-independent
224 assignment of values to \TeX's internal registers or tables.
225 Codes that are |max_internal| or less represent internal quantities
226 that might be expanded by `\.{\\the}'.
227
228 TCW: Add 3 internal commands: |set_cfont|, |puxg_assign_flag|, and |puxg_assign_int|.
229 Add 12 user commands: |pux_cface_def|, |pux_face_match|, |pux_font_match|,
230 |pux_set_cface|, |pux_set_cface_attrib|,|pux_set_cfont_attrib|,
231 |pux_char_num|, |pux_char_given|, |pux_space|, |pux_range_catcode|,
232 |pux_range_type_code|, and |pux_dump_font_info|.@^CJK Fonts Extension@>
233 @z
234
235 @x
236 @d def_font=88 {define a font file ( \.{\\font} )}
237 @d register=89 {internal register ( \.{\\count}, \.{\\dimen}, etc.~)}
238 @d max_internal=89 {the largest code that can follow \.{\\the}}
239 @d advance=90 {advance a register or parameter ( \.{\\advance} )}
240 @d multiply=91 {multiply a register or parameter ( \.{\\multiply} )}
241 @d divide=92 {divide a register or parameter ( \.{\\divide} )}
242 @d prefix=93 {qualify a definition ( \.{\\global}, \.{\\long}, \.{\\outer} )}
243 @d let=94 {assign a command code ( \.{\\let}, \.{\\futurelet} )}
244 @d shorthand_def=95 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)}
245   {or \.{\\charsubdef}}
246 @d read_to_cs=96 {read into a control sequence ( \.{\\read} )}
247 @d def=97 {macro definition ( \.{\\def}, \.{\\gdef}, \.{\\xdef}, \.{\\edef} )}
248 @d set_box=98 {set a box ( \.{\\setbox} )}
249 @d hyph_data=99 {hyphenation data ( \.{\\hyphenation}, \.{\\patterns} )}
250 @d set_interaction=100 {define level of interaction ( \.{\\batchmode}, etc.~)}
251 @d max_command=100 {the largest command code seen at |big_switch|}
252 @y
253 @d set_cfont=88 {TCW: set current chinese font ( font identifiers )}
254 @d def_font=89 {define a font file ( \.{\\font} )}
255 @d register=90 {internal register ( \.{\\count}, \.{\\dimen}, etc.~)}
256 @d puxg_assign_flag=91 {TCW: set a PU\TeX\ global flag (\.{\\puxgCdiOut}, \.{\\puxgRotateCtext})}
257 @d puxg_assign_int=92 {TCW: set a PU\TeX\ global integer (\.{\\puxgCspace}, \.{\\puxgCEspace})}
258 @d pux_get_int=93 {TCW: get internal integer values ( \.{\\PUXnumdigits}, \.{\\PUXsign}, \.{\\PUXdigit} )}
259 @d max_internal=93 {the largest code that can follow \.{\\the}}
260 @d advance=94 {advance a register or parameter ( \.{\\advance} )}
261 @d multiply=95 {multiply a register or parameter ( \.{\\multiply} )}
262 @d divide=96 {divide a register or parameter ( \.{\\divide} )}
263 @d prefix=97 {qualify a definition ( \.{\\global}, \.{\\long}, \.{\\outer} )}
264 @d let=98 {assign a command code ( \.{\\let}, \.{\\futurelet} )}
265 @d shorthand_def=99 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)}
266   {or \.{\\charsubdef}}
267 @d read_to_cs=100 {read into a control sequence ( \.{\\read} )}
268 @d def=101 {macro definition ( \.{\\def}, \.{\\gdef}, \.{\\xdef}, \.{\\edef} )}
269 @d set_box=102 {set a box ( \.{\\setbox} )}
270 @d hyph_data=103 {hyphenation data ( \.{\\hyphenation}, \.{\\patterns} )}
271 @d set_interaction=104 {define level of interaction ( \.{\\batchmode}, etc.~)}
272 @d pux_cface_def=105 {TCW: define a chinese font face ( \.{\\PUXcfacedef} )}
273 @d pux_face_match=106 {TCW: English and Chinese face matching pair ( \.{\\PUXfacematch} )}
274 @d pux_font_match=107 {TCW: English and CJK font matching pair ( \.{\\PUXfontmatch} )}
275 @d pux_set_cface=108 {TCW: Set Chinese face}
276 @d pux_set_cface_attrib=109 {TCW: Set attributes of a Chinese face ( \.{\\PUXsetcfacecspace, etc.} )}
277 @d pux_set_cfont_attrib=110 {TCW: Set attributes of a CJK font ( \.{\\PUXsetcfontcspace, etc.} )}
278 @d pux_char_num=111 {TCW: Chinese character number ( \.{\\PUXchar} )}
279 @d pux_char_given=112 {TCW: define a Chinese character ( \.{\\PUXchardef} )}
280 @d pux_space=113 {Append space glue between Chinese and Tex characters ( \.{\\PUXcespace} )}
281 @d pux_range_catcode=114 {TCW: set catcodes for a range of characters( \.{\\PUXrangecatcode} )}
282 @d pux_range_type_code=115 {TCW: set catcodes for a range of characters( \.{\\PUXrangecatcode} )}
283 @d pux_split_number=116 {TCW: split a number to digits ( \.{\\PUXsplitnumber} )}
284 @d puxg_assign_space=117 {TCW: set a PU\TeX\ global integer (\.{\\puxgCspace}, \.{\\puxgCEspace})}
285 @d pux_set_default_cface=118 {TCW: set default CJK font face ( \.{\\PUXsetdefaultcface} )}
286 @d pux_dump_font_info=119 {TCW: dump font information ( \.{\\PUXdumpfontinfo} )}
287 @d max_command=119 {the largest command code seen at |big_switch|}
288 @z
289
290 @x
291 In the first region we have 256 equivalents for ``active characters'' that
292 act as control sequences, followed by 256 equivalents for single-character
293 control sequences.
294 @y
295 In the first region we have 65536 equivalents for ``active characters'' that
296 act as control sequences, followed by 65536 equivalents for single-character
297 control sequences.
298 @z
299
300 @x
301 @d single_base=active_base+256 {equivalents of one-character control sequences}
302 @d null_cs=single_base+256 {equivalent of \.{\\csname\\endcsname}}
303 @y
304 @d single_base=active_base+65536 {equivalents of one-character control sequences}
305 @d null_cs=single_base+65536 {equivalent of \.{\\csname\\endcsname}}
306 @z
307
308 %% parallel font
309 @x
310 @d font_id_base=frozen_null_font-font_base
311   {begins table of 257 permanent font identifiers}
312 @d undefined_control_sequence=frozen_null_font+max_font_max+1 {dummy location}
313 @y
314 @d font_id_base=frozen_null_font-font_base
315   {begins table of 257 permanent English font identifiers}
316 @d font_max_limit=5000
317 @d cfont_id_base=font_id_base+font_max_limit+1
318   {TCW: begins table of 'font\_max\_limit' permanent CJK font identifiers}
319 @d cfont_max_limit=font_max_limit
320 @d cface_id_base=cfont_id_base+cfont_max_limit+1
321   {TCW: begins table of 257 permanent Chinese face identifiers}
322 @d undefined_control_sequence=cface_id_base+257 {dummy location}
323 @z
324
325 @x
326 token parameters, as well as the tables of \.{\\toks} and \.{\\box}
327 registers.
328 @y
329 token parameters, as well as the tables of \.{\\toks} and \.{\\box}
330 registers.
331
332 TCW: Define |cur_cfont_loc| for two-byte char and the macro |cur_cfont|.
333 @z
334
335 @x
336 @d math_font_base=cur_font_loc+1 {table of 48 math font numbers}
337 @y
338 @d cur_cface_loc=cur_font_loc+1 {TCW: internal chinese font number outside math mode}
339 @d cur_cfont_loc=cur_cface_loc+1 {TCW: internal chinese font number outside math mode}
340 @d ectbl_cface_num_base=cur_cfont_loc+1 {TCW: table of 257 CJK face numbers matched with TeX face}
341 @d max_cface=256 {maximal CJK font faces number}
342 @d font_matching_table_base=ectbl_cface_num_base+max_cface+1 {table of font matches}
343 @d math_font_base=font_matching_table_base+font_max_limit+1 {table of 48 math font numbers}
344 @z
345
346 @x
347   {table of 256 command codes (the ``catcodes'')}
348 @d lc_code_base=cat_code_base+256 {table of 256 lowercase mappings}
349 @y
350   {TCW: table of 65536 command codes (the ``catcodes'')}
351 @d pux_cat_code_base=cat_code_base+256
352 @d pux_type_code_base=cat_code_base+65536 {TCW: table of 65536 type codes}
353 @d lc_code_base=pux_type_code_base+65536 {table of 256 lowercase mappings}
354 @z
355
356 @x
357 @d math_code_base=sf_code_base+256 {table of 256 math mode mappings}
358 @y
359 @d pux_local_names_base=sf_code_base+256 {TCW: table of 256 CJK name mappings.}
360 @d math_code_base=pux_local_names_base+256 {table of 256 math mode mappings}
361 @z
362
363 @x
364 @d cur_font==equiv(cur_font_loc)
365 @y
366 @d cur_font==equiv(cur_font_loc)
367 @d cur_cface==equiv(cur_cface_loc) {TCW}
368 @d cur_cfont==equiv(cur_cfont_loc) {TCW}
369 @d ectbl_cface_num(#)==equiv(ectbl_cface_num_base+(#)) {TCW}
370 @d font_matching_table(#)==equiv(font_matching_table_base+((#)-font_base)) {TCW}
371 @z
372
373 @x
374 @d cat_code(#)==equiv(cat_code_base+#)
375 @y
376 @d cat_code(#)==equiv(cat_code_base+#)
377 @d type_code(#)==equiv(pux_type_code_base+#)
378 @d local_names(#)==equiv(pux_local_names_base+#)
379 @z
380
381 @x
382 packages, not in \TeX\ itself, so that global interchange of formats is
383 possible.
384 @y
385 packages, not in \TeX\ itself, so that global interchange of formats is
386 possible.
387
388 TCW: Add |null_cfont| and initialization for |cur_font|.
389 @z
390
391 @x
392 @d null_font==font_base
393 @y
394 @d null_font==font_base
395 @d null_cfont==cfont_base
396 @d default_cfont==null_cfont+1
397 @z
398
399 @x
400 begin if n=cur_font_loc then print("current font")
401 else if n<math_font_base+16 then
402 @y
403 begin if n=cur_font_loc then print("current font")
404 else if n=cur_cface_loc then print("current cface")
405 else if n=cur_cfont_loc then print("current cfont")
406 else if n<math_font_base+16 then
407 @z
408
409 @x
410   begin if n<lc_code_base then
411     begin print_esc("catcode"); print_int(n-cat_code_base);
412     end
413 @y
414   begin if n<pux_type_code_base then
415     begin
416       if n<pux_cat_code_base then print_esc("catcode")
417       else print_esc("PUXcatcode");
418       print_int(n-cat_code_base);
419     end
420   else if n<lc_code_base then
421       begin print_esc("PUXtypecode"); print_int(n-pux_type_code_base);
422       end
423 @z
424
425 @x
426   else  begin print_esc("sfcode"); print_int(n-sf_code_base);
427     end;
428 @y
429   else  if n<pux_local_names_base then
430     begin print_esc("sfcode"); print_int(n-sf_code_base);
431     end
432   else  begin print_esc("PUXlocalnames"); print_int(n-pux_local_names_base);
433     end;
434 @z
435
436 @x
437   print_char("="); print_int(equiv(n));
438 @y
439   print_char("=");
440   if n>=pux_local_names_base then
441     if n < 256 then print_char(equiv(n))
442     else print_wchar(equiv(n))
443   else print_int(equiv(n));
444 @z
445
446 @x
447 @d error_context_lines_code=54 {maximum intermediate line pairs shown}
448 @d tex_int_pars=55 {total number of \TeX's integer parameters}
449 @y
450 @d error_context_lines_code=54 {maximum intermediate line pairs shown}
451 @d puxg_rotate_ctext_code=55
452 @d puxg_cface_depth_code=56
453 @d pux_xspace_code=57
454 @d pux_wcharother_code=58
455 @d pux_CJKinput_code=59
456 @d pux_charset_code=60
457 @d pux_default_cface_code=61
458 @d pux_digit_num_code=62 {number of digits of the splitted number} 
459 @d pux_sign_code=63 {sign of the splitted number} 
460 @d pux_digit_base=64 {10 digits of splitted number} 
461 @d tex_int_pars=74 {total number of \TeX's integer parameters}
462 @z
463
464 @x
465 @d error_context_lines==int_par(error_context_lines_code)
466 @y
467 @d error_context_lines==int_par(error_context_lines_code)
468 @d puxg_rotate_ctext==int_par(puxg_rotate_ctext_code)
469 @d puxg_cface_depth==int_par(puxg_cface_depth_code)
470 @d pux_xspace==int_par(pux_xspace_code)
471 @d pux_wcharother==int_par(pux_wcharother_code)
472 @d pux_CJKinput==int_par(pux_CJKinput_code)
473 @d pux_charset==int_par(pux_charset_code)
474 @d pux_default_cface==int_par(pux_default_cface_code)
475 @d pux_digit_num==int_par(pux_digit_num_code)
476 @d pux_num_sign==int_par(pux_sign_code)
477 @d pux_nth_digit(#)==int_par(pux_digit_base+#)
478 @d default_csp=50
479 @d default_cesp=150
480 @d default_depth=200
481 @z
482
483 @x
484 othercases print("[unknown integer parameter!]")
485 @y
486 pux_xspace_code:print_esc("puxXspace");
487 pux_wcharother_code:print_esc("puxCJKcharOther");
488 pux_CJKinput_code:print_esc("puxCJKinput");
489 pux_charset_code:print_esc("puxCharSet");
490 puxg_rotate_ctext_code:print_esc("puxgRotateCtext");
491 puxg_cface_depth_code:print_esc("puxgCfaceDepth");
492 othercases print("[unknown integer parameter!]")
493 @z
494
495 @x
496 del_code("."):=0; {this null delimiter is used in error recovery}
497 @y
498 del_code("."):=0; {this null delimiter is used in error recovery}
499 puxg_cface_depth:=default_depth;
500 pux_CJKinput:=1;
501 @z
502
503 @x
504       if cat_code(p-single_base)=letter then print_char(" ");
505 @y
506       if get_cat_code(p-single_base)=letter then print_char(" ");
507 @z
508
509 @x
510 def_font: print_esc("font");
511 @y
512 def_font: print_esc("font");
513 pux_font_match: print_esc("PUXfontmatch"); {TCW}
514 pux_set_cface: print_esc("cface"); {TCW}
515 pux_range_catcode: print_esc("PUXrangecatcode"); {TCW}
516 pux_range_type_code: print_esc("PUXrangetypecode"); {TCW}
517 pux_split_number: print_esc("PUXsplitnumber"); {TCW}
518 @z
519
520 @x
521 A \TeX\ token is either a character or a control sequence, and it is
522 @^token@>
523 represented internally in one of two ways: (1)~A character whose ASCII
524 code number is |c| and whose command code is |m| is represented as the
525 number $2^8m+c$; the command code is in the range |1<=m<=14|. (2)~A control
526 sequence whose |eqtb| address is |p| is represented as the number
527 |cs_token_flag+p|. Here |cs_token_flag=@t$2^{12}-1$@>| is larger than
528 $2^8m+c$, yet it is small enough that |cs_token_flag+p< max_halfword|;
529 thus, a token fits comfortably in a halfword.
530
531 A token |t| represents a |left_brace| command if and only if
532 |t<left_brace_limit|; it represents a |right_brace| command if and only if
533 we have |left_brace_limit<=t<right_brace_limit|; and it represents a |match| or
534 |end_match| command if and only if |match_token<=t<=end_match_token|.
535 The following definitions take care of these token-oriented constants
536 and a few others.
537
538 @d cs_token_flag==@'7777 {amount added to the |eqtb| location in a
539   token that stands for a control sequence; is a multiple of~256, less~1}
540 @d left_brace_token=@'0400 {$2^8\cdot|left_brace|$}
541 @d left_brace_limit=@'1000 {$2^8\cdot(|left_brace|+1)$}
542 @d right_brace_token=@'1000 {$2^8\cdot|right_brace|$}
543 @d right_brace_limit=@'1400 {$2^8\cdot(|right_brace|+1)$}
544 @d math_shift_token=@'1400 {$2^8\cdot|math_shift|$}
545 @d tab_token=@'2000 {$2^8\cdot|tab_mark|$}
546 @d out_param_token=@'2400 {$2^8\cdot|out_param|$}
547 @d space_token=@'5040 {$2^8\cdot|spacer|+|" "|$}
548 @d letter_token=@'5400 {$2^8\cdot|letter|$}
549 @d other_token=@'6000 {$2^8\cdot|other_char|$}
550 @d match_token=@'6400 {$2^8\cdot|match|$}
551 @d end_match_token=@'7000 {$2^8\cdot|end_match|$}
552 @y
553 A \TeX\ token is either a character or a control sequence, and it is
554 @^token@>
555 represented internally in one of two ways: (1)~A character whose ASCII
556 code number is |c| and whose command code is |m| is represented as the
557 number $2^{16}m+c$; the command code is in the range |1<=m<=14|. (2)~A control
558 sequence whose |eqtb| address is |p| is represented as the number
559 |cs_token_flag+p|. Here |cs_token_flag=@t$2^{20}-1$@>| is larger than
560 $2^{16}m+c$, yet it is small enough that |cs_token_flag+p< max_halfword|;
561 thus, a token fits comfortably in a halfword.
562
563 A token |t| represents a |left_brace| command if and only if
564 |t<left_brace_limit|; it represents a |right_brace| command if and only if
565 we have |left_brace_limit<=t<right_brace_limit|; and it represents a |match| or
566 |end_match| command if and only if |match_token<=t<=end_match_token|.
567 The following definitions take care of these token-oriented constants
568 and a few others.
569
570 @d cs_token_flag==@"FFFFF {amount added to the |eqtb| location in a
571   token that stands for a control sequence; is a multiple of~65536, less~1}
572 @d left_brace_token==@"10000 {$2^{16}\cdot|left_brace|$}
573 @d left_brace_limit==@"20000 {$2^{16}\cdot(|left_brace|+1)$}
574 @d right_brace_token==@"20000 {$2^{16}\cdot|right_brace|$}
575 @d right_brace_limit==@"30000 {$2^{16}\cdot(|right_brace|+1)$}
576 @d math_shift_token==@"30000 {$2^{16}\cdot|math_shift|$}
577 @d tab_token==@"40000 {$2^{16}\cdot|tab_mark|$}
578 @d out_param_token==@"50000 {$2^{16}\cdot|out_param|$}
579 @d space_token==@"A0020 {$2^{16}\cdot|spacer|+|" "|$}
580 @d letter_token==@"B0000 {$2^{16}\cdot|letter|$}
581 @d other_token==@"C0000 {$2^{16}\cdot|other_char|$}
582 @d match_token==@"D0000 {$2^{16}\cdot|match|$}
583 @d end_match_token==@"E0000 {$2^{16}\cdot|end_match|$}
584 @z
585
586 @x
587 else  begin m:=info(p) div @'400; c:=info(p) mod @'400;
588 @y
589 else  begin m:=info(p) div @"10000; c:=info(p) mod @"10000;
590 @z
591
592 @x
593 left_brace,right_brace,math_shift,tab_mark,sup_mark,sub_mark,spacer,
594   letter,other_char: print(c);
595 @y
596 letter,other_char: if is_wchar(c) then print_wchar(c) else print(c);
597 left_brace,right_brace,math_shift,tab_mark,sup_mark,sub_mark,spacer: print(c);
598 @z
599
600 @x
601 @d chr_cmd(#)==begin print(#); print_ASCII(chr_code);
602   end
603 @y
604 @d chr_cmd(#)==begin print(#); print_ASCII(chr_code);
605   end
606 @d wchr_cmd(#)==begin print(#);
607   if is_wchar(chr_code) then
608     print_wchar(chr_code)
609   else print_ASCII(chr_code);
610   end
611 @z
612
613 @x
614 letter: chr_cmd("the letter ");
615 other_char: chr_cmd("the character ");
616 @y
617 letter: wchr_cmd("the letter ");
618 other_char: wchr_cmd("the character ");
619 @z
620
621 @x
622 @!d:2..3; {number of excess characters in an expanded code}
623 @y
624 @!d:2..3; {number of excess characters in an expanded code}
625 @!first_control_char:integer; {the first character code of control sequence}
626 @z
627
628 @x
629 @ @<Input from external file, |goto restart| if no input found@>=
630 @^inner loop@>
631 begin switch: if loc<=limit then {current line not yet finished}
632   begin cur_chr:=buffer[loc]; incr(loc);
633 @y
634 @ The |get_wchar| macro tries to read a double-byte character from |buffer|
635 at the position specified by the parameter. The code value is stored in the
636 global variable |cur_chr|.
637 @^inner loop@>
638 @^Modified for handling DBCS characters@>
639
640 @d get_wchar(#)==begin cur_chr:=buffer[#]; incr(#);
641      if cur_chr > 127 and pux_CJKinput = 1 then begin
642         cur_chr := cur_chr * 256 + buffer[#]; incr(#)
643      end
644    end
645
646 @<Input from external file, |goto restart| if no input found@>=
647 begin switch: if loc<=limit then {current line not yet finished}
648   begin get_wchar(loc);
649 @z
650
651 @x
652   reswitch: cur_cmd:=cat_code(cur_chr);
653 @y
654   reswitch: cur_cmd:=get_cat_code(cur_chr);
655 @z
656
657 @x
658 buffer and the process is repeated, slowly but surely.
659
660 @<Scan a control...@>=
661 begin if loc>limit then cur_cs:=null_cs {|state| is irrelevant in this case}
662 else  begin start_cs: k:=loc; cur_chr:=buffer[k]; cat:=cat_code(cur_chr);
663   incr(k);
664 @y
665 buffer and the process is repeated, slowly but surely.
666
667 \medskip
668
669 TCW: When the flag |expand_char| is true, we stop using |get_wchar| but
670 merely get a one-byte character so that reading DBCS characters
671 will not be confused. Besides, we neet to handle alphabetic numbers of the form
672 \.{'\\c}, where \.{c} is a DBCS characters.@^Modified for handling DBCS characters@>
673
674 @<Scan a control...@>=
675 begin if loc>limit then cur_cs:=null_cs {|state| is irrelevant in this case}
676 else  begin first_control_char := -1;@/
677 start_cs: k:=loc;
678       if expand_char then begin
679          cur_chr:=buffer[k];
680          incr(k);
681          expand_char:=false;
682       end
683       else get_wchar(k);
684       cat:=get_cat_code(cur_chr);
685       if first_control_char = -1 then first_control_char := cur_chr;
686 @z
687
688 @x
689   cur_cs:=single_base+buffer[loc]; incr(loc);
690   end;
691 @y
692   @#{the control sequence is a control symbol, i.e., its name consisits of  only one letter. }
693   if is_wchar(first_control_char) then begin
694     cur_cs:=single_base+first_control_char; loc:=loc+2;
695     end
696   else begin
697     cur_cs:=single_base+buffer[loc]; incr(loc);
698     end;
699   end;
700 @z
701
702 @x
703 the buffer left two or three places.
704 @y
705 the buffer left two or three places.
706
707 TCW: If it is indeed an expanded code, set the flag |expand_char|.
708 @^Modified for handling DBCS characters@>
709 @z
710
711 @x
712   begin c:=buffer[k+1]; @+if c<@'200 then {yes, one is indeed present}
713     begin d:=2;
714 @y
715   begin c:=buffer[k+1]; @+if c<@'200 then {yes, one is indeed present}
716     begin d:=2; expand_char:=true;
717 @z
718
719 @x
720 @ @<Scan ahead in the buffer...@>=
721 begin repeat cur_chr:=buffer[k]; cat:=cat_code(cur_chr); incr(k);
722 @y
723 @ @<Scan ahead in the buffer...@>=
724 @^Modified for handling DBCS characters@>
725 begin repeat get_wchar(k); cat:=get_cat_code(cur_chr);
726 @z
727
728 @x
729 if cat<>letter then decr(k);
730   {now |k| points to first nonletter}
731 if k>loc+1 then {multiletter control sequence has been scanned}
732 @y
733 if cat<>letter then if cur_chr > 256 then k:=k-2 { go back 2 steps for a non-letter DBCS code }
734 else decr(k);
735   {now |k| points to first nonletter}
736 if k>loc+1 and not (k = loc+2 and first_control_char > 255) then {multiletter control sequence has been scanned}
737 @z
738
739 @x
740   else  begin cur_cmd:=t div @'400; cur_chr:=t mod @'400;
741 @y
742   else  begin cur_cmd:=t div @"10000; cur_chr:=t mod @"10000;
743 @z
744
745 @x
746 if cur_cs=0 then cur_tok:=(cur_cmd*@'400)+cur_chr
747 @y
748 if cur_cs=0 then cur_tok:=(cur_cmd*@"10000)+cur_chr
749 @z
750
751 @x
752   buffer[j]:=info(p) mod @'400; incr(j); p:=link(p);
753 @y
754 @^Modified for handling DBCS characters@>
755   db_char:=info(p) mod @"10000;
756   if is_wchar(db_char) then {a double-byte char}
757      begin buffer[j]:=db_char div 256;
758      buffer[j+1]:=db_char mod 256;
759      j:=j + 2;
760      end
761   else begin
762      buffer[j]:=db_char;
763      incr(j);
764      end;
765   p:=link(p); {fix this for 2-byte code}
766 @z
767
768 @x
769 done: if cur_cs=0 then cur_tok:=(cur_cmd*@'400)+cur_chr
770 @y
771 done: if cur_cs=0 then cur_tok:=(cur_cmd*@"10000)+cur_chr
772 @z
773
774 @x
775 if cur_cs=0 then cur_tok:=(cur_cmd*@'400)+cur_chr
776 @y
777 if cur_cs=0 then cur_tok:=(cur_cmd*@"10000)+cur_chr
778 @z
779
780 @x
781 toks_register,assign_toks,def_family,set_font,def_font: @<Fetch a token list or
782   font identifier, provided that |level=tok_val|@>;
783 @y
784 toks_register,assign_toks,def_family,set_font,def_font,set_cfont:
785    @<Fetch a token list or font identifier, provided that |level=tok_val|@>;
786 @z
787
788 @x
789 assign_int: scanned_result(eqtb[m].int)(int_val);
790 @y
791 assign_int,puxg_assign_flag,puxg_assign_int: scanned_result(eqtb[m].int)(int_val);
792 pux_get_int:@<scan \PUTeX\ internal values@>;
793 @z
794
795 @x
796 char_given,math_given: scanned_result(cur_chr)(int_val);
797 @y
798 char_given,math_given,pux_char_given: scanned_result(cur_chr)(int_val);
799 @z
800
801 @x
802 @ @<Fetch a character code from some table@>=
803 begin scan_char_num;
804 @y
805 @ @<Fetch a character code from some table@>=
806 begin
807   if (m = pux_cat_code_base) or (m = pux_type_code_base) then
808     scan_wchar_num
809   else if m = pux_local_names_base then begin
810     char_val_flag:=true;
811     scan_eight_bit_int;
812     end
813   else
814     scan_char_num;
815 @z
816
817 @x
818 begin scan_font_ident;
819 if m=0 then scanned_result(hyphen_char[cur_val])(int_val)
820 else scanned_result(skew_char[cur_val])(int_val);
821 end
822 @y
823 begin scan_font_ident;
824 if cur_val <= font_max then
825   if m=0 then scanned_result(hyphen_char[cur_val])(int_val)
826   else scanned_result(skew_char[cur_val])(int_val);
827 end
828 @z
829
830 @x
831 @d octal_token=other_token+"'" {apostrophe, indicates an octal constant}
832 @d hex_token=other_token+"""" {double quote, indicates a hex constant}
833 @d alpha_token=other_token+"`" {reverse apostrophe, precedes alpha constants}
834 @d point_token=other_token+"." {decimal point}
835 @d continental_point_token=other_token+"," {decimal point, Eurostyle}
836 @y
837 @d octal_token==(other_token+"'") {apostrophe, indicates an octal constant}
838 @d hex_token==(other_token+"""") {double quote, indicates a hex constant}
839 @d alpha_token==(other_token+"`") {reverse apostrophe, precedes alpha constants}
840 @d point_token==(other_token+".") {decimal point}
841 @d continental_point_token==(other_token+",") {decimal point, Eurostyle}
842 @z
843
844 @x
845 if cur_val>255 then
846 @y
847 if cur_val>65535 then
848 @z
849
850 @x
851 @d zero_token=other_token+"0" {zero, the smallest digit}
852 @d A_token=letter_token+"A" {the smallest special hex digit}
853 @d other_A_token=other_token+"A" {special hex digit of type |other_char|}
854 @y
855 @d zero_token==(other_token+"0") {zero, the smallest digit}
856 @d A_token==(letter_token+"A") {the smallest special hex digit}
857 @d other_A_token==(other_token+"A") {special hex digit of type |other_char|}
858 @z
859
860 @x
861 `\.{height}' or `\.{width}' or `\.{depth}' specifications are
862 found (in any order).
863 @y
864 `\.{height}' or `\.{width}' or `\.{depth}' specifications are
865 found (in any order).
866
867 TCW: not intend to modify the function here;
868      just append declarations of scanning routines for PUTeX.
869 @z
870
871 @x
872 if scan_keyword("depth") then
873 @.depth@>
874   begin scan_normal_dimen; depth(q):=cur_val; goto reswitch;
875   end;
876 scan_rule_spec:=q;
877 end;
878 @y
879 if scan_keyword("depth") then
880 @.depth@>
881   begin scan_normal_dimen; depth(q):=cur_val; goto reswitch;
882   end;
883 scan_rule_spec:=q;
884 end;
885
886 @<PUTeX basic scanning routines@>@;
887 @z
888
889 @x
890 var p:pointer; {tail of the token list}
891 @!q:pointer; {new node being added to the token list via |store_new_token|}
892 @!t:halfword; {token being appended}
893 @!k:pool_pointer; {index into |str_pool|}
894 begin str_room(1);
895 p:=temp_head; link(p):=null; k:=b;
896 while k<pool_ptr do
897   begin t:=so(str_pool[k]);
898   if t=" " then t:=space_token
899   else t:=other_token+t;
900   fast_store_new_token(t);
901   incr(k);
902   end;
903 pool_ptr:=b; str_toks:=p;
904 end;
905 @y
906 var p:pointer; {tail of the token list}
907 @!q:pointer; {new node being added to the token list via |store_new_token|}
908 @!t:halfword; {token being appended}
909 @!k:pool_pointer; {index into |str_pool|}
910 begin str_room(1);
911 p:=temp_head; link(p):=null; k:=b;
912 while k<pool_ptr do
913   begin t:=so(str_pool[k]);
914   if t > 128 then begin
915     t:=t*256+so(str_pool[k+1]);
916     incr(k);
917     end;
918   if t=" " then t:=space_token
919   else t:=other_token+t;
920   fast_store_new_token(t);
921   incr(k);
922   end;
923 pool_ptr:=b; str_toks:=p;
924 end;
925 @z
926
927 @x
928 containing something like `\.{-3.0pt minus 0.5fill}'.
929 @y
930 containing something like `\.{-3.0pt minus 0.5fill}'.
931
932 TCW: make the function able to print CJK characters stored in local names table.
933
934 @z
935
936 @x
937 begin get_x_token; scan_something_internal(tok_val,false);
938 @y
939 begin get_x_token; char_val_flag:=false; scan_something_internal(tok_val,false);
940 @z
941
942 @x
943   int_val:print_int(cur_val);
944 @y
945   int_val:if char_val_flag then
946             if cur_val > 255 then print_wchar(cur_val)
947             else {an empty slot}
948             begin print_char("?"); print_char("?"); end
949           else print_int(cur_val);
950 @z
951
952 @x
953 @d font_name_code=4 {command code for \.{\\fontname}}
954 @d job_name_code=5 {command code for \.{\\jobname}}
955 @y
956 @d font_name_code=4 {command code for \.{\\fontname}}
957 @d cnumber_code=5 {command code for \.{\\PUXcnumber}}
958 @d scnumber_code=6 {command code for \.{\\PUXscnumber}}
959 @d ucnumber_code=7 {command code for \.{\\PUXucnumber}}
960 @d fcnumber_code=8 {command code for \.{\\PUXfcnumber}}
961 @d acnumber_code=9 {command code for \.{\\PUXacnumber}}
962 @d cjknumber_code=10 {command code for \.{\\PUXcjknumber}}
963 @d nameseq_code=11 {command code for \.{\\PUXnameseq}}
964 @d job_name_code=12 {command code for \.{\\jobname}}
965 @d lower_cdigit_base=10    {lowercase style Chinese number}
966 @d upper_cdigit_base=25    {uppercase style Chinese number}
967 @z
968
969 @x
970 primitive("jobname",convert,job_name_code);@/
971 @!@:job_name_}{\.{\\jobname} primitive@>
972 @y
973 primitive("jobname",convert,job_name_code);@/
974 @!@:job_name_}{\.{\\jobname} primitive@>
975 primitive("PUXcnumber",convert,cnumber_code);@/
976 @!@:cnumber_}{\.{\\PUXcnumber} primitive@>
977 primitive("PUXscnumber",convert,scnumber_code);@/
978 @!@:scnumber_}{\.{\\PUXscnumber} primitive@>
979 primitive("PUXucnumber",convert,ucnumber_code);@/
980 @!@:ucnumber_}{\.{\\PUXucnumber} primitive@>
981 primitive("PUXfcnumber",convert,fcnumber_code);@/
982 @!@:fcnumber_}{\.{\\PUXfcnumber} primitive@>
983 primitive("PUXacnumber",convert,acnumber_code);@/
984 @!@:acnumber_}{\.{\\PUXacnumber} primitive@>
985 primitive("PUXcjknumber",convert,cjknumber_code);@/
986 @!@:cjknumber_}{\.{\\PUXcjknumber} primitive@>
987 primitive("PUXnameseq",convert,nameseq_code);@/
988 @!@:cjknameseq_}{\.{\\PUXnameseq} primitive@>
989 @z
990
991 @x
992   meaning_code: print_esc("meaning");
993   font_name_code: print_esc("fontname");
994 @y
995   meaning_code: print_esc("meaning");
996   font_name_code: print_esc("fontname");
997   cnumber_code: print_esc("PUXcnumber");
998   scnumber_code: print_esc("PUXscnumber");
999   ucnumber_code: print_esc("PUXucnumber");
1000   fcnumber_code: print_esc("PUXfcnumber");
1001   acnumber_code: print_esc("PUXfanumber");
1002   cjknumber_code: print_esc("PUXcjknumber");
1003   nameseq_code: print_esc("PUXnameseq");
1004 @z
1005
1006 @x
1007 @!save_scanner_status:small_number; {|scanner_status| upon entry}
1008 @!b:pool_pointer; {base of temporary string}
1009 begin c:=cur_chr; @<Scan the argument for command |c|@>;
1010 @y
1011 @!save_scanner_status:small_number; {|scanner_status| upon entry}
1012 @!b:pool_pointer; {base of temporary string}
1013 @!dsize:integer;
1014 @!saved_val,digit_base,sign:integer;
1015 @!min_val,max_val,offset:integer;
1016 begin c:=cur_chr; @<Scan the argument for command |c|@>;
1017 @z
1018
1019 @x
1020 case c of
1021 number_code,roman_numeral_code: scan_int;
1022 @y
1023 case c of
1024 number_code,roman_numeral_code,cnumber_code,scnumber_code,ucnumber_code,
1025 fcnumber_code : scan_int;
1026 acnumber_code: @<scan and split the number@>;
1027 cjknumber_code:@<scan a CJK number with a possible selector and then  split it@>;
1028 nameseq_code:@<scan a CJK name sequence number@>;
1029 @z
1030
1031 @x
1032 roman_numeral_code: print_roman_int(cur_val);
1033 string_code:if cur_cs<>0 then sprint_cs(cur_cs)
1034   else print_char(cur_chr);
1035 @y
1036 roman_numeral_code: print_roman_int(cur_val);
1037 cnumber_code: print_chinese_int(cur_val,lower_cdigit_base,false,false);
1038 scnumber_code: print_chinese_int(cur_val,lower_cdigit_base,true,false);
1039 ucnumber_code: print_chinese_int(cur_val,upper_cdigit_base,false,false);
1040 fcnumber_code: print_chinese_int(cur_val,upper_cdigit_base,false,true);
1041 acnumber_code: @<using full-width arabic characters to print a CJK number@>;
1042 cjknumber_code: @<print a CJK number with specified format@>;
1043 nameseq_code: @<print a CJK name sequence member@>;
1044 string_code:if cur_cs<>0 then sprint_cs(cur_cs)
1045   else
1046     if is_wchar(cur_chr) then print_wchar(cur_chr)
1047     else print_char(cur_chr);
1048 @z
1049
1050 @x
1051 font_name_code: begin print(font_name[cur_val]);
1052   if font_size[cur_val]<>font_dsize[cur_val] then
1053     begin print(" at "); print_scaled(font_size[cur_val]);
1054     print("pt");
1055     end;
1056   end;
1057 @y
1058 font_name_code: begin
1059   if cur_val <=font_max then begin
1060     print(font_name[cur_val]);
1061     if font_size[cur_val]<>font_dsize[cur_val] then
1062       begin print(" at "); print_scaled(font_size[cur_val]);
1063       print("pt");
1064       end;
1065     end
1066   else begin
1067     print("CFONT");
1068     print(cface[cfont_face[cur_val]]);
1069     dsize:=cfont_dsize[cur_val] div @"10000;
1070     print_int(dsize);
1071     if cfont_size[cur_val]<>cfont_dsize[cur_val] then
1072       begin print(" at "); print_scaled(cfont_size[cur_val]);
1073       print("pt");
1074       end;
1075     end;
1076   end;
1077 @z
1078
1079 @x
1080 if (cur_cmd>active_char)or(cur_chr>255) then {not a character}
1081   begin m:=relax; n:=256;
1082 @y
1083 if (cur_cmd>active_char)or(cur_chr>65535) then {not a character}
1084   begin m:=relax; n:=256; {values other than 256 will break latex.fmt}
1085 @z
1086
1087 @x
1088 if (cur_cmd>active_char)or(cur_chr>255) then
1089   begin cur_cmd:=relax; cur_chr:=256;
1090   end;
1091 @y
1092 if (cur_cmd>active_char)or(cur_chr>65535) then
1093   begin cur_cmd:=relax; cur_chr:=256; {values other than 256 will break latex.fmt}
1094   end;
1095 @z
1096
1097 @x
1098   pack_job_name(".dvi");
1099   while not b_open_out(dvi_file) do
1100     prompt_file_name("file name for output",".dvi");
1101 @y
1102   pack_job_name(".cdi");
1103   while not b_open_out(dvi_file) do
1104     prompt_file_name("file name for output",".cdi");
1105 @z
1106
1107 @x
1108 @ Before we forget about the format of these tables, let's deal with two
1109 of \TeX's basic scanning routines related to font information.
1110
1111 @<Declare procedures that scan font-related stuff@>=
1112 procedure scan_font_ident;
1113 var f:internal_font_number;
1114 @!m:halfword;
1115 begin @<Get the next non-blank non-call...@>;
1116 if cur_cmd=def_font then f:=cur_font
1117 else if cur_cmd=set_font then f:=cur_chr
1118 @y
1119 @ Before we forget about the format of these tables, let's deal with two
1120 of \TeX's basic scanning routines related to font information.
1121
1122 TCW: handle the commands |def_cfont| and |set_cfont|.
1123
1124 @<Declare procedures that scan font-related stuff@>=
1125 procedure scan_font_ident;
1126 var f:integer;
1127 @!m:halfword;
1128 begin @<Get the next non-blank non-call...@>;
1129 if cur_cmd=def_font then f:=cur_font
1130 else if cur_cmd=set_font or cur_cmd=set_cfont then f:=cur_chr
1131 @z
1132
1133 @x
1134 bytes long, so it is in the range |0<=c<65536|. \TeX82 never uses this
1135 command, but it should come in handy for extensions of \TeX\ that deal
1136 with oriental languages.
1137 @y
1138 bytes long, so it is in the range |0<=c<65536|. \PUTeX\ uses this to typeset
1139 a CJK two-byte character.
1140 @z
1141
1142 @x
1143 \yskip\hang|pre| 247 |i[1]| |num[4]| |den[4]| |mag[4]| |k[1]| |x[k]|.
1144 Beginning of the preamble; this must come at the very beginning of the
1145 file. Parameters |i|, |num|, |den|, |mag|, |k|, and |x| are explained below.
1146 @y
1147 \yskip\hang|pre| 247 |i[1]| |c[1]| |num[4]| |den[4]| |mag[4]| |k[1]| |x[k]|.
1148 Beginning of the preamble; this must come at the very beginning of the
1149 file. Parameters |i|, |c|, |num|, |den|, |mag|, |k|, and |x| are explained below.
1150 @z
1151
1152 @x
1153 \yskip\hang|post_post| 249. Ending of the postamble, see below.
1154
1155 \yskip\noindent Commands 250--255 are undefined at the present time.
1156 @y
1157 \yskip\hang|post_post| 249. Ending of the postamble, see below.
1158
1159 \yskip\hang|cfnt| 250 |k[2]|. Set |cf:=k|. \PUTeX\ uses this command for CJK font
1160 numbers in the range |0<=k<65535|.
1161
1162 \yskip\hang|cfnt_def| 251 |k[2]| |l[1]| |n[l]| |c[1]| |s[4]| |ds[4]| |wt[2]| |y[1]|
1163   |w[4]| |h[4]| |d[4]| |fw[4]| |fh[4]| |fd[4]|. Define CJK font |k|, where |0<=k<65536|, see below.
1164
1165 \yskip\noindent Commands 252--255 are undefined at the present time.
1166 @z
1167
1168 @x
1169 @d set1=128 {typeset a character and move right}
1170 @y
1171 @d set1=128 {typeset a character and move right}
1172 @d set2=129 {typeset a two-byte CJK character and move right}
1173 @d set4=131 {typeset a four-byte CJK character and move right}
1174 @z
1175
1176 @x
1177 @d post_post=249 {postamble ending}
1178 @y
1179 @d post_post=249 {postamble ending}
1180 @d cfnt=250 {set current chinese font}
1181 @d cfnt_def=251 {define the meaning of a chinese font}
1182 @z
1183
1184 @x
1185 $$\hbox{|@!i[1]| |@!num[4]| |@!den[4]| |@!mag[4]| |@!k[1]| |@!x[k]|.}$$
1186 The |i| byte identifies \.{DVI} format; currently this byte is always set
1187 to~2. (The value |i=3| is currently used for an extended format that
1188 allows a mixture of right-to-left and left-to-right typesetting.
1189 Some day we will set |i=4|, when \.{DVI} format makes another
1190 incompatible change---perhaps in the year 2048.)
1191 @y
1192 $$\hbox{|@!i[1]| |@!c[1]| |@!num[4]| |@!den[4]| |@!mag[4]| |@!k[1]| |@!x[k]|.}$$
1193 The |i| byte identifies \.{CDI} format; currently this byte is always set
1194 to~100. (Some day we will set |i=101|, when \.{CDI} format makes another
1195 incompatible change---perhaps in the year 2048.)
1196
1197 The |c| byte identifies the default character code set of document. Currently, the following
1198 code value is defined:
1199
1200   0: USC2 (Unicode, not supported yet)
1201
1202   1: Big5 (Traditional Chinese used in Taiwan and Hong Kong)
1203   
1204   2: GBK (Simplified Chinese used in PRC and Singapore)
1205 @z
1206
1207 @x
1208 @d id_byte=2 {identifies the kind of \.{DVI} files described here}
1209 @y
1210 @d id_byte=100 {identifies the kind of \.{DVI} files described here}
1211 @z
1212
1213 @x
1214 @ Here's a procedure that outputs a font definition. Since \TeX82 uses at
1215 most 256 different fonts per job, |fnt_def1| is always used as the command code.
1216 @y
1217 @ Here's a procedure that outputs a font definition. Since \TeX82 uses at
1218 most 256 different fonts per job, |fnt_def1| is always used as the command code.
1219
1220 TCW: the procedure |dvi_cfont_def| outputs a chinese font definition.
1221 @z
1222
1223 @x
1224 @<Output the font name whose internal number is |f|@>;
1225 end;
1226 @y
1227 @<Output the font name whose internal number is |f|@>;
1228 end;
1229
1230 procedure dvi_cfont_def (f:internal_cfont_number);
1231 var k:pool_pointer;
1232     j:integer;
1233 begin
1234 j:=cfont_face[f];
1235 dvi_out(cfnt_def);
1236 dvi_out((f-cfont_base-1) div 256); dvi_out((f-cfont_base-1) mod 256);
1237 {Output the CJK font face name}
1238 dvi_out(length(cface_name[j]));
1239 for k:= str_start[cface_name[j]] to str_start[cface_name[j]+1] - 1 do dvi_out(str_pool[k]);
1240 dvi_out(cface_charset[j]);
1241 dvi_four(cfont_size[f]);
1242 dvi_four(cfont_dsize[f]);
1243 dvi_out(cface_weight[j] div 256); dvi_out(cface_weight[j] mod 256);
1244 dvi_out(cface_style[j]);
1245 dvi_four(cfont_width[f]);
1246 dvi_four(cfont_height[f]);
1247 dvi_four(cfont_depth[f]);
1248 dvi_four(cface_fw_width[j]);
1249 dvi_four(cface_fw_height[j]);
1250 dvi_four(cface_fw_depth[j]);
1251 end;
1252 @z
1253
1254 @x
1255 dvi_h:=0; dvi_v:=0; cur_h:=h_offset; dvi_f:=null_font;
1256 @y
1257 dvi_h:=0; dvi_v:=0; cur_h:=h_offset; dvi_f:=null_font; dvi_cf:=null_cfont;
1258 @z
1259
1260 @x
1261   begin dvi_out(pre); dvi_out(id_byte); {output the preamble}
1262 @y
1263   begin dvi_out(pre); dvi_out(id_byte);
1264   doc_charset:=pux_charset; dvi_out(doc_charset); {output the preamble}
1265 @z
1266
1267 @x
1268   print(" TeX output "); print_int(year); print_char(".");
1269 @y
1270   print(" PUTeX output "); print_int(year); print_char(".");
1271 @z
1272
1273 %% MMM
1274 @x
1275 @<Output node |p| for |hlist_out|...@>=
1276 reswitch: if is_char_node(p) then
1277   begin synch_h; synch_v;
1278   repeat f:=font(p); c:=character(p);
1279   if f<>dvi_f then @<Change font |dvi_f| to |f|@>;
1280   if font_ec[f]>=qo(c) then if font_bc[f]<=qo(c) then
1281     if char_exists(orig_char_info(f)(c)) then  {N.B.: not |char_info|}
1282       begin if c>=qi(128) then dvi_out(set1);
1283       dvi_out(qo(c));@/
1284       cur_h:=cur_h+char_width(f)(orig_char_info(f)(c));
1285       goto continue;
1286       end;
1287   if mltex_enabled_p then
1288     @<Output a substitution, |goto continue| if not possible@>;
1289 continue:
1290   p:=link(p);
1291   until not is_char_node(p);
1292   dvi_h:=cur_h;
1293   end
1294 else @<Output the non-|char_node| |p| for |hlist_out|
1295     and move to the next node@>
1296 @y
1297 @<Output node |p| for |hlist_out|...@>=
1298 reswitch: if is_char_node(p) then
1299   begin synch_h; synch_v;
1300   repeat f:=font(p); c:=character(p);
1301   if (is_wchar(c)) then begin
1302     if f<>dvi_cf then @<Change font |dvi_cf| to |f|@>;
1303     dvi_out(set2); dvi_out(c div 256); dvi_out(c mod 256);
1304     cur_h:=cur_h+cfont_width[f];
1305     end
1306   else begin
1307     if f<>dvi_f then @<Change font |dvi_f| to |f|@>;
1308     if font_ec[f]>=qo(c) then if font_bc[f]<=qo(c) then
1309       if char_exists(orig_char_info(f)(c)) then  {N.B.: not |char_info|}
1310       if c>=qi(128) then dvi_out(set1);
1311       dvi_out(qo(c));@/
1312       cur_h:=cur_h+char_width(f)(orig_char_info(f)(c));
1313       goto continue;
1314       end;
1315  if mltex_enabled_p then
1316     @<Output a substitution, |goto continue| if not possible@>;
1317 continue:
1318   p:=link(p);
1319   until not is_char_node(p);
1320   dvi_h:=cur_h;
1321   end
1322 else @<Output the non-|char_node| |p| for |hlist_out|
1323     and move to the next node@>
1324 @z
1325
1326 @x
1327   dvi_out(post_post); dvi_four(last_bop); dvi_out(id_byte);@/
1328 @y
1329   @<Output the CJK font definitions for all fonts that were used@>;
1330   dvi_out(post_post); dvi_four(last_bop); dvi_out(doc_charset); dvi_out(id_byte);@/
1331 @z
1332
1333 @x
1334 @<Incorporate character dimensions into the dimensions of the hbox...@>=
1335 begin f:=font(p); i:=char_info(f)(character(p)); hd:=height_depth(i);
1336 x:=x+char_width(f)(i);@/
1337 s:=char_height(f)(hd);@+if s>h then h:=s;
1338 s:=char_depth(f)(hd);@+if s>d then d:=s;
1339 p:=link(p);
1340 end
1341 @y
1342 @<Incorporate character dimensions into the dimensions of the hbox...@>=
1343 begin f:=font(p); c:=character(p);
1344 if (is_wchar(c)) then begin
1345   x:=x+cfont_width[f];@/
1346   s:=cfont_height[f];@+if s>h then h:=s;
1347   s:=cfont_depth[f];@+if s>d then d:=s;
1348   end
1349 else begin
1350   i:=char_info(f)(c); hd:=height_depth(i);
1351   x:=x+char_width(f)(i);@/
1352   s:=char_height(f)(hd);@+if s>h then h:=s;
1353   s:=char_depth(f)(hd);@+if s>d then d:=s;
1354   end;
1355 p:=link(p);
1356 end
1357 @z
1358
1359 @x
1360 font_in_short_display:=null_font; short_display(list_ptr(r)); print_ln;@/
1361 @y
1362 font_in_short_display:=null_font; cfont_in_short_display:=null_cfont;@/
1363 short_display(list_ptr(r)); print_ln;@/
1364 @z
1365
1366 @x
1367   if (is_char_node(p))and(link(p)=null) then
1368     begin f:=font(p); v:=char_width(f)(char_info(f)(character(p)));
1369     if v<>width(b) then link(p):=new_kern(width(b)-v);
1370     end;
1371 @y
1372   if (is_char_node(p))and(link(p)=null) then
1373     begin
1374     f:=font(p);
1375     if is_wchar_node(p) then
1376       v:=cfont_width[f]
1377     else
1378       v:=char_width(f)(char_info(f)(character(p)));
1379     if v<>width(b) then link(p):=new_kern(width(b)-v);
1380     end;
1381 @z
1382
1383 @x
1384 if is_char_node(v) then
1385   begin f:=font(v);
1386   break_width[1]:=break_width[1]-char_width(f)(char_info(f)(character(v)));
1387   end
1388 @y
1389 if is_char_node(v) then
1390   begin f:=font(v);
1391   if is_wchar_node(v) then
1392     break_width[1]:=break_width[1]-cfont_width[f]
1393   else
1394     break_width[1]:=break_width[1]-char_width(f)(char_info(f)(character(v)));
1395   end
1396 @z
1397
1398 @x
1399   ligature_node: begin f:=font(lig_char(v));@/
1400     break_width[1]:=@|break_width[1]-
1401       char_width(f)(char_info(f)(character(lig_char(v))));
1402     end;
1403 @y
1404   ligature_node: begin f:=font(lig_char(v));@/
1405     if is_wchar(character(lig_char(v))) then
1406     break_width[1]:=@|break_width[1]-cfont_width[f]
1407     else
1408     break_width[1]:=@|break_width[1]-
1409       char_width(f)(char_info(f)(character(lig_char(v))));
1410     end;
1411 @z
1412
1413 @x
1414 if is_char_node(s) then
1415   begin f:=font(s);
1416   break_width[1]:=@|break_width[1]+char_width(f)(char_info(f)(character(s)));
1417   end
1418 @y
1419 if is_char_node(s) then
1420   begin f:=font(s);
1421   if is_wchar_node(s) then
1422     break_width[1]:=break_width[1]+cfont_width[f]
1423   else
1424     break_width[1]:=@|break_width[1]+char_width(f)(char_info(f)(character(s)));
1425   end
1426 @z
1427
1428 @x
1429   ligature_node: begin f:=font(lig_char(s));
1430     break_width[1]:=break_width[1]+
1431       char_width(f)(char_info(f)(character(lig_char(s))));
1432     end;
1433 @y
1434   ligature_node: begin f:=font(lig_char(s));@/
1435     if is_wchar(character(lig_char(s))) then
1436     break_width[1]:=break_width[1]+cfont_width[f]
1437     else
1438     break_width[1]:=break_width[1]+
1439       char_width(f)(char_info(f)(character(lig_char(s))));
1440     end;
1441 @z
1442
1443 @x
1444 font_in_short_display:=null_font
1445 @y
1446 cfont_in_short_display:=null_cfont; font_in_short_display:=null_font
1447 @z
1448
1449 @x
1450 ligature_node: begin f:=font(lig_char(cur_p));
1451   act_width:=act_width+char_width(f)(char_info(f)(character(lig_char(cur_p))));
1452   end;
1453 @y
1454 ligature_node: begin f:=font(lig_char(cur_p));
1455   if is_wchar(character(lig_char(cur_p))) then
1456     act_width:=act_width+cfont_width[f]
1457   else
1458     act_width:=act_width+char_width(f)(char_info(f)(character(lig_char(cur_p))));
1459   end;
1460 @z
1461
1462 @x
1463 repeat f:=font(cur_p);
1464 act_width:=act_width+char_width(f)(char_info(f)(character(cur_p)));
1465 cur_p:=link(cur_p);
1466 until not is_char_node(cur_p);
1467 end
1468 @y
1469 repeat f:=font(cur_p);
1470 if is_wchar_node(cur_p) then
1471   act_width:=act_width+cfont_width[f]
1472 else
1473   act_width:=act_width+char_width(f)(char_info(f)(character(cur_p)));
1474 cur_p:=link(cur_p);
1475 until not is_char_node(cur_p);
1476 end
1477 @z
1478
1479 @x
1480 if is_char_node(s) then
1481   begin f:=font(s);
1482   disc_width:=disc_width+char_width(f)(char_info(f)(character(s)));
1483   end
1484 @y
1485 if is_char_node(s) then
1486   begin f:=font(s);
1487   if is_wchar_node(s) then
1488     disc_width:=disc_width+cfont_width[f]
1489   else
1490     disc_width:=disc_width+char_width(f)(char_info(f)(character(s)));
1491   end
1492 @z
1493
1494 @x
1495   ligature_node: begin f:=font(lig_char(s));
1496     disc_width:=disc_width+
1497       char_width(f)(char_info(f)(character(lig_char(s))));
1498     end;
1499 @y
1500   ligature_node: begin f:=font(lig_char(s));
1501     if is_wchar(character(lig_char(s))) then
1502       disc_width:=disc_width+cfont_width[f]
1503     else
1504       disc_width:=disc_width+
1505         char_width(f)(char_info(f)(character(lig_char(s))));
1506     end;
1507 @z
1508
1509 @x
1510 if is_char_node(s) then
1511   begin f:=font(s);
1512   act_width:=act_width+char_width(f)(char_info(f)(character(s)));
1513   end
1514 @y
1515 if is_char_node(s) then
1516   begin f:=font(s);
1517   if is_wchar_node(s) then
1518     act_width:=act_width+cfont_width[f]
1519   else
1520     act_width:=act_width+char_width(f)(char_info(f)(character(s)));
1521   end
1522 @z
1523
1524 @x
1525   ligature_node: begin f:=font(lig_char(s));
1526     act_width:=act_width+
1527       char_width(f)(char_info(f)(character(lig_char(s))));
1528     end;
1529 @y
1530   ligature_node: begin f:=font(lig_char(s));
1531     if is_wchar(character(lig_char(s))) then
1532       act_width:=act_width+cfont_width[f]
1533     else
1534       act_width:=act_width+
1535         char_width(f)(char_info(f)(character(lig_char(s))));
1536     end;
1537 @z
1538
1539 @x
1540   char_num: begin scan_char_num; cur_chr:=cur_val; cur_cmd:=char_given;
1541     goto reswitch;
1542     end;
1543   spacer,right_brace: begin if n>1 then @<Enter a hyphenation exception@>;
1544 @y
1545   char_num: begin scan_char_num; cur_chr:=cur_val; cur_cmd:=char_given;
1546     goto reswitch;
1547     end;
1548   pux_char_given:@<Give improper hyphenation error for Chinese characters inside@>;
1549   pux_char_num: begin scan_wchar_num; cur_chr:=cur_val; cur_cmd:=pux_char_given;
1550     goto reswitch;
1551     end;
1552   spacer,right_brace: begin if n>1 then @<Enter a hyphenation exception@>;
1553 @z
1554
1555 @x
1556 if cur_chr="-" then @<Append the value |n| to list |p|@>
1557 else  begin if lc_code(cur_chr)=0 then
1558     begin print_err("Not a letter");
1559 @.Not a letter@>
1560     help2("Letters in \hyphenation words must have \lccode>0.")@/
1561       ("Proceed; I'll ignore the character I just read.");
1562     error;
1563     end
1564   else if n<63 then
1565     begin incr(n); hc[n]:=lc_code(cur_chr);
1566     end;
1567   end
1568 @y
1569 if cur_chr="-" then @<Append the value |n| to list |p|@>
1570 else  begin if is_wchar(cur_chr) then
1571     begin print_err("Chinese character can't appear here");
1572 @.Not a letter@>
1573     help2("Letters in \hyphenation words can't be Chinese characters.")@/
1574       ("Proceed; I'll ignore the character I just read.");
1575     error;
1576     end
1577   else if lc_code(cur_chr)=0 then
1578     begin print_err("Not a letter");
1579 @.Not a letter@>
1580     help2("Letters in \hyphenation words must have \lccode>0.")@/
1581       ("Proceed; I'll ignore the character I just read.");
1582     error;
1583     end
1584   else if n<63 then
1585     begin incr(n); hc[n]:=lc_code(cur_chr);
1586     end;
1587   end
1588 @z
1589
1590 @x
1591 @d main_loop=70 {go here to typeset a string of consecutive characters}
1592 @y
1593 @d main_loop=70 {go here to typeset a string of consecutive characters}
1594 @d main_loop_wchar=130 {go here to typeset a string of consecutive double-byte characters}
1595 @d save_cur_wchar=132 {go here to typeset a double-byte characters}
1596 @d next_is_a_char=133 {go here if next token is a single-byte character}
1597 @d fetch_next_tok=134 {go here to fetch next token}
1598 @z
1599
1600 @x
1601 @t\4@>@<Declare the procedure called |handle_right_brace|@>@;
1602 procedure main_control; {governs \TeX's activities}
1603 @y
1604 @t\4@>@<Declare the procedure called |handle_right_brace|@>@;
1605 procedure main_control; {governs \TeX's activities}
1606 @z
1607
1608 @x
1609 label big_switch,reswitch,main_loop,main_loop_wrapup,
1610 @y
1611 label big_switch,reswitch,main_loop_wchar,main_loop_wchar+1,save_cur_wchar,
1612       next_is_a_char,fetch_next_tok,main_loop,main_loop+1,
1613       main_loop_wrapup,main_loop_lookahead+2,
1614 @z
1615
1616 @x
1617 var@!t:integer; {general-purpose temporary variable}
1618 begin if every_job<>null then begin_token_list(every_job,every_job_text);
1619 big_switch: get_x_token;@/
1620 @y
1621 var@!t:integer; {general-purpose temporary variable}
1622 begin if every_job<>null then begin_token_list(every_job,every_job_text);
1623 @<Initialization of global variables done in the |main_control| procedure@>@;
1624 big_switch: get_x_token;@/
1625 @z
1626
1627 @x
1628 hmode+letter,hmode+other_char,hmode+char_given: goto main_loop;
1629 @y
1630 hmode+letter,hmode+other_char,hmode+char_given:
1631   if is_wchar(cur_chr) then goto main_loop_wchar
1632   else goto main_loop;
1633 hmode+pux_char_given: goto main_loop_wchar;
1634 @z
1635
1636 @x
1637 hmode+char_num: begin scan_char_num; cur_chr:=cur_val; goto main_loop;@+end;
1638 hmode+no_boundary: begin get_x_token;
1639   if (cur_cmd=letter)or(cur_cmd=other_char)or(cur_cmd=char_given)or
1640    (cur_cmd=char_num) then cancel_boundary:=true;
1641   goto reswitch;
1642   end;
1643 @y
1644 hmode+char_num: begin scan_char_num; cur_chr:=cur_val; goto main_loop;@+end;
1645 hmode+pux_char_num: begin scan_wchar_num; cur_chr:=cur_val; goto main_loop_wchar;@+end;
1646 hmode+no_boundary: begin get_x_token;
1647   if (cur_cmd=letter)or(cur_cmd=other_char)or(cur_cmd=char_given)or
1648    (cur_cmd=char_num)or(cur_cmd=pux_char_num)or(cur_cmd=pux_char_given) then cancel_boundary:=true;
1649   goto reswitch;
1650   end;
1651 @z
1652
1653 @x
1654 hmode+spacer: if space_factor=1000 then goto append_normal_space
1655   else app_space;
1656 hmode+ex_space,mmode+ex_space: goto append_normal_space;
1657 @y
1658 @t\4@>@<Cases of |main_control| that handle spacer@>@;
1659 @z
1660
1661 @x
1662 main_loop:@<Append character |cur_chr| and the following characters (if~any)
1663 @y
1664 main_loop_wchar:@<Append double-byte character |cur_chr| and the following double-byte characters
1665   (if~any) to the current hlist in the current font; |goto main_loop| when a single-byte character
1666   has been fetched; |goto reswitch| when a non-character has been fetched@>;
1667 main_loop:@<Append character |cur_chr| and the following characters (if~any)
1668 @z
1669
1670 @x
1671 @d adjust_space_factor==@t@>@;@/
1672   main_s:=sf_code(cur_chr);
1673 @y
1674 @d adjust_space_factor==@t@>@;@/
1675   if (cur_chr < 256) then main_s:=sf_code(cur_chr)
1676   else main_s:=1000;
1677 @z
1678
1679 @x
1680 adjust_space_factor;@/
1681 main_f:=cur_font;
1682 @y
1683 main_cf:=cur_cfont; {in case the first letter is not a Chinese character}
1684 @<If the preceding node is wchar node, then append a cespace@>;
1685 main_loop+1:adjust_space_factor; main_f:=cur_font;
1686 @z
1687
1688 @x
1689 get_next; {set only |cur_cmd| and |cur_chr|, for speed}
1690 if cur_cmd=letter then goto main_loop_lookahead+1;
1691 if cur_cmd=other_char then goto main_loop_lookahead+1;
1692 if cur_cmd=char_given then goto main_loop_lookahead+1;
1693 x_token; {now expand and set |cur_cmd|, |cur_chr|, |cur_tok|}
1694 if cur_cmd=letter then goto main_loop_lookahead+1;
1695 if cur_cmd=other_char then goto main_loop_lookahead+1;
1696 if cur_cmd=char_given then goto main_loop_lookahead+1;
1697 if cur_cmd=char_num then
1698   begin scan_char_num; cur_chr:=cur_val; goto main_loop_lookahead+1;
1699   end;
1700 if cur_cmd=no_boundary then bchar:=non_char;
1701 cur_r:=bchar; lig_stack:=null; goto main_lig_loop;
1702 main_loop_lookahead+1: adjust_space_factor;
1703 fast_get_avail(lig_stack); font(lig_stack):=main_f;
1704 cur_r:=qi(cur_chr); character(lig_stack):=cur_r;
1705 if cur_r=false_bchar then cur_r:=non_char {this prevents spurious ligatures}
1706 @y
1707 @<Look ahead for next character. If it is a wide character then append
1708   a cespace, or leave |lig_stack| empty if there's no character there@>
1709 @z
1710
1711 @x
1712 else temp_ptr:=new_param_glue(space_skip_code);
1713 link(tail):=temp_ptr; tail:=temp_ptr;
1714 goto big_switch
1715 @y
1716 else temp_ptr:=new_param_glue(space_skip_code);
1717 link(tail):=temp_ptr; tail:=temp_ptr;
1718 if pux_xspace=0 then goto reswitch else goto big_switch
1719 @z
1720
1721 @x
1722 hbox_group: package(0);
1723 adjusted_hbox_group: begin adjust_tail:=adjust_head; package(0);
1724   end;
1725 @y
1726 hbox_group: @<Setup |hbox_tail| and package@>;
1727 adjusted_hbox_group: begin adjust_tail:=adjust_head;
1728   @<Setup |hbox_tail| and package@>;
1729   end;
1730 @z
1731
1732 @x
1733 vmode+start_par: new_graf(cur_chr>0);
1734 vmode+letter,vmode+other_char,vmode+char_num,vmode+char_given,
1735    vmode+math_shift,vmode+un_hbox,vmode+vrule,
1736 @y
1737 vmode+start_par: new_graf(cur_chr>0);
1738 vmode+letter,vmode+other_char,vmode+char_num,vmode+char_given,
1739    vmode+pux_char_num,vmode+pux_char_given,
1740    vmode+math_shift,vmode+un_hbox,vmode+vrule,
1741 @z
1742
1743 @x
1744 begin if tail<>head then
1745   begin if is_char_node(tail) then p:=tail
1746 @y
1747 begin if tail<>head then
1748   begin if is_char_node(tail) and not is_wchar_node(tail) then p:=tail
1749 @z
1750
1751 @x
1752 reswitch: if is_char_node(p) then
1753   begin f:=font(p); d:=char_width(f)(char_info(f)(character(p)));
1754   goto found;
1755   end;
1756 @y
1757 reswitch: if is_char_node(p) then
1758   begin f:=font(p);
1759   if is_wchar_node(p) then
1760     d:=cfont_width[f]
1761   else
1762     d:=char_width(f)(char_info(f)(character(p)));
1763   goto found;
1764   end;
1765 @z
1766
1767 @x
1768 letter,other_char,char_given: begin c:=ho(math_code(cur_chr));
1769     if c=@'100000 then
1770       begin @<Treat |cur_chr| as an active character@>;
1771       goto restart;
1772       end;
1773     end;
1774 @y
1775 letter,other_char,char_given: begin
1776   if is_wchar(cur_chr) then begin
1777     print_err("Chinese character is ignored in math mode");
1778     help1("Did you forget putting it into an \hbox?");
1779     error;
1780     goto restart;
1781     end
1782   else begin
1783     c:=ho(math_code(cur_chr));
1784     if c=@'100000 then
1785       begin @<Treat |cur_chr| as an active character@>;
1786       goto restart;
1787       end;
1788     end;
1789   end;
1790 @z
1791
1792 @x
1793 char_num: begin scan_char_num; cur_chr:=cur_val; cur_cmd:=char_given;
1794   goto reswitch;
1795   end;
1796 @y
1797 char_num: begin scan_char_num; cur_chr:=cur_val; cur_cmd:=char_given;
1798   goto reswitch;
1799   end;
1800 pux_char_num: begin scan_wchar_num; cur_chr:=cur_val; cur_cmd:=pux_char_given;
1801   goto reswitch;
1802   end;
1803 pux_char_given:begin print_err("Chinese character is ignored in math mode");
1804   help1("Did you forget putting it into an \hbox?");
1805   error;
1806   goto restart;
1807   end;
1808 @z
1809
1810 @x
1811 mmode+letter,mmode+other_char,mmode+char_given:
1812   set_math_char(ho(math_code(cur_chr)));
1813 @y
1814 mmode+letter,mmode+other_char,mmode+char_given:
1815   if is_wchar(cur_chr) then begin
1816     print_err("Chinese character is ignored in math mode");
1817     help1("Did you forget putting it into an \hbox?");
1818     error;
1819     end
1820   else
1821     set_math_char(ho(math_code(cur_chr)));
1822 @z
1823
1824 @x
1825   letter,other_char: cur_val:=del_code(cur_chr);
1826 @y
1827   letter,other_char:
1828     if is_wchar(cur_chr) then
1829       cur_val:=-1
1830     else
1831       cur_val:=del_code(cur_chr);
1832 @z
1833
1834 @x
1835 mmode+math_shift: if cur_group=math_shift_group then after_math
1836   else off_save;
1837 @y
1838 mmode+math_shift: if cur_group=math_shift_group then begin
1839     after_math;
1840     if math_mode_save<0 then begin
1841       get_x_token;
1842       @<If the token is a wide character, then append a cspace@>;
1843       goto reswitch;
1844       end;
1845     end
1846   else off_save;
1847 @z
1848
1849 @x
1850 tail_append(new_math(math_surround,after));
1851 space_factor:=1000; unsave;
1852 end
1853 @y
1854 math_mode_save:=m;
1855 tail_append(new_math(math_surround,after));
1856 space_factor:=1000; unsave;
1857 end
1858 @z
1859
1860 @x
1861 any_mode(set_font),
1862 any_mode(def_font),
1863 @y
1864 any_mode(set_font),
1865 any_mode(def_font),
1866 any_mode(set_cfont),
1867 any_mode(pux_cface_def),
1868 any_mode(pux_face_match),
1869 any_mode(pux_font_match),
1870 any_mode(pux_set_cface),
1871 any_mode(puxg_assign_flag),
1872 any_mode(puxg_assign_int),
1873 any_mode(pux_get_int),
1874 any_mode(pux_set_cface_attrib),
1875 any_mode(pux_set_cfont_attrib),
1876 any_mode(pux_range_catcode),
1877 any_mode(pux_range_type_code),
1878 any_mode(pux_split_number),
1879 any_mode(puxg_assign_space),
1880 any_mode(pux_set_default_cface),
1881 any_mode(pux_dump_font_info),
1882 @z
1883
1884 @x
1885 @t\4@>@<Declare subprocedures for |prefixed_command|@>@t@>@;@/
1886 procedure prefixed_command;
1887 @y
1888 @t\4@>@<Declare PUTeX subprocedures for |prefixed_command|@>@t@>@;@/
1889 @t\4@>@<Declare subprocedures for |prefixed_command|@>@t@>@;@/
1890 procedure prefixed_command;
1891 @z
1892
1893 @x
1894 @!n:integer; {ditto}
1895 @!e:boolean; {should a definition be expanded? or was \.{\\let} not done?}
1896 @y
1897 @!n:integer; {ditto}
1898 @!e:boolean; {should a definition be expanded? or was \.{\\let} not done?}
1899 @<Other variables used by the procedure |prefixed_command|@>@;
1900 @z
1901
1902 @x
1903 set_font: define(cur_font_loc,data,cur_chr);
1904 @y
1905 set_font: begin define(cur_font_loc,data,cur_chr);@/
1906   @<Set the matching CJK font@>;
1907   end;
1908 @z
1909
1910 @x
1911 @d toks_def_code=6 {|shorthand_def| for \.{\\toksdef}}
1912 @y
1913 @d toks_def_code=6 {|shorthand_def| for \.{\\toksdef}}
1914 @d pux_char_def_code=7 {|shorthand_def| for \.{\\PUXchardef}}
1915 @z
1916
1917 @x
1918 primitive("toksdef",shorthand_def,toks_def_code);@/
1919 @!@:toks_def_}{\.{\\toksdef} primitive@>
1920 @y
1921 primitive("toksdef",shorthand_def,toks_def_code);@/
1922 @!@:toks_def_}{\.{\\toksdef} primitive@>
1923 primitive("PUXchardef",shorthand_def,pux_char_def_code);@/
1924 @!@:pux_char_def_}{\.{\\toksdef} primitive@>
1925 @z
1926
1927 @x
1928   mu_skip_def_code: print_esc("muskipdef");
1929   char_sub_def_code: print_esc("charsubdef");
1930   othercases print_esc("toksdef")
1931 @y
1932   mu_skip_def_code: print_esc("muskipdef");
1933   char_sub_def_code: print_esc("charsubdef");
1934   toks_def_code: print_esc("toksdef");
1935   othercases print_esc("PUXchardef")
1936 @z
1937
1938 @x
1939   case n of
1940   char_def_code: begin scan_char_num; define(p,char_given,cur_val);
1941     end;
1942   math_char_def_code: begin scan_fifteen_bit_int; define(p,math_given,cur_val);
1943     end;
1944   othercases begin scan_eight_bit_int;
1945 @y
1946   case n of
1947   char_def_code: begin scan_char_num; define(p,char_given,cur_val);
1948     end;
1949   math_char_def_code: begin scan_fifteen_bit_int; define(p,math_given,cur_val);
1950     end;
1951   pux_char_def_code: begin scan_wchar_num; define(p,pux_char_given,cur_val);
1952     end;
1953   othercases begin scan_eight_bit_int;
1954 @z
1955
1956 @x
1957 primitive("catcode",def_code,cat_code_base);
1958 @!@:cat_code_}{\.{\\catcode} primitive@>
1959 @y
1960 primitive("catcode",def_code,cat_code_base);
1961 @!@:cat_code_}{\.{\\catcode} primitive@>
1962 primitive("PUXcatcode",def_code,pux_cat_code_base);
1963 @!@:pux_cat_code_}{\.{\\PUXcatcode} primitive@>
1964 primitive("PUXtypecode",def_code,pux_type_code_base);
1965 @!@:pux_type_code_base_}{\.{\\PUXtypecode} primitive@>
1966 primitive("PUXlocalnames",def_code,pux_local_names_base);
1967 @!@:pux_local_names_base_}{\.{\\PUXlocalnames} primitive@>
1968 @z
1969
1970 @x
1971   else if chr_code=math_code_base then print_esc("mathcode")
1972 @y
1973   else if chr_code=pux_cat_code_base then print_esc("PUXcatcode")
1974   else if chr_code=pux_type_code_base then print_esc("PUXtypecode")
1975   else if chr_code=pux_local_names_base then print_esc("PUXlocalnames")
1976   else if chr_code=math_code_base then print_esc("mathcode")
1977 @z
1978
1979 @x
1980   p:=cur_chr; scan_char_num; p:=p+cur_val; scan_optional_equals;
1981   scan_int;
1982 @y
1983   p:=cur_chr;
1984   if p = pux_cat_code_base then
1985         begin scan_wchar_num; p := cat_code_base;
1986         end
1987   else if p = pux_type_code_base then scan_wchar_num
1988   else if p = pux_local_names_base then scan_eight_bit_int
1989   else
1990         scan_char_num;
1991   p:=p+cur_val; scan_optional_equals;
1992   if p=pux_local_names_base then scan_wchar_num
1993   else scan_int;
1994 @z
1995
1996 @x
1997 else if cur_chr=math_code_base then n:=@'100000
1998 @y
1999 else if cur_chr=pux_cat_code_base then n:=max_char_code
2000 else if cur_chr=pux_type_code_base then n:=max_type_code
2001 else if cur_chr=pux_local_names_base then n:=65535
2002 else if cur_chr=math_code_base then n:=@'100000
2003 @z
2004
2005 @x
2006 set_box: begin scan_eight_bit_int;
2007   if global then n:=256+cur_val@+else n:=cur_val;
2008   scan_optional_equals;
2009   if set_box_allowed then scan_box(box_flag+n)
2010   else begin print_err("Improper "); print_esc("setbox");
2011 @y
2012 set_box: begin scan_eight_bit_int;
2013   if global then n:=256+cur_val@+else n:=cur_val;
2014   scan_optional_equals;
2015   if set_box_allowed then begin
2016     in_set_box:=true;
2017     scan_box(box_flag+n);
2018     in_set_box:=false;
2019     end
2020   else begin print_err("Improper "); print_esc("setbox");
2021 @z
2022
2023 @x
2024 procedure new_font(@!a:small_number);
2025 label common_ending;
2026 var u:pointer; {user's font identifier}
2027 @!s:scaled; {stated ``at'' size, or negative of scaled magnification}
2028 @!f:internal_font_number; {runs through existing fonts}
2029 @!t:str_number; {name for the frozen font identifier}
2030 @!old_setting:0..max_selector; {holds |selector| setting}
2031 begin if job_name=0 then open_log_file;
2032   {avoid confusing \.{texput} with the font name}
2033 @.texput@>
2034 get_r_token; u:=cur_cs;
2035 if u>=hash_base then t:=text(u)
2036 else if u>=single_base then
2037   if u=null_cs then t:="FONT"@+else t:=u-single_base
2038 else  begin old_setting:=selector; selector:=new_string;
2039   print("FONT"); print(u-active_base); selector:=old_setting;
2040 @.FONTx@>
2041   str_room(1); t:=make_string;
2042   end;
2043 define(u,set_font,null_font); scan_optional_equals; scan_file_name;
2044 @<Scan the font size specification@>;
2045 @<If this font has already been loaded, set |f| to the internal
2046   font number and |goto common_ending|@>;
2047 f:=read_font_info(u,cur_name,cur_area,s);
2048 common_ending: equiv(u):=f; eqtb[font_id_base+f]:=eqtb[u]; font_id_text(f):=t;
2049 end;
2050 @y
2051 @<Declare the function called |fw_times_sd|@>@;
2052 @<Declare the function called |find_cface_num|@>@;
2053 @<Declare the procedure called |check_cfont|@>@;
2054 @<Declare the procedure called |make_cfont|@>@;
2055 procedure new_font(@!a:small_number);
2056 label common_ending;
2057 var u:pointer; {user's font identifier}
2058 @!j,k:pool_pointer;
2059 @!s:scaled; {stated ``at'' size, or negative of scaled magnification}
2060 @!f:internal_font_number; {runs through existing fonts}
2061 @!t:str_number; {name for the frozen font identifier}
2062 @!old_setting:0..max_selector; {holds |selector| setting}
2063 @!flushable_string:str_number; {string not yet referenced}
2064 @<Other local variables used by procedure |new_font|@>@;
2065 begin if job_name=0 then open_log_file;
2066   {avoid confusing \.{texput} with the font name}
2067 @.texput@>
2068 get_r_token; u:=cur_cs;
2069 if u>=hash_base then t:=text(u)
2070 else if u>=single_base then
2071   if u=null_cs then t:="FONT"@+else t:=u-single_base
2072 else  begin old_setting:=selector; selector:=new_string;
2073   print("FONT"); print(u-active_base); selector:=old_setting;
2074 @.FONTx@>
2075   str_room(1); t:=make_string;
2076   end;
2077 scan_optional_equals; scan_file_name;@/
2078 @<Scan the font size specification@>;
2079 if (length(cur_name) > 5) then
2080   begin
2081   j:=str_start[cur_name];
2082   if (str_pool[j]='C' and str_pool[j+1]='F' and str_pool[j+2]='O'
2083       and str_pool[j+3]='N' and str_pool[j+4]='T') then
2084     @<Define a CJK font and then goto |common_ending|@>;
2085   end;
2086 define(u,set_font,null_font);
2087 @<If this font has already been loaded, set |f| to the internal
2088   font number and |goto common_ending|@>;
2089 f:=read_font_info(u,cur_name,cur_area,s);
2090 common_ending: equiv(u):=f; eqtb[font_id_base+f]:=eqtb[u]; font_id_text(f):=t;
2091 end;
2092 @z
2093
2094 @x
2095 @!t:halfword; {token}
2096 @!c:eight_bits; {character code}
2097 begin b:=cur_chr; p:=scan_toks(false,false); p:=link(def_ref);
2098 @y
2099 @!t:halfword; {token}
2100 @!c:quarterword; {character code}
2101 begin b:=cur_chr; p:=scan_toks(false,false); p:=link(def_ref);
2102 @z
2103
2104 @x
2105 @<Change the case of the token in |p|, if a change is appropriate@>=
2106 t:=info(p);
2107 if t<cs_token_flag+single_base then
2108   begin c:=t mod 256;
2109   if equiv(b+c)<>0 then info(p):=t-c+equiv(b+c);
2110   end
2111 @y
2112 @<Change the case of the token in |p|, if a change is appropriate@>=
2113 t:=info(p);
2114 if t<cs_token_flag+single_base then
2115   begin c:=t mod 65536;
2116   if c < 256 then {only convert the single-byte char}
2117     if equiv(b+c)<>0 then info(p):=t-c+equiv(b+c);
2118   end
2119 @z
2120
2121 @x
2122 @<Dump the font information@>;
2123 @y
2124 @<Dump the font information@>;
2125 @<Dump the CJK font face information@>;
2126 @<Dump the face matching table@>;
2127 @<Dump the CJK font information@>;
2128 @z
2129
2130 @x
2131 @<Undump the font information@>;
2132 @y
2133 @<Undump the font information@>;
2134 @<Undump the CJK font face information@>;
2135 @<Unump the face matching table@>;
2136 @<Undump the CJK font information@>;
2137 @z
2138
2139 @x
2140 15: begin font_in_short_display:=null_font; short_display(n);
2141 @y
2142 15: begin font_in_short_display:=null_font; cfont_in_short_display:=null_cfont; short_display(n);
2143 @z
2144
2145 @x
2146 @* \[55] Index.
2147 @y
2148 @* \[55] Introduction to \PUTeX.
2149 \PUTeX is an extension of \TeX to handle CJK character sets.
2150
2151 @ @<Glob...@>=
2152 @!hi_byte, @!lo_byte : ASCII_code;
2153 {temp var for storing high byte and low byte of a double-byte character}
2154 @!db_char : quarterword; {temp var for storing a double-byte character}
2155 @!expand_char : boolean;
2156 @!doc_charset : eight_bits;
2157 @!char_val_flag : boolean;
2158
2159 @ @<Set initial...@>=
2160 expand_char:=false;
2161
2162 @ The default catcode for CJK characters is `letter'.
2163
2164 @<Initialize table entries...@>=
2165 for k:= 256 to 65535 do
2166   begin cat_code(k) := letter;
2167   end;
2168
2169 @ Initially, \PUTeX\ just set type codes for OT1 encoding.
2170
2171 @d set_tail_forbidden(#) == set_type_code(#)(tail_forbidden)
2172 @d set_head_forbidden(#) == set_type_code(#)(head_forbidden)
2173
2174 @<Initialize table entries...@>=
2175 set_tail_forbidden("(");
2176 set_tail_forbidden("[");
2177 set_tail_forbidden("{");@/
2178 set_head_forbidden("!");
2179 set_head_forbidden(")");
2180 set_head_forbidden(",");@/
2181 set_head_forbidden(".");
2182 set_head_forbidden(":");
2183 set_head_forbidden(";");@/
2184 set_head_forbidden("?");
2185 set_head_forbidden("]");
2186 set_head_forbidden("}");
2187
2188 @ @<PUTeX routines...@>=
2189 function get_cat_code (ch:halfword) : halfword;
2190 var cat: halfword; {catcode}
2191 begin
2192   if pux_wcharother <> 0 then
2193     if ch > 255 then cat := other_char
2194     else cat := cat_code(ch)
2195   else cat := cat_code(ch);
2196   get_cat_code := cat;
2197 end;
2198
2199 @ @<Put each of \TeX's primitives into the hash table@>=
2200 primitive("PUXrangecatcode",pux_range_catcode,0);
2201 primitive("PUXrangetypecode",pux_range_type_code,0);
2202
2203 @ @<Other variables used by the procedure |prefixed_command|@>=
2204 @!bc, ec: halfword; {the begin char and end char of code range}
2205
2206 @ @<Assignments@>=
2207 pux_range_catcode, pux_range_type_code: begin
2208     p:=cur_chr;
2209     if cur_cmd = pux_range_catcode then begin
2210       n:=max_char_code;
2211       p:=cat_code_base;
2212     end
2213     else begin
2214       n:=max_type_code;
2215       p:=pux_type_code_base;
2216     end;
2217     scan_wchar_num; bc := cur_val;@/
2218     scan_keyword("to");@/
2219     scan_wchar_num; ec := cur_val;@/
2220     scan_optional_equals;@/
2221     scan_int;@/
2222     
2223     if (bc = 0) or (ec = 0) or (ec < bc) then begin
2224       if ec < bc then begin
2225         print_err("Invalid range setting, ec < bc");
2226       end;
2227       help1("I'm going to ignore this command.");@/
2228       error;
2229       goto exit; @.Invalid range@>
2230     end;
2231     
2232     if (cur_val < 0) or (cur_val > n) then begin
2233       print_err("Invalid catcode ("); print_int(cur_val);
2234       print("), should be in the range 0..15");@/
2235       help1("I'm going to ignore this command.");@/
2236       error;
2237       goto exit; @.Invalid code@>
2238     end;
2239
2240     for k := bc to ec do define(p+k,data,cur_val);
2241   end;
2242
2243 @ @<Initialize table entries...@>=
2244 for k:=0 to 255 do local_names(k) := "?";
2245
2246 @ @<PUTeX basic scanning routines@>=
2247 function scan_name: str_number;
2248   begin
2249   @<Get the next non-blank non-call token@>;
2250   while cur_cmd=letter do
2251     begin
2252     if (is_wchar(cur_chr)) then append_wchar(cur_chr) else append_char(cur_chr);
2253     get_x_token;
2254     end;
2255   if pool_ptr <> str_start[str_ptr] then
2256     scan_name:=make_string
2257   else
2258     scan_name:=0;
2259   end;
2260
2261 @ @<Declare procedures that scan restricted classes of integers@>=
2262 procedure scan_wchar_num;
2263 begin scan_int;
2264 if (cur_val<257)or(cur_val>65535) then
2265   begin print_err("Bad wide character code");
2266 @.Bad wide character code@>
2267   help2("A wide character number must be between 256 and 65536.")@/
2268     ("I changed this one to zero."); int_error(cur_val); cur_val:=0;
2269   end;
2270 end;
2271
2272 @* \[56] CJK Numbers.
2273
2274 @<Global variables@>=
2275 @!cnum_one_flag:boolean;
2276
2277 @
2278 @d ten_wchar_offset=10
2279 @d hundred_wchar_offset=11
2280 @d thousand_wchar_offset=12
2281 @d ten_thousand_wchar_offset=13
2282 @d hundred_million_wchar_offset=14
2283 @d arabic_wchar_offset=40
2284 @d negative_wchar_offset=50
2285 @d negative_wsym_offset=51
2286 @d twenty_wchar_offset=52
2287 @d thirty_wchar_offset=53
2288 @d CJK_digit_offset=0
2289 @d C_simple_digit_offset=10
2290 @d C_formal_digit_offset=25
2291 @d C_arabic_digit_offset=40
2292
2293
2294 @<Basic print...@>=
2295 procedure print_chinese_int (@!n,@!digit_base:integer;@!simple,@!formal:boolean);
2296 var @!m:integer;
2297 begin
2298   cnum_one_flag:=false;
2299   if n < 0 then begin
2300     {|print_dbchar| is replaced by the following 2 |print_char| calls. }
2301     print_wchar(local_names(negative_wchar_offset));
2302     negate(n);
2303     end;
2304   if n<100 then print_small_chinese_int(n,digit_base,simple,formal)
2305   else begin
2306     if n>99999999 then begin
2307       print_small_chinese_int(n div 100000000,digit_base,simple,formal);
2308       print_wchar(local_names(digit_base+hundred_million_wchar_offset));
2309       cnum_one_flag:=true;
2310       n:=n mod 100000000;
2311       if n>0 and n<10000000 then
2312         print_wchar(local_names(digit_base)); {zero character in Chinese}
2313       end;
2314     if n>9999 then begin
2315       print_medium_chinese_int(n div 10000,digit_base,simple,formal);
2316       print_wchar(local_names(digit_base+ten_thousand_wchar_offset));
2317       cnum_one_flag:=true;
2318       n:=n mod 10000;
2319       if n>0 and n<1000 then
2320         print_wchar(local_names(digit_base)); {zero character in Chinese}
2321       end;
2322     print_medium_chinese_int(n,digit_base,simple,formal);
2323   end;
2324 end;
2325
2326 @ The following procedure prints a number n, $0\le n \le 99$.
2327 @<Basic print...@>=
2328 procedure print_small_chinese_int (n,@!digit_base:integer;@!simple,@!formal:boolean);
2329 label done1;
2330 begin@/
2331   if n<10 then print_wchar(local_names(n+digit_base))
2332   else begin
2333     if n<20 then begin
2334       if formal or cnum_one_flag then
2335         print_wchar(local_names(digit_base+1));
2336       print_wchar(local_names(digit_base+10));@/
2337       goto done1;
2338       end;
2339     if n<30 and simple then begin
2340       print_wchar(local_names(twenty_wchar_offset));@/
2341       goto done1;
2342       end;
2343     if n<40 and simple then begin
2344       print_wchar(local_names(thirty_wchar_offset));@/
2345       goto done1;
2346       end;
2347     print_wchar(local_names(digit_base + n div 10));
2348     print_wchar(local_names(digit_base+10));
2349 done1: n:=n mod 10;
2350     if n>0 then print_wchar(local_names(n+digit_base));
2351     end
2352 end;
2353
2354 @ Print a chinese number of medium size.
2355 @<Basic print...@>=
2356 procedure print_medium_chinese_int (n,@!digit_base:integer;@!simple,@!formal:boolean);
2357 begin
2358   if n>999 then begin
2359     print_wchar(local_names(digit_base+n div 1000));
2360     print_wchar(local_names(digit_base+thousand_wchar_offset));
2361     n:=n mod 1000;
2362     if n>0 and n<99 then
2363         print_wchar(local_names(digit_base)); {zero character in Chinese}
2364     end;
2365   if n>99 then begin
2366     print_wchar(local_names(digit_base+n div 100));
2367     print_wchar(local_names(digit_base+hundred_wchar_offset));
2368     n:=n mod 100;
2369     if n>0 and n<9 then
2370         print_wchar(local_names(digit_base)); {zero character in Chinese}
2371     end;
2372   cnum_one_flag:=true;
2373   if n>0 then print_small_chinese_int(n,digit_base,simple,formal);
2374 end;
2375
2376 @ @<Put each of \TeX's primitives into the hash table@>=
2377 primitive("puxnumdigits",pux_get_int,int_base+pux_digit_num_code);
2378 primitive("puxsign",pux_get_int,int_base+pux_sign_code);
2379 primitive("puxdigit",pux_get_int,int_base+pux_digit_base);
2380
2381 @ @<Cases of |print_cmd_chr|...@>=
2382 pux_get_int:
2383   if chr_code=pux_digit_num_code+int_base then
2384     print_esc("puxnumdigits")
2385   else if chr_code=pux_sign_code+int_base then
2386     print_esc("puxsign")
2387   else if chr_code=pux_digit_base+int_base then
2388     print_esc("puxdigit");
2389
2390 @ @<Assignments@>=
2391 pux_get_int: begin
2392   print_err("You can't assign values to internal read-only parameters.");
2393   error;
2394 end;
2395
2396 @ @<scan \PUTeX\ internal values@>=
2397 begin
2398   if m=pux_digit_base+int_base then begin
2399     scan_int;
2400     if cur_val < 0 or cur_val > 9 then begin
2401       print_err("Improper digit place specified (");
2402       print_int(cur_val); print("), replaced by 0");
2403       cur_val:=0;
2404     end;
2405     m:=m+cur_val;
2406   end;
2407   scanned_result(eqtb[m].int)(int_val);
2408 end
2409
2410 @ @<Put each of \TeX's primitives into the hash table@>=
2411 primitive("PUXsplitnumber",pux_split_number,0);
2412
2413 @ @<Assignments@>=
2414 pux_split_number: begin
2415   scan_int;
2416   split_number(cur_val);
2417 end;
2418
2419 @ The following procedure splits the integer parameter |n| to digit list and stores the number of digits into
2420 |pux_digit_num|, the sign (1: positive or -1: negative) into |pux_num_sign|, and the digits into
2421 the array |pux_nth_digit|. Since the largest |n| is $2^{31}$, n contains at most 10 digits.
2422
2423 @<PUTeX routines...@>=
2424 procedure split_number (n:integer);
2425 var k: 0..10;
2426 begin
2427 if n<0 then begin
2428   pux_num_sign := -1;
2429   negate(n)
2430   end
2431 else
2432   pux_num_sign := 1;
2433 k:=0;
2434 repeat pux_nth_digit(k):=n mod 10; n:=n div 10; incr(k);
2435 until n=0;
2436 pux_digit_num:=k;
2437 while k < 10 do begin
2438   pux_nth_digit(k) := 0;
2439   incr(k);
2440   end;
2441 end;
2442
2443 @
2444 @<scan and split the number@>=
2445 begin
2446   scan_int;
2447   split_number(cur_val);
2448 end
2449
2450 @ @<scan a CJK number with a possible selector and then  split it@>=
2451 begin
2452   scan_int; saved_val:=cur_val;
2453   split_number(cur_val);
2454   if scan_keyword("offset") then begin
2455     scan_eight_bit_int;
2456     digit_base:=cur_val;
2457     if scan_keyword("sign") then begin
2458       scan_eight_bit_int;
2459       sign:=cur_val;
2460       end
2461     else
2462       sign:=negative_wchar_offset;
2463   end
2464   else digit_base:=0;
2465 end
2466
2467 @ Using full-width arabic characters to show chinese numbers.
2468 @<Basic print...@>=
2469 procedure print_cjk_int(@!n:integer;digit_base,sign:integer);
2470 var k:0..9; {index to current digit}
2471 begin
2472   if pux_num_sign = -1 then print_wchar(local_names(sign));
2473   for k:=pux_digit_num-1 downto 0 do
2474     print_wchar(local_names(digit_base+pux_nth_digit(k)));
2475 end;
2476
2477 @ @<using full-width arabic characters to print a CJK number@>=
2478 print_cjk_int(cur_val,C_arabic_digit_offset,negative_wsym_offset)
2479
2480 @ @<print a CJK number with specified format@>=
2481 print_cjk_int(saved_val,digit_base,sign)
2482
2483 @ @<scan a CJK name sequence number@>=
2484 begin
2485   scan_eight_bit_int; saved_val:=cur_val;
2486   if scan_keyword("min") then begin
2487     scan_optional_equals; scan_eight_bit_int;
2488     min_val:=cur_val;
2489   end
2490   else begin
2491     print_err("Missing 'min' part ("); print("min 0 inserted)");
2492     error;
2493   end;
2494   if scan_keyword("max") then begin
2495     scan_optional_equals; scan_eight_bit_int;
2496     max_val:=cur_val;
2497   end
2498   else begin
2499     print_err("Missing 'max' part ("); print("max 255 inserted)");
2500     error;
2501   end;
2502   if scan_keyword("offset") then begin
2503     scan_optional_equals; scan_eight_bit_int;
2504     offset:=cur_val;
2505   end
2506   else begin
2507     print_err("Missing 'offset' part ("); print("offset 0 inserted)");
2508     error;
2509   end;
2510   if min_val <= saved_val and saved_val <= max_val then
2511     cur_val:=offset+saved_val-min_val
2512   else begin
2513     print_err("Number is out of the range ("); print("replaced with the min value)");
2514     cur_val:=offset;
2515     error;
2516   end;
2517 end
2518
2519 @ @<print a CJK name sequence member@>=
2520 print_wchar(local_names(cur_val))
2521
2522 @ A fix\_word is a {\sl scaled integers\/} that are multiples
2523 of $2^{-20}$. In other words, a binary point is assumed to be twenty bit
2524 positions from the right end of a binary computer word.
2525 @d fw_unity == @"100000 {$2^{20}$, represents 1.00000}
2526 @d fw_two == @"200000 {$2^{21}$, represents 2.00000}
2527 @d fw_one_fifth==@"33333 {0.2}
2528 @d convfix(#)== (#)*fw_unity div 1000
2529
2530 @<Types...@>=
2531 @!fixword = integer; {this type is used for fixword (12.20) integers}
2532
2533
2534 @ @<Declare the function called |print_fixword|@>=
2535 procedure print_fixword(@!s:fixword); {prints fixword real, rounded to five
2536   digits}
2537 var delta:fixword; {amount of allowable inaccuracy}
2538 begin if s<0 then
2539   begin print_char("-"); negate(s); {print the sign, if negative}
2540   end;
2541 print_int(s div fw_unity); {print the integer part}
2542 print_char(".");
2543 s:=10*(s mod fw_unity)+5; delta:=10;
2544 repeat if delta>fw_unity then s:=s+@'200000000-50000; {round the last digit}
2545 print_char("0"+(s div fw_unity)); s:=10*(s mod fw_unity); delta:=delta*10;
2546 until s<=delta;
2547 end;
2548
2549
2550 @ The function |fw_times_sd| do the multiplication of a fixword and a scaled number.
2551 The value of fixword is assumed between 16 and $-16$.
2552 The function returns the result as a scaled number. (See also Sec. 571, 572 and 600.)
2553
2554 @<Declare the function called |fw_times_sd|@>=
2555 function fw_times_sd (@!x:fixword; @!z:scaled) : scaled;
2556   {compute |f| times |s|}
2557 var @!sw:scaled;
2558 @!a,@!b,@!c,@!d:eight_bits; {byte variables}
2559 @!alpha:integer;@!beta:1..16;
2560 begin @<Replace |z|...@>;
2561 if x>=0 then a:=x div @'100000000
2562 else  begin x:=x+@'10000000000;
2563   x:=x+@'10000000000;
2564   a:=(x div @'100000000) + 128;
2565   end;
2566 x:=x mod @'100000000; b:=x div @'200000;
2567 x:=x mod @'200000; c:=x div @'400;
2568 d:=x mod @'400;
2569 sw:=(((((d*z)div@'400)+(c*z))div@'400)+(b*z))div beta;
2570 if a=0 then fw_times_sd:=sw
2571 else if a=255 then fw_times_sd:=sw-alpha
2572 else fw_times_sd:=unity;
2573 end;
2574
2575 @ @<Put each of \TeX's primitives into the hash table@>=
2576 primitive("PUXchar",pux_char_num,0);
2577
2578 @ @<Cases of |print_cmd_chr|...@>=
2579 pux_char_num: print_esc("PUXchar");
2580
2581 @ @<Give improper hyphenation error for Chinese characters inside@>=
2582 begin print_err("Improper "); print_esc("hyphenation");
2583 @.Improper \\hyphenation...@>
2584   print(" will be flushed");
2585 help2("Hyphenation exceptions can't contain Chinese characters")@/
2586   ("But continue; I'll forgive and forget.");
2587 error;
2588 end
2589
2590
2591 @ @<Cases of |main_control| that build...@>=
2592 mmode+pux_char_num: begin scan_wchar_num; cur_chr:=cur_val;
2593   print_err("Chinese character is ignored in math mode");
2594   help1("Did you forget putting it into an \hbox?");
2595   error;
2596   end;
2597 mmode+pux_char_given: begin
2598   print_err("Chinese character is ignored in math mode");
2599   help1("Did you forget putting it into an \hbox?");
2600   error;
2601   end;
2602
2603 @ @<Cases of |print_cmd_chr|...@>=
2604 pux_char_given: begin print_esc("PUXchar"); print_hex(chr_code);
2605   end;
2606
2607 @* \[58] All about spaces.
2608  
2609 @d is_tail_forbidden(#) == type_code(#) = tail_forbidden
2610 @d is_head_forbidden(#) == type_code(#) = head_forbidden
2611 @d is_head_forbidden_wchar(#) == ((# > 255) and (type_code(#) = head_forbidden))
2612 @d is_punc_wchar(#) == ((# > 255) and (type_code(#) <> 0))
2613
2614 @
2615 @<Global variables@>=
2616 @!main_cf:internal_cfont_number; {the current chinese font}
2617 @!math_mode_save:-mmode..mmode;
2618 @!prev_main_cf:internal_cfont_number; {the current chinese font}
2619 @!pre_undet_glue_ptr:pointer; {point to the node just before a undetermined glue}
2620 @!undet_glue_ptr:pointer; {point to the undetermined glue}
2621 @!cglue_ptr:pointer;
2622 @!cglue_spec:pointer;
2623 @!pre_glue_char_ptr:pointer;
2624 @!outer_tail:pointer;
2625 @!hbox_tail:pointer;
2626 @!in_set_box:boolean;
2627
2628 @ @<Initialization of global variables done in the |main_control| procedure@>=
2629 pre_undet_glue_ptr:=null;
2630 pre_glue_char_ptr:=null;
2631
2632 @
2633 @d tail_append_glue(#)==
2634 begin cglue_ptr:=get_node(small_node_size); cglue_spec:=#;
2635 type(cglue_ptr):=glue_node; subtype(cglue_ptr):=normal;
2636 leader_ptr(cglue_ptr):=null; glue_ptr(cglue_ptr):=cglue_spec;
2637 incr(glue_ref_count(cglue_spec));
2638 tail_append(cglue_ptr);
2639 end
2640
2641 @ Here is the check done before switching to regular character string.
2642 @<If the preceding node is wchar node, then append a cespace@>=
2643 if tail=head then begin
2644   if mode=-hmode then begin {beginning of a restricted hlist}
2645     outer_tail:=nest[nest_ptr-1].tail_field;
2646     if pre_undet_glue_ptr<>null then begin
2647       if outer_tail=link(pre_undet_glue_ptr) and pre_glue_char_ptr<>null
2648              and is_wchar_node(pre_glue_char_ptr) then begin
2649         decr(glue_ref_count(glue_ptr(outer_tail)));
2650         glue_ptr(outer_tail):=cfont_ceglue_spec[prev_main_cf];
2651         incr(glue_ref_count(cfont_ceglue_spec[prev_main_cf]));
2652         end;
2653       pre_undet_glue_ptr:=null;
2654       end;
2655     end;
2656   end
2657 else if is_char_node(tail) and is_wchar_node(tail) then begin
2658   if is_head_forbidden(cur_chr) then tail_append(new_penalty(inf_penalty));
2659   tail_append_glue(cfont_ceglue_spec[main_cf]);
2660   end
2661 else if pre_undet_glue_ptr<>null and link(pre_undet_glue_ptr)=tail and
2662      pre_glue_char_ptr<>null and is_wchar_node(pre_glue_char_ptr) then begin
2663   decr(glue_ref_count(glue_ptr(tail)));
2664   glue_ptr(tail):=cfont_ceglue_spec[prev_main_cf];
2665   incr(glue_ref_count(cfont_ceglue_spec[prev_main_cf]));
2666   end;
2667 pre_undet_glue_ptr:=null;
2668 pre_glue_char_ptr:=null;
2669
2670
2671 @ If the next token come after the math shift \$ is a wide character, then
2672 a cespace is appended first.
2673 @<If the token is a wide character, then append a cspace@>=
2674 if cur_cmd=pux_char_num then
2675   begin scan_wchar_num; cur_chr:=cur_val; cur_cmd:=pux_char_given;
2676   end;
2677 if cur_cmd=letter or cur_cmd=other_char or cur_cmd=pux_char_given then
2678   if is_wchar(cur_chr) then
2679     if is_punc_wchar(cur_chr) then begin
2680       if is_head_forbidden(cur_chr) then tail_append(new_penalty(inf_penalty));
2681       tail_append_glue(zero_glue);
2682       end
2683     else
2684       tail_append_glue(cfont_ceglue_spec[main_cf])
2685
2686
2687 @
2688 @<Append double-byte character |cur_chr|...@>=
2689 main_cf:=cur_cfont;
2690 @<If the current wchar is at the beginning of a restricted hlist that
2691   is after a undetermined spacer, then we have to determine that space.
2692   When it is done |goto save_cur_wchar|@>;
2693 @<If the previous node is an undetermined glue, then make it certain and
2694   |goto save_cur_wchar|@>;
2695 if not is_char_node(tail) then goto save_cur_wchar;
2696 main_loop_wchar+1:@<the previous node is a character node, so we have to append
2697 a glue first@>;
2698 save_cur_wchar:
2699 fast_get_avail(lig_stack);
2700 font(lig_stack):=main_cf;
2701 character(lig_stack):=cur_chr;
2702 tail_append(lig_stack);@/
2703 @<Prepare a nonbreak space if the current wide character is not allowed to
2704   appear at the end of line@>;
2705 fetch_next_tok:get_next; {set only |cur_cmd| and |cur_chr|, for speed}
2706 @<Check the lookahead character@>;
2707 x_token; {now expand and set |cur_cmd|, |cur_chr|, |cur_tok|}
2708 @<Check the lookahead character@>;
2709 if cur_cmd=char_num then
2710   begin scan_char_num; cur_chr:=cur_val; cur_cmd:=char_given; goto next_is_a_char;
2711   end;
2712 if cur_cmd=pux_char_num then
2713   begin scan_wchar_num; cur_chr:=cur_val;
2714   if is_punc_wchar(cur_chr) then
2715     if is_head_forbidden(cur_chr) then tail_append(new_penalty(inf_penalty));
2716   tail_append_glue(cfont_glue_spec[main_cf]);
2717   goto save_cur_wchar;
2718   end;
2719 {next token is not a character token}
2720 if cur_cmd=math_shift then
2721   if is_punc_wchar(character(lig_stack)) then
2722     tail_append_glue(zero_glue)
2723   else
2724     tail_append_glue(cfont_ceglue_spec[main_cf]);
2725 goto reswitch;
2726 next_is_a_char: begin@/
2727   if cur_chr<256 then
2728     if is_head_forbidden(cur_chr) then tail_append(new_penalty(inf_penalty));
2729   if is_punc_wchar(character(lig_stack)) then
2730     tail_append_glue(zero_glue)
2731   else
2732     tail_append_glue(cfont_ceglue_spec[main_cf]);
2733   goto main_loop+1;
2734   end
2735
2736
2737 @ @<If the current wchar is at the beginning...@>=
2738 if tail=head then begin {beginning of a restricted hlist}
2739   if mode=-hmode then begin
2740     outer_tail:=nest[nest_ptr-1].tail_field;
2741     if pre_undet_glue_ptr<>null then begin
2742       if outer_tail=link(pre_undet_glue_ptr) then begin
2743         undet_glue_ptr:=outer_tail;
2744         @<Modify the undetermined glue according the type of pre-glue character@>;
2745         end;
2746       pre_undet_glue_ptr:=null;
2747       end;
2748     end;
2749   goto save_cur_wchar;
2750   end
2751
2752
2753 @ @<Modify the undetermined glue...@>=
2754 decr(glue_ref_count(glue_ptr(undet_glue_ptr)));
2755 if pre_glue_char_ptr<>null and is_wchar_node(pre_glue_char_ptr) then begin
2756   glue_ptr(undet_glue_ptr):=cfont_glue_spec[prev_main_cf];
2757   incr(glue_ref_count(cfont_glue_spec[prev_main_cf]));
2758   pre_glue_char_ptr:=null;
2759   end
2760 else begin
2761   glue_ptr(undet_glue_ptr):=cfont_ceglue_spec[prev_main_cf];
2762   incr(glue_ref_count(cfont_ceglue_spec[prev_main_cf]));
2763   end
2764
2765 @ @<If the previous node is an undetermined glue...@>=
2766 if pre_undet_glue_ptr<>null then begin
2767   if link(pre_undet_glue_ptr)=tail then begin
2768     undet_glue_ptr:=tail;
2769     @<Modify the undetermined glue according the type of pre-glue character@>;
2770     pre_undet_glue_ptr:=null;
2771     goto save_cur_wchar;
2772     end;
2773   pre_undet_glue_ptr:=null;
2774   end
2775
2776
2777 @ @<the previous node is a character node...@>=
2778 if is_wchar_node(tail) then begin
2779   if is_head_forbidden_wchar(cur_chr) then
2780     tail_append(new_penalty(inf_penalty));
2781   tail_append(new_glue(cfont_glue_spec[main_cf]));
2782   end
2783 else begin {previous node is a single byte character}
2784   if is_punc_wchar(cur_chr) then begin
2785     if is_head_forbidden(cur_chr) then tail_append(new_penalty(inf_penalty));
2786     tail_append_glue(zero_glue);
2787     end
2788   else begin
2789     if is_head_forbidden(character(tail)) then tail_append(new_penalty(inf_penalty));
2790     tail_append_glue(cfont_ceglue_spec[main_cf]);
2791     end;
2792   end
2793
2794
2795
2796 @ For those Chinese puncuations that shoudn't appear in the line end,
2797 we append a penalty node to prevent line boken after it.
2798 @<Prepare a nonbreak space if the current wide...@>=
2799 if is_punc_wchar(cur_chr) then
2800   if is_tail_forbidden(cur_chr) then tail_append(new_penalty(inf_penalty))
2801
2802 @ @<Check the lookahead character@>=
2803 if cur_cmd=letter or cur_cmd=other_char or cur_cmd=pux_char_given or
2804    cur_cmd=char_given then
2805   if is_wchar(cur_chr) then begin
2806     if is_punc_wchar(cur_chr) then
2807       if is_head_forbidden(cur_chr) then tail_append(new_penalty(inf_penalty));
2808     tail_append_glue(cfont_glue_spec[main_cf]);
2809     goto save_cur_wchar;
2810     end
2811   else goto next_is_a_char
2812
2813
2814 @ @<Look ahead for next character. If it is a wide...@>=
2815 get_next; {set only |cur_cmd| and |cur_chr|, for speed}
2816 if cur_cmd=letter or cur_cmd=other_char then
2817   if is_wchar(cur_chr) then goto main_loop_lookahead+2
2818   else goto main_loop_lookahead+1;
2819 if cur_cmd=char_given then goto main_loop_lookahead+1;
2820 if cur_cmd=pux_char_given then goto main_loop_lookahead+2;
2821 x_token; {now expand and set |cur_cmd|, |cur_chr|, |cur_tok|}
2822 if cur_cmd=letter or cur_cmd=other_char then
2823   if is_wchar(cur_chr) then goto main_loop_lookahead+2
2824   else goto main_loop_lookahead+1;
2825 if cur_cmd=char_given then goto main_loop_lookahead+1;
2826 if cur_cmd=char_num then
2827   begin scan_char_num; cur_chr:=cur_val; goto main_loop_lookahead+1;
2828   end;
2829 if cur_cmd=pux_char_num then
2830   begin scan_wchar_num; cur_chr:=cur_val; goto main_loop_lookahead+2;
2831   end;
2832 if cur_cmd=no_boundary then bchar:=non_char;
2833 main_loop_lookahead+2: cur_r:=bchar; lig_stack:=null; goto main_lig_loop;
2834 main_loop_lookahead+1: adjust_space_factor;
2835 fast_get_avail(lig_stack); font(lig_stack):=main_f;
2836 cur_r:=qi(cur_chr); character(lig_stack):=cur_r;
2837 if cur_r=false_bchar then cur_r:=non_char {this prevents spurious ligatures}
2838
2839
2840 @ @<Cases of |main_control| that handle spacer@>=
2841 hmode+spacer: @<Lookahead and determine the type of spacer to append@>;
2842 hmode+ex_space: @<Lookahead and determine the type of |ex_spacer| to append@>;
2843 mmode+ex_space: begin if pux_xspace=0 then get_x_token; {lookahead}
2844                 goto append_normal_space;
2845                 end;
2846 hmode+pux_space:@<Handle \PUTeX space command@>;
2847 mmode+pux_space:begin
2848   print_err("This space command is ignored in math mode");
2849   help1("Did you forget putting it into an \hbox?");
2850   error;
2851   end;
2852
2853 @ @<Setup |hbox_tail| and package@>=
2854 if in_set_box then package(0)
2855 else begin
2856   if tail<>head and is_char_node(tail) then
2857     hbox_tail:=tail
2858   else
2859     hbox_tail:=null;
2860   package(0);
2861   get_x_token;
2862   if cur_cmd<>spacer then hbox_tail:=null;
2863   back_input;
2864   end
2865
2866 @ @<Lookahead and determine the type of spacer to append@>=
2867 begin
2868 if pux_xspace=0 then begin
2869   if tail<>head and is_char_node(tail) then
2870     pre_glue_char_ptr:=tail
2871   else
2872     pre_glue_char_ptr:=null;
2873   get_x_token; {lookahead}
2874   if cur_cmd=char_num then
2875     begin scan_char_num; cur_chr:=cur_val; cur_cmd:=char_given;
2876     end
2877   else if cur_cmd=pux_char_num then
2878     begin scan_wchar_num; cur_chr:=cur_val; cur_cmd:=pux_char_given;
2879     end;
2880   if cur_cmd=letter or cur_cmd=other_char or cur_cmd=char_given or
2881      cur_cmd=pux_char_given then
2882     if is_wchar(cur_chr) then begin
2883       main_cf:=cur_cfont;
2884       if pre_glue_char_ptr<>null then goto main_loop_wchar+1;
2885       if hbox_tail<>null and is_wchar_node(hbox_tail) then begin
2886         tail_append_glue(cfont_glue_spec[main_cf]);
2887         hbox_tail:=null;
2888         end
2889       else begin
2890         tail_append_glue(cfont_ceglue_spec[main_cf]);
2891         if is_punc_wchar(cur_chr) then
2892           if is_head_forbidden(cur_chr) then tail_append(new_penalty(inf_penalty));
2893         if hbox_tail<>null then hbox_tail:= null;
2894         end;
2895       goto save_cur_wchar;
2896       end
2897     else if (pre_glue_char_ptr<>null and is_wchar_node(tail))
2898          or (hbox_tail<>null and is_wchar_node(hbox_tail)) then begin
2899         tail_append_glue(cfont_ceglue_spec[cur_cfont]);
2900         hbox_tail:=null;
2901         goto main_loop;
2902         end;
2903   prev_main_cf:=cur_cfont;
2904   pre_undet_glue_ptr:=tail;
2905   if pre_glue_char_ptr<>null and is_wchar_node(pre_glue_char_ptr) then begin
2906     tail_append_glue(cfont_ceglue_spec[cur_cfont]);
2907     goto reswitch;
2908     end;
2909   end;
2910 if space_factor=1000 then goto append_normal_space
2911 else begin app_space;
2912   if pux_xspace=0 then goto reswitch else goto big_switch;
2913   end;
2914 end
2915
2916 @ @<Lookahead and determine the type of |ex_spacer| to append@>=
2917 begin
2918 if pux_xspace=0 then begin
2919   get_x_token; {lookahead}
2920   if cur_cmd=char_num then
2921     begin scan_char_num; cur_chr:=cur_val; cur_cmd:=char_given;
2922     end;
2923   if cur_cmd=pux_char_num then
2924     begin scan_wchar_num; cur_chr:=cur_val; cur_cmd:=pux_char_given;
2925     end;
2926   if cur_cmd=letter or cur_cmd=other_char or cur_cmd=char_given or cur_cmd=pux_char_given then
2927     if is_wchar(cur_chr) then begin
2928       main_cf:=cur_cfont;
2929       if tail<>head and is_char_node(tail) then
2930         if is_wchar_node(tail) then
2931           goto append_normal_space
2932         else
2933           goto main_loop_wchar+1;
2934       tail_append_glue(cfont_glue_spec[main_cf]);
2935       goto save_cur_wchar;
2936       end
2937     else if tail<>head and is_char_node(tail) then
2938       if is_wchar_node(tail) then begin
2939         tail_append_glue(cfont_ceglue_spec[cur_cfont]);
2940         goto main_loop;
2941         end;
2942   if tail<>head and is_char_node(tail) then
2943     if is_wchar_node(tail) then begin
2944       tail_append_glue(cfont_glue_spec[cur_cfont]);
2945       goto reswitch;
2946       end;
2947   prev_main_cf:=cur_cfont;
2948   pre_undet_glue_ptr:=tail;
2949   end;
2950 goto append_normal_space;
2951 end
2952
2953 @
2954 @d pux_space_code=0
2955 @d pux_exspace_code=1
2956 @d pux_cspace_code=2
2957 @d pux_cespace_code=3
2958 @<Put each of \TeX's primitives into the hash table@>=
2959 primitive("PUXspace",pux_space,pux_space_code);
2960 primitive("PUXexspace",pux_space,pux_exspace_code);
2961 primitive("PUXcspace",pux_space,pux_cspace_code);
2962 primitive("PUXcespace",pux_space,pux_cespace_code);
2963
2964 @ @<Cases of |print_cmd_chr|...@>=
2965 pux_space: case chr_code of
2966   pux_space_code: print_esc("PUXspace");
2967   pux_exspace_code: print_esc("PUXexspace");
2968   pux_cspace_code: print_esc("PUXcspace");
2969   othercases print_esc("PUXcespace")
2970   endcases;
2971
2972 @ @<Handle \PUTeX space command@>=
2973 case cur_chr of
2974   pux_space_code: begin get_x_token;
2975     if space_factor=1000 then goto append_normal_space;
2976     app_space;
2977     if pux_xspace=0 then goto reswitch else goto big_switch;
2978     end;
2979   pux_exspace_code: begin get_x_token; goto append_normal_space;
2980     end;
2981   pux_cspace_code: tail_append(new_glue(cfont_glue_spec[cur_cfont]));
2982   othercases tail_append(new_glue(cfont_ceglue_spec[cur_cfont]))
2983   endcases
2984
2985 @* \[59] CJK font face definition table.
2986
2987 @ @<Put each of \TeX's primitives into the hash table@>=
2988 primitive("PUXcfacedef",pux_cface_def,0);
2989
2990 @ @<Cases of |print_cmd_chr|...@>=
2991 pux_cface_def: print_esc("PUXcfacedef"); {TCW}
2992
2993 @ @<Assignments@>=
2994 pux_cface_def: new_cface(a);
2995
2996
2997 @ @<Constants...@>=
2998 @!cface_base=0; {CJK font face base}
2999 @!null_cface=0; {null CJK font faces}
3000
3001 @
3002 @<Types...@>=
3003 @!internal_cface_number=cface_base..max_cface;
3004
3005 @ The CJK font face definition table is implemented by parallel arrays as follows.
3006 @d regular=0
3007 @d italic=@"40 {bit 6: italic flag}
3008 @d underline=@"20 {bit 5: underline flag}
3009 @d strikeout=@"10 {bit 4: strikeout flag}
3010 @d inverse=@"08 {bit 3: inverse flag}
3011 @d rotated=@"01 {bit 0: rotation flag}
3012 @d default_cface_weight==400
3013 @d default_cface_style=regular
3014 @d default_cface_fw_width==fw_unity
3015 @d default_cface_fw_height==fw_unity
3016 @d cface_id_text(#)==text(cface_id_base+#)
3017
3018 @<Global variables@>=
3019 @!cface_ptr:internal_cface_number;
3020   {index of the first unused entry}
3021 @!cface:array[internal_cface_number] of str_number;
3022   {CJK font face identifier}
3023 @!cface_name:array[internal_cface_number] of str_number;
3024   {CJK font face name}
3025 @!cface_charset:array[internal_cface_number] of eight_bits;
3026   {CJK font charset}
3027 @!cface_weight:array[internal_cface_number] of 1..1000;
3028   {CJK font weight}
3029 @!cface_style:array[internal_cface_number] of eight_bits;
3030   {CJK font style}
3031 @!cface_fw_width:array[internal_cface_number] of fixword;
3032   {CJK font width ratio}
3033 @!cface_fw_height:array[internal_cface_number] of fixword;
3034   {CJK font heigh ratio}
3035 @!cface_fw_depth:array[internal_cface_number] of fixword; 
3036   {CJK font depth ratio}
3037 @!cface_csp_width:array[internal_cface_number] of integer;
3038   {CJK font c-space width}
3039 @!cface_csp_shrink:array[internal_cface_number] of integer;
3040   {CJK font c-space shrink}
3041 @!cface_csp_stretch:array[internal_cface_number] of integer;
3042   {CJK font c-space stretch}
3043 @!cface_cesp_width:array[internal_cface_number] of integer;
3044   {CJK font ce-space width}
3045 @!cface_cesp_shrink:array[internal_cface_number] of integer;
3046   {CJK font ce-space shrink}
3047 @!cface_cesp_stretch:array[internal_cface_number] of integer;
3048   {CJK font ce-space stretch}
3049 @!cface_fw_default_depth:fixword;
3050
3051
3052 @ @<Put each of \TeX's primitives into the hash table@>=
3053 primitive("PUXsetdefaultcface",pux_set_default_cface,int_base+pux_default_cface_code);
3054
3055 @ @<Cases of |print_cmd_chr|...@>=
3056 pux_set_default_cface: print_esc("PUXsetdefaultcface"); {TCW}
3057
3058 @ @<Assignments@>=
3059 pux_set_default_cface: begin p:=cur_chr;
3060   @<Get the next non-blank non-call token@>;
3061   if cur_cmd = pux_set_cface then
3062     word_define(p,cur_chr)
3063   else begin
3064     print_err("Here should put a CJK font face command. ");
3065     print("The dafault CJK font face remains unchanged");
3066     error;
3067   end;
3068   end;
3069
3070
3071 @ @<PUTeX routines that will be used by TeX routines@>=
3072 procedure reset_cface_cspace (face_num:integer);
3073 begin
3074   cface_csp_width[face_num]:=g_cspace_width;@/
3075   cface_csp_shrink[face_num]:=g_cspace_shrink;@/
3076   cface_csp_stretch[face_num]:=g_cspace_stretch;@/
3077 end;
3078
3079 @ @<PUTeX routines that will be used by TeX routines@>=
3080 procedure reset_cface_cespace (face_num:integer);
3081 begin
3082   cface_cesp_width[face_num]:=g_cespace_width;@/
3083   cface_cesp_shrink[face_num]:=g_cespace_shrink;@/
3084   cface_cesp_stretch[face_num]:=g_cespace_stretch;@/
3085 end;
3086
3087 @ Setup default and null CJK font faces.
3088 @<Initialize table...@>=
3089 cur_cface:=null_cface; eq_type(cur_cface_loc):=data;
3090 eq_level(cur_cface_loc):=level_one;@/
3091 cface_fw_default_depth:=convfix(puxg_cface_depth);
3092 cface_ptr:=cface_base+1;
3093
3094 cface[null_cface]:="nullcface";@/
3095 cface_name[null_cface]:="nullcjkface";@/
3096 cface_charset[null_cface]:=0;@/
3097 cface_weight[null_cface]:=400; {normal weight}@/
3098 cface_style[null_cface]:=0;@/
3099 cface_fw_width[null_cface]:=0;@/
3100 cface_fw_height[null_cface]:=0;@/
3101 cface_fw_depth[null_cface]:=0;@/
3102 reset_cface_cspace(null_cface);@/
3103 reset_cface_cespace(null_cface);@/
3104
3105 @ The function |find_cface_num| searches the CJK font face definition table
3106 for the entry with the same identifier as |id|. The entry index is return if found;
3107 otherwise, the current value of |cface_ptr| is return.
3108
3109 @d cface_found(#)==((#)<cface_ptr)
3110
3111 @<Declare the function called |find_cface_num|@>=
3112 function find_cface_num(id:str_number):internal_cface_number;
3113   label done;
3114   var f:internal_cface_number; {runs through existing faces}
3115   begin
3116   f:=cface_base;
3117   while (f < cface_ptr) do
3118     begin
3119     if str_eq_str(id, cface[f]) then goto done;
3120     incr(f);
3121     end;
3122  done:find_cface_num:=f;
3123   end;
3124
3125 @ @<Declare subprocedures for |prefixed_command|@>=
3126 @<Declare the function called |print_fixword|@>@;
3127 procedure new_cface(@!a:small_number);
3128 label done, done1, common_ending;
3129 var u:pointer; {user's chinese face identifier}
3130 @!t:str_number; {name for the frozen font identifier}
3131 @!id:str_number; {CJK font face identifier}
3132 @!face_name:str_number; {CJK font face name}
3133 @!charset:integer; {CJK font charset}
3134 @!weight:integer; {CJK font weight}
3135 @!style:integer; {CJK font style}
3136 @!w:integer; {CJK font width ratio}
3137 @!h:integer; {CJK font height ratio}
3138 @!d:integer; {CJK font depth ratio}
3139 @!fix_w:fixword; {CJK font width ratio}
3140 @!fix_h:fixword; {CJK font height ratio}
3141 @!fix_d:fixword; {CJK font depth ratio}
3142 @!f:internal_cface_number; {runs through existing faces}
3143 @!k:integer;@/
3144 @<Other variables used by |new_cface|@>@;
3145 begin if job_name=0 then open_log_file;
3146   {avoid confusing \.{texput} with the font name}
3147 get_r_token; u:=cur_cs;
3148 if u>=hash_base then t:=text(u)
3149 else if u>=single_base then
3150   if u=null_cs then t:="CFACE"@+else t:=u-single_base
3151 else  begin old_setting:=selector; selector:=new_string;
3152   print("CFACE"); print(u-active_base); selector:=old_setting;
3153   str_room(1); t:=make_string;
3154   end;
3155 define(u,pux_set_cface,null_cface);
3156 scan_optional_equals;
3157 @<Setup variables before scanning CJK font face parameters@>;
3158 @<Scan CJK font face identifier@>;
3159 @<Scan CJK font face name@>;
3160 @<Scan optional CJK font face definition parameters@>;
3161 @<If the face name is missing, then ignore this face deinition@>;
3162 @<If this Chinese face has already been loaded, then |goto common_ending|@>;
3163 @<Setup this new Chinese face@>;
3164 common_ending: equiv(u):=f; eqtb[cface_id_base+f]:=eqtb[u]; cface_id_text(f):=t;
3165 end;
3166
3167 @ @<Setup variables before scanning CJK font face parameters@>=
3168 charset:=pux_charset; {set to the base charset of document}
3169 w:=1000; h:=1000; d:=puxg_cface_depth; @/
3170 weight:=400; {normal weight}@/
3171 style:=0; {regular style}
3172 if puxg_rotate_ctext<>0 then style:=style+rotated;
3173 f:=null_cface
3174
3175
3176 @ @<Scan CJK font face identifier@>=
3177 id:=scan_name;
3178 if id > 0 then
3179   begin
3180   f:=find_cface_num(id);
3181   if (f < cface_ptr) then
3182     begin
3183     flush_string; id:=cface[f]; {for saving string pool sapce}
3184     f:=null_cface;
3185     print_err("The Chinese face id ("); print(id);
3186     print(") is already used"); error;
3187     end;
3188   end
3189 else
3190   begin
3191   print_err("Missing CJK font face identifier"); error;
3192   end
3193
3194 @ @<Scan CJK font face name@>=
3195 begin
3196 face_name:=scan_name;
3197 if face_name > 0 then
3198   begin
3199   k:=cface_base;
3200   while (k < cface_ptr) do
3201     begin
3202     if str_eq_str(face_name, cface_name[k]) then
3203       begin
3204       flush_string;
3205       face_name:=cface_name[k]; f:=k;
3206       goto done1;
3207       end;
3208     incr(k);
3209     end;
3210   end
3211 else
3212   begin
3213   print_err("Missing CJK font face name"); error;
3214   face_name:=cface_name[null_cface];
3215   f:=null_cface;
3216   end;
3217 done1: end
3218
3219 @ @<Other variables used by |new_cface|@>=
3220 @!i_flag:boolean; {italic flag}
3221 @!u_flag:boolean; {underline flag}
3222 @!s_flag:boolean; {strikeout flag}
3223 @!r_flag:boolean; {rotation flag}
3224 @!v_flag:boolean; {inverse flag}
3225 @!more_param:boolean; {have more parameters to come}
3226
3227 @ @<Scan optional CJK font face definition parameters@>=
3228 i_flag:=false; u_flag:=false; s_flag:=false;@/
3229 r_flag:=false; v_flag:=false;@/
3230 more_param:=true;
3231 while more_param do
3232   begin
3233   @<Get the next non-blank non-call token@>;
3234   if cur_cmd=letter then
3235     case cur_chr of
3236       'c','C': @<Scan the CJK font charset@>;
3237       'w','W': @<Scan the CJK font width@>;
3238       'h','H': @<Scan the CJK font height@>;
3239       'd','D': @<Scan the CJK font depth@>;
3240       't','T': @<Scan the CJK font weight@>;
3241       's','S': @<Scan the CJK font style@>;
3242       othercases more_param:=false;
3243     endcases
3244   else more_param:=false;
3245   end;
3246 back_input
3247
3248
3249 @
3250 @<Scan the CJK font charset@>=
3251 begin scan_optional_equals;@/
3252 scan_int; 
3253 if (cur_val<0)or(cur_val>255) then
3254   begin print_err("Improper `charset' value (");
3255   print_int(charset); print("), replaced by default charset");
3256   help2("I can only handle nonnegative charset value up to 255,")@/
3257   ("so I've changed what you said to default charset.");
3258   error;
3259   end
3260 else
3261   charset:=cur_val;
3262 end
3263
3264 @
3265 @<Scan the CJK font width@>=
3266 begin scan_optional_equals;@/
3267 scan_int; w:=cur_val;
3268 if (w<=0)or(w>1000) then
3269   begin print_err("Improper `width' value (");
3270   print_int(w); print("), replaced by 1000");
3271   help2("I can only handle fonts at positive width ratio that are less")@/
3272   ("than or equal to 1000, so I've changed what you said to 1000.");
3273   error; w:=1000;
3274   end;
3275 end
3276
3277 @ @<Scan the CJK font height@>=
3278 begin scan_optional_equals;@/
3279 scan_int; h:=cur_val;
3280 if (h<=0)or(h>1000) then
3281   begin print_err("Improper `height value (");
3282   print_int(h); print("), replaced by 1000");
3283   help2("I can only handle fonts at positive height ratio that are less")@/
3284   ("than or equal to 1000, so I've changed what you said to 1000.");
3285   error; h:=1000;
3286   end;
3287 end
3288
3289 @ @<Scan the CJK font depth@>=
3290 begin scan_optional_equals;@/
3291 scan_int; d:=cur_val;
3292 if (d<0)or(d>1000) then
3293   begin print_err("Improper `depth' value (");
3294   print_int(d); print("), replaced by 0.2");
3295   help3("I can only handle fonts at nonegative depth ratio that are less")@/
3296   ("than or equal to 1000, so I've changed what you said to")@/
3297   ("the current \puxgCfaceDepth value.");
3298   error; d:=puxg_cface_depth;
3299   end;
3300 end
3301
3302 @ @<Scan the CJK font weight@>=
3303 begin scan_optional_equals;@/
3304 scan_int; weight:=cur_val;
3305 if (weight < 0) or (weight > 1000) then
3306   begin print_err("Illegal CJK font weight has been changed to 400");@/
3307   help1("The font weight must be between 1 and 1000.");
3308   int_error(cur_val); weight:=400; {normal weight}
3309   end;
3310 end
3311
3312 @
3313 @<Scan the CJK font style@>=
3314 begin scan_optional_equals;@/
3315 @<Get the next non-blank non-call token@>;
3316 if cur_cmd=letter then
3317   case cur_chr of
3318   "i", "I": if not i_flag then begin style:=style+italic; i_flag:=true; end;
3319   "u", "U": if not u_flag then begin style:=style+underline; u_flag:=true; end;
3320   "s", "S": if not s_flag then begin style:=style+strikeout; s_flag:=true; end;
3321   "r", "R": if not r_flag then @<Set CJK font rotation style@>;
3322   "v", "V": if not v_flag then begin style:=style+inverse; v_flag:=true; end;
3323   othercases@/
3324     begin print_err("Illegal CJK font style setting has been ignored");@/
3325     print(" ("); print(cur_chr); print(")"); back_error;
3326       {fix the case when cur\_chr is a double-byte char}
3327     help2("The CJK font style setting should use characters:")@/
3328     ("i:italic, u:underline, s:strikeout, r:rotated, v:reversed");
3329     end;
3330   endcases;@/
3331 end
3332
3333 @ @<Set CJK font rotation style@>=
3334 begin
3335 if puxg_rotate_ctext<>0 then
3336   style:=style-rotated
3337 else
3338   style:=style+rotated;
3339 r_flag:=true;
3340 end
3341
3342 @ @<If the face name is missing, then ignore this face deinition@>=
3343 if f=null_cface then
3344   goto common_ending
3345
3346
3347 @ @<If this Chinese face has...@>=
3348 fix_w:=convfix(w);
3349 fix_h:=convfix(h);
3350 fix_d:=convfix(d);
3351 if f <> null_cface then
3352   if weight=cface_weight[f] and style=cface_style[f] then
3353     if fix_w=cface_fw_width[f] and fix_h=cface_fw_height[f] and fix_d=cface_fw_depth[f] then@/
3354       goto common_ending
3355
3356 @
3357 @<Setup this new Chinese face@>=
3358 if cface_ptr <= max_cface then
3359   begin
3360   f:=cface_ptr;
3361   cface[f]:=id;
3362   cface_name[f]:=face_name;@/
3363   cface_charset[f]:=charset;@/
3364   cface_weight[f]:=weight;@/
3365   cface_style[f]:=style;@/
3366   if style mod 2 = 1 then begin
3367     cface_fw_width[f]:=fix_w; cface_fw_height[f]:=fix_h;
3368     end
3369   else begin
3370     cface_fw_width[f]:=fix_h; cface_fw_height[f]:=fix_w;
3371     end;
3372   cface_fw_depth[f]:=fix_d;@/
3373   reset_cface_cspace(f);@/
3374   reset_cface_cespace(f);@/
3375   incr(cface_ptr);
3376   end
3377 else begin
3378   f:=null_cface;
3379   print_err("CJK font Face definition table overflow"); error;
3380   end
3381   
3382 @* \[59] CJK font definition table.
3383
3384 @ @<Constants...@>=
3385 @!cfont_base=font_max_limit+1; {CJK font base}
3386 @!cfont_max=font_max_limit+1+cfont_max_limit; {maximum internal chinese font number}
3387
3388 @
3389 @<Types...@>=
3390 @!internal_cfont_number=cfont_base..cfont_max;
3391
3392 @ @<Initialize table entries...@>=
3393 cur_cfont:=default_cfont; eq_type(cur_cfont_loc):=data;
3394 eq_level(cur_cfont_loc):=level_one;@/
3395
3396 @ @<Global variables@>=
3397 @!cfont_ptr:internal_cfont_number;
3398 @!cfont_face:array[internal_cfont_number] of internal_cface_number;
3399   {CJK font face name}
3400 @!cfont_dsize:array[internal_cfont_number] of scaled;
3401   {CJK font design size}
3402 @!cfont_size:array[internal_cfont_number] of scaled;
3403   {CJK font size}
3404 @!cfont_width:array[internal_cfont_number] of scaled;
3405   {CJK font width}
3406 @!cfont_height:array[internal_cfont_number] of scaled;
3407   {CJK font heigh}
3408 @!cfont_depth:array[internal_cfont_number] of scaled;
3409   {CJK font depth}
3410 @!cfont_glue_spec:array[internal_cfont_number] of pointer;
3411   {CJK font inter-character space}
3412 @!cfont_ceglue_spec:array[internal_cfont_number] of pointer;
3413   {CJK font inter-character space}
3414 @!cfont_used:array[internal_cfont_number] of boolean;
3415   {has a character from this chinese font actually appeared in the output?}
3416
3417
3418 @ @<Set init...@>=
3419 for k:=cfont_base to cfont_max do cfont_used[k]:=false;
3420 cfont_face[null_cfont]:=null_cface;
3421 cfont_dsize[null_cfont]:=0;
3422 cfont_size[null_cfont]:=0;
3423 cfont_width[null_cfont]:=0;
3424 cfont_height[null_cfont]:=0;
3425 cfont_depth[null_cfont]:=0;
3426
3427 @ @<Initialize table entries...@>=
3428 cfont_ptr:=default_cfont;
3429
3430 @ @<Declare PUTeX subprocedures for |prefixed_command|@>=
3431 procedure set_cglue_spec(n:integer);
3432 var cface_num:integer;
3433 begin
3434   cface_num:=cfont_face[n];
3435   width(cfont_glue_spec[n]):=xn_over_d(cfont_size[n], cface_csp_width[cface_num], 1000);
3436   shrink(cfont_glue_spec[n]):=xn_over_d(cfont_size[n], cface_csp_shrink[cface_num], 1000);
3437   stretch(cfont_glue_spec[n]):=xn_over_d(cfont_size[n], cface_csp_stretch[cface_num], 1000);
3438 end;
3439
3440 @ @<Declare PUTeX subprocedures for |prefixed_command|@>=
3441 procedure set_ceglue_spec(n:integer);
3442 var cface_num:integer;
3443 begin
3444   cface_num:=cfont_face[n];
3445   width(cfont_ceglue_spec[n]):=xn_over_d(cfont_size[n], cface_cesp_width[cface_num], 1000);
3446   shrink(cfont_ceglue_spec[n]):=xn_over_d(cfont_size[n], cface_cesp_shrink[cface_num], 1000);
3447   stretch(cfont_ceglue_spec[n]):=xn_over_d(cfont_size[n], cface_cesp_stretch[cface_num], 1000);
3448 end;
3449
3450
3451 @ @<Initialization of global variables done in the |main_control| procedure@>=
3452 cfont_glue_spec[null_cfont]:=new_spec(zero_glue);
3453 cfont_ceglue_spec[null_cfont]:=new_spec(zero_glue);
3454
3455 @ @<Other local variables used by procedure |new_font|@>=
3456 @!face_id:str_number; {Chinese face name fetched from |\\font| command}
3457 @!jj:internal_cface_number;
3458 @!cface_num:internal_cface_number;
3459 @!ds:integer;
3460 @!dsize:scaled;
3461 @!size:scaled;
3462
3463 @
3464 @<Define a CJK font and then goto |common_ending|@>=
3465 begin
3466 define(u, set_cfont, null_cfont);
3467 cface_num:=pux_default_cface;@/
3468 @<Fetch the Chinese face name@>;
3469 @<Fetch the font design size and compute font 'at' size@>;
3470 @<If this CJK font has already been loaded, set |f| to the internal
3471   CJK font number and |goto| common\_ending@>;
3472 f:=make_cfont(cface_num,dsize,size);@/
3473 goto common_ending;
3474 end;
3475
3476 @
3477 @d is_letter(#)==((#>='A' and #<='Z') or (#>='a' and #<='z'))
3478 @<Fetch the Chinese face name@>=
3479 jj:=j;
3480 j:=j+5; {skip the prefix 'CFONT'}
3481 while is_letter(str_pool[j]) do {fixme for wchar}
3482   begin
3483   append_char(str_pool[j]);
3484   incr(j);
3485   end;
3486 if pool_ptr <> str_start[str_ptr] then
3487   begin
3488   face_id:=make_string;@/
3489   cface_num:=find_cface_num(face_id);
3490   flush_string;
3491   end
3492 else
3493   begin
3494   print_err("Missing Chinese face identifier"); error;
3495   end;
3496
3497 @
3498 @d is_digit(#)==(# >= '0' and # <= '9')
3499 @<Fetch the font design size and compute font 'at' size@>=
3500 ds:=0;
3501 while is_digit(str_pool[j]) do
3502   begin
3503   ds:= ds*10+(str_pool[j]-'0');
3504   incr(j);
3505   end;
3506 if ds=0 then
3507   begin
3508   print_err("Missing CJK font size specification, replaced by 10pt");
3509   ds:=10; {set to default size: 10pt}
3510   error;
3511   end;
3512 dsize:=mult_integers(ds,unity);
3513 if s=-1000 then
3514   size:=dsize
3515 else
3516   if s>=0 then size:=s
3517   else size:=xn_over_d(dsize, -s, 1000);
3518
3519 @
3520 @d defined_cfont(#)==(#)<cfont_ptr
3521 @d undefined_cfont(#)==(#)=cfont_ptr
3522
3523 @<Declare the procedure called |check_cfont|@>=
3524 function check_cfont(@!cface_num:internal_cface_number;@!size:scaled):internal_cfont_number;
3525 label done;
3526 var f:internal_cfont_number;
3527 begin
3528 f:=cfont_base+1;
3529 while (f<cfont_ptr) do
3530   begin
3531   if cface_num=cfont_face[f] and size=cfont_size[f] then goto done;
3532   incr(f);
3533   end;
3534 done:check_cfont:=f;
3535 end;
3536
3537 @ @<If this CJK font has already been...@>=
3538 f:=check_cfont(cface_num,size);
3539 if defined_cfont(f) then goto common_ending;
3540
3541
3542 @
3543 @<Declare the procedure called |make_cfont|@>=
3544 function make_cfont(cfn:internal_cface_number; dsize, size:scaled):internal_cfont_number;
3545 begin
3546 if cfont_ptr <= cfont_max then
3547   begin
3548   cfont_face[cfont_ptr]:=cfn;@/
3549   cfont_dsize[cfont_ptr]:=dsize;@/
3550   cfont_size[cfont_ptr]:=size;@/
3551   cfont_width[cfont_ptr]:=fw_times_sd(cface_fw_width[cfn], size);@/
3552   cfont_height[cfont_ptr]:=fw_times_sd(cface_fw_height[cfn], size);@/
3553   cfont_depth[cfont_ptr]:=fw_times_sd(cface_fw_depth[cfn], size);@/
3554   cfont_glue_spec[cfont_ptr]:=new_spec(zero_glue);
3555   set_cglue_spec(cfont_ptr);
3556   cfont_ceglue_spec[cfont_ptr]:=new_spec(zero_glue);
3557   set_ceglue_spec(cfont_ptr);
3558   make_cfont:=cfont_ptr;@/
3559   incr(cfont_ptr);
3560   end
3561 else
3562   begin
3563   print_err("CJK font table overflow"); error;
3564   end
3565 end;
3566
3567
3568 @ @<Cases of |print_cmd_chr|...@>=
3569 set_cfont:begin print("select CJK font "); slow_print(cface[cfont_face[chr_code]]);
3570   print(" at ("); print_scaled(cfont_size[chr_code]); print("pt"); print(")");
3571   end;
3572
3573 @* \[57] Matching faces.
3574 @d min_ectbl=0
3575 @d max_ectbl=255
3576
3577 @ @<Types...@>=
3578 @!internal_ectbl_number=min_ectbl..max_ectbl;
3579
3580
3581 @ @<Global variables@>=
3582 @!ectbl_eface_name:array[internal_ectbl_number] of str_number;
3583   {the table of English face names }
3584 @!ectbl_ptr:internal_ectbl_number;
3585   {index to the first unused entry}
3586
3587 @ |ectbl_cface_num| table entries are already initialized in section 232.
3588
3589 @<Initialize table entries...@>=
3590 ectbl_ptr:=min_ectbl;
3591 equiv(ectbl_cface_num_base):=null_cface;
3592 eq_type(ectbl_cface_num_base):=data;
3593 eq_level(ectbl_cface_num_base):=level_one;
3594 for k:=ectbl_cface_num_base+1 to font_matching_table_base-1 do
3595   eqtb[k]:=eqtb[ectbl_cface_num_base];
3596
3597
3598 @ @<Put each of \TeX's primitives into the hash table@>=
3599 primitive("PUXfacematch",pux_face_match,0);
3600
3601 @ @<Cases of |print_cmd_chr|...@>=
3602 pux_face_match: print_esc("PUXfacematch");
3603
3604 @ @<Assignments@>=
3605 pux_face_match: match_ec_face(a);
3606
3607
3608 @ The function |find_ec_num| lookup the |ectbl_eface_name| table
3609 for the name |eface_name|. It returns the index to the name if the name
3610 exits; otherwose, it returns the current value of |ectbl_ptr|.
3611
3612 @d ectbl_found(#)==((#)<ectbl_ptr)
3613
3614 @<Declare the function called |find_ec_num|@>=
3615 function find_ec_num(eface_name:str_number):internal_ectbl_number;
3616   label done;
3617   var k:integer;@/
3618   begin
3619   k:=min_ectbl;
3620   while k < ectbl_ptr do
3621     begin
3622     if str_eq_str(eface_name,ectbl_eface_name[k]) then goto done;
3623     incr(k);
3624     end;
3625 done: find_ec_num:=k;
3626   end;
3627
3628 @
3629 @<Declare subprocedures for |prefixed_command|@>=
3630 procedure make_cfont_id (f:internal_cfont_number; a:small_number);
3631 var
3632 @!i:0..23;
3633 @!m:integer;
3634 @!u: pointer;
3635 @!t:str_number;
3636 @!n:integer;
3637 begin
3638 buffer[buf_size+1]:='C';
3639 buffer[buf_size+2]:='F';
3640 buffer[buf_size+3]:='O';
3641 buffer[buf_size+4]:='N';
3642 buffer[buf_size+5]:='T';
3643 m:=buf_size+6;
3644 n:=f; i:=0;
3645 repeat dig[i]:=n mod 10; n:=n div 10; incr(i);
3646 until n=0;
3647 while i>0 do {append design size}
3648   begin decr(i);
3649   buffer[m]:="0"+dig[i];
3650   incr(m);
3651   end;
3652 no_new_control_sequence:=false;
3653 u:=id_lookup(buf_size+1,m-buf_size-1);
3654 no_new_control_sequence:=true;
3655 t:=text(u);
3656 define(u,set_cfont,f); eqtb[font_id_base+f]:=eqtb[u]; font_id_text(f):=t;
3657 end;
3658
3659 @ @<Declare PUTeX subprocedures for |prefixed_command|@>=
3660 function fetch_efont_face (@!efont_name:str_number):str_number;
3661 var k:integer;@/
3662 @!p:pool_pointer;
3663 @!s: str_number;
3664 begin
3665   p:=str_start[efont_name+1]-1; {last char position of efont\_name}@/
3666   while is_digit(str_pool[p]) do decr(p); {assumed that the TeX font name has letters}
3667   k:=str_start[efont_name];
3668   while k <= p do
3669     begin
3670     append_char(str_pool[k]);
3671     incr(k);
3672     end;
3673   s:=make_string;
3674   fetch_efont_face:=s;
3675 end;
3676
3677
3678 @
3679 @<Declare subprocedures for |prefixed_command|@>=
3680 @<Declare the function called |find_ec_num|@>@;
3681 procedure match_ec_face(@!a:small_number);
3682 label done1, done2, exit;
3683 var k, f:integer;
3684 @!eface_name, @!efname, @!efont_name, @!cface_id:str_number;
3685 @!cfont_num:internal_cfont_number;
3686 @!cface_num:internal_cface_number;
3687 @!err:boolean;
3688   begin
3689   err:=false; f:=ectbl_ptr;@/
3690   eface_name:=scan_name;
3691   if cur_cmd=pux_set_cface then
3692     eface_name:=fetch_efont_face(font_name[cur_font]) {should be flushed later}
3693   else if eface_name=0 then begin
3694       print_err("Missing a TeX face name");
3695       error; goto exit;
3696       end;
3697   f:=find_ec_num(eface_name);
3698   if ectbl_found(f) then begin {it is already in the |ectbl_eface_name| table}
3699     flush_string;
3700     eface_name:=ectbl_eface_name[f]
3701     end;
3702   if cur_cmd=pux_set_cface then begin {the second form: match face of current efont}
3703       cface_num:=cur_chr;
3704       @<Define the |cur_cfont| according to |cur_font| and |cface_num|@>;
3705       end
3706   else
3707     @<Fetch a Chinese face id@>;
3708   @<Add this face matching@>;
3709 exit: end;
3710
3711 @ @<Define the |cur_cfont| according to |cur_font| and |cface_num|@>=
3712 cfont_num:=check_cfont(cface_num, font_size[cur_font]);
3713 if undefined_cfont(cfont_num) then begin
3714   cfont_num:=make_cfont(cface_num,font_dsize[cur_font],font_size[cur_font]);
3715   make_cfont_id(cfont_num,a);
3716   end;
3717 define(cur_cfont_loc,data,cfont_num)
3718
3719
3720
3721 @ @<Fetch a Chinese face id@>=
3722 begin
3723 @<Get the next non-blank non-call token@>;
3724 if cur_cmd=pux_set_cface then
3725   cface_num:=cur_chr
3726 else begin
3727   print_err("Missing a CJK font face identifier");
3728   err:=true; error;
3729   cface_num:=pux_default_cface;
3730   end
3731 end
3732
3733 @ @<Add this face matching@>=
3734 if f > max_ectbl then begin
3735   print_err("Font face matching table overflow");
3736   err:=true;
3737   error;
3738   end;
3739 if not err then begin
3740   define(ectbl_cface_num_base+f,data,cface_num);
3741   if f = ectbl_ptr then begin {add this new eface name the the |eface_name table|}
3742     ectbl_eface_name[f]:=eface_name;
3743     incr(ectbl_ptr);
3744     end;
3745   end
3746
3747 @ @<Declare subprocedures for |prefixed_command|@>=
3748 function lookup_cface (@!efont_name: str_number) : internal_cface_number;
3749 var k:integer;@/
3750 @!cface_num:internal_cface_number;@/
3751 @!eface_name:str_number;@/
3752 begin
3753   eface_name:=fetch_efont_face(efont_name);
3754   k:=find_ec_num(eface_name);
3755   flush_string;
3756   if ectbl_found(k) then
3757     cface_num:=ectbl_cface_num(k)
3758   else cface_num:=pux_default_cface;
3759   lookup_cface:=cface_num;
3760 end;
3761
3762
3763 @* \[60] Font matching.
3764
3765 @ @<Initialize table entries...@>=
3766 equiv(font_matching_table_base):=null_cfont;
3767 eq_type(font_matching_table_base):=data;
3768 eq_level(font_matching_table_base):=level_one;
3769 for k:=font_matching_table_base+1 to math_font_base-1 do
3770   eqtb[k]:=eqtb[font_matching_table_base];
3771
3772 @ @<Put each of \TeX's primitives into the hash table@>=
3773 primitive("PUXfontmatch",pux_font_match,0);
3774
3775
3776 @ @<Assignments@>=
3777 pux_font_match: match_ec_font(a);
3778
3779 @ @<Declare subprocedures for |prefixed_command|@>=
3780 procedure match_ec_font(@!a:small_number);
3781 label done;
3782 var efont_num:internal_font_number;
3783 @!cfont_num:internal_cfont_number;
3784 @!cface_num:internal_cface_number;
3785 begin
3786   @<Get the next non-blank non-call token@>;
3787   if cur_cmd = pux_set_cface then {the first form}
3788     begin
3789     efont_num:=cur_font;
3790     cface_num:=cur_chr;
3791     @<Define the |cur_cfont| according to |cur_font| and |cface_num|@>;
3792     goto done;
3793     end;
3794   if cur_cmd = set_font then {the second form}
3795     efont_num:=cur_chr
3796   else begin
3797     print_err("Missing Tex font identifier");
3798     help2("I was looking for a control sequence whose")@/
3799     ("current meaning has been defined by \font.");
3800     back_error; efont_num:=null_font;
3801     end;
3802   @<Get the next non-blank non-call token@>;
3803   if cur_cmd = set_cfont then cfont_num:=cur_chr
3804   else begin
3805     print_err("Missing CJK font identifier");
3806     help2("I was looking for a control sequence whose")@/
3807     ("current meaning has been defined by \cfont.");
3808     back_error; cfont_num:=null_cfont;
3809     end;
3810 done:
3811   if efont_num<>null_font and cfont_num<>null_cfont then
3812     define(font_matching_table_base+efont_num-font_base,data,cfont_num);
3813 end;
3814
3815 @ @<Other variables used by the procedure |prefixed_command|@>=
3816 @!cface_num:internal_cface_number;
3817 @!cfont_num:internal_cfont_number;
3818
3819 @ @<Set the matching CJK font@>=
3820 cfont_num:=font_matching_table(cur_chr);
3821 if cfont_num=null_cfont then begin {efont not mapped}
3822   if cur_cface=null_cface then
3823     cface_num:=lookup_cface(font_name[cur_chr])
3824   else cface_num:=cur_cface;
3825   @<Build a CJK font according to |cur_chr| and |cface_num| if it is not exist@>;
3826   end
3827 else
3828   if cur_cface<>null_cface and cfont_face[cfont_num]<>cur_cface then begin
3829     cface_num:=cur_cface;
3830     @<Build a CJK font according to |cur_chr| and |cface_num| if it is not exist@>;
3831     end;
3832 define(cur_cfont_loc,data,cfont_num)
3833
3834 @ @<Build a CJK font according to |cur_chr| and |cface_num| if it is not exist@>=
3835 cfont_num:=check_cfont(cface_num, font_size[cur_chr]);
3836 if undefined_cfont(cfont_num) then begin
3837   cfont_num:=make_cfont(cface_num,font_dsize[cur_chr],font_size[cur_chr]);
3838   make_cfont_id(cfont_num,a);
3839   end
3840
3841 @ @<Assignments@>=
3842 set_cfont: define(cur_cfont_loc,data,cur_chr);
3843
3844 @ @<Other variables used by the procedure |prefixed_command|@>=
3845 cface_id:str_number;
3846
3847 @ @<Assignments@>=
3848 pux_set_cface: begin
3849   cface_num:=cur_chr;
3850   if cface_num <> cfont_face[cur_cfont] then begin
3851     @<Define the |cur_cfont| according to |cur_font| and |cface_num|@>;
3852     end;
3853   define(cur_cface_loc,data,cface_num);
3854   end;
3855
3856 @ @<Put each of \TeX's primitives into the hash table@>=
3857 primitive("puxgRotateCtext",puxg_assign_flag,int_base+puxg_rotate_ctext_code);
3858 primitive("puxXspace",puxg_assign_int,int_base+pux_xspace_code);
3859 primitive("puxCJKcharOther",puxg_assign_int,int_base+pux_wcharother_code);
3860 primitive("puxCJKinput",puxg_assign_int,int_base+pux_CJKinput_code);
3861 primitive("puxCharSet",puxg_assign_int,int_base+pux_charset_code);
3862 primitive("puxgCfaceDepth",puxg_assign_int,int_base+puxg_cface_depth_code);
3863
3864
3865 @ @<Cases of |print_cmd_chr|...@>=
3866 puxg_assign_flag:
3867   if chr_code=puxg_rotate_ctext_code+int_base then
3868     print_esc("puxgRotateCtext");
3869 puxg_assign_int:
3870   if chr_code=pux_xspace_code+int_base then
3871     print_esc("puxXspace")
3872   else if chr_code=pux_wcharother_code+int_base then
3873     print_esc("puxCJKcharOther")
3874   else if chr_code=pux_CJKinput_code+int_base then
3875     print_esc("puxCJKinput")
3876   else if chr_code=pux_charset_code+int_base then
3877     print_esc("puxCharSet")
3878   else if chr_code=puxg_cface_depth_code+int_base then
3879     print_esc("puxgCfaceDepth");
3880
3881 @ @<Assignments@>=
3882 puxg_assign_flag: begin p:=cur_chr; scan_optional_equals; scan_int;
3883   if cur_val=0 and eqtb[p].int<>0 then begin
3884     print_err("Reset a PUTeX global parameter is not allowed here");
3885     help2("If a PUTeX global parameter was set to be a nonzero value,")@/
3886          ("it can't be reset to be zero again");
3887     error;
3888     end
3889   else begin
3890     if p=puxg_rotate_ctext_code+int_base then
3891       @<Handle the command |puxgRotateCtext|@>;
3892     word_define(p,cur_val);
3893     end;
3894   end;
3895
3896 @ @<Handle the command |puxgRotateCtext|@>=
3897 if puxg_rotate_ctext=0 and cur_val<>0 then begin
3898   n:=cface_base;
3899   while n < cface_ptr do begin
3900     if cface_style[n] mod 2 = 1 then
3901       cface_style[n]:=cface_style[n]-rotated
3902     else
3903       cface_style[n]:=cface_style[n]+rotated;
3904     incr(n);
3905     end;
3906   end
3907
3908 @ @<Assignments@>=
3909 puxg_assign_int: begin p:=cur_chr; q:=p-int_base;
3910   scan_optional_equals; scan_int;
3911   if cur_val < 0 then begin
3912     print_err("Negative "); print_param(p-int_base);
3913     print(" value ("); print_int(cur_val); print("), it remains unchanged");
3914     help1("This PUTeX parameter can't be negative.");
3915     error;
3916     end
3917   else if q=pux_charset_code and cur_val > 255 then begin
3918     print_err("Too large "); print_param(q);
3919     print(" value ("); print_int(cur_val); print("), it remains unchanged");
3920     help1("The value of document charset should be in the range 0..255.");
3921     error;
3922     end
3923   else begin
3924     case q of
3925     pux_xspace_code,pux_wcharother_code,pux_CJKinput_code,pux_charset_code:word_define(p, cur_val);
3926     puxg_cface_depth_code: if cur_val<>eqtb[p].int then
3927             @<Set PUTeX global parameter |puxgCfaceDepth|@>;
3928     othercases begin
3929       print_err("Unknow integer parameter!");
3930       error;
3931       end;
3932     endcases
3933     end;
3934   end;
3935
3936 @ @<Set PUTeX global parameter |puxgCfaceDepth|@>=
3937 begin
3938   if cur_val>1000 then begin
3939     print_err("Improper `depth' value (");
3940     print_int(cur_val); print("). It is ignored");
3941     error;
3942     end
3943   else begin
3944     word_define(p,cur_val);
3945     cface_fw_default_depth:=convfix(puxg_cface_depth);
3946     n:=cface_base;
3947     while n<cface_ptr do begin
3948       cface_fw_depth[n]:=cface_fw_default_depth;
3949       incr(n);
3950       end;
3951     n:=cfont_base+1;
3952     while n<cfont_ptr do begin
3953       cfont_depth[n]:=fw_times_sd(cface_fw_depth[cfont_face[n]], cfont_size[n]);
3954       incr(n);
3955       end;
3956     end;
3957 end
3958
3959 @
3960 @d pux_set_cface_csp=0
3961 @d pux_set_cface_cesp=1
3962 @d pux_set_cface_depth=2
3963 @<Put each of \TeX's primitives into the hash table@>=
3964 primitive("PUXcfacecspace",pux_set_cface_attrib,pux_set_cface_csp);
3965 primitive("PUXcfacecespace",pux_set_cface_attrib,pux_set_cface_cesp);
3966 primitive("PUXcfacedepth",pux_set_cface_attrib,pux_set_cface_depth);
3967
3968 @ @<Cases of |print_cmd_chr|...@>=
3969 pux_set_cface_attrib: begin
3970   case chr_code of
3971   pux_set_cface_csp:print_esc("PUXcfacecspace");
3972   pux_set_cface_cesp:print_esc("PUXcfacecespace");
3973   pux_set_cface_depth:print_esc("PUXcfacedepth");
3974   endcases;
3975   end;
3976
3977 @ @<Assignments@>=
3978 pux_set_cface_attrib: begin p:=cur_chr;
3979   @<Get the next non-blank non-call token@>;
3980   if cur_cmd=pux_set_cface then
3981     cface_num:=cur_chr
3982   else begin
3983     cface_num:=null_cface;
3984     print_err("Missing a CJK font face identifier");
3985     error;
3986     end;
3987   scan_optional_equals;
3988   if p=pux_set_cface_csp or p=pux_set_cface_cesp then
3989     @<Scan spacing dimension of CJK font face@>
3990   else
3991     scan_int;
3992
3993   if cface_num<>null_cface then begin
3994     if p=pux_set_cface_csp then
3995       @<Modify the cspace factor of the specified chinese face@>
3996     else if p=pux_set_cface_cesp then
3997       @<Modify the cespace factor of the specified chinese face@>
3998     else if p=pux_set_cface_depth then
3999       @<Modify the depth factor of the specified chinese face@>;
4000     end;
4001   end;
4002
4003 @ @<Other variables used by the procedure |prefixed_command|@>=
4004 @!width_value:integer; {width of space}
4005 @!stretch_value:integer; {stretch of space}
4006 @!shrink_value:integer; {shrink of space}
4007
4008 @
4009 @d puxg_set_cspace=0
4010 @d puxg_set_cespace=1
4011
4012 @<Scan spacing dimension of CJK font face@>=
4013 begin
4014   scan_optional_equals;
4015   scan_int;
4016   width_value:=cur_val;
4017   if scan_keyword("plus") then begin
4018     scan_int; stretch_value:=cur_val;
4019     end
4020   else {make stretch value compatible to \PUTeX 3}
4021     if width_value < 250 and p = puxg_set_cspace then stretch_value:=125
4022     else stretch_value:=width_value/2;
4023
4024   if scan_keyword("minus") then begin
4025     scan_int; shrink_value:=cur_val;
4026     end
4027   else {make shrink value compatible to \PUTeX 3}
4028      if width_value > 0 then shrink_value:=width_value div 3
4029      else shrink_value:=-width_value div 3;
4030 end
4031
4032 @ @<Modify the cspace factor of the specified chinese face@>=
4033 begin
4034   if cface_csp_width[cface_num]<>width_value or 
4035      cface_csp_stretch[cface_num]<>stretch_value or
4036      cface_csp_shrink[cface_num]<>shrink_value then begin
4037     cface_csp_width[cface_num]:=width_value; 
4038     cface_csp_stretch[cface_num]:=stretch_value;
4039     cface_csp_shrink[cface_num]:=shrink_value;
4040     n:=cfont_base+1;
4041     while n<cfont_ptr do begin
4042       if cface_num = cfont_face[n] then set_cglue_spec(n);
4043       incr(n);
4044       end;
4045     end;
4046 end
4047
4048 @ @<Modify the cespace factor of the specified chinese face@>=
4049 begin
4050   if cface_cesp_width[cface_num]<>width_value or 
4051      cface_cesp_stretch[cface_num]<>stretch_value or
4052      cface_cesp_shrink[cface_num]<>shrink_value then begin
4053     cface_cesp_width[cface_num]:=width_value; 
4054     cface_cesp_stretch[cface_num]:=stretch_value;
4055     cface_cesp_shrink[cface_num]:=shrink_value;
4056     n:=cfont_base+1;
4057     while n<cfont_ptr do begin
4058       if cface_num=cfont_face[n] then set_ceglue_spec(n);
4059       incr(n);
4060       end;
4061     end;
4062 end
4063
4064 @ @<Modify the depth factor of the specified chinese face@>=
4065 begin
4066   cur_val:=convfix(cur_val);
4067   if cface_fw_depth[cface_num]<>cur_val then begin
4068     cface_fw_depth[cface_num]:=cur_val;
4069     n:=cfont_base+1;
4070     while n<cfont_ptr do begin
4071       if cface_num=cfont_face[n] then
4072         cfont_depth[n]:=fw_times_sd(cface_fw_depth[cface_num], cfont_size[n]);
4073       incr(n);
4074       end;
4075     end;
4076 end
4077
4078 @
4079 @d pux_set_cfont_csp=0
4080 @d pux_set_cfont_cesp=1
4081 @<Put each of \TeX's primitives into the hash table@>=
4082 primitive("PUXcfontcspace",pux_set_cfont_attrib,pux_set_cfont_csp);
4083 primitive("PUXcfontcespace",pux_set_cfont_attrib,pux_set_cfont_cesp);
4084
4085 @ @<Cases of |print_cmd_chr|...@>=
4086 pux_set_cfont_attrib: begin
4087   case chr_code of
4088   pux_set_cfont_csp:print_esc("PUXcfontcspace");
4089   pux_set_cfont_cesp:print_esc("PUXcfontcespace");
4090   endcases;
4091   end;
4092
4093 @ @<Assignments@>=
4094 pux_set_cfont_attrib: begin p:=cur_chr;
4095   @<Get the next non-blank non-call token@>;
4096   if cur_cmd = set_cfont then {the first form}
4097     begin
4098     cfont_num:=cur_chr;
4099     end
4100   else if cur_cmd = set_font and cur_chr=cur_font then
4101     cfont_num:=cur_cfont
4102   else begin
4103     print_err("Missing CJK font identifier");
4104     help2("I was looking for a control sequence whose")@/
4105     ("current meaning is a CJK font command.");
4106     back_error; cfont_num:=null_cfont;
4107     end;
4108   scan_optional_equals;
4109   case p of
4110   pux_set_cfont_csp: begin
4111     scan_glue(glue_val);
4112     width(cfont_glue_spec[cfont_num]):=width(cur_val);
4113     shrink(cfont_glue_spec[cfont_num]):=shrink(cur_val);
4114     stretch(cfont_glue_spec[cfont_num]):=stretch(cur_val);
4115     fast_delete_glue_ref(cur_val);
4116     end;
4117   pux_set_cfont_cesp: begin
4118     scan_glue(glue_val);
4119     width(cfont_ceglue_spec[cfont_num]):=width(cur_val);
4120     shrink(cfont_ceglue_spec[cfont_num]):=shrink(cur_val);
4121     stretch(cfont_ceglue_spec[cfont_num]):=stretch(cur_val);
4122     fast_delete_glue_ref(cur_val);
4123     end;
4124   endcases;
4125   end;
4126
4127 @ @<Global variables@>=
4128 @!g_cspace_width:integer;
4129 @!g_cspace_shrink:integer;
4130 @!g_cspace_stretch:integer;
4131 @!g_cespace_width:integer;
4132 @!g_cespace_shrink:integer;
4133 @!g_cespace_stretch:integer;
4134
4135 @
4136 @d default_csp_width=50
4137 @d default_cesp_width=150
4138 @<Set init...@>=
4139 g_cspace_width:=default_csp_width;
4140 g_cspace_shrink:=g_cspace_width div 3;
4141 g_cspace_stretch:=125;
4142 g_cespace_width:=default_cesp_width;
4143 g_cespace_shrink:=g_cespace_width div 3;
4144 g_cespace_stretch:=g_cespace_width div 2;
4145
4146 @ @<Put each of \TeX's primitives into the hash table@>=
4147 primitive("puxgCspace",puxg_assign_space,puxg_set_cspace);
4148 primitive("puxgCEspace",puxg_assign_space,puxg_set_cespace);
4149
4150
4151 @ @<Cases of |print_cmd_chr|...@>=
4152 puxg_assign_space: begin
4153   if chr_code = puxg_set_cspace then
4154     print_esc("puxgCspace")
4155   else if chr_code = puxg_set_cespace then
4156     print_esc("puxgCEspace");
4157   end;
4158
4159
4160
4161 @ @<Assignments@>=
4162 puxg_assign_space:  begin p:=cur_chr;
4163   @<Scan spacing dimension of CJK font face@>;
4164   if p = puxg_set_cspace then begin
4165     g_cspace_width:=width_value;
4166     g_cspace_stretch:=stretch_value;
4167     g_cspace_shrink:=shrink_value;
4168     n:=cface_base;
4169     while n < cface_ptr do begin
4170        cface_csp_width[n]:=width_value;
4171        cface_csp_shrink[n]:=shrink_value;
4172        cface_csp_stretch[n]:=stretch_value;
4173       incr(n);
4174       end;
4175     n:=cfont_base+1;
4176     while n<cfont_ptr do begin
4177       set_cglue_spec(n);
4178       incr(n);
4179       end;
4180
4181     end
4182   else if p = puxg_set_cespace then begin
4183     g_cespace_width:=width_value;
4184     g_cespace_stretch:=stretch_value;
4185     g_cespace_shrink:=shrink_value;
4186     end;
4187     n:=cface_base;
4188     while n < cface_ptr do begin
4189        cface_cesp_width[n]:=width_value;
4190        cface_cesp_shrink[n]:=shrink_value;
4191        cface_cesp_stretch[n]:=stretch_value;
4192       incr(n);
4193       end;
4194     n:=cfont_base+1;
4195     while n<cfont_ptr do begin
4196       set_ceglue_spec(n);
4197       incr(n);
4198       end;
4199   end;
4200
4201
4202 @* \[61] Dump Font Info.
4203
4204 @<Other variables used by the procedure |prefixed_command|@>=
4205 @!old_setting:0..max_selector; {holds |selector| setting}
4206
4207 @ @<Put each of \TeX's primitives into the hash table@>=
4208 primitive("PUXdumpfontinfo",pux_dump_font_info,0);
4209
4210 @ @<Cases of |print_cmd_chr|...@>=
4211 pux_dump_font_info: print_esc("PUXdumpfontinfo"); {TCW}
4212
4213 @ @<Assignments@>=
4214 pux_dump_font_info: begin old_setting:=selector; selector:=log_only;@/
4215   @<Print TeX fonts@>;@/
4216   @<Print CJK font faces@>;@/
4217   @<Print CJK fonts@>;@/
4218   @<Print font faces matching table@>;@/
4219   selector:=old_setting;
4220   end;
4221
4222 @ @<Print TeX fonts@>=
4223 print_ln; print("Tex fonts"); print_ln;
4224 n:=0;
4225 while n <= font_ptr do
4226   begin
4227   print_int(n); print(": "); print(font_name[n]);@/
4228   print(" dsize= "); print_scaled(font_dsize[n]); print("pt");@/
4229   print(" at "); print_scaled(font_size[n]); print("pt");@/
4230   print(" matched CJK font="); print_int(font_matching_table(n));
4231   print_ln; incr(n);
4232   end
4233
4234 @ @<Print CJK font faces@>=
4235 print("Chinese faces"); print_ln;
4236 n:=0;
4237 while n < cface_ptr do
4238   begin
4239   print_int(n); print(": "); print("id="); print(cface[n]);@/
4240   print(" name="); print(cface_name[n]);@/
4241   print(" charset="); print_int(cface_charset[n]);@/
4242   print(" weight="); print_int(cface_weight[n]);@/
4243   print(" style="); print_int(cface_style[n]);@/
4244   print(" w="); print_fixword(cface_fw_width[n]);@/
4245   print(" h="); print_fixword(cface_fw_height[n]);@/
4246   print(" d="); print_fixword(cface_fw_depth[n]);@/
4247   print_ln; incr(n);
4248   end
4249
4250 @ @<Print CJK fonts@>=
4251 print("CJK fonts"); print_ln;
4252 n:=cfont_base;
4253 while n < cfont_ptr do
4254   begin
4255   print_int(n); print(":face= ");
4256   print(cface[cfont_face[n]]);@/
4257   print(" dsize= "); print_scaled(cfont_dsize[n]); print("pt");@/
4258   print(" at "); print_scaled(cfont_size[n]); print("pt");@/
4259   print_ln; incr(n);
4260   end
4261
4262 @ @<Print font faces matching table@>=
4263 print("English/CJK font faces matching table"); print_ln;
4264 n:=min_ectbl;
4265 while n < ectbl_ptr do
4266   begin
4267   print_int(n); print(": "); print("eface="); print(ectbl_eface_name[n]);@/
4268   print(" cface_id="); print(cface[ectbl_cface_num(n)]);@/
4269   print(" cface_num="); print_int(ectbl_cface_num(n));@/
4270   print_ln; incr(n);
4271   end
4272
4273 @ @<Global variables@>=
4274 @!dvi_cf:internal_cfont_number;  {the current chinese font}
4275
4276 @ @<Output the CJK font definitions for all fonts that were used@>=
4277 while cfont_ptr>cfont_base do
4278   begin if cfont_used[cfont_ptr] then dvi_cfont_def(cfont_ptr);
4279   decr(cfont_ptr);
4280   end
4281
4282
4283 @ @<Change font |dvi_cf| to |f|@>=
4284 begin if not cfont_used[f] then
4285   begin dvi_cfont_def(f); cfont_used[f]:=true;
4286   end;
4287   dvi_out(cfnt); dvi_out((f-cfont_base-1) div 256); dvi_out((f-cfont_base-1) mod 256);
4288   dvi_cf:=f;
4289 end
4290
4291 @* \[62] Dump/undump \PUTeX\ internal information.
4292
4293 @ @<Dump the CJK font face information@>=
4294 dump_int(cface_ptr);
4295 dump_int(cface_fw_default_depth);
4296 for k:=cface_base to cface_ptr-1 do begin
4297   dump_int(cface[k]);
4298   dump_int(cface_name[k]);
4299   dump_int(cface_charset[k]);
4300   dump_int(cface_weight[k]);
4301   dump_int(cface_style[k]);
4302   dump_int(cface_fw_width[k]);
4303   dump_int(cface_fw_height[k]);
4304   dump_int(cface_fw_depth[k]);
4305   dump_int(cface_csp_width[k]);
4306   dump_int(cface_csp_shrink[k]);
4307   dump_int(cface_csp_stretch[k]);
4308   dump_int(cface_cesp_width[k]);
4309   dump_int(cface_cesp_shrink[k]);
4310   dump_int(cface_cesp_stretch[k]);
4311   print_ln;
4312   print_int(k); print(": "); print("id="); print(cface[k]);@/
4313   print(" name="); print(cface_name[k]);@/
4314   print(" charset="); print_int(cface_charset[k]);@/
4315   print(" weight="); print_int(cface_weight[k]);@/
4316   print(" style="); print_int(cface_style[k]);@/
4317   print(" w="); print_fixword(cface_fw_width[k]);@/
4318   print(" h="); print_fixword(cface_fw_height[k]);@/
4319   print(" d="); print_fixword(cface_fw_depth[k]);@/
4320   end;
4321 print_ln;
4322 print_int(cface_ptr-cface_base); print(" preloaded CJK font face");
4323 if cface_ptr<>cface_base+1 then print_char("s")
4324
4325 @ @<Undump the CJK font face information@>=
4326 undump_size(cface_base)(max_cface)('cface max')(cface_ptr);
4327 undump_int(cface_fw_default_depth);
4328 for k:=cface_base to cface_ptr-1 do begin
4329   undump_size(0)(pool_size)('cface id')(cface[k]);
4330   undump_size(0)(pool_size)('cface name')(cface_name[k]);
4331   undump_size(0)(255)('charset size')(cface_charset[k]);
4332   undump_size(1)(1000)('cface weight')(cface_weight[k]);
4333   undump_size(0)(255)('cface style')(cface_style[k]);
4334   undump_int(cface_fw_width[k]);
4335   undump_int(cface_fw_height[k]);
4336   undump_int(cface_fw_depth[k]);
4337   undump_int(cface_csp_width[k]);
4338   undump_int(cface_csp_shrink[k]);
4339   undump_int(cface_csp_stretch[k]);
4340   undump_int(cface_cesp_width[k]);
4341   undump_int(cface_cesp_shrink[k]);
4342   undump_int(cface_cesp_stretch[k]);
4343   end
4344
4345 @ @<Dump the face matching table@>=
4346 dump_int(ectbl_ptr);
4347 for k:=min_ectbl to ectbl_ptr-1 do
4348   dump_int(ectbl_eface_name[k])
4349
4350 @ @<Unump the face matching table@>=
4351 undump_size(min_ectbl)(max_ectbl)('ectbl_ptr')(ectbl_ptr);
4352 for k:=min_ectbl to ectbl_ptr-1 do
4353   undump_size(0)(pool_size)('ectbl eface name')(ectbl_eface_name[k])
4354
4355 @ @<Dump the CJK font information@>=
4356 begin
4357 dump_int(cfont_ptr);
4358 for k:=default_cfont to cfont_ptr-1 do begin
4359   dump_int(cfont_face[k]);
4360   dump_int(cfont_dsize[k]);
4361   dump_int(cfont_size[k]);
4362   dump_int(cfont_width[k]);
4363   dump_int(cfont_height[k]);
4364   dump_int(cfont_depth[k]);
4365   dump_int(cfont_glue_spec[k]);
4366   dump_int(cfont_ceglue_spec[k]);
4367   print_ln;
4368   print_int(k); print(":face= ");
4369   print(cface[cfont_face[k]]);@/
4370   print(" dsize= "); print_scaled(cfont_dsize[k]); print("pt");@/
4371   print(" at "); print_scaled(cfont_size[k]); print("pt");@/
4372   end;
4373 end
4374
4375 @ @<Undump the CJK font information@>=
4376 begin
4377 undump_size(cfont_base)(cfont_max)('cfont max')(cfont_ptr);
4378 for k:=default_cfont to cfont_ptr-1 do begin
4379   undump_size(cface_base)(max_cface)('cface max')(cfont_face[k]);
4380   undump_int(cfont_dsize[k]);
4381   undump_int(cfont_size[k]);
4382   undump_int(cfont_width[k]);
4383   undump_int(cfont_height[k]);
4384   undump_int(cfont_depth[k]);
4385   undump_int(cfont_glue_spec[k]);
4386   undump_int(cfont_ceglue_spec[k]);
4387   end;
4388 end
4389   
4390 @* \[63] Index.
4391
4392 @z
4393