% We start by making some default catcode assignments, in case we are % using ini\TeX{}. % \begin{macrocode} %<*pkg> \catcode`\{=1 \catcode`\}=2 \catcode`\#=6 \catcode`\^=7 % % \end{macrocode} % % \package{fontinst} uses some unusual, but convenient, settings of % |\catcode|. |@| and |_| are made letters, |~| is made a space, and % space and newline are ignored. Before setting those however, we save % the current values of the catcodes, so that they can be restored at % the end of \texttt{fontinst.sty}. % % \begin{macrocode} %<*pkg> \edef\spacecatcode{\the\catcode`\ } \edef\nlcatcode{\the\catcode`\^^M} \edef\atcatcode{\the\catcode`\@} \edef\underscorecatcode{\the\catcode`\_} \edef\tildecatcode{\the\catcode`\~} % \end{macrocode} % % \begin{macrocode} \catcode`\ =9 \catcode`\^^M=9 \catcode`\@=11 \catcode`\_=11 \catcode`\~=10 % % \end{macrocode} % \newlinechar=`\^^J % \begin{macro}{\a_read} % \begin{macro}{\b_read} % \begin{macro}{\a_filelineno} % \begin{macro}{\b_filelineno} % These control sequences are used for keeping track of the ``physical'' % side of the two input files. |\a_read| and |\b_read| are the stream % numbers. |\a_filelineno| and |\b_filelineno| are the respective % line numbers of the lines most recently read from these files. % \begin{macrocode} \newread\a_read \newread\b_read \newcount\a_filelineno \newcount\b_filelineno % \end{macrocode} % \end{macro}\end{macro}\end{macro}\end{macro} % % \begin{macro}{\a_lineno} % \begin{macro}{\b_lineno} % \begin{macro}{\a_bufbase} % \begin{macro}{\b_bufbase} % \begin{macro}{\a_bufmid} % \begin{macro}{\b_bufmid} % \begin{macro}{\a_buftop} % \begin{macro}{\b_buftop} % These count registers are used for managing the buffert of lines % that are read from the input files when a match between lines is % being looked for. This buffert consists of lines which are saved in % the macros % \begin{quote} % |\|\meta{letter}|_saved-|\meta{ofs} % \end{quote} % where \meta{letter} is |a| or |b| and \meta{ofs} is an integer, % being the index into the buffert. |\a_bufbase| and |\b_bufbase| % contain the \meta{ofs} of the first line currently in the buffert, % whereas |\a_buftop| and |\b_buftop| contain the \meta{ofs} of the % last such line. |\a_bufmid| and |\b_bufmid| hold the buffert % positions of the lines which are currently considered the next by % |\get_next_line|. If \(\mathtt{buftop}<\mathtt{bufmid}\) then the % buffert is empty. |\a_lineno| and |\b_lineno| are the respective % line numbers of the |\a_bufbase| and |\b_bufbase| lines. % % All these registers should be set globally. % \begin{macrocode} \newcount\a_lineno \newcount\b_lineno \newcount\a_bufbase \newcount\b_bufbase \newcount\a_bufmid \newcount\b_bufmid \newcount\a_buftop \newcount\b_buftop % \end{macrocode} % \end{macro}\end{macro}\end{macro}\end{macro}\end{macro}\end{macro} % \end{macro}\end{macro} % \begin{macro}{\get_next_line} % The |\get_next_line| macro is called as % \begin{quote} % |\get_next_line|\marg{letter} % \end{quote} % where \meta{letter} is |a| or |b|. This sets the % |\|\meta{letter}|_line| macro to the next line of that file and % updates the value of |\|\meta{letter}|_lineno|. % % The ``next line'' is normally read from input stream % |\|\meta{letter}|_read|, but if a line mismatch recently occured % then it might happen that the next line has already been read from % the file, and in that case it is taken from one of the % |\|\meta{letter}|_saved-|\meta{ofs} macros. % \begin{macrocode} \def\get_next_line#1{ \ifnum \csname#1_buftop\endcsname<\csname#1_bufmid\endcsname \ifeof \csname#1_read\endcsname \x_cs\let{#1_line}\end_of_file_line \else \read\csname#1_read\endcsname t\x_cs{o}{#1_line} \global\advance \csname#1_filelineno\endcsname \@ne \fi \else \expandafter\let \csname#1_line\expandafter\endcsname \csname#1_saved-\the\csname#1_bufmid\endcsname\endcsname \fi } % \end{macrocode} % \end{macro} % \begin{macro}{\end_of_file_line} % This macro expands to the text \verb*|(ENDOFFILE) | with the % catcodes it would have if read from an input file. It is used as an % end-of-file marker. % \begin{macrocode} \begingroup \catcode`\(=13 \catcode`\)=13 \gdef\end_of_file_line{(ENDOFFILE)~} \endgroup % \end{macrocode} % \end{macro} % \begin{macro}{\the_line} % The |\the_line| macro is called as % \begin{quote} % |\the_line|\marg{letter}\marg{ofs} % \end{quote} % where \meta{letter} is |a| or |b|, and \meta{ofs} is a \TeX\ number. % It expands to the control sequence |\|\meta{letter}|_saved-|^^A % \meta{ofs}. % \begin{macrocode} \def\the_line#1#2{\csname#1_saved-\number#2\endcsname} % \end{macrocode} % \end{macro} % \begin{macro}{\initialise_search} % The |\initialise_search| macro sets everything up for a search for % a match between lines. % % \begin{macrocode} \def\initialise_search{ \global\a_bufbase=\a_bufmid \global\b_bufbase=\b_bufmid \add_to_buffert{a} \add_to_buffert{b} \global\advance \a_bufmid \@ne \global\advance \b_bufmid \@ne } % \end{macrocode} % \end{macro} % \begin{macro}{\add_to_buffert} % The |\add_to_buffert| macro is called as % \begin{quote} % |\add_to_buffert|\marg{letter} % \end{quote} % It adds the line returned by |\get_next_line| to the corresponding % buffert (if it wasn't already there) and updates the counters for % that buffert. After this, the line following the line being put into % the buffert will be the line that |\get_next_line| returns. % \begin{macrocode} \def\add_to_buffert#1{ \ifnum \csname#1_buftop\endcsname<\csname#1_bufmid\endcsname \expandafter\let \csname#1_saved-\the\csname#1_bufmid\endcsname \expandafter\endcsname \csname#1_line\endcsname \global\advance \csname#1_buftop\endcsname \@ne \fi } % \end{macrocode} % \end{macro} \newcount\first_integer \newcount\second_integer % \begin{macro}{\match_lines} % The |\match_lines| macro tests if two lines can be considered the % same (up to metrics changes, which need not be small). It is called as % \begin{quote} % |\match_lines|\marg{line a}\marg{line b} % \end{quote} % \meta{line a} and \meta{line b} may be any amount of text which % eventually expands to the lines in question. |\match_lines| returns % its answer by setting the |_a_| switch to |false| (if the lines % match) or |true| (if the lines don't match). % % |\match_lines| also causes the |\first_dimen| and |\second_dimen| % registers, as well as the |_histogram_dimen_| switch to be updated, % so it can be immediately followed by a test of the metrics. % \begin{macrocode} \def\match_lines#1#2{ \first_integer=\z@ \second_integer=\z@ \first_dimen=\z@ \second_dimen=\z@ \x_cs\let{string-+}\empty_command \x_cs\let{string--}\empty_command % \end{macrocode} % \begin{macrocode} \def\sign{+} #1\line_stop \def\sign{-} #2\line_stop % \end{macrocode} % \begin{macrocode} \_a_false \expandafter\ifx \csname cmd-+ \expandafter\endcsname \csname cmd--\endcsname \else \_a_true \fi \ifnum \first_integer=\z@ \else \_a_true \fi \ifnum \second_integer=\z@ \else \_a_true \fi \expandafter\ifx \csname string-+ \expandafter\endcsname \csname string--\endcsname \else \_a_true \fi } % \end{macrocode} % \end{macro} % \begin{macro}{\try_matching} % \begin{macro}{\a_bufP} % \begin{macro}{\b_bufP} % The |\try_matching| descends through the buffert until the |_a_| % switch gets |false| or it has tried the bottommost lines in the % buffert. Since |\body| is already defined by the |\loop| in % |\process_lines|, |\try_matching| uses an explicit end recursion to % make the loop. % \begin{macrocode} \newcount\a_bufP \newcount\b_bufP \def\try_matching{ \global\advance \a_bufP \m@ne \global\advance \b_bufP \m@ne % % Begin debug % \wlog{a_bufbase:~\the\a_bufbase\space\space\space % b_bufbase:~\the\b_bufbase} % \wlog{a_bufmid:~\the\a_bufmid\space\space\space % b_bufmid:~\the\b_bufmid} % \wlog{a_buftop:~\the\a_buftop\space\space\space % b_buftop:~\the\b_buftop} % \wlog{a_bufP:~\the\a_bufP\space\space\space % b_bufP:~\the\b_bufP} % \begingroup % \def\do_left_paren{(}\def\do_right_paren{)} % \wlog{a_line:~\a_line} % \wlog{b_buf_line:~\the_line{b}{\b_bufP}} % \wlog{b_line:~\b_line} % \wlog{a_buf_line:~\the_line{a}{\a_bufP}^^J} % \endgroup % % End debug \match_lines{\a_line}{\the_line{b}{\b_bufP}} \if_a_ \match_lines{\the_line{a}{\a_bufP}}{\b_line} \if_a_ \else \global\a_bufmid=\a_bufP \fi \else \global\b_bufmid=\b_bufP \fi \ifnum \a_bufP>\a_bufbase \if_a_ \expandafter\expandafter\expandafter\try_matching \fi \fi } % \end{macrocode} % \end{macro} % \begin{macro}{\report_mismatch} % The |\report_mismatch| macro does precisely what it says. It also increases % the \texttt{bufbase} and \texttt{lineno} registers to point at the % matching lines. % \begin{macrocode} \def\report_mismatch{ \begingroup \def\do_left_paren{(} \def\do_right_paren{)} \wlog{Mismatch~in~first~file~(at~\the\a_lineno):} \loop \wlog{\the_line{a}{\a_bufbase}} \ifnum \a_bufbase<\a_bufmid \global\advance \a_bufbase \@ne \global\advance \a_lineno \@ne \repeat \wlog{Match~found~at~line~\the\a_lineno.} \wlog{Mismatch~in~second~file~(at~\the\b_lineno):} \loop \wlog{\the_line{b}{\b_bufbase}} \ifnum \b_bufbase<\b_bufmid \global\advance \b_bufbase \@ne \global\advance \b_lineno \@ne \repeat \wlog{Match~found~at~line~\the\b_lineno.} \endgroup \glyphified_location \ifnum 4>\compared_status \global\chardef\compared_status=4 \fi } % \end{macrocode} % \end{macro} \def\glyphified_location{ \ifx \encoding_name\empty_command \ifnum \m@ne<\last_character \wlog{This~is~related~to~slot~\the\last_character.^^J} \else \wlog{This~is~in~the~header.^^J} \fi \else \if_undefined{name-\encoding_name-\the\last_character}\then \ifnum \last_character=\m@ne \wlog{This~is~in~the~header.^^J} \else \wlog{This~is~related~to~slot~\the\last_character\space (unencoded).^^J} \fi \else \wlog{This~is~related~to~the~glyph~ \csname name-\encoding_name-\the\last_character\endcsname .^^J} \fi \fi } % \begin{macro}{\compared_status} % |\compared_status| is a \meta{chardef token} which stores the % current status of the comparision, according to the following table % \begin{enumerate} % \item[0] The property lists are equal---there may be checksum % differences, but nothing else. % \item[1] The property lists are almost equal---there are % differences in the metrics, but these are within the |\tolerance| % level. % \item[2] The property lists are essentially equal---there are % differences in the metrics, but these are within the |\tolerance| % level, with the exception of some \texttt{CHARHT}, % \texttt{CHARDP}, and \texttt{CHARIC} values. % \item[3] The property lists have metric differences---there are % metric differences not with category 2. % \item[4] The property lists are not completely matched. % \end{enumerate} % \end{macro} % \begin{macro}{\step_linenos} % The |\step_linenos| macro increments the |_lineno| line numbers. If % the current line was fetched from the buffert, then it also % increments the |_bufmid| and |_bufbase| registers, and checks % whether the buffert ended (in which case it is normalized to its % starting position, to conserve hash table space). % \begin{macrocode} \def\step_linenos{ \global\advance \a_lineno \@ne \ifnum \a_bufmid=\a_buftop \global\a_bufbase=\z@ \global\a_bufmid=\z@ \global\a_buftop=\m@ne \else\ifnum \a_bufmid<\a_buftop \global\advance \a_bufmid \@ne \global\advance \a_bufbase \@ne \fi\fi \global\advance \b_lineno \@ne \ifnum \b_bufmid=\b_buftop \global\b_bufbase=\z@ \global\b_bufmid=\z@ \global\b_buftop=\m@ne \else\ifnum \b_bufmid<\b_buftop \global\advance \b_bufmid \@ne \global\advance \b_bufbase \@ne \fi\fi } % \end{macrocode} % \end{macro} \newdimen\first_dimen \newdimen\second_dimen \newcount\ht_hist_i \newcount\ht_hist_ii \newcount\ht_hist_iii \newcount\ht_hist_iv \newcount\dp_hist_i \newcount\dp_hist_ii \newcount\dp_hist_iii \newcount\dp_hist_iv \newcount\ic_hist_i \newcount\ic_hist_ii \newcount\ic_hist_iii \newcount\ic_hist_iv % \begin{macro}{\clear_histograms} % This macro clears all the histograms. % \begin{macrocode} \def\clear_histograms{ \global\ht_hist_i=\z@ \global\ht_hist_ii=\z@ \global\ht_hist_iii=\z@ \global\ht_hist_iv=\z@ \global\dp_hist_i=\z@ \global\dp_hist_ii=\z@ \global\dp_hist_iii=\z@ \global\dp_hist_iv=\z@ \global\ic_hist_i=\z@ \global\ic_hist_ii=\z@ \global\ic_hist_iii=\z@ \global\ic_hist_iv=\z@ } % \enc{macrocode} % \end{macro} % \begin{macro}{\present_histograms} % This macro writes the histogram data to the log file. % \begin{macrocode} \def\present_histograms{ \wlog{\string\tolerance*~\space CHARHT~\space CHARDP~\space CHARIC} \wlog{~\space\space 1--~\space\space 10\hist_to_eight{ht}{i} \hist_to_eight{dp}{i}\hist_to_eight{ic}{i}} \wlog{~\space 10--~\space 100\hist_to_eight{ht}{ii} \hist_to_eight{dp}{ii}\hist_to_eight{ic}{ii}} \wlog{~100--~1000\hist_to_eight{ht}{iii}\hist_to_eight{dp}{iii} \hist_to_eight{ic}{iii}} \wlog{1000--10000\hist_to_eight{ht}{iv}\hist_to_eight{dp}{iv} \hist_to_eight{ic}{iv}} } \def\hist_to_eight#1#2{\x_cs\hist_to_eight_i{#1_hist_#2}} \def\hist_to_eight_i#1{ \ifnum #1<\@M \four_spaces \ifnum #1<\one_hundred \space\space \ifnum 10>#1 ~\fi \else \ifnum #1<\one_thousand \space\fi \fi \else \ifnum 1000000>#1 \space\space \ifnum 100000>#1 ~\fi \else \ifnum 1000000>#1 ~\fi \fi \fi \the#1 } % \end{macrocode} % \end{macro} % \begin{macro}{\metric_statistics} % \begin{macro}{\metric_origin} % The |\metric_statistics| macro takes care of comparing the metrics % by inspecting the values of |\first_dimen| and |\second_dimen|. It % has four classes of differences, which are represented by % |\compared_status| values 0--3: no difference, tolerable (almost no) % difference, histogrammed (essentially no) difference, and % non-tolerable difference. If a non-tolerable difference is found, % then the current lines are written to the log file. Histogrammed % differences causes the corresponding % |\|\meta{type}|_hist_|\meta{group} register to be incremented, and % tolerable differences only affect the value of |\compared_status|. % % The |\metric_origin| macro contains the \meta{type} of the metric % data. It is usually empty, but PL properties with metrics that have % histograms set it so that the correct histogram is updated. % % \begin{macrocode} \def\metric_statistics{ \_a_false % \ifdim \first_dimen<\z@ \first_dimen=-\first_dimen \fi \ifdim \first_dimen=\z@ \else\ifdim \first_dimen<\tolerance \ifnum 1>\compared_status \global\chardef\compared_status=1 \fi \else\ifx \metric_origin\empty_command \_a_true \else \a_count=\@ne \def\a_macro{10} \loop\ifdim \a_macro\tolerance<\first_dimen \edef\a_macro{\a_macro 0} \advance \a_count \@ne \repeat \if_undefined{\metric_origin _hist_ \romannumeral\a_count}\then \_a_true \else \global\advance \csname \metric_origin _hist_ \romannumeral\a_count \endcsname \@ne \ifnum 2>\compared_status \global\chardef\compared_status=2 \fi \fi \fi\fi\fi % \ifdim \second_dimen<\z@ \second_dimen=-\second_dimen \fi \ifdim \second_dimen=\z@ \else\ifdim \second_dimen<\tolerance \ifnum 1>\compared_status \global\chardef\compared_status=1 \fi \else\ifx \metric_origin\empty_command \_a_true \else \a_count=\@ne \def\a_macro{10} \loop\ifdim \a_macro\tolerance<\second_dimen \edef\a_macro{\a_macro 0} \advance \a_count \@ne \repeat \if_undefined{\metric_origin _hist_ \romannumeral\a_count}\then \_a_true \else \global\advance \csname \metric_origin _hist_ \romannumeral\a_count \endcsname \@ne \ifnum 2>\compared_status \global\chardef\compared_status=2 \fi \fi \fi\fi\fi % \if_a_ \ifnum 3>\compared_status \global\chardef\compared_status=3 \fi \begingroup \def\do_left_paren{(} \def\do_right_paren{)} \wlog{Metric~differences~at~lines~\the\a_lineno\space and~\the\b_lineno\space respectively:} \wlog{\a_line} \wlog{\b_line} \endgroup \glyphified_location \fi } % \end{macrocode} % \end{macro}\end{macro} \newif\if_b_ % \begin{macro}{\process_lines} % The |\process_lines| macro is the cheif executive in the comparision. % Its normal mode of operation is to retrive the next two lines from % the input files, match them, and update the metric differences % statistics. If the lines do not match, however, it starts building a % buffert of lines in which it searches for two matching lines. When % these two lines are found the mismatching portions of the files are % written to the log file, and the metric difference statistics are % updated for the two lines that matched. % % \begin{macrocode} \def\process_lines{ \get_next_line{a} \get_next_line{b} \match_lines{\a_line}{\b_line} \if_a_ % \end{macrocode} % Now the process of trying to find a match begins. At each step of % the search for a match, it tries all possible matches with the % lines read so far that haven't been tried at an earlier step. % \begin{macrocode} % \tracingmacros=\@ne\tracingcommands=\tw@ % DEBUG \initialise_search \loop \get_next_line{a} \get_next_line{b} \add_to_buffert{a} \add_to_buffert{b} \match_lines{\a_line}{\b_line} \if_a_ \global\a_bufP=\a_bufmid \global\b_bufP=\b_bufmid \try_matching \fi \if_a_ \global\advance \a_bufmid \@ne \global\advance \b_bufmid \@ne \ifnum \a_bufmid>\sixt@@n \errmessage{Big~buffert.~\the\a_lineno[\the\a_filelineno]: \the\b_lineno[\the\b_filelineno]} \fi % DEBUG \repeat \report_mismatch % \tracingcommands=\z@\tracingmacros=\z@ % DEBUG % \end{macrocode} % \begin{macrocode} \fi \metric_statistics \step_linenos \par % DEBUG \if \ifx \a_line\end_of_file_line \ifx \b_line\end_of_file_line 1\else 0\fi\else 0\fi 0 % then \expandafter\process_lines \fi } % \end{macrocode} % \end{macro} \def\loadencoding#1{{ \def\do_slot{\x_cs\xdef{name-#1-\the\slot_number}{\slot_name}} \inputetx{#1} }} % \begin{macro}{\comparePLs} % The |\comparePLs| command compares two property lists files. It is % geared against verifying that two different such files are as good % as equal, and it might take a very long time before it gives up on % trying to find any resemblance between them. It is furthermore only % meant to be used on (V)PL files generated by \package{TFtoPL} or % \package{VFtoVP}, because it assumes the property lists follow a % stricter syntax than \package{PLtoTF} and \package{VPtoVF} requires % them to. Finally it needs to be said that the comparision is rather % stupid in many respects, as it is completely line-oriented and % takes no notice of what kind of property list it is reading. This % may in some cases cause it to find ``matches'' between lines which % for syntactical reasons alone cannot match. % % |\comparePLs| is called as % \begin{quote} % |\comparePLs|\marg{first PL}\marg{second PL}\marg{encoding} % \end{quote} % where \meta{first PL} and \meta{second PL} are the complete names % (including extensions) of the files to compare. \meta{encoding} is % the name of the encoding to use when translating slots to glyph % names; leave it empty if you don't want to specify one. (One could % use the \texttt{CODINGSCHEME} property to determine the encoding in % that case, but this is not currently done). The slot to glyph % translation is only done to make it easier to locate the position of % some mismatch; it has not effect on the actual comparision. % \begin{macrocode} \newcount\last_character \def\comparePLs#1#2#3{{ \def\encoding_name{#3} \last_character=\m@ne \openin\a_read=#1\x_relax \openin\b_read=#2\x_relax \immediate\write\sixt@@n{#1~and^^J #2} \pl_catcodes \let\do_left_paren=\do_property \let\do_right_paren=\empty_command \global\chardef\compared_status=\z@ \clear_histograms \global\a_filelineno=\@ne \global\b_filelineno=\@ne \global\a_lineno=\@ne \global\b_lineno=\@ne \global\a_bufbase=\z@ \global\b_bufbase=\z@ \global\a_bufmid=\z@ \global\b_bufmid=\z@ \global\a_buftop=\m@ne \global\b_buftop=\m@ne \process_lines \closein\a_read \closein\b_read \ifcase \compared_status \immediate\write\sixt@@n{are~equal.^^J} \or \immediate\write\sixt@@n{are~almost~equal.^^J} \or \immediate\write\sixt@@n{are~essentially~equal.} \or \immediate\write\sixt@@n{have~non-tolerated~metric~differences.} \or \immediate\write\sixt@@n{do~not~completely~match.} \else \immediate\write\sixt@@n{could~not~be~matched!} \fi \ifnum 1<\compared_status \immediate\write\sixt@@n{See~log~file~for~specification.} \present_histograms \immediate\write\sixt@@n{} \fi }} % \end{macrocode} % \end{macro} \begingroup \catcode`\(=13 \catcode`\)=13 \gdef\pl_catcodes{ \catcode`\(=13 \def({\do_left_paren} \catcode`\)=13 \def){\do_right_paren} } \endgroup \def\do_property#1~{ \x_cs\edef{cmd-\sign}{#1} \let\metric_origin=\empty_command \x_cs\ifx{pl-#1}\x_relax \expandafter\ignore_parens \else \csname pl-#1 \expandafter\endcsname \fi } \def\pl_def_s#1(#2){\x_cs\def{pl-#1}#2~} \begingroup \catcode`\!=13\lccode`\!=`\) \lowercase{\endgroup \def\pl_def_p#1(#2){\x_cs\def{pl-#1}#2!} } \def\pl_let#1#2{ \expandafter\let \csname pl-#1 \expandafter\endcsname \csname pl-#2 \endcsname } \newdimen\tolerance \tolerance=110sp % The following is for gobbling to the next unmatched right parenthesis. % The |\catcode| trick used by the PL-to-MTX converter's % |\ignore_parens| cannot be used since the characters are already % tokenized, but one can do something similar with an |\edef| since one % does not have to worry about the PL files containing material which % expands in an undesirable way. % % The |\line_stop| is so that linebreaks in the parenthesis being % gobbled will not cause total havok (although the parenthesis won't be % gobbled completely). It inserts end-of-group tokens until the |\edef| % is terminated, and then the |\afterassignment| token will close the % group and restore the normal definition. \def\ignore_parens{ \begingroup \def\do_left_paren{{\iffalse}\fi} \def\do_right_paren{\iffalse{\fi}} \def\line_stop{\do_right_paren\line_stop} \afterassignment\endgroup \edef\a_macro{\iffalse}\fi } \def\line_stop{\x_relax} % \end{macrocode} % \begingroup \catcode`\(=1 \catcode`\)=2 \gdef\pl_string{ \begingroup \def\do_left_paren{(\iffalse)\fi} \def\do_right_paren{\iffalse(\fi)} \def\line_stop{\iffalse{\fi}\line_stop} \afterassignment\pl_string_i \edef\a_macro{\iffalse}\fi } \endgroup \def\pl_string_i{ \expandafter\endgroup \expandafter\def \csname string-\sign \expandafter\endcsname \expandafter{\a_macro} } \def\pl_real#1{\sign#1\hundred_pt} \newdimen\hundred_pt \hundred_pt=100pt % Convert a PL int to a \TeX{} int, assuming it's prefixed % by |C|, |D|, |O|, or |H|. % % \begin{macrocode} \def\pl_int#1#2{ \sign \ifx#1C `#2 \else\ifx#1D #2 \else\ifx#1O '#2 \else\ifx#1H "#2 \else -1\errmessage{Unknown~PL~number~prefix~`#1'} \fi\fi\fi\fi } % \end{macrocode} % \begin{macrocode} \pl_def_p{NEXTLARGER}(#1~#2){\advance \first_integer \pl_int{#1}{#2}} \pl_let{BOUNDARYCHAR}{NEXTLARGER} % \end{macrocode} % % % \begin{macrocode} \x_cs\let{pl-VTITLE}=\pl_string \pl_let{FONTNAME}{VTITLE} \pl_let{FONTAREA}{VTITLE} % \pl_let{CHECKSUM}{VTITLE} % % Not really a string, but unsigned numbers can become too large for TeX. % \pl_let{FONTCHECKSUM}{CHECKSUM} % Commented out since checksums vary too much. \pl_def_p{FONTAT}(R~#1){\advance \first_dimen \pl_real{#1}} \pl_let{FONTDSIZE}{FONTAT} \pl_let{SELECTFONT}{NEXTLARGER} \pl_let{SETCHAR}{NEXTLARGER} \pl_def_p{SETRULE}(R~#1~R~#2){ \advance \first_dimen \pl_real{#1} \advance \second_dimen \pl_real{#2} } \x_cs\let{pl-POP}\empty_command \pl_let{PUSH}{POP} \pl_let{MOVERIGHT}{FONTAT} \pl_let{MOVELEFT}{FONTAT} \pl_let{MOVEUP}{FONTAT} \pl_let{MOVEDOWN}{FONTAT} \pl_let{SPECIAL}{VTITLE} \pl_let{SPECIALHEX}{VTITLE} % \end{macrocode} % % \pl_let{CODINGSCHEME}{VTITLE} \pl_let{DESIGNSIZE}{FONTAT} \def\pl_parameter#1#2#3{ \advance \first_integer \pl_int{#1}{#2} \advance \first_dimen \pl_real{#3} } \pl_def_p{PARAMETER}(#1~#2~R~#3){\pl_parameter{#1}{#2}{#3}} \pl_def_p{SLANT}(R~#1){\pl_parameter{D}{1}{#1}} \pl_def_p{SPACE}(R~#1){\pl_parameter{D}{2}{#1}} \pl_def_p{STRETCH}(R~#1){\pl_parameter{D}{3}{#1}} \pl_def_p{SHRINK}(R~#1){\pl_parameter{D}{4}{#1}} \pl_def_p{XHEIGHT}(R~#1){\pl_parameter{D}{5}{#1}} \pl_def_p{QUAD}(R~#1){\pl_parameter{D}{6}{#1}} \pl_def_p{EXTRASPACE}(R~#1){\pl_parameter{D}{7}{#1}} \pl_def_p{NUM1}(R~#1){\pl_parameter{D}{8}{#1}} \pl_def_p{NUM2}(R~#1){\pl_parameter{D}{9}{#1}} \pl_def_p{NUM3}(R~#1){\pl_parameter{D}{10}{#1}} \pl_def_p{DENOM1}(R~#1){\pl_parameter{D}{11}{#1}} \pl_def_p{DENOM2}(R~#1){\pl_parameter{D}{12}{#1}} \pl_def_p{SUP1}(R~#1){\pl_parameter{D}{13}{#1}} \pl_def_p{SUP2}(R~#1){\pl_parameter{D}{14}{#1}} \pl_def_p{SUP3}(R~#1){\pl_parameter{D}{15}{#1}} \pl_def_p{SUB1}(R~#1){\pl_parameter{D}{16}{#1}} \pl_def_p{SUB2}(R~#1){\pl_parameter{D}{17}{#1}} \pl_def_p{SUPDROP}(R~#1){\pl_parameter{D}{18}{#1}} \pl_def_p{SUBDROP}(R~#1){\pl_parameter{D}{19}{#1}} \pl_def_p{DELIM1}(R~#1){\pl_parameter{D}{20}{#1}} \pl_def_p{DELIM2}(R~#1){\pl_parameter{D}{21}{#1}} \pl_def_p{AXISHEIGHT}(R~#1){\pl_parameter{D}{22}{#1}} \pl_let{DEFAULTRULETHICKNESS}{NUM1} \pl_let{BIGOPSPACING1}{NUM2} \pl_let{BIGOPSPACING2}{NUM3} \pl_let{BIGOPSPACING3}{DENOM1} \pl_let{BIGOPSPACING4}{DENOM2} \pl_let{BIGOPSPACING5}{SUP1} \def\boundarychar_name{BOUNDARYCHAR} \pl_def_s{LABEL}(#1){ \def\a_macro{#1} \ifx \a_macro\boundarychar_name \x_cs\let{string-\sign}\a_macro \else \def\a_macro{\csname pl-LABEL(i\endcsname #1~} \expandafter\a_macro \fi } \pl_def_p{LABEL(i}(#1~#2){ \last_character=\first_integer \advance \first_integer \pl_int{#1}{#2} } \pl_def_p{LIG}(#1~#2~#3~#4){ \advance \first_integer \pl_int{#1}{#2} \advance \second_integer \pl_int{#3}{#4} } \pl_let{/LIG}{LIG} \pl_let{/LIG>}{LIG} \pl_let{LIG/}{LIG} \pl_let{LIG/>}{LIG} \pl_let{/LIG/}{LIG} \pl_let{/LIG/>}{LIG} \pl_let{/LIG/>>}{LIG} \pl_let{HEADER}{LIG} % \def\pl_lig#1~#2~#3~#4~#5~{ % \x_cs\def{string-\sign}{#1} % \def\LIG#1~{ % \if\ifx #1C 0 % \else\ifx #1D 0 % \else\ifx #1H 0 % \else\ifx #1O 0 \else 1\fi\fi\fi\fi 0 % % then % \expandafter\both_of_two % \else % \expandafter\first_of_two % \fi{\pl_lig LIG}{~}#1~ % } % \def\/{\pl_lig/} \pl_let{KRN}{PARAMETER} \pl_let{SKIP}{NEXTLARGER} \pl_def_s{CHARACTER}(#1~#2){ \last_character=\first_integer \advance \first_integer \pl_int{#1}{#2} } \pl_let{CHARWD}{FONTAT} \pl_def_p{CHARHT}(R~#1){ \def\metric_origin{ht} \advance \first_dimen \pl_real{#1} } \pl_def_p{CHARDP}(R~#1){ \def\metric_origin{dp} \advance \first_dimen \pl_real{#1} } \pl_def_p{CHARIC}(R~#1){ \def\metric_origin{ic} \advance \first_dimen \pl_real{#1} } \pl_let{TOP}{NEXTLARGER} \pl_let{MID}{NEXTLARGER} \pl_let{BOT}{NEXTLARGER} \pl_let{REP}{NEXTLARGER} \pl_let{FONTDIMEN}{POP} \pl_let{LIGTABLE}{POP} \pl_let{VARCHAR}{POP} \pl_def_s{MAPFONT}(#1~#2){\advance \first_integer \pl_int{#1}{#2}} \pl_let{MAP}{POP} % \begin{macrocode} \catcode`\@=\atcatcode \catcode`\^^M=\nlcatcode \catcode`\ =\spacecatcode \catcode`\~=\tildecatcode \catcode`\_=\underscorecatcode % \end{macrocode}