summaryrefslogtreecommitdiff
path: root/dviware/ln03/rose/dvi2ln3.c
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /dviware/ln03/rose/dvi2ln3.c
Initial commit
Diffstat (limited to 'dviware/ln03/rose/dvi2ln3.c')
-rw-r--r--dviware/ln03/rose/dvi2ln3.c1654
1 files changed, 1654 insertions, 0 deletions
diff --git a/dviware/ln03/rose/dvi2ln3.c b/dviware/ln03/rose/dvi2ln3.c
new file mode 100644
index 0000000000..56765ef36d
--- /dev/null
+++ b/dviware/ln03/rose/dvi2ln3.c
@@ -0,0 +1,1654 @@
+/* Dvi2ln3 translates a TeX DVI file to an LN03 format file.
+
+Dvi2ln3 is still being developed. Copyright (c) 1985, 1986 by Digital
+Equipment Corporation, Maynard, Massachusetts, USA. Author: Flavio Rose,
+...!decwrl!dec-rhea!dec-dvinci!rose.
+
+Dvi2ln3 is based on the publicly-available program DVItype, written by
+David R. Fuchs of Stanford University; and also on earlier DEC programs,
+Dvi2lng, Topp and LN03Topp, for the LN01 and LN03 laser printers. This
+program is not a DEC product and is not guaranteed to work.
+
+Dvi2ln3 is written in VAX C. Specific VAX and VMS dependencies have
+generally been avoided, however. The reader may find them by searching for
+the strings VAX and VMS in this file.
+
+During development, double square brackets [[ ]] in a comment indicate some
+places where the code needs to be improved.
+
+[[Among the useful things that still need to be done: differentiating
+between int and long variables so this can be ported more easily to 16-bit
+architectures; testing to see if malloc returns 0; a \special for ROM
+fonts.]]
+
+Development history:
+
+Feb. 85: Did some early work on Dvi2ln3, translating bits and pieces
+ of Dvi2lng. Concluded, however, that it was better to translate
+ LN03Topp and Dvi2lng into C first. The reason for this is that code
+ which mimics an existing program is easier to write and to test.
+
+5/15/85: At this date, the old LN03Topp program has been successfully
+ translated into C (except for the ability to read files over
+ DECnet). At this point, did some further cleanup of the Dvi2ln3
+ source.
+
+ 6/4/85: Coding of Dvi2ln3 begins in earnest. Merging bits and
+ pieces from various places. Chucking chunks and all that
+ junk from LN03Topp; pass2 is just straightforward translation.
+
+6/22/85: Cleanup after initial debugging. Ready to distribute.
+
+10/8/85: Adding \special's to imitate Textset's DVIAPS program.
+ Corrected bug in parsing of \specials. Version 1.
+
+10/15/85: More changes for specials. Version 2.
+
+11/8/85: Fixed bug in ln03:defpoint \special. Version 3.
+
+11/15/85: Changed way information about font size is passed back
+ by add_txf_to_lnf. Add PXL-reading capability. Version 4.
+
+11/21/85: Error handling has been reformed. Still version 4.
+
+12/12/85: Bug correction in handling of plotfile special. Version 5.
+
+1/7/86: Clear all fonts from memory at beginning of document. Version 6.
+
+1/16/86: Fixed bug in dvi2ln3nft.c, nftf was not being closed after use.
+ Version 7. (Bug found by Mark DeVries.)
+
+3/4/86: Support for landscape added -- very easy, if only I had
+ known. Fixed bug found by Mark DeVries, error returned
+ if \special selects device other than LN03. Version 8.
+
+3/28/86: Conditionalization for Ultrix. #ifndef vms ==
+ #ifdef ultrix. Still emits 8-bit characters. Should be
+ unchanged under VMS. getenv is used to replace
+ logicals. Version 9.
+
+4/4/86: Added support for 7-bit only environments,
+ conditionalized on the SEVENBIT symbol. Still version 9.
+
+4/16/86: Final changes to make compilation under Ultrix
+ clean. Still version 9.
+
+*/
+
+#ifdef vms
+#include stdio
+#include ctype
+#else
+#include <stdio.h>
+#include <ctype.h>
+#endif
+
+/* Ultrix seems to want this: */
+
+#ifndef vms
+char *strchr(), *malloc(), *getenv();
+#define SEVENBIT 1
+#endif
+
+/* In VMS, we declare all global variables to be globaldef.
+This is not really necessary, just an old habit from working
+with other VMS languages. It's done with #define's, so it
+may easily be undone when porting the program to other
+systems. */
+
+#ifdef vms
+#define GLOBAL globaldef
+#define EXTERN globalref
+#else
+#define GLOBAL
+#define EXTERN extern
+#endif
+
+
+/* Here begins a long list of global variables. */
+
+/* hoff is the horizontal offset in pixels to be added to all dimensions
+read in; voff is the corresponding vertical offset. */
+
+GLOBAL int hoff, voff;
+GLOBAL FILE *dvifile,*tfmfile,*outfile;
+
+/* Each page in a DVI file is identified by ten longwords, which appear
+immediately after each bop (beginning of page) command. Dvi2ln3, like
+DVItype, supports certain options that allow one to print only selected
+pages. The following variables are used for this purpose.
+
+Num_pages is a count of how many pages have been passed to the output.
+Max_pages is the user-specified maximum number of pages to pass.
+How_many_counts denotes the number of identifying longwords to take into
+account when searching for the user-specified starting page. The user
+specifies the starting page as the first one whose identifying longwords
+match certain specified values, stored in start_page. However, identifying
+longword i is only required to match the value in start_page[i] if
+use_count[i] is nonzero. */
+
+GLOBAL long int num_pages,max_pages;
+GLOBAL int how_many_counts,use_count[10];
+GLOBAL long int start_page[10];
+
+/* When the output file can have no characters with code >
+127, the user should employ a dvi2ln3 which is recompiled
+with the symbol SEVENBIT defined. Such a dvi2ln3 will run slower
+than one which is allowed eight bits, and produce larger
+output files. */
+
+#ifdef SEVENBIT
+GLOBAL int right7;
+#endif
+
+/* FILESPECLEN is the maximum size of a file specification under VMS.
+[[Perhaps arrays of fixed size should not be used, but rather malloc should
+be employed...]] */
+
+#define FILESPECLEN 252
+
+/* landscape says whether we are printing in landscape or portrait. */
+
+GLOBAL char landscape;
+
+/* The main routine deals with the command line arguments, opens the dvi
+file, and then calls various other routines to handle the "passes". There
+are two passes, each of which involves reading the DVI file from start to
+finish; in between, the font load is constructed. */
+
+main(argc,argv)
+int argc;
+char *argv[];
+{
+ int status,i,jnam,jext;
+ char infnam[FILESPECLEN];
+
+ if (argc < 2) { printf("\n Usage: Dvi2ln3 <filename> <options>");
+ goto exit_label; }
+
+ printf("\n Dvi2ln3 9");
+
+/* [[The following could bomb if argv[1] is longer than FILESPECLEN
+characters. Sigh.]] */
+
+ strcpy(infnam,argv[1]);
+
+/* The extension of the input file defaults to .dvi. Locate the filename
+field within the filespec parameter, set jname to point to beginning, jext
+to point to one place after end. [[This code is of course dependent on the
+VMS filespec syntax.]] */
+
+ find_filename(infnam,&jnam,&jext);
+ if (infnam[jext] == '\0') strcat(infnam,".dvi");
+ dvifile = fopen(infnam,"r");
+ if (dvifile == NULL) { printf("\n Couldn't open dvi file");
+ goto exit_label; }
+
+/* Now decipher the options off the command line. */
+
+#ifdef SEVENBIT
+ right7 = 0;
+#endif
+ max_pages = 1000000000;
+ how_many_counts = 0;
+ hoff = 300;
+ voff = 300;
+ landscape = 0;
+ for (i=2; i<argc; i++) command_line_options(argv[i]);
+
+/* Now do the passes */
+
+ status = pass1();
+ if (status != 0) goto exit_label;
+#ifdef vms
+ if (rewind(dvifile) == -1) {
+ printf("\n Couldn't rewind dvi file.");
+ goto exit_label;
+ }
+#else
+ rewind(dvifile);
+#endif
+
+ status = open_output_file(infnam,jnam,jext,".ln3");
+ if (status != 0) { printf("\n Couldn't open output file");
+ goto exit_label; }
+
+ status = make_font_load();
+ if (status != 0) goto exit_label;
+
+ pass2();
+
+ fprintf(outfile,"\033c");
+ fclose(dvifile);
+ fclose(outfile);
+
+exit_label:
+#ifndef vms
+ printf("\n");
+#endif
+ ;
+}
+
+/* Find_filename finds the filename part of a filespec
+passed in s, returning the index of the first character in
+*ns, and the index of the character after the last in *ne.
+[[This works under VMS and Unix. MS-DOS still needs work.]]
+*/
+
+int find_filename(s,ns,ne)
+char s[];
+int *ns,*ne;
+{
+ int jnam,jext,j,slen;
+
+ slen = strlen(s);
+ jnam = 0;
+ for (j = slen-1; j >= 0; j--) {
+#ifdef vms
+ if (s[j] == ':' || s[j] == ']' ||
+ s[j] == '>') {
+#else
+ if (s[j] == '/') {
+#endif
+ jnam = j+1;
+ break;
+ }
+ }
+
+ jext = slen;
+ for (j = jnam; j < slen; j++) {
+#ifdef vms
+ if (s[j] == '.' || s[j] == ';') {
+#else
+ if (s[j] == '.') {
+#endif
+ jext = j;
+ break;
+ }
+ }
+
+ *ns = jnam;
+ *ne = jext;
+}
+
+/* ERROR HANDLING: Errors should be reported as close to the
+source as possible, so that the maximum amount of
+information is available to the user to identify the error.
+
+Errors in the format of DVI or TFM files are not reported
+specifically, since there exist programs, DVItype and
+TFtoPL, which diagnose errors in such files. This program
+accepts some incorrect DVI files, for example, those with a
+bad postamble or bad backpointers. [[However, someday we may
+rewrite the program to select pages by using these features
+of the DVI format, rather than by skipping unwanted pages.]]
+*/
+
+GLOBAL char *bad_DVI_message = "\nBad DVI file - check it with DVItype";
+
+/* Command_line_options reads and processes options off the
+string t. At this time, four options are supported.
+
+The N option sets the maximum number of pages to be printed.
+Its syntax is /N=<integer> .
+
+The H option modifies the default horizontal offset.
+
+The V option modifies the default vertical offset.
+
+The S option has syntax /S=<pagespec>{.<pagespec>}* where the {}* denotes
+repetition, and a <pagespec> is either an integer or * to indicate any
+value. An example would be "/S=*.8.3".
+
+The meaning of the S option is as follows: In a DVI file, pages are
+identified by ten longword values which follow each bop (beginning of page)
+command. The value of the S option indicates which page to start printing
+on. For example, "*.8.3" means start printing at the first page whose
+second identifying longword is 8 and third is 3.
+
+The L option says print in landscape.
+
+[[Is a European option needed?]] */
+
+int command_line_options(t)
+char *t;
+{
+ long int i,k;
+ char *u;
+
+ while ((t = strchr(t,'/')) != 0) {
+ t++;
+ if (toupper(t[0]) == 'N' && t[1] == '='
+ && (sscanf(&t[2],"%ld",&k) == 1))
+ max_pages = k;
+ if (toupper(t[0]) == 'H' && t[1] == '='
+ && (sscanf(&t[2],"%ld",&k) == 1))
+ hoff = k;
+ if (toupper(t[0]) == 'V' && t[1] == '='
+ && (sscanf(&t[2],"%ld",&k) == 1))
+ voff = k;
+ if (toupper(t[0]) == 'L') landscape = 1;
+ else if (toupper(t[0]) == 'S' && t[1] == '=') {
+ t += 2;
+ how_many_counts = 0;
+ for (;;) {
+ if (t[0] == '*') {
+ use_count[how_many_counts] = 0;
+ how_many_counts++;
+ }
+ else if (sscanf(t,"%ld",&k) != 0) {
+ use_count[how_many_counts] = 1;
+ start_page[how_many_counts] = k;
+ how_many_counts++;
+ } else break;
+ u = strchr(t,'.');
+ if (u == 0) break;
+ t = &u[1];
+ }
+ }
+ }
+}
+
+/* Open_output_file opens one of the output files, using the file pointer
+outfile. The name of the output file is obtained by appending the string
+ext to the substring of infnam beginning at jnam and ending at jext.
+
+[[This code contains a VMS dependency. We use creat followed by fdopen to
+open the file as a normal VMS file ("rat=cr","rfm=var") rather than a
+STREAM_LF file. Beginning with VAX C V2.0, this can be done by just calling
+fopen.]] */
+
+int open_output_file(infnam,jnam,jext,ext)
+char *infnam,*ext;
+int jnam,jext;
+{
+ char outfnam[FILESPECLEN];
+ int jj;
+
+ strcpy(outfnam,&infnam[jnam]);
+ strcpy(&outfnam[jext-jnam],ext);
+
+#ifdef vms
+ jj = creat(outfnam,0,"rat=cr","rfm=var");
+#else
+ jj = creat(outfnam,0700);
+#endif
+ if (jj == -1) return(1);
+ outfile = fdopen(jj,"w");
+ if (outfile == NULL) return(1);
+
+ return(0);
+}
+
+/* Bytes are read one by one from the DVI file using getc. We use an
+overlay, as suggested in the DVItype documentation, to combine these bytes
+into larger integers. [[Note that this technique relies on the fact that
+numbers on the VAX are stored with the least significant byte first. The
+macros below would have to be changed if the program were to be ported to a
+machine architecture for which this is not so.]]
+
+[[The use of getc is expensive, since getc is a function in VAX C V2.0.
+Eventually, one would want to rewrite these macros to work like the old
+getc macro.]] */
+
+GLOBAL union lc { long int l; unsigned long int ul; char c[4];
+ unsigned char uc[4]; } lcx;
+
+#define two_bytes_u lcx.uc[1] = getc(dvifile); \
+ lcx.uc[0] = getc(dvifile); lcx.uc[2] = 0; lcx.uc[3] = 0
+
+#define two_bytes_s lcx.c[1] = getc(dvifile); \
+ lcx.c[0] = getc(dvifile); \
+ if (lcx.c[1] >= 0) { lcx.uc[2] = 0; lcx.uc[3] = 0 ;} \
+ else { lcx.uc[2] = 255; lcx.uc[3] = 255; }
+
+#define three_bytes_u lcx.uc[3] = getc(dvifile); lcx.uc[1] = getc(dvifile); \
+ lcx.uc[0] = getc(dvifile); lcx.uc[2] = 0
+
+#define three_bytes_s lcx.c[2] = getc(dvifile); lcx.c[1] = getc(dvifile); \
+ lcx.c[0] = getc(dvifile); \
+ lcx.uc[3] = (lcx.c[2] >= 0) ? 0 : 255;
+
+#define four_bytes lcx.c[3] = getc(dvifile); \
+ lcx.c[2] = getc(dvifile); lcx.c[1] = getc(dvifile); \
+ lcx.c[0] = getc(dvifile);
+
+/* Knuth's programs like to hardcode fixed maximum sizes for various
+things, for example, the maximum number of fonts allowed in a DVI file. In
+general, it is preferable to use the C function malloc to allocate storage
+as needed. That is what we generally do in this Dvi2ln3, but there are some
+residues of the Knuthian approach, like MAXTEXFONTS below. By the way, we
+never attempt to return any storage to the system.
+
+[[Eventually, it would be better to get rid of MAXTEXFONTS and use a linked
+list of records instead. There would be no cpu time penalty to using a
+linked list, because the function set_curf below does a linear search
+through the font array anyway.]]
+
+Txf is a data structure describing a TeX font. */
+
+#define MAXTEXFONTS 100
+
+struct txf { unsigned char chu[256]; int bc, ec; long int space, design_size,
+ scaled_size; int nchs; };
+
+GLOBAL struct txf *txfa[MAXTEXFONTS+1];
+
+/* Font_name points to strings containing TeX font names. Those strings are
+created with malloc as needed. */
+
+GLOBAL char *font_name[MAXTEXFONTS+1];
+
+/* Font width information needs to be read from TFM files. TFM is a special
+format defined by TeX. Dvi2ln3 stores each width in a longword. DVItype
+tries to save space by a two-level width storage method. We just allocate
+an array of widths for each font with malloc.
+
+[[We don't check that font checksums match in Dvi2ln3, because there are a
+lot of slightly obsolete TFMs floating around which would result in a
+checksum error, but seem to give perfectly reasonable formatted output
+nonetheless.]] */
+
+GLOBAL long int *font_width[MAXTEXFONTS+1];
+
+/* TeX fonts are referred to by their internal numbers, which go from 0 to
+nf-1. The DVI file refers to them by external numbers, hence the array
+to_ext used to convert internal numbers to external numbers. Curf is the
+internal font number of the current font in the DVI file. */
+
+GLOBAL int to_ext[MAXTEXFONTS+1],
+ nf,
+ curf;
+
+/* In some switch statements, a lot of cases have to be enumerated. We
+employ the following Knuthian macro for that purpose: */
+
+#define four_cases(_x1) case _x1: case _x1+1: case _x1+2: case _x1+3:
+
+/* We define a lot of constants corresponding to the DVI operation codes.
+These are copied from DVItype. */
+
+#define id_byte 2 /* current version of the dvi format */
+#define set_char_0 0 /* typeset character 0 and move right */
+#define set1 128 /* typeset a character and move right */
+#define set_rule 132 /* typeset a rule and move right */
+#define put1 133 /* typeset a character */
+#define put_rule 137 /* typeset a rule */
+#define nop 138 /* no operation */
+#define bop 139 /* beginning of page */
+#define eop 140 /* ending of page */
+#define push 141 /* save the current positions */
+#define pop 142 /* restore previous positions */
+#define right1 143 /* move right */
+#define w0 147 /* move right by |w| */
+#define w1 148 /* move right and set |w| */
+#define x0 152 /* move right by |x| */
+#define x1 153 /* move right and set |x| */
+#define down1 157 /* move down */
+#define y0 161 /* move down by |y| */
+#define y1 162 /* move down and set |y| */
+#define z0 166 /* move down by |z| */
+#define z1 167 /* move down and set |z| */
+#define fnt_num_0 171 /* set current font to 0 */
+#define fnt1 235 /* set current font */
+#define xxx1 239 /* extension to dvi primitives (\special) */
+#define xxx4 242 /* potentially long extension to dvi primitives */
+#define fnt_def1 243 /* define the meaning of a font number */
+#define pre 247 /* preamble */
+#define post 248 /* postamble beginning */
+#define post_post 249 /* postamble ending */
+#define undefined_command 250
+
+GLOBAL long int mag, num, den;
+GLOBAL float conv, unmag_conv;
+
+/* Read_preamble reads the preamble of the dvi file. The comment is thrown
+away. The format version number is checked. The magnification, numerator,
+and denominator are remembered in the globals mag, num, den. The float
+values conv and unmag_conv serve to convert measurements from DVI units to
+pixels. */
+
+int read_preamble() {
+ unsigned int i;
+ int j;
+
+ i = getc(dvifile);
+ if (i != pre) return(1);
+ i = getc(dvifile);
+ if (i != id_byte) return(1);
+ four_bytes; num = lcx.l;
+ if (num <= 0) return(1);
+ four_bytes; den = lcx.l;
+ if (den <= 0) return(1);
+ four_bytes; mag = lcx.l;
+ if (mag <= 0) return(1);
+
+ unmag_conv = (num/254000.0) * (300.0/den);
+ conv = unmag_conv * (mag/1000.0);
+
+/* Skip over the comment field. */
+
+ i = getc(dvifile);
+ for (j=0; j<i; j++) getc(dvifile);
+ return(0);
+}
+
+/* The dvi file format requires us to keep track of various quantities,
+among them the horizontal and vertical positions h and v, and four values
+referred to simply as x, y, z and w. We also keep pixel-rounded versions
+of h and v, called hh and vv. */
+
+GLOBAL long h, v, x, y, z, w;
+GLOBAL int hh, vv;
+
+/* The following function, copied from DVItype, reads from the DVI file the
+first parameter of the current DVI command. In the case of functions whose
+first parameter is implicit, such as set_char_0 through set_char_127, the
+implicit parameter is returned. */
+
+long first_par(o)
+int o;
+{
+ unsigned int i;
+
+ if ((o >= set_char_0) && (o < set_char_0+128))
+ return(o-set_char_0);
+ if ((o >= fnt_num_0) && (o < fnt_num_0+64))
+ return(o-fnt_num_0);
+ switch (o) {
+ case set1:
+ case put1:
+ case fnt1:
+ case xxx1:
+ case fnt_def1:
+ i = getc(dvifile);
+ return(i);
+ case set1+1:
+ case put1+1:
+ case fnt1+1:
+ case xxx1+1:
+ case fnt_def1+1:
+ two_bytes_u;
+ return(lcx.ul);
+ case set1+2:
+ case put1+2:
+ case fnt1+2:
+ case xxx1+2:
+ case fnt_def1+2:
+ three_bytes_u;
+ return(lcx.ul);
+ case right1:
+ case w1:
+ case x1:
+ case down1:
+ case y1:
+ case z1:
+ return(getc(dvifile));
+ case right1+1:
+ case w1+1:
+ case x1+1:
+ case down1+1:
+ case y1+1:
+ case z1+1:
+ two_bytes_s;
+ return(lcx.l);
+ case right1+2:
+ case w1+2:
+ case x1+2:
+ case down1+2:
+ case y1+2:
+ case z1+2:
+ three_bytes_s;
+ return(lcx.l);
+ case set_rule:
+ case put_rule:
+ case right1+3:
+ case w1+3:
+ case x1+3:
+ case down1+3:
+ case y1+3:
+ case z1+3:
+ case set1+3:
+ case put1+3:
+ case fnt1+3:
+ case xxx1+3:
+ case fnt_def1+3:
+ four_bytes;
+ return(lcx.l);
+ case w0:
+ return(w);
+ case x0:
+ return(x);
+ case y0:
+ return(y);
+ case z0:
+ return(z);
+ default:
+ return(0);
+ }
+}
+
+/* Pass1 reads from the DVI file until the last page that has to be
+processed, as determined by the page selection data structures. Font
+definitions are processed, as are font selections; after the starting page
+begins, pass1 records which characters are used from which fonts. Other
+commands are ignored in pass1. Return 1 if something goes wrong, e.g. if
+the DVI file comes to a premature end. This resembles skip_pages below. */
+
+int pass1() {
+
+ unsigned int k;
+ long int p;
+ int i;
+ char startp;
+
+ if (read_preamble() != 0) {
+ printf(bad_DVI_message);
+ return(1);
+ }
+
+ for (;;) {
+ if (feof(dvifile)) {
+ printf(bad_DVI_message);
+ return(1);
+ }
+ k = getc(dvifile);
+ if (k == post) return(0);
+ p = first_par(k);
+ if (k >= set_char_0 && k < set_char_0+128) k = set1;
+ if (k >= fnt_num_0 && k < fnt_num_0+64) k = fnt1;
+
+ switch (k) {
+ case bop:
+ startp = 1;
+ for (i=0; i<10; i++) {
+ four_bytes;
+ if (i < how_many_counts && use_count[i] &&
+ lcx.l != start_page[i]) startp = 0;
+ }
+ four_bytes;
+ if (startp != 0) num_pages = 1;
+ else if (num_pages > 0) {
+ num_pages++;
+ if (num_pages > max_pages) return(0);
+ }
+ break;
+ case set_rule:
+ case put_rule:
+ four_bytes;
+ break;
+ four_cases(fnt_def1)
+ i = define_font(p);
+ if (i != 0) return(1);
+ break;
+ four_cases(fnt1)
+ if (num_pages > 0) set_curf(p);
+ break;
+ four_cases(set1)
+ four_cases(put1)
+ if (num_pages > 0)
+ txfa[curf] -> chu[p] = 1;
+ break;
+
+/* \special's are currently ignored in pass1, and handled only in pass2.
+[[This will change if the putchar special is implemented.]] */
+
+ four_cases(xxx1)
+ for (; p>0; p--) getc(dvifile);
+ break;
+ default:
+ break;
+ }
+ }
+/* return(0); /* Unreachable */
+}
+
+/* FONT LOAD BUILDING: The hardest thing Dvi2ln3 has to do is to build an
+LN03 font load that contains the glyphs required to print the DVI file. The
+following code pertains to that effort.
+
+LN03 fonts come in two flavors. Left fonts are invoked by character codes
+33 to 126. Right fonts are invoked by character codes 161 to 254. Hence: */
+
+#define leftfirst 33
+#define rightfirst 161
+#define leftlast 126
+#define rightlast 254
+
+/* It is believed that there is a maximum of 32 downline-loaded LN03 fonts.
+We always deal with these in pairs, using one as a left font, the other as
+a right font. Hence we have a maximum of 16 pairs. */
+
+#define maxnfonts 16
+
+/* We keep track of the true last character in each LN03 font pair; the
+width of each character; and the LN03 name assigned to that pair. */
+
+GLOBAL int lastch[maxnfonts];
+GLOBAL unsigned char chw[maxnfonts][256];
+GLOBAL char fname[maxnfonts][32];
+
+/* Txf is a record structure describing a TeX font. Txfa is an array of txf
+records. Txf2lnf describes the mapping between TeX fonts and pairs of LN03
+fonts. Because the constructed LN03 font load has just the glyphs that are
+needed, we can often cram more than one TeX font into a pair of LN03 fonts.
+*/
+
+GLOBAL int txf2lnf[MAXTEXFONTS];
+
+/* Maxfontnos reflects the fact that LN03 fonts must be denoted by a number
+from 10 to 19 in order to be selected as the LN03's current font. */
+
+#define maxfontnos 9
+
+/* The LN03 font-denoting numbers 10-19 have to be allocated among the
+fonts. The useno array keeps track of which number a font is using, -1 if
+the font currently doesn't have any number. The whouses array says which
+font is using a given number. */
+
+GLOBAL int useno[maxnfonts],whouses[maxfontnos];
+
+/* After the font load we declare the right and bottom margins we are going
+to use; these are always the maximum allowed values. */
+
+GLOBAL int maxrmar,maxbmar;
+
+/* The global ras_len_added is employed by the font-load-creating code to
+communicate how many bytes of raster information it adds to the font load
+each time it is called. [[Maybe there should be no EXTERNs in the main code
+file, just GLOBALs?]] */
+
+EXTERN long ras_len_added;
+
+#define max(x,y) (((x)>(y))?(x):(y))
+#define min(x,y) (((x)<(y))?(x):(y))
+
+/* Make_font_load calls on other procedures to generate the LN03 font load.
+It writes the opening lines of the output file, too. */
+
+int make_font_load() {
+
+ int i,j,jj,k,l,fno,maxfno,chsize;
+ long int totsize;
+ int lnfcnt,txfcnt,the_txf,txf_size,lnfleft;
+ int txford[MAXTEXFONTS];
+ char cnt[3];
+
+ totsize = 0;
+ chsize = 0;
+ curf = 0;
+ for (i=0; i<maxnfonts; i++)
+ for (j=0; j<256; j++) chw[i][j] = 0;
+
+ for (jj=0; jj<MAXTEXFONTS; jj++) txf2lnf[jj] = -1;
+
+/* Fill the fname strings with different valid LN03 font names. [[This
+initialization could be done statically, but then maxnfonts would be more
+hardcoded.]] */
+
+ for (i=0; i<maxnfonts; i++)
+ strcpy(fname[i],"U000000002SK00GG0001UZZZZ02F000");
+ for (jj=1; jj<maxnfonts; jj++) {
+ sprintf(cnt,"%02d",jj);
+ strncpy(&(fname[jj][5]),cnt,2);
+ }
+
+/* The margins are set to values that seem appropriate for American 8 1/2
+by 11" paper. It is not clear if this needs to be changed for European A4
+paper. Not changing it might deprive Europeans of access to the bottom
+1.5cm of their paper.
+
+It is not clear what the printable area is, or what happens when it is
+exceeded. */
+
+ if (landscape == 1) {
+ maxrmar = 3300;
+ maxbmar = 2475;
+ } else {
+ maxrmar = 2550;
+ maxbmar = 3300;
+ }
+
+/* In the following, esc[?21 J means print in landscape, esc[?27h means
+"advance the carriage by the character width when you set a character",
+esc[11h and esc[7 I together mean to interpret all dimensions in escape
+sequences as pixel units; esc[?52h means our origin of coordinates is the
+upper left edge of the paper; esc[%dt means the "maximum length" of the
+paper is maxbmar pixels. */
+
+ fprintf(outfile,"\033c");
+ if (landscape == 1) fprintf(outfile,"\033[?21 J");
+ fprintf(outfile,"\033[?27h\033[11h\033[7 I\033[?52h\033[%dt\n",
+ maxbmar);
+
+ for (i=0; i<maxnfonts; i++) useno[i] = -1;
+ for (i=0; i<maxfontnos; i++) whouses[i] = -1;
+ maxfno = -1;
+
+/* Write font loading escape sequence onto outf. The ;0y causes all
+previously downloaded fonts to be cleared from the LN03's font memory. */
+
+ fprintf(outfile,"\033P0;1;0y");
+
+/* Count how many glyphs each font requires. */
+
+ for (fno=0; fno<nf; fno++) {
+
+ txfa[fno] -> nchs = 0;
+ for(i=0; i<256; i++)
+ if (txfa[fno] -> chu[i] != 0) txfa[fno] -> nchs++;
+
+ if (txfa[fno] -> nchs > 188) goto need_empty_slots;
+ chsize += txfa[fno] -> nchs;
+ }
+ printf("\nFont load to contain %d glyphs.",chsize);
+
+
+/* Now we have to allocate TeX fonts to LN03 font pairs and perform the
+actual load. The goal is to use as few LN03 fonts as possible.
+
+I don't know any way to do the allocation optimally, so a first-fit
+heuristic is used.
+
+1. Find the largest unassigned TeX font. If none, exit, we're done.
+ Number of glyphs used is the measure of size.
+
+2. Allocate an LN03 font pair for that TeX font and put the TeX
+ font into it.
+
+3. Find the largest remaining TeX font that fits in what is left of
+ that LN03 font pair.
+
+ 3.1. if none exists, go to 1.
+ 3.2. if one exists, put it in the font pair and go back to 3.
+
+The txford array contains the TeX font numbers in the order that they are
+assigned. Txfcnt keeps track of how many TeX fonts have been assigned so
+far. */
+
+ lnfcnt = 0;
+ txfcnt = 0;
+ for (i=0; i<MAXTEXFONTS; i++) txford[i] = -1;
+
+ while (1) {
+
+/* Find largest unassigned TeX font */
+
+ lnfleft = rightlast-rightfirst+1+leftlast-leftfirst+1;
+ txf_size = -1;
+ for (j = 0; j < MAXTEXFONTS; j++) {
+ if (txfa[j] != 0 && txf2lnf[j] == -1
+ && txfa[j] -> nchs > txf_size) {
+ txf_size = txfa[j] -> nchs;
+ the_txf = j;
+ }
+ }
+ if (txf_size <= 0) goto assignment_done;
+ if (lnfcnt > maxnfonts) goto too_complex;
+ if (txf_size > lnfleft) goto need_empty_slots;
+
+/* Now allocate new LN03 font pair and put the current TeX font into it */
+
+ txf2lnf[the_txf] = lnfcnt;
+ txford[txfcnt] = the_txf;
+ txfcnt++;
+ k = leftfirst-1;
+ for (j = 0; j <= 255; j++) {
+ if (txfa[the_txf] -> chu[j] != 0) {
+ k++;
+ if (k == leftlast+1) k = rightfirst;
+ lnfleft--;
+ txfa[the_txf] -> chu[j] = k;
+ }
+ }
+ lastch[lnfcnt] = k;
+
+/* Now try to fill the remaining part of the LN03 font pair using other TeX
+fonts */
+
+ while (1) {
+
+ txf_size = -1;
+ for (j = 0; j < MAXTEXFONTS; j++) {
+ if (txfa[j] != 0 && txf2lnf[j] == -1
+ && txfa[j] -> nchs > txf_size
+ && txfa[j] -> nchs <= lnfleft) {
+ txf_size = txfa[j] -> nchs;
+ the_txf = j;
+ }
+ }
+ if (txf_size <= 0) break;
+
+ txf2lnf[the_txf] = lnfcnt;
+ txford[txfcnt] = the_txf;
+ txfcnt++;
+ k = lastch[lnfcnt];
+ for (j=0; j<=255; j++) {
+ if (txfa[the_txf] -> chu[j] != 0) {
+ k++;
+ lnfleft--;
+ if (k == leftlast+1) k = rightfirst;
+ txfa[the_txf] -> chu[j] = k;
+ }
+ }
+ lastch[lnfcnt] = k;
+ }
+
+ lnfcnt++;
+ }
+
+assignment_done:
+
+/* At this point, the TeX fonts have been assigned to LN03 font pairs. The
+assignment is reflected in the arrays txf2lnf, lastch and txford. It
+remains to actually generate the desired font load. This has to be done
+carefully, since the function add_txf_to_lnf only supports adding glyphs to
+an LN03 font pair in ascending order of character code. */
+
+ for (j=0; j<txfcnt; j++) {
+ k = txford[j];
+ if (j != 0 && txf2lnf[k] != txf2lnf[txford[j-1]])
+ fprintf(outfile,",\n");
+ add_txf_to_lnf(txf2lnf[k],k);
+ totsize += ras_len_added;
+ }
+
+/* [[At this point we ought to add code that writes a message saying how
+much font RAM the load will occupy. But there is no documentation for
+determining that! So, we make the following compromise:]] */
+
+ printf("\n Approximate size of font load: %ld bytes",totsize);
+
+/* Now output escape sequences to the LN03 that assign the available font
+numbers to the first ten font pairs in the load. [[We may want to insert a
+few \n's in the following to keep the line from getting too long.]] */
+
+ fprintf(outfile,"\n;Dvi2ln3 9 font load\033\\");
+ fprintf(outfile,"\033[1;%ds\033[%dt\033[1;%dr",maxrmar,maxbmar,maxbmar);
+ for (j=0; j <= min(maxfontnos,lnfcnt-1); j++) {
+ useno[j] = j;
+ whouses[j] = j;
+ k = fname[j][16];
+ fname[j][16] = '\0';
+ fprintf(outfile,"\033P1;1%d}%s\033\\",j,fname[j]);
+ fname[j][16] = k;
+ }
+ fprintf(outfile,"\033[10m");
+
+ return(0);
+
+too_complex:
+ printf("\n Can't construct a font load:");
+ printf("\n Dvi file uses too many glyphs from too many different fonts.");
+ return(1);
+
+/* [[We need to determine what the real limit is on the number of LN03
+fonts, and refine the test to detect if it is being exceeded. Fortunately,
+only a very complex DVI file could exceed the limit.]] */
+
+need_empty_slots:
+ printf("\nFont %s uses > 188 characters. Can't handle that.",
+ font_name[fno]);
+ return(1);
+
+/* [[The error message above should be fixed to specify the magnification
+of the font also.]] */
+
+}
+
+/* The lines in the LN3 file are limited to lengths of about 100 bytes. We
+keep track of how many bytes are written so far in the global lnhp. The
+accounting is conservative, so e.g. each integer representing a pixel
+position counts as 4 bytes even though it might be shorter. [[One could
+easily increase 100 to 200. It is not clear what problems are provoked by
+going over, say, 256.]]
+
+Vpset keeps track of whether the vertical position needs to be output to
+the LN03 file before setting any more characters. Hh_old keeps track of the
+horizontal position which LN03 thinks it's at. */
+
+GLOBAL int ln3p,vpset,hh_old;
+
+#define inc_ln3p(x) ln3p += x; if (ln3p > 100) \
+ { ln3p = 0; vpset = 0; hh_old = 30000; }
+
+/* [[In the above macro, hh_old is set to 30000 to mean "a very large
+number" (the maximum valid hh for an LN03 is 2550), so as to force the code
+below to re-output the true hh. What are the implications of this kludge?
+Would it not be more reasonable to have instead an hhset variable?]] */
+
+/* A stack of hvxyzw values is kept; the stack pointer is called s.
+[[Again, it would be better to make this stack a linked list.]] */
+
+#define STACKSIZE 100
+
+GLOBAL long hstack[STACKSIZE], vstack[STACKSIZE], xstack[STACKSIZE],
+ ystack[STACKSIZE], zstack[STACKSIZE], wstack[STACKSIZE];
+GLOBAL int hhstack[STACKSIZE], vvstack[STACKSIZE];
+GLOBAL int s;
+
+/* DVI files specify distances in units of 2^-16 points. When translating
+to a device-specific format, it is necessary to round the DVI distances to
+pixel units. This is done by means of the pixel_round macro.
+
+However, rather than using this macro in the straightforward way, rounding
+is often performed by more elaborate techniques, which we call "Stanford
+rules" (after John Le Carre's "Moscow rules"). These rules make use of a
+parameter MAX_DRIFT, which is roughly the maximum number of pixels that
+things are allowed to deviate from straightforward rounding. */
+
+#define pixel_round(x) ((int) ((x<0) ? \
+ (conv*(x)-0.5) : (conv*(x)+0.5)))
+
+#define MAX_DRIFT 2
+
+/* Pass2 reads the dvi file and interprets the commands in it, usually by
+calling other routines. The interpretation generally consists of writing
+something into the output file, updating the current fonts and positions,
+and possibly updating the stack. */
+
+int pass2()
+{
+ int i,j;
+ long int p;
+ unsigned int k;
+
+ if (read_preamble() != 0) {
+ printf(bad_DVI_message);
+ return(1);
+ }
+
+ curf = 0;
+ ln3p = 0;
+ s = 0;
+ vpset = 0;
+ hh_old = 30000;
+
+/* Skip pages until the desired starting page is reached. A nonzero value
+is returned if the starting page is never encountered. */
+
+ if (skip_pages() != 0) return(0);
+
+ for (;;) {
+ if feof(dvifile) {
+ printf(bad_DVI_message);
+ return(1); }
+ k = getc(dvifile);
+ if (k == post) return(0);
+ if (k >= undefined_command) {
+ printf(bad_DVI_message);
+ return(1); }
+
+ p = first_par(k);
+
+/* If the opcode is an "implicit parameter" opcode, either set_char_n and
+fnt_num_n, we change it to an explicit parameter opcode to make the case
+jumps more reasonable. */
+
+ if (k >= set_char_0 && k < set_char_0+128) k = set1;
+ if (k >= fnt_num_0 && k < fnt_num_0+64) k = fnt1;
+
+ j = do_command(k,p);
+ if (j == 2) return(0); /* done with the required number of pages */
+ else if (j == 1) return(1); /* error encountered, stop */
+
+ }
+}
+
+GLOBAL long first_counter;
+
+/* Read from the DVI file until the starting page condition is met. Return
+1 if something goes wrong, or if the DVI file comes to an end. This
+function is copied quite closely from DVItype. */
+
+int skip_pages() {
+
+ unsigned int k;
+ int i;
+ long p;
+ char startp;
+
+ for (;;) {
+ if (feof(dvifile)) return(1);
+ k = getc(dvifile);
+ if (k == post) return(1);
+ p = first_par(k);
+ if (k >= set_char_0 && k < set_char_0+128) k = set1;
+ if (k >= fnt_num_0 && k < fnt_num_0+64) k = fnt1;
+
+ switch (k) {
+ case bop:
+ startp = 1;
+ for (i=0; i<10; i++) {
+ four_bytes;
+ if (i == 0) first_counter = lcx.l;
+ if (i < how_many_counts && use_count[i] &&
+ lcx.l != start_page[i]) startp = 0;
+ }
+ four_bytes;
+ if (startp != 0) {
+ v = 0; vv = 0; h = 0; hh = 0;
+ printf("\n [%ld]",first_counter);
+ num_pages = 1; return(0); }
+ break;
+ case set_rule:
+ case put_rule:
+ four_bytes;
+ break;
+ four_cases(fnt_def1)
+
+/* [[Why are we defining fonts again here? Once, in pass1, ought to have
+been enough...]] */
+
+ i = define_font(p);
+ if (i != 0) return(1);
+ break;
+ four_cases(xxx1)
+ for (; p>0; p--) getc(dvifile);
+ break;
+ default:
+ break;
+ }
+ }
+/* return(0); /* Unreachable */
+}
+
+/* Do_command performs the DVI command of code k, assuming the "first
+parameter" is p. It is assumed that k is not one of set_char0 through
+set_char127. */
+
+int do_command(k,p)
+int k;
+long p;
+{
+ int i,j,l,lnf;
+
+ switch (k) {
+ four_cases(fnt_def1)
+ define_font_pass2();
+ break;
+
+/* It is possible that the dvi file sets some glyphs off the page. No error
+message is given, since the user will generally see what is happening in
+the output (plus, if Dvi2ln3 gives an error message, users will complain
+about Dvi2ln3 even though the error is in their TeX file).
+
+In most cases, dvi2ln3 takes no special action at all, since the LN03 will
+clip the glyphs for us. Unfortunately, the LN03 doesn't let us specify
+negative horizontal or vertical positions, so we have to clip glyphs at
+such positions away ourselves. Also, if one sets at a position below the
+bottom margin, the LN03 will eject a page, so glyphs that are set below
+that margin also have to be clipped by hand.
+
+The following code accomplishes that: */
+
+ four_cases(put1)
+ four_cases(set1)
+
+ if (vv+voff > 0 && vv+voff <= maxbmar && hh+hoff > 0) {
+ if (!vpset) {
+ fprintf(outfile,"\n\033[%dd",vv+voff);
+ fprintf(outfile,"\033[%d`",hh+hoff);
+ ln3p = 16;
+ vpset = 1;
+ hh_old = hh;
+ }
+ if (hh_old != hh) {
+ if (hh > hh_old) fprintf(outfile,"\033[%da",hh-hh_old);
+ else fprintf(outfile,"\033[%d`",hh+hoff);
+ ln3p += 7;
+ }
+
+#ifndef SEVENBIT
+ putc(txfa[curf] -> chu[p],outfile);
+#else
+ if (txfa[curf] -> chu[p] > 127) {
+ if (right7 == 0) {
+ fputs("\033n",outfile);
+ inc_ln3p(2);
+ right7 = 1;
+ }
+ putc(txfa[curf] -> chu[p]-128,outfile);
+ } else {
+ if (right7 == 1) {
+ putc(15,outfile);
+ inc_ln3p(1);
+ right7 = 0;
+ }
+ putc(txfa[curf] -> chu[p],outfile);
+ }
+#endif
+ inc_ln3p(1);
+ }
+ if (k >= put1) {
+ hh_old = hh+chw[txf2lnf[curf]][txfa[curf] -> chu[p]];
+ break;
+ }
+ h += font_width[curf][p];
+
+/* In rounding h to generate the pixel-position hh, Stanford rules (see
+above) come into play. We set the new hh (horizontal position in pixels) to
+the value obtained by adding the pixel width of the character being set to
+the current position. We then correct this value so that it does not exceed
+the rounded version of the true position by more than MAX_DRIFT pixels.
+
+Note that if we did not apply Stanford rules here, or equivalently if we
+set MAX_DRIFT to zero, many more set-X-position commands would appear in
+the output. */
+
+ hh += chw[txf2lnf[curf]][txfa[curf] -> chu[p]];
+ hh_old = hh;
+ l = pixel_round(h);
+ if (hh-l > MAX_DRIFT) hh = l+MAX_DRIFT;
+ else if (l-hh > MAX_DRIFT) hh = l-MAX_DRIFT;
+ break;
+
+ four_cases(fnt1)
+ set_curf(p);
+ lnf = txf2lnf[curf];
+ if (useno[lnf] == -1) {
+ useno[whouses[maxfontnos]] = -1;
+ useno[lnf] = maxfontnos;
+ whouses[maxfontnos] = lnf;
+ fprintf(outfile,"\033P1;1%d}%16s\033\\",maxfontnos,
+ fname[lnf]);
+ inc_ln3p(26);
+ }
+ fprintf(outfile,"\033[1%dm",useno[lnf]);
+ inc_ln3p(5);
+ break;
+
+ case set_rule:
+ case put_rule:
+
+/* When converting rule dimensions to pixel dimensions, we do not follow
+Stanford rules. Rather, we just round the true positions to obtain the
+pixel positions. This avoids unsightly gaps between rules. [[It should not
+cause much of a problem with typical rule applications (ruled tables,
+fraction bars)...but perhaps with large delimiters there might be some
+difficulty. This needs more thought...]] */
+
+ four_bytes;
+ if (p >= 0 && lcx.l >= 0)
+ do_rule(pixel_round(h),
+ pixel_round(v-p),pixel_round(h+lcx.l),
+ pixel_round(v));
+ if (k == set_rule) {
+ h += lcx.l;
+ hh = pixel_round(h);
+ }
+ break;
+
+ case push:
+ s++;
+ if (s == STACKSIZE) {
+ printf("\n Stack too deep for Dvi2ln3");
+ return(1);
+ }
+ xstack[s] = x;
+ ystack[s] = y;
+ vstack[s] = v;
+ hstack[s] = h;
+ vvstack[s] = vv;
+ hhstack[s] = hh;
+ wstack[s] = w;
+ zstack[s] = z;
+ break;
+
+ case pop:
+ if (s == 0) {
+ printf(bad_DVI_message);
+ return(1);
+ }
+ if (vv != vvstack[s]) vpset = 0;
+ x = xstack[s];
+ y = ystack[s];
+ v = vstack[s];
+ h = hstack[s];
+ vv = vvstack[s];
+ hh = hhstack[s];
+ w = wstack[s];
+ z = zstack[s];
+ s--;
+ break;
+
+ four_cases(xxx1)
+ do_special_pass2(p);
+ break;
+
+ case bop:
+
+/* If we've done the required number of pages, we'll skip the rest of the
+DVI file. If not, type the first parameter of bop on the user's terminal
+the way TeX does, to give an indication of progress. */
+
+ if (num_pages == max_pages) return(2);
+ v = 0; vv = 0; h = 0; hh = 0;
+ vpset = 0; hh_old = 100000;
+ four_bytes;
+ if (num_pages%12 == 0) printf("\n");
+ first_counter = lcx.l;
+ printf(" [%ld]",lcx.l);
+ num_pages++;
+ for (i = 0; i<40; i++) getc(dvifile);
+ break;
+
+ case eop:
+ fprintf(outfile,"\n\f");
+ ln3p = 0;
+ break;
+
+/* Now we have to consider the cases for pure motion. */
+
+ four_cases(right1)
+ set_h(h+p);
+ break;
+ four_cases(x1)
+ x = p;
+ case x0:
+ set_h(h+x);
+ break;
+ four_cases(y1)
+ y = p;
+ case y0:
+ set_v(v+y);
+ break;
+ four_cases(w1)
+ w = p;
+ case w0:
+ set_h(h+w);
+ break;
+ four_cases(z1)
+ z = p;
+ case z0:
+ set_v(v+z);
+ break;
+ four_cases(down1)
+ set_v(v+p);
+ break;
+
+ }
+ return(0);
+}
+
+/* Set_curf sets the current font to external number p. Note that the
+current font is maintained as an internal font number. */
+
+int set_curf(p)
+int p;
+{
+ to_ext[nf] = p;
+ curf = 0;
+ while (to_ext[curf] != p) { curf++; }
+}
+
+/* Define_font processes a font definition from the DVI file. The TFM file
+for the font is read at this point from the directory TEX$FONTS. */
+
+int define_font(e)
+int e;
+{
+ int i;
+ unsigned char p,n;
+ if (e == MAXTEXFONTS) { printf("\n Too many fonts for Dvi2ln3");
+ return(1); }
+ txfa[nf] = (struct txf *)malloc(sizeof(struct txf));
+ to_ext[nf] = e;
+ four_bytes;
+ four_bytes;
+ txfa[nf] -> scaled_size = lcx.l;
+ four_bytes;
+ txfa[nf] -> design_size = lcx.l;
+ for (i=0; i<256; i++) txfa[nf] -> chu[i] = '\0';
+ p = getc(dvifile); n = getc(dvifile);
+ font_name[nf] = malloc(p+n+1);
+ for (i=0; i<p+n; i++) { font_name[nf][i] = getc(dvifile); }
+ font_name[nf][p+n] = '\0';
+
+ if (txfa[nf] -> scaled_size <= 0 || txfa[nf] -> scaled_size >=
+ 8*8*8*8*8*8*8*8*8) {
+ printf("\n Font %s has a bad scaled size",font_name[nf]);
+ return(1);
+ }
+ if (txfa[nf] -> design_size <= 0 || txfa[nf] -> design_size >=
+ 8*8*8*8*8*8*8*8*8) {
+ printf("\n Font %s has a bad design size",font_name[nf]);
+ return(1);
+ }
+
+/* We follow DVItype and compute for each font a "space" parameter which is
+one-sixth of the scaled design size. This parameter is used in rounding the
+horizontal position to pixels according to "Stanford rules." See the
+function set_h below. */
+
+ txfa[nf] -> space = txfa[nf] -> scaled_size/6;
+
+ i = read_tfm_file();
+ if (i != 0) return(i);
+ nf++;
+ return(0);
+
+}
+
+/* TFM files, like the DVI file, are read with getc, foolish as that may
+seem. We use the same overlays that are used for merging DVI bytes into
+longwords. However, since the TFM file consists of longwords, only
+tfm_longword is need. [[This is also VAX dependent. It would not be
+possible to use stdio's longword reading function getw here, because the
+bytes have to be reversed.]] */
+
+#define tfm_longword { lcx.uc[3] = getc(tfmfile); \
+ lcx.uc[2] = getc(tfmfile); lcx.uc[1] = getc(tfmfile); \
+ lcx.uc[0] = getc(tfmfile); }
+
+/* Read_tfm_file obtains the character widths from the TFM file
+corresponding to font nf. */
+
+int read_tfm_file() {
+
+ int i,lh,nw;
+ int info[256];
+ long z,alpha,beta;
+ long width[256];
+
+ open_tfm_file();
+ if (tfmfile == NULL) {
+ printf("\n Can't open TFM file for font %s",font_name[nf]);
+ return(1); }
+
+/* The TFM format is described in some issue of the TUGBoat (TeX users'
+group newsletter), and in the comments to the program TFtoPL. Here we
+summarize those aspects of TFM format that are relevant to the task of
+extracting the widths of the characters.
+
+The first 24 bytes of a TFM file contain twelve 16-bit integers that give
+the lengths of the various subsequent portions of the file. The ones
+relevant to our purposes are LH, length of the header data, BC, the
+smallest character code in the font, EC, the largest character code in the
+font, and NW, number of words in the width table. So, we read those right
+now, and then skip over the remainder, and then over a set of LH longwords
+called the "header." */
+
+ tfm_longword;
+ lh = 256*lcx.uc[1] + lcx.uc[0];
+ tfm_longword;
+ txfa[nf] -> bc = 256*lcx.uc[3] + lcx.uc[2];
+ txfa[nf] -> ec = 256*lcx.uc[1] + lcx.uc[0];
+ tfm_longword;
+ nw = 256*lcx.uc[3] + lcx.uc[2];
+ if (txfa[nf] -> bc > 255 || txfa[nf] -> ec > 255 ||
+ txfa[nf] -> bc > txfa[nf] -> ec || nw > 256) {
+ printf("\n Bad TFM file for font %s",font_name[nf]);
+ return(1);
+ }
+
+ for(i=0; i<lh+3; i++) tfm_longword;
+
+/* After the header, there are two arrays in the TFM file that interest us.
+The first, INFO, is EC-BC+1 longwords long and contains pointers to the
+second, WIDTH, which is NW longwords long. For each character i, the width
+of i is WIDTH[INFO[i-BC]]. We read these arrays into memory. */
+
+ for(i=0; i<txfa[nf] -> ec-txfa[nf] -> bc+1; i++) {
+ tfm_longword;
+ if (lcx.uc[3] >= nw) {
+ printf("\n Bad TFM file for font %s",font_name[nf]);
+ return(1);
+ }
+ info[i] = lcx.uc[3];
+ }
+
+/* The widths are stored in a rather strange format known as a "fix-word."
+A nonnegative width is expressed in "fix-word" format by expressing it in
+units of 2^-20 times the design size. A negative width is expressed in
+"fix-word" format by expressing its negative in those units, and then
+changing the most significant byte to 255.
+
+One needs to convert these widths into DVI units, multiplying by the scaled
+design size according to a certain arcane algorithm. The algorithm is
+copied from DVItype, to which we refer the reader for an explanation. */
+
+ z = txfa[nf] -> scaled_size;
+ alpha = 16*z; beta = 16;
+ while (z >= 4*(8*8*8*8*8*8*8)) { z = z/2; beta = beta/2; }
+ for(i=0; i<nw; i++) {
+ tfm_longword;
+ width[i] = ( ( (lcx.uc[0]*z)/256 + lcx.uc[1]*z )/256 +
+ lcx.uc[2]*z)/beta;
+ if (lcx.uc[3] == 255) width[i] -= alpha;
+ }
+
+ fclose(tfmfile);
+
+/* Using these two arrays, we now compute the widths of the characters in
+the fonts and place them into two malloc'ed arrays, one for the widths in
+DVI units, one for the width in pixel units. */
+
+ font_width[nf] = (long int *)malloc(4*(txfa[nf] -> ec+1));
+
+ for (i=0; i<txfa[nf] -> bc; i++) font_width[nf][i] = 0;
+ for (i=txfa[nf] -> bc; i <= txfa[nf] -> ec; i++)
+ font_width[nf][i] = width[info[i-txfa[nf] -> bc]];
+ return(0);
+}
+
+/* Open_tfm_file finds and opens the tfm file corresponding to a font nf.
+The global file variable tfmfile is used to hold the file pointer. [[This
+function will not work if the TFM file lies over the net on a VMS V3.x
+host, because C file opens do not work in such circumstances. The problem
+can be ignored, because eventually there should be very few VMS V3.x hosts
+left.]] */
+
+int open_tfm_file () {
+
+ int jext,jnam;
+ char filespec[FILESPECLEN];
+
+#ifndef vms
+ char *texfontdir;
+#endif
+
+
+ find_filename(font_name[nf],&jnam,&jext);
+ filespec[0] = '\0';
+
+/* If there is no directory part, fill in using the logical tex$fonts */
+
+#ifdef vms
+ if (jnam == 0) strcpy(filespec,"tex$fonts:");
+#else
+ if (jnam == 0) {
+ texfontdir = getenv("TEX_FONTS");
+ strcpy(filespec,texfontdir);
+ strcat(filespec,"/");
+ }
+#endif
+ strcat(filespec,font_name[nf]);
+
+/* if there is no extension, add the extension ".tfm" */
+
+ if (font_name[nf][jext] == '\0') strcat(filespec,".tfm");
+ tfmfile = fopen(filespec,"r");
+
+}
+
+/* Define_font_pass2 skips a font definition from the DVI file. */
+
+int define_font_pass2()
+{
+ unsigned char p,n;
+ int i;
+ four_bytes;
+ four_bytes;
+ four_bytes;
+ p = getc(dvifile); n = getc(dvifile);
+ for (i=0; i<p+n; i++) getc(dvifile);
+}
+
+/* Do_rule writes into the ln3 file the escape sequence corresponding to a
+rule. The rule is silently clipped to fit on the page. */
+
+int do_rule(xx0,yy0,xx1,yy1)
+int xx0,yy0,xx1,yy1;
+{
+ int j;
+
+ xx0 = min(xx0+hoff,maxrmar);
+ xx1 = min(xx1+hoff,maxrmar);
+ xx0 = max(xx0,0);
+ xx1 = max(xx1,0);
+ yy0 = min(yy0+voff,maxbmar);
+ yy1 = min(yy1+voff,maxbmar);
+ yy0 = max(yy0,0);
+ yy1 = max(yy1,0);
+ if (xx0 > xx1) { j = xx0; xx0 = xx1; xx1 = j; }
+ if (yy0 > yy1) { j = yy0; yy0 = yy1; yy1 = j; }
+
+ if ((yy1 != yy0 && xx1 != xx0)) {
+ fprintf(outfile,"\033[1;%d;%d;%d;%d!|",
+ xx0,yy0,yy1-yy0,xx1-xx0);
+ inc_ln3p(25);
+ }
+}
+
+/* Set_v is called to execute vertical-position-altering commands, other
+than pops. It modifies v and vv, and outputs the vertical position to the
+LN3 file. We don't follow Stanford rules here. They sometimes set the
+vertical position in pixels vv to something other than the rounded value of
+v. Not following Stanford rules implies, for example, that the relative
+vertical positions of an accent and its accentee may differ by one pixel
+according to how the baseline of the accentee gets rounded. [[This should
+perhaps be fixed.]] */
+
+int set_v(v1)
+int v1;
+{
+ int l;
+
+ l = pixel_round(v1);
+ v = v1;
+ vv = l;
+ vpset = 0;
+}
+
+/* Set_h is called whenever a DVI command is encountered that alters the
+horizonal position, other than a set_char, set_rule or pop. It sets h to
+the new value, and alters hh according to Stanford rules. */
+
+int set_h(new_h)
+int new_h;
+{
+ int l,old_hh;
+
+ old_hh = hh;
+ l = pixel_round(new_h);
+ if (txfa[curf] == 0 || new_h-h >= txfa[curf] -> space
+ || new_h-h <= -4*txfa[curf] -> space) hh = l;
+ else {
+ hh += pixel_round(new_h-h);
+ if (hh-l > MAX_DRIFT) hh = l+MAX_DRIFT;
+ else if (hh-l < -MAX_DRIFT) hh = l-MAX_DRIFT;
+ }
+ h = new_h;
+ return(0);
+}