diff options
Diffstat (limited to 'dviware/ln03/rose/dvi2ln3.c')
-rw-r--r-- | dviware/ln03/rose/dvi2ln3.c | 1654 |
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); +} |