--- /dev/null
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%
+%%% WEB Change File for PUTeX (CJK version)
+%%% Modified and patched version for TeX Live
+%%%
+%%% Copyright (C) 1997-2004 Chey-Woei Tsay <cwtsay@pu.edu.tw>
+%%% Copyright (C) 2013-2014 Clerk Ma <clerkma@gmail.com>
+%%%
+%%% This is the change file of PUTeX.
+%%%
+%%% PUTeX is a free software; you can redistribute it and/or
+%%% modify it under the terms of the GNU General Public License as
+%%% published by the Free Software Foundation; either version 3, or (at
+%%% your option) any later version.
+%%%
+%%% PUTeX is distributed in the hope that it will be useful, but
+%%% WITHOUT ANY WARRANTY; without even the implied warranty of
+%%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+%%% General Public License for more details.
+%%%
+%%% You should have received a copy of the GNU General Public License
+%%% along with TeX Live; if not, write to the Free Software
+%%% Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+%%% USA.
+%%%
+%%%
+%%% Version 4.0
+%%% add \PUXcatcode command to set catcodes of dbcs characters.
+%%% remove print_dbchar (58, 59, 70, 318, print_chinese_int)
+%%%
+%%% Version 4.0-web2c
+%%% removed the MikTeX part.
+%%%
+%%%
+%%% TO DO:
+%%% new_character(582), make_accent(1123), char_box, rebox
+%%% mathmode: be awear of print_ASCII
+%%% check '(cat_code(buffer[loc])<>escape)' in section 1337
+%%%
+%%% \PUXsetcfacehook -- set cface hook macro that is called when switched to the cface
+%%% \PUXsetcfonthook -- set cfont hook macro that is called when switched to the cfont
+%%%
+%%% see section 224 for cspace skip and cespace skip
+%%%
+%%% New Indices:
+%%% @^Input Encoding Dependencies@>
+%%% @^Modified for handling DBCS characters@>
+%%% @^CJK Fonts Extension@>
+
+@x
+\def\gglob{20, 26} % this should be the next two sections of "<Global...>"
+@y
+\def\gglob{20, 26} % this should be the next two sections of "<Global...>"
+\def\PUTeX{PU\TeX}
+\def\putexadd{\hskip -0.5in putex -- add -- }
+\def\putexmod{\hskip -0.5in putex -- mod -- }
+\def\putexend{\hskip -0.5in putex -- end -- }
+@z
+
+@x
+@d banner==TeX_banner
+@d banner_k==TeX_banner_k
+@y
+@d PUTeX_version_string=='-5.0' {current \PUTeX\ version}
+@#
+@d PUTeX_banner=='This is PUTeX, Version 3.1415926',PUTeX_version_string
+@d PUTeX_banner_k==PUTeX_banner
+ {printed when \PUTeX\ starts}
+@#
+@d banner==PUTeX_banner
+@d banner_k==PUTeX_banner_k
+@z
+
+@x
+@t\4@>@<Error handling procedures@>@/
+@y
+@t\4@>@<Error handling procedures@>@/
+@t\4@>@<PUTeX routines that will be used by TeX routines@>@/
+@#
+{ end -- putex}
+@z
+
+@x
+xchr[@'40]:=' ';
+@y
+@#@t\putexadd@>@#
+for k := 0 to 255 do xchr[k] := k;
+@#@t\putexend@>@#
+xchr[@'40]:=' ';
+@z
+
+@x
+The |append_char| macro, defined here, does not check to see if the
+value of |pool_ptr| has gotten too high; this test is supposed to be
+made before |append_char| is used. There is also a |flush_char|
+@y
+The |append_char| and |append_wchar| macros, defined here, do not check to see if the
+value of |pool_ptr| has gotten too high; this test is supposed to be
+made before |append_char| (or |append_wchar|) is used. There is also a |flush_char|
+@z
+
+@x
+@d append_char(#) == {put |ASCII_code| \# at the end of |str_pool|}
+begin str_pool[pool_ptr]:=si(#); incr(pool_ptr);
+end
+@y
+@d append_char(#) == {put |ASCII_code| \# at the end of |str_pool|}
+begin str_pool[pool_ptr]:=si(#); incr(pool_ptr);
+end
+@#@t\putexadd@>
+@d append_wchar(#) == {TCW: put a double-byte char \# at the end of |str_pool|}
+begin str_pool[pool_ptr]:=# div 256; str_pool[pool_ptr+1]:=# mod 256;
+pool_ptr:=pool_ptr+2;
+end
+@#@t\putexend@>
+@z
+
+@x
+using the |xchr| array to map it into an external character compatible with
+|input_ln|. All printing comes through |print_ln| or |print_char|.
+@y
+using the |xchr| array to map it into an external character compatible with
+|input_ln|. All printing comes through |print_ln|, |print_char|, or |print_wchar|.
+
+TCW: The |print_wchar| macro is used to print one DBCS character.
+
+@d print_wchar(#)==begin print_char((#) div 256); print_char((#) mod 256) end {TCW}
+@z
+
+@x
+@d character == subtype {the character code in a |char_node|}
+@y
+@d character == subtype {the character code in a |char_node|}
+@d is_wchar_node(#) == (character(#)>255)
+@d is_wchar(#) == ((#)>255)
+@z
+
+%% parallel kanji font, when typesetting kanjis, we need a match table.
+@x
+@!font_in_short_display:integer; {an internal font number}
+@y
+@!font_in_short_display:integer; {an internal font number}
+@!cfont_in_short_display:integer; {TCW: an internal CJK font number}
+@z
+
+@x
+sort of ``complicated'' are indicated only by printing `\.{[]}'.
+@y
+sort of ``complicated'' are indicated only by printing `\.{[]}'.@^CJK Fonts Extension@>
+@z
+
+@x
+ begin if font(p)<>font_in_short_display then
+ begin if (font(p)>font_max) then
+ print_char("*")
+@.*\relax@>
+ else @<Print the font identifier for |font(p)|@>;
+ print_char(" "); font_in_short_display:=font(p);
+ end;
+ print_ASCII(qo(character(p)));
+ end;
+@y
+ begin if font(p)<>font_in_short_display and font(p)<>cfont_in_short_display then
+ begin if (font(p)>cfont_max) then
+ print_char("*")
+@.*\relax@>
+ else @<Print the font identifier for |font(p)|@>;
+ print_char(" ");
+ if font(p) <= font_max then
+ font_in_short_display:=font(p)
+ else
+ cfont_in_short_display:=font(p);
+ end;
+ if is_wchar_node(p) then
+ print_wchar(character(p))
+ else
+ print_ASCII(qo(character(p)));
+ end;
+@z
+
+@x
+its reference count, and one to print a rule dimension.
+@y
+its reference count, and one to print a rule dimension.@^CJK Fonts Extension@>
+@z
+
+@x
+else begin if (font(p)>font_max) then print_char("*")
+@y
+else begin if (font(p)>cfont_max) then print_char("*")
+@z
+
+@x
+ print_char(" "); print_ASCII(qo(character(p)));
+@y
+ print_char(" ");
+ if is_wchar_node(p) then
+ print_wchar(character(p))
+ else
+ print_ASCII(qo(character(p)));
+@z
+
+%% for kinsoku
+@x
+@d max_char_code=15 {largest catcode for individual characters}
+@y
+@d max_char_code=15 {largest catcode for individual characters}
+@d boundary_normal=0 {CJK characters can be in any positions of lines}
+@d tail_forbidden=1 {CJK characters can't be put in the head of lines}
+@d head_forbidden=2 {CJK characters can't be put in the tail of lines}
+@d max_type_code=2 {largest boundary code for CJK characters}
+@d set_type_code_end(#) == # end
+@d set_type_code(#) == begin
+ type_code(#) := set_type_code_end
+@z
+
+@x
+@ The next codes are special; they all relate to mode-independent
+assignment of values to \TeX's internal registers or tables.
+Codes that are |max_internal| or less represent internal quantities
+that might be expanded by `\.{\\the}'.
+@y
+@ The next codes are special; they all relate to mode-independent
+assignment of values to \TeX's internal registers or tables.
+Codes that are |max_internal| or less represent internal quantities
+that might be expanded by `\.{\\the}'.
+
+TCW: Add 3 internal commands: |set_cfont|, |puxg_assign_flag|, and |puxg_assign_int|.
+Add 12 user commands: |pux_cface_def|, |pux_face_match|, |pux_font_match|,
+|pux_set_cface|, |pux_set_cface_attrib|,|pux_set_cfont_attrib|,
+|pux_char_num|, |pux_char_given|, |pux_space|, |pux_range_catcode|,
+|pux_range_type_code|, and |pux_dump_font_info|.@^CJK Fonts Extension@>
+@z
+
+@x
+@d def_font=88 {define a font file ( \.{\\font} )}
+@d register=89 {internal register ( \.{\\count}, \.{\\dimen}, etc.~)}
+@d max_internal=89 {the largest code that can follow \.{\\the}}
+@d advance=90 {advance a register or parameter ( \.{\\advance} )}
+@d multiply=91 {multiply a register or parameter ( \.{\\multiply} )}
+@d divide=92 {divide a register or parameter ( \.{\\divide} )}
+@d prefix=93 {qualify a definition ( \.{\\global}, \.{\\long}, \.{\\outer} )}
+@d let=94 {assign a command code ( \.{\\let}, \.{\\futurelet} )}
+@d shorthand_def=95 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)}
+ {or \.{\\charsubdef}}
+@d read_to_cs=96 {read into a control sequence ( \.{\\read} )}
+@d def=97 {macro definition ( \.{\\def}, \.{\\gdef}, \.{\\xdef}, \.{\\edef} )}
+@d set_box=98 {set a box ( \.{\\setbox} )}
+@d hyph_data=99 {hyphenation data ( \.{\\hyphenation}, \.{\\patterns} )}
+@d set_interaction=100 {define level of interaction ( \.{\\batchmode}, etc.~)}
+@d max_command=100 {the largest command code seen at |big_switch|}
+@y
+@d set_cfont=88 {TCW: set current chinese font ( font identifiers )}
+@d def_font=89 {define a font file ( \.{\\font} )}
+@d register=90 {internal register ( \.{\\count}, \.{\\dimen}, etc.~)}
+@d puxg_assign_flag=91 {TCW: set a PU\TeX\ global flag (\.{\\puxgCdiOut}, \.{\\puxgRotateCtext})}
+@d puxg_assign_int=92 {TCW: set a PU\TeX\ global integer (\.{\\puxgCspace}, \.{\\puxgCEspace})}
+@d pux_get_int=93 {TCW: get internal integer values ( \.{\\PUXnumdigits}, \.{\\PUXsign}, \.{\\PUXdigit} )}
+@d max_internal=93 {the largest code that can follow \.{\\the}}
+@d advance=94 {advance a register or parameter ( \.{\\advance} )}
+@d multiply=95 {multiply a register or parameter ( \.{\\multiply} )}
+@d divide=96 {divide a register or parameter ( \.{\\divide} )}
+@d prefix=97 {qualify a definition ( \.{\\global}, \.{\\long}, \.{\\outer} )}
+@d let=98 {assign a command code ( \.{\\let}, \.{\\futurelet} )}
+@d shorthand_def=99 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)}
+ {or \.{\\charsubdef}}
+@d read_to_cs=100 {read into a control sequence ( \.{\\read} )}
+@d def=101 {macro definition ( \.{\\def}, \.{\\gdef}, \.{\\xdef}, \.{\\edef} )}
+@d set_box=102 {set a box ( \.{\\setbox} )}
+@d hyph_data=103 {hyphenation data ( \.{\\hyphenation}, \.{\\patterns} )}
+@d set_interaction=104 {define level of interaction ( \.{\\batchmode}, etc.~)}
+@d pux_cface_def=105 {TCW: define a chinese font face ( \.{\\PUXcfacedef} )}
+@d pux_face_match=106 {TCW: English and Chinese face matching pair ( \.{\\PUXfacematch} )}
+@d pux_font_match=107 {TCW: English and CJK font matching pair ( \.{\\PUXfontmatch} )}
+@d pux_set_cface=108 {TCW: Set Chinese face}
+@d pux_set_cface_attrib=109 {TCW: Set attributes of a Chinese face ( \.{\\PUXsetcfacecspace, etc.} )}
+@d pux_set_cfont_attrib=110 {TCW: Set attributes of a CJK font ( \.{\\PUXsetcfontcspace, etc.} )}
+@d pux_char_num=111 {TCW: Chinese character number ( \.{\\PUXchar} )}
+@d pux_char_given=112 {TCW: define a Chinese character ( \.{\\PUXchardef} )}
+@d pux_space=113 {Append space glue between Chinese and Tex characters ( \.{\\PUXcespace} )}
+@d pux_range_catcode=114 {TCW: set catcodes for a range of characters( \.{\\PUXrangecatcode} )}
+@d pux_range_type_code=115 {TCW: set catcodes for a range of characters( \.{\\PUXrangecatcode} )}
+@d pux_split_number=116 {TCW: split a number to digits ( \.{\\PUXsplitnumber} )}
+@d puxg_assign_space=117 {TCW: set a PU\TeX\ global integer (\.{\\puxgCspace}, \.{\\puxgCEspace})}
+@d pux_set_default_cface=118 {TCW: set default CJK font face ( \.{\\PUXsetdefaultcface} )}
+@d pux_dump_font_info=119 {TCW: dump font information ( \.{\\PUXdumpfontinfo} )}
+@d max_command=119 {the largest command code seen at |big_switch|}
+@z
+
+@x
+In the first region we have 256 equivalents for ``active characters'' that
+act as control sequences, followed by 256 equivalents for single-character
+control sequences.
+@y
+In the first region we have 65536 equivalents for ``active characters'' that
+act as control sequences, followed by 65536 equivalents for single-character
+control sequences.
+@z
+
+@x
+@d single_base=active_base+256 {equivalents of one-character control sequences}
+@d null_cs=single_base+256 {equivalent of \.{\\csname\\endcsname}}
+@y
+@d single_base=active_base+65536 {equivalents of one-character control sequences}
+@d null_cs=single_base+65536 {equivalent of \.{\\csname\\endcsname}}
+@z
+
+%% parallel font
+@x
+@d font_id_base=frozen_null_font-font_base
+ {begins table of 257 permanent font identifiers}
+@d undefined_control_sequence=frozen_null_font+max_font_max+1 {dummy location}
+@y
+@d font_id_base=frozen_null_font-font_base
+ {begins table of 257 permanent English font identifiers}
+@d font_max_limit=5000
+@d cfont_id_base=font_id_base+font_max_limit+1
+ {TCW: begins table of 'font\_max\_limit' permanent CJK font identifiers}
+@d cfont_max_limit=font_max_limit
+@d cface_id_base=cfont_id_base+cfont_max_limit+1
+ {TCW: begins table of 257 permanent Chinese face identifiers}
+@d undefined_control_sequence=cface_id_base+257 {dummy location}
+@z
+
+@x
+token parameters, as well as the tables of \.{\\toks} and \.{\\box}
+registers.
+@y
+token parameters, as well as the tables of \.{\\toks} and \.{\\box}
+registers.
+
+TCW: Define |cur_cfont_loc| for two-byte char and the macro |cur_cfont|.
+@z
+
+@x
+@d math_font_base=cur_font_loc+1 {table of 48 math font numbers}
+@y
+@d cur_cface_loc=cur_font_loc+1 {TCW: internal chinese font number outside math mode}
+@d cur_cfont_loc=cur_cface_loc+1 {TCW: internal chinese font number outside math mode}
+@d ectbl_cface_num_base=cur_cfont_loc+1 {TCW: table of 257 CJK face numbers matched with TeX face}
+@d max_cface=256 {maximal CJK font faces number}
+@d font_matching_table_base=ectbl_cface_num_base+max_cface+1 {table of font matches}
+@d math_font_base=font_matching_table_base+font_max_limit+1 {table of 48 math font numbers}
+@z
+
+@x
+ {table of 256 command codes (the ``catcodes'')}
+@d lc_code_base=cat_code_base+256 {table of 256 lowercase mappings}
+@y
+ {TCW: table of 65536 command codes (the ``catcodes'')}
+@d pux_cat_code_base=cat_code_base+256
+@d pux_type_code_base=cat_code_base+65536 {TCW: table of 65536 type codes}
+@d lc_code_base=pux_type_code_base+65536 {table of 256 lowercase mappings}
+@z
+
+@x
+@d math_code_base=sf_code_base+256 {table of 256 math mode mappings}
+@y
+@d pux_local_names_base=sf_code_base+256 {TCW: table of 256 CJK name mappings.}
+@d math_code_base=pux_local_names_base+256 {table of 256 math mode mappings}
+@z
+
+@x
+@d cur_font==equiv(cur_font_loc)
+@y
+@d cur_font==equiv(cur_font_loc)
+@d cur_cface==equiv(cur_cface_loc) {TCW}
+@d cur_cfont==equiv(cur_cfont_loc) {TCW}
+@d ectbl_cface_num(#)==equiv(ectbl_cface_num_base+(#)) {TCW}
+@d font_matching_table(#)==equiv(font_matching_table_base+((#)-font_base)) {TCW}
+@z
+
+@x
+@d cat_code(#)==equiv(cat_code_base+#)
+@y
+@d cat_code(#)==equiv(cat_code_base+#)
+@d type_code(#)==equiv(pux_type_code_base+#)
+@d local_names(#)==equiv(pux_local_names_base+#)
+@z
+
+@x
+packages, not in \TeX\ itself, so that global interchange of formats is
+possible.
+@y
+packages, not in \TeX\ itself, so that global interchange of formats is
+possible.
+
+TCW: Add |null_cfont| and initialization for |cur_font|.
+@z
+
+@x
+@d null_font==font_base
+@y
+@d null_font==font_base
+@d null_cfont==cfont_base
+@d default_cfont==null_cfont+1
+@z
+
+@x
+begin if n=cur_font_loc then print("current font")
+else if n<math_font_base+16 then
+@y
+begin if n=cur_font_loc then print("current font")
+else if n=cur_cface_loc then print("current cface")
+else if n=cur_cfont_loc then print("current cfont")
+else if n<math_font_base+16 then
+@z
+
+@x
+ begin if n<lc_code_base then
+ begin print_esc("catcode"); print_int(n-cat_code_base);
+ end
+@y
+ begin if n<pux_type_code_base then
+ begin
+ if n<pux_cat_code_base then print_esc("catcode")
+ else print_esc("PUXcatcode");
+ print_int(n-cat_code_base);
+ end
+ else if n<lc_code_base then
+ begin print_esc("PUXtypecode"); print_int(n-pux_type_code_base);
+ end
+@z
+
+@x
+ else begin print_esc("sfcode"); print_int(n-sf_code_base);
+ end;
+@y
+ else if n<pux_local_names_base then
+ begin print_esc("sfcode"); print_int(n-sf_code_base);
+ end
+ else begin print_esc("PUXlocalnames"); print_int(n-pux_local_names_base);
+ end;
+@z
+
+@x
+ print_char("="); print_int(equiv(n));
+@y
+ print_char("=");
+ if n>=pux_local_names_base then
+ if n < 256 then print_char(equiv(n))
+ else print_wchar(equiv(n))
+ else print_int(equiv(n));
+@z
+
+@x
+@d error_context_lines_code=54 {maximum intermediate line pairs shown}
+@d tex_int_pars=55 {total number of \TeX's integer parameters}
+@y
+@d error_context_lines_code=54 {maximum intermediate line pairs shown}
+@d puxg_rotate_ctext_code=55
+@d puxg_cface_depth_code=56
+@d pux_xspace_code=57
+@d pux_wcharother_code=58
+@d pux_CJKinput_code=59
+@d pux_charset_code=60
+@d pux_default_cface_code=61
+@d pux_digit_num_code=62 {number of digits of the splitted number}
+@d pux_sign_code=63 {sign of the splitted number}
+@d pux_digit_base=64 {10 digits of splitted number}
+@d tex_int_pars=74 {total number of \TeX's integer parameters}
+@z
+
+@x
+@d error_context_lines==int_par(error_context_lines_code)
+@y
+@d error_context_lines==int_par(error_context_lines_code)
+@d puxg_rotate_ctext==int_par(puxg_rotate_ctext_code)
+@d puxg_cface_depth==int_par(puxg_cface_depth_code)
+@d pux_xspace==int_par(pux_xspace_code)
+@d pux_wcharother==int_par(pux_wcharother_code)
+@d pux_CJKinput==int_par(pux_CJKinput_code)
+@d pux_charset==int_par(pux_charset_code)
+@d pux_default_cface==int_par(pux_default_cface_code)
+@d pux_digit_num==int_par(pux_digit_num_code)
+@d pux_num_sign==int_par(pux_sign_code)
+@d pux_nth_digit(#)==int_par(pux_digit_base+#)
+@d default_csp=50
+@d default_cesp=150
+@d default_depth=200
+@z
+
+@x
+othercases print("[unknown integer parameter!]")
+@y
+pux_xspace_code:print_esc("puxXspace");
+pux_wcharother_code:print_esc("puxCJKcharOther");
+pux_CJKinput_code:print_esc("puxCJKinput");
+pux_charset_code:print_esc("puxCharSet");
+puxg_rotate_ctext_code:print_esc("puxgRotateCtext");
+puxg_cface_depth_code:print_esc("puxgCfaceDepth");
+othercases print("[unknown integer parameter!]")
+@z
+
+@x
+del_code("."):=0; {this null delimiter is used in error recovery}
+@y
+del_code("."):=0; {this null delimiter is used in error recovery}
+puxg_cface_depth:=default_depth;
+pux_CJKinput:=1;
+@z
+
+@x
+ if cat_code(p-single_base)=letter then print_char(" ");
+@y
+ if get_cat_code(p-single_base)=letter then print_char(" ");
+@z
+
+@x
+def_font: print_esc("font");
+@y
+def_font: print_esc("font");
+pux_font_match: print_esc("PUXfontmatch"); {TCW}
+pux_set_cface: print_esc("cface"); {TCW}
+pux_range_catcode: print_esc("PUXrangecatcode"); {TCW}
+pux_range_type_code: print_esc("PUXrangetypecode"); {TCW}
+pux_split_number: print_esc("PUXsplitnumber"); {TCW}
+@z
+
+@x
+A \TeX\ token is either a character or a control sequence, and it is
+@^token@>
+represented internally in one of two ways: (1)~A character whose ASCII
+code number is |c| and whose command code is |m| is represented as the
+number $2^8m+c$; the command code is in the range |1<=m<=14|. (2)~A control
+sequence whose |eqtb| address is |p| is represented as the number
+|cs_token_flag+p|. Here |cs_token_flag=@t$2^{12}-1$@>| is larger than
+$2^8m+c$, yet it is small enough that |cs_token_flag+p< max_halfword|;
+thus, a token fits comfortably in a halfword.
+
+A token |t| represents a |left_brace| command if and only if
+|t<left_brace_limit|; it represents a |right_brace| command if and only if
+we have |left_brace_limit<=t<right_brace_limit|; and it represents a |match| or
+|end_match| command if and only if |match_token<=t<=end_match_token|.
+The following definitions take care of these token-oriented constants
+and a few others.
+
+@d cs_token_flag==@'7777 {amount added to the |eqtb| location in a
+ token that stands for a control sequence; is a multiple of~256, less~1}
+@d left_brace_token=@'0400 {$2^8\cdot|left_brace|$}
+@d left_brace_limit=@'1000 {$2^8\cdot(|left_brace|+1)$}
+@d right_brace_token=@'1000 {$2^8\cdot|right_brace|$}
+@d right_brace_limit=@'1400 {$2^8\cdot(|right_brace|+1)$}
+@d math_shift_token=@'1400 {$2^8\cdot|math_shift|$}
+@d tab_token=@'2000 {$2^8\cdot|tab_mark|$}
+@d out_param_token=@'2400 {$2^8\cdot|out_param|$}
+@d space_token=@'5040 {$2^8\cdot|spacer|+|" "|$}
+@d letter_token=@'5400 {$2^8\cdot|letter|$}
+@d other_token=@'6000 {$2^8\cdot|other_char|$}
+@d match_token=@'6400 {$2^8\cdot|match|$}
+@d end_match_token=@'7000 {$2^8\cdot|end_match|$}
+@y
+A \TeX\ token is either a character or a control sequence, and it is
+@^token@>
+represented internally in one of two ways: (1)~A character whose ASCII
+code number is |c| and whose command code is |m| is represented as the
+number $2^{16}m+c$; the command code is in the range |1<=m<=14|. (2)~A control
+sequence whose |eqtb| address is |p| is represented as the number
+|cs_token_flag+p|. Here |cs_token_flag=@t$2^{20}-1$@>| is larger than
+$2^{16}m+c$, yet it is small enough that |cs_token_flag+p< max_halfword|;
+thus, a token fits comfortably in a halfword.
+
+A token |t| represents a |left_brace| command if and only if
+|t<left_brace_limit|; it represents a |right_brace| command if and only if
+we have |left_brace_limit<=t<right_brace_limit|; and it represents a |match| or
+|end_match| command if and only if |match_token<=t<=end_match_token|.
+The following definitions take care of these token-oriented constants
+and a few others.
+
+@d cs_token_flag==@"FFFFF {amount added to the |eqtb| location in a
+ token that stands for a control sequence; is a multiple of~65536, less~1}
+@d left_brace_token==@"10000 {$2^{16}\cdot|left_brace|$}
+@d left_brace_limit==@"20000 {$2^{16}\cdot(|left_brace|+1)$}
+@d right_brace_token==@"20000 {$2^{16}\cdot|right_brace|$}
+@d right_brace_limit==@"30000 {$2^{16}\cdot(|right_brace|+1)$}
+@d math_shift_token==@"30000 {$2^{16}\cdot|math_shift|$}
+@d tab_token==@"40000 {$2^{16}\cdot|tab_mark|$}
+@d out_param_token==@"50000 {$2^{16}\cdot|out_param|$}
+@d space_token==@"A0020 {$2^{16}\cdot|spacer|+|" "|$}
+@d letter_token==@"B0000 {$2^{16}\cdot|letter|$}
+@d other_token==@"C0000 {$2^{16}\cdot|other_char|$}
+@d match_token==@"D0000 {$2^{16}\cdot|match|$}
+@d end_match_token==@"E0000 {$2^{16}\cdot|end_match|$}
+@z
+
+@x
+else begin m:=info(p) div @'400; c:=info(p) mod @'400;
+@y
+else begin m:=info(p) div @"10000; c:=info(p) mod @"10000;
+@z
+
+@x
+left_brace,right_brace,math_shift,tab_mark,sup_mark,sub_mark,spacer,
+ letter,other_char: print(c);
+@y
+letter,other_char: if is_wchar(c) then print_wchar(c) else print(c);
+left_brace,right_brace,math_shift,tab_mark,sup_mark,sub_mark,spacer: print(c);
+@z
+
+@x
+@d chr_cmd(#)==begin print(#); print_ASCII(chr_code);
+ end
+@y
+@d chr_cmd(#)==begin print(#); print_ASCII(chr_code);
+ end
+@d wchr_cmd(#)==begin print(#);
+ if is_wchar(chr_code) then
+ print_wchar(chr_code)
+ else print_ASCII(chr_code);
+ end
+@z
+
+@x
+letter: chr_cmd("the letter ");
+other_char: chr_cmd("the character ");
+@y
+letter: wchr_cmd("the letter ");
+other_char: wchr_cmd("the character ");
+@z
+
+@x
+@!d:2..3; {number of excess characters in an expanded code}
+@y
+@!d:2..3; {number of excess characters in an expanded code}
+@!first_control_char:integer; {the first character code of control sequence}
+@z
+
+@x
+@ @<Input from external file, |goto restart| if no input found@>=
+@^inner loop@>
+begin switch: if loc<=limit then {current line not yet finished}
+ begin cur_chr:=buffer[loc]; incr(loc);
+@y
+@ The |get_wchar| macro tries to read a double-byte character from |buffer|
+at the position specified by the parameter. The code value is stored in the
+global variable |cur_chr|.
+@^inner loop@>
+@^Modified for handling DBCS characters@>
+
+@d get_wchar(#)==begin cur_chr:=buffer[#]; incr(#);
+ if cur_chr > 127 and pux_CJKinput = 1 then begin
+ cur_chr := cur_chr * 256 + buffer[#]; incr(#)
+ end
+ end
+
+@<Input from external file, |goto restart| if no input found@>=
+begin switch: if loc<=limit then {current line not yet finished}
+ begin get_wchar(loc);
+@z
+
+@x
+ reswitch: cur_cmd:=cat_code(cur_chr);
+@y
+ reswitch: cur_cmd:=get_cat_code(cur_chr);
+@z
+
+@x
+buffer and the process is repeated, slowly but surely.
+
+@<Scan a control...@>=
+begin if loc>limit then cur_cs:=null_cs {|state| is irrelevant in this case}
+else begin start_cs: k:=loc; cur_chr:=buffer[k]; cat:=cat_code(cur_chr);
+ incr(k);
+@y
+buffer and the process is repeated, slowly but surely.
+
+\medskip
+
+TCW: When the flag |expand_char| is true, we stop using |get_wchar| but
+merely get a one-byte character so that reading DBCS characters
+will not be confused. Besides, we neet to handle alphabetic numbers of the form
+\.{'\\c}, where \.{c} is a DBCS characters.@^Modified for handling DBCS characters@>
+
+@<Scan a control...@>=
+begin if loc>limit then cur_cs:=null_cs {|state| is irrelevant in this case}
+else begin first_control_char := -1;@/
+start_cs: k:=loc;
+ if expand_char then begin
+ cur_chr:=buffer[k];
+ incr(k);
+ expand_char:=false;
+ end
+ else get_wchar(k);
+ cat:=get_cat_code(cur_chr);
+ if first_control_char = -1 then first_control_char := cur_chr;
+@z
+
+@x
+ cur_cs:=single_base+buffer[loc]; incr(loc);
+ end;
+@y
+ @#{the control sequence is a control symbol, i.e., its name consisits of only one letter. }
+ if is_wchar(first_control_char) then begin
+ cur_cs:=single_base+first_control_char; loc:=loc+2;
+ end
+ else begin
+ cur_cs:=single_base+buffer[loc]; incr(loc);
+ end;
+ end;
+@z
+
+@x
+the buffer left two or three places.
+@y
+the buffer left two or three places.
+
+TCW: If it is indeed an expanded code, set the flag |expand_char|.
+@^Modified for handling DBCS characters@>
+@z
+
+@x
+ begin c:=buffer[k+1]; @+if c<@'200 then {yes, one is indeed present}
+ begin d:=2;
+@y
+ begin c:=buffer[k+1]; @+if c<@'200 then {yes, one is indeed present}
+ begin d:=2; expand_char:=true;
+@z
+
+@x
+@ @<Scan ahead in the buffer...@>=
+begin repeat cur_chr:=buffer[k]; cat:=cat_code(cur_chr); incr(k);
+@y
+@ @<Scan ahead in the buffer...@>=
+@^Modified for handling DBCS characters@>
+begin repeat get_wchar(k); cat:=get_cat_code(cur_chr);
+@z
+
+@x
+if cat<>letter then decr(k);
+ {now |k| points to first nonletter}
+if k>loc+1 then {multiletter control sequence has been scanned}
+@y
+if cat<>letter then if cur_chr > 256 then k:=k-2 { go back 2 steps for a non-letter DBCS code }
+else decr(k);
+ {now |k| points to first nonletter}
+if k>loc+1 and not (k = loc+2 and first_control_char > 255) then {multiletter control sequence has been scanned}
+@z
+
+@x
+ else begin cur_cmd:=t div @'400; cur_chr:=t mod @'400;
+@y
+ else begin cur_cmd:=t div @"10000; cur_chr:=t mod @"10000;
+@z
+
+@x
+if cur_cs=0 then cur_tok:=(cur_cmd*@'400)+cur_chr
+@y
+if cur_cs=0 then cur_tok:=(cur_cmd*@"10000)+cur_chr
+@z
+
+@x
+ buffer[j]:=info(p) mod @'400; incr(j); p:=link(p);
+@y
+@^Modified for handling DBCS characters@>
+ db_char:=info(p) mod @"10000;
+ if is_wchar(db_char) then {a double-byte char}
+ begin buffer[j]:=db_char div 256;
+ buffer[j+1]:=db_char mod 256;
+ j:=j + 2;
+ end
+ else begin
+ buffer[j]:=db_char;
+ incr(j);
+ end;
+ p:=link(p); {fix this for 2-byte code}
+@z
+
+@x
+done: if cur_cs=0 then cur_tok:=(cur_cmd*@'400)+cur_chr
+@y
+done: if cur_cs=0 then cur_tok:=(cur_cmd*@"10000)+cur_chr
+@z
+
+@x
+if cur_cs=0 then cur_tok:=(cur_cmd*@'400)+cur_chr
+@y
+if cur_cs=0 then cur_tok:=(cur_cmd*@"10000)+cur_chr
+@z
+
+@x
+toks_register,assign_toks,def_family,set_font,def_font: @<Fetch a token list or
+ font identifier, provided that |level=tok_val|@>;
+@y
+toks_register,assign_toks,def_family,set_font,def_font,set_cfont:
+ @<Fetch a token list or font identifier, provided that |level=tok_val|@>;
+@z
+
+@x
+assign_int: scanned_result(eqtb[m].int)(int_val);
+@y
+assign_int,puxg_assign_flag,puxg_assign_int: scanned_result(eqtb[m].int)(int_val);
+pux_get_int:@<scan \PUTeX\ internal values@>;
+@z
+
+@x
+char_given,math_given: scanned_result(cur_chr)(int_val);
+@y
+char_given,math_given,pux_char_given: scanned_result(cur_chr)(int_val);
+@z
+
+@x
+@ @<Fetch a character code from some table@>=
+begin scan_char_num;
+@y
+@ @<Fetch a character code from some table@>=
+begin
+ if (m = pux_cat_code_base) or (m = pux_type_code_base) then
+ scan_wchar_num
+ else if m = pux_local_names_base then begin
+ char_val_flag:=true;
+ scan_eight_bit_int;
+ end
+ else
+ scan_char_num;
+@z
+
+@x
+begin scan_font_ident;
+if m=0 then scanned_result(hyphen_char[cur_val])(int_val)
+else scanned_result(skew_char[cur_val])(int_val);
+end
+@y
+begin scan_font_ident;
+if cur_val <= font_max then
+ if m=0 then scanned_result(hyphen_char[cur_val])(int_val)
+ else scanned_result(skew_char[cur_val])(int_val);
+end
+@z
+
+@x
+@d octal_token=other_token+"'" {apostrophe, indicates an octal constant}
+@d hex_token=other_token+"""" {double quote, indicates a hex constant}
+@d alpha_token=other_token+"`" {reverse apostrophe, precedes alpha constants}
+@d point_token=other_token+"." {decimal point}
+@d continental_point_token=other_token+"," {decimal point, Eurostyle}
+@y
+@d octal_token==(other_token+"'") {apostrophe, indicates an octal constant}
+@d hex_token==(other_token+"""") {double quote, indicates a hex constant}
+@d alpha_token==(other_token+"`") {reverse apostrophe, precedes alpha constants}
+@d point_token==(other_token+".") {decimal point}
+@d continental_point_token==(other_token+",") {decimal point, Eurostyle}
+@z
+
+@x
+if cur_val>255 then
+@y
+if cur_val>65535 then
+@z
+
+@x
+@d zero_token=other_token+"0" {zero, the smallest digit}
+@d A_token=letter_token+"A" {the smallest special hex digit}
+@d other_A_token=other_token+"A" {special hex digit of type |other_char|}
+@y
+@d zero_token==(other_token+"0") {zero, the smallest digit}
+@d A_token==(letter_token+"A") {the smallest special hex digit}
+@d other_A_token==(other_token+"A") {special hex digit of type |other_char|}
+@z
+
+@x
+`\.{height}' or `\.{width}' or `\.{depth}' specifications are
+found (in any order).
+@y
+`\.{height}' or `\.{width}' or `\.{depth}' specifications are
+found (in any order).
+
+TCW: not intend to modify the function here;
+ just append declarations of scanning routines for PUTeX.
+@z
+
+@x
+if scan_keyword("depth") then
+@.depth@>
+ begin scan_normal_dimen; depth(q):=cur_val; goto reswitch;
+ end;
+scan_rule_spec:=q;
+end;
+@y
+if scan_keyword("depth") then
+@.depth@>
+ begin scan_normal_dimen; depth(q):=cur_val; goto reswitch;
+ end;
+scan_rule_spec:=q;
+end;
+
+@<PUTeX basic scanning routines@>@;
+@z
+
+@x
+var p:pointer; {tail of the token list}
+@!q:pointer; {new node being added to the token list via |store_new_token|}
+@!t:halfword; {token being appended}
+@!k:pool_pointer; {index into |str_pool|}
+begin str_room(1);
+p:=temp_head; link(p):=null; k:=b;
+while k<pool_ptr do
+ begin t:=so(str_pool[k]);
+ if t=" " then t:=space_token
+ else t:=other_token+t;
+ fast_store_new_token(t);
+ incr(k);
+ end;
+pool_ptr:=b; str_toks:=p;
+end;
+@y
+var p:pointer; {tail of the token list}
+@!q:pointer; {new node being added to the token list via |store_new_token|}
+@!t:halfword; {token being appended}
+@!k:pool_pointer; {index into |str_pool|}
+begin str_room(1);
+p:=temp_head; link(p):=null; k:=b;
+while k<pool_ptr do
+ begin t:=so(str_pool[k]);
+ if t > 128 then begin
+ t:=t*256+so(str_pool[k+1]);
+ incr(k);
+ end;
+ if t=" " then t:=space_token
+ else t:=other_token+t;
+ fast_store_new_token(t);
+ incr(k);
+ end;
+pool_ptr:=b; str_toks:=p;
+end;
+@z
+
+@x
+containing something like `\.{-3.0pt minus 0.5fill}'.
+@y
+containing something like `\.{-3.0pt minus 0.5fill}'.
+
+TCW: make the function able to print CJK characters stored in local names table.
+
+@z
+
+@x
+begin get_x_token; scan_something_internal(tok_val,false);
+@y
+begin get_x_token; char_val_flag:=false; scan_something_internal(tok_val,false);
+@z
+
+@x
+ int_val:print_int(cur_val);
+@y
+ int_val:if char_val_flag then
+ if cur_val > 255 then print_wchar(cur_val)
+ else {an empty slot}
+ begin print_char("?"); print_char("?"); end
+ else print_int(cur_val);
+@z
+
+@x
+@d font_name_code=4 {command code for \.{\\fontname}}
+@d job_name_code=5 {command code for \.{\\jobname}}
+@y
+@d font_name_code=4 {command code for \.{\\fontname}}
+@d cnumber_code=5 {command code for \.{\\PUXcnumber}}
+@d scnumber_code=6 {command code for \.{\\PUXscnumber}}
+@d ucnumber_code=7 {command code for \.{\\PUXucnumber}}
+@d fcnumber_code=8 {command code for \.{\\PUXfcnumber}}
+@d acnumber_code=9 {command code for \.{\\PUXacnumber}}
+@d cjknumber_code=10 {command code for \.{\\PUXcjknumber}}
+@d nameseq_code=11 {command code for \.{\\PUXnameseq}}
+@d job_name_code=12 {command code for \.{\\jobname}}
+@d lower_cdigit_base=10 {lowercase style Chinese number}
+@d upper_cdigit_base=25 {uppercase style Chinese number}
+@z
+
+@x
+primitive("jobname",convert,job_name_code);@/
+@!@:job_name_}{\.{\\jobname} primitive@>
+@y
+primitive("jobname",convert,job_name_code);@/
+@!@:job_name_}{\.{\\jobname} primitive@>
+primitive("PUXcnumber",convert,cnumber_code);@/
+@!@:cnumber_}{\.{\\PUXcnumber} primitive@>
+primitive("PUXscnumber",convert,scnumber_code);@/
+@!@:scnumber_}{\.{\\PUXscnumber} primitive@>
+primitive("PUXucnumber",convert,ucnumber_code);@/
+@!@:ucnumber_}{\.{\\PUXucnumber} primitive@>
+primitive("PUXfcnumber",convert,fcnumber_code);@/
+@!@:fcnumber_}{\.{\\PUXfcnumber} primitive@>
+primitive("PUXacnumber",convert,acnumber_code);@/
+@!@:acnumber_}{\.{\\PUXacnumber} primitive@>
+primitive("PUXcjknumber",convert,cjknumber_code);@/
+@!@:cjknumber_}{\.{\\PUXcjknumber} primitive@>
+primitive("PUXnameseq",convert,nameseq_code);@/
+@!@:cjknameseq_}{\.{\\PUXnameseq} primitive@>
+@z
+
+@x
+ meaning_code: print_esc("meaning");
+ font_name_code: print_esc("fontname");
+@y
+ meaning_code: print_esc("meaning");
+ font_name_code: print_esc("fontname");
+ cnumber_code: print_esc("PUXcnumber");
+ scnumber_code: print_esc("PUXscnumber");
+ ucnumber_code: print_esc("PUXucnumber");
+ fcnumber_code: print_esc("PUXfcnumber");
+ acnumber_code: print_esc("PUXfanumber");
+ cjknumber_code: print_esc("PUXcjknumber");
+ nameseq_code: print_esc("PUXnameseq");
+@z
+
+@x
+@!save_scanner_status:small_number; {|scanner_status| upon entry}
+@!b:pool_pointer; {base of temporary string}
+begin c:=cur_chr; @<Scan the argument for command |c|@>;
+@y
+@!save_scanner_status:small_number; {|scanner_status| upon entry}
+@!b:pool_pointer; {base of temporary string}
+@!dsize:integer;
+@!saved_val,digit_base,sign:integer;
+@!min_val,max_val,offset:integer;
+begin c:=cur_chr; @<Scan the argument for command |c|@>;
+@z
+
+@x
+case c of
+number_code,roman_numeral_code: scan_int;
+@y
+case c of
+number_code,roman_numeral_code,cnumber_code,scnumber_code,ucnumber_code,
+fcnumber_code : scan_int;
+acnumber_code: @<scan and split the number@>;
+cjknumber_code:@<scan a CJK number with a possible selector and then split it@>;
+nameseq_code:@<scan a CJK name sequence number@>;
+@z
+
+@x
+roman_numeral_code: print_roman_int(cur_val);
+string_code:if cur_cs<>0 then sprint_cs(cur_cs)
+ else print_char(cur_chr);
+@y
+roman_numeral_code: print_roman_int(cur_val);
+cnumber_code: print_chinese_int(cur_val,lower_cdigit_base,false,false);
+scnumber_code: print_chinese_int(cur_val,lower_cdigit_base,true,false);
+ucnumber_code: print_chinese_int(cur_val,upper_cdigit_base,false,false);
+fcnumber_code: print_chinese_int(cur_val,upper_cdigit_base,false,true);
+acnumber_code: @<using full-width arabic characters to print a CJK number@>;
+cjknumber_code: @<print a CJK number with specified format@>;
+nameseq_code: @<print a CJK name sequence member@>;
+string_code:if cur_cs<>0 then sprint_cs(cur_cs)
+ else
+ if is_wchar(cur_chr) then print_wchar(cur_chr)
+ else print_char(cur_chr);
+@z
+
+@x
+font_name_code: begin print(font_name[cur_val]);
+ if font_size[cur_val]<>font_dsize[cur_val] then
+ begin print(" at "); print_scaled(font_size[cur_val]);
+ print("pt");
+ end;
+ end;
+@y
+font_name_code: begin
+ if cur_val <=font_max then begin
+ print(font_name[cur_val]);
+ if font_size[cur_val]<>font_dsize[cur_val] then
+ begin print(" at "); print_scaled(font_size[cur_val]);
+ print("pt");
+ end;
+ end
+ else begin
+ print("CFONT");
+ print(cface[cfont_face[cur_val]]);
+ dsize:=cfont_dsize[cur_val] div @"10000;
+ print_int(dsize);
+ if cfont_size[cur_val]<>cfont_dsize[cur_val] then
+ begin print(" at "); print_scaled(cfont_size[cur_val]);
+ print("pt");
+ end;
+ end;
+ end;
+@z
+
+@x
+if (cur_cmd>active_char)or(cur_chr>255) then {not a character}
+ begin m:=relax; n:=256;
+@y
+if (cur_cmd>active_char)or(cur_chr>65535) then {not a character}
+ begin m:=relax; n:=256; {values other than 256 will break latex.fmt}
+@z
+
+@x
+if (cur_cmd>active_char)or(cur_chr>255) then
+ begin cur_cmd:=relax; cur_chr:=256;
+ end;
+@y
+if (cur_cmd>active_char)or(cur_chr>65535) then
+ begin cur_cmd:=relax; cur_chr:=256; {values other than 256 will break latex.fmt}
+ end;
+@z
+
+@x
+ pack_job_name(".dvi");
+ while not b_open_out(dvi_file) do
+ prompt_file_name("file name for output",".dvi");
+@y
+ pack_job_name(".cdi");
+ while not b_open_out(dvi_file) do
+ prompt_file_name("file name for output",".cdi");
+@z
+
+@x
+@ Before we forget about the format of these tables, let's deal with two
+of \TeX's basic scanning routines related to font information.
+
+@<Declare procedures that scan font-related stuff@>=
+procedure scan_font_ident;
+var f:internal_font_number;
+@!m:halfword;
+begin @<Get the next non-blank non-call...@>;
+if cur_cmd=def_font then f:=cur_font
+else if cur_cmd=set_font then f:=cur_chr
+@y
+@ Before we forget about the format of these tables, let's deal with two
+of \TeX's basic scanning routines related to font information.
+
+TCW: handle the commands |def_cfont| and |set_cfont|.
+
+@<Declare procedures that scan font-related stuff@>=
+procedure scan_font_ident;
+var f:integer;
+@!m:halfword;
+begin @<Get the next non-blank non-call...@>;
+if cur_cmd=def_font then f:=cur_font
+else if cur_cmd=set_font or cur_cmd=set_cfont then f:=cur_chr
+@z
+
+@x
+bytes long, so it is in the range |0<=c<65536|. \TeX82 never uses this
+command, but it should come in handy for extensions of \TeX\ that deal
+with oriental languages.
+@y
+bytes long, so it is in the range |0<=c<65536|. \PUTeX\ uses this to typeset
+a CJK two-byte character.
+@z
+
+@x
+\yskip\hang|pre| 247 |i[1]| |num[4]| |den[4]| |mag[4]| |k[1]| |x[k]|.
+Beginning of the preamble; this must come at the very beginning of the
+file. Parameters |i|, |num|, |den|, |mag|, |k|, and |x| are explained below.
+@y
+\yskip\hang|pre| 247 |i[1]| |c[1]| |num[4]| |den[4]| |mag[4]| |k[1]| |x[k]|.
+Beginning of the preamble; this must come at the very beginning of the
+file. Parameters |i|, |c|, |num|, |den|, |mag|, |k|, and |x| are explained below.
+@z
+
+@x
+\yskip\hang|post_post| 249. Ending of the postamble, see below.
+
+\yskip\noindent Commands 250--255 are undefined at the present time.
+@y
+\yskip\hang|post_post| 249. Ending of the postamble, see below.
+
+\yskip\hang|cfnt| 250 |k[2]|. Set |cf:=k|. \PUTeX\ uses this command for CJK font
+numbers in the range |0<=k<65535|.
+
+\yskip\hang|cfnt_def| 251 |k[2]| |l[1]| |n[l]| |c[1]| |s[4]| |ds[4]| |wt[2]| |y[1]|
+ |w[4]| |h[4]| |d[4]| |fw[4]| |fh[4]| |fd[4]|. Define CJK font |k|, where |0<=k<65536|, see below.
+
+\yskip\noindent Commands 252--255 are undefined at the present time.
+@z
+
+@x
+@d set1=128 {typeset a character and move right}
+@y
+@d set1=128 {typeset a character and move right}
+@d set2=129 {typeset a two-byte CJK character and move right}
+@d set4=131 {typeset a four-byte CJK character and move right}
+@z
+
+@x
+@d post_post=249 {postamble ending}
+@y
+@d post_post=249 {postamble ending}
+@d cfnt=250 {set current chinese font}
+@d cfnt_def=251 {define the meaning of a chinese font}
+@z
+
+@x
+$$\hbox{|@!i[1]| |@!num[4]| |@!den[4]| |@!mag[4]| |@!k[1]| |@!x[k]|.}$$
+The |i| byte identifies \.{DVI} format; currently this byte is always set
+to~2. (The value |i=3| is currently used for an extended format that
+allows a mixture of right-to-left and left-to-right typesetting.
+Some day we will set |i=4|, when \.{DVI} format makes another
+incompatible change---perhaps in the year 2048.)
+@y
+$$\hbox{|@!i[1]| |@!c[1]| |@!num[4]| |@!den[4]| |@!mag[4]| |@!k[1]| |@!x[k]|.}$$
+The |i| byte identifies \.{CDI} format; currently this byte is always set
+to~100. (Some day we will set |i=101|, when \.{CDI} format makes another
+incompatible change---perhaps in the year 2048.)
+
+The |c| byte identifies the default character code set of document. Currently, the following
+code value is defined:
+
+ 0: USC2 (Unicode, not supported yet)
+
+ 1: Big5 (Traditional Chinese used in Taiwan and Hong Kong)
+
+ 2: GBK (Simplified Chinese used in PRC and Singapore)
+@z
+
+@x
+@d id_byte=2 {identifies the kind of \.{DVI} files described here}
+@y
+@d id_byte=100 {identifies the kind of \.{DVI} files described here}
+@z
+
+@x
+@ Here's a procedure that outputs a font definition. Since \TeX82 uses at
+most 256 different fonts per job, |fnt_def1| is always used as the command code.
+@y
+@ Here's a procedure that outputs a font definition. Since \TeX82 uses at
+most 256 different fonts per job, |fnt_def1| is always used as the command code.
+
+TCW: the procedure |dvi_cfont_def| outputs a chinese font definition.
+@z
+
+@x
+@<Output the font name whose internal number is |f|@>;
+end;
+@y
+@<Output the font name whose internal number is |f|@>;
+end;
+
+procedure dvi_cfont_def (f:internal_cfont_number);
+var k:pool_pointer;
+ j:integer;
+begin
+j:=cfont_face[f];
+dvi_out(cfnt_def);
+dvi_out((f-cfont_base-1) div 256); dvi_out((f-cfont_base-1) mod 256);
+{Output the CJK font face name}
+dvi_out(length(cface_name[j]));
+for k:= str_start[cface_name[j]] to str_start[cface_name[j]+1] - 1 do dvi_out(str_pool[k]);
+dvi_out(cface_charset[j]);
+dvi_four(cfont_size[f]);
+dvi_four(cfont_dsize[f]);
+dvi_out(cface_weight[j] div 256); dvi_out(cface_weight[j] mod 256);
+dvi_out(cface_style[j]);
+dvi_four(cfont_width[f]);
+dvi_four(cfont_height[f]);
+dvi_four(cfont_depth[f]);
+dvi_four(cface_fw_width[j]);
+dvi_four(cface_fw_height[j]);
+dvi_four(cface_fw_depth[j]);
+end;
+@z
+
+@x
+dvi_h:=0; dvi_v:=0; cur_h:=h_offset; dvi_f:=null_font;
+@y
+dvi_h:=0; dvi_v:=0; cur_h:=h_offset; dvi_f:=null_font; dvi_cf:=null_cfont;
+@z
+
+@x
+ begin dvi_out(pre); dvi_out(id_byte); {output the preamble}
+@y
+ begin dvi_out(pre); dvi_out(id_byte);
+ doc_charset:=pux_charset; dvi_out(doc_charset); {output the preamble}
+@z
+
+@x
+ print(" TeX output "); print_int(year); print_char(".");
+@y
+ print(" PUTeX output "); print_int(year); print_char(".");
+@z
+
+%% MMM
+@x
+@<Output node |p| for |hlist_out|...@>=
+reswitch: if is_char_node(p) then
+ begin synch_h; synch_v;
+ repeat f:=font(p); c:=character(p);
+ if f<>dvi_f then @<Change font |dvi_f| to |f|@>;
+ if font_ec[f]>=qo(c) then if font_bc[f]<=qo(c) then
+ if char_exists(orig_char_info(f)(c)) then {N.B.: not |char_info|}
+ begin if c>=qi(128) then dvi_out(set1);
+ dvi_out(qo(c));@/
+ cur_h:=cur_h+char_width(f)(orig_char_info(f)(c));
+ goto continue;
+ end;
+ if mltex_enabled_p then
+ @<Output a substitution, |goto continue| if not possible@>;
+continue:
+ p:=link(p);
+ until not is_char_node(p);
+ dvi_h:=cur_h;
+ end
+else @<Output the non-|char_node| |p| for |hlist_out|
+ and move to the next node@>
+@y
+@<Output node |p| for |hlist_out|...@>=
+reswitch: if is_char_node(p) then
+ begin synch_h; synch_v;
+ repeat f:=font(p); c:=character(p);
+ if (is_wchar(c)) then begin
+ if f<>dvi_cf then @<Change font |dvi_cf| to |f|@>;
+ dvi_out(set2); dvi_out(c div 256); dvi_out(c mod 256);
+ cur_h:=cur_h+cfont_width[f];
+ end
+ else begin
+ if f<>dvi_f then @<Change font |dvi_f| to |f|@>;
+ if font_ec[f]>=qo(c) then if font_bc[f]<=qo(c) then
+ if char_exists(orig_char_info(f)(c)) then {N.B.: not |char_info|}
+ if c>=qi(128) then dvi_out(set1);
+ dvi_out(qo(c));@/
+ cur_h:=cur_h+char_width(f)(orig_char_info(f)(c));
+ goto continue;
+ end;
+ if mltex_enabled_p then
+ @<Output a substitution, |goto continue| if not possible@>;
+continue:
+ p:=link(p);
+ until not is_char_node(p);
+ dvi_h:=cur_h;
+ end
+else @<Output the non-|char_node| |p| for |hlist_out|
+ and move to the next node@>
+@z
+
+@x
+ dvi_out(post_post); dvi_four(last_bop); dvi_out(id_byte);@/
+@y
+ @<Output the CJK font definitions for all fonts that were used@>;
+ dvi_out(post_post); dvi_four(last_bop); dvi_out(doc_charset); dvi_out(id_byte);@/
+@z
+
+@x
+@<Incorporate character dimensions into the dimensions of the hbox...@>=
+begin f:=font(p); i:=char_info(f)(character(p)); hd:=height_depth(i);
+x:=x+char_width(f)(i);@/
+s:=char_height(f)(hd);@+if s>h then h:=s;
+s:=char_depth(f)(hd);@+if s>d then d:=s;
+p:=link(p);
+end
+@y
+@<Incorporate character dimensions into the dimensions of the hbox...@>=
+begin f:=font(p); c:=character(p);
+if (is_wchar(c)) then begin
+ x:=x+cfont_width[f];@/
+ s:=cfont_height[f];@+if s>h then h:=s;
+ s:=cfont_depth[f];@+if s>d then d:=s;
+ end
+else begin
+ i:=char_info(f)(c); hd:=height_depth(i);
+ x:=x+char_width(f)(i);@/
+ s:=char_height(f)(hd);@+if s>h then h:=s;
+ s:=char_depth(f)(hd);@+if s>d then d:=s;
+ end;
+p:=link(p);
+end
+@z
+
+@x
+font_in_short_display:=null_font; short_display(list_ptr(r)); print_ln;@/
+@y
+font_in_short_display:=null_font; cfont_in_short_display:=null_cfont;@/
+short_display(list_ptr(r)); print_ln;@/
+@z
+
+@x
+ if (is_char_node(p))and(link(p)=null) then
+ begin f:=font(p); v:=char_width(f)(char_info(f)(character(p)));
+ if v<>width(b) then link(p):=new_kern(width(b)-v);
+ end;
+@y
+ if (is_char_node(p))and(link(p)=null) then
+ begin
+ f:=font(p);
+ if is_wchar_node(p) then
+ v:=cfont_width[f]
+ else
+ v:=char_width(f)(char_info(f)(character(p)));
+ if v<>width(b) then link(p):=new_kern(width(b)-v);
+ end;
+@z
+
+@x
+if is_char_node(v) then
+ begin f:=font(v);
+ break_width[1]:=break_width[1]-char_width(f)(char_info(f)(character(v)));
+ end
+@y
+if is_char_node(v) then
+ begin f:=font(v);
+ if is_wchar_node(v) then
+ break_width[1]:=break_width[1]-cfont_width[f]
+ else
+ break_width[1]:=break_width[1]-char_width(f)(char_info(f)(character(v)));
+ end
+@z
+
+@x
+ ligature_node: begin f:=font(lig_char(v));@/
+ break_width[1]:=@|break_width[1]-
+ char_width(f)(char_info(f)(character(lig_char(v))));
+ end;
+@y
+ ligature_node: begin f:=font(lig_char(v));@/
+ if is_wchar(character(lig_char(v))) then
+ break_width[1]:=@|break_width[1]-cfont_width[f]
+ else
+ break_width[1]:=@|break_width[1]-
+ char_width(f)(char_info(f)(character(lig_char(v))));
+ end;
+@z
+
+@x
+if is_char_node(s) then
+ begin f:=font(s);
+ break_width[1]:=@|break_width[1]+char_width(f)(char_info(f)(character(s)));
+ end
+@y
+if is_char_node(s) then
+ begin f:=font(s);
+ if is_wchar_node(s) then
+ break_width[1]:=break_width[1]+cfont_width[f]
+ else
+ break_width[1]:=@|break_width[1]+char_width(f)(char_info(f)(character(s)));
+ end
+@z
+
+@x
+ ligature_node: begin f:=font(lig_char(s));
+ break_width[1]:=break_width[1]+
+ char_width(f)(char_info(f)(character(lig_char(s))));
+ end;
+@y
+ ligature_node: begin f:=font(lig_char(s));@/
+ if is_wchar(character(lig_char(s))) then
+ break_width[1]:=break_width[1]+cfont_width[f]
+ else
+ break_width[1]:=break_width[1]+
+ char_width(f)(char_info(f)(character(lig_char(s))));
+ end;
+@z
+
+@x
+font_in_short_display:=null_font
+@y
+cfont_in_short_display:=null_cfont; font_in_short_display:=null_font
+@z
+
+@x
+ligature_node: begin f:=font(lig_char(cur_p));
+ act_width:=act_width+char_width(f)(char_info(f)(character(lig_char(cur_p))));
+ end;
+@y
+ligature_node: begin f:=font(lig_char(cur_p));
+ if is_wchar(character(lig_char(cur_p))) then
+ act_width:=act_width+cfont_width[f]
+ else
+ act_width:=act_width+char_width(f)(char_info(f)(character(lig_char(cur_p))));
+ end;
+@z
+
+@x
+repeat f:=font(cur_p);
+act_width:=act_width+char_width(f)(char_info(f)(character(cur_p)));
+cur_p:=link(cur_p);
+until not is_char_node(cur_p);
+end
+@y
+repeat f:=font(cur_p);
+if is_wchar_node(cur_p) then
+ act_width:=act_width+cfont_width[f]
+else
+ act_width:=act_width+char_width(f)(char_info(f)(character(cur_p)));
+cur_p:=link(cur_p);
+until not is_char_node(cur_p);
+end
+@z
+
+@x
+if is_char_node(s) then
+ begin f:=font(s);
+ disc_width:=disc_width+char_width(f)(char_info(f)(character(s)));
+ end
+@y
+if is_char_node(s) then
+ begin f:=font(s);
+ if is_wchar_node(s) then
+ disc_width:=disc_width+cfont_width[f]
+ else
+ disc_width:=disc_width+char_width(f)(char_info(f)(character(s)));
+ end
+@z
+
+@x
+ ligature_node: begin f:=font(lig_char(s));
+ disc_width:=disc_width+
+ char_width(f)(char_info(f)(character(lig_char(s))));
+ end;
+@y
+ ligature_node: begin f:=font(lig_char(s));
+ if is_wchar(character(lig_char(s))) then
+ disc_width:=disc_width+cfont_width[f]
+ else
+ disc_width:=disc_width+
+ char_width(f)(char_info(f)(character(lig_char(s))));
+ end;
+@z
+
+@x
+if is_char_node(s) then
+ begin f:=font(s);
+ act_width:=act_width+char_width(f)(char_info(f)(character(s)));
+ end
+@y
+if is_char_node(s) then
+ begin f:=font(s);
+ if is_wchar_node(s) then
+ act_width:=act_width+cfont_width[f]
+ else
+ act_width:=act_width+char_width(f)(char_info(f)(character(s)));
+ end
+@z
+
+@x
+ ligature_node: begin f:=font(lig_char(s));
+ act_width:=act_width+
+ char_width(f)(char_info(f)(character(lig_char(s))));
+ end;
+@y
+ ligature_node: begin f:=font(lig_char(s));
+ if is_wchar(character(lig_char(s))) then
+ act_width:=act_width+cfont_width[f]
+ else
+ act_width:=act_width+
+ char_width(f)(char_info(f)(character(lig_char(s))));
+ end;
+@z
+
+@x
+ char_num: begin scan_char_num; cur_chr:=cur_val; cur_cmd:=char_given;
+ goto reswitch;
+ end;
+ spacer,right_brace: begin if n>1 then @<Enter a hyphenation exception@>;
+@y
+ char_num: begin scan_char_num; cur_chr:=cur_val; cur_cmd:=char_given;
+ goto reswitch;
+ end;
+ pux_char_given:@<Give improper hyphenation error for Chinese characters inside@>;
+ pux_char_num: begin scan_wchar_num; cur_chr:=cur_val; cur_cmd:=pux_char_given;
+ goto reswitch;
+ end;
+ spacer,right_brace: begin if n>1 then @<Enter a hyphenation exception@>;
+@z
+
+@x
+if cur_chr="-" then @<Append the value |n| to list |p|@>
+else begin if lc_code(cur_chr)=0 then
+ begin print_err("Not a letter");
+@.Not a letter@>
+ help2("Letters in \hyphenation words must have \lccode>0.")@/
+ ("Proceed; I'll ignore the character I just read.");
+ error;
+ end
+ else if n<63 then
+ begin incr(n); hc[n]:=lc_code(cur_chr);
+ end;
+ end
+@y
+if cur_chr="-" then @<Append the value |n| to list |p|@>
+else begin if is_wchar(cur_chr) then
+ begin print_err("Chinese character can't appear here");
+@.Not a letter@>
+ help2("Letters in \hyphenation words can't be Chinese characters.")@/
+ ("Proceed; I'll ignore the character I just read.");
+ error;
+ end
+ else if lc_code(cur_chr)=0 then
+ begin print_err("Not a letter");
+@.Not a letter@>
+ help2("Letters in \hyphenation words must have \lccode>0.")@/
+ ("Proceed; I'll ignore the character I just read.");
+ error;
+ end
+ else if n<63 then
+ begin incr(n); hc[n]:=lc_code(cur_chr);
+ end;
+ end
+@z
+
+@x
+@d main_loop=70 {go here to typeset a string of consecutive characters}
+@y
+@d main_loop=70 {go here to typeset a string of consecutive characters}
+@d main_loop_wchar=130 {go here to typeset a string of consecutive double-byte characters}
+@d save_cur_wchar=132 {go here to typeset a double-byte characters}
+@d next_is_a_char=133 {go here if next token is a single-byte character}
+@d fetch_next_tok=134 {go here to fetch next token}
+@z
+
+@x
+@t\4@>@<Declare the procedure called |handle_right_brace|@>@;
+procedure main_control; {governs \TeX's activities}
+@y
+@t\4@>@<Declare the procedure called |handle_right_brace|@>@;
+procedure main_control; {governs \TeX's activities}
+@z
+
+@x
+label big_switch,reswitch,main_loop,main_loop_wrapup,
+@y
+label big_switch,reswitch,main_loop_wchar,main_loop_wchar+1,save_cur_wchar,
+ next_is_a_char,fetch_next_tok,main_loop,main_loop+1,
+ main_loop_wrapup,main_loop_lookahead+2,
+@z
+
+@x
+var@!t:integer; {general-purpose temporary variable}
+begin if every_job<>null then begin_token_list(every_job,every_job_text);
+big_switch: get_x_token;@/
+@y
+var@!t:integer; {general-purpose temporary variable}
+begin if every_job<>null then begin_token_list(every_job,every_job_text);
+@<Initialization of global variables done in the |main_control| procedure@>@;
+big_switch: get_x_token;@/
+@z
+
+@x
+hmode+letter,hmode+other_char,hmode+char_given: goto main_loop;
+@y
+hmode+letter,hmode+other_char,hmode+char_given:
+ if is_wchar(cur_chr) then goto main_loop_wchar
+ else goto main_loop;
+hmode+pux_char_given: goto main_loop_wchar;
+@z
+
+@x
+hmode+char_num: begin scan_char_num; cur_chr:=cur_val; goto main_loop;@+end;
+hmode+no_boundary: begin get_x_token;
+ if (cur_cmd=letter)or(cur_cmd=other_char)or(cur_cmd=char_given)or
+ (cur_cmd=char_num) then cancel_boundary:=true;
+ goto reswitch;
+ end;
+@y
+hmode+char_num: begin scan_char_num; cur_chr:=cur_val; goto main_loop;@+end;
+hmode+pux_char_num: begin scan_wchar_num; cur_chr:=cur_val; goto main_loop_wchar;@+end;
+hmode+no_boundary: begin get_x_token;
+ if (cur_cmd=letter)or(cur_cmd=other_char)or(cur_cmd=char_given)or
+ (cur_cmd=char_num)or(cur_cmd=pux_char_num)or(cur_cmd=pux_char_given) then cancel_boundary:=true;
+ goto reswitch;
+ end;
+@z
+
+@x
+hmode+spacer: if space_factor=1000 then goto append_normal_space
+ else app_space;
+hmode+ex_space,mmode+ex_space: goto append_normal_space;
+@y
+@t\4@>@<Cases of |main_control| that handle spacer@>@;
+@z
+
+@x
+main_loop:@<Append character |cur_chr| and the following characters (if~any)
+@y
+main_loop_wchar:@<Append double-byte character |cur_chr| and the following double-byte characters
+ (if~any) to the current hlist in the current font; |goto main_loop| when a single-byte character
+ has been fetched; |goto reswitch| when a non-character has been fetched@>;
+main_loop:@<Append character |cur_chr| and the following characters (if~any)
+@z
+
+@x
+@d adjust_space_factor==@t@>@;@/
+ main_s:=sf_code(cur_chr);
+@y
+@d adjust_space_factor==@t@>@;@/
+ if (cur_chr < 256) then main_s:=sf_code(cur_chr)
+ else main_s:=1000;
+@z
+
+@x
+adjust_space_factor;@/
+main_f:=cur_font;
+@y
+main_cf:=cur_cfont; {in case the first letter is not a Chinese character}
+@<If the preceding node is wchar node, then append a cespace@>;
+main_loop+1:adjust_space_factor; main_f:=cur_font;
+@z
+
+@x
+get_next; {set only |cur_cmd| and |cur_chr|, for speed}
+if cur_cmd=letter then goto main_loop_lookahead+1;
+if cur_cmd=other_char then goto main_loop_lookahead+1;
+if cur_cmd=char_given then goto main_loop_lookahead+1;
+x_token; {now expand and set |cur_cmd|, |cur_chr|, |cur_tok|}
+if cur_cmd=letter then goto main_loop_lookahead+1;
+if cur_cmd=other_char then goto main_loop_lookahead+1;
+if cur_cmd=char_given then goto main_loop_lookahead+1;
+if cur_cmd=char_num then
+ begin scan_char_num; cur_chr:=cur_val; goto main_loop_lookahead+1;
+ end;
+if cur_cmd=no_boundary then bchar:=non_char;
+cur_r:=bchar; lig_stack:=null; goto main_lig_loop;
+main_loop_lookahead+1: adjust_space_factor;
+fast_get_avail(lig_stack); font(lig_stack):=main_f;
+cur_r:=qi(cur_chr); character(lig_stack):=cur_r;
+if cur_r=false_bchar then cur_r:=non_char {this prevents spurious ligatures}
+@y
+@<Look ahead for next character. If it is a wide character then append
+ a cespace, or leave |lig_stack| empty if there's no character there@>
+@z
+
+@x
+else temp_ptr:=new_param_glue(space_skip_code);
+link(tail):=temp_ptr; tail:=temp_ptr;
+goto big_switch
+@y
+else temp_ptr:=new_param_glue(space_skip_code);
+link(tail):=temp_ptr; tail:=temp_ptr;
+if pux_xspace=0 then goto reswitch else goto big_switch
+@z
+
+@x
+hbox_group: package(0);
+adjusted_hbox_group: begin adjust_tail:=adjust_head; package(0);
+ end;
+@y
+hbox_group: @<Setup |hbox_tail| and package@>;
+adjusted_hbox_group: begin adjust_tail:=adjust_head;
+ @<Setup |hbox_tail| and package@>;
+ end;
+@z
+
+@x
+vmode+start_par: new_graf(cur_chr>0);
+vmode+letter,vmode+other_char,vmode+char_num,vmode+char_given,
+ vmode+math_shift,vmode+un_hbox,vmode+vrule,
+@y
+vmode+start_par: new_graf(cur_chr>0);
+vmode+letter,vmode+other_char,vmode+char_num,vmode+char_given,
+ vmode+pux_char_num,vmode+pux_char_given,
+ vmode+math_shift,vmode+un_hbox,vmode+vrule,
+@z
+
+@x
+begin if tail<>head then
+ begin if is_char_node(tail) then p:=tail
+@y
+begin if tail<>head then
+ begin if is_char_node(tail) and not is_wchar_node(tail) then p:=tail
+@z
+
+@x
+reswitch: if is_char_node(p) then
+ begin f:=font(p); d:=char_width(f)(char_info(f)(character(p)));
+ goto found;
+ end;
+@y
+reswitch: if is_char_node(p) then
+ begin f:=font(p);
+ if is_wchar_node(p) then
+ d:=cfont_width[f]
+ else
+ d:=char_width(f)(char_info(f)(character(p)));
+ goto found;
+ end;
+@z
+
+@x
+letter,other_char,char_given: begin c:=ho(math_code(cur_chr));
+ if c=@'100000 then
+ begin @<Treat |cur_chr| as an active character@>;
+ goto restart;
+ end;
+ end;
+@y
+letter,other_char,char_given: begin
+ if is_wchar(cur_chr) then begin
+ print_err("Chinese character is ignored in math mode");
+ help1("Did you forget putting it into an \hbox?");
+ error;
+ goto restart;
+ end
+ else begin
+ c:=ho(math_code(cur_chr));
+ if c=@'100000 then
+ begin @<Treat |cur_chr| as an active character@>;
+ goto restart;
+ end;
+ end;
+ end;
+@z
+
+@x
+char_num: begin scan_char_num; cur_chr:=cur_val; cur_cmd:=char_given;
+ goto reswitch;
+ end;
+@y
+char_num: begin scan_char_num; cur_chr:=cur_val; cur_cmd:=char_given;
+ goto reswitch;
+ end;
+pux_char_num: begin scan_wchar_num; cur_chr:=cur_val; cur_cmd:=pux_char_given;
+ goto reswitch;
+ end;
+pux_char_given:begin print_err("Chinese character is ignored in math mode");
+ help1("Did you forget putting it into an \hbox?");
+ error;
+ goto restart;
+ end;
+@z
+
+@x
+mmode+letter,mmode+other_char,mmode+char_given:
+ set_math_char(ho(math_code(cur_chr)));
+@y
+mmode+letter,mmode+other_char,mmode+char_given:
+ if is_wchar(cur_chr) then begin
+ print_err("Chinese character is ignored in math mode");
+ help1("Did you forget putting it into an \hbox?");
+ error;
+ end
+ else
+ set_math_char(ho(math_code(cur_chr)));
+@z
+
+@x
+ letter,other_char: cur_val:=del_code(cur_chr);
+@y
+ letter,other_char:
+ if is_wchar(cur_chr) then
+ cur_val:=-1
+ else
+ cur_val:=del_code(cur_chr);
+@z
+
+@x
+mmode+math_shift: if cur_group=math_shift_group then after_math
+ else off_save;
+@y
+mmode+math_shift: if cur_group=math_shift_group then begin
+ after_math;
+ if math_mode_save<0 then begin
+ get_x_token;
+ @<If the token is a wide character, then append a cspace@>;
+ goto reswitch;
+ end;
+ end
+ else off_save;
+@z
+
+@x
+tail_append(new_math(math_surround,after));
+space_factor:=1000; unsave;
+end
+@y
+math_mode_save:=m;
+tail_append(new_math(math_surround,after));
+space_factor:=1000; unsave;
+end
+@z
+
+@x
+any_mode(set_font),
+any_mode(def_font),
+@y
+any_mode(set_font),
+any_mode(def_font),
+any_mode(set_cfont),
+any_mode(pux_cface_def),
+any_mode(pux_face_match),
+any_mode(pux_font_match),
+any_mode(pux_set_cface),
+any_mode(puxg_assign_flag),
+any_mode(puxg_assign_int),
+any_mode(pux_get_int),
+any_mode(pux_set_cface_attrib),
+any_mode(pux_set_cfont_attrib),
+any_mode(pux_range_catcode),
+any_mode(pux_range_type_code),
+any_mode(pux_split_number),
+any_mode(puxg_assign_space),
+any_mode(pux_set_default_cface),
+any_mode(pux_dump_font_info),
+@z
+
+@x
+@t\4@>@<Declare subprocedures for |prefixed_command|@>@t@>@;@/
+procedure prefixed_command;
+@y
+@t\4@>@<Declare PUTeX subprocedures for |prefixed_command|@>@t@>@;@/
+@t\4@>@<Declare subprocedures for |prefixed_command|@>@t@>@;@/
+procedure prefixed_command;
+@z
+
+@x
+@!n:integer; {ditto}
+@!e:boolean; {should a definition be expanded? or was \.{\\let} not done?}
+@y
+@!n:integer; {ditto}
+@!e:boolean; {should a definition be expanded? or was \.{\\let} not done?}
+@<Other variables used by the procedure |prefixed_command|@>@;
+@z
+
+@x
+set_font: define(cur_font_loc,data,cur_chr);
+@y
+set_font: begin define(cur_font_loc,data,cur_chr);@/
+ @<Set the matching CJK font@>;
+ end;
+@z
+
+@x
+@d toks_def_code=6 {|shorthand_def| for \.{\\toksdef}}
+@y
+@d toks_def_code=6 {|shorthand_def| for \.{\\toksdef}}
+@d pux_char_def_code=7 {|shorthand_def| for \.{\\PUXchardef}}
+@z
+
+@x
+primitive("toksdef",shorthand_def,toks_def_code);@/
+@!@:toks_def_}{\.{\\toksdef} primitive@>
+@y
+primitive("toksdef",shorthand_def,toks_def_code);@/
+@!@:toks_def_}{\.{\\toksdef} primitive@>
+primitive("PUXchardef",shorthand_def,pux_char_def_code);@/
+@!@:pux_char_def_}{\.{\\toksdef} primitive@>
+@z
+
+@x
+ mu_skip_def_code: print_esc("muskipdef");
+ char_sub_def_code: print_esc("charsubdef");
+ othercases print_esc("toksdef")
+@y
+ mu_skip_def_code: print_esc("muskipdef");
+ char_sub_def_code: print_esc("charsubdef");
+ toks_def_code: print_esc("toksdef");
+ othercases print_esc("PUXchardef")
+@z
+
+@x
+ case n of
+ char_def_code: begin scan_char_num; define(p,char_given,cur_val);
+ end;
+ math_char_def_code: begin scan_fifteen_bit_int; define(p,math_given,cur_val);
+ end;
+ othercases begin scan_eight_bit_int;
+@y
+ case n of
+ char_def_code: begin scan_char_num; define(p,char_given,cur_val);
+ end;
+ math_char_def_code: begin scan_fifteen_bit_int; define(p,math_given,cur_val);
+ end;
+ pux_char_def_code: begin scan_wchar_num; define(p,pux_char_given,cur_val);
+ end;
+ othercases begin scan_eight_bit_int;
+@z
+
+@x
+primitive("catcode",def_code,cat_code_base);
+@!@:cat_code_}{\.{\\catcode} primitive@>
+@y
+primitive("catcode",def_code,cat_code_base);
+@!@:cat_code_}{\.{\\catcode} primitive@>
+primitive("PUXcatcode",def_code,pux_cat_code_base);
+@!@:pux_cat_code_}{\.{\\PUXcatcode} primitive@>
+primitive("PUXtypecode",def_code,pux_type_code_base);
+@!@:pux_type_code_base_}{\.{\\PUXtypecode} primitive@>
+primitive("PUXlocalnames",def_code,pux_local_names_base);
+@!@:pux_local_names_base_}{\.{\\PUXlocalnames} primitive@>
+@z
+
+@x
+ else if chr_code=math_code_base then print_esc("mathcode")
+@y
+ else if chr_code=pux_cat_code_base then print_esc("PUXcatcode")
+ else if chr_code=pux_type_code_base then print_esc("PUXtypecode")
+ else if chr_code=pux_local_names_base then print_esc("PUXlocalnames")
+ else if chr_code=math_code_base then print_esc("mathcode")
+@z
+
+@x
+ p:=cur_chr; scan_char_num; p:=p+cur_val; scan_optional_equals;
+ scan_int;
+@y
+ p:=cur_chr;
+ if p = pux_cat_code_base then
+ begin scan_wchar_num; p := cat_code_base;
+ end
+ else if p = pux_type_code_base then scan_wchar_num
+ else if p = pux_local_names_base then scan_eight_bit_int
+ else
+ scan_char_num;
+ p:=p+cur_val; scan_optional_equals;
+ if p=pux_local_names_base then scan_wchar_num
+ else scan_int;
+@z
+
+@x
+else if cur_chr=math_code_base then n:=@'100000
+@y
+else if cur_chr=pux_cat_code_base then n:=max_char_code
+else if cur_chr=pux_type_code_base then n:=max_type_code
+else if cur_chr=pux_local_names_base then n:=65535
+else if cur_chr=math_code_base then n:=@'100000
+@z
+
+@x
+set_box: begin scan_eight_bit_int;
+ if global then n:=256+cur_val@+else n:=cur_val;
+ scan_optional_equals;
+ if set_box_allowed then scan_box(box_flag+n)
+ else begin print_err("Improper "); print_esc("setbox");
+@y
+set_box: begin scan_eight_bit_int;
+ if global then n:=256+cur_val@+else n:=cur_val;
+ scan_optional_equals;
+ if set_box_allowed then begin
+ in_set_box:=true;
+ scan_box(box_flag+n);
+ in_set_box:=false;
+ end
+ else begin print_err("Improper "); print_esc("setbox");
+@z
+
+@x
+procedure new_font(@!a:small_number);
+label common_ending;
+var u:pointer; {user's font identifier}
+@!s:scaled; {stated ``at'' size, or negative of scaled magnification}
+@!f:internal_font_number; {runs through existing fonts}
+@!t:str_number; {name for the frozen font identifier}
+@!old_setting:0..max_selector; {holds |selector| setting}
+begin if job_name=0 then open_log_file;
+ {avoid confusing \.{texput} with the font name}
+@.texput@>
+get_r_token; u:=cur_cs;
+if u>=hash_base then t:=text(u)
+else if u>=single_base then
+ if u=null_cs then t:="FONT"@+else t:=u-single_base
+else begin old_setting:=selector; selector:=new_string;
+ print("FONT"); print(u-active_base); selector:=old_setting;
+@.FONTx@>
+ str_room(1); t:=make_string;
+ end;
+define(u,set_font,null_font); scan_optional_equals; scan_file_name;
+@<Scan the font size specification@>;
+@<If this font has already been loaded, set |f| to the internal
+ font number and |goto common_ending|@>;
+f:=read_font_info(u,cur_name,cur_area,s);
+common_ending: equiv(u):=f; eqtb[font_id_base+f]:=eqtb[u]; font_id_text(f):=t;
+end;
+@y
+@<Declare the function called |fw_times_sd|@>@;
+@<Declare the function called |find_cface_num|@>@;
+@<Declare the procedure called |check_cfont|@>@;
+@<Declare the procedure called |make_cfont|@>@;
+procedure new_font(@!a:small_number);
+label common_ending;
+var u:pointer; {user's font identifier}
+@!j,k:pool_pointer;
+@!s:scaled; {stated ``at'' size, or negative of scaled magnification}
+@!f:internal_font_number; {runs through existing fonts}
+@!t:str_number; {name for the frozen font identifier}
+@!old_setting:0..max_selector; {holds |selector| setting}
+@!flushable_string:str_number; {string not yet referenced}
+@<Other local variables used by procedure |new_font|@>@;
+begin if job_name=0 then open_log_file;
+ {avoid confusing \.{texput} with the font name}
+@.texput@>
+get_r_token; u:=cur_cs;
+if u>=hash_base then t:=text(u)
+else if u>=single_base then
+ if u=null_cs then t:="FONT"@+else t:=u-single_base
+else begin old_setting:=selector; selector:=new_string;
+ print("FONT"); print(u-active_base); selector:=old_setting;
+@.FONTx@>
+ str_room(1); t:=make_string;
+ end;
+scan_optional_equals; scan_file_name;@/
+@<Scan the font size specification@>;
+if (length(cur_name) > 5) then
+ begin
+ j:=str_start[cur_name];
+ if (str_pool[j]='C' and str_pool[j+1]='F' and str_pool[j+2]='O'
+ and str_pool[j+3]='N' and str_pool[j+4]='T') then
+ @<Define a CJK font and then goto |common_ending|@>;
+ end;
+define(u,set_font,null_font);
+@<If this font has already been loaded, set |f| to the internal
+ font number and |goto common_ending|@>;
+f:=read_font_info(u,cur_name,cur_area,s);
+common_ending: equiv(u):=f; eqtb[font_id_base+f]:=eqtb[u]; font_id_text(f):=t;
+end;
+@z
+
+@x
+@!t:halfword; {token}
+@!c:eight_bits; {character code}
+begin b:=cur_chr; p:=scan_toks(false,false); p:=link(def_ref);
+@y
+@!t:halfword; {token}
+@!c:quarterword; {character code}
+begin b:=cur_chr; p:=scan_toks(false,false); p:=link(def_ref);
+@z
+
+@x
+@<Change the case of the token in |p|, if a change is appropriate@>=
+t:=info(p);
+if t<cs_token_flag+single_base then
+ begin c:=t mod 256;
+ if equiv(b+c)<>0 then info(p):=t-c+equiv(b+c);
+ end
+@y
+@<Change the case of the token in |p|, if a change is appropriate@>=
+t:=info(p);
+if t<cs_token_flag+single_base then
+ begin c:=t mod 65536;
+ if c < 256 then {only convert the single-byte char}
+ if equiv(b+c)<>0 then info(p):=t-c+equiv(b+c);
+ end
+@z
+
+@x
+@<Dump the font information@>;
+@y
+@<Dump the font information@>;
+@<Dump the CJK font face information@>;
+@<Dump the face matching table@>;
+@<Dump the CJK font information@>;
+@z
+
+@x
+@<Undump the font information@>;
+@y
+@<Undump the font information@>;
+@<Undump the CJK font face information@>;
+@<Unump the face matching table@>;
+@<Undump the CJK font information@>;
+@z
+
+@x
+15: begin font_in_short_display:=null_font; short_display(n);
+@y
+15: begin font_in_short_display:=null_font; cfont_in_short_display:=null_cfont; short_display(n);
+@z
+
+@x
+@* \[55] Index.
+@y
+@* \[55] Introduction to \PUTeX.
+\PUTeX is an extension of \TeX to handle CJK character sets.
+
+@ @<Glob...@>=
+@!hi_byte, @!lo_byte : ASCII_code;
+{temp var for storing high byte and low byte of a double-byte character}
+@!db_char : quarterword; {temp var for storing a double-byte character}
+@!expand_char : boolean;
+@!doc_charset : eight_bits;
+@!char_val_flag : boolean;
+
+@ @<Set initial...@>=
+expand_char:=false;
+
+@ The default catcode for CJK characters is `letter'.
+
+@<Initialize table entries...@>=
+for k:= 256 to 65535 do
+ begin cat_code(k) := letter;
+ end;
+
+@ Initially, \PUTeX\ just set type codes for OT1 encoding.
+
+@d set_tail_forbidden(#) == set_type_code(#)(tail_forbidden)
+@d set_head_forbidden(#) == set_type_code(#)(head_forbidden)
+
+@<Initialize table entries...@>=
+set_tail_forbidden("(");
+set_tail_forbidden("[");
+set_tail_forbidden("{");@/
+set_head_forbidden("!");
+set_head_forbidden(")");
+set_head_forbidden(",");@/
+set_head_forbidden(".");
+set_head_forbidden(":");
+set_head_forbidden(";");@/
+set_head_forbidden("?");
+set_head_forbidden("]");
+set_head_forbidden("}");
+
+@ @<PUTeX routines...@>=
+function get_cat_code (ch:halfword) : halfword;
+var cat: halfword; {catcode}
+begin
+ if pux_wcharother <> 0 then
+ if ch > 255 then cat := other_char
+ else cat := cat_code(ch)
+ else cat := cat_code(ch);
+ get_cat_code := cat;
+end;
+
+@ @<Put each of \TeX's primitives into the hash table@>=
+primitive("PUXrangecatcode",pux_range_catcode,0);
+primitive("PUXrangetypecode",pux_range_type_code,0);
+
+@ @<Other variables used by the procedure |prefixed_command|@>=
+@!bc, ec: halfword; {the begin char and end char of code range}
+
+@ @<Assignments@>=
+pux_range_catcode, pux_range_type_code: begin
+ p:=cur_chr;
+ if cur_cmd = pux_range_catcode then begin
+ n:=max_char_code;
+ p:=cat_code_base;
+ end
+ else begin
+ n:=max_type_code;
+ p:=pux_type_code_base;
+ end;
+ scan_wchar_num; bc := cur_val;@/
+ scan_keyword("to");@/
+ scan_wchar_num; ec := cur_val;@/
+ scan_optional_equals;@/
+ scan_int;@/
+
+ if (bc = 0) or (ec = 0) or (ec < bc) then begin
+ if ec < bc then begin
+ print_err("Invalid range setting, ec < bc");
+ end;
+ help1("I'm going to ignore this command.");@/
+ error;
+ goto exit; @.Invalid range@>
+ end;
+
+ if (cur_val < 0) or (cur_val > n) then begin
+ print_err("Invalid catcode ("); print_int(cur_val);
+ print("), should be in the range 0..15");@/
+ help1("I'm going to ignore this command.");@/
+ error;
+ goto exit; @.Invalid code@>
+ end;
+
+ for k := bc to ec do define(p+k,data,cur_val);
+ end;
+
+@ @<Initialize table entries...@>=
+for k:=0 to 255 do local_names(k) := "?";
+
+@ @<PUTeX basic scanning routines@>=
+function scan_name: str_number;
+ begin
+ @<Get the next non-blank non-call token@>;
+ while cur_cmd=letter do
+ begin
+ if (is_wchar(cur_chr)) then append_wchar(cur_chr) else append_char(cur_chr);
+ get_x_token;
+ end;
+ if pool_ptr <> str_start[str_ptr] then
+ scan_name:=make_string
+ else
+ scan_name:=0;
+ end;
+
+@ @<Declare procedures that scan restricted classes of integers@>=
+procedure scan_wchar_num;
+begin scan_int;
+if (cur_val<257)or(cur_val>65535) then
+ begin print_err("Bad wide character code");
+@.Bad wide character code@>
+ help2("A wide character number must be between 256 and 65536.")@/
+ ("I changed this one to zero."); int_error(cur_val); cur_val:=0;
+ end;
+end;
+
+@* \[56] CJK Numbers.
+
+@<Global variables@>=
+@!cnum_one_flag:boolean;
+
+@
+@d ten_wchar_offset=10
+@d hundred_wchar_offset=11
+@d thousand_wchar_offset=12
+@d ten_thousand_wchar_offset=13
+@d hundred_million_wchar_offset=14
+@d arabic_wchar_offset=40
+@d negative_wchar_offset=50
+@d negative_wsym_offset=51
+@d twenty_wchar_offset=52
+@d thirty_wchar_offset=53
+@d CJK_digit_offset=0
+@d C_simple_digit_offset=10
+@d C_formal_digit_offset=25
+@d C_arabic_digit_offset=40
+
+@
+@<Basic print...@>=
+procedure print_chinese_int (@!n,@!digit_base:integer;@!simple,@!formal:boolean);
+var @!m:integer;
+begin
+ cnum_one_flag:=false;
+ if n < 0 then begin
+ {|print_dbchar| is replaced by the following 2 |print_char| calls. }
+ print_wchar(local_names(negative_wchar_offset));
+ negate(n);
+ end;
+ if n<100 then print_small_chinese_int(n,digit_base,simple,formal)
+ else begin
+ if n>99999999 then begin
+ print_small_chinese_int(n div 100000000,digit_base,simple,formal);
+ print_wchar(local_names(digit_base+hundred_million_wchar_offset));
+ cnum_one_flag:=true;
+ n:=n mod 100000000;
+ if n>0 and n<10000000 then
+ print_wchar(local_names(digit_base)); {zero character in Chinese}
+ end;
+ if n>9999 then begin
+ print_medium_chinese_int(n div 10000,digit_base,simple,formal);
+ print_wchar(local_names(digit_base+ten_thousand_wchar_offset));
+ cnum_one_flag:=true;
+ n:=n mod 10000;
+ if n>0 and n<1000 then
+ print_wchar(local_names(digit_base)); {zero character in Chinese}
+ end;
+ print_medium_chinese_int(n,digit_base,simple,formal);
+ end;
+end;
+
+@ The following procedure prints a number n, $0\le n \le 99$.
+@<Basic print...@>=
+procedure print_small_chinese_int (n,@!digit_base:integer;@!simple,@!formal:boolean);
+label done1;
+begin@/
+ if n<10 then print_wchar(local_names(n+digit_base))
+ else begin
+ if n<20 then begin
+ if formal or cnum_one_flag then
+ print_wchar(local_names(digit_base+1));
+ print_wchar(local_names(digit_base+10));@/
+ goto done1;
+ end;
+ if n<30 and simple then begin
+ print_wchar(local_names(twenty_wchar_offset));@/
+ goto done1;
+ end;
+ if n<40 and simple then begin
+ print_wchar(local_names(thirty_wchar_offset));@/
+ goto done1;
+ end;
+ print_wchar(local_names(digit_base + n div 10));
+ print_wchar(local_names(digit_base+10));
+done1: n:=n mod 10;
+ if n>0 then print_wchar(local_names(n+digit_base));
+ end
+end;
+
+@ Print a chinese number of medium size.
+@<Basic print...@>=
+procedure print_medium_chinese_int (n,@!digit_base:integer;@!simple,@!formal:boolean);
+begin
+ if n>999 then begin
+ print_wchar(local_names(digit_base+n div 1000));
+ print_wchar(local_names(digit_base+thousand_wchar_offset));
+ n:=n mod 1000;
+ if n>0 and n<99 then
+ print_wchar(local_names(digit_base)); {zero character in Chinese}
+ end;
+ if n>99 then begin
+ print_wchar(local_names(digit_base+n div 100));
+ print_wchar(local_names(digit_base+hundred_wchar_offset));
+ n:=n mod 100;
+ if n>0 and n<9 then
+ print_wchar(local_names(digit_base)); {zero character in Chinese}
+ end;
+ cnum_one_flag:=true;
+ if n>0 then print_small_chinese_int(n,digit_base,simple,formal);
+end;
+
+@ @<Put each of \TeX's primitives into the hash table@>=
+primitive("puxnumdigits",pux_get_int,int_base+pux_digit_num_code);
+primitive("puxsign",pux_get_int,int_base+pux_sign_code);
+primitive("puxdigit",pux_get_int,int_base+pux_digit_base);
+
+@ @<Cases of |print_cmd_chr|...@>=
+pux_get_int:
+ if chr_code=pux_digit_num_code+int_base then
+ print_esc("puxnumdigits")
+ else if chr_code=pux_sign_code+int_base then
+ print_esc("puxsign")
+ else if chr_code=pux_digit_base+int_base then
+ print_esc("puxdigit");
+
+@ @<Assignments@>=
+pux_get_int: begin
+ print_err("You can't assign values to internal read-only parameters.");
+ error;
+end;
+
+@ @<scan \PUTeX\ internal values@>=
+begin
+ if m=pux_digit_base+int_base then begin
+ scan_int;
+ if cur_val < 0 or cur_val > 9 then begin
+ print_err("Improper digit place specified (");
+ print_int(cur_val); print("), replaced by 0");
+ cur_val:=0;
+ end;
+ m:=m+cur_val;
+ end;
+ scanned_result(eqtb[m].int)(int_val);
+end
+
+@ @<Put each of \TeX's primitives into the hash table@>=
+primitive("PUXsplitnumber",pux_split_number,0);
+
+@ @<Assignments@>=
+pux_split_number: begin
+ scan_int;
+ split_number(cur_val);
+end;
+
+@ The following procedure splits the integer parameter |n| to digit list and stores the number of digits into
+|pux_digit_num|, the sign (1: positive or -1: negative) into |pux_num_sign|, and the digits into
+the array |pux_nth_digit|. Since the largest |n| is $2^{31}$, n contains at most 10 digits.
+
+@<PUTeX routines...@>=
+procedure split_number (n:integer);
+var k: 0..10;
+begin
+if n<0 then begin
+ pux_num_sign := -1;
+ negate(n)
+ end
+else
+ pux_num_sign := 1;
+k:=0;
+repeat pux_nth_digit(k):=n mod 10; n:=n div 10; incr(k);
+until n=0;
+pux_digit_num:=k;
+while k < 10 do begin
+ pux_nth_digit(k) := 0;
+ incr(k);
+ end;
+end;
+
+@
+@<scan and split the number@>=
+begin
+ scan_int;
+ split_number(cur_val);
+end
+
+@ @<scan a CJK number with a possible selector and then split it@>=
+begin
+ scan_int; saved_val:=cur_val;
+ split_number(cur_val);
+ if scan_keyword("offset") then begin
+ scan_eight_bit_int;
+ digit_base:=cur_val;
+ if scan_keyword("sign") then begin
+ scan_eight_bit_int;
+ sign:=cur_val;
+ end
+ else
+ sign:=negative_wchar_offset;
+ end
+ else digit_base:=0;
+end
+
+@ Using full-width arabic characters to show chinese numbers.
+@<Basic print...@>=
+procedure print_cjk_int(@!n:integer;digit_base,sign:integer);
+var k:0..9; {index to current digit}
+begin
+ if pux_num_sign = -1 then print_wchar(local_names(sign));
+ for k:=pux_digit_num-1 downto 0 do
+ print_wchar(local_names(digit_base+pux_nth_digit(k)));
+end;
+
+@ @<using full-width arabic characters to print a CJK number@>=
+print_cjk_int(cur_val,C_arabic_digit_offset,negative_wsym_offset)
+
+@ @<print a CJK number with specified format@>=
+print_cjk_int(saved_val,digit_base,sign)
+
+@ @<scan a CJK name sequence number@>=
+begin
+ scan_eight_bit_int; saved_val:=cur_val;
+ if scan_keyword("min") then begin
+ scan_optional_equals; scan_eight_bit_int;
+ min_val:=cur_val;
+ end
+ else begin
+ print_err("Missing 'min' part ("); print("min 0 inserted)");
+ error;
+ end;
+ if scan_keyword("max") then begin
+ scan_optional_equals; scan_eight_bit_int;
+ max_val:=cur_val;
+ end
+ else begin
+ print_err("Missing 'max' part ("); print("max 255 inserted)");
+ error;
+ end;
+ if scan_keyword("offset") then begin
+ scan_optional_equals; scan_eight_bit_int;
+ offset:=cur_val;
+ end
+ else begin
+ print_err("Missing 'offset' part ("); print("offset 0 inserted)");
+ error;
+ end;
+ if min_val <= saved_val and saved_val <= max_val then
+ cur_val:=offset+saved_val-min_val
+ else begin
+ print_err("Number is out of the range ("); print("replaced with the min value)");
+ cur_val:=offset;
+ error;
+ end;
+end
+
+@ @<print a CJK name sequence member@>=
+print_wchar(local_names(cur_val))
+
+@ A fix\_word is a {\sl scaled integers\/} that are multiples
+of $2^{-20}$. In other words, a binary point is assumed to be twenty bit
+positions from the right end of a binary computer word.
+@d fw_unity == @"100000 {$2^{20}$, represents 1.00000}
+@d fw_two == @"200000 {$2^{21}$, represents 2.00000}
+@d fw_one_fifth==@"33333 {0.2}
+@d convfix(#)== (#)*fw_unity div 1000
+
+@<Types...@>=
+@!fixword = integer; {this type is used for fixword (12.20) integers}
+
+
+@ @<Declare the function called |print_fixword|@>=
+procedure print_fixword(@!s:fixword); {prints fixword real, rounded to five
+ digits}
+var delta:fixword; {amount of allowable inaccuracy}
+begin if s<0 then
+ begin print_char("-"); negate(s); {print the sign, if negative}
+ end;
+print_int(s div fw_unity); {print the integer part}
+print_char(".");
+s:=10*(s mod fw_unity)+5; delta:=10;
+repeat if delta>fw_unity then s:=s+@'200000000-50000; {round the last digit}
+print_char("0"+(s div fw_unity)); s:=10*(s mod fw_unity); delta:=delta*10;
+until s<=delta;
+end;
+
+
+@ The function |fw_times_sd| do the multiplication of a fixword and a scaled number.
+The value of fixword is assumed between 16 and $-16$.
+The function returns the result as a scaled number. (See also Sec. 571, 572 and 600.)
+
+@<Declare the function called |fw_times_sd|@>=
+function fw_times_sd (@!x:fixword; @!z:scaled) : scaled;
+ {compute |f| times |s|}
+var @!sw:scaled;
+@!a,@!b,@!c,@!d:eight_bits; {byte variables}
+@!alpha:integer;@!beta:1..16;
+begin @<Replace |z|...@>;
+if x>=0 then a:=x div @'100000000
+else begin x:=x+@'10000000000;
+ x:=x+@'10000000000;
+ a:=(x div @'100000000) + 128;
+ end;
+x:=x mod @'100000000; b:=x div @'200000;
+x:=x mod @'200000; c:=x div @'400;
+d:=x mod @'400;
+sw:=(((((d*z)div@'400)+(c*z))div@'400)+(b*z))div beta;
+if a=0 then fw_times_sd:=sw
+else if a=255 then fw_times_sd:=sw-alpha
+else fw_times_sd:=unity;
+end;
+
+@ @<Put each of \TeX's primitives into the hash table@>=
+primitive("PUXchar",pux_char_num,0);
+
+@ @<Cases of |print_cmd_chr|...@>=
+pux_char_num: print_esc("PUXchar");
+
+@ @<Give improper hyphenation error for Chinese characters inside@>=
+begin print_err("Improper "); print_esc("hyphenation");
+@.Improper \\hyphenation...@>
+ print(" will be flushed");
+help2("Hyphenation exceptions can't contain Chinese characters")@/
+ ("But continue; I'll forgive and forget.");
+error;
+end
+
+
+@ @<Cases of |main_control| that build...@>=
+mmode+pux_char_num: begin scan_wchar_num; cur_chr:=cur_val;
+ print_err("Chinese character is ignored in math mode");
+ help1("Did you forget putting it into an \hbox?");
+ error;
+ end;
+mmode+pux_char_given: begin
+ print_err("Chinese character is ignored in math mode");
+ help1("Did you forget putting it into an \hbox?");
+ error;
+ end;
+
+@ @<Cases of |print_cmd_chr|...@>=
+pux_char_given: begin print_esc("PUXchar"); print_hex(chr_code);
+ end;
+
+@* \[58] All about spaces.
+
+@d is_tail_forbidden(#) == type_code(#) = tail_forbidden
+@d is_head_forbidden(#) == type_code(#) = head_forbidden
+@d is_head_forbidden_wchar(#) == ((# > 255) and (type_code(#) = head_forbidden))
+@d is_punc_wchar(#) == ((# > 255) and (type_code(#) <> 0))
+
+@
+@<Global variables@>=
+@!main_cf:internal_cfont_number; {the current chinese font}
+@!math_mode_save:-mmode..mmode;
+@!prev_main_cf:internal_cfont_number; {the current chinese font}
+@!pre_undet_glue_ptr:pointer; {point to the node just before a undetermined glue}
+@!undet_glue_ptr:pointer; {point to the undetermined glue}
+@!cglue_ptr:pointer;
+@!cglue_spec:pointer;
+@!pre_glue_char_ptr:pointer;
+@!outer_tail:pointer;
+@!hbox_tail:pointer;
+@!in_set_box:boolean;
+
+@ @<Initialization of global variables done in the |main_control| procedure@>=
+pre_undet_glue_ptr:=null;
+pre_glue_char_ptr:=null;
+
+@
+@d tail_append_glue(#)==
+begin cglue_ptr:=get_node(small_node_size); cglue_spec:=#;
+type(cglue_ptr):=glue_node; subtype(cglue_ptr):=normal;
+leader_ptr(cglue_ptr):=null; glue_ptr(cglue_ptr):=cglue_spec;
+incr(glue_ref_count(cglue_spec));
+tail_append(cglue_ptr);
+end
+
+@ Here is the check done before switching to regular character string.
+@<If the preceding node is wchar node, then append a cespace@>=
+if tail=head then begin
+ if mode=-hmode then begin {beginning of a restricted hlist}
+ outer_tail:=nest[nest_ptr-1].tail_field;
+ if pre_undet_glue_ptr<>null then begin
+ if outer_tail=link(pre_undet_glue_ptr) and pre_glue_char_ptr<>null
+ and is_wchar_node(pre_glue_char_ptr) then begin
+ decr(glue_ref_count(glue_ptr(outer_tail)));
+ glue_ptr(outer_tail):=cfont_ceglue_spec[prev_main_cf];
+ incr(glue_ref_count(cfont_ceglue_spec[prev_main_cf]));
+ end;
+ pre_undet_glue_ptr:=null;
+ end;
+ end;
+ end
+else if is_char_node(tail) and is_wchar_node(tail) then begin
+ if is_head_forbidden(cur_chr) then tail_append(new_penalty(inf_penalty));
+ tail_append_glue(cfont_ceglue_spec[main_cf]);
+ end
+else if pre_undet_glue_ptr<>null and link(pre_undet_glue_ptr)=tail and
+ pre_glue_char_ptr<>null and is_wchar_node(pre_glue_char_ptr) then begin
+ decr(glue_ref_count(glue_ptr(tail)));
+ glue_ptr(tail):=cfont_ceglue_spec[prev_main_cf];
+ incr(glue_ref_count(cfont_ceglue_spec[prev_main_cf]));
+ end;
+pre_undet_glue_ptr:=null;
+pre_glue_char_ptr:=null;
+
+
+@ If the next token come after the math shift \$ is a wide character, then
+a cespace is appended first.
+@<If the token is a wide character, then append a cspace@>=
+if cur_cmd=pux_char_num then
+ begin scan_wchar_num; cur_chr:=cur_val; cur_cmd:=pux_char_given;
+ end;
+if cur_cmd=letter or cur_cmd=other_char or cur_cmd=pux_char_given then
+ if is_wchar(cur_chr) then
+ if is_punc_wchar(cur_chr) then begin
+ if is_head_forbidden(cur_chr) then tail_append(new_penalty(inf_penalty));
+ tail_append_glue(zero_glue);
+ end
+ else
+ tail_append_glue(cfont_ceglue_spec[main_cf])
+
+
+@
+@<Append double-byte character |cur_chr|...@>=
+main_cf:=cur_cfont;
+@<If the current wchar is at the beginning of a restricted hlist that
+ is after a undetermined spacer, then we have to determine that space.
+ When it is done |goto save_cur_wchar|@>;
+@<If the previous node is an undetermined glue, then make it certain and
+ |goto save_cur_wchar|@>;
+if not is_char_node(tail) then goto save_cur_wchar;
+main_loop_wchar+1:@<the previous node is a character node, so we have to append
+a glue first@>;
+save_cur_wchar:
+fast_get_avail(lig_stack);
+font(lig_stack):=main_cf;
+character(lig_stack):=cur_chr;
+tail_append(lig_stack);@/
+@<Prepare a nonbreak space if the current wide character is not allowed to
+ appear at the end of line@>;
+fetch_next_tok:get_next; {set only |cur_cmd| and |cur_chr|, for speed}
+@<Check the lookahead character@>;
+x_token; {now expand and set |cur_cmd|, |cur_chr|, |cur_tok|}
+@<Check the lookahead character@>;
+if cur_cmd=char_num then
+ begin scan_char_num; cur_chr:=cur_val; cur_cmd:=char_given; goto next_is_a_char;
+ end;
+if cur_cmd=pux_char_num then
+ begin scan_wchar_num; cur_chr:=cur_val;
+ if is_punc_wchar(cur_chr) then
+ if is_head_forbidden(cur_chr) then tail_append(new_penalty(inf_penalty));
+ tail_append_glue(cfont_glue_spec[main_cf]);
+ goto save_cur_wchar;
+ end;
+{next token is not a character token}
+if cur_cmd=math_shift then
+ if is_punc_wchar(character(lig_stack)) then
+ tail_append_glue(zero_glue)
+ else
+ tail_append_glue(cfont_ceglue_spec[main_cf]);
+goto reswitch;
+next_is_a_char: begin@/
+ if cur_chr<256 then
+ if is_head_forbidden(cur_chr) then tail_append(new_penalty(inf_penalty));
+ if is_punc_wchar(character(lig_stack)) then
+ tail_append_glue(zero_glue)
+ else
+ tail_append_glue(cfont_ceglue_spec[main_cf]);
+ goto main_loop+1;
+ end
+
+
+@ @<If the current wchar is at the beginning...@>=
+if tail=head then begin {beginning of a restricted hlist}
+ if mode=-hmode then begin
+ outer_tail:=nest[nest_ptr-1].tail_field;
+ if pre_undet_glue_ptr<>null then begin
+ if outer_tail=link(pre_undet_glue_ptr) then begin
+ undet_glue_ptr:=outer_tail;
+ @<Modify the undetermined glue according the type of pre-glue character@>;
+ end;
+ pre_undet_glue_ptr:=null;
+ end;
+ end;
+ goto save_cur_wchar;
+ end
+
+
+@ @<Modify the undetermined glue...@>=
+decr(glue_ref_count(glue_ptr(undet_glue_ptr)));
+if pre_glue_char_ptr<>null and is_wchar_node(pre_glue_char_ptr) then begin
+ glue_ptr(undet_glue_ptr):=cfont_glue_spec[prev_main_cf];
+ incr(glue_ref_count(cfont_glue_spec[prev_main_cf]));
+ pre_glue_char_ptr:=null;
+ end
+else begin
+ glue_ptr(undet_glue_ptr):=cfont_ceglue_spec[prev_main_cf];
+ incr(glue_ref_count(cfont_ceglue_spec[prev_main_cf]));
+ end
+
+@ @<If the previous node is an undetermined glue...@>=
+if pre_undet_glue_ptr<>null then begin
+ if link(pre_undet_glue_ptr)=tail then begin
+ undet_glue_ptr:=tail;
+ @<Modify the undetermined glue according the type of pre-glue character@>;
+ pre_undet_glue_ptr:=null;
+ goto save_cur_wchar;
+ end;
+ pre_undet_glue_ptr:=null;
+ end
+
+
+@ @<the previous node is a character node...@>=
+if is_wchar_node(tail) then begin
+ if is_head_forbidden_wchar(cur_chr) then
+ tail_append(new_penalty(inf_penalty));
+ tail_append(new_glue(cfont_glue_spec[main_cf]));
+ end
+else begin {previous node is a single byte character}
+ if is_punc_wchar(cur_chr) then begin
+ if is_head_forbidden(cur_chr) then tail_append(new_penalty(inf_penalty));
+ tail_append_glue(zero_glue);
+ end
+ else begin
+ if is_head_forbidden(character(tail)) then tail_append(new_penalty(inf_penalty));
+ tail_append_glue(cfont_ceglue_spec[main_cf]);
+ end;
+ end
+
+
+
+@ For those Chinese puncuations that shoudn't appear in the line end,
+we append a penalty node to prevent line boken after it.
+@<Prepare a nonbreak space if the current wide...@>=
+if is_punc_wchar(cur_chr) then
+ if is_tail_forbidden(cur_chr) then tail_append(new_penalty(inf_penalty))
+
+@ @<Check the lookahead character@>=
+if cur_cmd=letter or cur_cmd=other_char or cur_cmd=pux_char_given or
+ cur_cmd=char_given then
+ if is_wchar(cur_chr) then begin
+ if is_punc_wchar(cur_chr) then
+ if is_head_forbidden(cur_chr) then tail_append(new_penalty(inf_penalty));
+ tail_append_glue(cfont_glue_spec[main_cf]);
+ goto save_cur_wchar;
+ end
+ else goto next_is_a_char
+
+
+@ @<Look ahead for next character. If it is a wide...@>=
+get_next; {set only |cur_cmd| and |cur_chr|, for speed}
+if cur_cmd=letter or cur_cmd=other_char then
+ if is_wchar(cur_chr) then goto main_loop_lookahead+2
+ else goto main_loop_lookahead+1;
+if cur_cmd=char_given then goto main_loop_lookahead+1;
+if cur_cmd=pux_char_given then goto main_loop_lookahead+2;
+x_token; {now expand and set |cur_cmd|, |cur_chr|, |cur_tok|}
+if cur_cmd=letter or cur_cmd=other_char then
+ if is_wchar(cur_chr) then goto main_loop_lookahead+2
+ else goto main_loop_lookahead+1;
+if cur_cmd=char_given then goto main_loop_lookahead+1;
+if cur_cmd=char_num then
+ begin scan_char_num; cur_chr:=cur_val; goto main_loop_lookahead+1;
+ end;
+if cur_cmd=pux_char_num then
+ begin scan_wchar_num; cur_chr:=cur_val; goto main_loop_lookahead+2;
+ end;
+if cur_cmd=no_boundary then bchar:=non_char;
+main_loop_lookahead+2: cur_r:=bchar; lig_stack:=null; goto main_lig_loop;
+main_loop_lookahead+1: adjust_space_factor;
+fast_get_avail(lig_stack); font(lig_stack):=main_f;
+cur_r:=qi(cur_chr); character(lig_stack):=cur_r;
+if cur_r=false_bchar then cur_r:=non_char {this prevents spurious ligatures}
+
+
+@ @<Cases of |main_control| that handle spacer@>=
+hmode+spacer: @<Lookahead and determine the type of spacer to append@>;
+hmode+ex_space: @<Lookahead and determine the type of |ex_spacer| to append@>;
+mmode+ex_space: begin if pux_xspace=0 then get_x_token; {lookahead}
+ goto append_normal_space;
+ end;
+hmode+pux_space:@<Handle \PUTeX space command@>;
+mmode+pux_space:begin
+ print_err("This space command is ignored in math mode");
+ help1("Did you forget putting it into an \hbox?");
+ error;
+ end;
+
+@ @<Setup |hbox_tail| and package@>=
+if in_set_box then package(0)
+else begin
+ if tail<>head and is_char_node(tail) then
+ hbox_tail:=tail
+ else
+ hbox_tail:=null;
+ package(0);
+ get_x_token;
+ if cur_cmd<>spacer then hbox_tail:=null;
+ back_input;
+ end
+
+@ @<Lookahead and determine the type of spacer to append@>=
+begin
+if pux_xspace=0 then begin
+ if tail<>head and is_char_node(tail) then
+ pre_glue_char_ptr:=tail
+ else
+ pre_glue_char_ptr:=null;
+ get_x_token; {lookahead}
+ if cur_cmd=char_num then
+ begin scan_char_num; cur_chr:=cur_val; cur_cmd:=char_given;
+ end
+ else if cur_cmd=pux_char_num then
+ begin scan_wchar_num; cur_chr:=cur_val; cur_cmd:=pux_char_given;
+ end;
+ if cur_cmd=letter or cur_cmd=other_char or cur_cmd=char_given or
+ cur_cmd=pux_char_given then
+ if is_wchar(cur_chr) then begin
+ main_cf:=cur_cfont;
+ if pre_glue_char_ptr<>null then goto main_loop_wchar+1;
+ if hbox_tail<>null and is_wchar_node(hbox_tail) then begin
+ tail_append_glue(cfont_glue_spec[main_cf]);
+ hbox_tail:=null;
+ end
+ else begin
+ tail_append_glue(cfont_ceglue_spec[main_cf]);
+ if is_punc_wchar(cur_chr) then
+ if is_head_forbidden(cur_chr) then tail_append(new_penalty(inf_penalty));
+ if hbox_tail<>null then hbox_tail:= null;
+ end;
+ goto save_cur_wchar;
+ end
+ else if (pre_glue_char_ptr<>null and is_wchar_node(tail))
+ or (hbox_tail<>null and is_wchar_node(hbox_tail)) then begin
+ tail_append_glue(cfont_ceglue_spec[cur_cfont]);
+ hbox_tail:=null;
+ goto main_loop;
+ end;
+ prev_main_cf:=cur_cfont;
+ pre_undet_glue_ptr:=tail;
+ if pre_glue_char_ptr<>null and is_wchar_node(pre_glue_char_ptr) then begin
+ tail_append_glue(cfont_ceglue_spec[cur_cfont]);
+ goto reswitch;
+ end;
+ end;
+if space_factor=1000 then goto append_normal_space
+else begin app_space;
+ if pux_xspace=0 then goto reswitch else goto big_switch;
+ end;
+end
+
+@ @<Lookahead and determine the type of |ex_spacer| to append@>=
+begin
+if pux_xspace=0 then begin
+ get_x_token; {lookahead}
+ if cur_cmd=char_num then
+ begin scan_char_num; cur_chr:=cur_val; cur_cmd:=char_given;
+ end;
+ if cur_cmd=pux_char_num then
+ begin scan_wchar_num; cur_chr:=cur_val; cur_cmd:=pux_char_given;
+ end;
+ if cur_cmd=letter or cur_cmd=other_char or cur_cmd=char_given or cur_cmd=pux_char_given then
+ if is_wchar(cur_chr) then begin
+ main_cf:=cur_cfont;
+ if tail<>head and is_char_node(tail) then
+ if is_wchar_node(tail) then
+ goto append_normal_space
+ else
+ goto main_loop_wchar+1;
+ tail_append_glue(cfont_glue_spec[main_cf]);
+ goto save_cur_wchar;
+ end
+ else if tail<>head and is_char_node(tail) then
+ if is_wchar_node(tail) then begin
+ tail_append_glue(cfont_ceglue_spec[cur_cfont]);
+ goto main_loop;
+ end;
+ if tail<>head and is_char_node(tail) then
+ if is_wchar_node(tail) then begin
+ tail_append_glue(cfont_glue_spec[cur_cfont]);
+ goto reswitch;
+ end;
+ prev_main_cf:=cur_cfont;
+ pre_undet_glue_ptr:=tail;
+ end;
+goto append_normal_space;
+end
+
+@
+@d pux_space_code=0
+@d pux_exspace_code=1
+@d pux_cspace_code=2
+@d pux_cespace_code=3
+@<Put each of \TeX's primitives into the hash table@>=
+primitive("PUXspace",pux_space,pux_space_code);
+primitive("PUXexspace",pux_space,pux_exspace_code);
+primitive("PUXcspace",pux_space,pux_cspace_code);
+primitive("PUXcespace",pux_space,pux_cespace_code);
+
+@ @<Cases of |print_cmd_chr|...@>=
+pux_space: case chr_code of
+ pux_space_code: print_esc("PUXspace");
+ pux_exspace_code: print_esc("PUXexspace");
+ pux_cspace_code: print_esc("PUXcspace");
+ othercases print_esc("PUXcespace")
+ endcases;
+
+@ @<Handle \PUTeX space command@>=
+case cur_chr of
+ pux_space_code: begin get_x_token;
+ if space_factor=1000 then goto append_normal_space;
+ app_space;
+ if pux_xspace=0 then goto reswitch else goto big_switch;
+ end;
+ pux_exspace_code: begin get_x_token; goto append_normal_space;
+ end;
+ pux_cspace_code: tail_append(new_glue(cfont_glue_spec[cur_cfont]));
+ othercases tail_append(new_glue(cfont_ceglue_spec[cur_cfont]))
+ endcases
+
+@* \[59] CJK font face definition table.
+
+@ @<Put each of \TeX's primitives into the hash table@>=
+primitive("PUXcfacedef",pux_cface_def,0);
+
+@ @<Cases of |print_cmd_chr|...@>=
+pux_cface_def: print_esc("PUXcfacedef"); {TCW}
+
+@ @<Assignments@>=
+pux_cface_def: new_cface(a);
+
+
+@ @<Constants...@>=
+@!cface_base=0; {CJK font face base}
+@!null_cface=0; {null CJK font faces}
+
+@
+@<Types...@>=
+@!internal_cface_number=cface_base..max_cface;
+
+@ The CJK font face definition table is implemented by parallel arrays as follows.
+@d regular=0
+@d italic=@"40 {bit 6: italic flag}
+@d underline=@"20 {bit 5: underline flag}
+@d strikeout=@"10 {bit 4: strikeout flag}
+@d inverse=@"08 {bit 3: inverse flag}
+@d rotated=@"01 {bit 0: rotation flag}
+@d default_cface_weight==400
+@d default_cface_style=regular
+@d default_cface_fw_width==fw_unity
+@d default_cface_fw_height==fw_unity
+@d cface_id_text(#)==text(cface_id_base+#)
+
+@<Global variables@>=
+@!cface_ptr:internal_cface_number;
+ {index of the first unused entry}
+@!cface:array[internal_cface_number] of str_number;
+ {CJK font face identifier}
+@!cface_name:array[internal_cface_number] of str_number;
+ {CJK font face name}
+@!cface_charset:array[internal_cface_number] of eight_bits;
+ {CJK font charset}
+@!cface_weight:array[internal_cface_number] of 1..1000;
+ {CJK font weight}
+@!cface_style:array[internal_cface_number] of eight_bits;
+ {CJK font style}
+@!cface_fw_width:array[internal_cface_number] of fixword;
+ {CJK font width ratio}
+@!cface_fw_height:array[internal_cface_number] of fixword;
+ {CJK font heigh ratio}
+@!cface_fw_depth:array[internal_cface_number] of fixword;
+ {CJK font depth ratio}
+@!cface_csp_width:array[internal_cface_number] of integer;
+ {CJK font c-space width}
+@!cface_csp_shrink:array[internal_cface_number] of integer;
+ {CJK font c-space shrink}
+@!cface_csp_stretch:array[internal_cface_number] of integer;
+ {CJK font c-space stretch}
+@!cface_cesp_width:array[internal_cface_number] of integer;
+ {CJK font ce-space width}
+@!cface_cesp_shrink:array[internal_cface_number] of integer;
+ {CJK font ce-space shrink}
+@!cface_cesp_stretch:array[internal_cface_number] of integer;
+ {CJK font ce-space stretch}
+@!cface_fw_default_depth:fixword;
+
+
+@ @<Put each of \TeX's primitives into the hash table@>=
+primitive("PUXsetdefaultcface",pux_set_default_cface,int_base+pux_default_cface_code);
+
+@ @<Cases of |print_cmd_chr|...@>=
+pux_set_default_cface: print_esc("PUXsetdefaultcface"); {TCW}
+
+@ @<Assignments@>=
+pux_set_default_cface: begin p:=cur_chr;
+ @<Get the next non-blank non-call token@>;
+ if cur_cmd = pux_set_cface then
+ word_define(p,cur_chr)
+ else begin
+ print_err("Here should put a CJK font face command. ");
+ print("The dafault CJK font face remains unchanged");
+ error;
+ end;
+ end;
+
+
+@ @<PUTeX routines that will be used by TeX routines@>=
+procedure reset_cface_cspace (face_num:integer);
+begin
+ cface_csp_width[face_num]:=g_cspace_width;@/
+ cface_csp_shrink[face_num]:=g_cspace_shrink;@/
+ cface_csp_stretch[face_num]:=g_cspace_stretch;@/
+end;
+
+@ @<PUTeX routines that will be used by TeX routines@>=
+procedure reset_cface_cespace (face_num:integer);
+begin
+ cface_cesp_width[face_num]:=g_cespace_width;@/
+ cface_cesp_shrink[face_num]:=g_cespace_shrink;@/
+ cface_cesp_stretch[face_num]:=g_cespace_stretch;@/
+end;
+
+@ Setup default and null CJK font faces.
+@<Initialize table...@>=
+cur_cface:=null_cface; eq_type(cur_cface_loc):=data;
+eq_level(cur_cface_loc):=level_one;@/
+cface_fw_default_depth:=convfix(puxg_cface_depth);
+cface_ptr:=cface_base+1;
+
+cface[null_cface]:="nullcface";@/
+cface_name[null_cface]:="nullcjkface";@/
+cface_charset[null_cface]:=0;@/
+cface_weight[null_cface]:=400; {normal weight}@/
+cface_style[null_cface]:=0;@/
+cface_fw_width[null_cface]:=0;@/
+cface_fw_height[null_cface]:=0;@/
+cface_fw_depth[null_cface]:=0;@/
+reset_cface_cspace(null_cface);@/
+reset_cface_cespace(null_cface);@/
+
+@ The function |find_cface_num| searches the CJK font face definition table
+for the entry with the same identifier as |id|. The entry index is return if found;
+otherwise, the current value of |cface_ptr| is return.
+
+@d cface_found(#)==((#)<cface_ptr)
+
+@<Declare the function called |find_cface_num|@>=
+function find_cface_num(id:str_number):internal_cface_number;
+ label done;
+ var f:internal_cface_number; {runs through existing faces}
+ begin
+ f:=cface_base;
+ while (f < cface_ptr) do
+ begin
+ if str_eq_str(id, cface[f]) then goto done;
+ incr(f);
+ end;
+ done:find_cface_num:=f;
+ end;
+
+@ @<Declare subprocedures for |prefixed_command|@>=
+@<Declare the function called |print_fixword|@>@;
+procedure new_cface(@!a:small_number);
+label done, done1, common_ending;
+var u:pointer; {user's chinese face identifier}
+@!t:str_number; {name for the frozen font identifier}
+@!id:str_number; {CJK font face identifier}
+@!face_name:str_number; {CJK font face name}
+@!charset:integer; {CJK font charset}
+@!weight:integer; {CJK font weight}
+@!style:integer; {CJK font style}
+@!w:integer; {CJK font width ratio}
+@!h:integer; {CJK font height ratio}
+@!d:integer; {CJK font depth ratio}
+@!fix_w:fixword; {CJK font width ratio}
+@!fix_h:fixword; {CJK font height ratio}
+@!fix_d:fixword; {CJK font depth ratio}
+@!f:internal_cface_number; {runs through existing faces}
+@!k:integer;@/
+@<Other variables used by |new_cface|@>@;
+begin if job_name=0 then open_log_file;
+ {avoid confusing \.{texput} with the font name}
+get_r_token; u:=cur_cs;
+if u>=hash_base then t:=text(u)
+else if u>=single_base then
+ if u=null_cs then t:="CFACE"@+else t:=u-single_base
+else begin old_setting:=selector; selector:=new_string;
+ print("CFACE"); print(u-active_base); selector:=old_setting;
+ str_room(1); t:=make_string;
+ end;
+define(u,pux_set_cface,null_cface);
+scan_optional_equals;
+@<Setup variables before scanning CJK font face parameters@>;
+@<Scan CJK font face identifier@>;
+@<Scan CJK font face name@>;
+@<Scan optional CJK font face definition parameters@>;
+@<If the face name is missing, then ignore this face deinition@>;
+@<If this Chinese face has already been loaded, then |goto common_ending|@>;
+@<Setup this new Chinese face@>;
+common_ending: equiv(u):=f; eqtb[cface_id_base+f]:=eqtb[u]; cface_id_text(f):=t;
+end;
+
+@ @<Setup variables before scanning CJK font face parameters@>=
+charset:=pux_charset; {set to the base charset of document}
+w:=1000; h:=1000; d:=puxg_cface_depth; @/
+weight:=400; {normal weight}@/
+style:=0; {regular style}
+if puxg_rotate_ctext<>0 then style:=style+rotated;
+f:=null_cface
+
+
+@ @<Scan CJK font face identifier@>=
+id:=scan_name;
+if id > 0 then
+ begin
+ f:=find_cface_num(id);
+ if (f < cface_ptr) then
+ begin
+ flush_string; id:=cface[f]; {for saving string pool sapce}
+ f:=null_cface;
+ print_err("The Chinese face id ("); print(id);
+ print(") is already used"); error;
+ end;
+ end
+else
+ begin
+ print_err("Missing CJK font face identifier"); error;
+ end
+
+@ @<Scan CJK font face name@>=
+begin
+face_name:=scan_name;
+if face_name > 0 then
+ begin
+ k:=cface_base;
+ while (k < cface_ptr) do
+ begin
+ if str_eq_str(face_name, cface_name[k]) then
+ begin
+ flush_string;
+ face_name:=cface_name[k]; f:=k;
+ goto done1;
+ end;
+ incr(k);
+ end;
+ end
+else
+ begin
+ print_err("Missing CJK font face name"); error;
+ face_name:=cface_name[null_cface];
+ f:=null_cface;
+ end;
+done1: end
+
+@ @<Other variables used by |new_cface|@>=
+@!i_flag:boolean; {italic flag}
+@!u_flag:boolean; {underline flag}
+@!s_flag:boolean; {strikeout flag}
+@!r_flag:boolean; {rotation flag}
+@!v_flag:boolean; {inverse flag}
+@!more_param:boolean; {have more parameters to come}
+
+@ @<Scan optional CJK font face definition parameters@>=
+i_flag:=false; u_flag:=false; s_flag:=false;@/
+r_flag:=false; v_flag:=false;@/
+more_param:=true;
+while more_param do
+ begin
+ @<Get the next non-blank non-call token@>;
+ if cur_cmd=letter then
+ case cur_chr of
+ 'c','C': @<Scan the CJK font charset@>;
+ 'w','W': @<Scan the CJK font width@>;
+ 'h','H': @<Scan the CJK font height@>;
+ 'd','D': @<Scan the CJK font depth@>;
+ 't','T': @<Scan the CJK font weight@>;
+ 's','S': @<Scan the CJK font style@>;
+ othercases more_param:=false;
+ endcases
+ else more_param:=false;
+ end;
+back_input
+
+
+@
+@<Scan the CJK font charset@>=
+begin scan_optional_equals;@/
+scan_int;
+if (cur_val<0)or(cur_val>255) then
+ begin print_err("Improper `charset' value (");
+ print_int(charset); print("), replaced by default charset");
+ help2("I can only handle nonnegative charset value up to 255,")@/
+ ("so I've changed what you said to default charset.");
+ error;
+ end
+else
+ charset:=cur_val;
+end
+
+@
+@<Scan the CJK font width@>=
+begin scan_optional_equals;@/
+scan_int; w:=cur_val;
+if (w<=0)or(w>1000) then
+ begin print_err("Improper `width' value (");
+ print_int(w); print("), replaced by 1000");
+ help2("I can only handle fonts at positive width ratio that are less")@/
+ ("than or equal to 1000, so I've changed what you said to 1000.");
+ error; w:=1000;
+ end;
+end
+
+@ @<Scan the CJK font height@>=
+begin scan_optional_equals;@/
+scan_int; h:=cur_val;
+if (h<=0)or(h>1000) then
+ begin print_err("Improper `height value (");
+ print_int(h); print("), replaced by 1000");
+ help2("I can only handle fonts at positive height ratio that are less")@/
+ ("than or equal to 1000, so I've changed what you said to 1000.");
+ error; h:=1000;
+ end;
+end
+
+@ @<Scan the CJK font depth@>=
+begin scan_optional_equals;@/
+scan_int; d:=cur_val;
+if (d<0)or(d>1000) then
+ begin print_err("Improper `depth' value (");
+ print_int(d); print("), replaced by 0.2");
+ help3("I can only handle fonts at nonegative depth ratio that are less")@/
+ ("than or equal to 1000, so I've changed what you said to")@/
+ ("the current \puxgCfaceDepth value.");
+ error; d:=puxg_cface_depth;
+ end;
+end
+
+@ @<Scan the CJK font weight@>=
+begin scan_optional_equals;@/
+scan_int; weight:=cur_val;
+if (weight < 0) or (weight > 1000) then
+ begin print_err("Illegal CJK font weight has been changed to 400");@/
+ help1("The font weight must be between 1 and 1000.");
+ int_error(cur_val); weight:=400; {normal weight}
+ end;
+end
+
+@
+@<Scan the CJK font style@>=
+begin scan_optional_equals;@/
+@<Get the next non-blank non-call token@>;
+if cur_cmd=letter then
+ case cur_chr of
+ "i", "I": if not i_flag then begin style:=style+italic; i_flag:=true; end;
+ "u", "U": if not u_flag then begin style:=style+underline; u_flag:=true; end;
+ "s", "S": if not s_flag then begin style:=style+strikeout; s_flag:=true; end;
+ "r", "R": if not r_flag then @<Set CJK font rotation style@>;
+ "v", "V": if not v_flag then begin style:=style+inverse; v_flag:=true; end;
+ othercases@/
+ begin print_err("Illegal CJK font style setting has been ignored");@/
+ print(" ("); print(cur_chr); print(")"); back_error;
+ {fix the case when cur\_chr is a double-byte char}
+ help2("The CJK font style setting should use characters:")@/
+ ("i:italic, u:underline, s:strikeout, r:rotated, v:reversed");
+ end;
+ endcases;@/
+end
+
+@ @<Set CJK font rotation style@>=
+begin
+if puxg_rotate_ctext<>0 then
+ style:=style-rotated
+else
+ style:=style+rotated;
+r_flag:=true;
+end
+
+@ @<If the face name is missing, then ignore this face deinition@>=
+if f=null_cface then
+ goto common_ending
+
+
+@ @<If this Chinese face has...@>=
+fix_w:=convfix(w);
+fix_h:=convfix(h);
+fix_d:=convfix(d);
+if f <> null_cface then
+ if weight=cface_weight[f] and style=cface_style[f] then
+ if fix_w=cface_fw_width[f] and fix_h=cface_fw_height[f] and fix_d=cface_fw_depth[f] then@/
+ goto common_ending
+
+@
+@<Setup this new Chinese face@>=
+if cface_ptr <= max_cface then
+ begin
+ f:=cface_ptr;
+ cface[f]:=id;
+ cface_name[f]:=face_name;@/
+ cface_charset[f]:=charset;@/
+ cface_weight[f]:=weight;@/
+ cface_style[f]:=style;@/
+ if style mod 2 = 1 then begin
+ cface_fw_width[f]:=fix_w; cface_fw_height[f]:=fix_h;
+ end
+ else begin
+ cface_fw_width[f]:=fix_h; cface_fw_height[f]:=fix_w;
+ end;
+ cface_fw_depth[f]:=fix_d;@/
+ reset_cface_cspace(f);@/
+ reset_cface_cespace(f);@/
+ incr(cface_ptr);
+ end
+else begin
+ f:=null_cface;
+ print_err("CJK font Face definition table overflow"); error;
+ end
+
+@* \[59] CJK font definition table.
+
+@ @<Constants...@>=
+@!cfont_base=font_max_limit+1; {CJK font base}
+@!cfont_max=font_max_limit+1+cfont_max_limit; {maximum internal chinese font number}
+
+@
+@<Types...@>=
+@!internal_cfont_number=cfont_base..cfont_max;
+
+@ @<Initialize table entries...@>=
+cur_cfont:=default_cfont; eq_type(cur_cfont_loc):=data;
+eq_level(cur_cfont_loc):=level_one;@/
+
+@ @<Global variables@>=
+@!cfont_ptr:internal_cfont_number;
+@!cfont_face:array[internal_cfont_number] of internal_cface_number;
+ {CJK font face name}
+@!cfont_dsize:array[internal_cfont_number] of scaled;
+ {CJK font design size}
+@!cfont_size:array[internal_cfont_number] of scaled;
+ {CJK font size}
+@!cfont_width:array[internal_cfont_number] of scaled;
+ {CJK font width}
+@!cfont_height:array[internal_cfont_number] of scaled;
+ {CJK font heigh}
+@!cfont_depth:array[internal_cfont_number] of scaled;
+ {CJK font depth}
+@!cfont_glue_spec:array[internal_cfont_number] of pointer;
+ {CJK font inter-character space}
+@!cfont_ceglue_spec:array[internal_cfont_number] of pointer;
+ {CJK font inter-character space}
+@!cfont_used:array[internal_cfont_number] of boolean;
+ {has a character from this chinese font actually appeared in the output?}
+
+
+@ @<Set init...@>=
+for k:=cfont_base to cfont_max do cfont_used[k]:=false;
+cfont_face[null_cfont]:=null_cface;
+cfont_dsize[null_cfont]:=0;
+cfont_size[null_cfont]:=0;
+cfont_width[null_cfont]:=0;
+cfont_height[null_cfont]:=0;
+cfont_depth[null_cfont]:=0;
+
+@ @<Initialize table entries...@>=
+cfont_ptr:=default_cfont;
+
+@ @<Declare PUTeX subprocedures for |prefixed_command|@>=
+procedure set_cglue_spec(n:integer);
+var cface_num:integer;
+begin
+ cface_num:=cfont_face[n];
+ width(cfont_glue_spec[n]):=xn_over_d(cfont_size[n], cface_csp_width[cface_num], 1000);
+ shrink(cfont_glue_spec[n]):=xn_over_d(cfont_size[n], cface_csp_shrink[cface_num], 1000);
+ stretch(cfont_glue_spec[n]):=xn_over_d(cfont_size[n], cface_csp_stretch[cface_num], 1000);
+end;
+
+@ @<Declare PUTeX subprocedures for |prefixed_command|@>=
+procedure set_ceglue_spec(n:integer);
+var cface_num:integer;
+begin
+ cface_num:=cfont_face[n];
+ width(cfont_ceglue_spec[n]):=xn_over_d(cfont_size[n], cface_cesp_width[cface_num], 1000);
+ shrink(cfont_ceglue_spec[n]):=xn_over_d(cfont_size[n], cface_cesp_shrink[cface_num], 1000);
+ stretch(cfont_ceglue_spec[n]):=xn_over_d(cfont_size[n], cface_cesp_stretch[cface_num], 1000);
+end;
+
+
+@ @<Initialization of global variables done in the |main_control| procedure@>=
+cfont_glue_spec[null_cfont]:=new_spec(zero_glue);
+cfont_ceglue_spec[null_cfont]:=new_spec(zero_glue);
+
+@ @<Other local variables used by procedure |new_font|@>=
+@!face_id:str_number; {Chinese face name fetched from |\\font| command}
+@!jj:internal_cface_number;
+@!cface_num:internal_cface_number;
+@!ds:integer;
+@!dsize:scaled;
+@!size:scaled;
+
+@
+@<Define a CJK font and then goto |common_ending|@>=
+begin
+define(u, set_cfont, null_cfont);
+cface_num:=pux_default_cface;@/
+@<Fetch the Chinese face name@>;
+@<Fetch the font design size and compute font 'at' size@>;
+@<If this CJK font has already been loaded, set |f| to the internal
+ CJK font number and |goto| common\_ending@>;
+f:=make_cfont(cface_num,dsize,size);@/
+goto common_ending;
+end;
+
+@
+@d is_letter(#)==((#>='A' and #<='Z') or (#>='a' and #<='z'))
+@<Fetch the Chinese face name@>=
+jj:=j;
+j:=j+5; {skip the prefix 'CFONT'}
+while is_letter(str_pool[j]) do {fixme for wchar}
+ begin
+ append_char(str_pool[j]);
+ incr(j);
+ end;
+if pool_ptr <> str_start[str_ptr] then
+ begin
+ face_id:=make_string;@/
+ cface_num:=find_cface_num(face_id);
+ flush_string;
+ end
+else
+ begin
+ print_err("Missing Chinese face identifier"); error;
+ end;
+
+@
+@d is_digit(#)==(# >= '0' and # <= '9')
+@<Fetch the font design size and compute font 'at' size@>=
+ds:=0;
+while is_digit(str_pool[j]) do
+ begin
+ ds:= ds*10+(str_pool[j]-'0');
+ incr(j);
+ end;
+if ds=0 then
+ begin
+ print_err("Missing CJK font size specification, replaced by 10pt");
+ ds:=10; {set to default size: 10pt}
+ error;
+ end;
+dsize:=mult_integers(ds,unity);
+if s=-1000 then
+ size:=dsize
+else
+ if s>=0 then size:=s
+ else size:=xn_over_d(dsize, -s, 1000);
+
+@
+@d defined_cfont(#)==(#)<cfont_ptr
+@d undefined_cfont(#)==(#)=cfont_ptr
+
+@<Declare the procedure called |check_cfont|@>=
+function check_cfont(@!cface_num:internal_cface_number;@!size:scaled):internal_cfont_number;
+label done;
+var f:internal_cfont_number;
+begin
+f:=cfont_base+1;
+while (f<cfont_ptr) do
+ begin
+ if cface_num=cfont_face[f] and size=cfont_size[f] then goto done;
+ incr(f);
+ end;
+done:check_cfont:=f;
+end;
+
+@ @<If this CJK font has already been...@>=
+f:=check_cfont(cface_num,size);
+if defined_cfont(f) then goto common_ending;
+
+
+@
+@<Declare the procedure called |make_cfont|@>=
+function make_cfont(cfn:internal_cface_number; dsize, size:scaled):internal_cfont_number;
+begin
+if cfont_ptr <= cfont_max then
+ begin
+ cfont_face[cfont_ptr]:=cfn;@/
+ cfont_dsize[cfont_ptr]:=dsize;@/
+ cfont_size[cfont_ptr]:=size;@/
+ cfont_width[cfont_ptr]:=fw_times_sd(cface_fw_width[cfn], size);@/
+ cfont_height[cfont_ptr]:=fw_times_sd(cface_fw_height[cfn], size);@/
+ cfont_depth[cfont_ptr]:=fw_times_sd(cface_fw_depth[cfn], size);@/
+ cfont_glue_spec[cfont_ptr]:=new_spec(zero_glue);
+ set_cglue_spec(cfont_ptr);
+ cfont_ceglue_spec[cfont_ptr]:=new_spec(zero_glue);
+ set_ceglue_spec(cfont_ptr);
+ make_cfont:=cfont_ptr;@/
+ incr(cfont_ptr);
+ end
+else
+ begin
+ print_err("CJK font table overflow"); error;
+ end
+end;
+
+
+@ @<Cases of |print_cmd_chr|...@>=
+set_cfont:begin print("select CJK font "); slow_print(cface[cfont_face[chr_code]]);
+ print(" at ("); print_scaled(cfont_size[chr_code]); print("pt"); print(")");
+ end;
+
+@* \[57] Matching faces.
+@d min_ectbl=0
+@d max_ectbl=255
+
+@ @<Types...@>=
+@!internal_ectbl_number=min_ectbl..max_ectbl;
+
+
+@ @<Global variables@>=
+@!ectbl_eface_name:array[internal_ectbl_number] of str_number;
+ {the table of English face names }
+@!ectbl_ptr:internal_ectbl_number;
+ {index to the first unused entry}
+
+@ |ectbl_cface_num| table entries are already initialized in section 232.
+
+@<Initialize table entries...@>=
+ectbl_ptr:=min_ectbl;
+equiv(ectbl_cface_num_base):=null_cface;
+eq_type(ectbl_cface_num_base):=data;
+eq_level(ectbl_cface_num_base):=level_one;
+for k:=ectbl_cface_num_base+1 to font_matching_table_base-1 do
+ eqtb[k]:=eqtb[ectbl_cface_num_base];
+
+
+@ @<Put each of \TeX's primitives into the hash table@>=
+primitive("PUXfacematch",pux_face_match,0);
+
+@ @<Cases of |print_cmd_chr|...@>=
+pux_face_match: print_esc("PUXfacematch");
+
+@ @<Assignments@>=
+pux_face_match: match_ec_face(a);
+
+
+@ The function |find_ec_num| lookup the |ectbl_eface_name| table
+for the name |eface_name|. It returns the index to the name if the name
+exits; otherwose, it returns the current value of |ectbl_ptr|.
+
+@d ectbl_found(#)==((#)<ectbl_ptr)
+
+@<Declare the function called |find_ec_num|@>=
+function find_ec_num(eface_name:str_number):internal_ectbl_number;
+ label done;
+ var k:integer;@/
+ begin
+ k:=min_ectbl;
+ while k < ectbl_ptr do
+ begin
+ if str_eq_str(eface_name,ectbl_eface_name[k]) then goto done;
+ incr(k);
+ end;
+done: find_ec_num:=k;
+ end;
+
+@
+@<Declare subprocedures for |prefixed_command|@>=
+procedure make_cfont_id (f:internal_cfont_number; a:small_number);
+var
+@!i:0..23;
+@!m:integer;
+@!u: pointer;
+@!t:str_number;
+@!n:integer;
+begin
+buffer[buf_size+1]:='C';
+buffer[buf_size+2]:='F';
+buffer[buf_size+3]:='O';
+buffer[buf_size+4]:='N';
+buffer[buf_size+5]:='T';
+m:=buf_size+6;
+n:=f; i:=0;
+repeat dig[i]:=n mod 10; n:=n div 10; incr(i);
+until n=0;
+while i>0 do {append design size}
+ begin decr(i);
+ buffer[m]:="0"+dig[i];
+ incr(m);
+ end;
+no_new_control_sequence:=false;
+u:=id_lookup(buf_size+1,m-buf_size-1);
+no_new_control_sequence:=true;
+t:=text(u);
+define(u,set_cfont,f); eqtb[font_id_base+f]:=eqtb[u]; font_id_text(f):=t;
+end;
+
+@ @<Declare PUTeX subprocedures for |prefixed_command|@>=
+function fetch_efont_face (@!efont_name:str_number):str_number;
+var k:integer;@/
+@!p:pool_pointer;
+@!s: str_number;
+begin
+ p:=str_start[efont_name+1]-1; {last char position of efont\_name}@/
+ while is_digit(str_pool[p]) do decr(p); {assumed that the TeX font name has letters}
+ k:=str_start[efont_name];
+ while k <= p do
+ begin
+ append_char(str_pool[k]);
+ incr(k);
+ end;
+ s:=make_string;
+ fetch_efont_face:=s;
+end;
+
+
+@
+@<Declare subprocedures for |prefixed_command|@>=
+@<Declare the function called |find_ec_num|@>@;
+procedure match_ec_face(@!a:small_number);
+label done1, done2, exit;
+var k, f:integer;
+@!eface_name, @!efname, @!efont_name, @!cface_id:str_number;
+@!cfont_num:internal_cfont_number;
+@!cface_num:internal_cface_number;
+@!err:boolean;
+ begin
+ err:=false; f:=ectbl_ptr;@/
+ eface_name:=scan_name;
+ if cur_cmd=pux_set_cface then
+ eface_name:=fetch_efont_face(font_name[cur_font]) {should be flushed later}
+ else if eface_name=0 then begin
+ print_err("Missing a TeX face name");
+ error; goto exit;
+ end;
+ f:=find_ec_num(eface_name);
+ if ectbl_found(f) then begin {it is already in the |ectbl_eface_name| table}
+ flush_string;
+ eface_name:=ectbl_eface_name[f]
+ end;
+ if cur_cmd=pux_set_cface then begin {the second form: match face of current efont}
+ cface_num:=cur_chr;
+ @<Define the |cur_cfont| according to |cur_font| and |cface_num|@>;
+ end
+ else
+ @<Fetch a Chinese face id@>;
+ @<Add this face matching@>;
+exit: end;
+
+@ @<Define the |cur_cfont| according to |cur_font| and |cface_num|@>=
+cfont_num:=check_cfont(cface_num, font_size[cur_font]);
+if undefined_cfont(cfont_num) then begin
+ cfont_num:=make_cfont(cface_num,font_dsize[cur_font],font_size[cur_font]);
+ make_cfont_id(cfont_num,a);
+ end;
+define(cur_cfont_loc,data,cfont_num)
+
+
+
+@ @<Fetch a Chinese face id@>=
+begin
+@<Get the next non-blank non-call token@>;
+if cur_cmd=pux_set_cface then
+ cface_num:=cur_chr
+else begin
+ print_err("Missing a CJK font face identifier");
+ err:=true; error;
+ cface_num:=pux_default_cface;
+ end
+end
+
+@ @<Add this face matching@>=
+if f > max_ectbl then begin
+ print_err("Font face matching table overflow");
+ err:=true;
+ error;
+ end;
+if not err then begin
+ define(ectbl_cface_num_base+f,data,cface_num);
+ if f = ectbl_ptr then begin {add this new eface name the the |eface_name table|}
+ ectbl_eface_name[f]:=eface_name;
+ incr(ectbl_ptr);
+ end;
+ end
+
+@ @<Declare subprocedures for |prefixed_command|@>=
+function lookup_cface (@!efont_name: str_number) : internal_cface_number;
+var k:integer;@/
+@!cface_num:internal_cface_number;@/
+@!eface_name:str_number;@/
+begin
+ eface_name:=fetch_efont_face(efont_name);
+ k:=find_ec_num(eface_name);
+ flush_string;
+ if ectbl_found(k) then
+ cface_num:=ectbl_cface_num(k)
+ else cface_num:=pux_default_cface;
+ lookup_cface:=cface_num;
+end;
+
+
+@* \[60] Font matching.
+
+@ @<Initialize table entries...@>=
+equiv(font_matching_table_base):=null_cfont;
+eq_type(font_matching_table_base):=data;
+eq_level(font_matching_table_base):=level_one;
+for k:=font_matching_table_base+1 to math_font_base-1 do
+ eqtb[k]:=eqtb[font_matching_table_base];
+
+@ @<Put each of \TeX's primitives into the hash table@>=
+primitive("PUXfontmatch",pux_font_match,0);
+
+
+@ @<Assignments@>=
+pux_font_match: match_ec_font(a);
+
+@ @<Declare subprocedures for |prefixed_command|@>=
+procedure match_ec_font(@!a:small_number);
+label done;
+var efont_num:internal_font_number;
+@!cfont_num:internal_cfont_number;
+@!cface_num:internal_cface_number;
+begin
+ @<Get the next non-blank non-call token@>;
+ if cur_cmd = pux_set_cface then {the first form}
+ begin
+ efont_num:=cur_font;
+ cface_num:=cur_chr;
+ @<Define the |cur_cfont| according to |cur_font| and |cface_num|@>;
+ goto done;
+ end;
+ if cur_cmd = set_font then {the second form}
+ efont_num:=cur_chr
+ else begin
+ print_err("Missing Tex font identifier");
+ help2("I was looking for a control sequence whose")@/
+ ("current meaning has been defined by \font.");
+ back_error; efont_num:=null_font;
+ end;
+ @<Get the next non-blank non-call token@>;
+ if cur_cmd = set_cfont then cfont_num:=cur_chr
+ else begin
+ print_err("Missing CJK font identifier");
+ help2("I was looking for a control sequence whose")@/
+ ("current meaning has been defined by \cfont.");
+ back_error; cfont_num:=null_cfont;
+ end;
+done:
+ if efont_num<>null_font and cfont_num<>null_cfont then
+ define(font_matching_table_base+efont_num-font_base,data,cfont_num);
+end;
+
+@ @<Other variables used by the procedure |prefixed_command|@>=
+@!cface_num:internal_cface_number;
+@!cfont_num:internal_cfont_number;
+
+@ @<Set the matching CJK font@>=
+cfont_num:=font_matching_table(cur_chr);
+if cfont_num=null_cfont then begin {efont not mapped}
+ if cur_cface=null_cface then
+ cface_num:=lookup_cface(font_name[cur_chr])
+ else cface_num:=cur_cface;
+ @<Build a CJK font according to |cur_chr| and |cface_num| if it is not exist@>;
+ end
+else
+ if cur_cface<>null_cface and cfont_face[cfont_num]<>cur_cface then begin
+ cface_num:=cur_cface;
+ @<Build a CJK font according to |cur_chr| and |cface_num| if it is not exist@>;
+ end;
+define(cur_cfont_loc,data,cfont_num)
+
+@ @<Build a CJK font according to |cur_chr| and |cface_num| if it is not exist@>=
+cfont_num:=check_cfont(cface_num, font_size[cur_chr]);
+if undefined_cfont(cfont_num) then begin
+ cfont_num:=make_cfont(cface_num,font_dsize[cur_chr],font_size[cur_chr]);
+ make_cfont_id(cfont_num,a);
+ end
+
+@ @<Assignments@>=
+set_cfont: define(cur_cfont_loc,data,cur_chr);
+
+@ @<Other variables used by the procedure |prefixed_command|@>=
+cface_id:str_number;
+
+@ @<Assignments@>=
+pux_set_cface: begin
+ cface_num:=cur_chr;
+ if cface_num <> cfont_face[cur_cfont] then begin
+ @<Define the |cur_cfont| according to |cur_font| and |cface_num|@>;
+ end;
+ define(cur_cface_loc,data,cface_num);
+ end;
+
+@ @<Put each of \TeX's primitives into the hash table@>=
+primitive("puxgRotateCtext",puxg_assign_flag,int_base+puxg_rotate_ctext_code);
+primitive("puxXspace",puxg_assign_int,int_base+pux_xspace_code);
+primitive("puxCJKcharOther",puxg_assign_int,int_base+pux_wcharother_code);
+primitive("puxCJKinput",puxg_assign_int,int_base+pux_CJKinput_code);
+primitive("puxCharSet",puxg_assign_int,int_base+pux_charset_code);
+primitive("puxgCfaceDepth",puxg_assign_int,int_base+puxg_cface_depth_code);
+
+
+@ @<Cases of |print_cmd_chr|...@>=
+puxg_assign_flag:
+ if chr_code=puxg_rotate_ctext_code+int_base then
+ print_esc("puxgRotateCtext");
+puxg_assign_int:
+ if chr_code=pux_xspace_code+int_base then
+ print_esc("puxXspace")
+ else if chr_code=pux_wcharother_code+int_base then
+ print_esc("puxCJKcharOther")
+ else if chr_code=pux_CJKinput_code+int_base then
+ print_esc("puxCJKinput")
+ else if chr_code=pux_charset_code+int_base then
+ print_esc("puxCharSet")
+ else if chr_code=puxg_cface_depth_code+int_base then
+ print_esc("puxgCfaceDepth");
+
+@ @<Assignments@>=
+puxg_assign_flag: begin p:=cur_chr; scan_optional_equals; scan_int;
+ if cur_val=0 and eqtb[p].int<>0 then begin
+ print_err("Reset a PUTeX global parameter is not allowed here");
+ help2("If a PUTeX global parameter was set to be a nonzero value,")@/
+ ("it can't be reset to be zero again");
+ error;
+ end
+ else begin
+ if p=puxg_rotate_ctext_code+int_base then
+ @<Handle the command |puxgRotateCtext|@>;
+ word_define(p,cur_val);
+ end;
+ end;
+
+@ @<Handle the command |puxgRotateCtext|@>=
+if puxg_rotate_ctext=0 and cur_val<>0 then begin
+ n:=cface_base;
+ while n < cface_ptr do begin
+ if cface_style[n] mod 2 = 1 then
+ cface_style[n]:=cface_style[n]-rotated
+ else
+ cface_style[n]:=cface_style[n]+rotated;
+ incr(n);
+ end;
+ end
+
+@ @<Assignments@>=
+puxg_assign_int: begin p:=cur_chr; q:=p-int_base;
+ scan_optional_equals; scan_int;
+ if cur_val < 0 then begin
+ print_err("Negative "); print_param(p-int_base);
+ print(" value ("); print_int(cur_val); print("), it remains unchanged");
+ help1("This PUTeX parameter can't be negative.");
+ error;
+ end
+ else if q=pux_charset_code and cur_val > 255 then begin
+ print_err("Too large "); print_param(q);
+ print(" value ("); print_int(cur_val); print("), it remains unchanged");
+ help1("The value of document charset should be in the range 0..255.");
+ error;
+ end
+ else begin
+ case q of
+ pux_xspace_code,pux_wcharother_code,pux_CJKinput_code,pux_charset_code:word_define(p, cur_val);
+ puxg_cface_depth_code: if cur_val<>eqtb[p].int then
+ @<Set PUTeX global parameter |puxgCfaceDepth|@>;
+ othercases begin
+ print_err("Unknow integer parameter!");
+ error;
+ end;
+ endcases
+ end;
+ end;
+
+@ @<Set PUTeX global parameter |puxgCfaceDepth|@>=
+begin
+ if cur_val>1000 then begin
+ print_err("Improper `depth' value (");
+ print_int(cur_val); print("). It is ignored");
+ error;
+ end
+ else begin
+ word_define(p,cur_val);
+ cface_fw_default_depth:=convfix(puxg_cface_depth);
+ n:=cface_base;
+ while n<cface_ptr do begin
+ cface_fw_depth[n]:=cface_fw_default_depth;
+ incr(n);
+ end;
+ n:=cfont_base+1;
+ while n<cfont_ptr do begin
+ cfont_depth[n]:=fw_times_sd(cface_fw_depth[cfont_face[n]], cfont_size[n]);
+ incr(n);
+ end;
+ end;
+end
+
+@
+@d pux_set_cface_csp=0
+@d pux_set_cface_cesp=1
+@d pux_set_cface_depth=2
+@<Put each of \TeX's primitives into the hash table@>=
+primitive("PUXcfacecspace",pux_set_cface_attrib,pux_set_cface_csp);
+primitive("PUXcfacecespace",pux_set_cface_attrib,pux_set_cface_cesp);
+primitive("PUXcfacedepth",pux_set_cface_attrib,pux_set_cface_depth);
+
+@ @<Cases of |print_cmd_chr|...@>=
+pux_set_cface_attrib: begin
+ case chr_code of
+ pux_set_cface_csp:print_esc("PUXcfacecspace");
+ pux_set_cface_cesp:print_esc("PUXcfacecespace");
+ pux_set_cface_depth:print_esc("PUXcfacedepth");
+ endcases;
+ end;
+
+@ @<Assignments@>=
+pux_set_cface_attrib: begin p:=cur_chr;
+ @<Get the next non-blank non-call token@>;
+ if cur_cmd=pux_set_cface then
+ cface_num:=cur_chr
+ else begin
+ cface_num:=null_cface;
+ print_err("Missing a CJK font face identifier");
+ error;
+ end;
+ scan_optional_equals;
+ if p=pux_set_cface_csp or p=pux_set_cface_cesp then
+ @<Scan spacing dimension of CJK font face@>
+ else
+ scan_int;
+
+ if cface_num<>null_cface then begin
+ if p=pux_set_cface_csp then
+ @<Modify the cspace factor of the specified chinese face@>
+ else if p=pux_set_cface_cesp then
+ @<Modify the cespace factor of the specified chinese face@>
+ else if p=pux_set_cface_depth then
+ @<Modify the depth factor of the specified chinese face@>;
+ end;
+ end;
+
+@ @<Other variables used by the procedure |prefixed_command|@>=
+@!width_value:integer; {width of space}
+@!stretch_value:integer; {stretch of space}
+@!shrink_value:integer; {shrink of space}
+
+@
+@d puxg_set_cspace=0
+@d puxg_set_cespace=1
+
+@<Scan spacing dimension of CJK font face@>=
+begin
+ scan_optional_equals;
+ scan_int;
+ width_value:=cur_val;
+ if scan_keyword("plus") then begin
+ scan_int; stretch_value:=cur_val;
+ end
+ else {make stretch value compatible to \PUTeX 3}
+ if width_value < 250 and p = puxg_set_cspace then stretch_value:=125
+ else stretch_value:=width_value/2;
+
+ if scan_keyword("minus") then begin
+ scan_int; shrink_value:=cur_val;
+ end
+ else {make shrink value compatible to \PUTeX 3}
+ if width_value > 0 then shrink_value:=width_value div 3
+ else shrink_value:=-width_value div 3;
+end
+
+@ @<Modify the cspace factor of the specified chinese face@>=
+begin
+ if cface_csp_width[cface_num]<>width_value or
+ cface_csp_stretch[cface_num]<>stretch_value or
+ cface_csp_shrink[cface_num]<>shrink_value then begin
+ cface_csp_width[cface_num]:=width_value;
+ cface_csp_stretch[cface_num]:=stretch_value;
+ cface_csp_shrink[cface_num]:=shrink_value;
+ n:=cfont_base+1;
+ while n<cfont_ptr do begin
+ if cface_num = cfont_face[n] then set_cglue_spec(n);
+ incr(n);
+ end;
+ end;
+end
+
+@ @<Modify the cespace factor of the specified chinese face@>=
+begin
+ if cface_cesp_width[cface_num]<>width_value or
+ cface_cesp_stretch[cface_num]<>stretch_value or
+ cface_cesp_shrink[cface_num]<>shrink_value then begin
+ cface_cesp_width[cface_num]:=width_value;
+ cface_cesp_stretch[cface_num]:=stretch_value;
+ cface_cesp_shrink[cface_num]:=shrink_value;
+ n:=cfont_base+1;
+ while n<cfont_ptr do begin
+ if cface_num=cfont_face[n] then set_ceglue_spec(n);
+ incr(n);
+ end;
+ end;
+end
+
+@ @<Modify the depth factor of the specified chinese face@>=
+begin
+ cur_val:=convfix(cur_val);
+ if cface_fw_depth[cface_num]<>cur_val then begin
+ cface_fw_depth[cface_num]:=cur_val;
+ n:=cfont_base+1;
+ while n<cfont_ptr do begin
+ if cface_num=cfont_face[n] then
+ cfont_depth[n]:=fw_times_sd(cface_fw_depth[cface_num], cfont_size[n]);
+ incr(n);
+ end;
+ end;
+end
+
+@
+@d pux_set_cfont_csp=0
+@d pux_set_cfont_cesp=1
+@<Put each of \TeX's primitives into the hash table@>=
+primitive("PUXcfontcspace",pux_set_cfont_attrib,pux_set_cfont_csp);
+primitive("PUXcfontcespace",pux_set_cfont_attrib,pux_set_cfont_cesp);
+
+@ @<Cases of |print_cmd_chr|...@>=
+pux_set_cfont_attrib: begin
+ case chr_code of
+ pux_set_cfont_csp:print_esc("PUXcfontcspace");
+ pux_set_cfont_cesp:print_esc("PUXcfontcespace");
+ endcases;
+ end;
+
+@ @<Assignments@>=
+pux_set_cfont_attrib: begin p:=cur_chr;
+ @<Get the next non-blank non-call token@>;
+ if cur_cmd = set_cfont then {the first form}
+ begin
+ cfont_num:=cur_chr;
+ end
+ else if cur_cmd = set_font and cur_chr=cur_font then
+ cfont_num:=cur_cfont
+ else begin
+ print_err("Missing CJK font identifier");
+ help2("I was looking for a control sequence whose")@/
+ ("current meaning is a CJK font command.");
+ back_error; cfont_num:=null_cfont;
+ end;
+ scan_optional_equals;
+ case p of
+ pux_set_cfont_csp: begin
+ scan_glue(glue_val);
+ width(cfont_glue_spec[cfont_num]):=width(cur_val);
+ shrink(cfont_glue_spec[cfont_num]):=shrink(cur_val);
+ stretch(cfont_glue_spec[cfont_num]):=stretch(cur_val);
+ fast_delete_glue_ref(cur_val);
+ end;
+ pux_set_cfont_cesp: begin
+ scan_glue(glue_val);
+ width(cfont_ceglue_spec[cfont_num]):=width(cur_val);
+ shrink(cfont_ceglue_spec[cfont_num]):=shrink(cur_val);
+ stretch(cfont_ceglue_spec[cfont_num]):=stretch(cur_val);
+ fast_delete_glue_ref(cur_val);
+ end;
+ endcases;
+ end;
+
+@ @<Global variables@>=
+@!g_cspace_width:integer;
+@!g_cspace_shrink:integer;
+@!g_cspace_stretch:integer;
+@!g_cespace_width:integer;
+@!g_cespace_shrink:integer;
+@!g_cespace_stretch:integer;
+
+@
+@d default_csp_width=50
+@d default_cesp_width=150
+@<Set init...@>=
+g_cspace_width:=default_csp_width;
+g_cspace_shrink:=g_cspace_width div 3;
+g_cspace_stretch:=125;
+g_cespace_width:=default_cesp_width;
+g_cespace_shrink:=g_cespace_width div 3;
+g_cespace_stretch:=g_cespace_width div 2;
+
+@ @<Put each of \TeX's primitives into the hash table@>=
+primitive("puxgCspace",puxg_assign_space,puxg_set_cspace);
+primitive("puxgCEspace",puxg_assign_space,puxg_set_cespace);
+
+
+@ @<Cases of |print_cmd_chr|...@>=
+puxg_assign_space: begin
+ if chr_code = puxg_set_cspace then
+ print_esc("puxgCspace")
+ else if chr_code = puxg_set_cespace then
+ print_esc("puxgCEspace");
+ end;
+
+
+
+@ @<Assignments@>=
+puxg_assign_space: begin p:=cur_chr;
+ @<Scan spacing dimension of CJK font face@>;
+ if p = puxg_set_cspace then begin
+ g_cspace_width:=width_value;
+ g_cspace_stretch:=stretch_value;
+ g_cspace_shrink:=shrink_value;
+ n:=cface_base;
+ while n < cface_ptr do begin
+ cface_csp_width[n]:=width_value;
+ cface_csp_shrink[n]:=shrink_value;
+ cface_csp_stretch[n]:=stretch_value;
+ incr(n);
+ end;
+ n:=cfont_base+1;
+ while n<cfont_ptr do begin
+ set_cglue_spec(n);
+ incr(n);
+ end;
+
+ end
+ else if p = puxg_set_cespace then begin
+ g_cespace_width:=width_value;
+ g_cespace_stretch:=stretch_value;
+ g_cespace_shrink:=shrink_value;
+ end;
+ n:=cface_base;
+ while n < cface_ptr do begin
+ cface_cesp_width[n]:=width_value;
+ cface_cesp_shrink[n]:=shrink_value;
+ cface_cesp_stretch[n]:=stretch_value;
+ incr(n);
+ end;
+ n:=cfont_base+1;
+ while n<cfont_ptr do begin
+ set_ceglue_spec(n);
+ incr(n);
+ end;
+ end;
+
+
+@* \[61] Dump Font Info.
+
+@<Other variables used by the procedure |prefixed_command|@>=
+@!old_setting:0..max_selector; {holds |selector| setting}
+
+@ @<Put each of \TeX's primitives into the hash table@>=
+primitive("PUXdumpfontinfo",pux_dump_font_info,0);
+
+@ @<Cases of |print_cmd_chr|...@>=
+pux_dump_font_info: print_esc("PUXdumpfontinfo"); {TCW}
+
+@ @<Assignments@>=
+pux_dump_font_info: begin old_setting:=selector; selector:=log_only;@/
+ @<Print TeX fonts@>;@/
+ @<Print CJK font faces@>;@/
+ @<Print CJK fonts@>;@/
+ @<Print font faces matching table@>;@/
+ selector:=old_setting;
+ end;
+
+@ @<Print TeX fonts@>=
+print_ln; print("Tex fonts"); print_ln;
+n:=0;
+while n <= font_ptr do
+ begin
+ print_int(n); print(": "); print(font_name[n]);@/
+ print(" dsize= "); print_scaled(font_dsize[n]); print("pt");@/
+ print(" at "); print_scaled(font_size[n]); print("pt");@/
+ print(" matched CJK font="); print_int(font_matching_table(n));
+ print_ln; incr(n);
+ end
+
+@ @<Print CJK font faces@>=
+print("Chinese faces"); print_ln;
+n:=0;
+while n < cface_ptr do
+ begin
+ print_int(n); print(": "); print("id="); print(cface[n]);@/
+ print(" name="); print(cface_name[n]);@/
+ print(" charset="); print_int(cface_charset[n]);@/
+ print(" weight="); print_int(cface_weight[n]);@/
+ print(" style="); print_int(cface_style[n]);@/
+ print(" w="); print_fixword(cface_fw_width[n]);@/
+ print(" h="); print_fixword(cface_fw_height[n]);@/
+ print(" d="); print_fixword(cface_fw_depth[n]);@/
+ print_ln; incr(n);
+ end
+
+@ @<Print CJK fonts@>=
+print("CJK fonts"); print_ln;
+n:=cfont_base;
+while n < cfont_ptr do
+ begin
+ print_int(n); print(":face= ");
+ print(cface[cfont_face[n]]);@/
+ print(" dsize= "); print_scaled(cfont_dsize[n]); print("pt");@/
+ print(" at "); print_scaled(cfont_size[n]); print("pt");@/
+ print_ln; incr(n);
+ end
+
+@ @<Print font faces matching table@>=
+print("English/CJK font faces matching table"); print_ln;
+n:=min_ectbl;
+while n < ectbl_ptr do
+ begin
+ print_int(n); print(": "); print("eface="); print(ectbl_eface_name[n]);@/
+ print(" cface_id="); print(cface[ectbl_cface_num(n)]);@/
+ print(" cface_num="); print_int(ectbl_cface_num(n));@/
+ print_ln; incr(n);
+ end
+
+@ @<Global variables@>=
+@!dvi_cf:internal_cfont_number; {the current chinese font}
+
+@ @<Output the CJK font definitions for all fonts that were used@>=
+while cfont_ptr>cfont_base do
+ begin if cfont_used[cfont_ptr] then dvi_cfont_def(cfont_ptr);
+ decr(cfont_ptr);
+ end
+
+
+@ @<Change font |dvi_cf| to |f|@>=
+begin if not cfont_used[f] then
+ begin dvi_cfont_def(f); cfont_used[f]:=true;
+ end;
+ dvi_out(cfnt); dvi_out((f-cfont_base-1) div 256); dvi_out((f-cfont_base-1) mod 256);
+ dvi_cf:=f;
+end
+
+@* \[62] Dump/undump \PUTeX\ internal information.
+
+@ @<Dump the CJK font face information@>=
+dump_int(cface_ptr);
+dump_int(cface_fw_default_depth);
+for k:=cface_base to cface_ptr-1 do begin
+ dump_int(cface[k]);
+ dump_int(cface_name[k]);
+ dump_int(cface_charset[k]);
+ dump_int(cface_weight[k]);
+ dump_int(cface_style[k]);
+ dump_int(cface_fw_width[k]);
+ dump_int(cface_fw_height[k]);
+ dump_int(cface_fw_depth[k]);
+ dump_int(cface_csp_width[k]);
+ dump_int(cface_csp_shrink[k]);
+ dump_int(cface_csp_stretch[k]);
+ dump_int(cface_cesp_width[k]);
+ dump_int(cface_cesp_shrink[k]);
+ dump_int(cface_cesp_stretch[k]);
+ print_ln;
+ print_int(k); print(": "); print("id="); print(cface[k]);@/
+ print(" name="); print(cface_name[k]);@/
+ print(" charset="); print_int(cface_charset[k]);@/
+ print(" weight="); print_int(cface_weight[k]);@/
+ print(" style="); print_int(cface_style[k]);@/
+ print(" w="); print_fixword(cface_fw_width[k]);@/
+ print(" h="); print_fixword(cface_fw_height[k]);@/
+ print(" d="); print_fixword(cface_fw_depth[k]);@/
+ end;
+print_ln;
+print_int(cface_ptr-cface_base); print(" preloaded CJK font face");
+if cface_ptr<>cface_base+1 then print_char("s")
+
+@ @<Undump the CJK font face information@>=
+undump_size(cface_base)(max_cface)('cface max')(cface_ptr);
+undump_int(cface_fw_default_depth);
+for k:=cface_base to cface_ptr-1 do begin
+ undump_size(0)(pool_size)('cface id')(cface[k]);
+ undump_size(0)(pool_size)('cface name')(cface_name[k]);
+ undump_size(0)(255)('charset size')(cface_charset[k]);
+ undump_size(1)(1000)('cface weight')(cface_weight[k]);
+ undump_size(0)(255)('cface style')(cface_style[k]);
+ undump_int(cface_fw_width[k]);
+ undump_int(cface_fw_height[k]);
+ undump_int(cface_fw_depth[k]);
+ undump_int(cface_csp_width[k]);
+ undump_int(cface_csp_shrink[k]);
+ undump_int(cface_csp_stretch[k]);
+ undump_int(cface_cesp_width[k]);
+ undump_int(cface_cesp_shrink[k]);
+ undump_int(cface_cesp_stretch[k]);
+ end
+
+@ @<Dump the face matching table@>=
+dump_int(ectbl_ptr);
+for k:=min_ectbl to ectbl_ptr-1 do
+ dump_int(ectbl_eface_name[k])
+
+@ @<Unump the face matching table@>=
+undump_size(min_ectbl)(max_ectbl)('ectbl_ptr')(ectbl_ptr);
+for k:=min_ectbl to ectbl_ptr-1 do
+ undump_size(0)(pool_size)('ectbl eface name')(ectbl_eface_name[k])
+
+@ @<Dump the CJK font information@>=
+begin
+dump_int(cfont_ptr);
+for k:=default_cfont to cfont_ptr-1 do begin
+ dump_int(cfont_face[k]);
+ dump_int(cfont_dsize[k]);
+ dump_int(cfont_size[k]);
+ dump_int(cfont_width[k]);
+ dump_int(cfont_height[k]);
+ dump_int(cfont_depth[k]);
+ dump_int(cfont_glue_spec[k]);
+ dump_int(cfont_ceglue_spec[k]);
+ print_ln;
+ print_int(k); print(":face= ");
+ print(cface[cfont_face[k]]);@/
+ print(" dsize= "); print_scaled(cfont_dsize[k]); print("pt");@/
+ print(" at "); print_scaled(cfont_size[k]); print("pt");@/
+ end;
+end
+
+@ @<Undump the CJK font information@>=
+begin
+undump_size(cfont_base)(cfont_max)('cfont max')(cfont_ptr);
+for k:=default_cfont to cfont_ptr-1 do begin
+ undump_size(cface_base)(max_cface)('cface max')(cfont_face[k]);
+ undump_int(cfont_dsize[k]);
+ undump_int(cfont_size[k]);
+ undump_int(cfont_width[k]);
+ undump_int(cfont_height[k]);
+ undump_int(cfont_depth[k]);
+ undump_int(cfont_glue_spec[k]);
+ undump_int(cfont_ceglue_spec[k]);
+ end;
+end
+
+@* \[63] Index.
+
+@z
+