[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Next fontinst version and code I once sent



Hi, Ulrik.

I thought I'd better send you the modifications I wrote about last week
before I go vist my parents for Christmas, so here they are:

We start by the encoding files section. There are no bugfixes here, only
new features: The encoding commands \setleftboundary, \endsetleftboundary,
and \setrightboundary (I added that one recently) and the slot command
\makerightboundary. I hope the descriptions below are sufficient.

I also noticed an error in the comments below: The arguments to \nextslot
and \skipslots must be <number>s, not <integer expression>s. Rowland's
manual describes the current implementation correctly, Alan's old comments
in the source does not. I don't see the point in not letting these numbers
be integer expressions, though. Someone will probably be upset about it,
sooner or later.

% \section{Encoding files}
%
% \DescribeMacro{\inputetx}
% The macro:
% \begin{quote}
%    |\inputetx{FILENAME}|
% \end{quote}
% inputs |FILENAME.etx|, ignoring anything between |\relax|
% and |\encoding|, and anything after |\endencoding|.
%
% The file name is transformed to lowercase before opening.
%
% \begin{macro}{\inputetx}
%    \begin{macrocode}
\def\inputetx#1{
   \edef\lowercase_file{\lowercase{
     \edef\noexpand\lowercase_file{#1}}}
   \lowercase_file
   \slot_number=0
   \def\relax{\let\relax=\x_relax\iffalse}
   \let\encoding=\fi
   \let\endencoding=\endinput
   \primitiveinput \lowercase_file.etx\x_relax
   \let\relax=\x_relax
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\setslot}
% \begin{macro}{\endsetslot}
% \begin{macro}{\slot_name}
%     |\setslot{NAME} SLOT COMMANDS \endsetslot|
%
% Sets |\slot_number| to the current slot, |\slot_name| to |NAME|,
% and calls |\do_slot| at the beginning of the slot and |\end_do_slot|
% at the end.  By default, |\do_slot| and |\end_do_slot| do nothing,
% but this is over-ridden later.
%
%    \begin{macrocode}
\def\setslot#1{\edef\slot_name{#1}\do_slot}
\def\endsetslot{\end_do_slot\advance\slot_number by 1\relax}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
%    \begin{macrocode}
\let\do_slot\empty_command
\let\do_new_slot\empty_command
\let\end_do_slot\empty_command
%    \end{macrocode}
%
% \begin{macro}{\nextslot}
% \begin{macro}{\skipslots}
% \begin{macro}{\slot_number}
%    |\nextslot{INTEGER EXPRESSION}|\\
%    |\skipslots{INTEGER EXPRESSION}|
%
% |\nextslot| sets the |\slot_number|.
% |\skipslots| addvances the |\slot_number|.
%
%    \begin{macrocode}
\newcount\slot_number
\def\nextslot#1{\slot_number=#1\relax}
\def\skipslots#1{\advance\slot_number by #1\relax}
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\setleftboundary}
% \begin{macro}{\endsetleftboundary}
% \begin{macro}{\do_boundary}
%   |\setleftboundary{|\meta{glyph}|}| \meta{slot commands}
%   |\endsetleftboundary|
%
%   These macros are like |\setslot| and |\endsetslot|, but they merely
%   set the left boundary ligkern program, they do not cause any
%   |CHARACTER| property list to be written. Thus the only metric
%   information connected to the \meta{glyph} argument that is ever used
%   is the kerns with this glyph on the left.
%
%   |\do_boundary| and |\endsetleftboundary| are initally |\relax|, but
%   are later redefined.
%
%    \begin{macrocode}
\def\setleftboundary#1{\edef\slot_name{#1}\do_boundary}
\let\endsetleftboundary\relax
\let\do_boundary\relax
%    \end{macrocode}
% \end{macro}\end{macro}\end{macro}
%
%
% \begin{macro}{\setrightboundary}
%   |\setrightboundary{|\meta{glyph}|}|
%
%   The |\setrightboundary| macro should be used to set which slot in font
%   is used as right boundary marker if that slot is empty. It advances
%   |\slot_number| just like a |\setslot| \textellipsis\ |\endsetslot|
%   pair, but since the slot will be left empty, there is no need for
%   any \meta{slot commands}, and hence there is no need for a closing
%   |\endset|\textellipsis\ command either.
%
%   If the right boundary marker slot is not to be left empty (often
%   unavoidable), then one should use the slot command
%   |\makerightboundary| instead.
%
%    \begin{macrocode}
\def\setrightboundary#1{
   \makerightboundary{#1}
   \advance \slot_number 1\relax
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\ligature}
% \begin{macro}{\nextlarger}
% \begin{macro}{\varchar}
% \begin{macro}{\comment}
% \begin{macro}{\makerightboundary}
% The \meta{slot commands} are:
% \begin{quote}
%    |\ligature{|\meta{lig}|}{|\meta{glyph}|}{|\meta{glyph}|}|\\
%    |\nextlarger{|\meta{glyph}|}|\\
%    |\varchar| \meta{varchar commands} |\endvarchar|\\
%    |\comment{|\meta{text}|}|\\
%    |\usedas{|\meta{command}|}{|\meta{type}|}|\\
%    |\makerightboundary{|\meta{glyph}|}|
% \end{quote}
% By default, these do nothing, but are overridden later.
%
%    \begin{macrocode}
\let\ligature=\gobble_three
\let\nextlarger=\gobble_one
\let\varchar=\empty_command
\let\endvarchar=\empty_command
\let\comment=\gobble_one
\let\usedas=\gobble_two
\let\makerightboundary=\gobble_one
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\vartop}
% \begin{macro}{\varmid}
% \begin{macro}{\varbot}
% \begin{macro}{\varrep}
% The |VARCHAR COMMANDS| are:
% \begin{quote}
%    |\vartop{GLYPH}|\\
%    |\varmid{GLYPH}|\\
%    |\varbot{GLYPH}|\\
%    |\varrep{GLYPH}|
% \end{quote}
%
%    \begin{macrocode}
\let\vartop=\gobble_one
\let\varmid=\gobble_one
\let\varbot=\gobble_one
\let\varrep=\gobble_one
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\useexamplefont}
% \begin{macro}{\slotexample}
% \begin{macro}{\setslotcomment}
% \begin{macro}{\resetslotcomment}
% \begin{macro}{\unsetslotcomment}
% These macros were recently added in the \texttt{fontdoc} package.
% They do nothing in \texttt{fontinst}, just gobble their arguments.
%    \begin{macrocode}
\let\useexamplefont=\gobble_one
\let\slotexample=\empty_command
\let\setslotcomment=\gobble_one
\let\resetslotcomment=\gobble_one
\let\unsetslotcomment=\empty_command
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


Next, we get to the PL to MTX file conversion. I think the following is a
complete list of the new features I included:

* The command \pltomtxgivenetx, which I described in a previous letter.

* Kerns in the BOUNDARYCHAR ligkern program will be written to the MTX file
if there is a \setleftboundary ... \endsetleftboundary pair in the encoding
file read in.

* The BOUNDARYCHAR slot (right boundary marker) from the program will be
registered in the MTX file if there is a \setslot ... \endsetslot pair for
that slot. The MTX will contain
   \setstr{rightboundary}{<GLYPH NAME>}
for the glyph in question, so that it is available for further processing
in metric files.

* Some VPL-specific property lists are ignored. This makes it possible to
convert correct VPL files (one has to change the suffix, though). This is
one of the items in TODO (where did that file go, BTW?).

There are also some bugfixes:

* (LABEL BOUNDARYCHAR) no longer causes an error.

