modernc.org/knuth@v0.0.4/vptovf/vptovf.go (about)

     1  // Code generated by '[/tmp/go-build2255657050/b001/exe/generate]', DO NOT EDIT.
     2  
     3  // % This program by D. E. Knuth is not copyrighted and can be used freely.
     4  // % Version 1 was implemented in December 1989.
     5  // % Version 1.1 fixed some for-loop indices for stricter Pascal (April 1990).
     6  // % Version 1.2 fixed `nonexistent char 0' bug, and a bit more (September 1990).
     7  // % Version 1.3 has more robust `out_scaled' (March 1991).
     8  // % Version 1.4 (March 1995) initialized lk_step_ended (Armin K\"ollner).
     9  // % Version 1.5 (August 1998) corrected vf_fix(0) (Wayne Sullivan).
    10  // % Version 1.6 (January 2014) corrected possible end-of-line glitch (Ken Nakano),
    11  // %  and get_fix now treats -- as + (Peter Breitenlohner).
    12  //
    13  // % Here is TeX material that gets inserted after \input webmac
    14  // \def\hang[\hangindent 3em\indent\ignorespaces]
    15  // \font\ninerm=cmr9
    16  // \let\mc=\ninerm % medium caps for names like SAIL
    17  // \def\PASCAL[Pascal]
    18  // \font\logo=logo10 % for the METAFONT logo
    19  // \def\MF[[\logo METAFONT]]
    20  //
    21  // \def\(#1)[] % this is used to make section names sort themselves better
    22  // \def\9#1[] % this is used for sort keys in the index
    23  //
    24  // \def\title[VP\lowercase[to]VF]
    25  // \def\contentspagenumber[201]
    26  // \def\topofcontents[\null
    27  //   \titlefalse % include headline on the contents page
    28  //   \def\rheader[\mainfont\hfil \contentspagenumber]
    29  //   \vfill
    30  //   \centerline[\titlefont The [\ttitlefont VPtoVF] processor]
    31  //   \vskip 15pt
    32  //   \centerline[(Version 1.6, January 2014)]
    33  //   \vfill]
    34  // \def\botofcontents[\vfill
    35  //   \centerline[\hsize 5in\baselineskip9pt
    36  //     \vbox[\ninerm\noindent
    37  //     The preparation of this program
    38  //     was supported in part by the National Science
    39  //     Foundation and by the System Development Foundation. `\TeX' is a
    40  //     trademark of the American Mathematical Society.]]]
    41  // \pageno=\contentspagenumber \advance\pageno by 1
    42  //
    43  //
    44  
    45  // 1. Introduction
    46  
    47  // tangle:pos vptovf.web:41:14:
    48  
    49  // The \.[VPtoVF] utility program converts virtual-property-list (``\.[VPL]'')
    50  // files into an equivalent pair of files called a virtual font (``\.[VF]'') file
    51  // and a \TeX\ font metric (``\.[TFM]'') file. It also makes a thorough check
    52  // of the given \.[VPL] file, so that the \.[VF] file should be acceptable to
    53  // device drivers and the \.[TFM] file should be acceptable to \TeX.
    54  //
    55  // \indent\.[VPtoVF] is an extended version of the program \.[PLtoTF], which
    56  // is part of the standard \TeX ware library.
    57  // The idea of a virtual font was inspired by the work of David R. Fuchs
    58  // \xref[Fuchs, David Raymond]
    59  // who designed a similar set of conventions in 1984 while developing a
    60  // device driver for ArborText, Inc. He wrote a somewhat similar program
    61  // called \.[PLFONT].
    62  //
    63  // The |banner| string defined here should be changed whenever \.[VPtoVF]
    64  // gets modified.
    65  
    66  // 2.
    67  
    68  // tangle:pos vptovf.web:59:75:
    69  
    70  // This program is written entirely in standard \PASCAL, except that
    71  // it has to do some slightly system-dependent character code conversion
    72  // on input. Furthermore, lower case letters are used in error messages;
    73  // they could be converted to upper case if necessary. The input is read
    74  // from |vpl_file|, and the output is written on |vf_file| and |tfm_file|;
    75  // error messages and
    76  // other remarks are written on the |output| file, which the user may
    77  // choose to assign to the terminal if the system permits it.
    78  // \xref[system dependencies]
    79  //
    80  // The term |print| is used instead of |write| when this program writes on
    81  // the |output| file, so that all such output can be easily deflected.
    82  
    83  package vptovf
    84  
    85  import (
    86  	"math"
    87  	"unsafe"
    88  
    89  	"modernc.org/knuth"
    90  )
    91  
    92  var (
    93  	_ = math.MaxInt32
    94  	_ unsafe.Pointer
    95  )
    96  
    97  type (
    98  	char   = byte
    99  	signal int
   100  )
   101  
   102  func strcopy(dst []char, src string) {
   103  	for i := 0; i < len(dst) && i < len(src); i++ {
   104  		dst[i] = src[i]
   105  	}
   106  }
   107  
   108  func arraystr(a []char) string {
   109  	b := make([]byte, len(a))
   110  	for i, c := range a {
   111  		b[i] = c
   112  	}
   113  	return string(b)
   114  }
   115  
   116  func abs(n int32) int32 {
   117  	if n >= 0 {
   118  		return n
   119  	}
   120  
   121  	return -n
   122  }
   123  
   124  func fabs(f float64) float64 {
   125  	if f >= 0 {
   126  		return f
   127  	}
   128  
   129  	return -f
   130  }
   131  
   132  func round(f float64) int32 {
   133  	if f >= 0 {
   134  		return int32(f + 0.5)
   135  	}
   136  
   137  	return int32(f - 0.5)
   138  }
   139  
   140  const (
   141  	firstOrd             = 0    /* ordinal number of the smallest element of |char| */
   142  	lastOrd              = 127  /* ordinal number of the largest element of |char| */
   143  	invalidCode          = 0177 /* code deserving an error message */
   144  	maxNameIndex         = 100  /* upper bound on the number of keywords */
   145  	maxLetters           = 666  /* upper bound on the total length of all keywords */
   146  	longestName          = 20   /* length of \.[DEFAULTRULETHICKNESS] */
   147  	hashPrime            = 141  /* size of the hash table */
   148  	commentCode          = 0
   149  	checkSumCode         = 1
   150  	designSizeCode       = 2
   151  	designUnitsCode      = 3
   152  	codingSchemeCode     = 4
   153  	familyCode           = 5
   154  	faceCode             = 6
   155  	sevenBitSafeFlagCode = 7
   156  	headerCode           = 8
   157  	fontDimenCode        = 9
   158  	ligTableCode         = 10
   159  	boundaryCharCode     = 11
   160  	virtualTitleCode     = 12
   161  	mapFontCode          = 13
   162  	characterCode        = 14
   163  	fontNameCode         = 20
   164  	fontAreaCode         = 21
   165  	fontChecksumCode     = 22
   166  	fontAtCode           = 23
   167  	fontDsizeCode        = 24
   168  	parameterCode        = 30
   169  	charInfoCode         = 60
   170  	width                = 1
   171  	height               = 2
   172  	depth                = 3
   173  	italic               = 4
   174  	charWdCode           = charInfoCode + width
   175  	charHtCode           = charInfoCode + height
   176  	charDpCode           = charInfoCode + depth
   177  	charIcCode           = charInfoCode + italic
   178  	nextLargerCode       = 65
   179  	mapCode              = 66
   180  	varCharCode          = 67
   181  	selectFontCode       = 80
   182  	setCharCode          = 81
   183  	setRuleCode          = 82
   184  	moveRightCode        = 83
   185  	moveDownCode         = 85
   186  	pushCode             = 87
   187  	popCode              = 88
   188  	specialCode          = 89
   189  	specialHexCode       = 90
   190  	labelCode            = 100
   191  	stopCode             = 101
   192  	skipCode             = 102
   193  	krnCode              = 103
   194  	ligCode              = 104
   195  	checkSumLoc          = 0
   196  	designSizeLoc        = 4
   197  	codingSchemeLoc      = 8
   198  	familyLoc            = codingSchemeLoc + 40
   199  	sevenFlagLoc         = familyLoc + 20
   200  	faceLoc              = sevenFlagLoc + 3
   201  	memSize              = 1028 + 4 /* number of nonzero memory addresses */
   202  	noTag                = 0        /* vanilla character */
   203  	ligTag               = 1        /* character has a ligature/kerning program */
   204  	listTag              = 2        /* character has a successor in a charlist */
   205  	extTag               = 3        /* character is extensible */
   206  	stopFlag             = 128      /* value indicating `\.[STOP]' in a lig/kern program */
   207  	kernFlag             = 128      /* op code for a kern step */
   208  	setChar0             = 0        /* \.[DVI] command to typeset character 0 and move right */
   209  	set1                 = 128      /* typeset a character and move right */
   210  	setRule              = 132      /* typeset a rule and move right */
   211  	push                 = 141      /* save the current positions */
   212  	pop                  = 142      /* restore previous positions */
   213  	right1               = 143      /* move right */
   214  	w0                   = 147      /* move right by |w| */
   215  	w1                   = 148      /* move right and set |w| */
   216  	x0                   = 152      /* move right by |x| */
   217  	x1                   = 153      /* move right and set |x| */
   218  	down1                = 157      /* move down */
   219  	y0                   = 161      /* move down by |y| */
   220  	y1                   = 162      /* move down and set |y| */
   221  	z0                   = 166      /* move down by |z| */
   222  	z1                   = 167      /* move down and set |z| */
   223  	fntNum0              = 171      /* set current font to 0 */
   224  	fnt1                 = 235      /* set current font */
   225  	xxx1                 = 239      /* extension to \.[DVI] primitives */
   226  	xxx4                 = 242      /* potentially long extension to \.[DVI] primitives */
   227  	fntDef1              = 243      /* define the meaning of a font number */
   228  	pre                  = 247      /* preamble */
   229  	post                 = 248      /* postamble beginning */
   230  	simple               = 0        /* $f(x,y)=z$ */
   231  	leftZ                = 1        /* $f(x,y)=f(z,y)$ */
   232  	rightZ               = 2        /* $f(x,y)=f(x,z)$ */
   233  	bothZ                = 3        /* $f(x,y)=f(f(x,z),y)$ */
   234  	pending              = 4        /* $f(x,y)$ is being evaluated */
   235  	idByte               = 202      /* current version of \.[VF] format */
   236  
   237  	// Constants in the outer block
   238  	bufSize        = 60  // length of lines displayed in error messages
   239  	maxHeaderBytes = 100 // four times the maximum number of words allowed in
   240  	//   the \.[TFM] file header block, must be 1024 or less
   241  
   242  	vfSize        = 10000 // maximum length of |vf| data, in bytes
   243  	maxStack      = 100   // maximum depth of simulated \.[DVI] stack
   244  	maxParamWords = 30    // the maximum number of \.[fontdimen] parameters allowed
   245  	maxLigSteps   = 5000
   246  	// maximum length of ligature program, must be at most $32767-257=32510$
   247  	maxKerns = 500  // the maximum number of distinct kern values
   248  	hashSize = 5003 // preferably a prime number, a bit larger than the number
   249  // of character pairs in lig/kern steps
   250  )
   251  
   252  type (
   253  	// Types in the outer block
   254  	// byte =  /* 0..255 */  byte // unsigned eight-bit quantity
   255  	asciiCode = /* 040..0177 */ byte // standard ASCII code numbers
   256  
   257  	fourBytes = struct {
   258  		b0 byte
   259  		b1 byte
   260  		b2 byte
   261  		b3 byte
   262  	}
   263  
   264  	fixWord = int32 // a scaled real value with 20 bits of fraction
   265  
   266  	headerIndex = /* 0..maxHeaderBytes */ byte
   267  	indx        = /* 0..077777 */ uint16
   268  
   269  	pointer = /* 0..memSize */ uint16 // an index into memory
   270  )
   271  
   272  type prg struct {
   273  	stdin, stdout, stderr knuth.File
   274  	// Globals in the outer block
   275  	vplFile/* text */ knuth.File
   276  
   277  	vfFile  knuth.File
   278  	tfmFile knuth.File
   279  
   280  	xord [256]asciiCode // conversion table
   281  
   282  	line       int32 // the number of the current line
   283  	goodIndent int32 // the number of lines since the last bad indentation
   284  	indent     int32 // the number of spaces per open parenthesis, zero if unknown
   285  	level      int32 // the current number of open parentheses
   286  
   287  	leftLn, rightLn bool // are the left and right ends of the buffer
   288  	//   at end-of-line marks?
   289  
   290  	limit/* 0..bufSize */ byte // position of the last character present in the buffer
   291  	loc/* 0..bufSize */ byte   // position of the last character read in the buffer
   292  	buffer                     [60]char
   293  	inputHasEnded              bool // there is no more input to read
   294  
   295  	charsOnLine/* 0..8 */ byte // the number of characters printed on the current line
   296  
   297  	curChar asciiCode // we have just read this
   298  
   299  	start                              [100] /* 0..maxLetters */ uint16
   300  	dictionary                         [667]asciiCode
   301  	startPtr/* 0..maxNameIndex */ byte // the first available place in |start|
   302  	dictPtr/* 0..maxLetters */ uint16  // the first available place in |dictionary|
   303  
   304  	curName                             [20]asciiCode // a name to look up
   305  	nameLength/* 0..longestName */ byte // its length
   306  	namePtr/* 0..maxNameIndex */ byte   // its ordinal number in the dictionary
   307  
   308  	nhash                            [141] /* 0..maxNameIndex */ byte
   309  	curHash/* 0..hashPrime-1 */ byte // current position in the hash table
   310  
   311  	equiv   [101]byte
   312  	curCode byte // equivalent most recently found in |equiv|
   313  
   314  	curBytes  fourBytes // a four-byte accumulator
   315  	zeroBytes fourBytes // four bytes all zero
   316  
   317  	fractionDigits [7]int32 // $2^[21]$ times $d_j$
   318  
   319  	headerBytes                       [101]byte       // the header block
   320  	headerPtr                         headerIndex     // the number of header bytes in use
   321  	designSize                        fixWord         // the design size
   322  	designUnits                       fixWord         // reciprocal of the scaling factor
   323  	frozenDu                          bool            // have we used |design_units| irrevocably?
   324  	sevenBitSafeFlag                  bool            // does the file claim to be seven-bit-safe?
   325  	ligKern                           [5001]fourBytes // the ligature program
   326  	nl/* 0..32767 */ uint16           // the number of ligature/kern instructions so far
   327  	minNl/* 0..32767 */ uint16        // the final value of |nl| must be at least this
   328  	kern                              [501]fixWord // the distinct kerning amounts
   329  	nk/* 0..maxKerns */ uint16        // the number of entries of |kern|
   330  	exten                             [256]fourBytes // extensible character specs
   331  	ne/* 0..256 */ uint16             // the number of extensible characters
   332  	param                             [30]fixWord // \.[FONTDIMEN] parameters
   333  	np/* 0..maxParamWords */ byte     // the largest parameter set nonzero
   334  	checkSumSpecified                 bool // did the user name the check sum?
   335  	bchar/* 0..256 */ uint16          // the right boundary character, or 256 if unspecified
   336  	vf                                [10001]byte // stored bytes for \.[VF] file
   337  	vfPtr/* 0..vfSize */ uint16       // first unused location in |vf|
   338  	vtitleStart/* 0..vfSize */ uint16 // starting location of \.[VTITLE] string
   339  	vtitleLength                      byte // length of \.[VTITLE] string
   340  	packetStart                       [256] /* 0..vfSize */ uint16
   341  	// beginning location of character packet
   342  	packetLength               [256]int32 // length of character packet
   343  	fontPtr/* 0..256 */ uint16 // number of distinct local fonts seen
   344  	curFont/* 0..256 */ uint16 // number of the current local font
   345  	fnameStart                 [256] /* 0..vfSize */ uint16 // beginning of local font name
   346  	fnameLength                [256]byte                    // length of local font name
   347  	fareaStart                 [256] /* 0..vfSize */ uint16 // beginning of local font area
   348  	fareaLength                [256]byte                    // length of local font area
   349  	fontChecksum               [256]fourBytes               // local font checksum
   350  	fontNumber                 [257]fourBytes               // local font id number
   351  	fontAt                     [256]fixWord                 // local font ``at size''
   352  	fontDsize                  [256]fixWord                 // local font design size
   353  
   354  	memory        [1033]fixWord                  // character dimensions and kerns
   355  	memPtr        pointer                        // largest |memory| word in use
   356  	link          [1033]pointer                  // to make lists of |memory| items
   357  	charWd        [256]pointer                   // pointers to the widths
   358  	charHt        [256]pointer                   // pointers to the heights
   359  	charDp        [256]pointer                   // pointers to the depths
   360  	charIc        [256]pointer                   // pointers to italic corrections
   361  	charTag       [256] /* noTag..extTag */ byte // character tags
   362  	charRemainder [257] /* 0..65535 */ uint16    // pointers to ligature labels,
   363  	//   next larger characters, or extensible characters
   364  
   365  	nextD fixWord // the next larger interval that is worth trying
   366  
   367  	index  [1033]byte
   368  	excess byte // number of words to remove, if list is being shortened
   369  
   370  	c byte    // the current character or byte being processed
   371  	x fixWord // current dimension of interest
   372  	k int32   // general-purpose index
   373  
   374  	lkStepEnded bool
   375  	// was the last \.[LIGTABLE] property \.[LIG] or \.[KRN]?
   376  	krnPtr/* 0..maxKerns */ uint16 // an index into |kern|
   377  
   378  	hstack                         [101] /* 0..2 */ byte // number of known horizontal movements
   379  	vstack                         [101] /* 0..2 */ byte // number of known vertical movements
   380  	wstack, xstack, ystack, zstack [101]fixWord
   381  	stackPtr/* 0..maxStack */ byte
   382  
   383  	sevenUnsafe bool // do seven-bit characters generate eight-bit ones?
   384  
   385  	delta fixWord // size of the intervals needed for rounding
   386  
   387  	ligPtr/* 0..maxLigSteps */ uint16       // an index into |lig_kern|
   388  	hash                                    [5004] /* 0..66048 */ uint32 // $256x+y+1$ for $x\le257$ and $y\le255$
   389  	class                                   [5004] /* simple..pending */ byte
   390  	ligZ                                    [5004] /* 0..257 */ uint16
   391  	hashPtr/* 0..hashSize */ uint16         // the number of nonzero entries in |hash|
   392  	hashList                                [5004] /* 0..hashSize */ uint16 // list of those nonzero entries
   393  	h, hh/* 0..hashSize */ uint16           // indices into the hash table
   394  	tt                                      indx // temporary register
   395  	xLigCycle, yLigCycle/* 0..256 */ uint16 // problematic ligature pair
   396  
   397  	bc                      byte // the smallest character code in the font
   398  	ec                      byte // the largest character code in the font
   399  	lh                      byte // the number of words in the header block
   400  	lf/* 0..32767 */ uint16 // the number of words in the entire \.[TFM] file
   401  	notFound                bool    // has a font character been found?
   402  	tempWidth               fixWord // width being used to compute a check sum
   403  
   404  	j/* 0..maxHeaderBytes */ byte     // index into |header_bytes|
   405  	p                                 pointer // index into |memory|
   406  	q/* width..italic */ byte         // runs through the list heads for dimensions
   407  	parPtr/* 0..maxParamWords */ byte // runs through the parameters
   408  
   409  	labelTable [257]struct {
   410  		rr int16 // sorted label values
   411  		cc byte  // associated characters
   412  	}
   413  	labelPtr/* 0..256 */ uint16 // index of highest entry in |label_table|
   414  	sortPtr/* 0..256 */ uint16  // index into |label_table|
   415  	lkOffset/* 0..256 */ uint16 // smallest offset value that might work
   416  	t/* 0..077777 */ uint16     // label value that is being redirected
   417  	extraLocNeeded              bool // do we need a special word for |bchar|?
   418  
   419  	vcount int32 // number of bytes written to |vf_file|
   420  }
   421  
   422  func (prg *prg) initialize() { // this procedure gets things started properly
   423  	var (
   424  		// Local variables for initialization
   425  		k int32 // all-purpose initialization index
   426  
   427  		h/* 0..hashPrime-1 */ byte // runs through the hash table
   428  
   429  		d headerIndex // an index into |header_bytes|
   430  
   431  		c byte // runs through all character codes
   432  	)
   433  	prg.stdout.Writeln("This is VPtoVF, Version 1.6 (govptovf v0.0-prerelease)")
   434  
   435  	// Set initial values
   436  	prg.vplFile.Reset()
   437  
   438  	prg.vfFile.Rewrite()
   439  	prg.tfmFile.Rewrite()
   440  
   441  	for ii := int32(firstOrd); ii <= lastOrd; ii++ {
   442  		k = ii
   443  		_ = k
   444  		prg.xord[char(k)] = byte(invalidCode)
   445  	}
   446  	prg.xord[' '] = ' '
   447  	prg.xord['!'] = '!'
   448  	prg.xord['"'] = '"'
   449  	prg.xord['#'] = '#'
   450  	prg.xord['$'] = '$'
   451  	prg.xord['%'] = '%'
   452  	prg.xord['&'] = '&'
   453  	prg.xord['\''] = '\''
   454  	prg.xord['('] = '('
   455  	prg.xord[')'] = ')'
   456  	prg.xord['*'] = '*'
   457  	prg.xord['+'] = '+'
   458  	prg.xord[','] = ','
   459  	prg.xord['-'] = '-'
   460  	prg.xord['.'] = '.'
   461  	prg.xord['/'] = '/'
   462  	prg.xord['0'] = '0'
   463  	prg.xord['1'] = '1'
   464  	prg.xord['2'] = '2'
   465  	prg.xord['3'] = '3'
   466  	prg.xord['4'] = '4'
   467  	prg.xord['5'] = '5'
   468  	prg.xord['6'] = '6'
   469  	prg.xord['7'] = '7'
   470  	prg.xord['8'] = '8'
   471  	prg.xord['9'] = '9'
   472  	prg.xord[':'] = ':'
   473  	prg.xord[';'] = ';'
   474  	prg.xord['<'] = '<'
   475  	prg.xord['='] = '='
   476  	prg.xord['>'] = '>'
   477  	prg.xord['?'] = '?'
   478  	prg.xord['@'] = '@'
   479  	prg.xord['A'] = 'A'
   480  	prg.xord['B'] = 'B'
   481  	prg.xord['C'] = 'C'
   482  	prg.xord['D'] = 'D'
   483  	prg.xord['E'] = 'E'
   484  	prg.xord['F'] = 'F'
   485  	prg.xord['G'] = 'G'
   486  	prg.xord['H'] = 'H'
   487  	prg.xord['I'] = 'I'
   488  	prg.xord['J'] = 'J'
   489  	prg.xord['K'] = 'K'
   490  	prg.xord['L'] = 'L'
   491  	prg.xord['M'] = 'M'
   492  	prg.xord['N'] = 'N'
   493  	prg.xord['O'] = 'O'
   494  	prg.xord['P'] = 'P'
   495  	prg.xord['Q'] = 'Q'
   496  	prg.xord['R'] = 'R'
   497  	prg.xord['S'] = 'S'
   498  	prg.xord['T'] = 'T'
   499  	prg.xord['U'] = 'U'
   500  	prg.xord['V'] = 'V'
   501  	prg.xord['W'] = 'W'
   502  	prg.xord['X'] = 'X'
   503  	prg.xord['Y'] = 'Y'
   504  	prg.xord['Z'] = 'Z'
   505  	prg.xord['['] = '['
   506  	prg.xord['\\'] = '\\'
   507  	prg.xord[']'] = ']'
   508  	prg.xord['^'] = '^'
   509  	prg.xord['_'] = '_'
   510  	prg.xord['`'] = '`'
   511  	prg.xord['a'] = 'a'
   512  	prg.xord['b'] = 'b'
   513  	prg.xord['c'] = 'c'
   514  	prg.xord['d'] = 'd'
   515  	prg.xord['e'] = 'e'
   516  	prg.xord['f'] = 'f'
   517  	prg.xord['g'] = 'g'
   518  	prg.xord['h'] = 'h'
   519  	prg.xord['i'] = 'i'
   520  	prg.xord['j'] = 'j'
   521  	prg.xord['k'] = 'k'
   522  	prg.xord['l'] = 'l'
   523  	prg.xord['m'] = 'm'
   524  	prg.xord['n'] = 'n'
   525  	prg.xord['o'] = 'o'
   526  	prg.xord['p'] = 'p'
   527  	prg.xord['q'] = 'q'
   528  	prg.xord['r'] = 'r'
   529  	prg.xord['s'] = 's'
   530  	prg.xord['t'] = 't'
   531  	prg.xord['u'] = 'u'
   532  	prg.xord['v'] = 'v'
   533  	prg.xord['w'] = 'w'
   534  	prg.xord['x'] = 'x'
   535  	prg.xord['y'] = 'y'
   536  	prg.xord['z'] = 'z'
   537  	prg.xord['{'] = '{'
   538  	prg.xord['|'] = '|'
   539  	prg.xord['}'] = '}'
   540  	prg.xord['~'] = '~'
   541  
   542  	prg.line = 0
   543  	prg.goodIndent = 0
   544  	prg.indent = 0
   545  	prg.level = 0
   546  
   547  	prg.limit = 0
   548  	prg.loc = 0
   549  	prg.leftLn = true
   550  	prg.rightLn = true
   551  	prg.inputHasEnded = false
   552  
   553  	prg.charsOnLine = 0
   554  
   555  	prg.startPtr = 1
   556  	prg.start[1-1] = 0
   557  	prg.dictPtr = 0
   558  
   559  	for ii := int32(0); ii <= hashPrime-1; ii++ {
   560  		h = byte(ii)
   561  		_ = h
   562  		prg.nhash[h] = 0
   563  	}
   564  
   565  	prg.zeroBytes.b0 = 0
   566  	prg.zeroBytes.b1 = 0
   567  	prg.zeroBytes.b2 = 0
   568  	prg.zeroBytes.b3 = 0
   569  
   570  	for ii := int32(0); ii <= 18*4-1; ii++ {
   571  		d = headerIndex(ii)
   572  		_ = d
   573  		prg.headerBytes[d] = 0
   574  	}
   575  	prg.headerBytes[8] = 11
   576  	prg.headerBytes[9] = 'U'
   577  	prg.headerBytes[10] = 'N'
   578  	prg.headerBytes[11] = 'S'
   579  	prg.headerBytes[12] = 'P'
   580  	prg.headerBytes[13] = 'E'
   581  	prg.headerBytes[14] = 'C'
   582  	prg.headerBytes[15] = 'I'
   583  	prg.headerBytes[16] = 'F'
   584  	prg.headerBytes[17] = 'I'
   585  	prg.headerBytes[18] = 'E'
   586  	prg.headerBytes[19] = 'D'
   587  	// \xref[UNSPECIFIED]
   588  	for ii := int32(familyLoc); ii <= familyLoc+11; ii++ {
   589  		d = headerIndex(ii)
   590  		_ = d
   591  		prg.headerBytes[d] = prg.headerBytes[int32(d)-40]
   592  	}
   593  	prg.designSize = 10 * 04000000
   594  	prg.designUnits = 04000000
   595  	prg.frozenDu = false
   596  	prg.sevenBitSafeFlag = false
   597  
   598  	prg.headerPtr = byte(18 * 4)
   599  	prg.nl = 0
   600  	prg.minNl = 0
   601  	prg.nk = 0
   602  	prg.ne = 0
   603  	prg.np = 0
   604  
   605  	prg.checkSumSpecified = false
   606  	prg.bchar = 256
   607  
   608  	prg.vfPtr = 0
   609  	prg.vtitleStart = 0
   610  	prg.vtitleLength = 0
   611  	prg.fontPtr = 0
   612  	for ii := int32(0); ii <= 255; ii++ {
   613  		k = ii
   614  		_ = k
   615  		prg.packetStart[k] = uint16(vfSize)
   616  	}
   617  	for ii := int32(0); ii <= 127; ii++ {
   618  		k = ii
   619  		_ = k
   620  		prg.packetLength[k] = 1
   621  	}
   622  	for ii := int32(128); ii <= 255; ii++ {
   623  		k = ii
   624  		_ = k
   625  		prg.packetLength[k] = 2
   626  	}
   627  
   628  	prg.charRemainder[256] = 077777
   629  	for ii := int32(0); ii <= 255; ii++ {
   630  		c = byte(ii)
   631  		_ = c
   632  		prg.charWd[c] = 0
   633  		prg.charHt[c] = 0
   634  		prg.charDp[c] = 0
   635  		prg.charIc[c] = 0
   636  
   637  		prg.charTag[c] = byte(noTag)
   638  		prg.charRemainder[c] = 0
   639  	}
   640  	prg.memory[0] = 017777777777 // an ``infinite'' element at the end of the lists
   641  	prg.memory[width] = 0
   642  	prg.link[width] = 0 // width list is empty
   643  	prg.memory[height] = 0
   644  	prg.link[height] = 0 // height list is empty
   645  	prg.memory[depth] = 0
   646  	prg.link[depth] = 0 // depth list is empty
   647  	prg.memory[italic] = 0
   648  	prg.link[italic] = 0 // italic list is empty
   649  	prg.memPtr = uint16(italic)
   650  
   651  	prg.hashPtr = 0
   652  	prg.yLigCycle = 256
   653  	for ii := int32(0); ii <= hashSize; ii++ {
   654  		k = ii
   655  		_ = k
   656  		prg.hash[k] = 0
   657  	}
   658  
   659  }
   660  
   661  // 4.
   662  
   663  // tangle:pos vptovf.web:101:40:
   664  
   665  // Here are some macros for common programming idioms.
   666  
   667  // 7.
   668  
   669  // tangle:pos vptovf.web:133:17:
   670  
   671  // A \.[VPL] file is like a \.[PL] file with a few extra features, so we
   672  // can begin to define it by reviewing the definition of \.[PL] files. The
   673  // material in the next few sections is copied from the program \.[PLtoTF].
   674  //
   675  // A \.[PL] file is a list of entries of the form
   676  // $$\.[(PROPERTYNAME VALUE)]$$
   677  // where the property name is one of a finite set of names understood by
   678  // this program, and the value may itself in turn be a property list.
   679  // The idea is best understood by looking at an example, so let's consider
   680  // a fragment of the \.[PL] file for a hypothetical font.
   681  // $$\vbox[\halign[\.[#]\hfil\cr
   682  // (FAMILY NOVA)\cr
   683  // (FACE F MIE)\cr
   684  // (CODINGSCHEME ASCII)\cr
   685  // (DESIGNSIZE D 10)\cr
   686  // (DESIGNUNITS D 18)\cr
   687  // (COMMENT A COMMENT IS IGNORED)\cr
   688  // (COMMENT (EXCEPT THIS ONE ISN'T))\cr
   689  // (COMMENT (ACTUALLY IT IS, EVEN THOUGH\cr
   690  // \qquad\qquad IT SAYS IT ISN'T))\cr
   691  // (FONTDIMEN\cr
   692  // \qquad   (SLANT R -.25)\cr
   693  // \qquad   (SPACE D 6)\cr
   694  // \qquad   (SHRINK D 2)\cr
   695  // \qquad   (STRETCH D 3)\cr
   696  // \qquad   (XHEIGHT R 10.55)\cr
   697  // \qquad   (QUAD D 18)\cr
   698  // \qquad   )\cr
   699  // (LIGTABLE\cr
   700  // \qquad   (LABEL C f)\cr
   701  // \qquad   (LIG C f O 200)\cr
   702  // \qquad   (SKIP D 1)\cr
   703  // \qquad   (LABEL O 200)\cr
   704  // \qquad   (LIG C i O 201)\cr
   705  // \qquad   (KRN O 51 R 1.5)\cr
   706  // \qquad   (/LIG C ? C f)\cr
   707  // \qquad   (STOP)\cr
   708  // \qquad   )\cr
   709  // (CHARACTER C f\cr
   710  // \qquad   (CHARWD D 6)\cr
   711  // \qquad   (CHARHT R 13.5)\cr
   712  // \qquad   (CHARIC R 1.5)\cr
   713  // \qquad   )\cr]]$$
   714  // This example says that the font whose metric information is being described
   715  // belongs to the hypothetical
   716  // \.[NOVA] family; its face code is medium italic extended;
   717  // and the characters appear in ASCII code positions. The design size is 10 points,
   718  // and all other sizes in this \.[PL] file are given in units such that 18 units
   719  // equals the design size. The font is slanted with a slope of $-.25$ (hence the
   720  // letters actually slant backward---perhaps that is why the family name is
   721  // \.[NOVA]). The normal space between words is 6 units (i.e., one third of
   722  // the 18-unit design size), with glue that shrinks by 2 units or stretches by 3.
   723  // The letters for which accents don't need to be raised or lowered are 10.55
   724  // units high, and one em equals 18 units.
   725  //
   726  // The example ligature table is a bit trickier. It specifies that the
   727  // letter \.f followed by another \.f is changed to code @'200, while
   728  // code @'200 followed by \.i is changed to @'201; presumably codes @'200
   729  // and @'201 represent the ligatures `ff' and `ffi'.  Moreover, in both cases
   730  // \.f and @'200, if the following character is the code @'51 (which is a
   731  // right parenthesis), an additional 1.5 units of space should be inserted
   732  // before the @'51.  (The `\.[SKIP]~\.D~\.1' skips over one \.[LIG] or
   733  // \.[KRN] command, which in this case is the second \.[LIG]; in this way
   734  // two different ligature/kern programs can come together.)
   735  // Finally, if either \.f or @'200 is followed by a question mark,
   736  // the question mark is replaced by \.f and the ligature program is
   737  // started over. (Thus, the character pair `\.[f?]' would actually become
   738  // the ligature `ff', and `\.[ff?]' or `\.[f?f]' would become `fff'. To
   739  // avoid this restart procedure, the \.[/LIG] command could be replaced
   740  // by \.[/LIG>]; then `\.[f?]' would become `f\kern0ptf' and `\.[f?f]'
   741  // would become `f\kern0ptff'.)
   742  //
   743  // Character \.f itself is 6 units wide and 13.5 units tall, in this example.
   744  // Its depth is zero (since \.[CHARDP] is not given), and its italic correction
   745  // is 1.5 units.
   746  
   747  // 8.
   748  
   749  // tangle:pos vptovf.web:209:14:
   750  
   751  // The example above illustrates most of the features found in \.[PL] files.
   752  // Note that some property names, like \.[FAMILY] or \.[COMMENT], take a
   753  // string as their value; this string continues until the first unmatched
   754  // right parenthesis. But most property names, like \.[DESIGNSIZE] and \.[SLANT]
   755  // and \.[LABEL], take a number as their value. This number can be expressed in
   756  // a variety of ways, indicated by a prefixed code; \.D stands for decimal,
   757  // \.H for hexadecimal, \.O for octal, \.R for real, \.C for character, and
   758  // \.F for ``face.''  Other property names, like \.[LIG], take two numbers as
   759  // their value.  And still other names, like \.[FONTDIMEN] and \.[LIGTABLE] and
   760  // \.[CHARACTER], have more complicated values that involve property lists.
   761  //
   762  // A property name is supposed to be used only in an appropriate property
   763  // list.  For example, \.[CHARWD] shouldn't occur on the outer level or
   764  // within \.[FONTDIMEN].
   765  //
   766  // The individual property-and-value pairs in a property list can appear in
   767  // any order. For instance, `\.[SHRINK]' precedes `\.[STRETCH]' in the example
   768  // above, although the \.[TFM] file always puts the stretch parameter first.
   769  // One could even give the information about characters like `\.f' before
   770  // specifying the number of units in the design size, or before specifying the
   771  // ligature and kerning table. However, the \.[LIGTABLE] itself is an exception
   772  // to this rule; the individual elements of the \.[LIGTABLE] property list
   773  // can be reordered only to a certain extent without changing the meaning
   774  // of that table.
   775  //
   776  // If property-and-value pairs are omitted, a default value is used. For example,
   777  // we have already noted that the default for \.[CHARDP] is zero. The default
   778  // for [\sl every\/] numeric value is, in fact, zero, unless otherwise stated
   779  // below.
   780  //
   781  // If the same property name is used more than once, \.[VPtoVF] will not notice
   782  // the discrepancy; it simply uses the final value given. Once again, however, the
   783  // \.[LIGTABLE] is an exception to this rule; \.[VPtoVF] will complain if there
   784  // is more than one label for some character. And of course many of the
   785  // entries in the \.[LIGTABLE] property list have the same property name.
   786  
   787  // 9.
   788  
   789  // tangle:pos vptovf.web:245:71:
   790  
   791  // A \.[VPL] file also includes information about how to create each character,
   792  // by typesetting characters from other fonts and/or by drawing lines, etc.
   793  // Such information is the value of the `\.[MAP]' property, which can be
   794  // illustrated as follows:
   795  // $$\vbox[\halign[\.[#]\hfil\cr
   796  // (MAPFONT D 0 (FONTNAME Times-Roman))\cr
   797  // (MAPFONT D 1 (FONTNAME Symbol))\cr
   798  // (MAPFONT D 2 (FONTNAME cmr10)(FONTAT D 20))\cr
   799  // (CHARACTER O 0 (MAP (SELECTFONT D 1)(SETCHAR C G)))\cr
   800  // (CHARACTER O 76 (MAP (SETCHAR O 277)))\cr
   801  // (CHARACTER D 197 (MAP\cr
   802  // \qquad(PUSH)(SETCHAR C A)(POP)\cr
   803  // \qquad(MOVEUP R 0.937)(MOVERIGHT R 1.5)(SETCHAR O 312)))\cr
   804  // (CHARACTER O 200 (MAP (MOVEDOWN R 2.1)(SETRULE R 1 R 8)))\cr
   805  // (CHARACTER O 201 (MAP\cr
   806  // \qquad (SPECIAL ps: /SaveGray currentgray def .5 setgray)\cr
   807  // \qquad (SELECTFONT D 2)(SETCHAR C A)\cr
   808  // \qquad (SPECIAL ps: SaveGray setgray)))\cr
   809  // ]]$$
   810  // (These specifications appear in addition to the conventional \.[PL]
   811  // information. The \.[MAP] attribute can be mixed in with other attributes
   812  // like \.[CHARWD] or it can be given separately.)
   813  //
   814  // In this example, the virtual font is composed of characters that can be
   815  // fabricated from three actual fonts, `\.[Times-Roman]',
   816  // `\.[Symbol]', and `\.[cmr10] \.[at] \.[20\\u]' (where \.[\\u]
   817  // is the unit size in this \.[VPL] file). Character |@'0| is typeset as
   818  // a `G' from the symbol font. Character |@'76| is typeset as character |@'277|
   819  // from the ordinary Times font. (If no other font is selected, font
   820  // number~0 is the default. If no \.[MAP] attribute is given, the default map
   821  // is a character of the same number in the default font.)
   822  //
   823  // Character 197 (decimal) is more interesting: First an A is typeset (in the
   824  // default font Times), and this is enclosed by \.[PUSH] and \.[POP] so that
   825  // the original position is restored. Then the accent character |@'312| is
   826  // typeset, after moving up .937 units and right 1.5 units.
   827  //
   828  // To typeset character |@'200| in this virtual font, we move down 2.1 units,
   829  // then typeset a rule that is 1 unit high and 8 units wide.
   830  //
   831  // Finally, to typeset character |@'201|, we do something that requires a
   832  // special ability to interpret PostScript commands; this example
   833  // sets the PostScript ``color'' to 50\char`\%\ gray and typesets an `A'
   834  // from \.[cmr10] \.[at] \.[20\\u] in that color.
   835  //
   836  // In general, the \.[MAP] attribute of a virtual character can be any sequence
   837  // of typesetting commands that might appear in a page of a \.[DVI] file.
   838  // A single character might map into an entire page.
   839  
   840  // 10.
   841  
   842  // tangle:pos vptovf.web:294:50:
   843  
   844  // But instead of relying on a hypothetical example, let's consider a complete
   845  // grammar for \.[VPL] files, beginning with the (unchanged) grammatical rules
   846  // for \.[PL] files. At the outer level, the following property names
   847  // are valid in any \.[PL] file:
   848  //
   849  // \yskip\hang\.[CHECKSUM] (four-byte value). The value, which should be a
   850  // nonnegative integer less than $2^[32]$, is used to identify a particular
   851  // version of a font; it should match the check sum value stored with the font
   852  // itself. An explicit check sum of zero is used to bypass
   853  // check sum testing. If no checksum is specified in the \.[VPL] file,
   854  // \.[VPtoVF] will compute the checksum that \MF\ would compute from the
   855  // same data.
   856  //
   857  // \yskip\hang\.[DESIGNSIZE] (numeric value, default is 10). The value, which
   858  // should be a real number in the range |1.0<=x<2048|, represents the default
   859  // amount by which all quantities will be scaled if the font is not loaded
   860  // with an `\.[at]' specification. For example, if one says
   861  // `\.[\\font\\A=cmr10 at 15pt]' in \TeX\ language, the design size in the \.[TFM]
   862  // file is ignored and effectively replaced by 15 points; but if one simply
   863  // says `\.[\\font\\A=cmr10]' the stated design size is used. This quantity is
   864  // always in units of printer's points.
   865  //
   866  // \yskip\hang\.[DESIGNUNITS] (numeric value, default is 1). The value
   867  // should be a positive real number; it says how many units equals the design
   868  // size (or the eventual `\.[at]' size, if the font is being scaled). For
   869  // example, suppose you have a font that has been digitized with 600 pixels per
   870  // em, and the design size is one em; then you could say `\.[(DESIGNUNITS R 600)]'
   871  // if you wanted to give all of your measurements in units of pixels.
   872  //
   873  // \yskip\hang\.[CODINGSCHEME] (string value, default is `\.[UNSPECIFIED]').
   874  // The string should not contain parentheses, and its length must be less than 40.
   875  // It identifies the correspondence between the numeric codes and font characters.
   876  // (\TeX\ ignores this information, but other software programs make use of it.)
   877  //
   878  // \yskip\hang\.[FAMILY] (string value, default is `\.[UNSPECIFIED]').
   879  // The string should not contain parentheses, and its length must be less than 20.
   880  // It identifies the name of the family to which this font belongs, e.g.,
   881  // `\.[HELVETICA]'.  (\TeX\ ignores this information; but it is needed, for
   882  // example, when converting \.[DVI] files to \.[PRESS] files for Xerox
   883  // equipment.)
   884  //
   885  // \yskip\hang\.[FACE] (one-byte value). This number, which must lie between
   886  // 0 and 255 inclusive, is a subsidiary ident\-ifi\-ca\-tion of the font within its
   887  // family. For example, bold italic condensed fonts might have the same family name
   888  // as light roman extended fonts, differing only in their face byte.  (\TeX\
   889  // ignores this information; but it is needed, for example, when converting
   890  // \.[DVI] files to \.[PRESS] files for Xerox equipment.)
   891  //
   892  // \yskip\hang\.[SEVENBITSAFEFLAG] (string value, default is `\.[FALSE]'). The
   893  // value should start with either `\.T' (true) or `\.F' (false). If true, character
   894  // codes less than 128 cannot lead to codes of 128 or more via ligatures or
   895  // charlists or extensible characters. (\TeX82 ignores this flag, but older
   896  // versions of \TeX\ would only accept \.[TFM] files that were seven-bit safe.)
   897  // \.[VPtoVF] computes the correct value of this flag and gives an error message
   898  // only if a claimed ``true'' value is incorrect.
   899  //
   900  // \yskip\hang\.[HEADER] (a one-byte value followed by a four-byte value).
   901  // The one-byte value should be between 18 and a maximum limit that can be
   902  // raised or lowered depending on the compile-time setting of |max_header_bytes|.
   903  // The four-byte value goes into the header word whose index is the one-byte
   904  // value; for example, to set |header[18]:=1|, one may write
   905  // `\.[(HEADER D 18 O 1)]'. This notation is used for header information that
   906  // is presently unnamed. (\TeX\ ignores it.)
   907  //
   908  // \yskip\hang\.[FONTDIMEN] (property list value). See below for the names
   909  // allowed in this property list.
   910  //
   911  // \yskip\hang\.[LIGTABLE] (property list value). See below for the rules
   912  // about this special kind of property list.
   913  //
   914  // \yskip\hang\.[BOUNDARYCHAR] (one-byte value). If this character appears in
   915  // a \.[LIGTABLE] command, it matches ``end of word'' as well as itself.
   916  // If no boundary character is given and no \.[LABEL] \.[BOUNDARYCHAR] occurs
   917  // within \.[LIGTABLE], word boundaries will not affect ligatures or kerning.
   918  //
   919  // \yskip\hang\.[CHARACTER]. The value is a one-byte integer followed by
   920  // a property list. The integer represents the number of a character that is
   921  // present in the font; the property list of a character is defined below.
   922  // The default is an empty property list.
   923  
   924  // 11.
   925  
   926  // tangle:pos vptovf.web:374:39:
   927  
   928  // Numeric property list values can be given in various forms identified by
   929  // a prefixed letter.
   930  //
   931  // \yskip\hang\.C denotes an ASCII character, which should be a standard visible
   932  // character that is not a parenthesis. The numeric value will therefore be
   933  // between @'41 and @'176 but not @'50 or @'51.
   934  //
   935  // \yskip\hang\.D denotes an unsigned decimal integer, which must be
   936  // less than $2^[32]$, i.e., at most `\.[D 4294967295]'.
   937  //
   938  // \yskip\hang\.F denotes a three-letter Xerox face code; the admissible codes
   939  // are \.[MRR], \.[MIR], \.[BRR], \.[BIR], \.[LRR], \.[LIR], \.[MRC], \.[MIC],
   940  // \.[BRC], \.[BIC], \.[LRC], \.[LIC], \.[MRE], \.[MIE], \.[BRE], \.[BIE],
   941  // \.[LRE], and \.[LIE], denoting the integers 0 to 17, respectively.
   942  //
   943  // \yskip\hang\.O denotes an unsigned octal integer, which must be less than
   944  // $2^[32]$, i.e., at most `\.[O 37777777777]'.
   945  //
   946  // \yskip\hang\.H denotes an unsigned hexadecimal integer, which must be less than
   947  // $2^[32]$, i.e., at most `\.[H FFFFFFFF]'.
   948  //
   949  // \yskip\hang\.R denotes a real number in decimal notation, optionally preceded
   950  // by a `\.+' or `\.-' sign, and optionally including a decimal point. The
   951  // absolute value must be less than 2048.
   952  
   953  // 12.
   954  
   955  // tangle:pos vptovf.web:399:39:
   956  
   957  // The property names allowed in a \.[FONTDIMEN] property list correspond to
   958  // various \TeX\ parameters, each of which has a (real) numeric value. All
   959  // of the parameters except \.[SLANT] are in design units. The admissible
   960  // names are \.[SLANT], \.[SPACE], \.[STRETCH], \.[SHRINK], \.[XHEIGHT],
   961  // \.[QUAD], \.[EXTRASPACE], \.[NUM1], \.[NUM2], \.[NUM3], \.[DENOM1],
   962  // \.[DENOM2], \.[SUP1], \.[SUP2], \.[SUP3], \.[SUB1], \.[SUB2], \.[SUPDROP],
   963  // \.[SUBDROP], \.[DELIM1], \.[DELIM2], and \.[AXISHEIGHT], for parameters
   964  // 1~to~22. The alternate names \.[DEFAULTRULETHICKNESS],
   965  // \.[BIGOPSPACING1], \.[BIGOPSPACING2], \.[BIGOPSPACING3],
   966  // \.[BIGOPSPACING4], and \.[BIGOPSPACING5], may also be used for parameters
   967  // 8 to 13.
   968  //
   969  // The notation `\.[PARAMETER] $n$' provides another way to specify the
   970  // $n$th parameter; for example, `\.[(PARAMETER] \.[D 1 R -.25)]' is another way
   971  // to specify that the \.[SLANT] is $-0.25$. The value of $n$ must be positive
   972  // and less than |max_param_words|.
   973  
   974  // 13.
   975  
   976  // tangle:pos vptovf.web:416:33:
   977  
   978  // The elements of a \.[CHARACTER] property list can be of six different types.
   979  //
   980  // \yskip\hang\.[CHARWD] (real value) denotes the character's width in
   981  // design units.
   982  //
   983  // \yskip\hang\.[CHARHT] (real value) denotes the character's height in
   984  // design units.
   985  //
   986  // \yskip\hang\.[CHARDP] (real value) denotes the character's depth in
   987  // design units.
   988  //
   989  // \yskip\hang\.[CHARIC] (real value) denotes the character's italic correction in
   990  // design units.
   991  //
   992  // \yskip\hang\.[NEXTLARGER] (one-byte value), specifies the character that
   993  // follows the present one in a ``charlist.'' The value must be the number of a
   994  // character in the font, and there must be no infinite cycles of supposedly
   995  // larger and larger characters.
   996  //
   997  // \yskip\hang\.[VARCHAR] (property list value), specifies an extensible character.
   998  // This option and \.[NEXTLARGER] are mutually exclusive; i.e., they cannot
   999  // both be used within the same \.[CHARACTER] list.
  1000  //
  1001  // \yskip\noindent
  1002  // The elements of a \.[VARCHAR] property list are either \.[TOP], \.[MID],
  1003  // \.[BOT], or \.[REP]; the values are integers, which must be zero or the number
  1004  // of a character in the font. A zero value for \.[TOP], \.[MID], or \.[BOT] means
  1005  // that the corresponding piece of the extensible character is absent. A nonzero
  1006  // value, or a \.[REP] value of zero, denotes the character code used to make
  1007  // up the top, middle, bottom, or replicated piece of an extensible character.
  1008  
  1009  // 14.
  1010  
  1011  // tangle:pos vptovf.web:447:76:
  1012  
  1013  // A \.[LIGTABLE] property list contains elements of four kinds, specifying a
  1014  // program in a simple command language that \TeX\ uses for ligatures and kerns.
  1015  // If several \.[LIGTABLE] lists appear, they are effectively concatenated into
  1016  // a single list.
  1017  //
  1018  // \yskip\hang\.[LABEL] (one-byte value) means that the program for the
  1019  // stated character value starts here. The integer must be the number of a
  1020  // character in the font; its \.[CHARACTER] property list must not have a
  1021  // \.[NEXTLARGER] or \.[VARCHAR] field. At least one \.[LIG] or \.[KRN] step
  1022  // must follow.
  1023  //
  1024  // \yskip\hang\.[LABEL] \.[BOUNDARYCHAR] means that the program for
  1025  // beginning-of-word ligatures starts here.
  1026  //
  1027  // \yskip\hang\.[LIG] (two one-byte values). The instruction `\.[(LIG] $c$ $r$\.)'
  1028  // means, ``If the next character is $c$, then insert character~$r$ and
  1029  // possibly delete the current character and/or~$c$;
  1030  // otherwise go on to the next instruction.''
  1031  // Characters $r$ and $c$ must be present in the font. \.[LIG] may be immediately
  1032  // preceded or followed by a slash, and then immediately followed by \.>
  1033  // characters not exceeding the number of slashes. Thus there are eight
  1034  // possible forms:
  1035  // $$\hbox to .8\hsize[\.[LIG]\hfil\.[/LIG]\hfil\.[/LIG>]\hfil
  1036  // \.[LIG/]\hfil\.[LIG/>]\hfil\.[/LIG/]\hfil\.[/LIG/>]\hfil\.[/LIG/>>]]$$
  1037  // The slashes specify retention of the left or right original character; the
  1038  // \.> signs specify passing over the result without further ligature processing.
  1039  //
  1040  // \yskip\hang\.[KRN] (a one-byte value and a real value). The instruction
  1041  // `\.[(KRN] $c$ $r$\.)' means, ``If the next character is $c$, then insert
  1042  // a blank space of width $r$ between the current character and $c$;
  1043  // otherwise go on to the next instruction.'' The value of $r$, which is in
  1044  // design units, is often negative. Character code $c$ must exist
  1045  // in the font.
  1046  //
  1047  // \yskip\hang\.[STOP] (no value). This instruction ends a ligature/kern program.
  1048  // It must follow either a \.[LIG] or \.[KRN] instruction, not a \.[LABEL]
  1049  // or \.[STOP] or \.[SKIP].
  1050  //
  1051  // \yskip\hang\.[SKIP] (value in the range |0..127|). This instruction specifies
  1052  // continuation of a ligature/kern program after the specified number of \.[LIG]
  1053  // or \.[KRN] steps has been skipped over. The number of subsequent \.[LIG] and
  1054  // \.[KRN] instructions must therefore exceed this specified amount.
  1055  
  1056  // 15.
  1057  
  1058  // tangle:pos vptovf.web:490:66:
  1059  
  1060  // In addition to all these possibilities, the property name \.[COMMENT] is
  1061  // allowed in any property list. Such comments are ignored.
  1062  
  1063  // 16.
  1064  
  1065  // tangle:pos vptovf.web:493:57:
  1066  
  1067  // So that is what \.[PL] files hold. In a \.[VPL] file additional
  1068  // properties are recognized; two of these are valid on the outermost level:
  1069  //
  1070  // \yskip\hang\.[VTITLE] (string value, default is empty). The value will be
  1071  // reproduced at the beginning of the \.[VF] file (and printed on the terminal
  1072  // by \.[VFtoVP] when it examines that file).
  1073  //
  1074  // \yskip\hang\.[MAPFONT]. The value is a nonnegative integer followed by
  1075  // a property list. The integer represents an identifying number for fonts
  1076  // used in \.[MAP] attributes. The property list, which identifies the font and
  1077  // relative size, is defined below.
  1078  //
  1079  // \yskip\noindent
  1080  // And one additional ``virtual property'' is valid within a \.[CHARACTER]:
  1081  //
  1082  // \yskip\hang\.[MAP]. The value is a property list consisting of typesetting
  1083  // commands. Default is the single command \.[SETCHAR]~$c$, where $c$ is
  1084  // the current character number.
  1085  
  1086  // 17.
  1087  
  1088  // tangle:pos vptovf.web:512:30:
  1089  
  1090  // The elements of a \.[MAPFONT] property list can be of the following types.
  1091  //
  1092  // \yskip\hang\.[FONTNAME] (string value, default is \.[NULL]).
  1093  // This is the font's identifying name.
  1094  //
  1095  // \yskip\hang\.[FONTAREA] (string value, default is empty). If the font appears
  1096  // in a nonstandard directory, according to local conventions, the directory
  1097  // name is given here. (This is system dependent, just as in \.[DVI] files.)
  1098  //
  1099  // \yskip\hang\.[FONTCHECKSUM] (four-byte value, default is zero). This value,
  1100  // which should be a nonnegative integer less than $2^[32]$, can be used to
  1101  // check that the font being referred to matches the intended font. If nonzero,
  1102  // it should equal the \.[CHECKSUM] parameter in that font.
  1103  //
  1104  // \yskip\hang\.[FONTAT] (numeric value, default is the \.[DESIGNUNITS] of the
  1105  // present virtual font). This value is relative to the design units of
  1106  // the present virtual font, hence it will be scaled when the virtual
  1107  // font is magnified or reduced.  It represents the value that will
  1108  // effectively replace the design size of the font being referred to,
  1109  // so that all characters will be scaled appropriately.
  1110  //
  1111  // \yskip\hang\.[FONTDSIZE] (numeric value, default is 10). This value is
  1112  // absolute, in units of printer's points. It should equal the \.[DESIGNSIZE]
  1113  // parameter in the font being referred to.
  1114  //
  1115  // \yskip\noindent
  1116  // If any of the
  1117  // string values contain parentheses, the parentheses must be balanced. Leading
  1118  // blanks are removed from the strings, but trailing blanks are not.
  1119  
  1120  // 18.
  1121  
  1122  // tangle:pos vptovf.web:542:66:
  1123  
  1124  // Finally, the elements of a \.[MAP] property list are an ordered sequence
  1125  // of typesetting commands chosen from among the following:
  1126  //
  1127  // \yskip\hang\.[SELECTFONT] (four-byte integer value). The value must be the
  1128  // number of a previously defined \.[MAPFONT]. This font (or more precisely, the
  1129  // final font that is mapped to that code number, if two \.[MAPFONT] properties
  1130  // happen to specify the same code) will be used in subsequent \.[SETCHAR]
  1131  // instructions until overridden by another \.[SELECTFONT]. The first-specified
  1132  // \.[MAPFONT] is implicitly selected before the first \.[SELECTFONT] in every
  1133  // character's map.
  1134  //
  1135  // \yskip\hang\.[SETCHAR] (one-byte integer value). There must be a character of
  1136  // this number in the currently selected font. (\.[VPtoVF] doesn't check that
  1137  // the character is valid, but \.[VFtoVP] does.) That character is typeset at the
  1138  // current position, and the typesetter moves right by the \.[CHARWD] in
  1139  // that character's \.[TFM] file.
  1140  //
  1141  // \yskip\hang\.[SETRULE] (two real values). The first value specifies height,
  1142  // the second specifies width, in design units. If both height and width are
  1143  // positive, a rule is typeset at the current position. Then the typesetter
  1144  // moves right, by the specified width.
  1145  //
  1146  // \yskip\hang\.[MOVERIGHT], \.[MOVELEFT], \.[MOVEUP], \.[MOVEDOWN] (real
  1147  // value). The typesetter moves its current position
  1148  // by the number of design units specified.
  1149  //
  1150  // \yskip\hang\.[PUSH]. The current typesetter position is remembered, to
  1151  // be restored on a subsequent \.[POP].
  1152  //
  1153  // \yskip\hang\.[POP]. The current typesetter position is reset to where it
  1154  // was on the most recent unmatched \.[PUSH]. The \.[PUSH] and \.[POP]
  1155  // commands in any \.[MAP] must be properly nested like balanced parentheses.
  1156  //
  1157  // \yskip\hang\.[SPECIAL] (string value). The subsequent characters, starting
  1158  // with the first nonblank and ending just before the first `\.)' that has no
  1159  // matching `\.(', are interpreted according to local conventions with the
  1160  // same system-dependent meaning as a `special' (\\[xxx]) command
  1161  // in a \.[DVI] file.
  1162  //
  1163  // \yskip\hang\.[SPECIALHEX] (hexadecimal string value). The subsequent
  1164  // nonblank characters before the next `\.)' must consist entirely of
  1165  // hexadecimal digits, and they must contain an even number of such digits.
  1166  // Each pair of hex digits specifies a byte, and this string of bytes is
  1167  // treated just as the value of a \.[SPECIAL]. (This convention permits
  1168  // arbitrary byte strings to be represented in an ordinary text file.)
  1169  
  1170  // 19.
  1171  
  1172  // tangle:pos vptovf.web:588:68:
  1173  
  1174  // Virtual font mapping is a recursive process, like macro expansion.
  1175  // Thus, a \.[MAPFONT] might
  1176  // specify another virtual font, whose characters are themselves mapped to
  1177  // other fonts. As an example of this possibility, consider the
  1178  // following curious file called \.[recurse.vpl], which defines a
  1179  // virtual font that is self-contained and self-referential:
  1180  // $$\vbox[\halign[\.[#]\cr
  1181  // (VTITLE Example of recursion)\cr
  1182  // (MAPFONT D 0 (FONTNAME recurse)(FONTAT D 2))\cr
  1183  // (CHARACTER C A (CHARWD D 1)(CHARHT D 1)(MAP (SETRULE D 1 D 1)))\cr
  1184  // (CHARACTER C B (CHARWD D 2)(CHARHT D 2)(MAP (SETCHAR C A)))\cr
  1185  // (CHARACTER C C (CHARWD D 4)(CHARHT D 4)(MAP (SETCHAR C B)))\cr
  1186  // ]]$$
  1187  // The design size is 10 points (the default), hence the character \.A
  1188  // in font \.[recurse] is a $10\times10$ point black square. Character \.B
  1189  // is typeset as character \.A in \.[recurse] [scaled] [2000], hence it
  1190  // is a $20\times20$ point black square. And character \.C is typeset as
  1191  // character \.[B] in \.[recurse] [scaled] [2000], hence its size is
  1192  // $40\times40$.
  1193  //
  1194  // Users are responsible for making sure that infinite recursion doesn't happen.
  1195  
  1196  // 20.
  1197  
  1198  // tangle:pos vptovf.web:610:78:
  1199  
  1200  // So that is what \.[VPL] files hold. From these rules,
  1201  // you can guess (correctly) that \.[VPtoVF] operates in four main stages.
  1202  // First it assigns the default values to all properties; then it scans
  1203  // through the \.[VPL] file, changing property values as new ones are seen; then
  1204  // it checks the information and corrects any problems; and finally it outputs
  1205  // the \.[VF] and \.[TFM] files.
  1206  
  1207  // 33.
  1208  
  1209  // tangle:pos vptovf.web:742:18:
  1210  
  1211  // The following routine prints an error message and an indication of
  1212  // where the error was detected. The error message should not include any
  1213  // final punctuation, since this procedure supplies its own.
  1214  func (prg *prg) showErrorContext() { // prints the current scanner location
  1215  	var (
  1216  		k /* 0..bufSize */ byte // an index into |buffer|
  1217  	)
  1218  	prg.stdout.Writeln(" (line ", prg.line, knuth.WriteWidth(1), ").")
  1219  	if !prg.leftLn {
  1220  		prg.stdout.Write("...")
  1221  	}
  1222  	for ii := int32(1); ii <= int32(prg.loc); ii++ {
  1223  		k = byte(ii)
  1224  		_ = k
  1225  		prg.stdout.Write(string(rune(prg.buffer[k-1])))
  1226  	} // print the characters already scanned
  1227  	prg.stdout.Writeln(" ")
  1228  	if !prg.leftLn {
  1229  		prg.stdout.Write("   ")
  1230  	}
  1231  	for ii := int32(1); ii <= int32(prg.loc); ii++ {
  1232  		k = byte(ii)
  1233  		_ = k
  1234  		prg.stdout.Write(" ")
  1235  	} // space out the second line
  1236  	for ii := int32(prg.loc) + 1; ii <= int32(prg.limit); ii++ {
  1237  		k = byte(ii)
  1238  		_ = k
  1239  		prg.stdout.Write(string(rune(prg.buffer[k-1])))
  1240  	} // print the characters yet unseen
  1241  	if prg.rightLn {
  1242  		prg.stdout.Writeln(" ")
  1243  	} else {
  1244  		prg.stdout.Writeln("...")
  1245  	}
  1246  	prg.charsOnLine = 0
  1247  }
  1248  
  1249  // 34.
  1250  
  1251  // tangle:pos vptovf.web:763:5:
  1252  
  1253  // Here is a procedure that does the right thing when we are done
  1254  // reading the present contents of the buffer. It keeps |buffer[buf_size]|
  1255  // empty, in order to avoid range errors on certain \PASCAL\ compilers.
  1256  //
  1257  // An infinite sequence of right parentheses is placed at the end of the
  1258  // file, so that the program is sure to get out of whatever level of nesting
  1259  // it is in.
  1260  //
  1261  // On some systems it is desirable to modify this code so that tab marks
  1262  // in the buffer are replaced by blank spaces. (Simply setting
  1263  // |xord[chr(@'11)]:=" "| would not work; for example, two-line
  1264  // error messages would not come out properly aligned.)
  1265  // \xref[system dependencies]
  1266  func (prg *prg) fillBuffer() {
  1267  	prg.leftLn = prg.rightLn
  1268  	prg.limit = 0
  1269  	prg.loc = 0
  1270  	if prg.leftLn {
  1271  		if prg.line > 0 {
  1272  			prg.vplFile.Readln()
  1273  		}
  1274  		prg.line = prg.line + 1
  1275  	}
  1276  	if prg.vplFile.EOF() {
  1277  		prg.limit = 1
  1278  		prg.buffer[1-1] = ')'
  1279  		prg.rightLn = false
  1280  		prg.inputHasEnded = true
  1281  	} else {
  1282  		for int32(prg.limit) < bufSize-2 && !prg.vplFile.EOLN() {
  1283  			prg.limit = byte(int32(prg.limit) + 1)
  1284  			prg.vplFile.Read(&prg.buffer[prg.limit-1])
  1285  		}
  1286  		prg.buffer[int32(prg.limit)+1-1] = ' '
  1287  		prg.rightLn = prg.vplFile.EOLN()
  1288  		if prg.rightLn {
  1289  			prg.limit = byte(int32(prg.limit) + 1)
  1290  			prg.buffer[int32(prg.limit)+1-1] = ' '
  1291  		}
  1292  		if prg.leftLn {
  1293  			for int32(prg.loc) < int32(prg.limit) && int32(prg.buffer[int32(prg.loc)+1-1]) == ' ' {
  1294  				prg.loc = byte(int32(prg.loc) + 1)
  1295  			}
  1296  			if int32(prg.loc) < int32(prg.limit) {
  1297  				if prg.level == 0 {
  1298  					if int32(prg.loc) == 0 {
  1299  						prg.goodIndent = prg.goodIndent + 1
  1300  					} else {
  1301  						if prg.goodIndent >= 10 {
  1302  							if int32(prg.charsOnLine) > 0 {
  1303  								prg.stdout.Writeln(" ")
  1304  							}
  1305  							prg.stdout.Write("Warning: Indented line occurred at level zero")
  1306  							prg.showErrorContext()
  1307  						}
  1308  						prg.goodIndent = 0
  1309  						prg.indent = 0
  1310  					}
  1311  				} else if prg.indent == 0 {
  1312  					if int32(prg.loc)%prg.level == 0 {
  1313  						prg.indent = int32(prg.loc) / prg.level
  1314  						prg.goodIndent = 1
  1315  					} else {
  1316  						prg.goodIndent = 0
  1317  					}
  1318  				} else if prg.indent*prg.level == int32(prg.loc) {
  1319  					prg.goodIndent = prg.goodIndent + 1
  1320  				} else {
  1321  					if prg.goodIndent >= 10 {
  1322  						if int32(prg.charsOnLine) > 0 {
  1323  							prg.stdout.Writeln(" ")
  1324  						}
  1325  						prg.stdout.Write("Warning: Inconsistent indentation; ",
  1326  							// \xref[Warning: Inconsistent indentation...]
  1327  							"you are at parenthesis level ", prg.level, knuth.WriteWidth(1))
  1328  						prg.showErrorContext()
  1329  					}
  1330  					prg.goodIndent = 0
  1331  					prg.indent = 0
  1332  				}
  1333  			}
  1334  		}
  1335  	}
  1336  }
  1337  
  1338  // 37.
  1339  
  1340  // tangle:pos vptovf.web:831:48:
  1341  
  1342  // Here is a procedure that sets |cur_char| to an ASCII code for the
  1343  // next character of input, if that character is a letter or digit or slash
  1344  // or \.>. Otherwise
  1345  // it sets |cur_char:=" "|, and the input system will be poised to reread the
  1346  // character that was rejected, whether or not it was a space.
  1347  // Lower case letters are converted to upper case.
  1348  func (prg *prg) getKeywordChar() {
  1349  	for int32(prg.loc) == int32(prg.limit) && !prg.rightLn {
  1350  		prg.fillBuffer()
  1351  	}
  1352  	if int32(prg.loc) == int32(prg.limit) {
  1353  		prg.curChar = ' '
  1354  	} else {
  1355  		prg.curChar = prg.xord[prg.buffer[int32(prg.loc)+1-1]]
  1356  		if int32(prg.curChar) >= 'a' {
  1357  			prg.curChar = byte(int32(prg.curChar) - 040)
  1358  		}
  1359  		if int32(prg.curChar) >= '0' && int32(prg.curChar) <= '9' {
  1360  			prg.loc = byte(int32(prg.loc) + 1)
  1361  		} else if int32(prg.curChar) >= 'A' && int32(prg.curChar) <= 'Z' {
  1362  			prg.loc = byte(int32(prg.loc) + 1)
  1363  		} else if int32(prg.curChar) == '/' {
  1364  			prg.loc = byte(int32(prg.loc) + 1)
  1365  		} else if int32(prg.curChar) == '>' {
  1366  			prg.loc = byte(int32(prg.loc) + 1)
  1367  		} else {
  1368  			prg.curChar = ' '
  1369  		}
  1370  	}
  1371  }
  1372  
  1373  // 38.
  1374  
  1375  // tangle:pos vptovf.web:851:5:
  1376  
  1377  // The following procedure sets |cur_char| to the next character code,
  1378  // and converts lower case to upper case. If the character is a left or
  1379  // right parenthesis, it will not be ``digested''; the character will
  1380  // be read again and again, until the calling routine does something
  1381  // like `|incr(loc)|' to get past it. Such special treatment of parentheses
  1382  // insures that the structural information they contain won't be lost in
  1383  // the midst of other error recovery operations.
  1384  func (prg *prg) getNext() {
  1385  	for int32(prg.loc) == int32(prg.limit) {
  1386  		prg.fillBuffer()
  1387  	}
  1388  	prg.loc = byte(int32(prg.loc) + 1)
  1389  	prg.curChar = prg.xord[prg.buffer[prg.loc-1]]
  1390  	if int32(prg.curChar) >= 'a' {
  1391  		if int32(prg.curChar) <= 'z' {
  1392  			prg.curChar = byte(int32(prg.curChar) - 040)
  1393  		} else {
  1394  			if int32(prg.curChar) == invalidCode {
  1395  				{
  1396  					if int32(prg.charsOnLine) > 0 {
  1397  						prg.stdout.Writeln(" ")
  1398  					}
  1399  					prg.stdout.Write("Illegal character in the file")
  1400  					prg.showErrorContext()
  1401  				}
  1402  				// \xref[Illegal character...]
  1403  				prg.curChar = '?'
  1404  			}
  1405  		}
  1406  	} else if int32(prg.curChar) <= ')' && int32(prg.curChar) >= '(' {
  1407  		prg.loc = byte(int32(prg.loc) - 1)
  1408  	}
  1409  }
  1410  
  1411  // 39.
  1412  
  1413  // tangle:pos vptovf.web:876:5:
  1414  
  1415  // Here's a procedure that scans a hexadecimal digit or a right parenthesis.
  1416  func (prg *prg) getHex() (r byte) {
  1417  	var (
  1418  		a int32 // partial result
  1419  	)
  1420  	for {
  1421  		prg.getNext()
  1422  		if int32(prg.curChar) != ' ' {
  1423  			break
  1424  		}
  1425  	}
  1426  	a = int32(prg.curChar) - ')'
  1427  	if a > 0 {
  1428  		a = int32(prg.curChar) - '0'
  1429  		if int32(prg.curChar) > '9' {
  1430  			if int32(prg.curChar) < 'A' {
  1431  				a = -1
  1432  			} else {
  1433  				a = int32(prg.curChar) - 'A' + 10
  1434  			}
  1435  		}
  1436  	}
  1437  	if a < 0 || a > 15 {
  1438  		{
  1439  			if int32(prg.charsOnLine) > 0 {
  1440  				prg.stdout.Writeln(" ")
  1441  			}
  1442  			prg.stdout.Write("Illegal hexadecimal digit")
  1443  			prg.showErrorContext()
  1444  		}
  1445  		r = 0
  1446  		// \xref[Illegal hexadecimal digit]
  1447  	} else {
  1448  		r = byte(a)
  1449  	}
  1450  	return r
  1451  }
  1452  
  1453  // 40.
  1454  
  1455  // tangle:pos vptovf.web:895:5:
  1456  
  1457  // The next procedure is used to ignore the text of a comment, or to pass over
  1458  // erroneous material. As such, it has the privilege of passing parentheses.
  1459  // It stops after the first right parenthesis that drops the level below
  1460  // the level in force when the procedure was called.
  1461  func (prg *prg) skipToEndOfItem() {
  1462  	var (
  1463  		l int32 // initial value of |level|
  1464  	)
  1465  	l = prg.level
  1466  	for prg.level >= l {
  1467  		for int32(prg.loc) == int32(prg.limit) {
  1468  			prg.fillBuffer()
  1469  		}
  1470  		prg.loc = byte(int32(prg.loc) + 1)
  1471  		if int32(prg.buffer[prg.loc-1]) == ')' {
  1472  			prg.level = prg.level - 1
  1473  		} else if int32(prg.buffer[prg.loc-1]) == '(' {
  1474  			prg.level = prg.level + 1
  1475  		}
  1476  	}
  1477  	if prg.inputHasEnded {
  1478  		if int32(prg.charsOnLine) > 0 {
  1479  			prg.stdout.Writeln(" ")
  1480  		}
  1481  		prg.stdout.Write("File ended unexpectedly: No closing \")\"")
  1482  		prg.showErrorContext()
  1483  	}
  1484  	// \xref[File ended unexpectedly...]
  1485  	prg.curChar = ' ' // now the right parenthesis has been read and digested
  1486  }
  1487  
  1488  // 41.
  1489  
  1490  // tangle:pos vptovf.web:914:5:
  1491  
  1492  // A similar procedure copies the bytes remaining in an item. The copied bytes
  1493  // go into an array |vf| that we'll declare later. Leading blanks are ignored.
  1494  func (prg *prg) copyToEndOfItem() {
  1495  	var (
  1496  		l             int32 // initial value of |level|
  1497  		nonblankFound bool  // have we seen a nonblank character yet?
  1498  	)
  1499  	l = prg.level
  1500  	nonblankFound = false
  1501  	for true {
  1502  		for int32(prg.loc) == int32(prg.limit) {
  1503  			prg.fillBuffer()
  1504  		}
  1505  		if int32(prg.buffer[int32(prg.loc)+1-1]) == ')' {
  1506  			if prg.level == l {
  1507  				goto _30
  1508  			} else {
  1509  				prg.level = prg.level - 1
  1510  			}
  1511  		}
  1512  		prg.loc = byte(int32(prg.loc) + 1)
  1513  		if int32(prg.buffer[prg.loc-1]) == '(' {
  1514  			prg.level = prg.level + 1
  1515  		}
  1516  		if int32(prg.buffer[prg.loc-1]) != ' ' {
  1517  			nonblankFound = true
  1518  		}
  1519  		if nonblankFound {
  1520  			if int32(prg.xord[prg.buffer[prg.loc-1]]) == invalidCode {
  1521  				{
  1522  					if int32(prg.charsOnLine) > 0 {
  1523  						prg.stdout.Writeln(" ")
  1524  					}
  1525  					prg.stdout.Write("Illegal character in the file")
  1526  					prg.showErrorContext()
  1527  				}
  1528  				// \xref[Illegal character...]
  1529  				{
  1530  					prg.vf[prg.vfPtr] = '?'
  1531  					if int32(prg.vfPtr) == vfSize {
  1532  						if int32(prg.charsOnLine) > 0 {
  1533  							prg.stdout.Writeln(" ")
  1534  						}
  1535  						prg.stdout.Write("I'm out of memory---increase my vfsize!")
  1536  						prg.showErrorContext()
  1537  					} else {
  1538  						prg.vfPtr = uint16(int32(prg.vfPtr) + 1)
  1539  					}
  1540  				}
  1541  			} else {
  1542  				prg.vf[prg.vfPtr] = prg.xord[prg.buffer[prg.loc-1]]
  1543  				if int32(prg.vfPtr) == vfSize {
  1544  					if int32(prg.charsOnLine) > 0 {
  1545  						prg.stdout.Writeln(" ")
  1546  					}
  1547  					prg.stdout.Write("I'm out of memory---increase my vfsize!")
  1548  					prg.showErrorContext()
  1549  				} else {
  1550  					prg.vfPtr = uint16(int32(prg.vfPtr) + 1)
  1551  				}
  1552  			}
  1553  		}
  1554  	}
  1555  _30:
  1556  }
  1557  
  1558  // 42.
  1559  
  1560  // tangle:pos vptovf.web:946:8:
  1561  
  1562  // Sometimes we merely want to skip past characters in the input until we
  1563  // reach a left or a right parenthesis. For example, we do this whenever we
  1564  // have finished scanning a property value and we hope that a right parenthesis
  1565  // is next (except for possible blank spaces).
  1566  
  1567  // 43.
  1568  
  1569  // tangle:pos vptovf.web:957:69:
  1570  
  1571  // After a property value has been scanned, we want to move just past the
  1572  // right parenthesis that should come next in the input (except for possible
  1573  // blank spaces).
  1574  func (prg *prg) finishTheProperty() {
  1575  	for int32(prg.curChar) == ' ' {
  1576  		prg.getNext()
  1577  	}
  1578  	if int32(prg.curChar) != ')' {
  1579  		if int32(prg.charsOnLine) > 0 {
  1580  			prg.stdout.Writeln(" ")
  1581  		}
  1582  		prg.stdout.Write("Junk after property value will be ignored")
  1583  		prg.showErrorContext()
  1584  	}
  1585  	// \xref[Junk after property value...]
  1586  	prg.skipToEndOfItem()
  1587  }
  1588  
  1589  // 50.
  1590  
  1591  // tangle:pos vptovf.web:1014:41:
  1592  
  1593  // Since there is no chance of the hash table overflowing, the procedure
  1594  // is very simple. After |lookup| has done its work, |cur_hash| will point
  1595  // to the place where the given name was found, or where it should be inserted.
  1596  func (prg *prg) lookup() { // finds |cur_name| in the dictionary
  1597  	var (
  1598  		k/* 0..longestName */ byte       // index into |cur_name|
  1599  		j/* 0..maxLetters */ uint16      // index into |dictionary|
  1600  		notFound                    bool // clumsy thing necessary to avoid |goto| statement
  1601  	)
  1602  	prg.curHash = prg.curName[1-1]
  1603  	for ii := int32(2); ii <= int32(prg.nameLength); ii++ {
  1604  		k = byte(ii)
  1605  		_ = k
  1606  		prg.curHash = byte((int32(prg.curHash) + int32(prg.curHash) + int32(prg.curName[k-1])) % hashPrime)
  1607  	}
  1608  	notFound = true
  1609  	for notFound {
  1610  		if int32(prg.curHash) == 0 {
  1611  			prg.curHash = byte(hashPrime - 1)
  1612  		} else {
  1613  			prg.curHash = byte(int32(prg.curHash) - 1)
  1614  		}
  1615  		if int32(prg.nhash[prg.curHash]) == 0 {
  1616  			notFound = false
  1617  		} else {
  1618  			j = prg.start[prg.nhash[prg.curHash]-1]
  1619  			if int32(prg.start[int32(prg.nhash[prg.curHash])+1-1]) == int32(j)+int32(prg.nameLength) {
  1620  				notFound = false
  1621  				for ii := int32(1); ii <= int32(prg.nameLength); ii++ {
  1622  					k = byte(ii)
  1623  					_ = k
  1624  					if int32(prg.dictionary[int32(j)+int32(k)-1]) != int32(prg.curName[k-1]) {
  1625  						notFound = true
  1626  					}
  1627  				}
  1628  			}
  1629  		}
  1630  	}
  1631  	prg.namePtr = prg.nhash[prg.curHash]
  1632  }
  1633  
  1634  // 53.
  1635  
  1636  // tangle:pos vptovf.web:1099:61:
  1637  
  1638  // We have to get the keywords into the hash table and into the dictionary in
  1639  // the first place (sigh). The procedure that does this has the desired
  1640  // |equiv| code as a parameter. In order to facilitate \.[WEB] macro writing
  1641  // for the initialization, the keyword being initialized is placed into the
  1642  // last positions of |cur_name|, instead of the first positions.
  1643  func (prg *prg) enterName(v byte) { // |cur_name| goes into the dictionary
  1644  	var (
  1645  		k /* 0..longestName */ byte
  1646  	)
  1647  	for ii := int32(1); ii <= int32(prg.nameLength); ii++ {
  1648  		k = byte(ii)
  1649  		_ = k
  1650  		prg.curName[k-1] = prg.curName[int32(k)+longestName-int32(prg.nameLength)-1]
  1651  	}
  1652  	// now the name has been shifted into the correct position
  1653  	prg.lookup() // this sets |cur_hash| to the proper insertion place
  1654  	prg.nhash[prg.curHash] = prg.startPtr
  1655  	prg.equiv[prg.startPtr] = v
  1656  	for ii := int32(1); ii <= int32(prg.nameLength); ii++ {
  1657  		k = byte(ii)
  1658  		_ = k
  1659  		prg.dictionary[prg.dictPtr] = prg.curName[k-1]
  1660  		prg.dictPtr = uint16(int32(prg.dictPtr) + 1)
  1661  	}
  1662  	prg.startPtr = byte(int32(prg.startPtr) + 1)
  1663  	prg.start[prg.startPtr-1] = prg.dictPtr
  1664  }
  1665  
  1666  // 54.
  1667  
  1668  // tangle:pos vptovf.web:1118:5:
  1669  
  1670  // Here are the macros to load a name of up to 20 letters into the
  1671  // dictionary. For example, the macro |load5| is used for five-letter keywords.
  1672  
  1673  // 58.
  1674  
  1675  // tangle:pos vptovf.web:1269:65:
  1676  
  1677  // When a left parenthesis has been scanned, the following routine
  1678  // is used to interpret the keyword that follows, and to store the
  1679  // equivalent value in |cur_code|.
  1680  func (prg *prg) getName() {
  1681  	prg.loc = byte(int32(prg.loc) + 1)
  1682  	prg.level = prg.level + 1 // pass the left parenthesis
  1683  	prg.curChar = ' '
  1684  	for int32(prg.curChar) == ' ' {
  1685  		prg.getNext()
  1686  	}
  1687  	if int32(prg.curChar) > ')' || int32(prg.curChar) < '(' {
  1688  		prg.loc = byte(int32(prg.loc) - 1)
  1689  	} // back up one character
  1690  	prg.nameLength = 0
  1691  	prg.getKeywordChar() // prepare to scan the name
  1692  	for int32(prg.curChar) != ' ' {
  1693  		if int32(prg.nameLength) == longestName {
  1694  			prg.curName[1-1] = 'X'
  1695  		} else {
  1696  			prg.nameLength = byte(int32(prg.nameLength) + 1)
  1697  		}
  1698  		prg.curName[prg.nameLength-1] = prg.curChar
  1699  		prg.getKeywordChar()
  1700  	}
  1701  	prg.lookup()
  1702  	if int32(prg.namePtr) == 0 {
  1703  		if int32(prg.charsOnLine) > 0 {
  1704  			prg.stdout.Writeln(" ")
  1705  		}
  1706  		prg.stdout.Write("Sorry, I don't know that property name")
  1707  		prg.showErrorContext()
  1708  	}
  1709  	// \xref[Sorry, I don't know...]
  1710  	prg.curCode = prg.equiv[prg.namePtr]
  1711  }
  1712  
  1713  // 59. Scanning numeric data
  1714  
  1715  // tangle:pos vptovf.web:1293:22:
  1716  
  1717  // The next thing we need is a trio of subroutines to read the one-byte,
  1718  // four-byte, and real numbers that may appear as property values.
  1719  // These subroutines are careful to stick to numbers between $-2^[31]$
  1720  // and $2^[31]-1$, inclusive, so that a computer with two's complement
  1721  // 32-bit arithmetic will not be interrupted by overflow.
  1722  
  1723  // 60.
  1724  
  1725  // tangle:pos vptovf.web:1298:55:
  1726  
  1727  // The first number scanner, which returns a one-byte value, surely has
  1728  // no problems of arithmetic overflow.
  1729  func (prg *prg) getByte() (r byte) { // scans a one-byte property value
  1730  	var (
  1731  		acc int32     // an accumulator
  1732  		t   asciiCode // the type of value to be scanned
  1733  	)
  1734  	for {
  1735  		prg.getNext()
  1736  		if int32(prg.curChar) != ' ' {
  1737  			break
  1738  		}
  1739  	} // skip the blanks before the type code
  1740  	t = prg.curChar
  1741  	acc = 0
  1742  	for {
  1743  		prg.getNext()
  1744  		if int32(prg.curChar) != ' ' {
  1745  			break
  1746  		}
  1747  	} // skip the blanks after the type code
  1748  	if int32(t) == 'C' {
  1749  		if int32(prg.curChar) >= 041 && int32(prg.curChar) <= 0176 && (int32(prg.curChar) < '(' || int32(prg.curChar) > ')') {
  1750  			acc = int32(prg.xord[prg.buffer[prg.loc-1]])
  1751  		} else {
  1752  			{
  1753  				if int32(prg.charsOnLine) > 0 {
  1754  					prg.stdout.Writeln(" ")
  1755  				}
  1756  				prg.stdout.Write("\"C\" value must be standard ASCII and not a paren")
  1757  				prg.showErrorContext()
  1758  			}
  1759  			for {
  1760  				prg.getNext()
  1761  				if int32(prg.curChar) == '(' || int32(prg.curChar) == ')' {
  1762  					break
  1763  				}
  1764  			}
  1765  		}
  1766  	} else if int32(t) == 'D' {
  1767  		for int32(prg.curChar) >= '0' && int32(prg.curChar) <= '9' {
  1768  			acc = acc*10 + int32(prg.curChar) - '0'
  1769  			if acc > 255 {
  1770  				{
  1771  					{
  1772  						if int32(prg.charsOnLine) > 0 {
  1773  							prg.stdout.Writeln(" ")
  1774  						}
  1775  						prg.stdout.Write("This value shouldn't exceed 255")
  1776  						prg.showErrorContext()
  1777  					}
  1778  					for {
  1779  						prg.getNext()
  1780  						if int32(prg.curChar) == '(' || int32(prg.curChar) == ')' {
  1781  							break
  1782  						}
  1783  					}
  1784  				}
  1785  				// \xref[This value shouldn't...]
  1786  				acc = 0
  1787  				prg.curChar = ' '
  1788  			} else {
  1789  				prg.getNext()
  1790  			}
  1791  		}
  1792  		{
  1793  			if int32(prg.curChar) > ')' || int32(prg.curChar) < '(' {
  1794  				prg.loc = byte(int32(prg.loc) - 1)
  1795  			}
  1796  		}
  1797  	} else if int32(t) == 'O' {
  1798  		for int32(prg.curChar) >= '0' && int32(prg.curChar) <= '7' {
  1799  			acc = acc*8 + int32(prg.curChar) - '0'
  1800  			if acc > 255 {
  1801  				{
  1802  					{
  1803  						if int32(prg.charsOnLine) > 0 {
  1804  							prg.stdout.Writeln(" ")
  1805  						}
  1806  						prg.stdout.Write("This value shouldn't exceed '377")
  1807  						prg.showErrorContext()
  1808  					}
  1809  					for {
  1810  						prg.getNext()
  1811  						if int32(prg.curChar) == '(' || int32(prg.curChar) == ')' {
  1812  							break
  1813  						}
  1814  					}
  1815  				}
  1816  				// \xref[This value shouldn't...]
  1817  				acc = 0
  1818  				prg.curChar = ' '
  1819  			} else {
  1820  				prg.getNext()
  1821  			}
  1822  		}
  1823  		{
  1824  			if int32(prg.curChar) > ')' || int32(prg.curChar) < '(' {
  1825  				prg.loc = byte(int32(prg.loc) - 1)
  1826  			}
  1827  		}
  1828  	} else if int32(t) == 'H' {
  1829  		for int32(prg.curChar) >= '0' && int32(prg.curChar) <= '9' || int32(prg.curChar) >= 'A' && int32(prg.curChar) <= 'F' {
  1830  			if int32(prg.curChar) >= 'A' {
  1831  				prg.curChar = byte(int32(prg.curChar) + '0' + 10 - 'A')
  1832  			}
  1833  			acc = acc*16 + int32(prg.curChar) - '0'
  1834  			if acc > 255 {
  1835  				{
  1836  					{
  1837  						if int32(prg.charsOnLine) > 0 {
  1838  							prg.stdout.Writeln(" ")
  1839  						}
  1840  						prg.stdout.Write("This value shouldn't exceed \"FF")
  1841  						prg.showErrorContext()
  1842  					}
  1843  					for {
  1844  						prg.getNext()
  1845  						if int32(prg.curChar) == '(' || int32(prg.curChar) == ')' {
  1846  							break
  1847  						}
  1848  					}
  1849  				}
  1850  				// \xref[This value shouldn't...]
  1851  				acc = 0
  1852  				prg.curChar = ' '
  1853  			} else {
  1854  				prg.getNext()
  1855  			}
  1856  		}
  1857  		{
  1858  			if int32(prg.curChar) > ')' || int32(prg.curChar) < '(' {
  1859  				prg.loc = byte(int32(prg.loc) - 1)
  1860  			}
  1861  		}
  1862  	} else if int32(t) == 'F' {
  1863  		if int32(prg.curChar) == 'B' {
  1864  			acc = 2
  1865  		} else if int32(prg.curChar) == 'L' {
  1866  			acc = 4
  1867  		} else if int32(prg.curChar) != 'M' {
  1868  			acc = 18
  1869  		}
  1870  		prg.getNext()
  1871  		if int32(prg.curChar) == 'I' {
  1872  			acc = acc + 1
  1873  		} else if int32(prg.curChar) != 'R' {
  1874  			acc = 18
  1875  		}
  1876  		prg.getNext()
  1877  		if int32(prg.curChar) == 'C' {
  1878  			acc = acc + 6
  1879  		} else if int32(prg.curChar) == 'E' {
  1880  			acc = acc + 12
  1881  		} else if int32(prg.curChar) != 'R' {
  1882  			acc = 18
  1883  		}
  1884  		if acc >= 18 {
  1885  			{
  1886  				{
  1887  					if int32(prg.charsOnLine) > 0 {
  1888  						prg.stdout.Writeln(" ")
  1889  					}
  1890  					prg.stdout.Write("Illegal face code, I changed it to MRR")
  1891  					prg.showErrorContext()
  1892  				}
  1893  				for {
  1894  					prg.getNext()
  1895  					if int32(prg.curChar) == '(' || int32(prg.curChar) == ')' {
  1896  						break
  1897  					}
  1898  				}
  1899  			}
  1900  			// \xref[Illegal face code...]
  1901  			acc = 0
  1902  		}
  1903  	} else {
  1904  		{
  1905  			if int32(prg.charsOnLine) > 0 {
  1906  				prg.stdout.Writeln(" ")
  1907  			}
  1908  			prg.stdout.Write("You need \"C\" or \"D\" or \"O\" or \"H\" or \"F\" here")
  1909  			prg.showErrorContext()
  1910  		}
  1911  		for {
  1912  			prg.getNext()
  1913  			if int32(prg.curChar) == '(' || int32(prg.curChar) == ')' {
  1914  				break
  1915  			}
  1916  		}
  1917  	}
  1918  	// \xref[You need "C" or "D" ...here]
  1919  	prg.curChar = ' '
  1920  	r = byte(acc)
  1921  	return r
  1922  }
  1923  
  1924  // 69.
  1925  
  1926  // tangle:pos vptovf.web:1406:72:
  1927  
  1928  // Since the |get_four_bytes| routine is used very infrequently, no attempt
  1929  // has been made to make it fast; we only want it to work.
  1930  func (prg *prg) getFourBytes() { // scans an unsigned constant and sets |four_bytes|
  1931  	var (
  1932  		c  int32 // local two-byte accumulator
  1933  		r1 int32 // radix
  1934  	)
  1935  	for {
  1936  		prg.getNext()
  1937  		if int32(prg.curChar) != ' ' {
  1938  			break
  1939  		}
  1940  	} // skip the blanks before the type code
  1941  	r1 = 0
  1942  	prg.curBytes = prg.zeroBytes // start with the accumulator zero
  1943  	if int32(prg.curChar) == 'H' {
  1944  		r1 = 16
  1945  	} else if int32(prg.curChar) == 'O' {
  1946  		r1 = 8
  1947  	} else if int32(prg.curChar) == 'D' {
  1948  		r1 = 10
  1949  	} else {
  1950  		{
  1951  			if int32(prg.charsOnLine) > 0 {
  1952  				prg.stdout.Writeln(" ")
  1953  			}
  1954  			prg.stdout.Write("Decimal (\"D\"), octal (\"O\"), or hex (\"H\") value needed here")
  1955  			prg.showErrorContext()
  1956  		}
  1957  		for {
  1958  			prg.getNext()
  1959  			if int32(prg.curChar) == '(' || int32(prg.curChar) == ')' {
  1960  				break
  1961  			}
  1962  		}
  1963  	}
  1964  	// \xref[Decimal ("D"), octal ("O"), or hex...]
  1965  	if r1 > 0 {
  1966  		for {
  1967  			prg.getNext()
  1968  			if int32(prg.curChar) != ' ' {
  1969  				break
  1970  			}
  1971  		} // skip the blanks after the type code
  1972  		for int32(prg.curChar) >= '0' && int32(prg.curChar) <= '9' || int32(prg.curChar) >= 'A' && int32(prg.curChar) <= 'F' {
  1973  
  1974  			// Multiply by |r|, add |cur_char-"0"|, and |get_next|
  1975  			if int32(prg.curChar) >= 'A' {
  1976  				prg.curChar = byte(int32(prg.curChar) + '0' + 10 - 'A')
  1977  			}
  1978  			if int32(prg.curChar) >= '0'+r1 {
  1979  				{
  1980  					if int32(prg.charsOnLine) > 0 {
  1981  						prg.stdout.Writeln(" ")
  1982  					}
  1983  					prg.stdout.Write("Illegal digit")
  1984  					prg.showErrorContext()
  1985  				}
  1986  				for {
  1987  					prg.getNext()
  1988  					if int32(prg.curChar) == '(' || int32(prg.curChar) == ')' {
  1989  						break
  1990  					}
  1991  				}
  1992  			} else {
  1993  				c = int32(prg.curBytes.b3)*r1 + int32(prg.curChar) - '0'
  1994  				prg.curBytes.b3 = byte(c % 256)
  1995  
  1996  				c = int32(prg.curBytes.b2)*r1 + c/256
  1997  				prg.curBytes.b2 = byte(c % 256)
  1998  
  1999  				c = int32(prg.curBytes.b1)*r1 + c/256
  2000  				prg.curBytes.b1 = byte(c % 256)
  2001  
  2002  				c = int32(prg.curBytes.b0)*r1 + c/256
  2003  				if c < 256 {
  2004  					prg.curBytes.b0 = byte(c)
  2005  				} else {
  2006  					prg.curBytes = prg.zeroBytes
  2007  					if r1 == 8 {
  2008  						{
  2009  							if int32(prg.charsOnLine) > 0 {
  2010  								prg.stdout.Writeln(" ")
  2011  							}
  2012  							prg.stdout.Write("Sorry, the maximum octal value is O 37777777777")
  2013  							prg.showErrorContext()
  2014  						}
  2015  						for {
  2016  							prg.getNext()
  2017  							if int32(prg.curChar) == '(' || int32(prg.curChar) == ')' {
  2018  								break
  2019  							}
  2020  						}
  2021  					} else if r1 == 10 {
  2022  						{
  2023  							if int32(prg.charsOnLine) > 0 {
  2024  								prg.stdout.Writeln(" ")
  2025  							}
  2026  							prg.stdout.Write("Sorry, the maximum decimal value is D 4294967295")
  2027  							prg.showErrorContext()
  2028  						}
  2029  						for {
  2030  							prg.getNext()
  2031  							if int32(prg.curChar) == '(' || int32(prg.curChar) == ')' {
  2032  								break
  2033  							}
  2034  						}
  2035  					} else {
  2036  						{
  2037  							if int32(prg.charsOnLine) > 0 {
  2038  								prg.stdout.Writeln(" ")
  2039  							}
  2040  							prg.stdout.Write("Sorry, the maximum hex value is H FFFFFFFF")
  2041  							prg.showErrorContext()
  2042  						}
  2043  						for {
  2044  							prg.getNext()
  2045  							if int32(prg.curChar) == '(' || int32(prg.curChar) == ')' {
  2046  								break
  2047  							}
  2048  						}
  2049  					}
  2050  				}
  2051  				prg.getNext()
  2052  			}
  2053  		}
  2054  	}
  2055  }
  2056  
  2057  // 72.
  2058  
  2059  // tangle:pos vptovf.web:1461:67:
  2060  
  2061  // When a real value is desired, we might as well treat `\.D' and `\.R'
  2062  // formats as if they were identical.
  2063  func (prg *prg) getFix() (r fixWord) { // scans a real property value
  2064  	var (
  2065  		negative         bool  // was there a minus sign?
  2066  		acc              int32 // an accumulator
  2067  		intPart          int32 // the integer part
  2068  		j/* 0..7 */ byte       // the number of decimal places stored
  2069  	)
  2070  	for {
  2071  		prg.getNext()
  2072  		if int32(prg.curChar) != ' ' {
  2073  			break
  2074  		}
  2075  	} // skip the blanks before the type code
  2076  	negative = false
  2077  	acc = 0 // start with the accumulators zero
  2078  	if int32(prg.curChar) != 'R' && int32(prg.curChar) != 'D' {
  2079  		{
  2080  			if int32(prg.charsOnLine) > 0 {
  2081  				prg.stdout.Writeln(" ")
  2082  			}
  2083  			prg.stdout.Write("An \"R\" or \"D\" value is needed here")
  2084  			prg.showErrorContext()
  2085  		}
  2086  		for {
  2087  			prg.getNext()
  2088  			if int32(prg.curChar) == '(' || int32(prg.curChar) == ')' {
  2089  				break
  2090  			}
  2091  		}
  2092  	} else {
  2093  		for {
  2094  			prg.getNext()
  2095  			if int32(prg.curChar) == '-' {
  2096  				prg.curChar = ' '
  2097  				negative = !negative
  2098  			} else if int32(prg.curChar) == '+' {
  2099  				prg.curChar = ' '
  2100  			}
  2101  			if int32(prg.curChar) != ' ' {
  2102  				break
  2103  			}
  2104  		}
  2105  		for int32(prg.curChar) >= '0' && int32(prg.curChar) <= '9' {
  2106  
  2107  			// Multiply by 10, add |cur_char-"0"|, and |get_next|
  2108  			acc = acc*10 + int32(prg.curChar) - '0'
  2109  			if acc >= 2048 {
  2110  				{
  2111  					{
  2112  						if int32(prg.charsOnLine) > 0 {
  2113  							prg.stdout.Writeln(" ")
  2114  						}
  2115  						prg.stdout.Write("Real constants must be less than 2048")
  2116  						prg.showErrorContext()
  2117  					}
  2118  					for {
  2119  						prg.getNext()
  2120  						if int32(prg.curChar) == '(' || int32(prg.curChar) == ')' {
  2121  							break
  2122  						}
  2123  					}
  2124  				}
  2125  				// \xref[Real constants must be...]
  2126  				acc = 0
  2127  				prg.curChar = ' '
  2128  			} else {
  2129  				prg.getNext()
  2130  			}
  2131  		}
  2132  		intPart = acc
  2133  		acc = 0
  2134  		if int32(prg.curChar) == '.' {
  2135  			j = 0
  2136  			prg.getNext()
  2137  			for int32(prg.curChar) >= '0' && int32(prg.curChar) <= '9' {
  2138  				if int32(j) < 7 {
  2139  					j = byte(int32(j) + 1)
  2140  					prg.fractionDigits[j-1] = 010000000 * (int32(prg.curChar) - '0')
  2141  				}
  2142  				prg.getNext()
  2143  			}
  2144  			acc = 0
  2145  			for int32(j) > 0 {
  2146  				acc = prg.fractionDigits[j-1] + acc/10
  2147  				j = byte(int32(j) - 1)
  2148  			}
  2149  			acc = (acc + 10) / 20
  2150  		}
  2151  		if acc >= 04000000 && intPart == 2047 {
  2152  			{
  2153  				if int32(prg.charsOnLine) > 0 {
  2154  					prg.stdout.Writeln(" ")
  2155  				}
  2156  				prg.stdout.Write("Real constants must be less than 2048")
  2157  				prg.showErrorContext()
  2158  			}
  2159  			for {
  2160  				prg.getNext()
  2161  				if int32(prg.curChar) == '(' || int32(prg.curChar) == ')' {
  2162  					break
  2163  				}
  2164  			}
  2165  		} else {
  2166  			acc = intPart*04000000 + acc
  2167  		}
  2168  	}
  2169  	if negative {
  2170  		r = -acc
  2171  	} else {
  2172  		r = acc
  2173  	}
  2174  	return r
  2175  }
  2176  
  2177  // 85.
  2178  
  2179  // tangle:pos vptovf.web:1680:17:
  2180  
  2181  // As an example of these data structures, let us consider the simple
  2182  // routine that inserts a potentially new element into one of the dimension
  2183  // lists. The first parameter indicates the list head (i.e., |h=width| for
  2184  // the width list, etc.); the second parameter is the value that is to be
  2185  // inserted into the list if it is not already present.  The procedure
  2186  // returns the value of the location where the dimension appears in |memory|.
  2187  // The fact that |memory[0]| is larger than any legal dimension makes the
  2188  // algorithm particularly short.
  2189  //
  2190  // We do have to handle two somewhat subtle situations. A width of zero must be
  2191  // put into the list, so that a zero-width character in the font will not appear
  2192  // to be nonexistent (i.e., so that its |char_wd| index will not be zero), but
  2193  // this does not need to be done for heights, depths, or italic corrections.
  2194  // Furthermore, it is necessary to test for memory overflow even though we
  2195  // have provided room for the maximum number of different dimensions in any
  2196  // legal font, since the \.[VPL] file might foolishly give any number of
  2197  // different sizes to the same character.
  2198  func (prg *prg) sortIn(h pointer, d fixWord) (r pointer) { // inserts into list
  2199  	var (
  2200  		p pointer // the current node of interest
  2201  	)
  2202  	if d == 0 && int32(h) != width {
  2203  		r = 0
  2204  	} else {
  2205  		p = h
  2206  		for d >= prg.memory[prg.link[p]] {
  2207  			p = prg.link[p]
  2208  		}
  2209  		if d == prg.memory[p] && int32(p) != int32(h) {
  2210  			r = p
  2211  		} else if int32(prg.memPtr) == memSize {
  2212  			{
  2213  				if int32(prg.charsOnLine) > 0 {
  2214  					prg.stdout.Writeln(" ")
  2215  				}
  2216  				prg.stdout.Write("Memory overflow: more than 1028 widths, etc")
  2217  				prg.showErrorContext()
  2218  			}
  2219  			// \xref[Memory overflow...]
  2220  			prg.stdout.Writeln("Congratulations! It's hard to make this error.")
  2221  			r = p
  2222  		} else {
  2223  			prg.memPtr = uint16(int32(prg.memPtr) + 1)
  2224  			prg.memory[prg.memPtr] = d
  2225  			prg.link[prg.memPtr] = prg.link[p]
  2226  			prg.link[p] = prg.memPtr
  2227  			prg.memory[h] = prg.memory[h] + 1
  2228  			r = prg.memPtr
  2229  		}
  2230  	}
  2231  	return r
  2232  }
  2233  
  2234  // 87.
  2235  
  2236  // tangle:pos vptovf.web:1733:67:
  2237  
  2238  // Once again we can make good use of the fact that |memory[0]| is ``infinite.''
  2239  func (prg *prg) minCover(h pointer, d fixWord) (r int32) {
  2240  	var (
  2241  		p pointer // the current node of interest
  2242  		l fixWord // the least element covered by the current interval
  2243  		m int32   // the current size of the cover being generated
  2244  	)
  2245  	m = 0
  2246  	p = prg.link[h]
  2247  	prg.nextD = prg.memory[0]
  2248  	for int32(p) != 0 {
  2249  		m = m + 1
  2250  		l = prg.memory[p]
  2251  		for prg.memory[prg.link[p]] <= l+d {
  2252  			p = prg.link[p]
  2253  		}
  2254  		p = prg.link[p]
  2255  		if prg.memory[p]-l < prg.nextD {
  2256  			prg.nextD = prg.memory[p] - l
  2257  		}
  2258  	}
  2259  	r = m
  2260  	return r
  2261  }
  2262  
  2263  // 88.
  2264  
  2265  // tangle:pos vptovf.web:1749:5:
  2266  
  2267  // The following procedure uses |min_cover| to determine the smallest $d$
  2268  // such that a given list can be covered with at most a given number of
  2269  // intervals.
  2270  func (prg *prg) shorten(h pointer, m int32) (r fixWord) { // finds best way to round
  2271  	var (
  2272  		d fixWord // the current trial interval length
  2273  		k int32   // the size of a minimum cover
  2274  	)
  2275  	if prg.memory[h] > m {
  2276  		prg.excess = byte(prg.memory[h] - m)
  2277  		k = prg.minCover(h, fixWord(0))
  2278  		d = prg.nextD // now the answer is at least |d|
  2279  		for {
  2280  			d = d + d
  2281  			k = prg.minCover(h, d)
  2282  			if k <= m {
  2283  				break
  2284  			}
  2285  		} // first we ascend rapidly until finding the range
  2286  		d = d / 2
  2287  		k = prg.minCover(h, d) // now we run through the feasible steps
  2288  		for k > m {
  2289  			d = prg.nextD
  2290  			k = prg.minCover(h, d)
  2291  		}
  2292  		r = d
  2293  	} else {
  2294  		r = 0
  2295  	}
  2296  	return r
  2297  }
  2298  
  2299  // 90.
  2300  
  2301  // tangle:pos vptovf.web:1778:71:
  2302  
  2303  // Here is the procedure that sets the |index| values. It also shortens
  2304  // the list so that there is only one element per covering interval;
  2305  // the remaining elements are the midpoints of their clusters.
  2306  func (prg *prg) setIndices(h pointer, d fixWord) { // reduces and indexes a list
  2307  	var (
  2308  		p pointer // the current node of interest
  2309  		q pointer // trails one step behind |p|
  2310  		m byte    // index number of nodes in the current interval
  2311  		l fixWord // least value in the current interval
  2312  	)
  2313  	q = h
  2314  	p = prg.link[q]
  2315  	m = 0
  2316  	for int32(p) != 0 {
  2317  		m = byte(int32(m) + 1)
  2318  		l = prg.memory[p]
  2319  		prg.index[p] = m
  2320  		for prg.memory[prg.link[p]] <= l+d {
  2321  			p = prg.link[p]
  2322  			prg.index[p] = m
  2323  			prg.excess = byte(int32(prg.excess) - 1)
  2324  			if int32(prg.excess) == 0 {
  2325  				d = 0
  2326  			}
  2327  		}
  2328  		prg.link[q] = p
  2329  		prg.memory[p] = l + (prg.memory[p]-l)/2
  2330  		q = p
  2331  		p = prg.link[p]
  2332  	}
  2333  	prg.memory[h] = int32(m)
  2334  }
  2335  
  2336  // 93.
  2337  
  2338  // tangle:pos vptovf.web:1820:22:
  2339  
  2340  // The |junk_error| routine just referred to is called when something
  2341  // appears in the forbidden area between properties of a property list.
  2342  func (prg *prg) junkError() {
  2343  	{
  2344  		if int32(prg.charsOnLine) > 0 {
  2345  			prg.stdout.Writeln(" ")
  2346  		}
  2347  		prg.stdout.Write("There's junk here that is not in parentheses")
  2348  		prg.showErrorContext()
  2349  	}
  2350  	// \xref[There's junk here...]
  2351  	for {
  2352  		prg.getNext()
  2353  		if int32(prg.curChar) == '(' || int32(prg.curChar) == ')' {
  2354  			break
  2355  		}
  2356  	}
  2357  }
  2358  
  2359  // 96.
  2360  
  2361  // tangle:pos vptovf.web:1870:4:
  2362  
  2363  // The |case| statement just given makes use of three subroutines that we
  2364  // haven't defined yet. The first of these puts a 32-bit octal quantity
  2365  // into four specified bytes of the header block.
  2366  func (prg *prg) readFourBytes(l headerIndex) {
  2367  	prg.getFourBytes()
  2368  	prg.headerBytes[l] = prg.curBytes.b0
  2369  	prg.headerBytes[int32(l)+1] = prg.curBytes.b1
  2370  	prg.headerBytes[int32(l)+2] = prg.curBytes.b2
  2371  	prg.headerBytes[int32(l)+3] = prg.curBytes.b3
  2372  }
  2373  
  2374  // 97.
  2375  
  2376  // tangle:pos vptovf.web:1882:5:
  2377  
  2378  // The second little procedure is used to scan a string and to store it in
  2379  // the ``[\mc BCPL] format'' required by \.[TFM] files. The string is supposed
  2380  // to contain at most |n| bytes, including the first byte (which holds the
  2381  // length of the rest of the string).
  2382  func (prg *prg) readBcpl(l headerIndex, n byte) {
  2383  	var (
  2384  		k headerIndex
  2385  	)
  2386  	k = l
  2387  	for int32(prg.curChar) == ' ' {
  2388  		prg.getNext()
  2389  	}
  2390  	for int32(prg.curChar) != '(' && int32(prg.curChar) != ')' {
  2391  		if int32(k) < int32(l)+int32(n) {
  2392  			k = byte(int32(k) + 1)
  2393  		}
  2394  		if int32(k) < int32(l)+int32(n) {
  2395  			prg.headerBytes[k] = prg.curChar
  2396  		}
  2397  		prg.getNext()
  2398  	}
  2399  	if int32(k) == int32(l)+int32(n) {
  2400  		{
  2401  			if int32(prg.charsOnLine) > 0 {
  2402  				prg.stdout.Writeln(" ")
  2403  			}
  2404  			prg.stdout.Write("String is too long; its first ", int32(n)-1, knuth.WriteWidth(1),
  2405  				// \xref[String is too long...]
  2406  				" characters will be kept")
  2407  			prg.showErrorContext()
  2408  		}
  2409  		k = byte(int32(k) - 1)
  2410  	}
  2411  	prg.headerBytes[l] = byte(int32(k) - int32(l))
  2412  	for int32(k) < int32(l)+int32(n)-1 { // tidy up the remaining bytes by setting them to nulls
  2413  		k = byte(int32(k) + 1)
  2414  		prg.headerBytes[k] = 0
  2415  	}
  2416  }
  2417  
  2418  // 111.
  2419  
  2420  // tangle:pos vptovf.web:2091:4:
  2421  
  2422  // When a character is about to be tagged, we call the following
  2423  // procedure so that an error message is given in case of multiple tags.
  2424  func (prg *prg) checkTag(c byte) {
  2425  	switch prg.charTag[c] {
  2426  	case noTag:
  2427  	case ligTag:
  2428  		if int32(prg.charsOnLine) > 0 {
  2429  			prg.stdout.Writeln(" ")
  2430  		}
  2431  		prg.stdout.Write("This character already appeared in a LIGTABLE LABEL")
  2432  		prg.showErrorContext()
  2433  	// \xref[This character already...]
  2434  	case listTag:
  2435  		if int32(prg.charsOnLine) > 0 {
  2436  			prg.stdout.Writeln(" ")
  2437  		}
  2438  		prg.stdout.Write("This character already has a NEXTLARGER spec")
  2439  		prg.showErrorContext()
  2440  	case extTag:
  2441  		if int32(prg.charsOnLine) > 0 {
  2442  			prg.stdout.Writeln(" ")
  2443  		}
  2444  		prg.stdout.Write("This character already has a VARCHAR spec")
  2445  		prg.showErrorContext()
  2446  	}
  2447  }
  2448  
  2449  // 122. Assembling the mappings
  2450  
  2451  // tangle:pos vptovf.web:2251:24:
  2452  
  2453  // Each \.[MAP] property is a sequence of \.[DVI] instructions, for which
  2454  // we need to know some of the opcodes.
  2455  
  2456  // 124.
  2457  
  2458  // tangle:pos vptovf.web:2285:26:
  2459  
  2460  // The packet is built by straightforward assembly of \.[DVI] instructions.
  2461  // Declare the |vf_fix| procedure
  2462  func (prg *prg) vfFix(opcode byte, x fixWord) {
  2463  	var (
  2464  		negative         bool
  2465  		k/* 0..4 */ byte       // number of bytes to typeset
  2466  		t                int32 // threshold
  2467  	)
  2468  	prg.frozenDu = true
  2469  	if prg.designUnits != 04000000 {
  2470  		x = round(float64(x) / float64(prg.designUnits) * 1048576.0)
  2471  	}
  2472  	if x >= 0 {
  2473  		negative = false
  2474  	} else {
  2475  		negative = true
  2476  		x = -1 - x
  2477  	}
  2478  	if int32(opcode) == 0 {
  2479  		k = 4
  2480  		t = 0100000000
  2481  	} else {
  2482  		t = 127
  2483  		k = 1
  2484  		for x > t {
  2485  			t = 256*t + 255
  2486  			k = byte(int32(k) + 1)
  2487  		}
  2488  		{
  2489  			prg.vf[prg.vfPtr] = byte(int32(opcode) + int32(k) - 1)
  2490  			if int32(prg.vfPtr) == vfSize {
  2491  				if int32(prg.charsOnLine) > 0 {
  2492  					prg.stdout.Writeln(" ")
  2493  				}
  2494  				prg.stdout.Write("I'm out of memory---increase my vfsize!")
  2495  				prg.showErrorContext()
  2496  			} else {
  2497  				prg.vfPtr = uint16(int32(prg.vfPtr) + 1)
  2498  			}
  2499  		}
  2500  		t = t/128 + 1
  2501  	}
  2502  	for {
  2503  		if negative {
  2504  			{
  2505  				prg.vf[prg.vfPtr] = byte(255 - x/t)
  2506  				if int32(prg.vfPtr) == vfSize {
  2507  					if int32(prg.charsOnLine) > 0 {
  2508  						prg.stdout.Writeln(" ")
  2509  					}
  2510  					prg.stdout.Write("I'm out of memory---increase my vfsize!")
  2511  					prg.showErrorContext()
  2512  				} else {
  2513  					prg.vfPtr = uint16(int32(prg.vfPtr) + 1)
  2514  				}
  2515  			}
  2516  			negative = false
  2517  			x = x/t*t + t - 1 - x
  2518  		} else {
  2519  			prg.vf[prg.vfPtr] = byte(x / t % 256)
  2520  			if int32(prg.vfPtr) == vfSize {
  2521  				if int32(prg.charsOnLine) > 0 {
  2522  					prg.stdout.Writeln(" ")
  2523  				}
  2524  				prg.stdout.Write("I'm out of memory---increase my vfsize!")
  2525  				prg.showErrorContext()
  2526  			} else {
  2527  				prg.vfPtr = uint16(int32(prg.vfPtr) + 1)
  2528  			}
  2529  		}
  2530  		k = byte(int32(k) - 1)
  2531  		t = t / 256
  2532  		if int32(k) == 0 {
  2533  			break
  2534  		}
  2535  	}
  2536  }
  2537  
  2538  func (prg *prg) readPacket(c byte) {
  2539  	var (
  2540  		cc                                 byte    // character being typeset
  2541  		x                                  fixWord // movement
  2542  		h, v/* 0..2 */ byte                        // top of |hstack| and |vstack|
  2543  		specialStart/* 0..vfSize */ uint16         // location of |xxx1| command
  2544  		k/* 0..vfSize */ uint16                    // loop index
  2545  	)
  2546  	prg.packetStart[c] = prg.vfPtr
  2547  	prg.stackPtr = 0
  2548  	h = 0
  2549  	v = 0
  2550  	prg.curFont = 0
  2551  	for prg.level == 2 {
  2552  		for int32(prg.curChar) == ' ' {
  2553  			prg.getNext()
  2554  		}
  2555  		if int32(prg.curChar) == '(' {
  2556  			prg.getName()
  2557  			if int32(prg.curCode) == commentCode {
  2558  				prg.skipToEndOfItem()
  2559  			} else if int32(prg.curCode) < selectFontCode || int32(prg.curCode) > specialHexCode {
  2560  				{
  2561  					if int32(prg.charsOnLine) > 0 {
  2562  						prg.stdout.Writeln(" ")
  2563  					}
  2564  					prg.stdout.Write("This property name doesn't belong in a MAP list")
  2565  					prg.showErrorContext()
  2566  				}
  2567  				prg.skipToEndOfItem()
  2568  			} else {
  2569  				switch prg.curCode {
  2570  				case selectFontCode:
  2571  					// Assemble a font selection
  2572  					prg.getFourBytes()
  2573  					prg.fontNumber[prg.fontPtr] = prg.curBytes
  2574  					prg.curFont = 0
  2575  					for int32(prg.fontNumber[prg.curFont].b3) != int32(prg.fontNumber[prg.fontPtr].b3) || int32(prg.fontNumber[prg.curFont].b2) != int32(prg.fontNumber[prg.fontPtr].b2) || int32(prg.fontNumber[prg.curFont].b1) != int32(prg.fontNumber[prg.fontPtr].b1) || int32(prg.fontNumber[prg.curFont].b0) != int32(prg.fontNumber[prg.fontPtr].b0) {
  2576  						prg.curFont = uint16(int32(prg.curFont) + 1)
  2577  					}
  2578  					if int32(prg.curFont) == int32(prg.fontPtr) {
  2579  						if int32(prg.charsOnLine) > 0 {
  2580  							prg.stdout.Writeln(" ")
  2581  						}
  2582  						prg.stdout.Write("Undefined MAPFONT cannot be selected")
  2583  						prg.showErrorContext()
  2584  					} else if int32(prg.curFont) < 64 {
  2585  						prg.vf[prg.vfPtr] = byte(fntNum0 + int32(prg.curFont))
  2586  						if int32(prg.vfPtr) == vfSize {
  2587  							if int32(prg.charsOnLine) > 0 {
  2588  								prg.stdout.Writeln(" ")
  2589  							}
  2590  							prg.stdout.Write("I'm out of memory---increase my vfsize!")
  2591  							prg.showErrorContext()
  2592  						} else {
  2593  							prg.vfPtr = uint16(int32(prg.vfPtr) + 1)
  2594  						}
  2595  					} else {
  2596  						{
  2597  							prg.vf[prg.vfPtr] = byte(fnt1)
  2598  							if int32(prg.vfPtr) == vfSize {
  2599  								if int32(prg.charsOnLine) > 0 {
  2600  									prg.stdout.Writeln(" ")
  2601  								}
  2602  								prg.stdout.Write("I'm out of memory---increase my vfsize!")
  2603  								prg.showErrorContext()
  2604  							} else {
  2605  								prg.vfPtr = uint16(int32(prg.vfPtr) + 1)
  2606  							}
  2607  						}
  2608  						{
  2609  							prg.vf[prg.vfPtr] = byte(prg.curFont)
  2610  							if int32(prg.vfPtr) == vfSize {
  2611  								if int32(prg.charsOnLine) > 0 {
  2612  									prg.stdout.Writeln(" ")
  2613  								}
  2614  								prg.stdout.Write("I'm out of memory---increase my vfsize!")
  2615  								prg.showErrorContext()
  2616  							} else {
  2617  								prg.vfPtr = uint16(int32(prg.vfPtr) + 1)
  2618  							}
  2619  						}
  2620  					}
  2621  
  2622  				case setCharCode:
  2623  					// Assemble a typesetting instruction
  2624  					if int32(prg.curFont) == int32(prg.fontPtr) {
  2625  						if int32(prg.charsOnLine) > 0 {
  2626  							prg.stdout.Writeln(" ")
  2627  						}
  2628  						prg.stdout.Write("Character cannot be typeset in undefined font")
  2629  						prg.showErrorContext()
  2630  					} else {
  2631  						cc = prg.getByte()
  2632  						if int32(cc) >= 128 {
  2633  							prg.vf[prg.vfPtr] = byte(set1)
  2634  							if int32(prg.vfPtr) == vfSize {
  2635  								if int32(prg.charsOnLine) > 0 {
  2636  									prg.stdout.Writeln(" ")
  2637  								}
  2638  								prg.stdout.Write("I'm out of memory---increase my vfsize!")
  2639  								prg.showErrorContext()
  2640  							} else {
  2641  								prg.vfPtr = uint16(int32(prg.vfPtr) + 1)
  2642  							}
  2643  						}
  2644  						{
  2645  							prg.vf[prg.vfPtr] = cc
  2646  							if int32(prg.vfPtr) == vfSize {
  2647  								if int32(prg.charsOnLine) > 0 {
  2648  									prg.stdout.Writeln(" ")
  2649  								}
  2650  								prg.stdout.Write("I'm out of memory---increase my vfsize!")
  2651  								prg.showErrorContext()
  2652  							} else {
  2653  								prg.vfPtr = uint16(int32(prg.vfPtr) + 1)
  2654  							}
  2655  						}
  2656  					}
  2657  
  2658  				case setRuleCode:
  2659  					// Assemble a rulesetting instruction
  2660  					{
  2661  						prg.vf[prg.vfPtr] = byte(setRule)
  2662  						if int32(prg.vfPtr) == vfSize {
  2663  							if int32(prg.charsOnLine) > 0 {
  2664  								prg.stdout.Writeln(" ")
  2665  							}
  2666  							prg.stdout.Write("I'm out of memory---increase my vfsize!")
  2667  							prg.showErrorContext()
  2668  						} else {
  2669  							prg.vfPtr = uint16(int32(prg.vfPtr) + 1)
  2670  						}
  2671  					}
  2672  					prg.vfFix(byte(0), prg.getFix())
  2673  					prg.vfFix(byte(0), prg.getFix())
  2674  
  2675  				case moveRightCode, moveRightCode + 1:
  2676  					// Assemble a horizontal movement
  2677  					if int32(prg.curCode) == moveRightCode {
  2678  						x = prg.getFix()
  2679  					} else {
  2680  						x = -prg.getFix()
  2681  					}
  2682  					if int32(h) == 0 {
  2683  						prg.wstack[prg.stackPtr] = x
  2684  						h = 1
  2685  						prg.vfFix(byte(w1), x)
  2686  					} else if x == prg.wstack[prg.stackPtr] {
  2687  						prg.vf[prg.vfPtr] = byte(w0)
  2688  						if int32(prg.vfPtr) == vfSize {
  2689  							if int32(prg.charsOnLine) > 0 {
  2690  								prg.stdout.Writeln(" ")
  2691  							}
  2692  							prg.stdout.Write("I'm out of memory---increase my vfsize!")
  2693  							prg.showErrorContext()
  2694  						} else {
  2695  							prg.vfPtr = uint16(int32(prg.vfPtr) + 1)
  2696  						}
  2697  					} else if int32(h) == 1 {
  2698  						prg.xstack[prg.stackPtr] = x
  2699  						h = 2
  2700  						prg.vfFix(byte(x1), x)
  2701  					} else if x == prg.xstack[prg.stackPtr] {
  2702  						prg.vf[prg.vfPtr] = byte(x0)
  2703  						if int32(prg.vfPtr) == vfSize {
  2704  							if int32(prg.charsOnLine) > 0 {
  2705  								prg.stdout.Writeln(" ")
  2706  							}
  2707  							prg.stdout.Write("I'm out of memory---increase my vfsize!")
  2708  							prg.showErrorContext()
  2709  						} else {
  2710  							prg.vfPtr = uint16(int32(prg.vfPtr) + 1)
  2711  						}
  2712  					} else {
  2713  						prg.vfFix(byte(right1), x)
  2714  					}
  2715  
  2716  				case moveDownCode, moveDownCode + 1:
  2717  					// Assemble a vertical movement
  2718  					if int32(prg.curCode) == moveDownCode {
  2719  						x = prg.getFix()
  2720  					} else {
  2721  						x = -prg.getFix()
  2722  					}
  2723  					if int32(v) == 0 {
  2724  						prg.ystack[prg.stackPtr] = x
  2725  						v = 1
  2726  						prg.vfFix(byte(y1), x)
  2727  					} else if x == prg.ystack[prg.stackPtr] {
  2728  						prg.vf[prg.vfPtr] = byte(y0)
  2729  						if int32(prg.vfPtr) == vfSize {
  2730  							if int32(prg.charsOnLine) > 0 {
  2731  								prg.stdout.Writeln(" ")
  2732  							}
  2733  							prg.stdout.Write("I'm out of memory---increase my vfsize!")
  2734  							prg.showErrorContext()
  2735  						} else {
  2736  							prg.vfPtr = uint16(int32(prg.vfPtr) + 1)
  2737  						}
  2738  					} else if int32(v) == 1 {
  2739  						prg.zstack[prg.stackPtr] = x
  2740  						v = 2
  2741  						prg.vfFix(byte(z1), x)
  2742  					} else if x == prg.zstack[prg.stackPtr] {
  2743  						prg.vf[prg.vfPtr] = byte(z0)
  2744  						if int32(prg.vfPtr) == vfSize {
  2745  							if int32(prg.charsOnLine) > 0 {
  2746  								prg.stdout.Writeln(" ")
  2747  							}
  2748  							prg.stdout.Write("I'm out of memory---increase my vfsize!")
  2749  							prg.showErrorContext()
  2750  						} else {
  2751  							prg.vfPtr = uint16(int32(prg.vfPtr) + 1)
  2752  						}
  2753  					} else {
  2754  						prg.vfFix(byte(down1), x)
  2755  					}
  2756  
  2757  				case pushCode:
  2758  					// Assemble a stack push
  2759  					if int32(prg.stackPtr) == maxStack {
  2760  						if int32(prg.charsOnLine) > 0 {
  2761  							prg.stdout.Writeln(" ")
  2762  						}
  2763  						prg.stdout.Write("Don't push so much---stack is full!")
  2764  						prg.showErrorContext()
  2765  					} else {
  2766  						{
  2767  							prg.vf[prg.vfPtr] = byte(push)
  2768  							if int32(prg.vfPtr) == vfSize {
  2769  								if int32(prg.charsOnLine) > 0 {
  2770  									prg.stdout.Writeln(" ")
  2771  								}
  2772  								prg.stdout.Write("I'm out of memory---increase my vfsize!")
  2773  								prg.showErrorContext()
  2774  							} else {
  2775  								prg.vfPtr = uint16(int32(prg.vfPtr) + 1)
  2776  							}
  2777  						}
  2778  						prg.hstack[prg.stackPtr] = h
  2779  						prg.vstack[prg.stackPtr] = v
  2780  						prg.stackPtr = byte(int32(prg.stackPtr) + 1)
  2781  						h = 0
  2782  						v = 0
  2783  					}
  2784  
  2785  				case popCode:
  2786  					// Assemble a stack pop
  2787  					if int32(prg.stackPtr) == 0 {
  2788  						if int32(prg.charsOnLine) > 0 {
  2789  							prg.stdout.Writeln(" ")
  2790  						}
  2791  						prg.stdout.Write("Empty stack cannot be popped")
  2792  						prg.showErrorContext()
  2793  					} else {
  2794  						{
  2795  							prg.vf[prg.vfPtr] = byte(pop)
  2796  							if int32(prg.vfPtr) == vfSize {
  2797  								if int32(prg.charsOnLine) > 0 {
  2798  									prg.stdout.Writeln(" ")
  2799  								}
  2800  								prg.stdout.Write("I'm out of memory---increase my vfsize!")
  2801  								prg.showErrorContext()
  2802  							} else {
  2803  								prg.vfPtr = uint16(int32(prg.vfPtr) + 1)
  2804  							}
  2805  						}
  2806  						prg.stackPtr = byte(int32(prg.stackPtr) - 1)
  2807  						h = prg.hstack[prg.stackPtr]
  2808  						v = prg.vstack[prg.stackPtr]
  2809  					}
  2810  
  2811  				case specialCode, specialHexCode:
  2812  					// Assemble a special command
  2813  					{
  2814  						prg.vf[prg.vfPtr] = byte(xxx1)
  2815  						if int32(prg.vfPtr) == vfSize {
  2816  							if int32(prg.charsOnLine) > 0 {
  2817  								prg.stdout.Writeln(" ")
  2818  							}
  2819  							prg.stdout.Write("I'm out of memory---increase my vfsize!")
  2820  							prg.showErrorContext()
  2821  						} else {
  2822  							prg.vfPtr = uint16(int32(prg.vfPtr) + 1)
  2823  						}
  2824  					}
  2825  					{
  2826  						prg.vf[prg.vfPtr] = 0
  2827  						if int32(prg.vfPtr) == vfSize {
  2828  							if int32(prg.charsOnLine) > 0 {
  2829  								prg.stdout.Writeln(" ")
  2830  							}
  2831  							prg.stdout.Write("I'm out of memory---increase my vfsize!")
  2832  							prg.showErrorContext()
  2833  						} else {
  2834  							prg.vfPtr = uint16(int32(prg.vfPtr) + 1)
  2835  						}
  2836  					} // dummy length
  2837  					specialStart = prg.vfPtr
  2838  					if int32(prg.curCode) == specialCode {
  2839  						prg.copyToEndOfItem()
  2840  					} else {
  2841  						for {
  2842  							x = int32(prg.getHex())
  2843  							if int32(prg.curChar) > ')' {
  2844  								prg.vf[prg.vfPtr] = byte(x*16 + int32(prg.getHex()))
  2845  								if int32(prg.vfPtr) == vfSize {
  2846  									if int32(prg.charsOnLine) > 0 {
  2847  										prg.stdout.Writeln(" ")
  2848  									}
  2849  									prg.stdout.Write("I'm out of memory---increase my vfsize!")
  2850  									prg.showErrorContext()
  2851  								} else {
  2852  									prg.vfPtr = uint16(int32(prg.vfPtr) + 1)
  2853  								}
  2854  							}
  2855  							if int32(prg.curChar) <= ')' {
  2856  								break
  2857  							}
  2858  						}
  2859  					}
  2860  					if int32(prg.vfPtr)-int32(specialStart) > 255 {
  2861  						if int32(prg.vfPtr)+3 > vfSize {
  2862  							{
  2863  								if int32(prg.charsOnLine) > 0 {
  2864  									prg.stdout.Writeln(" ")
  2865  								}
  2866  								prg.stdout.Write("Special command being clipped---no room left!")
  2867  								prg.showErrorContext()
  2868  							}
  2869  							// \xref[Special command being clipped...]
  2870  							prg.vfPtr = uint16(int32(specialStart) + 255)
  2871  							prg.vf[int32(specialStart)-1] = 255
  2872  						} else {
  2873  							for ii := int32(prg.vfPtr); ii >= int32(specialStart); ii-- {
  2874  								k = uint16(ii)
  2875  								_ = k
  2876  								prg.vf[int32(k)+3] = prg.vf[k]
  2877  							}
  2878  							x = int32(prg.vfPtr) - int32(specialStart)
  2879  							prg.vfPtr = uint16(int32(prg.vfPtr) + 3)
  2880  							prg.vf[int32(specialStart)-2] = byte(xxx4)
  2881  							prg.vf[int32(specialStart)-1] = byte(x / 0100000000)
  2882  							prg.vf[specialStart] = byte(x / 0200000 % 256)
  2883  							prg.vf[int32(specialStart)+1] = byte(x / 0400 % 256)
  2884  							prg.vf[int32(specialStart)+2] = byte(x % 256)
  2885  						}
  2886  					} else {
  2887  						prg.vf[int32(specialStart)-1] = byte(int32(prg.vfPtr) - int32(specialStart))
  2888  					}
  2889  
  2890  				}
  2891  
  2892  				prg.finishTheProperty()
  2893  			}
  2894  		} else if int32(prg.curChar) == ')' {
  2895  			prg.skipToEndOfItem()
  2896  		} else {
  2897  			prg.junkError()
  2898  		}
  2899  	}
  2900  	for int32(prg.stackPtr) > 0 {
  2901  		{
  2902  			if int32(prg.charsOnLine) > 0 {
  2903  				prg.stdout.Writeln(" ")
  2904  			}
  2905  			prg.stdout.Write("Missing POP supplied")
  2906  			prg.showErrorContext()
  2907  		}
  2908  		// \xref[Missing POP supplied]
  2909  		{
  2910  			prg.vf[prg.vfPtr] = byte(pop)
  2911  			if int32(prg.vfPtr) == vfSize {
  2912  				if int32(prg.charsOnLine) > 0 {
  2913  					prg.stdout.Writeln(" ")
  2914  				}
  2915  				prg.stdout.Write("I'm out of memory---increase my vfsize!")
  2916  				prg.showErrorContext()
  2917  			} else {
  2918  				prg.vfPtr = uint16(int32(prg.vfPtr) + 1)
  2919  			}
  2920  		}
  2921  		prg.stackPtr = byte(int32(prg.stackPtr) - 1)
  2922  	}
  2923  	prg.packetLength[c] = int32(prg.vfPtr) - int32(prg.packetStart[c])
  2924  	{
  2925  		prg.loc = byte(int32(prg.loc) - 1)
  2926  		prg.level = prg.level + 1
  2927  		prg.curChar = ')'
  2928  	}
  2929  }
  2930  
  2931  // 136.
  2932  
  2933  // tangle:pos vptovf.web:2449:6:
  2934  
  2935  // The input routine is now complete except for the following code,
  2936  // which prints a progress report as the file is being read.
  2937  func (prg *prg) printOctal(c byte) {
  2938  	prg.stdout.Write("'", int32(c)/64, knuth.WriteWidth(1), int32(c)/8%8, knuth.WriteWidth(1), int32(c)%8, knuth.WriteWidth(1))
  2939  }
  2940  
  2941  // 146.
  2942  
  2943  // tangle:pos vptovf.web:2579:4:
  2944  
  2945  // It's not trivial to check for infinite loops generated by repeated
  2946  // insertion of ligature characters. But fortunately there is a nice
  2947  // algorithm for such testing, copied here from the program \.[TFtoPL]
  2948  // where it is explained further.
  2949  
  2950  // 150.
  2951  
  2952  // tangle:pos vptovf.web:2630:4:
  2953  
  2954  // The |hash_input| procedure is copied from \.[TFtoPL], but it is made
  2955  // into a boolean function that returns |false| if the ligature command
  2956  // was masked by a previous one.
  2957  func (prg *prg) hashInput(p, c indx) (r bool) { // go here for a quick exit
  2958  	var (
  2959  		cc/* simple..bothZ */ byte       // class of data being entered
  2960  		zz/* 0..255 */ byte              // function value or ligature character being entered
  2961  		y/* 0..255 */ byte               // the character after the cursor
  2962  		key                        int32 // value to be stored in |hash|
  2963  		t                          int32 // temporary register for swapping
  2964  	)
  2965  	if int32(prg.hashPtr) == hashSize {
  2966  		r = false
  2967  		goto _30
  2968  	}
  2969  
  2970  	// Compute the command parameters |y|, |cc|, and |zz|
  2971  	y = prg.ligKern[p].b1
  2972  	t = int32(prg.ligKern[p].b2)
  2973  	cc = byte(simple)
  2974  	zz = prg.ligKern[p].b3
  2975  	if t >= kernFlag {
  2976  		zz = y
  2977  	} else {
  2978  		switch t {
  2979  		case 0, 6: // \.[LIG],\.[/LIG>]
  2980  		case 5, 11:
  2981  			zz = y // \.[LIG/>], \.[/LIG/>>]
  2982  		case 1, 7:
  2983  			cc = byte(leftZ) // \.[LIG/], \.[/LIG/>]
  2984  		case 2:
  2985  			cc = byte(rightZ) // \.[/LIG]
  2986  		case 3:
  2987  			cc = byte(bothZ) // \.[/LIG/]
  2988  		} // there are no other cases
  2989  	}
  2990  	key = 256*int32(c) + int32(y) + 1
  2991  	prg.h = uint16(1009 * key % hashSize)
  2992  	for int32(prg.hash[prg.h]) > 0 {
  2993  		if int32(prg.hash[prg.h]) <= key {
  2994  			if int32(prg.hash[prg.h]) == key {
  2995  				r = false
  2996  				goto _30 // unused ligature command
  2997  			}
  2998  			t = int32(prg.hash[prg.h])
  2999  			prg.hash[prg.h] = uint32(key)
  3000  			key = t // do ordered-hash-table insertion
  3001  			t = int32(prg.class[prg.h])
  3002  			prg.class[prg.h] = cc
  3003  			cc = byte(t) // namely, do a swap
  3004  			t = int32(prg.ligZ[prg.h])
  3005  			prg.ligZ[prg.h] = uint16(zz)
  3006  			zz = byte(t)
  3007  		}
  3008  		if int32(prg.h) > 0 {
  3009  			prg.h = uint16(int32(prg.h) - 1)
  3010  		} else {
  3011  			prg.h = uint16(hashSize)
  3012  		}
  3013  	}
  3014  	prg.hash[prg.h] = uint32(key)
  3015  	prg.class[prg.h] = cc
  3016  	prg.ligZ[prg.h] = uint16(zz)
  3017  	prg.hashPtr = uint16(int32(prg.hashPtr) + 1)
  3018  	prg.hashList[prg.hashPtr] = prg.h
  3019  	r = true
  3020  _30:
  3021  	;
  3022  	return r
  3023  } // \2
  3024  // compute $f$ for arguments known to be in |hash[h]|
  3025  func (prg *prg) eval(x, y indx) (r indx) { // compute $f(x,y)$ with hashtable lookup
  3026  	var (
  3027  		key int32 // value sought in hash table
  3028  	)
  3029  	key = 256*int32(x) + int32(y) + 1
  3030  	prg.h = uint16(1009 * key % hashSize)
  3031  	for int32(prg.hash[prg.h]) > key {
  3032  		if int32(prg.h) > 0 {
  3033  			prg.h = uint16(int32(prg.h) - 1)
  3034  		} else {
  3035  			prg.h = uint16(hashSize)
  3036  		}
  3037  	}
  3038  	if int32(prg.hash[prg.h]) < key {
  3039  		r = y
  3040  	} else {
  3041  		r = prg.f(prg.h, x, y)
  3042  	}
  3043  	return r
  3044  }
  3045  
  3046  // 152.
  3047  
  3048  // tangle:pos vptovf.web:2675:6:
  3049  
  3050  // (More good stuff from \.[TFtoPL].)
  3051  func (prg *prg) f(h, x, y indx) (r indx) {
  3052  	switch prg.class[h] {
  3053  	case simple:
  3054  	case leftZ:
  3055  		prg.class[h] = byte(pending)
  3056  		prg.ligZ[h] = prg.eval(prg.ligZ[h], y)
  3057  		prg.class[h] = byte(simple)
  3058  
  3059  	case rightZ:
  3060  		prg.class[h] = byte(pending)
  3061  		prg.ligZ[h] = prg.eval(x, prg.ligZ[h])
  3062  		prg.class[h] = byte(simple)
  3063  
  3064  	case bothZ:
  3065  		prg.class[h] = byte(pending)
  3066  		prg.ligZ[h] = prg.eval(prg.eval(x, prg.ligZ[h]), y)
  3067  		prg.class[h] = byte(simple)
  3068  
  3069  	case pending:
  3070  		prg.xLigCycle = x
  3071  		prg.yLigCycle = y
  3072  		prg.ligZ[h] = 257
  3073  		prg.class[h] = byte(simple)
  3074  		// the value 257 will break all cycles, since it's not in |hash|
  3075  	} // there are no other cases
  3076  	r = prg.ligZ[h]
  3077  	return r
  3078  }
  3079  
  3080  // 156. The TFM output phase
  3081  
  3082  // tangle:pos vptovf.web:2771:21:
  3083  
  3084  // Now that we know how to get all of the font data correctly stored in
  3085  // \.[VPtoVF]'s memory, it only remains to write the answers out.
  3086  //
  3087  // First of all, it is convenient to have an abbreviation for output to the
  3088  // \.[TFM] file:
  3089  
  3090  // 165.
  3091  
  3092  // tangle:pos vptovf.web:2885:6:
  3093  
  3094  // When a scaled quantity is output, we may need to divide it by |design_units|.
  3095  // The following subroutine takes care of this, using floating point arithmetic
  3096  // only if |design_units<>1.0|.
  3097  func (prg *prg) outScaled(x fixWord) { // outputs a scaled |fix_word|
  3098  	var (
  3099  		n                      byte // the first byte after the sign
  3100  		m/* 0..65535 */ uint16      // the two least significant bytes
  3101  	)
  3102  	if fabs(float64(x)/float64(prg.designUnits)) >= 16.0 {
  3103  		prg.stdout.Writeln("The relative dimension ", float64(x)/float64(04000000), knuth.WriteWidth(1), knuth.WriteWidth(3),
  3104  			" is too large.")
  3105  		// \xref[The relative dimension...]
  3106  		prg.stdout.Write("  (Must be less than 16*designsize")
  3107  		if prg.designUnits != 04000000 {
  3108  			prg.stdout.Write(" =", float64(prg.designUnits)/float64(0200000), knuth.WriteWidth(1), knuth.WriteWidth(3),
  3109  				" designunits")
  3110  		}
  3111  		prg.stdout.Writeln(")")
  3112  		x = 0
  3113  	}
  3114  	if prg.designUnits != 04000000 {
  3115  		x = round(float64(x) / float64(prg.designUnits) * 1048576.0)
  3116  	}
  3117  	if x < 0 {
  3118  		prg.tfmFile.Write(255)
  3119  		x = x + 0100000000
  3120  		if x <= 0 {
  3121  			x = 1
  3122  		}
  3123  	} else {
  3124  		prg.tfmFile.Write(0)
  3125  		if x >= 0100000000 {
  3126  			x = 077777777
  3127  		}
  3128  	}
  3129  	n = byte(x / 0200000)
  3130  	m = uint16(x % 0200000)
  3131  	prg.tfmFile.Write(n)
  3132  	prg.tfmFile.Write(int32(m) / 256)
  3133  	prg.tfmFile.Write(int32(m) % 256)
  3134  }
  3135  
  3136  // 176.
  3137  
  3138  // tangle:pos vptovf.web:3049:57:
  3139  
  3140  // We need a routine to output integers as four bytes. Negative values
  3141  // will never be less than $-2^[24]$.
  3142  func (prg *prg) voutInt(x int32) {
  3143  	if x >= 0 {
  3144  		prg.vfFile.Write(x / 0100000000)
  3145  	} else {
  3146  		prg.vfFile.Write(255)
  3147  		x = x + 0100000000
  3148  	}
  3149  	prg.vfFile.Write(x / 0200000 % 256)
  3150  	prg.vfFile.Write(x / 0400 % 256)
  3151  	prg.vfFile.Write(x % 256)
  3152  }
  3153  
  3154  // 180. The main program
  3155  
  3156  // tangle:pos vptovf.web:3109:17:
  3157  
  3158  // The routines sketched out so far need to be packaged into separate procedures,
  3159  // on some systems, since some \PASCAL\ compilers place a strict limit on the
  3160  // size of a routine. The packaging is done here in an attempt to avoid some
  3161  // system-dependent changes.
  3162  func (prg *prg) paramEnter() {
  3163  	prg.nameLength = 5
  3164  	prg.curName[16-1] = 'S'
  3165  	prg.curName[17-1] = 'L'
  3166  	prg.curName[18-1] = 'A'
  3167  	prg.curName[19-1] = 'N'
  3168  	prg.curName[20-1] = 'T'
  3169  	prg.enterName(byte(parameterCode + 1))
  3170  
  3171  	prg.nameLength = 5
  3172  	prg.curName[16-1] = 'S'
  3173  	prg.curName[17-1] = 'P'
  3174  	prg.curName[18-1] = 'A'
  3175  	prg.curName[19-1] = 'C'
  3176  	prg.curName[20-1] = 'E'
  3177  	prg.enterName(byte(parameterCode + 2))
  3178  
  3179  	prg.nameLength = 7
  3180  	prg.curName[14-1] = 'S'
  3181  	prg.curName[15-1] = 'T'
  3182  	prg.curName[16-1] = 'R'
  3183  	prg.curName[17-1] = 'E'
  3184  	prg.curName[18-1] = 'T'
  3185  	prg.curName[19-1] = 'C'
  3186  	prg.curName[20-1] = 'H'
  3187  	prg.enterName(byte(parameterCode + 3))
  3188  
  3189  	prg.nameLength = 6
  3190  	prg.curName[15-1] = 'S'
  3191  	prg.curName[16-1] = 'H'
  3192  	prg.curName[17-1] = 'R'
  3193  	prg.curName[18-1] = 'I'
  3194  	prg.curName[19-1] = 'N'
  3195  	prg.curName[20-1] = 'K'
  3196  	prg.enterName(byte(parameterCode + 4))
  3197  
  3198  	prg.nameLength = 7
  3199  	prg.curName[14-1] = 'X'
  3200  	prg.curName[15-1] = 'H'
  3201  	prg.curName[16-1] = 'E'
  3202  	prg.curName[17-1] = 'I'
  3203  	prg.curName[18-1] = 'G'
  3204  	prg.curName[19-1] = 'H'
  3205  	prg.curName[20-1] = 'T'
  3206  	prg.enterName(byte(parameterCode + 5))
  3207  
  3208  	prg.nameLength = 4
  3209  	prg.curName[17-1] = 'Q'
  3210  	prg.curName[18-1] = 'U'
  3211  	prg.curName[19-1] = 'A'
  3212  	prg.curName[20-1] = 'D'
  3213  	prg.enterName(byte(parameterCode + 6))
  3214  
  3215  	prg.nameLength = 10
  3216  	prg.curName[11-1] = 'E'
  3217  	prg.curName[12-1] = 'X'
  3218  	prg.curName[13-1] = 'T'
  3219  	prg.curName[14-1] = 'R'
  3220  	prg.curName[15-1] = 'A'
  3221  	prg.curName[16-1] = 'S'
  3222  	prg.curName[17-1] = 'P'
  3223  	prg.curName[18-1] = 'A'
  3224  	prg.curName[19-1] = 'C'
  3225  	prg.curName[20-1] = 'E'
  3226  	prg.enterName(byte(parameterCode + 7))
  3227  
  3228  	prg.nameLength = 4
  3229  	prg.curName[17-1] = 'N'
  3230  	prg.curName[18-1] = 'U'
  3231  	prg.curName[19-1] = 'M'
  3232  	prg.curName[20-1] = '1'
  3233  	prg.enterName(byte(parameterCode + 8))
  3234  
  3235  	prg.nameLength = 4
  3236  	prg.curName[17-1] = 'N'
  3237  	prg.curName[18-1] = 'U'
  3238  	prg.curName[19-1] = 'M'
  3239  	prg.curName[20-1] = '2'
  3240  	prg.enterName(byte(parameterCode + 9))
  3241  
  3242  	prg.nameLength = 4
  3243  	prg.curName[17-1] = 'N'
  3244  	prg.curName[18-1] = 'U'
  3245  	prg.curName[19-1] = 'M'
  3246  	prg.curName[20-1] = '3'
  3247  	prg.enterName(byte(parameterCode + 10))
  3248  
  3249  	prg.nameLength = 6
  3250  	prg.curName[15-1] = 'D'
  3251  	prg.curName[16-1] = 'E'
  3252  	prg.curName[17-1] = 'N'
  3253  	prg.curName[18-1] = 'O'
  3254  	prg.curName[19-1] = 'M'
  3255  	prg.curName[20-1] = '1'
  3256  	prg.enterName(byte(parameterCode + 11))
  3257  
  3258  	prg.nameLength = 6
  3259  	prg.curName[15-1] = 'D'
  3260  	prg.curName[16-1] = 'E'
  3261  	prg.curName[17-1] = 'N'
  3262  	prg.curName[18-1] = 'O'
  3263  	prg.curName[19-1] = 'M'
  3264  	prg.curName[20-1] = '2'
  3265  	prg.enterName(byte(parameterCode + 12))
  3266  
  3267  	prg.nameLength = 4
  3268  	prg.curName[17-1] = 'S'
  3269  	prg.curName[18-1] = 'U'
  3270  	prg.curName[19-1] = 'P'
  3271  	prg.curName[20-1] = '1'
  3272  	prg.enterName(byte(parameterCode + 13))
  3273  
  3274  	prg.nameLength = 4
  3275  	prg.curName[17-1] = 'S'
  3276  	prg.curName[18-1] = 'U'
  3277  	prg.curName[19-1] = 'P'
  3278  	prg.curName[20-1] = '2'
  3279  	prg.enterName(byte(parameterCode + 14))
  3280  
  3281  	prg.nameLength = 4
  3282  	prg.curName[17-1] = 'S'
  3283  	prg.curName[18-1] = 'U'
  3284  	prg.curName[19-1] = 'P'
  3285  	prg.curName[20-1] = '3'
  3286  	prg.enterName(byte(parameterCode + 15))
  3287  
  3288  	prg.nameLength = 4
  3289  	prg.curName[17-1] = 'S'
  3290  	prg.curName[18-1] = 'U'
  3291  	prg.curName[19-1] = 'B'
  3292  	prg.curName[20-1] = '1'
  3293  	prg.enterName(byte(parameterCode + 16))
  3294  
  3295  	prg.nameLength = 4
  3296  	prg.curName[17-1] = 'S'
  3297  	prg.curName[18-1] = 'U'
  3298  	prg.curName[19-1] = 'B'
  3299  	prg.curName[20-1] = '2'
  3300  	prg.enterName(byte(parameterCode + 17))
  3301  
  3302  	prg.nameLength = 7
  3303  	prg.curName[14-1] = 'S'
  3304  	prg.curName[15-1] = 'U'
  3305  	prg.curName[16-1] = 'P'
  3306  	prg.curName[17-1] = 'D'
  3307  	prg.curName[18-1] = 'R'
  3308  	prg.curName[19-1] = 'O'
  3309  	prg.curName[20-1] = 'P'
  3310  	prg.enterName(byte(parameterCode + 18))
  3311  
  3312  	prg.nameLength = 7
  3313  	prg.curName[14-1] = 'S'
  3314  	prg.curName[15-1] = 'U'
  3315  	prg.curName[16-1] = 'B'
  3316  	prg.curName[17-1] = 'D'
  3317  	prg.curName[18-1] = 'R'
  3318  	prg.curName[19-1] = 'O'
  3319  	prg.curName[20-1] = 'P'
  3320  	prg.enterName(byte(parameterCode + 19))
  3321  
  3322  	prg.nameLength = 6
  3323  	prg.curName[15-1] = 'D'
  3324  	prg.curName[16-1] = 'E'
  3325  	prg.curName[17-1] = 'L'
  3326  	prg.curName[18-1] = 'I'
  3327  	prg.curName[19-1] = 'M'
  3328  	prg.curName[20-1] = '1'
  3329  	prg.enterName(byte(parameterCode + 20))
  3330  
  3331  	prg.nameLength = 6
  3332  	prg.curName[15-1] = 'D'
  3333  	prg.curName[16-1] = 'E'
  3334  	prg.curName[17-1] = 'L'
  3335  	prg.curName[18-1] = 'I'
  3336  	prg.curName[19-1] = 'M'
  3337  	prg.curName[20-1] = '2'
  3338  	prg.enterName(byte(parameterCode + 21))
  3339  
  3340  	prg.nameLength = 10
  3341  	prg.curName[11-1] = 'A'
  3342  	prg.curName[12-1] = 'X'
  3343  	prg.curName[13-1] = 'I'
  3344  	prg.curName[14-1] = 'S'
  3345  	prg.curName[15-1] = 'H'
  3346  	prg.curName[16-1] = 'E'
  3347  	prg.curName[17-1] = 'I'
  3348  	prg.curName[18-1] = 'G'
  3349  	prg.curName[19-1] = 'H'
  3350  	prg.curName[20-1] = 'T'
  3351  	prg.enterName(byte(parameterCode + 22))
  3352  
  3353  	prg.nameLength = 20
  3354  	prg.curName[1-1] = 'D'
  3355  	prg.curName[2-1] = 'E'
  3356  	prg.curName[3-1] = 'F'
  3357  	prg.curName[4-1] = 'A'
  3358  	prg.curName[5-1] = 'U'
  3359  	prg.curName[6-1] = 'L'
  3360  	prg.curName[7-1] = 'T'
  3361  	prg.curName[8-1] = 'R'
  3362  	prg.curName[9-1] = 'U'
  3363  	prg.curName[10-1] = 'L'
  3364  	prg.curName[11-1] = 'E'
  3365  	prg.curName[12-1] = 'T'
  3366  	prg.curName[13-1] = 'H'
  3367  	prg.curName[14-1] = 'I'
  3368  	prg.curName[15-1] = 'C'
  3369  	prg.curName[16-1] = 'K'
  3370  	prg.curName[17-1] = 'N'
  3371  	prg.curName[18-1] = 'E'
  3372  	prg.curName[19-1] = 'S'
  3373  	prg.curName[20-1] = 'S'
  3374  	prg.enterName(byte(parameterCode + 8))
  3375  
  3376  	prg.nameLength = 13
  3377  	prg.curName[8-1] = 'B'
  3378  	prg.curName[9-1] = 'I'
  3379  	prg.curName[10-1] = 'G'
  3380  	prg.curName[11-1] = 'O'
  3381  	prg.curName[12-1] = 'P'
  3382  	prg.curName[13-1] = 'S'
  3383  	prg.curName[14-1] = 'P'
  3384  	prg.curName[15-1] = 'A'
  3385  	prg.curName[16-1] = 'C'
  3386  	prg.curName[17-1] = 'I'
  3387  	prg.curName[18-1] = 'N'
  3388  	prg.curName[19-1] = 'G'
  3389  	prg.curName[20-1] = '1'
  3390  	prg.enterName(byte(parameterCode + 9))
  3391  
  3392  	prg.nameLength = 13
  3393  	prg.curName[8-1] = 'B'
  3394  	prg.curName[9-1] = 'I'
  3395  	prg.curName[10-1] = 'G'
  3396  	prg.curName[11-1] = 'O'
  3397  	prg.curName[12-1] = 'P'
  3398  	prg.curName[13-1] = 'S'
  3399  	prg.curName[14-1] = 'P'
  3400  	prg.curName[15-1] = 'A'
  3401  	prg.curName[16-1] = 'C'
  3402  	prg.curName[17-1] = 'I'
  3403  	prg.curName[18-1] = 'N'
  3404  	prg.curName[19-1] = 'G'
  3405  	prg.curName[20-1] = '2'
  3406  	prg.enterName(byte(parameterCode + 10))
  3407  
  3408  	prg.nameLength = 13
  3409  	prg.curName[8-1] = 'B'
  3410  	prg.curName[9-1] = 'I'
  3411  	prg.curName[10-1] = 'G'
  3412  	prg.curName[11-1] = 'O'
  3413  	prg.curName[12-1] = 'P'
  3414  	prg.curName[13-1] = 'S'
  3415  	prg.curName[14-1] = 'P'
  3416  	prg.curName[15-1] = 'A'
  3417  	prg.curName[16-1] = 'C'
  3418  	prg.curName[17-1] = 'I'
  3419  	prg.curName[18-1] = 'N'
  3420  	prg.curName[19-1] = 'G'
  3421  	prg.curName[20-1] = '3'
  3422  	prg.enterName(byte(parameterCode + 11))
  3423  
  3424  	prg.nameLength = 13
  3425  	prg.curName[8-1] = 'B'
  3426  	prg.curName[9-1] = 'I'
  3427  	prg.curName[10-1] = 'G'
  3428  	prg.curName[11-1] = 'O'
  3429  	prg.curName[12-1] = 'P'
  3430  	prg.curName[13-1] = 'S'
  3431  	prg.curName[14-1] = 'P'
  3432  	prg.curName[15-1] = 'A'
  3433  	prg.curName[16-1] = 'C'
  3434  	prg.curName[17-1] = 'I'
  3435  	prg.curName[18-1] = 'N'
  3436  	prg.curName[19-1] = 'G'
  3437  	prg.curName[20-1] = '4'
  3438  	prg.enterName(byte(parameterCode + 12))
  3439  
  3440  	prg.nameLength = 13
  3441  	prg.curName[8-1] = 'B'
  3442  	prg.curName[9-1] = 'I'
  3443  	prg.curName[10-1] = 'G'
  3444  	prg.curName[11-1] = 'O'
  3445  	prg.curName[12-1] = 'P'
  3446  	prg.curName[13-1] = 'S'
  3447  	prg.curName[14-1] = 'P'
  3448  	prg.curName[15-1] = 'A'
  3449  	prg.curName[16-1] = 'C'
  3450  	prg.curName[17-1] = 'I'
  3451  	prg.curName[18-1] = 'N'
  3452  	prg.curName[19-1] = 'G'
  3453  	prg.curName[20-1] = '5'
  3454  	prg.enterName(byte(parameterCode + 13))
  3455  
  3456  }
  3457  
  3458  func (prg *prg) vplEnter() {
  3459  	prg.nameLength = 6
  3460  	prg.curName[15-1] = 'V'
  3461  	prg.curName[16-1] = 'T'
  3462  	prg.curName[17-1] = 'I'
  3463  	prg.curName[18-1] = 'T'
  3464  	prg.curName[19-1] = 'L'
  3465  	prg.curName[20-1] = 'E'
  3466  	prg.enterName(byte(virtualTitleCode))
  3467  
  3468  	prg.nameLength = 7
  3469  	prg.curName[14-1] = 'M'
  3470  	prg.curName[15-1] = 'A'
  3471  	prg.curName[16-1] = 'P'
  3472  	prg.curName[17-1] = 'F'
  3473  	prg.curName[18-1] = 'O'
  3474  	prg.curName[19-1] = 'N'
  3475  	prg.curName[20-1] = 'T'
  3476  	prg.enterName(byte(mapFontCode))
  3477  
  3478  	prg.nameLength = 3
  3479  	prg.curName[18-1] = 'M'
  3480  	prg.curName[19-1] = 'A'
  3481  	prg.curName[20-1] = 'P'
  3482  	prg.enterName(byte(mapCode))
  3483  
  3484  	prg.nameLength = 8
  3485  	prg.curName[13-1] = 'F'
  3486  	prg.curName[14-1] = 'O'
  3487  	prg.curName[15-1] = 'N'
  3488  	prg.curName[16-1] = 'T'
  3489  	prg.curName[17-1] = 'N'
  3490  	prg.curName[18-1] = 'A'
  3491  	prg.curName[19-1] = 'M'
  3492  	prg.curName[20-1] = 'E'
  3493  	prg.enterName(byte(fontNameCode))
  3494  
  3495  	prg.nameLength = 8
  3496  	prg.curName[13-1] = 'F'
  3497  	prg.curName[14-1] = 'O'
  3498  	prg.curName[15-1] = 'N'
  3499  	prg.curName[16-1] = 'T'
  3500  	prg.curName[17-1] = 'A'
  3501  	prg.curName[18-1] = 'R'
  3502  	prg.curName[19-1] = 'E'
  3503  	prg.curName[20-1] = 'A'
  3504  	prg.enterName(byte(fontAreaCode))
  3505  
  3506  	prg.nameLength = 12
  3507  	prg.curName[9-1] = 'F'
  3508  	prg.curName[10-1] = 'O'
  3509  	prg.curName[11-1] = 'N'
  3510  	prg.curName[12-1] = 'T'
  3511  	prg.curName[13-1] = 'C'
  3512  	prg.curName[14-1] = 'H'
  3513  	prg.curName[15-1] = 'E'
  3514  	prg.curName[16-1] = 'C'
  3515  	prg.curName[17-1] = 'K'
  3516  	prg.curName[18-1] = 'S'
  3517  	prg.curName[19-1] = 'U'
  3518  	prg.curName[20-1] = 'M'
  3519  	prg.enterName(byte(fontChecksumCode))
  3520  
  3521  	prg.nameLength = 6
  3522  	prg.curName[15-1] = 'F'
  3523  	prg.curName[16-1] = 'O'
  3524  	prg.curName[17-1] = 'N'
  3525  	prg.curName[18-1] = 'T'
  3526  	prg.curName[19-1] = 'A'
  3527  	prg.curName[20-1] = 'T'
  3528  	prg.enterName(byte(fontAtCode))
  3529  
  3530  	prg.nameLength = 9
  3531  	prg.curName[12-1] = 'F'
  3532  	prg.curName[13-1] = 'O'
  3533  	prg.curName[14-1] = 'N'
  3534  	prg.curName[15-1] = 'T'
  3535  	prg.curName[16-1] = 'D'
  3536  	prg.curName[17-1] = 'S'
  3537  	prg.curName[18-1] = 'I'
  3538  	prg.curName[19-1] = 'Z'
  3539  	prg.curName[20-1] = 'E'
  3540  	prg.enterName(byte(fontDsizeCode))
  3541  
  3542  	prg.nameLength = 10
  3543  	prg.curName[11-1] = 'S'
  3544  	prg.curName[12-1] = 'E'
  3545  	prg.curName[13-1] = 'L'
  3546  	prg.curName[14-1] = 'E'
  3547  	prg.curName[15-1] = 'C'
  3548  	prg.curName[16-1] = 'T'
  3549  	prg.curName[17-1] = 'F'
  3550  	prg.curName[18-1] = 'O'
  3551  	prg.curName[19-1] = 'N'
  3552  	prg.curName[20-1] = 'T'
  3553  	prg.enterName(byte(selectFontCode))
  3554  
  3555  	prg.nameLength = 7
  3556  	prg.curName[14-1] = 'S'
  3557  	prg.curName[15-1] = 'E'
  3558  	prg.curName[16-1] = 'T'
  3559  	prg.curName[17-1] = 'C'
  3560  	prg.curName[18-1] = 'H'
  3561  	prg.curName[19-1] = 'A'
  3562  	prg.curName[20-1] = 'R'
  3563  	prg.enterName(byte(setCharCode))
  3564  
  3565  	prg.nameLength = 7
  3566  	prg.curName[14-1] = 'S'
  3567  	prg.curName[15-1] = 'E'
  3568  	prg.curName[16-1] = 'T'
  3569  	prg.curName[17-1] = 'R'
  3570  	prg.curName[18-1] = 'U'
  3571  	prg.curName[19-1] = 'L'
  3572  	prg.curName[20-1] = 'E'
  3573  	prg.enterName(byte(setRuleCode))
  3574  
  3575  	prg.nameLength = 9
  3576  	prg.curName[12-1] = 'M'
  3577  	prg.curName[13-1] = 'O'
  3578  	prg.curName[14-1] = 'V'
  3579  	prg.curName[15-1] = 'E'
  3580  	prg.curName[16-1] = 'R'
  3581  	prg.curName[17-1] = 'I'
  3582  	prg.curName[18-1] = 'G'
  3583  	prg.curName[19-1] = 'H'
  3584  	prg.curName[20-1] = 'T'
  3585  	prg.enterName(byte(moveRightCode))
  3586  
  3587  	prg.nameLength = 8
  3588  	prg.curName[13-1] = 'M'
  3589  	prg.curName[14-1] = 'O'
  3590  	prg.curName[15-1] = 'V'
  3591  	prg.curName[16-1] = 'E'
  3592  	prg.curName[17-1] = 'L'
  3593  	prg.curName[18-1] = 'E'
  3594  	prg.curName[19-1] = 'F'
  3595  	prg.curName[20-1] = 'T'
  3596  	prg.enterName(byte(moveRightCode + 1))
  3597  
  3598  	prg.nameLength = 8
  3599  	prg.curName[13-1] = 'M'
  3600  	prg.curName[14-1] = 'O'
  3601  	prg.curName[15-1] = 'V'
  3602  	prg.curName[16-1] = 'E'
  3603  	prg.curName[17-1] = 'D'
  3604  	prg.curName[18-1] = 'O'
  3605  	prg.curName[19-1] = 'W'
  3606  	prg.curName[20-1] = 'N'
  3607  	prg.enterName(byte(moveDownCode))
  3608  
  3609  	prg.nameLength = 6
  3610  	prg.curName[15-1] = 'M'
  3611  	prg.curName[16-1] = 'O'
  3612  	prg.curName[17-1] = 'V'
  3613  	prg.curName[18-1] = 'E'
  3614  	prg.curName[19-1] = 'U'
  3615  	prg.curName[20-1] = 'P'
  3616  	prg.enterName(byte(moveDownCode + 1))
  3617  
  3618  	prg.nameLength = 4
  3619  	prg.curName[17-1] = 'P'
  3620  	prg.curName[18-1] = 'U'
  3621  	prg.curName[19-1] = 'S'
  3622  	prg.curName[20-1] = 'H'
  3623  	prg.enterName(byte(pushCode))
  3624  
  3625  	prg.nameLength = 3
  3626  	prg.curName[18-1] = 'P'
  3627  	prg.curName[19-1] = 'O'
  3628  	prg.curName[20-1] = 'P'
  3629  	prg.enterName(byte(popCode))
  3630  
  3631  	prg.nameLength = 7
  3632  	prg.curName[14-1] = 'S'
  3633  	prg.curName[15-1] = 'P'
  3634  	prg.curName[16-1] = 'E'
  3635  	prg.curName[17-1] = 'C'
  3636  	prg.curName[18-1] = 'I'
  3637  	prg.curName[19-1] = 'A'
  3638  	prg.curName[20-1] = 'L'
  3639  	prg.enterName(byte(specialCode))
  3640  
  3641  	prg.nameLength = 10
  3642  	prg.curName[11-1] = 'S'
  3643  	prg.curName[12-1] = 'P'
  3644  	prg.curName[13-1] = 'E'
  3645  	prg.curName[14-1] = 'C'
  3646  	prg.curName[15-1] = 'I'
  3647  	prg.curName[16-1] = 'A'
  3648  	prg.curName[17-1] = 'L'
  3649  	prg.curName[18-1] = 'H'
  3650  	prg.curName[19-1] = 'E'
  3651  	prg.curName[20-1] = 'X'
  3652  	prg.enterName(byte(specialHexCode))
  3653  
  3654  }
  3655  
  3656  func (prg *prg) nameEnter() {
  3657  	prg.equiv[0] = byte(commentCode) // this is used after unknown keywords
  3658  	prg.nameLength = 8
  3659  	prg.curName[13-1] = 'C'
  3660  	prg.curName[14-1] = 'H'
  3661  	prg.curName[15-1] = 'E'
  3662  	prg.curName[16-1] = 'C'
  3663  	prg.curName[17-1] = 'K'
  3664  	prg.curName[18-1] = 'S'
  3665  	prg.curName[19-1] = 'U'
  3666  	prg.curName[20-1] = 'M'
  3667  	prg.enterName(byte(checkSumCode))
  3668  
  3669  	prg.nameLength = 10
  3670  	prg.curName[11-1] = 'D'
  3671  	prg.curName[12-1] = 'E'
  3672  	prg.curName[13-1] = 'S'
  3673  	prg.curName[14-1] = 'I'
  3674  	prg.curName[15-1] = 'G'
  3675  	prg.curName[16-1] = 'N'
  3676  	prg.curName[17-1] = 'S'
  3677  	prg.curName[18-1] = 'I'
  3678  	prg.curName[19-1] = 'Z'
  3679  	prg.curName[20-1] = 'E'
  3680  	prg.enterName(byte(designSizeCode))
  3681  
  3682  	prg.nameLength = 11
  3683  	prg.curName[10-1] = 'D'
  3684  	prg.curName[11-1] = 'E'
  3685  	prg.curName[12-1] = 'S'
  3686  	prg.curName[13-1] = 'I'
  3687  	prg.curName[14-1] = 'G'
  3688  	prg.curName[15-1] = 'N'
  3689  	prg.curName[16-1] = 'U'
  3690  	prg.curName[17-1] = 'N'
  3691  	prg.curName[18-1] = 'I'
  3692  	prg.curName[19-1] = 'T'
  3693  	prg.curName[20-1] = 'S'
  3694  	prg.enterName(byte(designUnitsCode))
  3695  
  3696  	prg.nameLength = 12
  3697  	prg.curName[9-1] = 'C'
  3698  	prg.curName[10-1] = 'O'
  3699  	prg.curName[11-1] = 'D'
  3700  	prg.curName[12-1] = 'I'
  3701  	prg.curName[13-1] = 'N'
  3702  	prg.curName[14-1] = 'G'
  3703  	prg.curName[15-1] = 'S'
  3704  	prg.curName[16-1] = 'C'
  3705  	prg.curName[17-1] = 'H'
  3706  	prg.curName[18-1] = 'E'
  3707  	prg.curName[19-1] = 'M'
  3708  	prg.curName[20-1] = 'E'
  3709  	prg.enterName(byte(codingSchemeCode))
  3710  
  3711  	prg.nameLength = 6
  3712  	prg.curName[15-1] = 'F'
  3713  	prg.curName[16-1] = 'A'
  3714  	prg.curName[17-1] = 'M'
  3715  	prg.curName[18-1] = 'I'
  3716  	prg.curName[19-1] = 'L'
  3717  	prg.curName[20-1] = 'Y'
  3718  	prg.enterName(byte(familyCode))
  3719  
  3720  	prg.nameLength = 4
  3721  	prg.curName[17-1] = 'F'
  3722  	prg.curName[18-1] = 'A'
  3723  	prg.curName[19-1] = 'C'
  3724  	prg.curName[20-1] = 'E'
  3725  	prg.enterName(byte(faceCode))
  3726  
  3727  	prg.nameLength = 16
  3728  	prg.curName[5-1] = 'S'
  3729  	prg.curName[6-1] = 'E'
  3730  	prg.curName[7-1] = 'V'
  3731  	prg.curName[8-1] = 'E'
  3732  	prg.curName[9-1] = 'N'
  3733  	prg.curName[10-1] = 'B'
  3734  	prg.curName[11-1] = 'I'
  3735  	prg.curName[12-1] = 'T'
  3736  	prg.curName[13-1] = 'S'
  3737  	prg.curName[14-1] = 'A'
  3738  	prg.curName[15-1] = 'F'
  3739  	prg.curName[16-1] = 'E'
  3740  	prg.curName[17-1] = 'F'
  3741  	prg.curName[18-1] = 'L'
  3742  	prg.curName[19-1] = 'A'
  3743  	prg.curName[20-1] = 'G'
  3744  	prg.enterName(byte(sevenBitSafeFlagCode))
  3745  
  3746  	prg.nameLength = 6
  3747  	prg.curName[15-1] = 'H'
  3748  	prg.curName[16-1] = 'E'
  3749  	prg.curName[17-1] = 'A'
  3750  	prg.curName[18-1] = 'D'
  3751  	prg.curName[19-1] = 'E'
  3752  	prg.curName[20-1] = 'R'
  3753  	prg.enterName(byte(headerCode))
  3754  
  3755  	prg.nameLength = 9
  3756  	prg.curName[12-1] = 'F'
  3757  	prg.curName[13-1] = 'O'
  3758  	prg.curName[14-1] = 'N'
  3759  	prg.curName[15-1] = 'T'
  3760  	prg.curName[16-1] = 'D'
  3761  	prg.curName[17-1] = 'I'
  3762  	prg.curName[18-1] = 'M'
  3763  	prg.curName[19-1] = 'E'
  3764  	prg.curName[20-1] = 'N'
  3765  	prg.enterName(byte(fontDimenCode))
  3766  
  3767  	prg.nameLength = 8
  3768  	prg.curName[13-1] = 'L'
  3769  	prg.curName[14-1] = 'I'
  3770  	prg.curName[15-1] = 'G'
  3771  	prg.curName[16-1] = 'T'
  3772  	prg.curName[17-1] = 'A'
  3773  	prg.curName[18-1] = 'B'
  3774  	prg.curName[19-1] = 'L'
  3775  	prg.curName[20-1] = 'E'
  3776  	prg.enterName(byte(ligTableCode))
  3777  
  3778  	prg.nameLength = 12
  3779  	prg.curName[9-1] = 'B'
  3780  	prg.curName[10-1] = 'O'
  3781  	prg.curName[11-1] = 'U'
  3782  	prg.curName[12-1] = 'N'
  3783  	prg.curName[13-1] = 'D'
  3784  	prg.curName[14-1] = 'A'
  3785  	prg.curName[15-1] = 'R'
  3786  	prg.curName[16-1] = 'Y'
  3787  	prg.curName[17-1] = 'C'
  3788  	prg.curName[18-1] = 'H'
  3789  	prg.curName[19-1] = 'A'
  3790  	prg.curName[20-1] = 'R'
  3791  	prg.enterName(byte(boundaryCharCode))
  3792  
  3793  	prg.nameLength = 9
  3794  	prg.curName[12-1] = 'C'
  3795  	prg.curName[13-1] = 'H'
  3796  	prg.curName[14-1] = 'A'
  3797  	prg.curName[15-1] = 'R'
  3798  	prg.curName[16-1] = 'A'
  3799  	prg.curName[17-1] = 'C'
  3800  	prg.curName[18-1] = 'T'
  3801  	prg.curName[19-1] = 'E'
  3802  	prg.curName[20-1] = 'R'
  3803  	prg.enterName(byte(characterCode))
  3804  
  3805  	prg.nameLength = 9
  3806  	prg.curName[12-1] = 'P'
  3807  	prg.curName[13-1] = 'A'
  3808  	prg.curName[14-1] = 'R'
  3809  	prg.curName[15-1] = 'A'
  3810  	prg.curName[16-1] = 'M'
  3811  	prg.curName[17-1] = 'E'
  3812  	prg.curName[18-1] = 'T'
  3813  	prg.curName[19-1] = 'E'
  3814  	prg.curName[20-1] = 'R'
  3815  	prg.enterName(byte(parameterCode))
  3816  
  3817  	prg.nameLength = 6
  3818  	prg.curName[15-1] = 'C'
  3819  	prg.curName[16-1] = 'H'
  3820  	prg.curName[17-1] = 'A'
  3821  	prg.curName[18-1] = 'R'
  3822  	prg.curName[19-1] = 'W'
  3823  	prg.curName[20-1] = 'D'
  3824  	prg.enterName(byte(charWdCode))
  3825  
  3826  	prg.nameLength = 6
  3827  	prg.curName[15-1] = 'C'
  3828  	prg.curName[16-1] = 'H'
  3829  	prg.curName[17-1] = 'A'
  3830  	prg.curName[18-1] = 'R'
  3831  	prg.curName[19-1] = 'H'
  3832  	prg.curName[20-1] = 'T'
  3833  	prg.enterName(byte(charHtCode))
  3834  
  3835  	prg.nameLength = 6
  3836  	prg.curName[15-1] = 'C'
  3837  	prg.curName[16-1] = 'H'
  3838  	prg.curName[17-1] = 'A'
  3839  	prg.curName[18-1] = 'R'
  3840  	prg.curName[19-1] = 'D'
  3841  	prg.curName[20-1] = 'P'
  3842  	prg.enterName(byte(charDpCode))
  3843  
  3844  	prg.nameLength = 6
  3845  	prg.curName[15-1] = 'C'
  3846  	prg.curName[16-1] = 'H'
  3847  	prg.curName[17-1] = 'A'
  3848  	prg.curName[18-1] = 'R'
  3849  	prg.curName[19-1] = 'I'
  3850  	prg.curName[20-1] = 'C'
  3851  	prg.enterName(byte(charIcCode))
  3852  
  3853  	prg.nameLength = 10
  3854  	prg.curName[11-1] = 'N'
  3855  	prg.curName[12-1] = 'E'
  3856  	prg.curName[13-1] = 'X'
  3857  	prg.curName[14-1] = 'T'
  3858  	prg.curName[15-1] = 'L'
  3859  	prg.curName[16-1] = 'A'
  3860  	prg.curName[17-1] = 'R'
  3861  	prg.curName[18-1] = 'G'
  3862  	prg.curName[19-1] = 'E'
  3863  	prg.curName[20-1] = 'R'
  3864  	prg.enterName(byte(nextLargerCode))
  3865  
  3866  	prg.nameLength = 7
  3867  	prg.curName[14-1] = 'V'
  3868  	prg.curName[15-1] = 'A'
  3869  	prg.curName[16-1] = 'R'
  3870  	prg.curName[17-1] = 'C'
  3871  	prg.curName[18-1] = 'H'
  3872  	prg.curName[19-1] = 'A'
  3873  	prg.curName[20-1] = 'R'
  3874  	prg.enterName(byte(varCharCode))
  3875  
  3876  	prg.nameLength = 3
  3877  	prg.curName[18-1] = 'T'
  3878  	prg.curName[19-1] = 'O'
  3879  	prg.curName[20-1] = 'P'
  3880  	prg.enterName(byte(varCharCode + 1))
  3881  
  3882  	prg.nameLength = 3
  3883  	prg.curName[18-1] = 'M'
  3884  	prg.curName[19-1] = 'I'
  3885  	prg.curName[20-1] = 'D'
  3886  	prg.enterName(byte(varCharCode + 2))
  3887  
  3888  	prg.nameLength = 3
  3889  	prg.curName[18-1] = 'B'
  3890  	prg.curName[19-1] = 'O'
  3891  	prg.curName[20-1] = 'T'
  3892  	prg.enterName(byte(varCharCode + 3))
  3893  
  3894  	prg.nameLength = 3
  3895  	prg.curName[18-1] = 'R'
  3896  	prg.curName[19-1] = 'E'
  3897  	prg.curName[20-1] = 'P'
  3898  	prg.enterName(byte(varCharCode + 4))
  3899  
  3900  	prg.nameLength = 3
  3901  	prg.curName[18-1] = 'E'
  3902  	prg.curName[19-1] = 'X'
  3903  	prg.curName[20-1] = 'T'
  3904  	prg.enterName(byte(varCharCode + 4)) // compatibility with older \.[PL] format
  3905  	prg.nameLength = 7
  3906  	prg.curName[14-1] = 'C'
  3907  	prg.curName[15-1] = 'O'
  3908  	prg.curName[16-1] = 'M'
  3909  	prg.curName[17-1] = 'M'
  3910  	prg.curName[18-1] = 'E'
  3911  	prg.curName[19-1] = 'N'
  3912  	prg.curName[20-1] = 'T'
  3913  	prg.enterName(byte(commentCode))
  3914  
  3915  	prg.nameLength = 5
  3916  	prg.curName[16-1] = 'L'
  3917  	prg.curName[17-1] = 'A'
  3918  	prg.curName[18-1] = 'B'
  3919  	prg.curName[19-1] = 'E'
  3920  	prg.curName[20-1] = 'L'
  3921  	prg.enterName(byte(labelCode))
  3922  
  3923  	prg.nameLength = 4
  3924  	prg.curName[17-1] = 'S'
  3925  	prg.curName[18-1] = 'T'
  3926  	prg.curName[19-1] = 'O'
  3927  	prg.curName[20-1] = 'P'
  3928  	prg.enterName(byte(stopCode))
  3929  
  3930  	prg.nameLength = 4
  3931  	prg.curName[17-1] = 'S'
  3932  	prg.curName[18-1] = 'K'
  3933  	prg.curName[19-1] = 'I'
  3934  	prg.curName[20-1] = 'P'
  3935  	prg.enterName(byte(skipCode))
  3936  
  3937  	prg.nameLength = 3
  3938  	prg.curName[18-1] = 'K'
  3939  	prg.curName[19-1] = 'R'
  3940  	prg.curName[20-1] = 'N'
  3941  	prg.enterName(byte(krnCode))
  3942  
  3943  	prg.nameLength = 3
  3944  	prg.curName[18-1] = 'L'
  3945  	prg.curName[19-1] = 'I'
  3946  	prg.curName[20-1] = 'G'
  3947  	prg.enterName(byte(ligCode))
  3948  
  3949  	prg.nameLength = 4
  3950  	prg.curName[17-1] = '/'
  3951  	prg.curName[18-1] = 'L'
  3952  	prg.curName[19-1] = 'I'
  3953  	prg.curName[20-1] = 'G'
  3954  	prg.enterName(byte(ligCode + 2))
  3955  
  3956  	prg.nameLength = 5
  3957  	prg.curName[16-1] = '/'
  3958  	prg.curName[17-1] = 'L'
  3959  	prg.curName[18-1] = 'I'
  3960  	prg.curName[19-1] = 'G'
  3961  	prg.curName[20-1] = '>'
  3962  	prg.enterName(byte(ligCode + 6))
  3963  
  3964  	prg.nameLength = 4
  3965  	prg.curName[17-1] = 'L'
  3966  	prg.curName[18-1] = 'I'
  3967  	prg.curName[19-1] = 'G'
  3968  	prg.curName[20-1] = '/'
  3969  	prg.enterName(byte(ligCode + 1))
  3970  
  3971  	prg.nameLength = 5
  3972  	prg.curName[16-1] = 'L'
  3973  	prg.curName[17-1] = 'I'
  3974  	prg.curName[18-1] = 'G'
  3975  	prg.curName[19-1] = '/'
  3976  	prg.curName[20-1] = '>'
  3977  	prg.enterName(byte(ligCode + 5))
  3978  
  3979  	prg.nameLength = 5
  3980  	prg.curName[16-1] = '/'
  3981  	prg.curName[17-1] = 'L'
  3982  	prg.curName[18-1] = 'I'
  3983  	prg.curName[19-1] = 'G'
  3984  	prg.curName[20-1] = '/'
  3985  	prg.enterName(byte(ligCode + 3))
  3986  
  3987  	prg.nameLength = 6
  3988  	prg.curName[15-1] = '/'
  3989  	prg.curName[16-1] = 'L'
  3990  	prg.curName[17-1] = 'I'
  3991  	prg.curName[18-1] = 'G'
  3992  	prg.curName[19-1] = '/'
  3993  	prg.curName[20-1] = '>'
  3994  	prg.enterName(byte(ligCode + 7))
  3995  
  3996  	prg.nameLength = 7
  3997  	prg.curName[14-1] = '/'
  3998  	prg.curName[15-1] = 'L'
  3999  	prg.curName[16-1] = 'I'
  4000  	prg.curName[17-1] = 'G'
  4001  	prg.curName[18-1] = '/'
  4002  	prg.curName[19-1] = '>'
  4003  	prg.curName[20-1] = '>'
  4004  	prg.enterName(byte(ligCode + 11))
  4005  
  4006  	prg.vplEnter()
  4007  	prg.paramEnter()
  4008  }
  4009  
  4010  func (prg *prg) readLigKern() {
  4011  	var (
  4012  		krnPtr/* 0..maxKerns */ uint16      // an index into |kern|
  4013  		c                              byte // runs through all character codes
  4014  	)
  4015  	{
  4016  		prg.lkStepEnded = false
  4017  		for prg.level == 1 {
  4018  			for int32(prg.curChar) == ' ' {
  4019  				prg.getNext()
  4020  			}
  4021  			if int32(prg.curChar) == '(' {
  4022  				prg.getName()
  4023  				if int32(prg.curCode) == commentCode {
  4024  					prg.skipToEndOfItem()
  4025  				} else if int32(prg.curCode) < labelCode {
  4026  					{
  4027  						if int32(prg.charsOnLine) > 0 {
  4028  							prg.stdout.Writeln(" ")
  4029  						}
  4030  						prg.stdout.Write("This property name doesn't belong in a LIGTABLE list")
  4031  						prg.showErrorContext()
  4032  					}
  4033  					prg.skipToEndOfItem()
  4034  				} else {
  4035  					switch prg.curCode {
  4036  					case labelCode:
  4037  						// Read a label step
  4038  						for int32(prg.curChar) == ' ' {
  4039  							prg.getNext()
  4040  						}
  4041  						if int32(prg.curChar) == 'B' {
  4042  							prg.charRemainder[256] = prg.nl
  4043  							for {
  4044  								prg.getNext()
  4045  								if int32(prg.curChar) == '(' || int32(prg.curChar) == ')' {
  4046  									break
  4047  								}
  4048  							} // \.[LABEL BOUNDARYCHAR]
  4049  						} else {
  4050  							{
  4051  								if int32(prg.curChar) > ')' || int32(prg.curChar) < '(' {
  4052  									prg.loc = byte(int32(prg.loc) - 1)
  4053  								}
  4054  							}
  4055  							c = prg.getByte()
  4056  							prg.checkTag(c)
  4057  							prg.charTag[c] = byte(ligTag)
  4058  							prg.charRemainder[c] = prg.nl
  4059  						}
  4060  						if int32(prg.minNl) <= int32(prg.nl) {
  4061  							prg.minNl = uint16(int32(prg.nl) + 1)
  4062  						}
  4063  						prg.lkStepEnded = false
  4064  
  4065  					case stopCode:
  4066  						// Read a stop step
  4067  						if !prg.lkStepEnded {
  4068  							if int32(prg.charsOnLine) > 0 {
  4069  								prg.stdout.Writeln(" ")
  4070  							}
  4071  							prg.stdout.Write("STOP must follow LIG or KRN")
  4072  							prg.showErrorContext()
  4073  						} else {
  4074  							prg.ligKern[int32(prg.nl)-1].b0 = byte(stopFlag)
  4075  							prg.lkStepEnded = false
  4076  						}
  4077  
  4078  					case skipCode:
  4079  						// Read a skip step
  4080  						if !prg.lkStepEnded {
  4081  							if int32(prg.charsOnLine) > 0 {
  4082  								prg.stdout.Writeln(" ")
  4083  							}
  4084  							prg.stdout.Write("SKIP must follow LIG or KRN")
  4085  							prg.showErrorContext()
  4086  						} else {
  4087  							c = prg.getByte()
  4088  							if int32(c) >= 128 {
  4089  								if int32(prg.charsOnLine) > 0 {
  4090  									prg.stdout.Writeln(" ")
  4091  								}
  4092  								prg.stdout.Write("Maximum SKIP amount is 127")
  4093  								prg.showErrorContext()
  4094  							} else if int32(prg.nl)+int32(c) >= maxLigSteps {
  4095  								if int32(prg.charsOnLine) > 0 {
  4096  									prg.stdout.Writeln(" ")
  4097  								}
  4098  								prg.stdout.Write("Sorry, LIGTABLE too long for me to handle")
  4099  								prg.showErrorContext()
  4100  							} else {
  4101  								prg.ligKern[int32(prg.nl)-1].b0 = c
  4102  								if int32(prg.minNl) <= int32(prg.nl)+int32(c) {
  4103  									prg.minNl = uint16(int32(prg.nl) + int32(c) + 1)
  4104  								}
  4105  							}
  4106  							prg.lkStepEnded = false
  4107  						}
  4108  
  4109  					case krnCode:
  4110  						// Read a kerning step
  4111  						prg.ligKern[prg.nl].b0 = 0
  4112  						prg.ligKern[prg.nl].b1 = prg.getByte()
  4113  						prg.kern[prg.nk] = prg.getFix()
  4114  						krnPtr = 0
  4115  						for prg.kern[krnPtr] != prg.kern[prg.nk] {
  4116  							krnPtr = uint16(int32(krnPtr) + 1)
  4117  						}
  4118  						if int32(krnPtr) == int32(prg.nk) {
  4119  							if int32(prg.nk) < maxKerns {
  4120  								prg.nk = uint16(int32(prg.nk) + 1)
  4121  							} else {
  4122  								{
  4123  									if int32(prg.charsOnLine) > 0 {
  4124  										prg.stdout.Writeln(" ")
  4125  									}
  4126  									prg.stdout.Write("Sorry, too many different kerns for me to handle")
  4127  									prg.showErrorContext()
  4128  								}
  4129  								// \xref[Sorry, too many different kerns...]
  4130  								krnPtr = uint16(int32(krnPtr) - 1)
  4131  							}
  4132  						}
  4133  						prg.ligKern[prg.nl].b2 = byte(kernFlag + int32(krnPtr)/256)
  4134  						prg.ligKern[prg.nl].b3 = byte(int32(krnPtr) % 256)
  4135  						if int32(prg.nl) >= maxLigSteps-1 {
  4136  							if int32(prg.charsOnLine) > 0 {
  4137  								prg.stdout.Writeln(" ")
  4138  							}
  4139  							prg.stdout.Write("Sorry, LIGTABLE too long for me to handle")
  4140  							prg.showErrorContext()
  4141  						} else {
  4142  							prg.nl = uint16(int32(prg.nl) + 1)
  4143  						}
  4144  						prg.lkStepEnded = true
  4145  
  4146  					case ligCode, ligCode + 1, ligCode + 2, ligCode + 3,
  4147  						ligCode + 5, ligCode + 6, ligCode + 7, ligCode + 11:
  4148  						// Read a ligature step
  4149  						prg.ligKern[prg.nl].b0 = 0
  4150  						prg.ligKern[prg.nl].b2 = byte(int32(prg.curCode) - ligCode)
  4151  						prg.ligKern[prg.nl].b1 = prg.getByte()
  4152  						prg.ligKern[prg.nl].b3 = prg.getByte()
  4153  						if int32(prg.nl) >= maxLigSteps-1 {
  4154  							if int32(prg.charsOnLine) > 0 {
  4155  								prg.stdout.Writeln(" ")
  4156  							}
  4157  							prg.stdout.Write("Sorry, LIGTABLE too long for me to handle")
  4158  							prg.showErrorContext()
  4159  						} else {
  4160  							prg.nl = uint16(int32(prg.nl) + 1)
  4161  						}
  4162  						prg.lkStepEnded = true
  4163  
  4164  					} // there are no other cases |>=label_code|
  4165  					prg.finishTheProperty()
  4166  				}
  4167  			} else if int32(prg.curChar) == ')' {
  4168  				prg.skipToEndOfItem()
  4169  			} else {
  4170  				prg.junkError()
  4171  			}
  4172  		}
  4173  		{
  4174  			prg.loc = byte(int32(prg.loc) - 1)
  4175  			prg.level = prg.level + 1
  4176  			prg.curChar = ')'
  4177  		}
  4178  	}
  4179  }
  4180  
  4181  func (prg *prg) readCharInfo() {
  4182  	var (
  4183  		c byte // the char
  4184  	)
  4185  	{
  4186  		c = prg.getByte() // read the character code that is being specified
  4187  
  4188  		// Print |c| in octal notation
  4189  		{
  4190  			if int32(prg.charsOnLine) == 8 {
  4191  				prg.stdout.Writeln(" ")
  4192  				prg.charsOnLine = 1
  4193  			} else {
  4194  				if int32(prg.charsOnLine) > 0 {
  4195  					prg.stdout.Write(" ")
  4196  				}
  4197  				prg.charsOnLine = byte(int32(prg.charsOnLine) + 1)
  4198  			}
  4199  			prg.printOctal(c) // progress report
  4200  		}
  4201  		for prg.level == 1 {
  4202  			for int32(prg.curChar) == ' ' {
  4203  				prg.getNext()
  4204  			}
  4205  			if int32(prg.curChar) == '(' {
  4206  				prg.getName()
  4207  				if int32(prg.curCode) == commentCode {
  4208  					prg.skipToEndOfItem()
  4209  				} else if int32(prg.curCode) < charWdCode || int32(prg.curCode) > varCharCode {
  4210  					{
  4211  						if int32(prg.charsOnLine) > 0 {
  4212  							prg.stdout.Writeln(" ")
  4213  						}
  4214  						prg.stdout.Write("This property name doesn't belong in a CHARACTER list")
  4215  						prg.showErrorContext()
  4216  					}
  4217  					prg.skipToEndOfItem()
  4218  				} else {
  4219  					switch prg.curCode {
  4220  					case charWdCode:
  4221  						prg.charWd[c] = prg.sortIn(pointer(width), prg.getFix())
  4222  					case charHtCode:
  4223  						prg.charHt[c] = prg.sortIn(pointer(height), prg.getFix())
  4224  					case charDpCode:
  4225  						prg.charDp[c] = prg.sortIn(pointer(depth), prg.getFix())
  4226  					case charIcCode:
  4227  						prg.charIc[c] = prg.sortIn(pointer(italic), prg.getFix())
  4228  					case nextLargerCode:
  4229  						prg.checkTag(c)
  4230  						prg.charTag[c] = byte(listTag)
  4231  						prg.charRemainder[c] = uint16(prg.getByte())
  4232  
  4233  					case mapCode:
  4234  						prg.readPacket(c)
  4235  					case varCharCode:
  4236  						// Read an extensible recipe for |c|
  4237  						if int32(prg.ne) == 256 {
  4238  							if int32(prg.charsOnLine) > 0 {
  4239  								prg.stdout.Writeln(" ")
  4240  							}
  4241  							prg.stdout.Write("At most 256 VARCHAR specs are allowed")
  4242  							prg.showErrorContext()
  4243  						} else {
  4244  							prg.checkTag(c)
  4245  							prg.charTag[c] = byte(extTag)
  4246  							prg.charRemainder[c] = prg.ne
  4247  
  4248  							prg.exten[prg.ne] = prg.zeroBytes
  4249  							for prg.level == 2 {
  4250  								for int32(prg.curChar) == ' ' {
  4251  									prg.getNext()
  4252  								}
  4253  								if int32(prg.curChar) == '(' {
  4254  									prg.getName()
  4255  									if int32(prg.curCode) == commentCode {
  4256  										prg.skipToEndOfItem()
  4257  									} else if int32(prg.curCode) < varCharCode+1 || int32(prg.curCode) > varCharCode+4 {
  4258  										{
  4259  											if int32(prg.charsOnLine) > 0 {
  4260  												prg.stdout.Writeln(" ")
  4261  											}
  4262  											prg.stdout.Write("This property name doesn't belong in a VARCHAR list")
  4263  											prg.showErrorContext()
  4264  										}
  4265  										prg.skipToEndOfItem()
  4266  									} else {
  4267  										switch int32(prg.curCode) - (varCharCode + 1) {
  4268  										case 0:
  4269  											prg.exten[prg.ne].b0 = prg.getByte()
  4270  										case 1:
  4271  											prg.exten[prg.ne].b1 = prg.getByte()
  4272  										case 2:
  4273  											prg.exten[prg.ne].b2 = prg.getByte()
  4274  										case 3:
  4275  											prg.exten[prg.ne].b3 = prg.getByte()
  4276  										}
  4277  
  4278  										prg.finishTheProperty()
  4279  									}
  4280  								} else if int32(prg.curChar) == ')' {
  4281  									prg.skipToEndOfItem()
  4282  								} else {
  4283  									prg.junkError()
  4284  								}
  4285  							}
  4286  							prg.ne = uint16(int32(prg.ne) + 1)
  4287  							{
  4288  								prg.loc = byte(int32(prg.loc) - 1)
  4289  								prg.level = prg.level + 1
  4290  								prg.curChar = ')'
  4291  							}
  4292  						}
  4293  
  4294  					}
  4295  
  4296  					prg.finishTheProperty()
  4297  				}
  4298  			} else if int32(prg.curChar) == ')' {
  4299  				prg.skipToEndOfItem()
  4300  			} else {
  4301  				prg.junkError()
  4302  			}
  4303  		}
  4304  		if int32(prg.charWd[c]) == 0 {
  4305  			prg.charWd[c] = prg.sortIn(pointer(width), fixWord(0))
  4306  		} // legitimatize |c|
  4307  		{
  4308  			prg.loc = byte(int32(prg.loc) - 1)
  4309  			prg.level = prg.level + 1
  4310  			prg.curChar = ')'
  4311  		}
  4312  	}
  4313  }
  4314  
  4315  func (prg *prg) readInput() {
  4316  	var (
  4317  		c byte // header or parameter index
  4318  	)
  4319  	prg.curChar = ' '
  4320  	for {
  4321  		for int32(prg.curChar) == ' ' {
  4322  			prg.getNext()
  4323  		}
  4324  		if int32(prg.curChar) == '(' {
  4325  			prg.getName()
  4326  			if int32(prg.curCode) == commentCode {
  4327  				prg.skipToEndOfItem()
  4328  			} else if int32(prg.curCode) > characterCode {
  4329  				{
  4330  					if int32(prg.charsOnLine) > 0 {
  4331  						prg.stdout.Writeln(" ")
  4332  					}
  4333  					prg.stdout.Write("This property name doesn't belong on the outer level")
  4334  					prg.showErrorContext()
  4335  				}
  4336  				prg.skipToEndOfItem()
  4337  			} else {
  4338  				switch prg.curCode {
  4339  				case checkSumCode:
  4340  					prg.checkSumSpecified = true
  4341  					prg.readFourBytes(headerIndex(checkSumLoc))
  4342  
  4343  				case designSizeCode:
  4344  					// Read the design size
  4345  					prg.nextD = prg.getFix()
  4346  					if prg.nextD < 04000000 {
  4347  						if int32(prg.charsOnLine) > 0 {
  4348  							prg.stdout.Writeln(" ")
  4349  						}
  4350  						prg.stdout.Write("The design size must be at least 1")
  4351  						prg.showErrorContext()
  4352  					} else {
  4353  						prg.designSize = prg.nextD
  4354  					}
  4355  
  4356  				case designUnitsCode:
  4357  					// Read the design units
  4358  					prg.nextD = prg.getFix()
  4359  					if prg.nextD <= 0 {
  4360  						if int32(prg.charsOnLine) > 0 {
  4361  							prg.stdout.Writeln(" ")
  4362  						}
  4363  						prg.stdout.Write("The number of units per design size must be positive")
  4364  						prg.showErrorContext()
  4365  					} else if prg.frozenDu {
  4366  						if int32(prg.charsOnLine) > 0 {
  4367  							prg.stdout.Writeln(" ")
  4368  						}
  4369  						prg.stdout.Write("Sorry, it's too late to change the design units")
  4370  						prg.showErrorContext()
  4371  					} else {
  4372  						prg.designUnits = prg.nextD
  4373  					}
  4374  
  4375  				case codingSchemeCode:
  4376  					prg.readBcpl(headerIndex(codingSchemeLoc), byte(40))
  4377  				case familyCode:
  4378  					prg.readBcpl(headerIndex(familyLoc), byte(20))
  4379  				case faceCode:
  4380  					prg.headerBytes[faceLoc] = prg.getByte()
  4381  				case sevenBitSafeFlagCode:
  4382  					// Read the seven-bit-safe flag
  4383  					for int32(prg.curChar) == ' ' {
  4384  						prg.getNext()
  4385  					}
  4386  					if int32(prg.curChar) == 'T' {
  4387  						prg.sevenBitSafeFlag = true
  4388  					} else if int32(prg.curChar) == 'F' {
  4389  						prg.sevenBitSafeFlag = false
  4390  					} else {
  4391  						if int32(prg.charsOnLine) > 0 {
  4392  							prg.stdout.Writeln(" ")
  4393  						}
  4394  						prg.stdout.Write("The flag value should be \"TRUE\" or \"FALSE\"")
  4395  						prg.showErrorContext()
  4396  					}
  4397  					// \xref[The flag value should be...]
  4398  					for {
  4399  						prg.getNext()
  4400  						if int32(prg.curChar) == '(' || int32(prg.curChar) == ')' {
  4401  							break
  4402  						}
  4403  					}
  4404  
  4405  				case headerCode:
  4406  					// Read an indexed header word
  4407  					c = prg.getByte()
  4408  					if int32(c) < 18 {
  4409  						{
  4410  							if int32(prg.charsOnLine) > 0 {
  4411  								prg.stdout.Writeln(" ")
  4412  							}
  4413  							prg.stdout.Write("HEADER indices should be 18 or more")
  4414  							prg.showErrorContext()
  4415  						}
  4416  						for {
  4417  							prg.getNext()
  4418  							if int32(prg.curChar) == '(' || int32(prg.curChar) == ')' {
  4419  								break
  4420  							}
  4421  						}
  4422  					} else if 4*int32(c)+4 > maxHeaderBytes {
  4423  						{
  4424  							if int32(prg.charsOnLine) > 0 {
  4425  								prg.stdout.Writeln(" ")
  4426  							}
  4427  							prg.stdout.Write("This HEADER index is too big for my present table size")
  4428  							prg.showErrorContext()
  4429  						}
  4430  						for {
  4431  							prg.getNext()
  4432  							if int32(prg.curChar) == '(' || int32(prg.curChar) == ')' {
  4433  								break
  4434  							}
  4435  						}
  4436  					} else {
  4437  						for int32(prg.headerPtr) < 4*int32(c)+4 {
  4438  							prg.headerBytes[prg.headerPtr] = 0
  4439  							prg.headerPtr = byte(int32(prg.headerPtr) + 1)
  4440  						}
  4441  						prg.readFourBytes(headerIndex(4 * int32(c)))
  4442  					}
  4443  
  4444  				case fontDimenCode:
  4445  					// Read font parameter list
  4446  					for prg.level == 1 {
  4447  						for int32(prg.curChar) == ' ' {
  4448  							prg.getNext()
  4449  						}
  4450  						if int32(prg.curChar) == '(' {
  4451  							prg.getName()
  4452  							if int32(prg.curCode) == commentCode {
  4453  								prg.skipToEndOfItem()
  4454  							} else if int32(prg.curCode) < parameterCode || int32(prg.curCode) >= charWdCode {
  4455  								{
  4456  									if int32(prg.charsOnLine) > 0 {
  4457  										prg.stdout.Writeln(" ")
  4458  									}
  4459  									prg.stdout.Write("This property name doesn't belong in a FONTDIMEN list")
  4460  									prg.showErrorContext()
  4461  								}
  4462  								prg.skipToEndOfItem()
  4463  							} else {
  4464  								if int32(prg.curCode) == parameterCode {
  4465  									c = prg.getByte()
  4466  								} else {
  4467  									c = byte(int32(prg.curCode) - parameterCode)
  4468  								}
  4469  								if int32(c) == 0 {
  4470  									{
  4471  										if int32(prg.charsOnLine) > 0 {
  4472  											prg.stdout.Writeln(" ")
  4473  										}
  4474  										prg.stdout.Write("PARAMETER index must not be zero")
  4475  										prg.showErrorContext()
  4476  									}
  4477  									prg.skipToEndOfItem()
  4478  								} else if int32(c) > maxParamWords {
  4479  									{
  4480  										if int32(prg.charsOnLine) > 0 {
  4481  											prg.stdout.Writeln(" ")
  4482  										}
  4483  										prg.stdout.Write("This PARAMETER index is too big for my present table size")
  4484  										prg.showErrorContext()
  4485  									}
  4486  									prg.skipToEndOfItem()
  4487  								} else {
  4488  									for int32(prg.np) < int32(c) {
  4489  										prg.np = byte(int32(prg.np) + 1)
  4490  										prg.param[prg.np-1] = 0
  4491  									}
  4492  									prg.param[c-1] = prg.getFix()
  4493  									prg.finishTheProperty()
  4494  								}
  4495  							}
  4496  						} else if int32(prg.curChar) == ')' {
  4497  							prg.skipToEndOfItem()
  4498  						} else {
  4499  							prg.junkError()
  4500  						}
  4501  					}
  4502  					{
  4503  						prg.loc = byte(int32(prg.loc) - 1)
  4504  						prg.level = prg.level + 1
  4505  						prg.curChar = ')'
  4506  					}
  4507  
  4508  				case ligTableCode:
  4509  					prg.readLigKern()
  4510  				case boundaryCharCode:
  4511  					prg.bchar = uint16(prg.getByte())
  4512  				case virtualTitleCode:
  4513  					prg.vtitleStart = prg.vfPtr
  4514  					prg.copyToEndOfItem()
  4515  					if int32(prg.vfPtr) > int32(prg.vtitleStart)+255 {
  4516  						{
  4517  							if int32(prg.charsOnLine) > 0 {
  4518  								prg.stdout.Writeln(" ")
  4519  							}
  4520  							prg.stdout.Write("VTITLE clipped to 255 characters")
  4521  							prg.showErrorContext()
  4522  						}
  4523  						prg.vtitleLength = 255
  4524  						// \xref[VTITLE clipped...]
  4525  					} else {
  4526  						prg.vtitleLength = byte(int32(prg.vfPtr) - int32(prg.vtitleStart))
  4527  					}
  4528  
  4529  				case mapFontCode:
  4530  					// Read a local font list
  4531  					prg.getFourBytes()
  4532  					prg.fontNumber[prg.fontPtr] = prg.curBytes
  4533  					prg.curFont = 0
  4534  					for int32(prg.fontNumber[prg.curFont].b3) != int32(prg.fontNumber[prg.fontPtr].b3) || int32(prg.fontNumber[prg.curFont].b2) != int32(prg.fontNumber[prg.fontPtr].b2) || int32(prg.fontNumber[prg.curFont].b1) != int32(prg.fontNumber[prg.fontPtr].b1) || int32(prg.fontNumber[prg.curFont].b0) != int32(prg.fontNumber[prg.fontPtr].b0) {
  4535  						prg.curFont = uint16(int32(prg.curFont) + 1)
  4536  					}
  4537  					if int32(prg.curFont) == int32(prg.fontPtr) {
  4538  						if int32(prg.fontPtr) < 256 {
  4539  							prg.fontPtr = uint16(int32(prg.fontPtr) + 1)
  4540  							prg.fnameStart[prg.curFont] = uint16(vfSize)
  4541  							prg.fnameLength[prg.curFont] = 4 // \.[NULL]
  4542  							prg.fareaStart[prg.curFont] = uint16(vfSize)
  4543  							prg.fareaLength[prg.curFont] = 0
  4544  							prg.fontChecksum[prg.curFont] = prg.zeroBytes
  4545  							prg.fontAt[prg.curFont] = 04000000     // denotes design size of this virtual font
  4546  							prg.fontDsize[prg.curFont] = 050000000 // the |fix_word| for 10
  4547  						} else {
  4548  							if int32(prg.charsOnLine) > 0 {
  4549  								prg.stdout.Writeln(" ")
  4550  							}
  4551  							prg.stdout.Write("I can handle only 256 different mapfonts")
  4552  							prg.showErrorContext()
  4553  						}
  4554  					}
  4555  					// \xref[I can handle only 256...]
  4556  					if int32(prg.curFont) == int32(prg.fontPtr) {
  4557  						prg.skipToEndOfItem()
  4558  					} else {
  4559  						for prg.level == 1 {
  4560  							for int32(prg.curChar) == ' ' {
  4561  								prg.getNext()
  4562  							}
  4563  							if int32(prg.curChar) == '(' {
  4564  								prg.getName()
  4565  								if int32(prg.curCode) == commentCode {
  4566  									prg.skipToEndOfItem()
  4567  								} else if int32(prg.curCode) < fontNameCode || int32(prg.curCode) > fontDsizeCode {
  4568  									{
  4569  										if int32(prg.charsOnLine) > 0 {
  4570  											prg.stdout.Writeln(" ")
  4571  										}
  4572  										prg.stdout.Write("This property name doesn't belong in a MAPFONT list")
  4573  										prg.showErrorContext()
  4574  									}
  4575  									prg.skipToEndOfItem()
  4576  								} else {
  4577  									switch prg.curCode {
  4578  									case fontNameCode:
  4579  										// Read a local font name
  4580  										prg.fnameStart[prg.curFont] = prg.vfPtr
  4581  										prg.copyToEndOfItem()
  4582  										if int32(prg.vfPtr) > int32(prg.fnameStart[prg.curFont])+255 {
  4583  											{
  4584  												if int32(prg.charsOnLine) > 0 {
  4585  													prg.stdout.Writeln(" ")
  4586  												}
  4587  												prg.stdout.Write("FONTNAME clipped to 255 characters")
  4588  												prg.showErrorContext()
  4589  											}
  4590  											// \xref[FONTNAME clipped...]
  4591  											prg.fnameLength[prg.curFont] = 255
  4592  										} else {
  4593  											prg.fnameLength[prg.curFont] = byte(int32(prg.vfPtr) - int32(prg.fnameStart[prg.curFont]))
  4594  										}
  4595  
  4596  									case fontAreaCode:
  4597  										// Read a local font area
  4598  										prg.fareaStart[prg.curFont] = prg.vfPtr
  4599  										prg.copyToEndOfItem()
  4600  										if int32(prg.vfPtr) > int32(prg.fareaStart[prg.curFont])+255 {
  4601  											{
  4602  												if int32(prg.charsOnLine) > 0 {
  4603  													prg.stdout.Writeln(" ")
  4604  												}
  4605  												prg.stdout.Write("FONTAREA clipped to 255 characters")
  4606  												prg.showErrorContext()
  4607  											}
  4608  											// \xref[FONTAREA clipped...]
  4609  											prg.fareaLength[prg.curFont] = 255
  4610  										} else {
  4611  											prg.fareaLength[prg.curFont] = byte(int32(prg.vfPtr) - int32(prg.fareaStart[prg.curFont]))
  4612  										}
  4613  
  4614  									case fontChecksumCode:
  4615  										prg.getFourBytes()
  4616  										prg.fontChecksum[prg.curFont] = prg.curBytes
  4617  
  4618  									case fontAtCode:
  4619  										prg.frozenDu = true
  4620  										if prg.designUnits == 04000000 {
  4621  											prg.fontAt[prg.curFont] = prg.getFix()
  4622  										} else {
  4623  											prg.fontAt[prg.curFont] = round(float64(prg.getFix()) / float64(prg.designUnits) * 1048576.0)
  4624  										}
  4625  
  4626  									case fontDsizeCode:
  4627  										prg.fontDsize[prg.curFont] = prg.getFix()
  4628  									} // there are no other cases
  4629  									prg.finishTheProperty()
  4630  								}
  4631  							} else if int32(prg.curChar) == ')' {
  4632  								prg.skipToEndOfItem()
  4633  							} else {
  4634  								prg.junkError()
  4635  							}
  4636  						}
  4637  					}
  4638  					{
  4639  						prg.loc = byte(int32(prg.loc) - 1)
  4640  						prg.level = prg.level + 1
  4641  						prg.curChar = ')'
  4642  					}
  4643  
  4644  				case characterCode:
  4645  					prg.readCharInfo()
  4646  				}
  4647  				prg.finishTheProperty()
  4648  			}
  4649  		} else if int32(prg.curChar) == ')' && !prg.inputHasEnded {
  4650  			{
  4651  				if int32(prg.charsOnLine) > 0 {
  4652  					prg.stdout.Writeln(" ")
  4653  				}
  4654  				prg.stdout.Write("Extra right parenthesis")
  4655  				prg.showErrorContext()
  4656  			}
  4657  			prg.loc = byte(int32(prg.loc) + 1)
  4658  			prg.curChar = ' '
  4659  		} else if !prg.inputHasEnded {
  4660  			prg.junkError()
  4661  		}
  4662  		if prg.inputHasEnded {
  4663  			break
  4664  		}
  4665  	}
  4666  }
  4667  
  4668  func (prg *prg) corrAndCheck() {
  4669  	var (
  4670  		c/* 0..256 */ uint16                   // runs through all character codes
  4671  		hh/* 0..hashSize */ uint16             // an index into |hash_list|
  4672  		ligPtr/* 0..maxLigSteps */ uint16      // an index into |lig_kern|
  4673  		g                                 byte // a character generated by the current character |c|
  4674  	)
  4675  	if int32(prg.nl) > 0 {
  4676  		if int32(prg.charRemainder[256]) < 077777 {
  4677  			prg.ligKern[prg.nl].b0 = 255
  4678  			prg.ligKern[prg.nl].b1 = 0
  4679  			prg.ligKern[prg.nl].b2 = 0
  4680  			prg.ligKern[prg.nl].b3 = 0
  4681  			prg.nl = uint16(int32(prg.nl) + 1)
  4682  		} // |bchar_label| will be stored later
  4683  		for int32(prg.minNl) > int32(prg.nl) {
  4684  			prg.ligKern[prg.nl].b0 = 255
  4685  			prg.ligKern[prg.nl].b1 = 0
  4686  			prg.ligKern[prg.nl].b2 = 0
  4687  			prg.ligKern[prg.nl].b3 = 0
  4688  			prg.nl = uint16(int32(prg.nl) + 1)
  4689  		}
  4690  		if int32(prg.ligKern[int32(prg.nl)-1].b0) == 0 {
  4691  			prg.ligKern[int32(prg.nl)-1].b0 = byte(stopFlag)
  4692  		}
  4693  	}
  4694  	prg.sevenUnsafe = false
  4695  	for ii := int32(0); ii <= 255; ii++ {
  4696  		c = uint16(ii)
  4697  		_ = c
  4698  		if int32(prg.charWd[c]) != 0 {
  4699  			switch prg.charTag[c] {
  4700  			case noTag:
  4701  			case ligTag:
  4702  				// Check ligature program of |c|
  4703  				ligPtr = prg.charRemainder[c]
  4704  				for {
  4705  					if prg.hashInput(ligPtr, c) {
  4706  						if int32(prg.ligKern[ligPtr].b2) < kernFlag {
  4707  							if int32(prg.ligKern[ligPtr].b1) != int32(prg.bchar) {
  4708  								g = prg.ligKern[ligPtr].b1
  4709  								if int32(prg.charWd[g]) == 0 {
  4710  									prg.charWd[g] = prg.sortIn(pointer(width), fixWord(0))
  4711  									prg.stdout.Write("LIG character examined by", " ")
  4712  									prg.printOctal(byte(c))
  4713  									prg.stdout.Writeln(" had no CHARACTER spec.")
  4714  								}
  4715  							}
  4716  							// \xref[LIG character examined...]
  4717  							{
  4718  								g = prg.ligKern[ligPtr].b3
  4719  								if int32(prg.charWd[g]) == 0 {
  4720  									prg.charWd[g] = prg.sortIn(pointer(width), fixWord(0))
  4721  									prg.stdout.Write("LIG character generated by", " ")
  4722  									prg.printOctal(byte(c))
  4723  									prg.stdout.Writeln(" had no CHARACTER spec.")
  4724  								}
  4725  							}
  4726  							// \xref[LIG character generated...]
  4727  							if int32(prg.ligKern[ligPtr].b3) >= 128 {
  4728  								if int32(c) < 128 || int32(c) == 256 {
  4729  									if int32(prg.ligKern[ligPtr].b1) < 128 || int32(prg.ligKern[ligPtr].b1) == int32(prg.bchar) {
  4730  										prg.sevenUnsafe = true
  4731  									}
  4732  								}
  4733  							}
  4734  						} else if int32(prg.ligKern[ligPtr].b1) != int32(prg.bchar) {
  4735  							g = prg.ligKern[ligPtr].b1
  4736  							if int32(prg.charWd[g]) == 0 {
  4737  								prg.charWd[g] = prg.sortIn(pointer(width), fixWord(0))
  4738  								prg.stdout.Write("KRN character examined by", " ")
  4739  								prg.printOctal(byte(c))
  4740  								prg.stdout.Writeln(" had no CHARACTER spec.")
  4741  							}
  4742  						}
  4743  						// \xref[KRN character examined...]
  4744  					}
  4745  					if int32(prg.ligKern[ligPtr].b0) >= stopFlag {
  4746  						ligPtr = prg.nl
  4747  					} else {
  4748  						ligPtr = uint16(int32(ligPtr) + 1 + int32(prg.ligKern[ligPtr].b0))
  4749  					}
  4750  					if int32(ligPtr) >= int32(prg.nl) {
  4751  						break
  4752  					}
  4753  				}
  4754  
  4755  			case listTag:
  4756  				g = byte(prg.charRemainder[c])
  4757  				if int32(g) >= 128 && int32(c) < 128 {
  4758  					prg.sevenUnsafe = true
  4759  				}
  4760  				if int32(prg.charWd[g]) == 0 {
  4761  					prg.charWd[g] = prg.sortIn(pointer(width), fixWord(0))
  4762  					prg.stdout.Write("The character NEXTLARGER than", " ")
  4763  					prg.printOctal(byte(c))
  4764  					prg.stdout.Writeln(" had no CHARACTER spec.")
  4765  				}
  4766  			// \xref[The character NEXTLARGER...]
  4767  			case extTag:
  4768  				// Check the pieces of |exten[c]|
  4769  				if int32(prg.exten[prg.charRemainder[c]].b0) > 0 {
  4770  					g = prg.exten[prg.charRemainder[c]].b0
  4771  					if int32(g) >= 128 && int32(c) < 128 {
  4772  						prg.sevenUnsafe = true
  4773  					}
  4774  					if int32(prg.charWd[g]) == 0 {
  4775  						prg.charWd[g] = prg.sortIn(pointer(width), fixWord(0))
  4776  						prg.stdout.Write("TOP piece of character", " ")
  4777  						prg.printOctal(byte(c))
  4778  						prg.stdout.Writeln(" had no CHARACTER spec.")
  4779  					}
  4780  				}
  4781  				// \xref[TOP piece of character...]
  4782  				if int32(prg.exten[prg.charRemainder[c]].b1) > 0 {
  4783  					g = prg.exten[prg.charRemainder[c]].b1
  4784  					if int32(g) >= 128 && int32(c) < 128 {
  4785  						prg.sevenUnsafe = true
  4786  					}
  4787  					if int32(prg.charWd[g]) == 0 {
  4788  						prg.charWd[g] = prg.sortIn(pointer(width), fixWord(0))
  4789  						prg.stdout.Write("MID piece of character", " ")
  4790  						prg.printOctal(byte(c))
  4791  						prg.stdout.Writeln(" had no CHARACTER spec.")
  4792  					}
  4793  				}
  4794  				// \xref[MID piece of character...]
  4795  				if int32(prg.exten[prg.charRemainder[c]].b2) > 0 {
  4796  					g = prg.exten[prg.charRemainder[c]].b2
  4797  					if int32(g) >= 128 && int32(c) < 128 {
  4798  						prg.sevenUnsafe = true
  4799  					}
  4800  					if int32(prg.charWd[g]) == 0 {
  4801  						prg.charWd[g] = prg.sortIn(pointer(width), fixWord(0))
  4802  						prg.stdout.Write("BOT piece of character", " ")
  4803  						prg.printOctal(byte(c))
  4804  						prg.stdout.Writeln(" had no CHARACTER spec.")
  4805  					}
  4806  				}
  4807  				// \xref[BOT piece of character...]
  4808  				{
  4809  					g = prg.exten[prg.charRemainder[c]].b3
  4810  					if int32(g) >= 128 && int32(c) < 128 {
  4811  						prg.sevenUnsafe = true
  4812  					}
  4813  					if int32(prg.charWd[g]) == 0 {
  4814  						prg.charWd[g] = prg.sortIn(pointer(width), fixWord(0))
  4815  						prg.stdout.Write("REP piece of character", " ")
  4816  						prg.printOctal(byte(c))
  4817  						prg.stdout.Writeln(" had no CHARACTER spec.")
  4818  					}
  4819  				}
  4820  				// \xref[REP piece of character...]
  4821  
  4822  			}
  4823  		}
  4824  	}
  4825  	if int32(prg.charRemainder[256]) < 077777 {
  4826  		c = 256
  4827  		// Check ligature program of |c|
  4828  		{
  4829  			ligPtr = prg.charRemainder[c]
  4830  			for {
  4831  				if prg.hashInput(ligPtr, c) {
  4832  					if int32(prg.ligKern[ligPtr].b2) < kernFlag {
  4833  						if int32(prg.ligKern[ligPtr].b1) != int32(prg.bchar) {
  4834  							g = prg.ligKern[ligPtr].b1
  4835  							if int32(prg.charWd[g]) == 0 {
  4836  								prg.charWd[g] = prg.sortIn(pointer(width), fixWord(0))
  4837  								prg.stdout.Write("LIG character examined by", " ")
  4838  								prg.printOctal(byte(c))
  4839  								prg.stdout.Writeln(" had no CHARACTER spec.")
  4840  							}
  4841  						}
  4842  						// \xref[LIG character examined...]
  4843  						{
  4844  							g = prg.ligKern[ligPtr].b3
  4845  							if int32(prg.charWd[g]) == 0 {
  4846  								prg.charWd[g] = prg.sortIn(pointer(width), fixWord(0))
  4847  								prg.stdout.Write("LIG character generated by", " ")
  4848  								prg.printOctal(byte(c))
  4849  								prg.stdout.Writeln(" had no CHARACTER spec.")
  4850  							}
  4851  						}
  4852  						// \xref[LIG character generated...]
  4853  						if int32(prg.ligKern[ligPtr].b3) >= 128 {
  4854  							if int32(c) < 128 || int32(c) == 256 {
  4855  								if int32(prg.ligKern[ligPtr].b1) < 128 || int32(prg.ligKern[ligPtr].b1) == int32(prg.bchar) {
  4856  									prg.sevenUnsafe = true
  4857  								}
  4858  							}
  4859  						}
  4860  					} else if int32(prg.ligKern[ligPtr].b1) != int32(prg.bchar) {
  4861  						g = prg.ligKern[ligPtr].b1
  4862  						if int32(prg.charWd[g]) == 0 {
  4863  							prg.charWd[g] = prg.sortIn(pointer(width), fixWord(0))
  4864  							prg.stdout.Write("KRN character examined by", " ")
  4865  							prg.printOctal(byte(c))
  4866  							prg.stdout.Writeln(" had no CHARACTER spec.")
  4867  						}
  4868  					}
  4869  					// \xref[KRN character examined...]
  4870  				}
  4871  				if int32(prg.ligKern[ligPtr].b0) >= stopFlag {
  4872  					ligPtr = prg.nl
  4873  				} else {
  4874  					ligPtr = uint16(int32(ligPtr) + 1 + int32(prg.ligKern[ligPtr].b0))
  4875  				}
  4876  				if int32(ligPtr) >= int32(prg.nl) {
  4877  					break
  4878  				}
  4879  			}
  4880  		}
  4881  	}
  4882  	if prg.sevenBitSafeFlag && prg.sevenUnsafe {
  4883  		prg.stdout.Writeln("The font is not really seven-bit-safe!")
  4884  	}
  4885  	// \xref[The font is not...safe]
  4886  
  4887  	// Check for infinite ligature loops
  4888  	if int32(prg.hashPtr) < hashSize {
  4889  		for ii := int32(1); ii <= int32(prg.hashPtr); ii++ {
  4890  			hh = uint16(ii)
  4891  			_ = hh
  4892  			prg.tt = prg.hashList[hh]
  4893  			if int32(prg.class[prg.tt]) > simple {
  4894  				prg.tt = prg.f(prg.tt, indx((int32(prg.hash[prg.tt])-1)/256), indx((int32(prg.hash[prg.tt])-1)%256))
  4895  			}
  4896  		}
  4897  	}
  4898  	if int32(prg.hashPtr) == hashSize || int32(prg.yLigCycle) < 256 {
  4899  		if int32(prg.hashPtr) < hashSize {
  4900  			prg.stdout.Write("Infinite ligature loop starting with ")
  4901  			// \xref[Infinite ligature loop...]
  4902  			if int32(prg.xLigCycle) == 256 {
  4903  				prg.stdout.Write("boundary")
  4904  			} else {
  4905  				prg.printOctal(byte(prg.xLigCycle))
  4906  			}
  4907  			prg.stdout.Write(" and ")
  4908  			prg.printOctal(byte(prg.yLigCycle))
  4909  			prg.stdout.Writeln("!")
  4910  		} else {
  4911  			prg.stdout.Writeln("Sorry, I haven't room for so many ligature/kern pairs!")
  4912  		}
  4913  		// \xref[Sorry, I haven't room...]
  4914  		prg.stdout.Writeln("All ligatures will be cleared.")
  4915  		for ii := int32(0); ii <= 255; ii++ {
  4916  			c = uint16(ii)
  4917  			_ = c
  4918  			if int32(prg.charTag[c]) == ligTag {
  4919  				prg.charTag[c] = byte(noTag)
  4920  				prg.charRemainder[c] = 0
  4921  			}
  4922  		}
  4923  		prg.nl = 0
  4924  		prg.bchar = 256
  4925  		prg.charRemainder[256] = 077777
  4926  	}
  4927  
  4928  	// Doublecheck the lig/kern commands and the extensible recipes
  4929  	if int32(prg.nl) > 0 {
  4930  		for ii := int32(0); ii <= int32(prg.nl)-1; ii++ {
  4931  			ligPtr = uint16(ii)
  4932  			_ = ligPtr
  4933  			if int32(prg.ligKern[ligPtr].b2) < kernFlag {
  4934  				if int32(prg.ligKern[ligPtr].b0) < 255 {
  4935  					{
  4936  						c = uint16(prg.ligKern[ligPtr].b1)
  4937  						if int32(prg.charWd[c]) == 0 {
  4938  							if int32(c) != int32(prg.bchar) {
  4939  								prg.ligKern[ligPtr].b1 = 0 // \1
  4940  								if int32(prg.charWd[0]) == 0 {
  4941  									prg.charWd[0] = prg.sortIn(pointer(width), fixWord(0))
  4942  								}
  4943  								prg.stdout.Write("Unused ", "LIG step", " refers to nonexistent character ")
  4944  								prg.printOctal(byte(c))
  4945  								prg.stdout.Writeln("!")
  4946  							}
  4947  						}
  4948  					}
  4949  					{
  4950  						c = uint16(prg.ligKern[ligPtr].b3)
  4951  						if int32(prg.charWd[c]) == 0 {
  4952  							if int32(c) != int32(prg.bchar) {
  4953  								prg.ligKern[ligPtr].b3 = 0 // \1
  4954  								if int32(prg.charWd[0]) == 0 {
  4955  									prg.charWd[0] = prg.sortIn(pointer(width), fixWord(0))
  4956  								}
  4957  								prg.stdout.Write("Unused ", "LIG step", " refers to nonexistent character ")
  4958  								prg.printOctal(byte(c))
  4959  								prg.stdout.Writeln("!")
  4960  							}
  4961  						}
  4962  					}
  4963  				}
  4964  			} else {
  4965  				c = uint16(prg.ligKern[ligPtr].b1)
  4966  				if int32(prg.charWd[c]) == 0 {
  4967  					if int32(c) != int32(prg.bchar) {
  4968  						prg.ligKern[ligPtr].b1 = 0 // \1
  4969  						if int32(prg.charWd[0]) == 0 {
  4970  							prg.charWd[0] = prg.sortIn(pointer(width), fixWord(0))
  4971  						}
  4972  						prg.stdout.Write("Unused ", "KRN step", " refers to nonexistent character ")
  4973  						prg.printOctal(byte(c))
  4974  						prg.stdout.Writeln("!")
  4975  					}
  4976  				}
  4977  			}
  4978  		}
  4979  	}
  4980  	// \xref[Unused LIG step...]
  4981  	// \xref[Unused KRN step...]
  4982  	if int32(prg.ne) > 0 {
  4983  		for ii := int32(0); ii <= int32(prg.ne)-1; ii++ {
  4984  			g = byte(ii)
  4985  			_ = g
  4986  			{
  4987  				c = uint16(prg.exten[g].b0)
  4988  				if int32(c) > 0 {
  4989  					if int32(prg.charWd[c]) == 0 {
  4990  						prg.exten[g].b0 = 0 // \1
  4991  						if int32(prg.charWd[0]) == 0 {
  4992  							prg.charWd[0] = prg.sortIn(pointer(width), fixWord(0))
  4993  						}
  4994  						prg.stdout.Write("Unused ", "VARCHAR TOP", " refers to nonexistent character ")
  4995  						prg.printOctal(byte(c))
  4996  						prg.stdout.Writeln("!")
  4997  					}
  4998  				}
  4999  			}
  5000  			{
  5001  				c = uint16(prg.exten[g].b1)
  5002  				if int32(c) > 0 {
  5003  					if int32(prg.charWd[c]) == 0 {
  5004  						prg.exten[g].b1 = 0 // \1
  5005  						if int32(prg.charWd[0]) == 0 {
  5006  							prg.charWd[0] = prg.sortIn(pointer(width), fixWord(0))
  5007  						}
  5008  						prg.stdout.Write("Unused ", "VARCHAR MID", " refers to nonexistent character ")
  5009  						prg.printOctal(byte(c))
  5010  						prg.stdout.Writeln("!")
  5011  					}
  5012  				}
  5013  			}
  5014  			{
  5015  				c = uint16(prg.exten[g].b2)
  5016  				if int32(c) > 0 {
  5017  					if int32(prg.charWd[c]) == 0 {
  5018  						prg.exten[g].b2 = 0 // \1
  5019  						if int32(prg.charWd[0]) == 0 {
  5020  							prg.charWd[0] = prg.sortIn(pointer(width), fixWord(0))
  5021  						}
  5022  						prg.stdout.Write("Unused ", "VARCHAR BOT", " refers to nonexistent character ")
  5023  						prg.printOctal(byte(c))
  5024  						prg.stdout.Writeln("!")
  5025  					}
  5026  				}
  5027  			}
  5028  			{
  5029  				c = uint16(prg.exten[g].b3)
  5030  				if int32(prg.charWd[c]) == 0 {
  5031  					prg.exten[g].b3 = 0 // \1
  5032  					if int32(prg.charWd[0]) == 0 {
  5033  						prg.charWd[0] = prg.sortIn(pointer(width), fixWord(0))
  5034  					}
  5035  					prg.stdout.Write("Unused ", "VARCHAR REP", " refers to nonexistent character ")
  5036  					prg.printOctal(byte(c))
  5037  					prg.stdout.Writeln("!")
  5038  				}
  5039  			}
  5040  			// \xref[Unused VARCHAR...]
  5041  		}
  5042  	}
  5043  	for ii := int32(0); ii <= 255; ii++ {
  5044  		c = uint16(ii)
  5045  		_ = c
  5046  
  5047  		// Make sure that |c| is not the largest element of a charlist cycle
  5048  		if int32(prg.charTag[c]) == listTag {
  5049  			g = byte(prg.charRemainder[c])
  5050  			for int32(g) < int32(c) && int32(prg.charTag[g]) == listTag {
  5051  				g = byte(prg.charRemainder[g])
  5052  			}
  5053  			if int32(g) == int32(c) {
  5054  				prg.charTag[c] = byte(noTag)
  5055  				prg.stdout.Write("A cycle of NEXTLARGER characters has been broken at ")
  5056  				// \xref[A cycle of NEXTLARGER...]
  5057  				prg.printOctal(byte(c))
  5058  				prg.stdout.Writeln(".")
  5059  			}
  5060  		}
  5061  	}
  5062  
  5063  	// Put the width, height, depth, and italic lists into final form
  5064  	prg.delta = prg.shorten(pointer(width), 255)
  5065  	prg.setIndices(pointer(width), prg.delta)
  5066  	if prg.delta > 0 {
  5067  		prg.stdout.Writeln("I had to round some " /* \xref[I had to round...]  */, "width", "s by ", float64((prg.delta+1)/2)/float64(04000000), knuth.WriteWidth(1), knuth.WriteWidth(7), " units.")
  5068  	}
  5069  
  5070  	prg.delta = prg.shorten(pointer(height), 15)
  5071  	prg.setIndices(pointer(height), prg.delta)
  5072  	if prg.delta > 0 {
  5073  		prg.stdout.Writeln("I had to round some " /* \xref[I had to round...]  */, "height", "s by ", float64((prg.delta+1)/2)/float64(04000000), knuth.WriteWidth(1), knuth.WriteWidth(7), " units.")
  5074  	}
  5075  
  5076  	prg.delta = prg.shorten(pointer(depth), 15)
  5077  	prg.setIndices(pointer(depth), prg.delta)
  5078  	if prg.delta > 0 {
  5079  		prg.stdout.Writeln("I had to round some " /* \xref[I had to round...]  */, "depth", "s by ", float64((prg.delta+1)/2)/float64(04000000), knuth.WriteWidth(1), knuth.WriteWidth(7), " units.")
  5080  	}
  5081  
  5082  	prg.delta = prg.shorten(pointer(italic), 63)
  5083  	prg.setIndices(pointer(italic), prg.delta)
  5084  	if prg.delta > 0 {
  5085  		prg.stdout.Writeln("I had to round some " /* \xref[I had to round...]  */, "italic correction", "s by ", float64((prg.delta+1)/2)/float64(04000000), knuth.WriteWidth(1), knuth.WriteWidth(7), " units.")
  5086  	}
  5087  
  5088  }
  5089  
  5090  func (prg *prg) vfOutput() {
  5091  	var (
  5092  		c                          byte  // runs through all character codes
  5093  		curFont/* 0..256 */ uint16       // runs through all local fonts
  5094  		k                          int32 // loop index
  5095  	)
  5096  	prg.vfFile.Write(pre)
  5097  	prg.vfFile.Write(idByte)
  5098  	prg.vfFile.Write(prg.vtitleLength)
  5099  	for ii := int32(0); ii <= int32(prg.vtitleLength)-1; ii++ {
  5100  		k = ii
  5101  		_ = k
  5102  		prg.vfFile.Write(prg.vf[int32(prg.vtitleStart)+k])
  5103  	}
  5104  	for ii := int32(checkSumLoc); ii <= designSizeLoc+3; ii++ {
  5105  		k = ii
  5106  		_ = k
  5107  		prg.vfFile.Write(prg.headerBytes[k])
  5108  	}
  5109  	prg.vcount = int32(prg.vtitleLength) + 11
  5110  	for ii := int32(0); ii <= int32(prg.fontPtr)-1; ii++ {
  5111  		curFont = uint16(ii)
  5112  		_ = curFont
  5113  		// Output a local font definition
  5114  		prg.vfFile.Write(fntDef1)
  5115  		prg.vfFile.Write(curFont)
  5116  
  5117  		prg.vfFile.Write(prg.fontChecksum[curFont].b0)
  5118  		prg.vfFile.Write(prg.fontChecksum[curFont].b1)
  5119  		prg.vfFile.Write(prg.fontChecksum[curFont].b2)
  5120  		prg.vfFile.Write(prg.fontChecksum[curFont].b3)
  5121  		prg.voutInt(prg.fontAt[curFont])
  5122  		prg.voutInt(prg.fontDsize[curFont])
  5123  		prg.vfFile.Write(prg.fareaLength[curFont])
  5124  		prg.vfFile.Write(prg.fnameLength[curFont])
  5125  		for ii := int32(0); ii <= int32(prg.fareaLength[curFont])-1; ii++ {
  5126  			k = ii
  5127  			_ = k
  5128  			prg.vfFile.Write(prg.vf[int32(prg.fareaStart[curFont])+k])
  5129  		}
  5130  		if int32(prg.fnameStart[curFont]) == vfSize {
  5131  			prg.vfFile.Write('N')
  5132  			prg.vfFile.Write('U')
  5133  			prg.vfFile.Write('L')
  5134  			prg.vfFile.Write('L')
  5135  		} else {
  5136  			for ii := int32(0); ii <= int32(prg.fnameLength[curFont])-1; ii++ {
  5137  				k = ii
  5138  				_ = k
  5139  				prg.vfFile.Write(prg.vf[int32(prg.fnameStart[curFont])+k])
  5140  			}
  5141  		}
  5142  		prg.vcount = prg.vcount + 12 + int32(prg.fareaLength[curFont]) + int32(prg.fnameLength[curFont])
  5143  	}
  5144  	for ii := int32(prg.bc); ii <= int32(prg.ec); ii++ {
  5145  		c = byte(ii)
  5146  		_ = c
  5147  		if int32(prg.charWd[c]) > 0 {
  5148  			prg.x = prg.memory[prg.charWd[c]]
  5149  			if prg.designUnits != 04000000 {
  5150  				prg.x = round(float64(prg.x) / float64(prg.designUnits) * 1048576.0)
  5151  			}
  5152  			if prg.packetLength[c] > 241 || prg.x < 0 || prg.x >= 0100000000 {
  5153  				prg.vfFile.Write(242)
  5154  				prg.voutInt(prg.packetLength[c])
  5155  				prg.voutInt(int32(c))
  5156  				prg.voutInt(prg.x)
  5157  				prg.vcount = prg.vcount + 13 + prg.packetLength[c]
  5158  			} else {
  5159  				prg.vfFile.Write(prg.packetLength[c])
  5160  				prg.vfFile.Write(c)
  5161  				prg.vfFile.Write(prg.x / 0200000)
  5162  				prg.vfFile.Write(prg.x / 0400 % 256)
  5163  				prg.vfFile.Write(prg.x % 256)
  5164  				prg.vcount = prg.vcount + 5 + prg.packetLength[c]
  5165  			}
  5166  			if int32(prg.packetStart[c]) == vfSize {
  5167  				if int32(c) >= 128 {
  5168  					prg.vfFile.Write(set1)
  5169  				}
  5170  				prg.vfFile.Write(c)
  5171  			} else {
  5172  				for ii := int32(0); ii <= prg.packetLength[c]-1; ii++ {
  5173  					k = ii
  5174  					_ = k
  5175  					prg.vfFile.Write(prg.vf[int32(prg.packetStart[c])+k])
  5176  				}
  5177  			}
  5178  		}
  5179  	}
  5180  	for {
  5181  		prg.vfFile.Write(post)
  5182  		prg.vcount = prg.vcount + 1
  5183  		if prg.vcount%4 == 0 {
  5184  			break
  5185  		}
  5186  	}
  5187  }
  5188  
  5189  // 181.
  5190  
  5191  // tangle:pos vptovf.web:3157:5:
  5192  
  5193  // Here is where \.[VPtoVF] begins and ends.
  5194  func (prg *prg) main() {
  5195  	defer func() {
  5196  		if prg.stderr != nil {
  5197  			prg.stderr.Close()
  5198  		}
  5199  		if prg.stdin != nil {
  5200  			prg.stdin.Close()
  5201  		}
  5202  		if prg.stdout != nil {
  5203  			prg.stdout.Close()
  5204  		}
  5205  		if prg.tfmFile != nil {
  5206  			prg.tfmFile.Close()
  5207  		}
  5208  		if prg.vfFile != nil {
  5209  			prg.vfFile.Close()
  5210  		}
  5211  		if prg.vplFile != nil {
  5212  			prg.vplFile.Close()
  5213  		}
  5214  	}()
  5215  
  5216  	prg.initialize()
  5217  
  5218  	prg.nameEnter()
  5219  
  5220  	prg.readInput()
  5221  	prg.stdout.Writeln(".")
  5222  
  5223  	prg.corrAndCheck()
  5224  
  5225  	// Do the \.[TFM] output
  5226  
  5227  	// Compute the twelve subfile sizes
  5228  	prg.lh = byte(int32(prg.headerPtr) / 4)
  5229  
  5230  	prg.notFound = true
  5231  	prg.bc = 0
  5232  	for prg.notFound {
  5233  		if int32(prg.charWd[prg.bc]) > 0 || int32(prg.bc) == 255 {
  5234  			prg.notFound = false
  5235  		} else {
  5236  			prg.bc = byte(int32(prg.bc) + 1)
  5237  		}
  5238  	}
  5239  	prg.notFound = true
  5240  	prg.ec = 255
  5241  	for prg.notFound {
  5242  		if int32(prg.charWd[prg.ec]) > 0 || int32(prg.ec) == 0 {
  5243  			prg.notFound = false
  5244  		} else {
  5245  			prg.ec = byte(int32(prg.ec) - 1)
  5246  		}
  5247  	}
  5248  	if int32(prg.bc) > int32(prg.ec) {
  5249  		prg.bc = 1
  5250  	}
  5251  	prg.memory[width] = prg.memory[width] + 1
  5252  	prg.memory[height] = prg.memory[height] + 1
  5253  	prg.memory[depth] = prg.memory[depth] + 1
  5254  	prg.memory[italic] = prg.memory[italic] + 1
  5255  
  5256  	// Compute the ligature/kern program offset
  5257  
  5258  	// Insert all labels into |label_table|
  5259  	prg.labelPtr = 0
  5260  	prg.labelTable[0].rr = int16(-1) // sentinel
  5261  	for ii := int32(prg.bc); ii <= int32(prg.ec); ii++ {
  5262  		prg.c = byte(ii)
  5263  		_ = prg.c
  5264  		if int32(prg.charTag[prg.c]) == ligTag {
  5265  			prg.sortPtr = prg.labelPtr // there's a hole at position |sort_ptr+1|
  5266  			for int32(prg.labelTable[prg.sortPtr].rr) > int32(prg.charRemainder[prg.c]) {
  5267  				prg.labelTable[int32(prg.sortPtr)+1] = prg.labelTable[prg.sortPtr]
  5268  				prg.sortPtr = uint16(int32(prg.sortPtr) - 1) // move the hole
  5269  			}
  5270  			prg.labelTable[int32(prg.sortPtr)+1].cc = prg.c
  5271  			prg.labelTable[int32(prg.sortPtr)+1].rr = int16(prg.charRemainder[prg.c])
  5272  			prg.labelPtr = uint16(int32(prg.labelPtr) + 1)
  5273  		}
  5274  	}
  5275  	if int32(prg.bchar) < 256 {
  5276  		prg.extraLocNeeded = true
  5277  		prg.lkOffset = 1
  5278  	} else {
  5279  		prg.extraLocNeeded = false
  5280  		prg.lkOffset = 0
  5281  	}
  5282  
  5283  	// Find the minimum |lk_offset| and adjust all remainders
  5284  	{
  5285  		prg.sortPtr = prg.labelPtr // the largest unallocated label
  5286  		if int32(prg.labelTable[prg.sortPtr].rr)+int32(prg.lkOffset) > 255 {
  5287  			prg.lkOffset = 0
  5288  			prg.extraLocNeeded = false // location 0 can do double duty
  5289  			for {
  5290  				prg.charRemainder[prg.labelTable[prg.sortPtr].cc] = prg.lkOffset
  5291  				for int32(prg.labelTable[int32(prg.sortPtr)-1].rr) == int32(prg.labelTable[prg.sortPtr].rr) {
  5292  					prg.sortPtr = uint16(int32(prg.sortPtr) - 1)
  5293  					prg.charRemainder[prg.labelTable[prg.sortPtr].cc] = prg.lkOffset
  5294  				}
  5295  				prg.lkOffset = uint16(int32(prg.lkOffset) + 1)
  5296  				prg.sortPtr = uint16(int32(prg.sortPtr) - 1)
  5297  				if int32(prg.lkOffset)+int32(prg.labelTable[prg.sortPtr].rr) < 256 {
  5298  					break
  5299  				}
  5300  			}
  5301  			// N.B.: |lk_offset=256| satisfies this when |sort_ptr=0|
  5302  		}
  5303  		if int32(prg.lkOffset) > 0 {
  5304  			for int32(prg.sortPtr) > 0 {
  5305  				prg.charRemainder[prg.labelTable[prg.sortPtr].cc] = uint16(int32(prg.charRemainder[prg.labelTable[prg.sortPtr].cc]) + int32(prg.lkOffset))
  5306  				prg.sortPtr = uint16(int32(prg.sortPtr) - 1)
  5307  			}
  5308  		}
  5309  	}
  5310  	if int32(prg.charRemainder[256]) < 077777 {
  5311  		prg.ligKern[int32(prg.nl)-1].b2 = byte((int32(prg.charRemainder[256]) + int32(prg.lkOffset)) / 256)
  5312  		prg.ligKern[int32(prg.nl)-1].b3 = byte((int32(prg.charRemainder[256]) + int32(prg.lkOffset)) % 256)
  5313  	}
  5314  	prg.lf = uint16(6 + int32(prg.lh) + (int32(prg.ec) - int32(prg.bc) + 1) + prg.memory[width] + prg.memory[height] + prg.memory[depth] + prg.memory[italic] + int32(prg.nl) + int32(prg.lkOffset) + int32(prg.nk) + int32(prg.ne) + int32(prg.np))
  5315  
  5316  	// Output the twelve subfile sizes
  5317  	prg.tfmFile.Write(int32(prg.lf) / 256)
  5318  	prg.tfmFile.Write(int32(prg.lf) % 256)
  5319  	prg.tfmFile.Write(int32(prg.lh) / 256)
  5320  	prg.tfmFile.Write(int32(prg.lh) % 256)
  5321  	prg.tfmFile.Write(int32(prg.bc) / 256)
  5322  	prg.tfmFile.Write(int32(prg.bc) % 256)
  5323  	prg.tfmFile.Write(int32(prg.ec) / 256)
  5324  	prg.tfmFile.Write(int32(prg.ec) % 256)
  5325  	prg.tfmFile.Write(prg.memory[width] / 256)
  5326  	prg.tfmFile.Write(prg.memory[width] % 256)
  5327  	prg.tfmFile.Write(prg.memory[height] / 256)
  5328  	prg.tfmFile.Write(prg.memory[height] % 256)
  5329  	prg.tfmFile.Write(prg.memory[depth] / 256)
  5330  	prg.tfmFile.Write(prg.memory[depth] % 256)
  5331  	prg.tfmFile.Write(prg.memory[italic] / 256)
  5332  	prg.tfmFile.Write(prg.memory[italic] % 256)
  5333  	prg.tfmFile.Write((int32(prg.nl) + int32(prg.lkOffset)) / 256)
  5334  	prg.tfmFile.Write((int32(prg.nl) + int32(prg.lkOffset)) % 256)
  5335  	prg.tfmFile.Write(int32(prg.nk) / 256)
  5336  	prg.tfmFile.Write(int32(prg.nk) % 256)
  5337  	prg.tfmFile.Write(int32(prg.ne) / 256)
  5338  	prg.tfmFile.Write(int32(prg.ne) % 256)
  5339  	prg.tfmFile.Write(int32(prg.np) / 256)
  5340  	prg.tfmFile.Write(int32(prg.np) % 256)
  5341  
  5342  	// Output the header block
  5343  	if !prg.checkSumSpecified {
  5344  		prg.curBytes.b0 = prg.bc
  5345  		prg.curBytes.b1 = prg.ec
  5346  		prg.curBytes.b2 = prg.bc
  5347  		prg.curBytes.b3 = prg.ec
  5348  		for ii := int32(prg.bc); ii <= int32(prg.ec); ii++ {
  5349  			prg.c = byte(ii)
  5350  			_ = prg.c
  5351  			if int32(prg.charWd[prg.c]) > 0 {
  5352  				prg.tempWidth = prg.memory[prg.charWd[prg.c]]
  5353  				if prg.designUnits != 04000000 {
  5354  					prg.tempWidth = round(float64(prg.tempWidth) / float64(prg.designUnits) * 1048576.0)
  5355  				}
  5356  				prg.tempWidth = prg.tempWidth + (int32(prg.c)+4)*020000000 // this should be positive
  5357  				prg.curBytes.b0 = byte((int32(prg.curBytes.b0) + int32(prg.curBytes.b0) + prg.tempWidth) % 255)
  5358  				prg.curBytes.b1 = byte((int32(prg.curBytes.b1) + int32(prg.curBytes.b1) + prg.tempWidth) % 253)
  5359  				prg.curBytes.b2 = byte((int32(prg.curBytes.b2) + int32(prg.curBytes.b2) + prg.tempWidth) % 251)
  5360  				prg.curBytes.b3 = byte((int32(prg.curBytes.b3) + int32(prg.curBytes.b3) + prg.tempWidth) % 247)
  5361  			}
  5362  		}
  5363  		prg.headerBytes[checkSumLoc] = prg.curBytes.b0
  5364  		prg.headerBytes[checkSumLoc+1] = prg.curBytes.b1
  5365  		prg.headerBytes[checkSumLoc+2] = prg.curBytes.b2
  5366  		prg.headerBytes[checkSumLoc+3] = prg.curBytes.b3
  5367  	}
  5368  	prg.headerBytes[designSizeLoc] = byte(prg.designSize / 0100000000)
  5369  	// this works since |design_size>0|
  5370  	prg.headerBytes[designSizeLoc+1] = byte(prg.designSize / 0200000 % 256)
  5371  	prg.headerBytes[designSizeLoc+2] = byte(prg.designSize / 256 % 256)
  5372  	prg.headerBytes[designSizeLoc+3] = byte(prg.designSize % 256)
  5373  	if !prg.sevenUnsafe {
  5374  		prg.headerBytes[sevenFlagLoc] = 128
  5375  	}
  5376  	for ii := int32(0); ii <= int32(prg.headerPtr)-1; ii++ {
  5377  		prg.j = byte(ii)
  5378  		_ = prg.j
  5379  		prg.tfmFile.Write(prg.headerBytes[prg.j])
  5380  	}
  5381  
  5382  	// Output the character info
  5383  	prg.index[0] = 0
  5384  	for ii := int32(prg.bc); ii <= int32(prg.ec); ii++ {
  5385  		prg.c = byte(ii)
  5386  		_ = prg.c
  5387  		prg.tfmFile.Write(prg.index[prg.charWd[prg.c]])
  5388  		prg.tfmFile.Write(int32(prg.index[prg.charHt[prg.c]])*16 + int32(prg.index[prg.charDp[prg.c]]))
  5389  		prg.tfmFile.Write(int32(prg.index[prg.charIc[prg.c]])*4 + int32(prg.charTag[prg.c]))
  5390  		prg.tfmFile.Write(prg.charRemainder[prg.c])
  5391  	}
  5392  
  5393  	// Output the dimensions themselves
  5394  	for ii := int32(width); ii <= italic; ii++ {
  5395  		prg.q = byte(ii)
  5396  		_ = prg.q
  5397  		prg.tfmFile.Write(0)
  5398  		prg.tfmFile.Write(0)
  5399  		prg.tfmFile.Write(0)
  5400  		prg.tfmFile.Write(0)    // output the zero word
  5401  		prg.p = prg.link[prg.q] // head of list
  5402  		for int32(prg.p) > 0 {
  5403  			prg.outScaled(prg.memory[prg.p])
  5404  			prg.p = prg.link[prg.p]
  5405  		}
  5406  	}
  5407  
  5408  	// Output the ligature/kern program
  5409  	if prg.extraLocNeeded {
  5410  		prg.tfmFile.Write(255)
  5411  		prg.tfmFile.Write(prg.bchar)
  5412  		prg.tfmFile.Write(0)
  5413  		prg.tfmFile.Write(0)
  5414  	} else {
  5415  		for ii := int32(1); ii <= int32(prg.lkOffset); ii++ {
  5416  			prg.sortPtr = uint16(ii)
  5417  			_ = prg.sortPtr // output the redirection specs
  5418  			prg.t = uint16(prg.labelTable[prg.labelPtr].rr)
  5419  			if int32(prg.bchar) < 256 {
  5420  				prg.tfmFile.Write(255)
  5421  				prg.tfmFile.Write(prg.bchar)
  5422  			} else {
  5423  				prg.tfmFile.Write(254)
  5424  				prg.tfmFile.Write(0)
  5425  			}
  5426  			prg.tfmFile.Write((int32(prg.t) + int32(prg.lkOffset)) / 256)
  5427  			prg.tfmFile.Write((int32(prg.t) + int32(prg.lkOffset)) % 256)
  5428  			for {
  5429  				prg.labelPtr = uint16(int32(prg.labelPtr) - 1)
  5430  				if int32(prg.labelTable[prg.labelPtr].rr) < int32(prg.t) {
  5431  					break
  5432  				}
  5433  			}
  5434  		}
  5435  	}
  5436  	if int32(prg.nl) > 0 {
  5437  		for ii := int32(0); ii <= int32(prg.nl)-1; ii++ {
  5438  			prg.ligPtr = uint16(ii)
  5439  			_ = prg.ligPtr
  5440  			prg.tfmFile.Write(prg.ligKern[prg.ligPtr].b0)
  5441  			prg.tfmFile.Write(prg.ligKern[prg.ligPtr].b1)
  5442  			prg.tfmFile.Write(prg.ligKern[prg.ligPtr].b2)
  5443  			prg.tfmFile.Write(prg.ligKern[prg.ligPtr].b3)
  5444  		}
  5445  	}
  5446  	if int32(prg.nk) > 0 {
  5447  		for ii := int32(0); ii <= int32(prg.nk)-1; ii++ {
  5448  			prg.krnPtr = uint16(ii)
  5449  			_ = prg.krnPtr
  5450  			prg.outScaled(prg.kern[prg.krnPtr])
  5451  		}
  5452  	}
  5453  
  5454  	// Output the extensible character recipes
  5455  	if int32(prg.ne) > 0 {
  5456  		for ii := int32(0); ii <= int32(prg.ne)-1; ii++ {
  5457  			prg.c = byte(ii)
  5458  			_ = prg.c
  5459  			prg.tfmFile.Write(prg.exten[prg.c].b0)
  5460  			prg.tfmFile.Write(prg.exten[prg.c].b1)
  5461  			prg.tfmFile.Write(prg.exten[prg.c].b2)
  5462  			prg.tfmFile.Write(prg.exten[prg.c].b3)
  5463  		}
  5464  	}
  5465  
  5466  	// Output the parameters
  5467  	for ii := int32(1); ii <= int32(prg.np); ii++ {
  5468  		prg.parPtr = byte(ii)
  5469  		_ = prg.parPtr
  5470  		if int32(prg.parPtr) == 1 {
  5471  			if prg.param[1-1] < 0 {
  5472  				prg.param[1-1] = prg.param[1-1] + 010000000000
  5473  				prg.tfmFile.Write(prg.param[1-1]/0100000000 + 256 - 64)
  5474  			} else {
  5475  				prg.tfmFile.Write(prg.param[1-1] / 0100000000)
  5476  			}
  5477  			prg.tfmFile.Write(prg.param[1-1] / 0200000 % 256)
  5478  			prg.tfmFile.Write(prg.param[1-1] / 256 % 256)
  5479  			prg.tfmFile.Write(prg.param[1-1] % 256)
  5480  		} else {
  5481  			prg.outScaled(prg.param[prg.parPtr-1])
  5482  		}
  5483  	}
  5484  	prg.vfOutput()
  5485  }
  5486  
  5487  // 182. System-dependent changes
  5488  
  5489  // tangle:pos vptovf.web:3169:25:
  5490  
  5491  // This section should be replaced, if necessary, by changes to the program
  5492  // that are necessary to make \.[VPtoVF] work at a particular installation.
  5493  // It is usually best to design your change file so that all changes to
  5494  // previous sections preserve the section numbering; then everybody's version
  5495  // will be consistent with the printed program. More extensive changes,
  5496  // which introduce new sections, can be inserted here; then only the index
  5497  // itself will get a new section number.
  5498  // \xref[system dependencies]
  5499  
  5500  // 183. Index
  5501  
  5502  // tangle:pos vptovf.web:3179:6:
  5503  
  5504  // Pointers to error messages appear here together with the section numbers
  5505  // where each ident\-i\-fier is used.