%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% %%% WEB Change File for PUTeX (CJK version) %%% Modified and patched version for TeX Live %%% %%% Copyright (C) 1997-2004 Chey-Woei Tsay %%% Copyright (C) 2013-2014 Clerk Ma %%% %%% 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 "" @y \def\gglob{20, 26} % this should be the next two sections of "" \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@>@@/ @y @t\4@>@@/ @t\4@>@@/ @# { 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_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_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=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 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= @^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 @= 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. @= 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@> @= 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 @ @= begin repeat cur_chr:=buffer[k]; cat:=cat_code(cur_chr); incr(k); @y @ @= @^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: @; @y toks_register,assign_toks,def_family,set_font,def_font,set_cfont: @; @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:@; @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 @ @= begin scan_char_num; @y @ @= 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; @@; @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 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; @; @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; @; @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: @; cjknumber_code:@; nameseq_code:@; @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: @; cjknumber_code: @; nameseq_code: @; 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. @= procedure scan_font_ident; var f:internal_font_number; @!m:halfword; begin @; 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|. @= procedure scan_font_ident; var f:integer; @!m:halfword; begin @; 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 @; end; @y @; 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 @= reswitch: if is_char_node(p) then begin synch_h; synch_v; repeat f:=font(p); c:=character(p); if f<>dvi_f then @; 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 @; continue: p:=link(p); until not is_char_node(p); dvi_h:=cur_h; end else @ @y @= 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 @; 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 @; 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 @; continue: p:=link(p); until not is_char_node(p); dvi_h:=cur_h; end else @ @z @x dvi_out(post_post); dvi_four(last_bop); dvi_out(id_byte);@/ @y @; dvi_out(post_post); dvi_four(last_bop); dvi_out(doc_charset); dvi_out(id_byte);@/ @z @x @= 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 @= 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 @; @y char_num: begin scan_char_num; cur_chr:=cur_val; cur_cmd:=char_given; goto reswitch; end; pux_char_given:@; 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 @; @z @x if cur_chr="-" then @ 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 @ 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@>@@; procedure main_control; {governs \TeX's activities} @y @t\4@>@@; 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); @@; 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@>@@; @z @x main_loop:@; main_loop:@@;@/ 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} @; 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 @ @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: @; adjusted_hbox_group: begin adjust_tail:=adjust_head; @; 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 @; 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 @; 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; @; 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@>@@t@>@;@/ procedure prefixed_command; @y @t\4@>@@t@>@;@/ @t\4@>@@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?} @@; @z @x set_font: define(cur_font_loc,data,cur_chr); @y set_font: begin define(cur_font_loc,data,cur_chr);@/ @; 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; @; @; 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 @@; @@; @@; @@; 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} @@; 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;@/ @; 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 @; end; define(u,set_font,null_font); @; 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 @= t:=info(p); if t0 then info(p):=t-c+equiv(b+c); end @y @= t:=info(p); if t0 then info(p):=t-c+equiv(b+c); end @z @x @; @y @; @; @; @; @z @x @; @y @; @; @; @; @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. @ @= @!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; @ @= expand_char:=false; @ The default catcode for CJK characters is `letter'. @= 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) @= 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("}"); @ @= 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; @ @= primitive("PUXrangecatcode",pux_range_catcode,0); primitive("PUXrangetypecode",pux_range_type_code,0); @ @= @!bc, ec: halfword; {the begin char and end char of code range} @ @= 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; @ @= for k:=0 to 255 do local_names(k) := "?"; @ @= function scan_name: str_number; begin @; 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; @ @= 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. @= @!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 @ @= 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$. @= 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. @= 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; @ @= 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); @ @= 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"); @ @= pux_get_int: begin print_err("You can't assign values to internal read-only parameters."); error; end; @ @= 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 @ @= primitive("PUXsplitnumber",pux_split_number,0); @ @= 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. @= 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; @ @= begin scan_int; split_number(cur_val); end @ @= 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. @= 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; @ @= print_cjk_int(cur_val,C_arabic_digit_offset,negative_wsym_offset) @ @= print_cjk_int(saved_val,digit_base,sign) @ @= 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_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 @= @!fixword = integer; {this type is used for fixword (12.20) integers} @ @= 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.) @= 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 @; 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; @ @= primitive("PUXchar",pux_char_num,0); @ @= pux_char_num: print_esc("PUXchar"); @ @= 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 @ @= 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; @ @= 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)) @ @= @!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; @ @= 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 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 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]) @ @= main_cf:=cur_cfont; @; @; if not is_char_node(tail) then goto save_cur_wchar; main_loop_wchar+1:@; save_cur_wchar: fast_get_avail(lig_stack); font(lig_stack):=main_cf; character(lig_stack):=cur_chr; tail_append(lig_stack);@/ @; fetch_next_tok:get_next; {set only |cur_cmd| and |cur_chr|, for speed} @; x_token; {now expand and set |cur_cmd|, |cur_chr|, |cur_tok|} @; 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 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; @; end; pre_undet_glue_ptr:=null; end; end; goto save_cur_wchar; end @ @= 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 pre_undet_glue_ptr<>null then begin if link(pre_undet_glue_ptr)=tail then begin undet_glue_ptr:=tail; @; pre_undet_glue_ptr:=null; goto save_cur_wchar; end; pre_undet_glue_ptr:=null; end @ @= 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. @= if is_punc_wchar(cur_chr) then if is_tail_forbidden(cur_chr) then tail_append(new_penalty(inf_penalty)) @ @= 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 @ @= 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} @ @= hmode+spacer: @; hmode+ex_space: @; mmode+ex_space: begin if pux_xspace=0 then get_x_token; {lookahead} goto append_normal_space; end; hmode+pux_space:@; 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; @ @= 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 @ @= 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 @ @= 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 @= 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); @ @= 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; @ @= 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. @ @= primitive("PUXcfacedef",pux_cface_def,0); @ @= pux_cface_def: print_esc("PUXcfacedef"); {TCW} @ @= pux_cface_def: new_cface(a); @ @= @!cface_base=0; {CJK font face base} @!null_cface=0; {null CJK font faces} @ @= @!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+#) @= @!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; @ @= primitive("PUXsetdefaultcface",pux_set_default_cface,int_base+pux_default_cface_code); @ @= pux_set_default_cface: print_esc("PUXsetdefaultcface"); {TCW} @ @= pux_set_default_cface: begin p:=cur_chr; @; 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; @ @= 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; @ @= 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. @= 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(#)==((#)= 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; @ @= @@; 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;@/ @@; 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; @; @; @; @; @; @; @; common_ending: equiv(u):=f; eqtb[cface_id_base+f]:=eqtb[u]; cface_id_text(f):=t; end; @ @= 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 @ @= 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 @ @= 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 @ @= @!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} @ @= i_flag:=false; u_flag:=false; s_flag:=false;@/ r_flag:=false; v_flag:=false;@/ more_param:=true; while more_param do begin @; if cur_cmd=letter then case cur_chr of 'c','C': @; 'w','W': @; 'h','H': @; 'd','D': @; 't','T': @; 's','S': @; othercases more_param:=false; endcases else more_param:=false; end; back_input @ @= 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 @ @= 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 @ @= 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 @ @= 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 @ @= 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 @ @= begin scan_optional_equals;@/ @; 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 @; "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 @ @= begin if puxg_rotate_ctext<>0 then style:=style-rotated else style:=style+rotated; r_flag:=true; end @ @= if f=null_cface then goto common_ending @ @= 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 @ @= 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. @ @= @!cfont_base=font_max_limit+1; {CJK font base} @!cfont_max=font_max_limit+1+cfont_max_limit; {maximum internal chinese font number} @ @= @!internal_cfont_number=cfont_base..cfont_max; @ @= cur_cfont:=default_cfont; eq_type(cur_cfont_loc):=data; eq_level(cur_cfont_loc):=level_one;@/ @ @= @!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?} @ @= 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; @ @= cfont_ptr:=default_cfont; @ @= 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; @ @= 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; @ @= cfont_glue_spec[null_cfont]:=new_spec(zero_glue); cfont_ceglue_spec[null_cfont]:=new_spec(zero_glue); @ @= @!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; @ @= begin define(u, set_cfont, null_cfont); cface_num:=pux_default_cface;@/ @; @; @; f:=make_cfont(cface_num,dsize,size);@/ goto common_ending; end; @ @d is_letter(#)==((#>='A' and #<='Z') or (#>='a' and #<='z')) @= 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') @= 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(#)==(#)= 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= f:=check_cfont(cface_num,size); if defined_cfont(f) then goto common_ending; @ @= 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; @ @= 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 @ @= @!internal_ectbl_number=min_ectbl..max_ectbl; @ @= @!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. @= 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]; @ @= primitive("PUXfacematch",pux_face_match,0); @ @= pux_face_match: print_esc("PUXfacematch"); @ @= 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(#)==((#)= 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; @ @= 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; @ @= 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; @ @= @@; 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; @; end else @; @; exit: end; @ @= 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) @ @= begin @; 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 @ @= 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 @ @= 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. @ @= 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]; @ @= primitive("PUXfontmatch",pux_font_match,0); @ @= pux_font_match: match_ec_font(a); @ @= 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 @; if cur_cmd = pux_set_cface then {the first form} begin efont_num:=cur_font; cface_num:=cur_chr; @; 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; @; 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; @ @= @!cface_num:internal_cface_number; @!cfont_num:internal_cfont_number; @ @= 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; @; end else if cur_cface<>null_cface and cfont_face[cfont_num]<>cur_cface then begin cface_num:=cur_cface; @; end; define(cur_cfont_loc,data,cfont_num) @ @= 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 @ @= set_cfont: define(cur_cfont_loc,data,cur_chr); @ @= cface_id:str_number; @ @= pux_set_cface: begin cface_num:=cur_chr; if cface_num <> cfont_face[cur_cfont] then begin @; end; define(cur_cface_loc,data,cface_num); end; @ @= 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); @ @= 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"); @ @= 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 @; word_define(p,cur_val); end; end; @ @= 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 @ @= 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 @; othercases begin print_err("Unknow integer parameter!"); error; end; endcases end; end; @ @= 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= 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); @ @= 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; @ @= pux_set_cface_attrib: begin p:=cur_chr; @; 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 @ else scan_int; if cface_num<>null_cface then begin if p=pux_set_cface_csp then @ else if p=pux_set_cface_cesp then @ else if p=pux_set_cface_depth then @; end; end; @ @= @!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 @= 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 @ @= 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= 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= 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= primitive("PUXcfontcspace",pux_set_cfont_attrib,pux_set_cfont_csp); primitive("PUXcfontcespace",pux_set_cfont_attrib,pux_set_cfont_cesp); @ @= 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; @ @= pux_set_cfont_attrib: begin p:=cur_chr; @; 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; @ @= @!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 @= 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; @ @= primitive("puxgCspace",puxg_assign_space,puxg_set_cspace); primitive("puxgCEspace",puxg_assign_space,puxg_set_cespace); @ @= 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; @ @= puxg_assign_space: begin p:=cur_chr; @; 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= @!old_setting:0..max_selector; {holds |selector| setting} @ @= primitive("PUXdumpfontinfo",pux_dump_font_info,0); @ @= pux_dump_font_info: print_esc("PUXdumpfontinfo"); {TCW} @ @= pux_dump_font_info: begin old_setting:=selector; selector:=log_only;@/ @;@/ @;@/ @;@/ @;@/ selector:=old_setting; end; @ @= 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("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_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("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 @ @= @!dvi_cf:internal_cfont_number; {the current chinese font} @ @= while cfont_ptr>cfont_base do begin if cfont_used[cfont_ptr] then dvi_cfont_def(cfont_ptr); decr(cfont_ptr); end @ @= 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_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_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_int(ectbl_ptr); for k:=min_ectbl to ectbl_ptr-1 do dump_int(ectbl_eface_name[k]) @ @= 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]) @ @= 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 @ @= 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