* Bad numbers in LABEL property lists are reported immediately, not once
for every subsequent KRN in the ligkern program that follows.

* Kerns are only written if both slots are mensioned in the encoding.


% \subsection{Converting a \texttt{PL} file to an \texttt{MTX} file}
%
% \DescribeMacro{\pltomtx}
% The macro:
% \begin{quote}
%    |\pltomtx{PLFILE}{MTXFILE}|
% \end{quote}
% reads |PLFILE.pl|, and writes the same information out to |MTXFILE.mtx|.
% It can't cope with |SKIP| commands.
%
% \begin{macro}{\pltomtx}
% \begin{macro}{\pltomtxgivenetx}
%    \begin{macrocode}
\def\pltomtx#1#2{{\pl_to_mtx{#1}{#2}\pltomtx}}
\def\pltomtxgivenetx#1#2#3{{
   \def\do_slot{\x_cs\let{name-\the\slot_number}\slot_name}
   \def\do_boundary{\x_cs\let{name-BOUNDARYCHAR}\slot_name}
   \inputetx{#3}
   \let\CODINGSCHEME=\ignore_parens
   \pl_to_mtx{#1}{#2}\pltomtxgivenetx
}}
%    \end{macrocode}
% \end{macro}\end{macro}
%
%
% \begin{macro}{\pl_to_mtx}
%   The |\pl_to_mtx| macro contains all code common to |\pltomtx| and
%   |\pltomtxgivenetx|.
%
%    \begin{macrocode}
\def\pl_to_mtx#1#2#3{
   \def\raw_font_name{#1}
   \open_out{\temp_prefix#2.mtx}
   \out_line{\percent_char~Filename:~#2.mtx}
   \out_line{\percent_char~Created~by:~tex~\jobname}
   \out_line{\percent_char~Created~using:~\string#3{#1}{#2}}
   \out_line{}
   \out_line{\percent_char~This~file~contains~the~
      information~of~#1.pl~in~a~form}
   \out_line{\percent_char~more~easily~read~by~TeX.~
      It~is~used~by~the~fontinst~package.}
   \out_line{}
   \out_line{\percent_char~THIS~FILE~CAN~BE~DELETED.}
   \out_line{}
   \out_line{\string\relax}
   \out_line{\string\metrics}
   \out_line{}
   \out_line{\string\needsfontinstversion{\fontinstversion}}
   \out_line{}
   \catcode`\(=0 \catcode`\)=9
   \let\/=\ignore_parens
   \let\do_pl_glyph=\relax
   \primitiveinput #1.pl\relax
   \do_pl_glyph
   \out_line{}
   \ifisint{\percent_char boundarychar}\then
      \f_count=\int{\percent_char boundarychar}
      \x_cs\ifx{name-\the\f_count}\relax \else
         \out_line{\string\setstr{rightboundary}
            {\csname name-\the\f_count\endcsname}
         }
         \out_line{}
      \fi
   \fi
   \out_line{\string\endmetrics}
   \close_out{Metrics}
}
%    \end{macrocode}
% \end{macro}
%
% To parse a |.pl| file, we first make |(| the escape character, make |)|
% ignored, then define the various PL commands.
%
% We can ignore a parenthesis matched string by making |(| and |)| the
% group delimiters, then gobbling them up.
%
%    \begin{macrocode}
\def\ignore_parens{\bgroup\catcode`(=1 \catcode`)=2 \relax
   \expandafter\expandafter\expandafter\gobble_parens
      \iftrue\expandafter{\else}\fi}
\def\gobble_parens#1{\egroup}
%    \end{macrocode}
%
% Convert a PL real to an AFM unit, assuming it contains a decimal point.
%
%    \begin{macrocode}
\def\pl_real#1{\pl_realer(#1000)}
\def\pl_realer(#1.#2#3#4#5){#1#2#3#4}
%    \end{macrocode}
%
% 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{
   \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}
%
% Many of the PL commands are ignored, and I'm assuming the |R|s are in
% the places \texttt{tftopl} puts them, which is a bit naughty of me.
%
%    \begin{macrocode}
\let\COMMENT=\ignore_parens
\let\FAMILY=\ignore_parens
\let\FACE=\ignore_parens
\let\CHECKSUM=\ignore_parens
\let\LIG=\ignore_parens
\let\NEXTLARGER=\ignore_parens
\let\VARCHAR=\ignore_parens
%    \end{macrocode}
%
% The commands which are unique for VPL files---|VTITLE|, |MAPFONT|,
% |MAP|, |FONTNAME|, |FONTAREA|, |FONTCHECKSUM|, |FONTAT|,
% |FONTDSIZE|, |SELECTFONT|, |SETCHAR|, |SETRULE|, |MOVERIGHT|,
% |MOVELEFT|, |MOVEUP|, |MOVEDOWN|, |PUSH|, |POP|, |SPECIAL|, and
% |SPECIALHEX|---should also be ignored, but it is actually sufficient
% to ignore the first three since the others are only allowed inside
% |MAP| or |MAPFONT| property lists.
%
%    \begin{macrocode}
\let\VTITLE=\ignore_parens
\let\MAPFONT=\ignore_parens
\let\MAP=\ignore_parens
%    \end{macrocode}
%
%
% When we reach a |CODINGSCHEME| instruction, we read the coding string,
% and read in the corresponding |ENCODING.etx| file.
%
% (LH 98/12/04: If the PL file is converted using the |\pltomtxgivenetx|
% command rather than the |\pltomtx| command, then the |CODINGSCHEME|
% instruction is ignored since an encoding file has already been read in.)
%
% The corresponding |ENCODING| is specified by |\declareencoding|
% statements (see below).  Each |\declare_encdoing| defines a macro
% |\enc-CODINGSCHEME| which expands to |ENCODING|.
%
%    \begin{macrocode}
\def\CODINGSCHEME{\bgroup\catcode`\)=12\relax\CODINGSCHEME_cont}
\def\CODINGSCHEME_cont#1){
   \egroup
   \x_cs\ifx{enc-#1}\relax
      \errhelp{The~encoding~`#1'~has~not~been~declared.^^J
         You~should~declare~it~with~\string\declareencoding{#1}{ETXFILE}.^^J
         Press~<RETURN>~to~carry~on~with~fingers~crossed,^^J
         or~X~<RETURN>~to~exit.}
      \errmessage{Undeclared~encoding~`#1'}
   \else
      \def\do_slot{\x_cs\let{name-\the\slot_number}\slot_name}
      \def\do_boundary{\x_cs\let{name-BOUNDARYCHAR}\slot_name}
      \catcode`\(=12 \catcode`\)=12
      \x_cs\inputetx{enc-#1}\relax
      \catcode`\(=0 \catcode`\)=9
   \fi
}
%    \end{macrocode}
%    \begin{macrocode}
\def\DESIGNSIZE~#1~#2~{
   \a_dimen=#2pt
   \out_line{\string\setdim{designsize}{\the\a_dimen}}
}
\def\DESIGNUNITS~#1~#2~{
   \a_dimen=#2pt
   \out_line{\string\setdim{designunits}{\the\a_dimen}}
}
\def\BOUNDARYCHAR~#1~#2~{
   \setint{\percent_char boundarychar}{\pl_int{#1}{#2}}
}
%    \end{macrocode}
%
% The following fontdimens are converted to ints and written out
% to the |.mtx| file.
%
%    \begin{macrocode}
\let\FONTDIMEN=\relax
\def\SLANT~R~#1~{\out_line{\string\setint{italicslant}{\pl_real{#1}}}}
\def\SPACE~R~#1~{\out_line{\string\setint{interword}{\pl_real{#1}}}}
\def\STRETCH~R~#1~{\out_line{\string\setint{stretchword}{\pl_real{#1}}}}
\def\SHRINK~R~#1~{\out_line{\string\setint{shrinkword}{\pl_real{#1}}}}
\def\XHEIGHT~R~#1~{\out_line{\string\setint{xheight}{\pl_real{#1}}}}
\def\QUAD~R~#1~{\out_line{\string\setint{quad}{\pl_real{#1}}}}
\def\EXTRASPACE~R~#1~{\out_line{\string\setint{extraspace}{\pl_real{#1}}}}
\def\DEFAULTRULETHICKNESS~R~#1~{
   \out_line{\string\setint{underlinethickness}{\pl_real{#1}}}
}
%    \end{macrocode}
%
% The following fontdimens are ignored.
%
%    \begin{macrocode}
\def\HEADER~#1~#2~#3~#4~{}
\def\SEVENBITSAFEFLAG~#1~{}
\def\PARAMETER~#1~#2~#3~#4~{}
\def\NUM#1~#2~#3~{}
\def\DENOM#1~#2~#3~{}
\def\SUP#1~#2~#3~{}
\def\SUB#1~#2~#3~{}
\def\SUBDROP~#1~#2~{}
\def\SUPDROP~#1~#2~{}
\def\DELIM#1~#2~#3~{}
\def\AXISHEIGHT~#1~#2~{}
\def\BIGOPSPACING#1~#2~#3~{}
%    \end{macrocode}
%
% The following ligtable commands are processed.
%
%    \begin{macrocode}
\def\LIGTABLE{\let\do=\never_do\let\temp_command\empty_command}
\def\LABEL~#1{\ifx #1B
      \expandafter\LABEL_boundarychar
   \else
      \expandafter\LABEL_slot \expandafter#1
   \fi
}
\def\LABEL_slot #1~#2~{
   \f_count=\pl_int{#1}{#2}
   \edef\temp_command{\temp_command
      \x_cs\do_if_defined{name-\the\f_count}
   }
}
\def\LABEL_boundarychar OUNDARYCHAR{
   \edef\temp_command{\temp_command
      \x_cs\do_if_defined{name-BOUNDARYCHAR}
   }
}
\def\do_if_defined#1{\ifx #1\relax \else \do{#1} \fi}
\def\STOP{\let\temp_command\empty_command}
\def\SKIP~#1~#2~{\immediate\write16{Warning:~SKIP~instruction~ignored.}}
%    \end{macrocode}
%
%    \begin{macrocode}
\def\KRN~#1~#2~R~#3~{
   \edef\do{\noexpand\write_pl_krn{\pl_int{#1}{#2}}{\pl_real{#3}}}
   \temp_command
   \let\do=\never_do
}
\def\write_pl_krn#1#2#3{
   \f_count=#1\relax
   \x_cs\ifx{name-\the\f_count}\relax \else
      \out_line{\string\setkern{#3}
         {\csname name-\the\f_count\endcsname}{#2}
      }
   \fi
}
%    \end{macrocode}
%
% The following character metrics are processed.
%
%    \begin{macrocode}
\def\CHARWD~R~#1~{\b_count=\pl_real{#1}}
\def\CHARHT~R~#1~{\c_count=\pl_real{#1}}
\def\CHARDP~R~#1~{\d_count=\pl_real{#1}}
\def\CHARIC~R~#1~{\e_count=\pl_real{#1}}
\def\CHARACTER~#1~#2~{
   \do_pl_glyph
   \a_count=\pl_int{#1}{#2}
   \b_count=0
   \c_count=0
   \d_count=0
   \e_count=0
   \let\do_pl_glyph=\write_pl_glyph
}
%    \end{macrocode}
%
%    \begin{macrocode}
\def\write_pl_glyph{
      \x_cs\ifx{name-\the\a_count}\relax\else
         \out_line{\string\setrawglyph
            {\csname~name-\the\a_count\endcsname}
            {\raw_font_name}
            {\the\a_dimen}
            {\the\a_count}
            {\the\b_count}
            {\the\c_count}
            {\the\d_count}
            {\the\e_count}}
      \fi
   }
%    \end{macrocode}
%
%
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


Then there is the metric packages. This is a new feature which was included
in the code I sent last as well, I have merely made a few corrections in
the comments. Note that it relies on the "processing of comma-separated
lists" that is in the code I sent last.

% \subsection{Metric packages}
%
% The idea of the metric package commands is to make it easier to split
% all the commands normally kept in |latin.mtx| on several files, which
% is handy if one wants to make minor modifications to some of the
% commands or simply leave some of the parts in |latin.mtx| out to
% speed up the fontmaking\footnote{In my experience, the speedup can be
% considerable.}. They are not of any use to those who use fontinst only
% at the |\latinfamily| level, but they should prove useful to those who
% are in the business of modifying |latin.mtx| or writing their own
% alternatives, as it simplifies modularisation.
%
% The main problem with splitting up |latin.mtx| (or some other metric
% file which fulfills an equivalent function) is that there are some
% commands which are defined at the top and which are then used in almost
% all sections of the file. One must make certain that these commands
% are always loaded, which makes the metric files somewhat harder to
% use (especially if the one who tries to use them is not the one who
% wrote them).
%
% One strategy is to include all definitions needed for a metric file in
% it. This has the disadvantage that the commands will have to be
% definied several times. Furthermore the commands will appear in
% several files, so if one finds a bug in one of them, one will have to
% correct this bug in several files (the number of files can soon become
% quite large), a boring procedure indeed.
%
% Another strategy is to put all the command definitions in one file
% and then explicitly include it in the \meta{file-list} argument of
% |\installfont|. This eliminates the repeated bug fixing problem, but
% requires the user to do something that the computer can actually do
% just as well.
%
% A third strategy is to put the command definitions in one or several
% files and then in each metric file the user explicitly mensions load
% the command definitions needed for that particular file. Metric
% packages uses an improved version of this strategy, since they also
% make it possible for fontinst to remember which packages (i.e., sets
% of command definitions) that have already been loaded, so that they
% are not unnecessarily loaded again.
%
% \begin{macro}{\ProvidesMtxPackage}
%   The call
%   \begin{quote}
%     |\ProvidesMtxPackage{|\meta{package~name}|}|
%   \end{quote}
%   signals to the package managing system that there is no need to load
%   this package again.
%    \begin{macrocode}
\def\ProvidesMtxPackage#1{\x_cs\let{pack-#1}P}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\usemtxpackage}
%   The call
%   \begin{quote}
%     |\usemtxpackage{|\meta{package~list}|}|
%   \end{quote}
%   inputs those of the packages in the list that have not been loaded
%   yet (i.e., those for which no |\ProvidesMtxPackage| has been made).
%   Each package is assumed to reside in the metric file that
%   |\inputmtx| loads when given the name of the package as argument.
%
%   The call
%   \begin{quote}
%     |\usemtxpackage[|\meta{filename}|]{|\meta{package~list}|}|
%   \end{quote}
%   inputs the packages in the list if at least one of them has not been
%   loaded yet. In this case, all the packages are assumed to reside in
%   the single metric file that |\inputmtx| loads when given
%   \meta{filename} as argument.
%
%    \begin{macrocode}
\def\usemtxpackage{\futurelet\next_token\test_UseMtxPkg_arguments}
\def\test_UseMtxPkg_arguments{\ifx\next_token[
      \expandafter\mtx_package_given_file
   \else
      \expandafter\mtx_package_separate_files
   \fi
}
%    \end{macrocode}
%    \begin{macrocode}
\newif\if_load_mtx_package_
\def\mtx_package_given_file[#1]#2{
   \_load_mtx_package_false
   \process_csep_list\load_true_unless_loaded #2,\process_csep_list,
   \if_load_mtx_package_ \inputmtx{#1} \fi
}
\def\load_true_unless_loaded#1{
   \x_cs\ifx{pack-#1}P\else\_load_mtx_package_true\fi
}
%    \end{macrocode}
%    \begin{macrocode}
\def\mtx_package_separate_files#1{
   \process_csep_list\load_file_unless_loaded #1,\process_csep_list,
}
\def\load_file_unless_loaded#1{
   \x_cs\ifx{pack-#1}P\else \inputmtx{#1} \fi
}
%    \end{macrocode}
% \end{macro}
%


Then there is the definition of \unsetkerns. This is another new feature
that was in the previous piece of code, but I changed some details here so
that it does not use the integer control sequences any more---a change that
is motivated by the reimplementation of the assignment mechanism.

% \begin{macro}{\unsetkerns}
%   |\unsetkerns{|\meta{left~glyph~list}|}{|\meta{right~glyph~list}|}|
%
%   This command unsets all kerns with a glyph in the \meta{left~glyph~list}
%   on the left and a glyph in the \meta{right~glyph~list} on the right.
%   The lists themselves are ordinary comma-separated lists.
%
%   The implementation itself simply goes through |\r-|\meta{left~glyph}
%   for each element \meta{left~glyph} in \meta{left~glyph~list} and
%   |\l-|\meta{right~glyph} for each element \meta{right~glyph} in
%   \meta{right~glyph~list}, removing each |\k|\meta{token}\meta{token}
%   tripple that refers to a glyph from the opposite list as it goes
%   along. To make this test reasonably fast, the routine first ``marks''
%   the glyphs in the other list by setting the control sequences
%   |\slots-|\meta{glyph} to |U| (the letter token U). This mark is
%   later removed when the |\r-|\meta{glyph} or |\l-|\meta{glyph}
%   respectively control sequences have been gone through; the
%   |\slots-|\meta{glyph} control sequences are then set to |\relax|.
%
%    \begin{macrocode}
\def\unsetkerns#1#2{
   \let\k\k_unless_to_U
   \process_csep_list\make_slots_U#1,\process_csep_list,
   \def\do##1{\x_cs\main_remove_Us{l-##1}}
   \process_csep_list\do#2,\process_csep_list,
   \process_csep_list\make_slots_relax#1,\process_csep_list,
   \process_csep_list\make_slots_U#2,\process_csep_list,
   \def\do##1{\x_cs\main_remove_Us{r-##1}}
   \process_csep_list\do#1,\process_csep_list,
   \process_csep_list\make_slots_relax#2,\process_csep_list,
}
\def\make_slots_U#1{\x_cs\let{slots-#1}U}
\def\make_slots_relax#1{\x_cs\let{slots-#1}\relax}
\def\k_unless_to_U#1#2{
   \x_cs\ifx{slots-\expandafter\gobble_three\string#1}U \else
      \noexpand\k\noexpand#1\noexpand#2
   \fi
}
\def\main_remove_Us#1{
   \ifx#1\relax \else
      \edef#1{#1}
      \ifx#1\empty_command \let#1\relax \fi
   \fi
}
%    \end{macrocode}
% \end{macro}
%


Finally, we get to the heavy part: The ETX to VPL conversion.

All the new features in the previous piece of code I sent you are included
here, but it also includes a new feature:

* Improved interface to setting left and right boundary (the old interface
is little more than a hack, and it only give access to a minor portion of
what the PL files allow for boundaries) through using \setleftboundary ...
\endsetleftboundary (for setting the left boundary ligkern program) and
using \setrightboundary or \makerightboundary (for setting the BOUNDARYCHAR
slot = right boundary).

By including or not including the option "boundaryCompability" when
generating fontinst.sty, it is possible to control whether fontinst should
be backward compatible with the old syntax for setting left and right
boundaries or not.

Apart from that, there are some bugfixes:

* Given that a \setkern{LEFT}{RIGHT}{<>} has been made, the ligkern
programs for each slot which has been assigned the LEFT glyph will contain
a KRN instruction for every slot that the RIGHT glyph has been assigned to.

* Similarly for ligatures, every \ligature{LIG}{RIGHT}{TO} will write a LIG
instruction for every slot that the RIGHT glyph has been assigned to.

These fixes relies on the modifications of the assignment mechanism that
has been made. I hope that the descriptions of these changes that appear
below are sufficient.

% \subsection{Converting an \texttt{ETX} file to a \texttt{(V)PL} file}
%
% \subsubsection{Lowest-level user interface}
%
% \DescribeMacro{\etxtovpl}
% The macro:
% \begin{quote}
%    |\etxtovpl{ENCODING}{VPLFILE}|
% \end{quote}
% writes a virtual font (as a virtual property list) with the encoding
% |ENCODING|.  (This macro is called by |\installfont|.)
%
% \DescribeMacro{\etxtopl}
% The macro:
% \begin{quote}
%    |\etxtopl{ENCODING}{PLFILE}|
% \end{quote}
% writes a font (as a property list) with the encoding |ENCODING|.
% (This macro is called by |\installrawfont|.)
%
% \begin{macro}{\etxtovpl}
% \begin{macro}{\etxtopl}
%    \begin{macrocode}
\def\etxtovpl#1#2{{
   \def\vpl_extension{vpl}
   \def\vpl_title{COMMENT}
   \def\vpl_font{virtual~font}
   \def\vpl_Font{Virtual~font}
   \def\vpl_caller{\string\etxtovpl}
   \def\vpl_to_vf##1{vpltovf~##1.vpl~##1.vf~##1.tfm}
   \etx_to_font{#1}{#2}
}}
\def\etxtopl#1#2{{
   \def\vpl_extension{pl}
   \def\vpl_title{COMMENT}
   \def\vpl_font{font}
   \def\vpl_Font{Font}
   \def\vpl_caller{\string\etxtopl}
   \def\vpl_to_vf##1{pltotfm~##1.pl~##1.tfm}
   \_including_map_false
   \etx_to_font{#1}{#2}
}}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\if_including_map_}
%   LH 1998/10/02: The v1.5 method of controlling whether \texttt{MAP}
%   and \texttt{MAPFONT} property lists should be written requires that
%   some code is put in an awkward place (in |\make_mapfonts| rather
%   than |\make_characters|). As I am reorganising the code anyway, I
%   saw it best to let a switch control this instead. If
%   |\if_including_map_| is true, \texttt{MAP} and \texttt{MAPFONT}
%   property lists are written to the file (which should be a VPL), if
%   it is false then they are not written to the file (which is then a
%   normal PL).
%    \begin{macrocode}
\newif\if_including_map_
\_including_map_true
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\etx_to_font}
%   |\etx_to_font{|\meta{encoding}|}{|\meta{fontfile}|}| makes a |.vpl|
%   file.
%
%    \begin{macrocode}
\def\etx_to_font#1#2{
   \make_assignments{#1}
   \open_out{#2.\vpl_extension}
   \out_line{(\vpl_title\space\vpl_font\space
      #2~created~by~fontinst~v\fontinstversion)}
   \out_line{}
   \out_line{(COMMENT~Filename:~#2.\vpl_extension)}
   \out_line{(COMMENT~Created~by:~tex~\jobname)}
   \out_line{(COMMENT~Created~using:~\vpl_caller{#1}{#2})}
   \out_line{}
   \out_line{(COMMENT~This~file~can~be~turned~into~a~\vpl_font\space with)}
   \out_line{(COMMENT~\vpl_to_vf{#2})}
   \out_line{}
   \out_line{(COMMENT~THIS~FILE~CAN~THEN~BE~DELETED.)}
   \out_line{}
   \make_header{#1}
   \if_including_map_ \make_mapfonts{#1} \fi
   \make_fontdimens{#1}
   \make_ligtable{#1}
   \make_characters{#1}
   \make_tidy{#1}
   \out_line{}
   \out_line{(COMMENT~END~OF~FILE~#2.\vpl_extension)}
   \close_out{\vpl_Font}
}
%    \end{macrocode}
% \end{macro}
%
%
% \subsubsection{Hooks into the (\texttt{V})\texttt{PL} file generation}
%
% \begin{macro}{\pre_first_etx_pass_hook}
% \begin{macro}{\pre_second_etx_pass_hook}
% \begin{macro}{\pre_third_etx_pass_hook}
% \begin{macro}{\pre_fourth_etx_pass_hook}
% \begin{macro}{\post_first_etx_pass_hook}
% \begin{macro}{\post_second_etx_pass_hook}
% \begin{macro}{\post_third_etx_pass_hook}
% \begin{macro}{\post_fourth_etx_pass_hook}
% \begin{macro}{\tidying_up_hook}
%   LH 1998/09/30: As the |\etxtovpl| and |\etxtopl| macros are the
%   lowest-level interfaces to what they do that are available in fontinst
%   and as the amount of code they execute is really quite large, I feel
%   there is a need for some robust mechanism for adding code to this,
%   in case the need should arise. Such a mechanism is provided by the
%   following hooks:
%    \begin{macrocode}
\let\pre_first_etx_pass_hook\relax
\let\pre_second_etx_pass_hook\relax
\let\pre_third_etx_pass_hook\relax
\let\pre_fourth_etx_pass_hook\relax
\let\post_first_etx_pass_hook\relax
\let\post_second_etx_pass_hook\relax
\let\post_third_etx_pass_hook\relax
\let\post_fourth_etx_pass_hook\relax
\let\tidying_up_hook\relax
%    \end{macrocode}
%   To include code in one of them, one should write things like
%   \begin{quote}
%     |\add_to\pre_first_etx_pass_hook{|\meta{extra~code}|}|
%   \end{quote}
% \end{macro} \end{macro} \end{macro} \end{macro} \end{macro}
% \end{macro} \end{macro} \end{macro} \end{macro}
%
%
% \subsubsection{Glyph to slot assignments}
%
% LH 1998/12/06: The way fontinst has traditionally kept track of which
% glyph goes to which slot---information which is needed when writing
% the |LIGTABLE| in a (V)PL, for |\nextlarger|, and for the varchar
% commands---is by storing the slot number in the integer
% whose name is the name of the glyph. There are two main problems with
% this implementation: (i)~If a user sets an integer which happens to
% have the same name as a glyph that is not assigned to any slot, then
% kerns for that unused glyph might be written to the file, accidentally
% creating a kerning pair where there should be none. (ii)~It is only
% possible to store one slot number per glyph, so if one uses the same
% glyph for several slots then fontinst can only write kerns (and
% ligatures) for one of the occurencies, despite the fact that all
% occurences have the same typographical need for them. These problems
% do only occur for glyphs on the right side of a ligature/kerning
% pair, but they are still serious enough. I have therefore
% reimplemented this part of fontinst.
%
% The new implementation does not use integers, instead it uses a new
% family of macros with names on the form |\slots-|\meta{glyph}. These
% macros expand to sequences of |\do|\thinspace|\|\meta{slot}, where
% \meta{slot} is a slot number; a similar mechanism is used to store
% kern \meta{amount}s in the |\l-|\meta{glyph} and |\r-|\meta{glyph}
% macros.
%
% In the entire space of such names, each slot sould be mensioned
% at most once, with one exception, namely the slot which serves as
% right boundary marker, which may occur twice (once for the glyph
% which actually is assigned to the slot and once for the right boundary
% marker glyph). To detect whether there is a collision between these two
% uses of the slot, the right boundary marker glyph uses |\rboundary_do|
% instead of |\do| and the glyph whose slot serves as boundarychar uses
% |\rbserver_do| instead of |\do|. By redefining these two control
% sequences to generate a warning message when appropriate, the occurence
% of such a collision can be brought to the user's attention.
%
% LH 1998/12/11: As it turned out to not be such a big deal, I have
% included some code (protected by a docstrip option called
% \Module{boundaryCompability}) that makes fontinst compatible with the
% previous syntax for boundary handling. I don't recommend using it though,
% since it makes fontinst store almost all slot numbers in two places.
%
%
% \begin{macro}{\make_assignments}
%    \begin{macrocode}
\def\make_assignments#1{
   \let\do_slot=\assign_slot
   \let\end_do_slot=\end_assign_slot
   \def\do_boundary{\bgroup
      \let\makerightboundary=\bad_makerightboundary
   }
   \let\endsetleftboundary=\egroup
   \let\makerightboundary=\assign_rboundary
   \pre_first_etx_pass_hook
   \inputetx{#1}
   \post_first_etx_pass_hook
   \let\end_do_slot=\empty_command
   \let\do_boundary=\relax
   \let\endsetleftboundary=\relax
   \let\makerightboundary=\gobble_one
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\assign_slot}
% \begin{macro}{\end_assign_slot}
%   |\assign_slot| begins the assignment of a slot to a glyph.
%   |\end_assign_slot| completes it. In the time between these two,
%   some information is stored in |\a_toks|, so that it can be
%   modified by an intervening |\makerightboundary| (which is then
%   |\assign_rboundary|).
%    \begin{macrocode}
\def\assign_slot{
   \a_toks=\expandafter{
      \expandafter\do \csname\the\slot_number\endcsname
   }
}
\def\end_assign_slot{
   \expandafter\add_to \csname slots-\slot_name\expandafter\endcsname
      \expandafter{\the\a_toks}
%<boundaryCompability>   \resetint\slot_name\slot_number
}
%    \end{macrocode}
% \end{macro}\end{macro}
%
%
% \begin{macro}{\assign_rboundary}
% \begin{macro}{\bad_makerightboundary}
%   |\assign_rboundary| is what |\makerightboundary| is when it is
%   assigning a slot to act as right boundary marker.
%
%   |\bad_makerightboundary| is what |\makerightboundary| temporarily
%   gets set to between |\setleftboundary| and |\endsetleftboundary|.
%    \begin{macrocode}
\def\assign_rboundary#1{
   \expandafter\add_to \csname slots-#1\expandafter\endcsname
      \expandafter{
      \expandafter\rboundary_do \csname\the\slot_number\endcsname
   }
   \setint{\percent_char boundarychar}\slot_number
   \a_toks=\expandafter{
      \expandafter\rbserver_do \csname\the\slot_number\endcsname
   }
}
\def\bad_makerightboundary#1{
   \errhelp={The~left~boundary~is~not~a~slot,~so~it~cannot~serve~
      as~right~boundary.}
   \errmessage{Incorrect~use~of~\string\makerightboundary}
}
%    \end{macrocode}
% \end{macro} \end{macro}
%
% \begin{macro}{\get_slot_num}
%   It is sometimes necessary to get the number of an arbitrary slot
%   given only the name of the glyph which has been assigned to the
%   slot. In such situations, the call
%   \begin{quote}
%     |\get_slot_num{|\meta{glyph}|}|
%   \end{quote}
%   will set |\result| to the number of one such slot if the glyph has
%   been assigned to some slot, or set |\result| to minus one if the glyph
%   has not been assigned to a slot.
%    \begin{macrocode}
\def\get_slot_num#1{
%<*!boundaryCompability>
   \global\result=-1
   \bgroup
      \def\do##1{
         \global\result=\expandafter\gobble_one \string##1
         \let\do=\gobble_one
      }
      \def\rbserver_do{\do}
      \let\rboundary_do=\gobble_one
      \csname slots-#1\endcsname
   \egroup
%</!boundaryCompability>
%<*boundaryCompability>
   \ifisint{#1}\then
      \global\result=\int{#1}
   \else
      \global\result=-1
   \fi
   \relax
%</boundaryCompability>
}
%    \end{macrocode}
% \end{macro}
%
%
% \subsubsection{(\texttt{V})\texttt{PL} dimensions}
%
% |\afmconvert|\meta{dimen}|=|\meta{integer expression}|;|
% converts a count into a dimen, assuming the count is a number
% of AFM units.  I'll assume that the largest dimension I'll have
% to deal with is 131pt, to try to minimize rounding errors.
%
%    \begin{macrocode}
\newdimen\scaled_design_size
%    \end{macrocode}
%
%    \begin{macrocode}
\def\afm_convert#1=#2;{
   \eval_expr{#2}
   #1=\scaled_design_size
   \divide#1 by 8
   \multiply #1 by \result
   \divide #1 by \one_thousand
   \multiply#1 by 8
}
%    \end{macrocode}
%
% The commands |\vpl_real\dimen| or |\vpl_int\count| print a dimension or
% integer in (V)PL syntax.
%
%    \begin{macrocode}
\def\vpl_real#1{R~\expandafter\lose_measure\the#1}
\def\vpl_int#1{D~\the#1}
%    \end{macrocode}
%
%
% \subsubsection{(\texttt{V})\texttt{PL} file header}
%
% LH 1998/12/04: I have removed the count register |\boundary_char| as
% the reimplementation of the left and right boundaries have drastically
% decreased the need to check which slot serves as the right boundary.
% Instead the integer |%boundarychar| (whose name cannot normally be typed)
% is used to store the number of this slot, but the user need never (and
% should not) access this integer directly. If the integer is not set
% then no slot serves as boundarychar.
%
%    \begin{macrocode}
\newdimen\side_bearings
\newdimen\curr_bearings
%    \end{macrocode}
%
%    \begin{macrocode}
\def\make_header#1{
   \global\font_count=0
   \setdim{designsize}{10pt}
   \scaled_design_size=\dim{designsize}
   \out_line{(DESIGNSIZE~\vpl_real\scaled_design_size)}
   \out_line{(DESIGNUNITS~\vpl_real\scaled_design_size)}
   \setstr{codingscheme}{UNKNOWN}
   \out_line{(CODINGSCHEME~\str{codingscheme})}
%<*boundaryCompability>
   \ifisint{boundarychar}\then
      \setint{\percent_char boundarychar}{\int{boundarychar}}
      \immediate\write16{Please~use~\string\setleftboundary\space
         and/or~\string\makerightboundary^^J
         instead~of~setting~the~boundarychar~integer.}
   \fi
%</boundaryCompability>
   \ifisint{\percent_char boundarychar}\then
      \a_count=\int{\percent_char boundarychar}
      \out_line{(BOUNDARYCHAR~\vpl_int\a_count)}
   \fi
   \setint{letterspacing}{0}
   \afm_convert\side_bearings=\div{\int{letterspacing}}{2};
   \ifdim\side_bearings=0pt
      \let\do_character_sidebearings=\relax
   \fi
   \setint{minimumkern}{0}
   \minimum_kern=\int{minimumkern}
   \out_line{}
}
%    \end{macrocode}
%
%
% \subsubsection{The mapfonts}
%
%    \begin{macrocode}
\def\make_mapfonts#1{
   \let\saved_scale\vpl_scale
   \let\saved_mapfont\vpl_mapfont
   \let\do_slot=\do_mapfont
   \pre_second_etx_pass_hook
   \inputetx{#1}
   \post_second_etx_pass_hook
   \out_line{}
}
%    \end{macrocode}
%
% |\do_mapfont| produces a |MAPFONT| entry for each font used by
% glyph |\slot_name|.
%
%    \begin{macrocode}
\def\do_mapfont{
   \ifisglyph\slot_name\then
      \mapfonts\slot_name
   \fi
}
%    \end{macrocode}
%
% The following commands can be used in a |MAPFONT|:
%
%    \begin{macrocode}
\def\vpl_scale#1#2{{
   \divide \scaled_design_size by 8
   \multiply \scaled_design_size by #1
   \divide \scaled_design_size by \one_thousand
   \multiply \scaled_design_size by 8
   #2
}}
%    \end{macrocode}
%    \begin{macrocode}
\def\vpl_mapfont#1#2{
   \a_dimen=#2
   \x_cs\ifx{#1-\the\scaled_design_size}\relax
      \x_cs\xdef{#1-\the\scaled_design_size}{\the\font_count}
      \x_cs\xdef{f-\the\font_count}{#1-\the\scaled_design_size}
      \out_line{(MAPFONT~\vpl_int\font_count\space
         (FONTNAME~#1)~
         (FONTDSIZE~\vpl_real\a_dimen)~
         (FONTAT~\vpl_real\scaled_design_size))}
      \global\advance\font_count by 1
   \fi
}
%    \end{macrocode}
%    \begin{macrocode}
\newcount\font_count
\newcount\next_mapfont
\newcount\prev_mapfont
%    \end{macrocode}
%
%
% \subsubsection{The fontdimens}
%
%    \begin{macrocode}
\def\make_fontdimens#1{
   \out_line{(FONTDIMEN}
      \ifisint{fontdimen(1)}\then
         \a_dimen=\int{fontdimen(1)}pt
         \divide\a_dimen by \one_thousand
         \out_lline{(PARAMETER~D~1~\vpl_real\a_dimen)}
      \fi
      \a_count=2
      \loop\ifnum\a_count<256
         {\ifisint{fontdimen(\the\a_count)}\then
            \afm_convert\a_dimen=\int{fontdimen(\the\a_count)};
            \out_lline{(PARAMETER~\vpl_int\a_count\space\vpl_real\a_dimen)}
         \fi}
      \advance\a_count by 1 \repeat
   \out_lline{)}
   \out_line{}
}
%    \end{macrocode}
%
%
% \subsubsection{The ligtable}
%
% \begin{macro}{\make_ligtable}
%    \begin{macrocode}
\def\make_ligtable#1{
   \bgroup
      \out_line{(LIGTABLE}
%<!boundaryCompability>      \let\do_slot=\bgroup
%<*boundaryCompability>
      \def\do_slot{\bgroup
         \ifisint{boundarychar}\then
            \ifnum \int{boundarychar}=\slot_number
               \def\vpl_liglabel{\out_liglabel\boundary_liglabel}
            \fi
         \fi
      }
%</boundaryCompability>
      \let\end_do_slot=\vpl_kerning
      \def\do_boundary{\bgroup \let\vpl_liglabel=\boundary_liglabel}
      \let\endsetleftboundary=\vpl_kerning
      \let\ligature=\vpl_ligature
      \let\k=\vpl_kern
      \let\rbserver_do=\vpl_rbserver_do
      \let\rboundary_do=\vpl_rboundary_do
      \pre_third_etx_pass_hook
      \inputetx{#1}
      \post_third_etx_pass_hook
      \out_lline{)}
   \egroup
   \out_line{}
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\vpl_rbserver_do}
% \begin{macro}{\vpl_rboundary_do}
% \begin{macro}{\wrn_rboundary_do}
%   |\vpl_rbserver_do| and |\vpl_rboundary_do| are what |\rbserver_do|
%   and |\rboundary_do| respectively are when a ligkern program is being
%   written and no entry has yet been written for the boundarychar
%   slot. |\wrn_rboundary_do| is what one of them will get set to
%   afterwards, so that warnings are written when collisions between
%   using the slot as a right boundary marker and using the slot for
%   the actual glyph occur.
%    \begin{macrocode}
\def\vpl_rbserver_do#1{
   \do{#1}
   \let\rboundary_do=\wrn_rboundary_do
}
\def\vpl_rboundary_do#1{
   \do{#1}
   \let\rbserver_do=\wrn_rboundary_do
}
\def\wrn_rboundary_do#1{
   \do{#1}
   \immediate\write16{Boundarychar~slot~usage~collision~in~
      `\slot_name'~ligkern~program.}
}
%    \end{macrocode}
% \end{macro}\end{macro}\end{macro}
%
%
% \begin{macro}{\vpl_ligature}
%   |\vpl_ligature{|\meta{type}|}{|\meta{glyph}|}{|\meta{glyph}|}|
%   produces a ligtable entry for glyph |\slot_name|.
%    \begin{macrocode}
\def\vpl_ligature#1#2#3{
   \get_slot_num{#3}
   \ifnum -1=\result
      \immediate\write16{Warning:~\string\ligature\space
         for~unknown~slot~`#3'.}
   \else
      \x_cs\ifx{slots-#2}\relax
         \immediate\write16{Warning:~\string\ligature\space
            for~unknown~slot~`#2'.}
      \else
         \def\do##1{
            \vpl_liglabel
            \out_lline{(#1~D~\expandafter\gobble_one\string##1~
               \vpl_int\result)~(COMMENT~#2~#3)}
         }
         \csname slots-#2\endcsname
      \fi
   \fi
}
%    \end{macrocode}
% \end{macro}
%
%
%
% \begin{macro}{\vpl_kerning}
%   |\vpl_kerning| writes out kerning instructions.
%    \begin{macrocode}
\def\vpl_kerning{
   \let\do=\vpl_kern_do
   \csname~r-\slot_name\endcsname
   \vpl_ligstop
   \egroup
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\vpl_kern}
%   |\vpl_kern\l-NAME\AMOUNT| writes out a |KRN| instruction.
%
%   LH 1998/10/02: |\vpl_kern| has been modified so that at most one
%   \texttt{KRN} instruction is written for each (ordered) pair of
%   characters. The idea is basically to make fontinst forget, until
%   the end of |\vpl_kerning|, that the glyph for which |\vpl_kern| is
%   being called has been assigned a slot, as this stops any more
%   \texttt{KRN} instructions for that particular glyph from being
%   written. |\vpl_kern| has also been modified so that it will not write
%   out any \texttt{KRN} instructions for kerns whose absolute value is
%   less than or equal to |\minimum_kern|. |\minimum_kern| gets set to
%   the value of the integer \texttt{minimumkern} in |\make_header|. If
%   the user has not set \texttt{minimumkern}, a default value of 0 will
%   be supplied by fontinst.
%
%   LH 1998/12/07: Much of the code from |\vpl_kern| has been moved to
%   |\vpl_kern_do|.
%
%    \begin{macrocode}
\def\vpl_kern#1#2{
   \edef\temp_command{\expandafter\gobble_three\string#1}
   \a_count=\expandafter\gobble_one\string#2\relax
   \ifnum -\a_count>\a_count
      \a_count=-\a_count
   \fi
   \ifnum \a_count>\minimum_kern
      \afm_convert\a_dimen=\expandafter\gobble_one\string#2;
      \csname slots-\temp_command\endcsname
   \fi
   \x_cs\let{slots-\temp_command}=\relax
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\vpl_kern_do}
%   |\vpl_kern_do| is what |\do| is defined to be when kerns are written.
%    \begin{macrocode}
\def\vpl_kern_do#1{
   \vpl_liglabel
   \out_lline{
      (KRN~D~\expandafter\gobble_one\string#1~\vpl_real\a_dimen)~
      (COMMENT~\temp_command)
   }
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\out_liglabel}
% \begin{macro}{\boundary_liglabel}
% \begin{macro}{\vpl_liglabel}
%   |\out_liglabel| writes out a |LIGLABEL| instruction for a slot.
%   |\boundary_liglabel| writes out a |LIGLABEL| instruction for the
%   |BOUNDARYCHAR| ligkern program. |\vpl_liglabel| writes out the
%   correct |LIGLABEL| instruction for the current ligkern program, if it
%   is approriate.
%
%    \begin{macrocode}
\def\out_liglabel{
   \out_lline{(LABEL~\vpl_int\slot_number)~(COMMENT~\slot_name)}
   \let\vpl_liglabel=\relax
   \let\vpl_ligstop=\out_ligstop
}
\def\boundary_liglabel{
   \out_lline{(LABEL~BOUNDARYCHAR)~(COMMENT~\slot_name)}
   \let\vpl_liglabel=\relax
   \let\vpl_ligstop=\out_ligstop
}
\let\vpl_liglabel=\out_liglabel
%    \end{macrocode}
% \end{macro}\end{macro}\end{macro}
%
% |\vpl_ligstop| writes out a |LIGSTOP| instruction if appropriate.
%
%    \begin{macrocode}
\def\out_ligstop{\out_lline{(STOP)}
   \let\vpl_liglabel=\out_liglabel
   \let\vpl_ligstop=\relax}
\let\vpl_ligstop=\relax
%    \end{macrocode}
%
%
% \subsubsection{The characters}
%
%    \begin{macrocode}
\def\make_characters#1{
   \bgroup
      \let\do_slot=\do_character
      \let\end_do_slot=\end_do_character
      \let\nextlarger=\vpl_nextlarger
      \let\varchar=\vpl_varchar
      \let\endvarchar=\end_vpl_varchar
      \let\vartop=\vpl_vartop
      \let\varmid=\vpl_varmid
      \let\varbot=\vpl_varbot
      \let\varrep=\vpl_varrep
      \if_including_map_
         \let\saved_raw\vpl_raw
         \let\saved_rule\vpl_rule
         \let\saved_special\vpl_special
         \let\saved_warning\vpl_warning
         \let\saved_movert\vpl_movert
         \let\saved_moveup\vpl_moveup
         \let\saved_push\vpl_push
         \let\saved_pop\vpl_pop
      \else
         \let\do_character_map\relax
      \fi
      \pre_fourth_etx_pass_hook
      \inputetx{#1}
      \post_fourth_etx_pass_hook
   \egroup
}
%    \end{macrocode}
%
% |\do_character| produces a character entry for glyph |\slot_name| in
% slot |\slot_number|.  First of all, the version with letterspacing:
%
%    \begin{macrocode}
\def\do_character{
   \x_cs\ifx{g-\slot_name}\relax
      \expandafter\gobble_setslot
   \else
      \ifx\slot_name\notdef_name\else
         \out_line{(CHARACTER~\vpl_int\slot_number\space
            (COMMENT~\slot_name)}
         \afm_convert\a_dimen=\width\slot_name;
         \do_character_sidebearings
         \out_lline{(CHARWD~\vpl_real\a_dimen)}
         \afm_convert\a_dimen=\height\slot_name;
         \out_lline{(CHARHT~\vpl_real\a_dimen)}
         \afm_convert\a_dimen=\depth\slot_name;
         \out_lline{(CHARDP~\vpl_real\a_dimen)}
         \afm_convert\a_dimen=\italic\slot_name;
         \ifnum\a_dimen>0
            \out_lline{(CHARIC~\vpl_real\a_dimen)}
         \fi
         \do_character_map
      \fi
   \fi
}
%    \end{macrocode}
%
%    \begin{macrocode}
\def\do_character_sidebearings{
   \ifisint{\slot_name-spacing}\then
      \afm_convert\curr_bearings=\int{\slot_name-spacing};
      \divide\curr_bearings by 2
   \else
      \curr_bearings=\side_bearings
   \fi
   \afm_convert\a_dimen=\width\slot_name;
   \advance\a_dimen by 2\curr_bearings
}
%    \end{macrocode}
%
%    \begin{macrocode}
\def\do_character_map{
   \global\prev_mapfont=0 \out_lline{(MAP}
      \ifdim \curr_bearings=0pt
         \mapcommands\slot_name
      \else
         \out_llline{(MOVERIGHT~\vpl_real\curr_bearings)}
         \mapcommands\slot_name
         \out_llline{(MOVERIGHT~\vpl_real\curr_bearings)}
      \fi
   \out_llline{)}
}
%    \end{macrocode}
%
% Now the version without:
%
%    \begin{macrocode}
\def\do_character_no_letterspacing{
   \x_cs\ifx{g-\slot_name}\relax
      \expandafter\gobble_setslot
   \else
      \ifx\slot_name\notdef_name\else
         \out_line{(CHARACTER~\vpl_int\slot_number\space
            (COMMENT~\slot_name)}
         \afm_convert\a_dimen=\width\slot_name;
         \out_lline{(CHARWD~\vpl_real\a_dimen)}
         \afm_convert\a_dimen=\height\slot_name;
         \out_lline{(CHARHT~\vpl_real\a_dimen)}
         \afm_convert\a_dimen=\depth\slot_name;
         \out_lline{(CHARDP~\vpl_real\a_dimen)}
         \afm_convert\a_dimen=\italic\slot_name;
         \ifnum\a_dimen>0 \out_lline{(CHARIC~\vpl_real\a_dimen)} \fi
         \global\prev_mapfont=0 \out_lline{(MAP}
            \mapcommands\slot_name
         \out_llline{)}
      \fi
   \fi
}
\def\gobble_setslot#1\endsetslot{\endsetslot}
%    \end{macrocode}
%
%    \begin{macrocode}
\def\end_do_character{
   \ifisglyph\slot_name\then
      \out_lline{)}
   \fi
}
%    \end{macrocode}
%
%    \begin{macrocode}
\def\notdef_name{.notdef}
%    \end{macrocode}
%
%
% \subsubsection{Slot commands that ends up in a character property list}
%
% |\vpl_nextlarger{NAME}| produces a |NEXTLARGER| entry.
%
%    \begin{macrocode}
\def\vpl_nextlarger#1{
   \get_slot_num{#1}
   \ifnum -1<\result
      \out_lline{(NEXTLARGER~D~\the\result)~(COMMENT~#1)}
   \else
      \immediate\write16{Warning:~\string\nextlarger\space
         for~unknown~slot~`#1'}
   \fi
}
%    \end{macrocode}
%
% |\vpl_varchar VARCHAR COMMANDS \end_vpl_varchar| produces
% a |VARCHAR| entry.
%
%    \begin{macrocode}
\def\vpl_varchar{\out_lline{(VARCHAR}}
%    \end{macrocode}
%
%    \begin{macrocode}
\def\vpl_vartop#1{
   \get_slot_num{#1}
   \ifnum -1<\result
      \out_llline{(TOP~D~\the\result)~(COMMENT~#1)}
   \else
      \immediate\write16{Warning:~\string\vartop\space
         for~unknown~slot~`#1'}
   \fi
}
\def\vpl_varmid#1{
   \get_slot_num{#1}
   \ifnum -1<\result
      \out_llline{(MID~D~\the\result)~(COMMENT~#1)}
   \else
      \immediate\write16{Warning:~\string\varmid\space
         for~unknown~slot~`#1'}
   \fi
}
\def\vpl_varbot#1{
   \get_slot_num{#1}
   \ifnum -1<\result
      \out_llline{(BOT~D~\the\result)~(COMMENT~#1)}
   \else
      \immediate\write16{Warning:~\string\varbot\space
         for~unknown~slot~`#1'}
   \fi
}
\def\vpl_varrep#1{
   \get_slot_num{#1}
   \ifnum -1<\result
      \out_llline{(REP~D~\the\result)~(COMMENT~#1)}
   \else
      \immediate\write16{Warning:~\string\varrep\space
         for~unknown~slot~`#1'}
   \fi
}
%    \end{macrocode}
%
%    \begin{macrocode}
\def\end_vpl_varchar{\out_llline{)}}
%    \end{macrocode}
%
%
% \subsubsection{Saved map commands}
%
% The following commands (and |\vpl_scale|, which is defined above) can
% be used in a glyph:
%
%    \begin{macrocode}
\def\vpl_raw#1#2#3{
   \global\next_mapfont=\csname~#1-\the\scaled_design_size\endcsname\relax
   \ifnum\next_mapfont=\prev_mapfont\else
      \out_llline{(SELECTFONT~\vpl_int\next_mapfont)~
         (COMMENT~#1~at~\the\scaled_design_size)}
   \fi
   \out_llline{(SETCHAR~D~#2)~(COMMENT~#3)}
   \global\prev_mapfont=\next_mapfont
}
%    \end{macrocode}
%    \begin{macrocode}
\def\vpl_rule#1#2{
   \afm_convert\a_dimen=#1;
   \afm_convert\b_dimen=#2;
   \out_llline{(SETRULE~\vpl_real\b_dimen\space~\vpl_real\a_dimen)}
}
%    \end{macrocode}
%
%    \begin{macrocode}
\def\vpl_special#1{
   \out_llline{(SPECIAL~#1)}}
\def\vpl_warning#1{
   \out_llline{(SPECIAL~Warning:~#1)}
   \immediate\write16{Warning:~#1.}
}
%    \end{macrocode}
%
%    \begin{macrocode}
\def\vpl_movert#1{
   \afm_convert\a_dimen=#1;
   \out_llline{(MOVERIGHT~\vpl_real\a_dimen)}
}
\def\vpl_moveup#1{
   \afm_convert\a_dimen=#1;
   \out_llline{(MOVEUP~\vpl_real\a_dimen)}
}
%    \end{macrocode}
%
%    \begin{macrocode}
\def\vpl_push{\out_llline{(PUSH)}}
\def\vpl_pop{\out_llline{(POP)}}
%    \end{macrocode}
%
%
% \subsubsection{Tidying up}
%
%    \begin{macrocode}
\def\make_tidy#1{
   \tidying_up_hook
   \if_including_map_
      \a_count=0\loop\ifnum\a_count<\font_count
         \edef\temp_command{\csname~f-\the\a_count\endcsname}
         \global\x_cs\let\temp_command\relax
         \advance\a_count by 1
      \repeat
      \global\font_count=0
   \fi
}
%    \end{macrocode}
%

But that's it. Have fun, and Merry Christmas!


/Lars Hellström