modernc.org/knuth@v0.0.4/web/testdata/ctan.org/tex-archive/systems/knuth/local/mfware-sparc/pktype.web (about) 1 % PKtype.web 2 % 3 % PKtype verifies the correctness of a PK file. 4 % 5 % Preliminary 0.0 version: May, 1985 6 % First release, 0.9 version: 8 May 1985 7 % Updated to reflect new pk format, 2.0 version: 25 July 1985 8 % Updated again for new pk format, 2.1 version: 15 August 1985 9 % Docmentation updated, 2.2 version: 17 November 1987 10 % 11 % slight editing to correspond with MFware report -- don, 21 Oct 89 12 % additional editing suggested by P Breitenlohner -- don, 18 Nov 89 13 % Corrected two typos -- 21 Dec 96 (don) 14 15 \def\versiondate{18 November 1989} 16 % 17 \def\hang{\hangindent 3em\noindent\ignorespaces} 18 \font\ninerm=cmr9 19 \font\logo=logo10 % font used for the METAFONT logo 20 \def\MF{{\logo META}\-{\logo FONT}} 21 \def\PASCAL{Pascal} 22 \def\tamu{Texas A\char38 M} 23 \def\(#1){} % this is used to make section names sort themselves better 24 \def\9#1{} % this is used for sort keys in the index 25 \def\title{PKtype} 26 \def\contentspagenumber{0} 27 \def\topofcontents{\null 28 \def\titlepage{F} % include headline on the contents page 29 \def\rheader{\mainfont\hfil \contentspagenumber} 30 \vfill 31 \centerline{\titlefont The {\ttitlefont PKtype} processor} 32 \vskip 15pt 33 \centerline{(Version 2.3, \versiondate)} 34 \vfill} 35 \def\botofcontents{\vfill 36 \centerline{\hsize 5in\baselineskip9pt 37 \vbox{\ninerm\noindent 38 The preparation of this report 39 was supported in part by the National Science 40 Foundation under grants IST-8201926 and MCS-8300984, 41 and by the System Development Foundation. `\TeX' is a 42 trademark of the American Mathematical Society.}}} 43 \pageno=\contentspagenumber \advance\pageno by 1 44 45 @* Introduction. 46 This program reads a \.{PK} file, verifies that it is in the correct 47 format, and writes it in textual format. 48 49 @ The |banner| string defined here should be changed whenever \.{PKtype} 50 gets modified. 51 52 @d banner=='This is PKtype, Version 2.3' {printed when the program starts} 53 54 @ This program is written in standard \PASCAL, except where it is necessary 55 to use extensions; for example, \.{PKtype} must read files whose names 56 are dynamically specified, and that would be impossible in pure \PASCAL. 57 58 @d othercases == others: {default for cases not listed explicitly} 59 @d endcases == @+end {follows the default case in an extended |case| statement} 60 @f othercases == else 61 @f endcases == end 62 63 @ Both the input and output come from binary files. On line interaction 64 is handled through \PASCAL's standard |input| and |output| files. Two macros 65 are used to write to the type file, so this output can easily be redirected. 66 67 @d print_ln(#)==write_ln(output,#) 68 @d print(#)==write(output,#) 69 @d t_print_ln(#)==write_ln(typ_file,#) 70 @d t_print(#)==write(typ_file,#) 71 72 @p program PKtype(@!input,@!output); 73 label @<Labels in the outer block@>@/ 74 const @<Constants in the outer block@>@/ 75 type @<Types in the outer block@>@/ 76 var @<Globals in the outer block@>@/ 77 procedure initialize; {this procedure gets things started properly} 78 var i:integer; {loop index for initializations} 79 begin print_ln(banner);@/ 80 @<Set initial values@>@/ 81 end; 82 83 @ If the program has to stop prematurely, it goes to the 84 `|final_end|'. 85 86 @d final_end=9999 {label for the end of it all} 87 88 @<Labels...@>=final_end; 89 90 @ These constants determine the maximum length of a file name and the length 91 of the terminal line, as well as the widest character that can be translated. 92 @^system dependencies@> 93 94 @<Constants...@>= 95 @!name_length=80; {maximum length of a file name} 96 @!terminal_line_length=132; {maximum length of an input line} 97 98 @ Here are some macros for common programming idioms. 99 100 @d incr(#) == #:=#+1 {increase a variable by unity} 101 @d decr(#) == #:=#-1 {decrease a variable by unity} 102 @d do_nothing == {empty statement} 103 104 @ It is possible that a malformed packed file (heaven forbid!) or some other 105 error might be detected by this program. Such errors might occur in a deeply 106 nested procedure, so the procedure called |jump_out| has been added to transfer 107 to the very end of the program with an error message. 108 109 @d abort(#)==begin print_ln(' ',#); t_print_ln(' ',#); jump_out; end 110 111 @p procedure jump_out; 112 begin goto final_end; 113 end; 114 115 @* The character set. 116 Like all programs written with the \.{WEB} system, \.{PKtype} can be 117 used with any character set. But it uses ASCII code internally, because 118 the programming for portable input-output is easier when a fixed internal 119 code is used. 120 121 The next few sections of \.{PKtype} have therefore been copied from the 122 analogous ones in the \.{WEB} system routines. They have been considerably 123 simplified, since \.{PKtype} need not deal with the controversial 124 ASCII codes less than @'40 or greater than @'176. 125 126 @<Types...@>= 127 @!ASCII_code=" ".."~"; {a subrange of the integers} 128 129 @ The original \PASCAL\ compiler was designed in the late 60s, when six-bit 130 character sets were common, so it did not make provision for lower case 131 letters. Nowadays, of course, we need to deal with both upper and lower case 132 alphabets in a convenient way, especially in a program like \.{PKtype}. 133 So we shall assume that the \PASCAL\ system being used for \.{PKtype} 134 has a character set containing at least the standard visible characters 135 of ASCII code (|"!"| through |"~"|). 136 137 Some \PASCAL\ compilers use the original name |char| for the data type 138 associated with the characters in text files, while other \PASCAL s 139 consider |char| to be a 64-element subrange of a larger data type that has 140 some other name. In order to accommodate this difference, we shall use 141 the name |text_char| to stand for the data type of the characters in the 142 output file. We shall also assume that |text_char| consists of 143 the elements |chr(first_text_char)| through |chr(last_text_char)|, 144 inclusive. The following definitions should be adjusted if necessary. 145 @^system dependencies@> 146 147 @d text_char == char {the data type of characters in text files} 148 @d first_text_char=0 {ordinal number of the smallest element of |text_char|} 149 @d last_text_char=127 {ordinal number of the largest element of |text_char|} 150 151 @<Types...@>= 152 @!text_file=packed file of text_char; 153 154 @ The \.{PKtype} processor converts between ASCII code and 155 the user's external character set by means of arrays |xord| and |xchr| 156 that are analogous to \PASCAL's |ord| and |chr| functions. 157 158 @<Globals...@>= 159 @!xord: array [text_char] of ASCII_code; 160 {specifies conversion of input characters} 161 @!xchr: array [0..255] of text_char; 162 {specifies conversion of output characters} 163 164 @ Under our assumption that the visible characters of standard ASCII are 165 all present, the following assignment statements initialize the 166 |xchr| array properly, without needing any system-dependent changes. 167 168 @<Set init...@>= 169 for i:=0 to @'37 do xchr[i]:='?'; 170 xchr[@'40]:=' '; 171 xchr[@'41]:='!'; 172 xchr[@'42]:='"'; 173 xchr[@'43]:='#'; 174 xchr[@'44]:='$'; 175 xchr[@'45]:='%'; 176 xchr[@'46]:='&'; 177 xchr[@'47]:='''';@/ 178 xchr[@'50]:='('; 179 xchr[@'51]:=')'; 180 xchr[@'52]:='*'; 181 xchr[@'53]:='+'; 182 xchr[@'54]:=','; 183 xchr[@'55]:='-'; 184 xchr[@'56]:='.'; 185 xchr[@'57]:='/';@/ 186 xchr[@'60]:='0'; 187 xchr[@'61]:='1'; 188 xchr[@'62]:='2'; 189 xchr[@'63]:='3'; 190 xchr[@'64]:='4'; 191 xchr[@'65]:='5'; 192 xchr[@'66]:='6'; 193 xchr[@'67]:='7';@/ 194 xchr[@'70]:='8'; 195 xchr[@'71]:='9'; 196 xchr[@'72]:=':'; 197 xchr[@'73]:=';'; 198 xchr[@'74]:='<'; 199 xchr[@'75]:='='; 200 xchr[@'76]:='>'; 201 xchr[@'77]:='?';@/ 202 xchr[@'100]:='@@'; 203 xchr[@'101]:='A'; 204 xchr[@'102]:='B'; 205 xchr[@'103]:='C'; 206 xchr[@'104]:='D'; 207 xchr[@'105]:='E'; 208 xchr[@'106]:='F'; 209 xchr[@'107]:='G';@/ 210 xchr[@'110]:='H'; 211 xchr[@'111]:='I'; 212 xchr[@'112]:='J'; 213 xchr[@'113]:='K'; 214 xchr[@'114]:='L'; 215 xchr[@'115]:='M'; 216 xchr[@'116]:='N'; 217 xchr[@'117]:='O';@/ 218 xchr[@'120]:='P'; 219 xchr[@'121]:='Q'; 220 xchr[@'122]:='R'; 221 xchr[@'123]:='S'; 222 xchr[@'124]:='T'; 223 xchr[@'125]:='U'; 224 xchr[@'126]:='V'; 225 xchr[@'127]:='W';@/ 226 xchr[@'130]:='X'; 227 xchr[@'131]:='Y'; 228 xchr[@'132]:='Z'; 229 xchr[@'133]:='['; 230 xchr[@'134]:='\'; 231 xchr[@'135]:=']'; 232 xchr[@'136]:='^'; 233 xchr[@'137]:='_';@/ 234 xchr[@'140]:='`'; 235 xchr[@'141]:='a'; 236 xchr[@'142]:='b'; 237 xchr[@'143]:='c'; 238 xchr[@'144]:='d'; 239 xchr[@'145]:='e'; 240 xchr[@'146]:='f'; 241 xchr[@'147]:='g';@/ 242 xchr[@'150]:='h'; 243 xchr[@'151]:='i'; 244 xchr[@'152]:='j'; 245 xchr[@'153]:='k'; 246 xchr[@'154]:='l'; 247 xchr[@'155]:='m'; 248 xchr[@'156]:='n'; 249 xchr[@'157]:='o';@/ 250 xchr[@'160]:='p'; 251 xchr[@'161]:='q'; 252 xchr[@'162]:='r'; 253 xchr[@'163]:='s'; 254 xchr[@'164]:='t'; 255 xchr[@'165]:='u'; 256 xchr[@'166]:='v'; 257 xchr[@'167]:='w';@/ 258 xchr[@'170]:='x'; 259 xchr[@'171]:='y'; 260 xchr[@'172]:='z'; 261 xchr[@'173]:='{'; 262 xchr[@'174]:='|'; 263 xchr[@'175]:='}'; 264 xchr[@'176]:='~'; 265 for i:=@'177 to 255 do xchr[i]:='?'; 266 267 @ The following system-independent code makes the |xord| array contain a 268 suitable inverse to the information in |xchr|. 269 270 @<Set init...@>= 271 for i:=first_text_char to last_text_char do xord[chr(i)]:=@'40; 272 for i:=" " to "~" do xord[xchr[i]]:=i; 273 274 @* Packed file format. 275 The packed file format is a compact representation of the data contained in a 276 \.{GF} file. The information content is the same, but packed (\.{PK}) files 277 are almost always less than half the size of their \.{GF} counterparts. They 278 are also easier to convert into a raster representation because they do not 279 have a profusion of \\{paint}, \\{skip}, and \\{new\_row} commands to be 280 separately interpreted. In addition, the \.{PK} format expressly forbids 281 \&{special} commands within a character. The minimum bounding box for each 282 character is explicit in the format, and does not need to be scanned for as in 283 the \.{GF} format. Finally, the width and escapement values are combined with 284 the raster information into character ``packets'', making it simpler in many 285 cases to process a character. 286 287 A \.{PK} file is organized as a stream of 8-bit bytes. At times, these bytes 288 might be split into 4-bit nybbles or single bits, or combined into multiple 289 byte parameters. When bytes are split into smaller pieces, the `first' piece 290 is always the most significant of the byte. For instance, the first bit of 291 a byte is the bit with value 128; the first nybble can be found by dividing 292 a byte by 16. Similarly, when bytes are combined into multiple byte 293 parameters, the first byte is the most significant of the parameter. If the 294 parameter is signed, it is represented by two's-complement notation. 295 296 The set of possible eight-bit values is separated into two sets, those that 297 introduce a character definition, and those that do not. The values that 298 introduce a character definition range from 0 to 239; byte values 299 above 239 are interpreted as commands. Bytes that introduce character 300 definitions are called flag bytes, and various fields within the byte indicate 301 various things about how the character definition is encoded. Command bytes 302 have zero or more parameters, and can never appear within a character 303 definition or between parameters of another command, where they would be 304 interpeted as data. 305 306 A \.{PK} file consists of a preamble, followed by a sequence of one or more 307 character definitions, followed by a postamble. The preamble command must 308 be the first byte in the file, followed immediately by its parameters. 309 Any number of character definitions may follow, and any command but the 310 preamble command and the postamble command may occur between character 311 definitions. The very last command in the file must be the postamble. 312 313 @ The packed file format is intended to be easy to read and interpret by 314 device drivers. The small size of the file reduces the input/output overhead 315 each time a font is loaded. For those drivers that load and save each font 316 file into memory, the small size also helps reduce the memory requirements. 317 The length of each character packet is specified, allowing the character raster 318 data to be loaded into memory by simply counting bytes, rather than 319 interpreting each command; then, each character can be interpreted on a demand 320 basis. This also makes it possible for a driver to skip a particular 321 character quickly if it knows that the character is unused. 322 323 @ First, the command bytes will be presented; then the format of the 324 character definitions will be defined. Eight of the possible sixteen 325 commands (values 240 through 255) are currently defined; the others are 326 reserved for future extensions. The commands are listed below. Each command 327 is specified by its symbolic name (e.g., \\{pk\_no\_op}), its opcode byte, 328 and any parameters. The parameters are followed by a bracketed number 329 telling how many bytes they occupy, with the number preceded by a plus sign if 330 it is a signed quantity. (Four byte quantities are always signed, however.) 331 332 \yskip\hang|pk_xxx1| 240 |k[1]| |x[k]|. This command is undefined in general; 333 it functions as a $(k+2)$-byte \\{no\_op} unless special \.{PK}-reading 334 programs are being used. \MF\ generates \\{xxx} commands when encountering 335 a \&{special} string. It is recommended that |x| be a string having the form 336 of a keyword followed by possible parameters relevant to that keyword. 337 338 \yskip\hang\\{pk\_xxx2} 241 |k[2]| |x[k]|. Like |pk_xxx1|, but |0<=k<65536|. 339 340 \yskip\hang\\{pk\_xxx3} 242 |k[3]| |x[k]|. Like |pk_xxx1|, but 341 |0<=k<@t$2^{24}$@>|. \MF\ uses this when sending a \&{special} string whose 342 length exceeds~255. 343 344 \yskip\hang\\{pk\_xxx4} 243 |k[4]| |x[k]|. Like |pk_xxx1|, but |k| can be 345 ridiculously large; |k| musn't be negative. 346 347 \yskip\hang|pk_yyy| 244 |y[4]|. This command is undefined in general; it 348 functions as a five-byte \\{no\_op} unless special \.{PK} reading programs 349 are being used. \MF\ puts |scaled| numbers into |yyy|'s, as a result of 350 \&{numspecial} commands; the intent is to provide numeric parameters to 351 \\{xxx} commands that immediately precede. 352 353 \yskip\hang|pk_post| 245. Beginning of the postamble. This command is 354 followed by enough |pk_no_op| commands to make the file a multiple 355 of four bytes long. Zero through three bytes are usual, but any number 356 is allowed. 357 This should make the file easy to read on machines that pack four bytes to 358 a word. 359 360 \yskip\hang|pk_no_op| 246. No operation, do nothing. Any number of 361 |pk_no_op|'s may appear between \.{PK} commands, but a |pk_no_op| cannot be 362 inserted between a command and its parameters, between two parameters, or 363 inside a character definition. 364 365 \yskip\hang|pk_pre| 247 |i[1]| |k[1]| |x[k]| |ds[4]| |cs[4]| |hppp[4]| 366 |vppp[4]|. Preamble command. Here, |i| is the identification byte of the 367 file, currently equal to 89. The string |x| is merely a comment, usually 368 indicating the source of the \.{PK} file. The parameters |ds| and |cs| are 369 the design size of the file in $1/2^{20}$ points, and the checksum of the 370 file, respectively. The checksum should match the \.{TFM} file and the 371 \.{GF} files for this font. Parameters |hppp| and |vppp| are the ratios 372 of pixels per point, horizontally and vertically, multiplied by $2^{16}$; they 373 can be used to correlate the font with specific device resolutions, 374 magnifications, and ``at sizes''. Usually, the name of the \.{PK} file is 375 formed by concatenating the font name (e.g., cmr10) with the resolution at 376 which the font is prepared in pixels per inch multiplied by the magnification 377 factor, and the letters \.{pk}. For instance, cmr10 at 300 dots per inch 378 should be named \.{cmr10.300pk}; at one thousand dots per inch and magstephalf, 379 it should be named \.{cmr10.1095pk}. 380 381 @ We put a few of the above opcodes into definitions for symbolic use by 382 this program. 383 384 @d pk_id = 89 {the version of \.{PK} file described} 385 @d pk_xxx1 = 240 {\&{special} commands} 386 @d pk_yyy = 244 {\&{numspecial} commands} 387 @d pk_post = 245 {postamble} 388 @d pk_no_op = 246 {no operation} 389 @d pk_pre = 247 {preamble} 390 @d pk_undefined == 248, 249, 250, 251, 252, 253, 254, 255 391 392 @ The \.{PK} format has two conflicting goals: to pack character raster and 393 size information as compactly as possible, while retaining ease of translation 394 into raster and other forms. A suitable compromise was found in the use of 395 run-encoding of the raster information. Instead of packing the individual 396 bits of the character, we instead count the number of consecutive `black' or 397 `white' pixels in a horizontal raster row, and then encode this number. Run 398 counts are found for each row from left to right, traversing rows from the 399 top to bottom. This is essentially the way the \.{GF} format works. 400 Instead of presenting each row individually, however, we concatenate all 401 of the horizontal raster rows into one long string of pixels, and encode this 402 row. With knowledge of the width of the bit-map, the original character glyph 403 can easily be reconstructed. In addition, we do not need special commands to 404 mark the end of one row and the beginning of the next. 405 406 Next, we place the burden of finding the minimum bounding box on the part 407 of the font generator, since the characters will usually be used much more 408 often than they are generated. The minimum bounding box is the smallest 409 rectangle that encloses all `black' pixels of a character. We also 410 eliminate the need for a special end of character marker, by supplying 411 exactly as many bits as are required to fill the minimum bounding box, from 412 which the end of the character is implicit. 413 414 Let us next consider the distribution of the run counts. Analysis of several 415 dozen pixel files at 300 dots per inch yields a distribution peaking at four, 416 falling off slowly until ten, then a bit more steeply until twenty, and then 417 asymptotically approaching the horizontal. Thus, the great majority of our 418 run counts will fit in a four-bit nybble. The eight-bit byte is attractive for 419 our run-counts, as it is the standard on many systems; however, the wasted four 420 bits in the majority of cases seem a high price to pay. Another possibility 421 is to use a Huffman-type encoding scheme with a variable number of bits for 422 each run-count; this was rejected because of the overhead in fetching and 423 examining individual bits in the file. Thus, the character raster definitions 424 in the \.{PK} file format are based on the four-bit nybble. 425 426 @ An analysis of typical pixel files yielded another interesting statistic: 427 Fully 37\char`\%\ 428 of the raster rows were duplicates of the previous row. Thus, the \.{PK} 429 format allows the specification of repeat counts, which indicate how many times 430 a horizontal raster row is to be repeated. These repeated rows are taken out 431 of the character glyph before individual rows are concatenated into the long 432 string of pixels. 433 434 For elegance, we disallow a run count of zero. The case of a null raster 435 description should be gleaned from the character width and height being equal 436 to zero, and no raster data should be read. No other zero counts are ever 437 necessary. Also, in the absence of repeat counts, the repeat value is set to 438 be zero (only the original row is sent.) If a repeat count is seen, it takes 439 effect on the current row. The current row is defined as the row on which the 440 first pixel of the next run count will lie. The repeat count is set back to 441 zero when the last pixel in the current row is seen, and the row is sent out. 442 443 This poses a problem for entirely black and entirely white rows, however. Let 444 us say that the current row ends with four white pixels, and then we have five 445 entirely empty rows, followed by a black pixel at the beginning of the next 446 row, and the character width is ten pixels. We would like to use a repeat 447 count, but there is no legal place to put it. If we put it before the white 448 run count, it will apply to the current row. If we put it after, it applies 449 to the row with the black pixel at the beginning. Thus, entirely white or 450 entirely black repeated rows are always packed as large run counts (in this 451 case, a white run count of 54) rather than repeat counts. 452 453 @ Now we turn our attention to the actual packing of the run counts and 454 repeat counts into nybbles. There are only sixteen possible nybble values. 455 We need to indicate run counts and repeat counts. Since the run counts are 456 much more common, we will devote the majority of the nybble values to them. 457 We therefore indicate a repeat count by a nybble of 14 followed by a packed 458 number, where a packed number will be explained later. Since the repeat 459 count value of one is so common, we indicate a repeat one command by a single 460 nybble of 15. A 14 followed by the packed number 1 is still legal for a 461 repeat one count. The run counts are coded directly as packed 462 numbers. 463 464 For packed numbers, therefore, we have the nybble values 0 through 13. We 465 need to represent the positive integers up to, say, $2^{31}-1$. We would 466 like the more common smaller numbers to take only one or two nybbles, and 467 the infrequent large numbers to take three or more. We could therefore 468 allocate one nybble value to indicate a large run count taking three or more 469 nybbles. We do this with the value 0. 470 471 @ We are left with the values 1 through 13. We can allocate some of these, say 472 |dyn_f|, to be one-nybble run counts. 473 These will work for the run counts |1..dyn_f|. For subsequent run 474 counts, we will use a nybble greater than |dyn_f|, followed by a second nybble, 475 whose value can run from 0 through 15. Thus, the two-nybble values will 476 run from |dyn_f+1..(13-dyn_f)*16+dyn_f|. We have our definition of large run 477 count values now, being all counts greater than |(13-dyn_f)*16+dyn_f|. 478 479 We can analyze our several dozen pixel files and determine an optimal value of 480 |dyn_f|, and use this value for all of the characters. Unfortunately, values 481 of |dyn_f| that pack small characters well tend to pack the large characters 482 poorly, and values that pack large characters well are not efficient for the 483 smaller characters. Thus, we choose the optimal |dyn_f| on a character basis, 484 picking the value that will pack each individual character in the smallest 485 number of nybbles. Legal values of |dyn_f| run from 0 (with no one-nybble run 486 counts) to 13 (with no two-nybble run counts). 487 488 @ Our only remaining task in the coding of packed numbers is the large run 489 counts. We use a scheme suggested by D.~E.~Knuth 490 @^Knuth, Donald Ervin@> 491 that simply and elegantly represents arbitrarily large values. The 492 general scheme to represent an integer |i| is to write its hexadecimal 493 representation, with leading zeros removed. Then we count the number of 494 digits, and prepend one less than that many zeros before the hexadecimal 495 representation. Thus, the values from one to fifteen occupy one nybble; 496 the values sixteen through 255 occupy three, the values 256 through 4095 497 require five, etc. 498 499 For our purposes, however, we have already represented the numbers one 500 through |(13-dyn_f)*16+dyn_f|. In addition, the one-nybble values have 501 already been taken by our other commands, which means that only the values 502 from sixteen up are available to us for long run counts. Thus, we simply 503 normalize our long run counts, by subtracting |(13-dyn_f)*16+dyn_f+1| and 504 adding 16, and then we represent the result according to the scheme above. 505 506 @ The final algorithm for decoding the run counts based on the above scheme 507 looks like this, assuming that a procedure called \\{get\_nyb} is available 508 to get the next nybble from the file, and assuming that the global 509 |repeat_count| indicates whether a row needs to be repeated. Note that this 510 routine is recursive, but since a repeat count can never directly follow 511 another repeat count, it can only be recursive to one level. 512 513 @<Packed number procedure@>= 514 function pk_packed_num : integer ; 515 var i, @!j : integer ; 516 begin 517 i := get_nyb ; 518 if i = 0 then begin 519 repeat j := get_nyb ; incr(i) ; until j <> 0 ; 520 while i > 0 do begin j := j * 16 + get_nyb ; decr(i) ; end ; 521 pk_packed_num := j - 15 + (13-dyn_f)*16 + dyn_f ; 522 end else if i <= dyn_f then 523 pk_packed_num := i 524 else if i < 14 then 525 pk_packed_num := (i-dyn_f-1)*16+get_nyb+dyn_f+1 526 else begin 527 if repeat_count <> 0 then abort('Second repeat count for this row!') ; 528 @.Second repeat count...@> 529 repeat_count := 1; {prevent recursion more than one level} 530 if i = 14 then repeat_count := pk_packed_num; 531 send_out(true, repeat_count) ; 532 pk_packed_num := pk_packed_num ; 533 end ; 534 end ; 535 536 @ For low resolution fonts, or characters with `gray' areas, run encoding can 537 often make the character many times larger. Therefore, for those characters 538 that cannot be encoded efficiently with run counts, the \.{PK} format allows 539 bit-mapping of the characters. This is indicated by a |dyn_f| value of 540 14. The bits are packed tightly, by concatenating all of the horizontal raster 541 rows into one long string, and then packing this string eight bits to a byte. 542 The number of bytes required can be calculated by |(width*height+7) div 8|. 543 This format should only be used when packing the character by run counts takes 544 more bytes than this, although, of course, it is legal for any character. 545 Any extra bits in the last byte should be set to zero. 546 547 @ At this point, we are ready to introduce the format for a character 548 descriptor. It consists of three parts: a flag byte, a character preamble, 549 and the raster data. The most significant four bits of the flag byte 550 yield the |dyn_f| value for that character. (Notice that only values of 551 0 through 14 are legal for |dyn_f|, with 14 indicating a bit mapped character; 552 thus, the flag bytes do not conflict with the command bytes, whose upper nybble 553 is always 15.) The next bit (with weight 8) indicates whether the first run 554 count is a black count or a white count, with a one indicating a black count. 555 For bit-mapped characters, this bit should be set to a zero. The next bit 556 (with weight 4) indicates whether certain later parameters (referred to as size 557 parameters) are given in one-byte or two-byte quantities, with a one indicating 558 that they are in two-byte quantities. The last two bits are concatenated on to 559 the beginning of the packet-length parameter in the character preamble, 560 which will be explained below. 561 562 However, if the last three bits of the flag byte are all set (normally 563 indicating that the size parameters are two-byte values and that a 3 should be 564 prepended to the length parameter), then a long format of the character 565 preamble should be used instead of one of the short forms. 566 567 Therefore, there are three formats for the character preamble; the one that 568 is used depends on the least significant three bits of the flag byte. If the 569 least significant three bits are in the range zero through three, the short 570 format is used. If they are in the range four through six, the extended short 571 format is used. Otherwise, if the least significant bits are all set, then 572 the long form of the character preamble is used. The preamble formats are 573 explained below. 574 575 \yskip\hang Short form: |flag[1]| |pl[1]| |cc[1]| |tfm[3]| |dm[1]| |w[1]| 576 |h[1]| |hoff[+1]| |voff[+1]|. 577 If this format of the character preamble is used, the above 578 parameters must all fit in the indicated number of bytes, signed or unsigned 579 as indicated. Almost all of the standard \TeX\ font characters fit; the few 580 exceptions are fonts such as \.{cminch}. 581 582 \yskip\hang Extended short form: |flag[1]| |pl[2]| |cc[1]| |tfm[3]| |dm[2]| 583 |w[2]| |h[2]| |hoff[+2]| |voff[+2]|. Larger characters use this extended 584 format. 585 586 \yskip\hang Long form: |flag[1]| |pl[4]| |cc[4]| |tfm[4]| |dx[4]| |dy[4]| 587 |w[4]| |h[4]| |hoff[4]| |voff[4]|. This is the general format that 588 allows all of the 589 parameters of the \.{GF} file format, including vertical escapement. 590 \vskip\baselineskip 591 The |flag| parameter is the flag byte. The parameter |pl| (packet length) 592 contains the offset 593 of the byte following this character descriptor, with respect to the beginning 594 of the |tfm| width parameter. This is given so a \.{PK} reading program can, 595 once it has read the flag byte, packet length, and character code (|cc|), skip 596 over the character by simply reading this many more bytes. For the two short 597 forms of the character preamble, the last two bits of the flag byte should be 598 considered the two most-significant bits of the packet length. For the short 599 format, the true packet length might be calculated as |(flag mod 4)*256+pl|; 600 for the short extended format, it might be calculated as 601 |(flag mod 4)*65536+pl|. 602 603 The |w| parameter is the width and the |h| parameter is the height in pixels 604 of the minimum bounding box. The |dx| and |dy| parameters are the horizontal 605 and vertical escapements, respectively. In the short formats, |dy| is assumed 606 to be zero and |dm| is |dx| but in pixels; 607 in the long format, |dx| and |dy| are both 608 in pixels multiplied by $2^{16}$. The |hoff| is the horizontal offset from the 609 upper left pixel to the reference pixel; the |voff| is the vertical offset. 610 They are both given in pixels, with right and down being positive. The 611 reference pixel is the pixel that occupies the unit square in \MF; the 612 \MF\ reference point is the lower left hand corner of this pixel. (See the 613 example below.) 614 615 @ \TeX\ requires all characters that have the same character codes 616 modulo 256 to have also the same |tfm| widths and escapement values. The \.{PK} 617 format does not itself make this a requirement, but in order for the font to 618 work correctly with the \TeX\ software, this constraint should be observed. 619 (The standard version of \TeX\ cannot output character codes greater 620 than 255, but extended versions do exist.) 621 622 Following the character preamble is the raster information for the 623 character, packed by run counts or by bits, as indicated by the flag byte. 624 If the character is packed by run counts and the required number of nybbles 625 is odd, then the last byte of the raster description should have a zero 626 for its least significant nybble. 627 628 @ As an illustration of the \.{PK} format, the character \char4\ from the font 629 amr10 at 300 dots per inch will be encoded. This character was chosen 630 because it illustrates some 631 of the borderline cases. The raster for the character looks like this (the 632 row numbers are chosen for convenience, and are not \MF's row numbers.) 633 634 \vskip\baselineskip 635 {\def\smbox{\vrule height 7pt width 7pt depth 0pt \hskip 3pt}% 636 \catcode`\*=\active \let*=\smbox 637 \centerline{\vbox{\baselineskip=10pt 638 \halign{\hfil#\quad&&\hfil#\hfil\cr 639 0& & &*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*\cr 640 1& & &*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*\cr 641 2& & &*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*\cr 642 3& & &*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*\cr 643 4& & &*&*& & & & & & & & & & & & & & & & &*&*\cr 644 5& & &*&*& & & & & & & & & & & & & & & & &*&*\cr 645 6& & &*&*& & & & & & & & & & & & & & & & &*&*\cr 646 7\cr 647 8\cr 648 9& & & & &*&*& & & & & & & & & & & & &*&*& & \cr 649 10& & & & &*&*& & & & & & & & & & & & &*&*& & \cr 650 11& & & & &*&*& & & & & & & & & & & & &*&*& & \cr 651 12& & & & &*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*& & \cr 652 13& & & & &*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*& & \cr 653 14& & & & &*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*& & \cr 654 15& & & & &*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*& & \cr 655 16& & & & &*&*& & & & & & & & & & & & &*&*& & \cr 656 17& & & & &*&*& & & & & & & & & & & & &*&*& & \cr 657 18& & & & &*&*& & & & & & & & & & & & &*&*& & \cr 658 19\cr 659 20\cr 660 21\cr 661 22& & &*&*& & & & & & & & & & & & & & & & &*&*\cr 662 23& & &*&*& & & & & & & & & & & & & & & & &*&*\cr 663 24& & &*&*& & & & & & & & & & & & & & & & &*&*\cr 664 25& & &*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*\cr 665 26& & &*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*\cr 666 27& & &*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*\cr 667 28&+& &*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*&*\cr 668 &\hphantom{*}&\hphantom{*}\cr 669 }}}} 670 The width of the minimum bounding box for this character is 20; its height 671 is 29. The `+' represents the reference pixel; notice how it lies outside the 672 minimum bounding box. The |hoff| value is $-2$, and the |voff| is~28. 673 674 The first task is to calculate the run counts and repeat counts. The repeat 675 counts are placed at the first transition (black to white or white to black) 676 in a row, and are enclosed in brackets. White counts are enclosed in 677 parentheses. It is relatively easy to generate the counts list: 678 \vskip\baselineskip 679 \centerline{82 [2] (16) 2 (42) [2] 2 (12) 2 (4) [3]} 680 \centerline{16 (4) [2] 2 (12) 2 (62) [2] 2 (16) 82} 681 \vskip\baselineskip 682 Note that any duplicated rows that are not all white or all black are removed 683 before the run counts are calculated. The rows thus removed are rows 5, 6, 684 10, 11, 13, 14, 15, 17, 18, 23, and 24. 685 686 @ The next step in the encoding of this character is to calculate the optimal 687 value of |dyn_f|. The details of how this calculation is done are not 688 important here; suffice it to say that there is a simple algorithm that can 689 determine the best value of |dyn_f| in one pass over the count list. For this 690 character, the optimal value turns out to be 8 (atypically low). Thus, all 691 count values less than or equal to 8 are packed in one nybble; those from 692 nine to $(13-8)*16+8$ or 88 are packed in two nybbles. The run encoded values 693 now become (in hex, separated according to the above list): 694 \vskip\baselineskip 695 \centerline{\tt D9 E2 97 2 B1 E2 2 93 2 4 E3} 696 \centerline{\tt 97 4 E2 2 93 2 C5 E2 2 97 D9} 697 \vskip\baselineskip\noindent 698 which comes to 36 nybbles, or 18 bytes. This is shorter than the 73 bytes 699 required for the bit map, so we use the run count packing. 700 701 @ The short form of the character preamble is used because all of the 702 parameters fit in their respective lengths. The packet length is therefore 703 18 bytes for the raster, plus 704 eight bytes for the character preamble parameters following the character 705 code, or 26. The |tfm| width for this character is 640796, or {\tt 9C71C} in 706 hexadecimal. The horizontal escapement is 25 pixels. The flag byte is 707 88 hex, indicating the short preamble, the black first count, and the 708 |dyn_f| value of 8. The final total character packet, in hexadecimal, is: 709 \vskip\baselineskip 710 $$\vbox{\halign{\hfil #\quad&&{\tt #\ }\cr 711 Flag byte&88\cr 712 Packet length&1A\cr 713 Character code&04\cr 714 |tfm| width&09&C7&1C\cr 715 Horizontal escapement (pixels)&19\cr 716 Width of bit map&14\cr 717 Height of bit map&1D\cr 718 Horizontal offset (signed)&FE\cr 719 Vertical offset&1C\cr 720 Raster data&D9&E2&97\cr 721 &2B&1E&22\cr 722 &93&24&E3\cr 723 &97&4E&22\cr 724 &93&2C&5E\cr 725 &22&97&D9\cr}}$$ 726 727 @* Input and output. 728 There are two types of files that this program must deal with---standard 729 text files and files of bytes (packed files.) 730 For our purposes, we shall consider an eight-bit byte to consist of the 731 values |0..255|. If your system does not pack these values to a byte, it is 732 no major difficulty; you must only insure that the input function 733 |pk_byte| can read packed bytes. 734 735 @<Types...@>= 736 @!eight_bits=0..255; {packed file byte} 737 @!byte_file=packed file of eight_bits ; {for packed file words} 738 @^system dependencies@> 739 740 @ @<Glob...@>= 741 @!pk_file:byte_file; {where the input comes from} 742 @!typ_file:text_file; {where the final output goes} 743 @^system dependencies@> 744 745 @ To prepare these files for input and output, we |reset| and |rewrite| them. 746 An extension of \PASCAL\ is needed, since we want to associate files 747 with external names that are specified dynamically (i.e., not 748 known at compile time). The following code assumes that `|reset(f,s)|' 749 does this, when |f| is a file variable and |s| is a string variable that 750 specifies the file name. If |eof(f)| is true immediately after 751 |reset(f,s)| has acted, we assume that no file named |s| is accessible. 752 @^system dependencies@> 753 754 @p procedure open_pk_file; {prepares the input for reading} 755 begin reset(pk_file,pk_name); 756 pk_loc := 0 ; 757 end; 758 @# 759 procedure open_typ_file; {prepares to write text data to the |typ_file|} 760 begin rewrite(typ_file,typ_name); 761 end; 762 763 @ We need a place to store the names of the input and output file, as well 764 as a byte counter for the output file. 765 766 @<Glob...@>= 767 @!pk_name,@!typ_name:packed array[1..name_length] of char; {name of input 768 and output files} 769 @!pk_loc:integer; {how many bytes have we read?} 770 771 @ We also need a function that will get a single byte from the \.{pk} file. 772 773 @p function pk_byte : eight_bits ; 774 var temp : eight_bits ; 775 begin 776 temp := pk_file^ ; 777 get(pk_file) ; 778 incr(pk_loc) ; 779 pk_byte := temp ; 780 end ; 781 782 @ Now we are ready to open the files. 783 784 @<Open files@>= 785 open_pk_file ; 786 open_typ_file ; 787 t_print_ln(banner) ; 788 t_print('Input file: ') ; 789 i := 1 ; 790 while pk_name[i] <> ' ' do begin 791 t_print(pk_name[i]) ; incr(i) ; 792 end ; 793 t_print_ln(' ') 794 795 @ As we are reading the packed file, we often need to fetch 16 and 32 bit 796 quantities. Here we have two procedures to do this. 797 798 @p function get_16 : integer ; 799 var a : integer ; 800 begin a := pk_byte ; get_16 := a * 256 + pk_byte ; end ; 801 @# 802 function get_32 : integer ; 803 var a : integer ; 804 begin a := get_16 ; if a > 32767 then a := a - 65536 ; 805 get_32 := a * 65536 + get_16 ; end ; 806 807 @ We still need the |term_pos| variable. 808 809 @<Glob...@>= 810 @!term_pos : integer ; {current terminal position} 811 812 @ Now we read and check the preamble of the \.{PK} file. In the preamble, we 813 find the |hppp|, |design_size|, |checksum|. 814 815 @<Read preamble@>= 816 if pk_byte <> pk_pre then abort('Bad PK file: pre command missing!') ; 817 @.pre command missing@> 818 if pk_byte <> pk_id then abort('Wrong version of PK file!') ; 819 @.Wrong version of PK file@> 820 j := pk_byte ; 821 t_print('''') ; 822 for i := 1 to j do t_print(xchr[pk_byte]) ; 823 t_print_ln('''') ; 824 design_size := get_32 ; 825 t_print_ln('Design size = ',design_size:1) ; 826 checksum := get_32 ; 827 t_print_ln('Checksum = ',checksum:1) ; 828 hppp := get_32 ; vppp := get_32 ; 829 t_print('Resolution: horizontal = ',hppp:1,' vertical = ',vppp:1) ; 830 magnification := round(hppp * 72.27 / 65536) ; 831 t_print_ln(' (',magnification:1,' dpi)') ; 832 if hppp <> vppp then print_ln('Warning: aspect ratio not 1:1!') 833 834 @ Of course, we need to define the above variables. 835 836 @<Glob...@>= 837 @!magnification : integer ; {resolution at which pixel file is prepared} 838 @!design_size : integer ; {design size in FIXes} 839 @!checksum : integer ; {checksum of pixel file} 840 @!hppp, @!vppp : integer ; {horizontal and vertical points per inch} 841 842 @* Character unpacking. 843 Here we simply unpack the character, writing the information we glean to the 844 |typ_file|. 845 846 @<Unpack and write character@>= 847 t_print((pk_loc-1):1,': Flag byte = ',flag_byte:1) ; 848 dyn_f := flag_byte div 16 ; 849 flag_byte := flag_byte mod 16 ; 850 turn_on := flag_byte >= 8 ; 851 if turn_on then flag_byte := flag_byte - 8 ; 852 if flag_byte = 7 then 853 @<Read long character preamble@> 854 else if flag_byte > 3 then 855 @<Read extended short character preamble@> 856 else 857 @<Read short character preamble@> ; 858 t_print_ln(' Character = ',car:1,' Packet length = ', 859 packet_length:1) ; 860 t_print_ln(' Dynamic packing variable = ',dyn_f:1) ; 861 t_print(' TFM width = ',tfm_width:1,' dx = ',dx:1) ; 862 if dy <> 0 then t_print_ln(' dy = ',dy:1) else t_print_ln(' ') ; 863 t_print_ln(' Height = ',height:1,' Width = ',width:1,' X-offset = ', 864 x_off:1, ' Y-offset = ',y_off:1) ; 865 @<Read and translate raster description@> ; 866 if end_of_packet <> pk_loc then abort('Bad PK file: Bad packet length!') 867 @.Bad packet length@> 868 869 @ We need a whole lot of globals used but not defined up there. 870 871 @<Glob...@>= 872 @!i, @!j : integer ; {index pointers} 873 @!flag_byte : integer ; {the byte that introduces the character definition} 874 @!end_of_packet : integer ; {where we expect the end of the packet to be} 875 @!width, @!height : integer ; {width and height of character} 876 @!x_off, @!y_off : integer ; {x and y offsets of character} 877 @!tfm_width : integer ; {character tfm width} 878 @!tfms : array [0..255] of integer ; {character tfm widths} 879 @!dx, @!dy : integer ; {escapement values} 880 @!dxs, @!dys : array [0..255] of integer ; {escapement values} 881 @!status : array[0..255] of boolean ; {has the character been seen?} 882 @!dyn_f : integer ; {dynamic packing variable} 883 @!car : integer ; {the character we are reading} 884 @!packet_length : integer ; {the length of the character packet} 885 886 @ Now, the preamble reading modules. First, we have the general case: the 887 long character preamble format. 888 889 @<Read long character preamble@>= 890 begin 891 packet_length := get_32 ; car := get_32 ; 892 end_of_packet := packet_length + pk_loc ; 893 packet_length := packet_length + 9 ; 894 tfm_width := get_32 ; 895 dx := get_32 ; dy := get_32 ; 896 width := get_32 ; 897 height := get_32 ; 898 x_off := get_32 ; y_off := get_32 ; 899 end 900 901 @ This module reads the character preamble with double byte parameters. 902 903 @<Read extended short character preamble@>= 904 begin 905 packet_length := (flag_byte - 4) * 65536 + get_16 ; 906 car := pk_byte ; 907 end_of_packet := packet_length + pk_loc ; 908 packet_length := packet_length + 4 ; 909 i := pk_byte ; 910 tfm_width := i * 65536 + get_16 ; 911 dx := get_16 * 65536 ; 912 dy := 0 ; 913 width := get_16 ; 914 height := get_16 ; 915 x_off := get_16 ; y_off := get_16 ; 916 if x_off > 32767 then x_off := x_off - 65536 ; 917 if y_off > 32767 then y_off := y_off - 65536 ; 918 end 919 920 @ Here we read the most common character preamble, that with single byte 921 parameters. 922 923 @<Read short character preamble@>= 924 begin 925 packet_length := flag_byte * 256 + pk_byte ; 926 car := pk_byte ; 927 end_of_packet := packet_length + pk_loc ; 928 packet_length := packet_length + 3 ; 929 i := pk_byte ; 930 tfm_width := i * 65536 + get_16 ; 931 dx := pk_byte * 65536 ; 932 dy := 0 ; 933 width := pk_byte ; 934 height := pk_byte ; 935 x_off := pk_byte ; y_off := pk_byte ; 936 if x_off > 127 then x_off := x_off - 256 ; 937 if y_off > 127 then y_off := y_off - 256 ; 938 end 939 940 @ Now we have the most important part of the program, where we actually 941 interpret the commands in the raster description. First of all, we need 942 a procedure to get a single nybble from the file, as well as one to get 943 a single bit. 944 945 @p function get_nyb : integer ; 946 var temp : eight_bits ; 947 begin 948 if bit_weight = 0 then begin 949 input_byte := pk_byte ; 950 bit_weight := 16 ; 951 end ; 952 temp := input_byte div bit_weight ; 953 input_byte := input_byte - temp * bit_weight ; 954 bit_weight := bit_weight div 16 ; 955 get_nyb := temp ; 956 end ; 957 @# 958 function get_bit : boolean ; 959 var temp : boolean ; 960 begin 961 bit_weight := bit_weight div 2 ; 962 if bit_weight = 0 then begin 963 input_byte := pk_byte ; 964 bit_weight := 128 ; 965 end ; 966 temp := input_byte >= bit_weight ; 967 if temp then 968 input_byte := input_byte - bit_weight ; 969 get_bit := temp ; 970 end ; 971 972 @ We also need a function to write output to the screen. We put as many 973 counts on a line as possible, to reduce the volume of output. Each count 974 will appear as a number, with white counts enclosed by parentheses and repeat 975 counts by brackets. 976 977 @p procedure send_out(@!repeat_count: boolean ; @!value : integer ) ; 978 var i, len : integer ; 979 begin 980 i := 10 ; len := 1 ; 981 while value >= i do begin incr(len) ; i := i * 10 ; end ; 982 if repeat_count or not turn_on then len := len + 2 ; 983 if term_pos + len > 78 then begin 984 term_pos := len + 2 ; t_print_ln(' ') ; t_print(' ') ; 985 end else term_pos := term_pos + len ; 986 if repeat_count then t_print('[', value:1, ']') 987 else if turn_on then t_print(value:1) 988 else t_print('(', value:1, ')') ; 989 end ; 990 @<Packed number procedure@> 991 992 @ Now, the globals to help communication between these procedures. 993 994 @<Glob...@>= 995 @!input_byte : eight_bits ; {the byte we are currently decimating} 996 @!bit_weight : eight_bits ; {weight of the current bit} 997 @!nybble : eight_bits ; {the current nybble} 998 999 @ And the main procedure. 1000 1001 @<Read and translate raster description@>= 1002 bit_weight := 0 ; 1003 if dyn_f = 14 then 1004 @<Get raster by bits@> 1005 else @<Create normally packed raster@> 1006 1007 @ If |dyn_f=14|, then we need to get the raster representation 1008 one bit at a time. 1009 1010 @<Get raster by bits@>= 1011 begin 1012 for i := 1 to height do begin 1013 t_print(' ') ; 1014 for j := 1 to width do 1015 if get_bit then t_print('*') 1016 else t_print('.') ; 1017 t_print_ln(' ') ; 1018 end; 1019 end 1020 1021 @ Otherwise, we translate the bit counts into the raster rows. |count| 1022 contains the number of bits of the current color, and |turn_on| indicates 1023 whether or not they should be black. |rows_left| contains the number of 1024 rows to be sent. 1025 1026 @<Create normally packed raster@>= 1027 begin 1028 term_pos := 2 ; 1029 t_print(' ') ; 1030 rows_left := height ; 1031 h_bit := width ; 1032 repeat_count := 0 ; 1033 while rows_left > 0 do begin 1034 count := pk_packed_num ; 1035 send_out(false, count) ; 1036 if count >= h_bit then begin 1037 rows_left := rows_left - repeat_count - 1 ; 1038 repeat_count := 0 ; 1039 count := count - h_bit ; 1040 h_bit := width ; 1041 rows_left := rows_left - count div width ; 1042 count := count mod width ; 1043 end ; 1044 h_bit := h_bit - count ; 1045 turn_on := not turn_on ; 1046 end ; 1047 t_print_ln(' ') ; 1048 if (rows_left <> 0) or (h_bit <> width) then 1049 abort('Bad PK file: More bits than required!'); 1050 @.More bits than required@> 1051 end 1052 1053 @ We need to declare the repeat flag, bit counter, and color flag here. 1054 1055 @<Glob...@>= 1056 @!repeat_count : integer ; {how many times to repeat the next row?} 1057 @!rows_left : integer ; {how many rows left?} 1058 @!turn_on : boolean ; {are we black here?} 1059 @!h_bit : integer ; {what is our horizontal position?} 1060 @!count : integer ; {how many bits of current color left?} 1061 1062 @ If any specials are found, we write them out here. 1063 1064 @d four_cases(#)==#,#+1,#+2,#+3 1065 1066 @p procedure skip_specials ; 1067 var @!i, @!j: integer ; 1068 begin 1069 repeat 1070 flag_byte := pk_byte ; 1071 if flag_byte >= 240 then 1072 case flag_byte of 1073 four_cases(pk_xxx1): 1074 begin 1075 t_print((pk_loc-1):1,': Special: ''') ; 1076 i := 0 ; 1077 for j := pk_xxx1 to flag_byte do i := 256 * i + pk_byte ; 1078 for j := 1 to i do t_print(xchr[pk_byte]) ; 1079 t_print_ln('''') ; 1080 end ; 1081 pk_yyy : t_print_ln((pk_loc-1):1,': Num special: ',get_32:1) ; 1082 pk_post : t_print_ln((pk_loc-1):1,': Postamble') ; 1083 pk_no_op : t_print_ln((pk_loc-1):1,': No op') ; 1084 pk_pre, pk_undefined : abort('Unexpected ', flag_byte:1,'!') ; 1085 @.Unexpected bbb@> 1086 endcases ; 1087 until (flag_byte < 240) or (flag_byte = pk_post) ; 1088 end ; 1089 1090 @* Terminal communication. 1091 We must get the file names and determine whether input is to be in 1092 hexadecimal or binary. To do this, we use the standard input path 1093 name. We need a procedure to flush the input buffer. For most systems, 1094 this will be an empty statement. For other systems, a |print_ln| will 1095 provide a quick fix. We also need a routine to get a line of input from 1096 the terminal. On some systems, a simple |read_ln| will do. Finally, 1097 a macro to print a string to the first blank is required. 1098 1099 @d flush_buffer == begin end 1100 @d get_line(#) == if eoln(input) then read_ln(input) ; 1101 i := 1 ; 1102 while not (eoln(input) or eof(input)) do begin 1103 #[i] := input^ ; 1104 incr(i) ; 1105 get(input) ; 1106 end ; 1107 #[i] := ' ' 1108 1109 @ @p procedure dialog ; 1110 var i : integer ; {index variable} 1111 buffer : packed array [1..name_length] of char; {input buffer} 1112 begin 1113 for i := 1 to name_length do begin 1114 typ_name[i] := ' ' ; 1115 pk_name[i] := ' ' ; 1116 end; 1117 print('Input file name: ') ; 1118 flush_buffer ; 1119 get_line(pk_name) ; 1120 print('Output file name: ') ; 1121 flush_buffer ; 1122 get_line(typ_name) ; 1123 end ; 1124 1125 @* The main program. 1126 Now that we have all the pieces written, let us put them together. 1127 1128 @p begin 1129 initialize ; 1130 dialog ; 1131 @<Open files@> ; 1132 @<Read preamble@> ; 1133 skip_specials ; 1134 while flag_byte <> pk_post do begin 1135 @<Unpack and write character@> ; 1136 skip_specials ; 1137 end ; 1138 j := 0 ; 1139 while not eof(pk_file) do begin 1140 i := pk_byte ; 1141 if i <> pk_no_op then abort('Bad byte at end of file: ',i:1) ; 1142 @.Bad byte at end of file@> 1143 t_print_ln((pk_loc-1):1,': No op') ; 1144 incr(j) ; 1145 end ; 1146 t_print_ln(pk_loc:1,' bytes read from packed file.'); 1147 final_end : 1148 end . 1149 1150 @* System-dependent changes. 1151 This section should be replaced, if necessary, by changes to the program 1152 that are necessary to make \.{PKtype} work at a particular installation. 1153 Any additional routines should be inserted here. 1154 @^system dependencies@> 1155 1156 @* Index. 1157 Pointers to error messages appear here together with the section numbers 1158 where each ident\-i\-fier is used.