summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/doc/fontinst/base/test/comparemetrics.sty
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/doc/fontinst/base/test/comparemetrics.sty')
-rw-r--r--Master/texmf-dist/doc/fontinst/base/test/comparemetrics.sty941
1 files changed, 941 insertions, 0 deletions
diff --git a/Master/texmf-dist/doc/fontinst/base/test/comparemetrics.sty b/Master/texmf-dist/doc/fontinst/base/test/comparemetrics.sty
new file mode 100644
index 00000000000..7864da89731
--- /dev/null
+++ b/Master/texmf-dist/doc/fontinst/base/test/comparemetrics.sty
@@ -0,0 +1,941 @@
+% 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
+%</pkg>
+% \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
+%</pkg>
+% \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}