From e0c6872cf40896c7be36b11dcc744620f10adf1d Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Mon, 2 Sep 2019 13:46:59 +0900 Subject: Initial commit --- dviware/ln03/rose/clink.opt | 1 + dviware/ln03/rose/dvi2ln3.c | 1654 ++++++++++++++++++++++++++++++++++++ dviware/ln03/rose/dvi2ln3.dif | 109 +++ dviware/ln03/rose/dvi2ln3.lis | 1602 ++++++++++++++++++++++++++++++++++ dviware/ln03/rose/dvi2ln3nft.c | 1145 +++++++++++++++++++++++++ dviware/ln03/rose/ffc.pas | 277 ++++++ dviware/ln03/rose/ffc.web | 991 +++++++++++++++++++++ dviware/ln03/rose/forpxl.fdl | 4 + dviware/ln03/rose/ln03bis.mem | 632 ++++++++++++++ dviware/ln03/rose/ln03topp.pli | 1255 +++++++++++++++++++++++++++ dviware/ln03/rose/lnfinc.pli | 35 + dviware/ln03/rose/newffc.c | 1293 ++++++++++++++++++++++++++++ dviware/ln03/rose/older_driver.mem | 84 ++ dviware/ln03/rose/picmode.pli | 529 ++++++++++++ dviware/ln03/rose/specials.c | 480 +++++++++++ dviware/ln03/rose/toppnft.pli | 654 ++++++++++++++ 16 files changed, 10745 insertions(+) create mode 100644 dviware/ln03/rose/clink.opt create mode 100644 dviware/ln03/rose/dvi2ln3.c create mode 100644 dviware/ln03/rose/dvi2ln3.dif create mode 100644 dviware/ln03/rose/dvi2ln3.lis create mode 100644 dviware/ln03/rose/dvi2ln3nft.c create mode 100644 dviware/ln03/rose/ffc.pas create mode 100644 dviware/ln03/rose/ffc.web create mode 100644 dviware/ln03/rose/forpxl.fdl create mode 100644 dviware/ln03/rose/ln03bis.mem create mode 100644 dviware/ln03/rose/ln03topp.pli create mode 100644 dviware/ln03/rose/lnfinc.pli create mode 100644 dviware/ln03/rose/newffc.c create mode 100644 dviware/ln03/rose/older_driver.mem create mode 100644 dviware/ln03/rose/picmode.pli create mode 100644 dviware/ln03/rose/specials.c create mode 100644 dviware/ln03/rose/toppnft.pli (limited to 'dviware/ln03/rose') diff --git a/dviware/ln03/rose/clink.opt b/dviware/ln03/rose/clink.opt new file mode 100644 index 0000000000..a01884977f --- /dev/null +++ b/dviware/ln03/rose/clink.opt @@ -0,0 +1 @@ +sys$share:vaxcrtl/share 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 +#include +#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 "); + 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= 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= . + +The H option modifies the default horizontal offset. + +The V option modifies the default vertical offset. + +The S option has syntax /S={.}* where the {}* denotes +repetition, and a 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= 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 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 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 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 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 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 ec+1)); + + for (i=0; i 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 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); +} diff --git a/dviware/ln03/rose/dvi2ln3.dif b/dviware/ln03/rose/dvi2ln3.dif new file mode 100644 index 0000000000..56d9066f2e --- /dev/null +++ b/dviware/ln03/rose/dvi2ln3.dif @@ -0,0 +1,109 @@ +----------------------------------------------------------------------------------------------------------------------------------- +File USER$1:[ROSE.TG.C]DVI2LN3.C;48 | File USER$1:[ROSE.TG.UNIX]DVI2LN3.C;1 +-------------------------------- 3 --------------------------------------------------------------- 3 ------------------------------ +Dvi2ln3 is still being developed. Copyright (c) 1985, 1986 by D | Dvi2ln3 is still being developed. Copyright (c) 1985, 1986, 198 +-------------------------------- 62 -------------------------------------------------------------- 62 ----------------------------- +3/4/86: Support for landscape added -- very easy, if only I h | + known. Fixed bug found by Mark DeVries, error returne | + if \special selects device other than LN03. Version 8 | + | +-------------------------------- 86 -------------------------------------------------------------- 82 ----------------------------- +#endif | char *strchr(), *malloc(), *getenv(); + | #endif +/* Here begins a long list of global variables. */ | +-------------------------------- 120 ------------------------------------------------------------- 115 ---------------------------- +/* landscape says whether we are printing in landscape or portr | + | +GLOBAL char landscape; | + | +-------------------------------- 139 ------------------------------------------------------------- 130 ---------------------------- + printf("\n Dvi2ln3 8"); | printf("\n Dvi2ln3 7"); +-------------------------------- 151 ------------------------------------------------------------- 142 ---------------------------- + find_VMS_filename(infnam,&jnam,&jext); | find_ULTRIX_filename(infnam,&jnam,&jext); +-------------------------------- 163 ------------------------------------------------------------- 154 ---------------------------- + landscape = 0; | +-------------------------------- 170 ------------------------------------------------------------- 160 ---------------------------- + if (rewind(dvifile) == -1) { | rewind(dvifile); + printf("\n Couldn't rewind dvi file."); | + goto exit_label; | + } | +-------------------------------- 189 ------------------------------------------------------------- 176 ---------------------------- + ; | printf("\n"); +} | } + | +/* Find_VMS_filename finds the filename part of a VMS filespec | /* find_ULTRIX_filename finds the filename part of a VMS filesp +-------------------------------- 201 ------------------------------------------------------------- 188 ---------------------------- +int find_VMS_filename(s,ns,ne) | int find_ULTRIX_filename(s,ns,ne) +-------------------------------- 210 ------------------------------------------------------------- 197 ---------------------------- + if (s[j] == ':' || s[j] == ']' || | if (s[j] == '/') { + s[j] == '>') { | +-------------------------------- 219 ------------------------------------------------------------- 205 ---------------------------- + if (s[j] == '.' || s[j] == ';') { | if (s[j] == '.') { +-------------------------------- 260 ------------------------------------------------------------- 246 ---------------------------- +second identifying longword is 8 and third is 3. | second identifying longword is 8 and third is 3. */ + | +The L option says print in landscape. | /* [[The toupper's below cause difficulty under Ultrix. Probabl + | can be fixed by #including .]] */ +[[Is a European option needed?]] */ | +-------------------------------- 283 ------------------------------------------------------------- 268 ---------------------------- + if (toupper(t[0]) == 'L') landscape = 1; | +-------------------------------- 327 ------------------------------------------------------------- 311 ---------------------------- + jj = creat(outfnam,0); | jj = creat(outfnam, 0700); +-------------------------------- 749 ------------------------------------------------------------- 733 ---------------------------- +/* The margins are set to values that seem appropriate for Amer | /* The margins are set to values appropriate for American 8 1/2 +by 11" paper. It is not clear if this needs to be changed for E | paper. It is not clear if this needs to be changed for European +paper. Not changing it might deprive Europeans of access to the | Not changing it might deprive Europeans of access to the bottom +1.5cm of their paper. | their paper. */ + | +It is not clear what the printable area is, or what happens whe | maxrmar = 2550; +exceeded. */ | maxbmar = 3300; + | + if (landscape == 1) { | /* In the following, esc[?27h means "advance the carriage by th + maxrmar = 3300; | width when you set a character", esc[11h and esc[7 I together m + maxbmar = 2475; | interpret all dimensions in escape sequences as pixel units; es + } else { | our origin of coordinates is the upper left edge of the paper; + maxrmar = 2550; | means the "maximum length" of the paper is maxbmar pixels. */ + maxbmar = 3300; | + } | fprintf(outfile,"\033c\033[?27h\033[11h\033[7 I\033[?52h\03 + | +/* In the following, esc[?21 J means print in landscape, esc[?2 | +"advance the carriage by the character width when you set a cha | +esc[11h and esc[7 I together mean to interpret all dimensions i | +sequences as pixel units; esc[?52h means our origin of coordina | +upper left edge of the paper; esc[%dt means the "maximum length | +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 | +-------------------------------- 919 ------------------------------------------------------------- 892 ---------------------------- + fprintf(outfile,"\n;Dvi2ln3 8 font load\033\\"); | fprintf(outfile,"\n;Dvi2ln3 7 font load\033\\"); +-------------------------------- 1127 ------------------------------------------------------------ 1100 --------------------------- +about Dvi2ln3 even though the error is in their TeX file). | about Dvi2ln3 even though the error is in their TeX file). In m + | dvi2ln3 takes no special action at all, since the LN03 will cli +In most cases, dvi2ln3 takes no special action at all, since th | for us. Unfortunately, the LN03 doesn't let us specify negative +clip the glyphs for us. Unfortunately, the LN03 doesn't let us | or vertical positions, so we have to clip glyphs at such positi +negative horizontal or vertical positions, so we have to clip g | ourselves. The following code accomplishes that: */ +such positions away ourselves. Also, if one sets at a position | +bottom margin, the LN03 will eject a page, so glyphs that are s | +that margin also have to be clipped by hand. | + | +The following code accomplishes that: */ | +-------------------------------- 1141 ------------------------------------------------------------ 1109 --------------------------- + if (vv+voff > 0 && vv+voff <= maxbmar && hh+hoff > | if (vv+voff > 0 && hh+hoff > 0) { +-------------------------------- 1481 ------------------------------------------------------------ 1449 --------------------------- + | char *texfontdir; + find_VMS_filename(font_name[nf],&jnam,&jext); | + | find_ULTRIX_filename(font_name[nf],&jnam,&jext); +-------------------------------- 1487 ------------------------------------------------------------ 1456 --------------------------- + if (jnam == 0) strcpy(filespec,"tex$fonts:"); | if (jnam == 0) texfontdir = getenv("TEX_FONTS"); + | strcpy(filespec,texfontdir); + | strcat(filespec,"/"); +----------------------------------------------------------------------------------------------------------------------------------- + +Number of difference sections found: 21 +Number of difference records found: 78 + +DIFFERENCES /IGNORE=()/OUTPUT=USER$1:[ROSE.TG.C]DVI2LN3.DIF;1/PARALLEL- + USER$1:[ROSE.TG.C]DVI2LN3.C;48- + USER$1:[ROSE.TG.UNIX]DVI2LN3.C;1 diff --git a/dviware/ln03/rose/dvi2ln3.lis b/dviware/ln03/rose/dvi2ln3.lis new file mode 100644 index 0000000000..b8c209889d --- /dev/null +++ b/dviware/ln03/rose/dvi2ln3.lis @@ -0,0 +1,1602 @@ + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 1 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + + + 1 /* Dvi2ln3 translates a TeX DVI file to an LN03 format file. + 2 + 3 Dvi2ln3 is still being developed. Copyright (c) 1985 by Digital Equipment + 4 Corporation, Maynard, Massachusetts, USA. Author: Flavio Rose, + 5 shasta!decwrl!dec-rhea!dec-dvinci!rose. + 6 + 7 Dvi2ln3 is based on the publicly-available program DVItype, written by + 8 David R. Fuchs of Stanford University; and also on earlier DEC programs for + 9 the LN01 and LN03 laser printers, Dvi2lng, Topp and LN03Topp. This program + 10 is not a DEC product and is not guaranteed to work. + 11 + 12 Dvi2ln3 is written in VAX C. Specific VAX and VMS dependencies have + 13 generally been avoided, however. The reader may find them by searching + 14 for the strings VAX and VMS in this file. + 15 + 16 During development, double square brackets [[ ]] in a comment indicate some + 17 places where the code needs to be improved. + 18 + 19 [[Among the useful things that still need to be done: differentiating + 20 between int and long variables so this can be ported more easily to 16-bit + 21 architectures; testing to see if malloc returns 0; a \special for ROM + 22 fonts; a \special for sixels.]] + 23 + 24 Development history: + 25 + 26 Feb. 85: Did some early work on Dvi2ln3, translating bits and pieces + 27 of Dvi2lng. Concluded, however, that it was better to translate + 28 LN03Topp and Dvi2lng into C first. The reason for this is that code + 29 which mimics an existing program is easier to write and to test. + 30 + 31 5/15/85: At this date, the old LN03Topp program has been successfully + 32 translated into C (except for the ability to read files over + 33 DECnet). At this point, did some further cleanup of the Dvi2ln3 + 34 source. + 35 + 36 6/4/85: Coding of Dvi2ln3 begins in earnest. Merging bits and + 37 pieces from various places. Chucking chunks and all that + 38 junk from LN03Topp; pass2 is just straightforward translation. + 39 + 40 6/22/85: Cleanup after initial debugging. Ready to distribute. + 41 + 42 10/14/85: Bug in parsing of \special's. Version 1. + 43 + 44 */ + 45 + 46 #include stdio + 104 + 105 /* To please the VMS linker, we declare all global variables to be + 106 globaldef. This is done with #define's, so it may easily be undone when + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 2 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + 107 porting the program to other systems. */ + 108 + 109 #ifdef vms + 110 #define GLOBAL globaldef + 111 #define EXTERN globalref + 112 #else + 113 X #define GLOBAL + 114 X #define EXTERN extern + 115 #endif + 116 + 117 /* hoff is the horizontal offset in pixels to be added to all dimensions + 118 read in; voff is the corresponding vertical offset. */ + 119 + 120 GLOBAL int hoff, voff, startp; + 121 GLOBAL FILE *dvifile,*tfmfile,*outfile; + 122 + 123 /* Each page in a DVI file is identified by ten longwords, which appear + 124 immediately after each bop (beginning of page) command. Dvi2ln3, like + 125 DVItype, supports certain options that allow one to print only selected + 126 pages. The following variables are used for this purpose. + 127 + 128 Num_pages is a count of how many pages have been passed to the output. + 129 Max_pages is the user-specified maximum number of pages to pass. + 130 How_many_counts denotes the number of identifying longwords to take into + 131 account when searching for the user-specified starting page. The user + 132 specifies the starting page as the first one whose identifying longwords + 133 match certain specified values, stored in start_page. However, identifying + 134 longword i is only required to match the value in start_page[i] if + 135 use_count[i] is nonzero. */ + 136 + 137 GLOBAL long int num_pages,max_pages; + 138 GLOBAL int how_many_counts,use_count[10]; + 139 GLOBAL long int start_page[10]; + 140 + 141 /* FILESPECLEN is the maximum size of a file specification under VMS. + 142 [[Perhaps arrays of fixed size should not be used, but rather malloc should + 143 be employed...]] */ + 144 + 145 #define FILESPECLEN 252 + 146 + 147 /* The main routine deals with the command line arguments, opens the dvi + 148 file, and then calls various other routines to handle the "passes". There + 149 are two passes which involve reading the DVI file; in between, the font + 150 load is constructed. */ + 151 + 152 main(argc,argv) + 153 int argc; + 154 char *argv[]; + 155 { + 156 1 int status,i,jnam,jext; + 157 1 char infnam[FILESPECLEN]; + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 3 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + 158 1 + 159 1 if (argc < 2) { printf("\n Usage: Dvi2ln3 "); + 160 2 goto exit_label; } + 161 1 + 162 1 printf("\n Dvi2ln3 1"); + 163 1 + 164 1 strcpy(infnam,argv[1]); + 165 1 + 166 1 /* The extension of the input file defaults to .dvi. Locate the filename + 167 1 field within the filespec parameter, set jname to point to beginning, jext + 168 1 to point to one place after end. [[This code is of course dependent on the + 169 1 VMS filespec syntax.]] */ + 170 1 + 171 1 find_VMS_filename(infnam,&jnam,&jext); + 172 1 if (infnam[jext] == '\0') strcat(infnam,".dvi"); + 173 1 dvifile = fopen(infnam,"r"); + 174 1 if (dvifile == NULL) { printf("\n Couldn't open dvi file"); + 175 2 goto exit_label; } + 176 1 + 177 1 /* Now decipher the options off the command line. */ + 178 1 + 179 1 max_pages = 1000000000; + 180 1 how_many_counts = 0; + 181 1 hoff = 300; + 182 1 voff = 300; + 183 1 for (i=2; i= 0; j--) { + 227 2 if (s[j] == ':' || s[j] == ']' || + 228 2 s[j] == '>') { + 229 3 jnam = j+1; + 230 3 break; + 231 3 } + 232 2 } + 233 1 + 234 1 jext = slen; + 235 1 for (j = jnam; j < slen; j++) { + 236 2 if (s[j] == '.' || s[j] == ';') { + 237 3 jext = j; + 238 3 break; + 239 3 } + 240 2 } + 241 1 + 242 1 *ns = jnam; + 243 1 *ne = jext; + 244 1 } + 245 + 246 /* ERROR HANDLING: Errors should be reported as close to the source as + 247 possible, so that the maximum amount of information is available to the + 248 user to identify the error. + 249 + 250 Errors in the format of DVI or TFM files are not reported specifically, + 251 since there exist programs, DVItype and TFtoPL, which diagnose errors in + 252 such files. This program accepts some incorrect DVI files, for example, + 253 those with a bad postamble or bad backpointers. [[However, someday we may + 254 rewrite the program to select pages by using these features of the DVI + 255 format, rather than by skipping unwanted pages.]] */ + 256 + 257 GLOBAL char *bad_DVI_message = "\nBad DVI file - check it with DVItype"; + 258 + 259 /* Command_line_options reads and processes options off the string s. At + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 5 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + 260 this time, four options are supported. + 261 + 262 The N option sets the maximum number of pages to be printed. Its syntax is + 263 /N= . + 264 + 265 The H option modifies the default horizontal offset. + 266 + 267 The V option modifies the default vertical offset. + 268 + 269 The S option has syntax /S={.}* where the {}* denotes + 270 repetition, and a is either an integer or * to indicate any + 271 value. An example would be "/S=*.8.3". + 272 + 273 The meaning of the S option is as follows: In a DVI file, pages are + 274 identified by ten longword values which follow each bop (beginning of page) + 275 command. The value of the S option indicates which page to start printing + 276 on. For example, "*.8.3" means start printing at the first page whose + 277 second identifying longword is 8 and third is 3. */ + 278 + 279 int command_line_options(t) + 280 char *t; + 281 { + 282 1 long int i,k; + 283 1 char *u; + 284 1 + 285 1 while ((t = strchr(t,'/')) != 0) { + 286 2 t++; + 287 2 if (toupper(t[0]) == 'N' && t[1] == '=' + 288 2 && (sscanf(&t[2],"%ld",&k) == 1)) + 289 2 max_pages = k; + 290 2 if (toupper(t[0]) == 'H' && t[1] == '=' + 291 2 && (sscanf(&t[2],"%ld",&k) == 1)) + 292 2 hoff = k; + 293 2 if (toupper(t[0]) == 'V' && t[1] == '=' + 294 2 && (sscanf(&t[2],"%ld",&k) == 1)) + 295 2 voff = k; + 296 2 else if (toupper(t[0]) == 'S' && t[1] == '=') { + 297 3 t += 2; + 298 3 how_many_counts = 0; + 299 3 for (;;) { + 300 4 if (t[0] == '*') { + 301 5 use_count[how_many_counts] = 0; + 302 5 how_many_counts++; + 303 5 } + 304 4 else if (sscanf(t,"%ld",&k) != 0) { + 305 5 use_count[how_many_counts] = 1; + 306 5 start_page[how_many_counts] = k; + 307 5 how_many_counts++; + 308 5 } else break; + 309 4 u = strchr(t,'.'); + 310 4 if (u == 0) break; + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 6 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + 311 4 t = &u[1]; + 312 4 } + 313 3 } + 314 2 } + 315 1 } + 316 + 317 /* Open_output_file opens one of the output files, using the file pointer + 318 outfile. The name of the output file is obtained by appending the string + 319 ext to the substring of infnam beginning at jnam and ending at jext. + 320 + 321 [[This code contains a VMS depndency. We use creat followed by fdopen to + 322 open the file as a normal VMS file ("rat=cr","rfm=var") rather than a + 323 STREAM_LF file. Beginning with VAX C V2.0, this can be done by just calling + 324 fopen.]] */ + 325 + 326 int open_output_file(infnam,jnam,jext,ext) + 327 char *infnam,*ext; + 328 int jnam,jext; + 329 { + 330 1 char outfnam[FILESPECLEN]; + 331 1 int jj; + 332 1 + 333 1 strcpy(outfnam,&infnam[jnam]); + 334 1 strcpy(&outfnam[jext-jnam],ext); + 335 1 + 336 1 jj = creat(outfnam,0,"rat=cr","rfm=var"); + 337 1 if (jj == -1) return(1); + 338 1 outfile = fdopen(jj,"w"); + 339 1 if (outfile == NULL) return(1); + 340 1 + 341 1 return(0); + 342 1 } + 343 + 344 /* Bytes are read one by one from the DVI file using getc. We use an + 345 overlay, as suggested in the DVItype documentation, to combine these bytes + 346 into larger integers. [[Note that this technique relies on the fact that + 347 numbers on the VAX are stored with the least significant byte first. The + 348 macros below would have to be changed if the program were to be ported to a + 349 machine architecture for which this is not so.]] + 350 + 351 [[The use of getc is expensive, since getc is a function in VAX C V2.0. + 352 Eventually, one would want to rewrite these macros to work like the old + 353 getc macro.]] */ + 354 + 355 GLOBAL union lc { long int l; unsigned long int ul; char c[4]; + 356 unsigned char uc[4]; } lcx; + 357 + 358 #define two_bytes_u lcx.uc[1] = getc(dvifile); \ + 359 lcx.uc[0] = getc(dvifile); lcx.uc[2] = 0; lcx.uc[3] = 0 + 360 + 361 #define two_bytes_s lcx.c[1] = getc(dvifile); \ + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 7 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + 362 lcx.c[0] = getc(dvifile); \ + 363 if (lcx.c[1] >= 0) { lcx.uc[2] = 0; lcx.uc[3] = 0 ;} \ + 364 else { lcx.uc[2] = 255; lcx.uc[3] = 255; } + 365 + 366 #define three_bytes_u lcx.uc[3] = getc(dvifile); lcx.uc[1] = getc(dvifile); \ + 367 lcx.uc[0] = getc(dvifile); lcx.uc[2] = 0 + 368 + 369 #define three_bytes_s lcx.c[2] = getc(dvifile); lcx.c[1] = getc(dvifile); \ + 370 lcx.c[0] = getc(dvifile); \ + 371 lcx.uc[3] = (lcx.c[2] >= 0) ? 0 : 255; + 372 + 373 #define four_bytes lcx.c[3] = getc(dvifile); \ + 374 lcx.c[2] = getc(dvifile); lcx.c[1] = getc(dvifile); \ + 375 lcx.c[0] = getc(dvifile); + 376 + 377 /* Knuth's programs like to hardcode fixed maximum sizes for various + 378 things, for example, the maximum number of fonts allowed in a DVI file. In + 379 general, it is preferable to use the C function malloc to allocate storage + 380 as needed. That is what we generally do in this Dvi2ln3, but there are some + 381 residues of the Knuthian approach, like MAXTEXFONTS below. By the way, we + 382 never attempt to return any storage to the system. + 383 + 384 [[Eventually, it would be better to get rid of MAXTEXFONTS and use a linked + 385 list of records instead. There would be no cpu time penalty to using a + 386 linked list, because the function set_curf below does a linear search + 387 through the font array anyway.]] */ + 388 + 389 #define MAXTEXFONTS 100 + 390 + 391 struct txf { unsigned char chu[256]; int bc, ec; long int space, design_size, + 392 scaled_size; int nchs; }; + 393 + 394 GLOBAL struct txf *txfa[MAXTEXFONTS+1]; + 395 + 396 /* Font width information needs to be read from TFM files. TFM is a special + 397 format defined by TeX. Dvi2ln3 stores each width in a longword. DVItype + 398 tries to save space by a two-level width storage method. We just allocate + 399 an array of widths for each font with malloc. + 400 + 401 [[We don't check that font checksums match in Dvi2ln3, because there are a + 402 lot of slightly obsolete TFMs floating around which would result in a + 403 checksum error, but seem to give perfectly reasonable formatted output + 404 nonetheless.]] */ + 405 + 406 GLOBAL long int *font_width[MAXTEXFONTS+1]; + 407 + 408 /* TeX fonts are referred to by their internal numbers, which go from 0 to + 409 nf-1. The DVI file refers to them by external numbers, hence the array + 410 to_ext used to convert internal numbers to external numbers. Curf is the + 411 internal font number of the current font in the DVI file. */ + 412 + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 8 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + 413 GLOBAL int to_ext[MAXTEXFONTS+1], + 414 nf, + 415 curf; + 416 + 417 /* In some switch statements, a lot of cases have to be enumerated. We + 418 employ this Knuthian macro for that purpose: */ + 419 + 420 #define four_cases(_x1) case _x1: case _x1+1: case _x1+2: case _x1+3: + 421 + 422 /* We define a lot of constants corresponding to the DVI operation codes. + 423 These are copied from DVItype. */ + 424 + 425 #define id_byte 2 /* current version of the dvi format */ + 426 #define set_char_0 0 /* typeset character 0 and move right */ + 427 #define set1 128 /* typeset a character and move right */ + 428 #define set_rule 132 /* typeset a rule and move right */ + 429 #define put1 133 /* typeset a character */ + 430 #define put_rule 137 /* typeset a rule */ + 431 #define nop 138 /* no operation */ + 432 #define bop 139 /* beginning of page */ + 433 #define eop 140 /* ending of page */ + 434 #define push 141 /* save the current positions */ + 435 #define pop 142 /* restore previous positions */ + 436 #define right1 143 /* move right */ + 437 #define w0 147 /* move right by |w| */ + 438 #define w1 148 /* move right and set |w| */ + 439 #define x0 152 /* move right by |x| */ + 440 #define x1 153 /* move right and set |x| */ + 441 #define down1 157 /* move down */ + 442 #define y0 161 /* move down by |y| */ + 443 #define y1 162 /* move down and set |y| */ + 444 #define z0 166 /* move down by |z| */ + 445 #define z1 167 /* move down and set |z| */ + 446 #define fnt_num_0 171 /* set current font to 0 */ + 447 #define fnt1 235 /* set current font */ + 448 #define xxx1 239 /* extension to dvi primitives (\special) */ + 449 #define xxx4 242 /* potentially long extension to dvi primitives */ + 450 #define fnt_def1 243 /* define the meaning of a font number */ + 451 #define pre 247 /* preamble */ + 452 #define post 248 /* postamble beginning */ + 453 #define post_post 249 /* postamble ending */ + 454 #define undefined_command 250 + 455 + 456 GLOBAL long int mag, num, den; + 457 GLOBAL float conv, unmag_conv; + 458 + 459 /* Read_preamble reads the preamble of the dvi file. The comment is thrown + 460 away. The format version number is checked. The magnification, numerator, + 461 and denominator are remembered in the globals mag, num, den. The float + 462 values conv and unmag_conv serve to convert measurements from DVI units to + 463 pixels. */ + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 9 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + 464 + 465 int read_preamble() { + 466 1 unsigned int i; + 467 1 int j; + 468 1 + 469 1 i = getc(dvifile); + 470 1 if (i != pre) return(1); + 471 1 i = getc(dvifile); + 472 1 if (i != id_byte) return(1); + 473 1 four_bytes; num = lcx.l; + 474 1 if (num <= 0) return(1); + 475 1 four_bytes; den = lcx.l; + 476 1 if (den <= 0) return(1); + 477 1 four_bytes; mag = lcx.l; + 478 1 if (mag <= 0) return(1); + 479 1 + 480 1 unmag_conv = (num/254000.0) * (300.0/den); + 481 1 conv = unmag_conv * (mag/1000.0); + 482 1 + 483 1 /* Skip over the comment field. */ + 484 1 + 485 1 i = getc(dvifile); + 486 1 for (j=0; j= set_char_0) && (o < set_char_0+128)) + 509 1 return(o-set_char_0); + 510 1 if ((o >= fnt_num_0) && (o < fnt_num_0+64)) + 511 1 return(o-fnt_num_0); + 512 1 switch (o) { + 513 2 case set1: + 514 2 case put1: + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 10 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + 515 2 case fnt1: + 516 2 case xxx1: + 517 2 case fnt_def1: + 518 2 i = getc(dvifile); + 519 2 return(i); + 520 2 case set1+1: + 521 2 case put1+1: + 522 2 case fnt1+1: + 523 2 case xxx1+1: + 524 2 case fnt_def1+1: + 525 2 two_bytes_u; + 526 2 return(lcx.ul); + 527 2 case set1+2: + 528 2 case put1+2: + 529 2 case fnt1+2: + 530 2 case xxx1+2: + 531 2 case fnt_def1+2: + 532 2 three_bytes_u; + 533 2 return(lcx.ul); + 534 2 case right1: + 535 2 case w1: + 536 2 case x1: + 537 2 case down1: + 538 2 case y1: + 539 2 case z1: + 540 2 return(getc(dvifile)); + 541 2 case right1+1: + 542 2 case w1+1: + 543 2 case x1+1: + 544 2 case down1+1: + 545 2 case y1+1: + 546 2 case z1+1: + 547 2 two_bytes_s; + 548 2 return(lcx.l); + 549 2 case right1+2: + 550 2 case w1+2: + 551 2 case x1+2: + 552 2 case down1+2: + 553 2 case y1+2: + 554 2 case z1+2: + 555 2 three_bytes_s; + 556 2 return(lcx.l); + 557 2 case set_rule: + 558 2 case put_rule: + 559 2 case right1+3: + 560 2 case w1+3: + 561 2 case x1+3: + 562 2 case down1+3: + 563 2 case y1+3: + 564 2 case z1+3: + 565 2 case set1+3: + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 11 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + 566 2 case put1+3: + 567 2 case fnt1+3: + 568 2 case xxx1+3: + 569 2 case fnt_def1+3: + 570 2 four_bytes; + 571 2 return(lcx.l); + 572 2 case w0: + 573 2 return(w); + 574 2 case x0: + 575 2 return(x); + 576 2 case y0: + 577 2 return(y); + 578 2 case z0: + 579 2 return(z); + 580 2 default: + 581 2 return(0); + 582 2 } + 583 1 } + 584 + 585 /* Pass1 reads from the DVI file until the starting page condition is met. + 586 Return 1 if something goes wrong, or if the DVI file comes to an end. This + 587 resembles skip_pages below. */ + 588 + 589 int pass1() { + 590 1 + 591 1 unsigned int k; + 592 1 long int p; + 593 1 int i; + 594 1 char startp; + 595 1 + 596 1 if (read_preamble() != 0) { + 597 2 printf(bad_DVI_message); + 598 2 return(1); + 599 2 } + 600 1 + 601 1 for (;;) { + 602 2 if (feof(dvifile)) { + 603 3 printf(bad_DVI_message); + 604 3 return(1); + 605 3 } + 606 2 k = getc(dvifile); + 607 2 if (k == post) return(0); + 608 2 p = first_par(k); + 609 2 if (k >= set_char_0 && k < set_char_0+128) k = set1; + 610 2 if (k >= fnt_num_0 && k < fnt_num_0+64) k = fnt1; + 611 2 + 612 2 switch (k) { + 613 3 case bop: + 614 3 startp = 1; + 615 3 for (i=0; i<10; i++) { + 616 4 four_bytes; + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 12 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + 617 4 if (i < how_many_counts && use_count[i] && + 618 4 lcx.l != start_page[i]) startp = 0; + 619 4 } + 620 3 four_bytes; + 621 3 if (startp != 0) num_pages = 1; + 622 3 else if (num_pages > 0) { + 623 4 num_pages++; + 624 4 if (num_pages > max_pages) return(0); + 625 4 } + 626 3 break; + 627 3 case set_rule: + 628 3 case put_rule: + 629 3 four_bytes; + 630 3 break; + 631 3 four_cases(fnt_def1) + 632 3 i = define_font(p); + 633 3 if (i != 0) return(1); + 634 3 break; + 635 3 four_cases(fnt1) + 636 3 if (num_pages > 0) set_curf(p); + 637 3 break; + 638 3 four_cases(set1) + 639 3 four_cases(put1) + 640 3 if (num_pages > 0) + 641 3 txfa[curf] -> chu[p] = 1; + 642 3 break; + 643 3 four_cases(xxx1) + 644 3 for (; p>0; p--) getc(dvifile); + 645 3 break; + 646 3 default: + 647 3 break; + 648 3 } + 649 2 } + 650 1 return(0); + 651 1 } + 652 + 653 #define leftfirst 33 + 654 #define rightfirst 161 + 655 #define leftlast 126 + 656 #define rightlast 254 + 657 + 658 /* The define of maxnfonts below is based on a belief, perhaps + 659 superstitious, that there is a limit of 31 downline-loaded fonts in the + 660 LN03. For us an nfont is two LN03 fonts, hence the following definition. */ + 661 + 662 #define maxnfonts 16 + 663 + 664 /* Txf is a record structure describing a TeX font. Txfa is an array of txf + 665 records. Txf2lnf describes the mapping between TeX fonts and pairs of LN03 + 666 fonts. Because the constructed LN03 font load has just the glyphs that are + 667 needed, we can often cram more than one TeX font into a pair of LN03 fonts. + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 13 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + 668 + 669 Why a pair of fonts? Because LN03 fonts are allowed to hold 94 glyphs only. + 670 They come in two flavors, "left" which answer to character codes 33 to 126, + 671 and "right" which answer to codes 161 to 254. LN03Topp assigns each TeX + 672 font to one "lnfno", where each lnfno denotes a pair of LN03 fonts, one + 673 left, one right. */ + 674 + 675 GLOBAL int txf2lnf[MAXTEXFONTS]; + 676 + 677 /* Maxfontnos reflects the fact that all LN03 fonts must be denoted by + 678 a number from 10 to 19. */ + 679 + 680 #define maxfontnos 9 + 681 + 682 GLOBAL int lastch[maxnfonts]; + 683 GLOBAL unsigned char chw[maxnfonts][256]; + 684 GLOBAL char fname[maxnfonts][32]; + 685 + 686 /* The LN03 font-denoting numbers 10-19 have to be allocated among the + 687 fonts. The useno array keeps track of which number a font is allowed to + 688 use, -1 if none is currently allocated. The whouses array says which font + 689 is using a number. */ + 690 + 691 GLOBAL int useno[maxnfonts],whouses[maxfontnos]; + 692 + 693 /* Font_name points to strings containing font names, which are created + 694 with malloc as needed. */ + 695 + 696 GLOBAL char *font_name[MAXTEXFONTS+1]; + 697 + 698 GLOBAL int maxrmar,maxbmar; + 699 + 700 #define max(x,y) (((x)>(y))?(x):(y)) + 701 #define min(x,y) (((x)<(y))?(x):(y)) + 702 + 703 /* Make_font_load calls on other procedures to generate the LN03 font load. + 704 */ + 705 + 706 int make_font_load() { + 707 1 + 708 1 int i,j,jj,k,l,fno,maxfno,chsize; + 709 1 long int totsize; + 710 1 int lnfcnt,txfcnt,the_txf,txf_size,lnfleft; + 711 1 int txford[MAXTEXFONTS]; + 712 1 char cnt[3]; + 713 1 + 714 1 totsize = 0; + 715 1 chsize = 0; + 716 1 curf = 0; + 717 1 for (i=0; i nchs = 0; + 762 2 for(i=0; i<256; i++) + 763 2 if (txfa[fno] -> chu[i] != 0) txfa[fno] -> nchs++; + 764 2 + 765 2 if (txfa[fno] -> nchs > 188) goto need_empty_slots; + 766 2 chsize += txfa[fno] -> nchs; + 767 2 } + 768 1 printf("\nFont load to contain %d glyphs.",chsize); + 769 1 + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 15 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + 770 1 + 771 1 /* Now we have to allocate TeX fonts to LN03 fonts pairs and perform the + 772 1 actual load. The goal is to use as few slots as possible, where an LN03 + 773 1 font pair with <= 94 glyphs is one slot, and a font pair with > 94 but <= + 774 1 188 glyphs is two slots. + 775 1 + 776 1 As in the LN01 case, the allocation problem seems to be some sort of hard + 777 1 bin packing problem. (Proof of NP-hardness, anyone?) So we use a best fit + 778 1 heuristic: + 779 1 + 780 1 1. Find the unassigned largest TeX font. If none, exit, we're done. + 781 1 + 782 1 2. Allocate an LN03 font pair for that TeX font and put the TeX + 783 1 font into it. + 784 1 + 785 1 3. Find the largest remaining TeX font that fits in what is left of + 786 1 that LN03 font pair. + 787 1 + 788 1 3.1. if none exists, go to 1. + 789 1 3.2. if one exists, put it in the font pair and go back to 3. + 790 1 + 791 1 The txford array contains the TeX font numbers in the order that they are + 792 1 assigned. Txfcnt keeps track of how many TeX fonts have been assigned so + 793 1 far. */ + 794 1 + 795 1 lnfcnt = 0; + 796 1 txfcnt = 0; + 797 1 for (i=0; i nchs > txf_size) { + 808 4 txf_size = txfa[j] -> nchs; + 809 4 the_txf = j; + 810 4 } + 811 3 } + 812 2 if (txf_size <= 0) goto assignment_done; + 813 2 if (lnfcnt > maxnfonts) goto too_complex; + 814 2 if (txf_size > lnfleft) goto need_empty_slots; + 815 2 + 816 2 /* Now allocate new LN03 font pair and put the current TeX font into it */ + 817 2 + 818 2 txf2lnf[the_txf] = lnfcnt; + 819 2 txford[txfcnt] = the_txf; + 820 2 txfcnt++; + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 16 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + 821 2 k = leftfirst-1; + 822 2 for (j = 0; j <= 255; j++) { + 823 3 if (txfa[the_txf] -> chu[j] != 0) { + 824 4 k++; + 825 4 if (k == leftlast+1) k = rightfirst; + 826 4 lnfleft--; + 827 4 txfa[the_txf] -> chu[j] = k; + 828 4 } + 829 3 } + 830 2 lastch[lnfcnt] = k; + 831 2 + 832 2 /* Now try to fill the remaining part of the LN03 font pair using other TeX + 833 2 fonts */ + 834 2 + 835 2 while (1) { + 836 3 + 837 3 txf_size = -1; + 838 3 for (j = 0; j < MAXTEXFONTS; j++) { + 839 4 if (txfa[j] != 0 && txf2lnf[j] == -1 + 840 4 && txfa[j] -> nchs > txf_size + 841 4 && txfa[j] -> nchs <= lnfleft) { + 842 5 txf_size = txfa[j] -> nchs; + 843 5 the_txf = j; + 844 5 } + 845 4 } + 846 3 if (txf_size <= 0) break; + 847 3 + 848 3 txf2lnf[the_txf] = lnfcnt; + 849 3 txford[txfcnt] = the_txf; + 850 3 txfcnt++; + 851 3 k = lastch[lnfcnt]; + 852 3 for (j=0; j<=255; j++) { + 853 4 if (txfa[the_txf] -> chu[j] != 0) { + 854 5 k++; + 855 5 lnfleft--; + 856 5 if (k == leftlast+1) k = rightfirst; + 857 5 txfa[the_txf] -> chu[j] = k; + 858 5 } + 859 4 } + 860 3 lastch[lnfcnt] = k; + 861 3 } + 862 2 + 863 2 lnfcnt++; + 864 2 } + 865 1 + 866 1 assignment_done: + 867 1 + 868 1 /* At this point the array txf2lnf is properly initialized, as are lastch + 869 1 and txford. It remains to actually generate the desired font load. This has + 870 1 to be done carefully, since the function add_txf_to_lnf only supports + 871 1 adding glyphs to an LN03 font pair in ascending order of character code. */ + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 17 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + 872 1 + 873 1 for (j=0; j 188 characters. Can't handle that.", + 914 1 font_name[fno]); + 915 1 return(1); + 916 1 + 917 1 /* [[The error message above should be fixed to specify the magnification + 918 1 of the font also.]] */ + 919 1 + 920 1 } + 921 + 922 /* The lines in the LN3 file are limited to lengths of about 100 bytes. We + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 18 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + 923 keep track of how many bytes are written so far in the global lnhp. The + 924 accounting is conservative, so e.g. each pixel position counts as 4 bytes + 925 even though it might be shorter. [[One could easily increase 100 to 200. It + 926 is not clear what problems are provoked by going over, say, 256.]] + 927 + 928 Vpset keeps track of whether the vertical position needs to be output to + 929 the LN03 file before setting any more characters. Hh_old keeps track of the + 930 horizontal position which LN03 thinks it's at. */ + 931 + 932 GLOBAL int ln3p,vpset,hh_old; + 933 + 934 #define inc_ln3p(x) ln3p += x; if (ln3p > 100) \ + 935 { ln3p = 0; vpset = 0; hh_old = 30000; } + 936 + 937 /* [[In the above macro, hh_old is set to 30000 to mean "a very large + 938 number" (the maximum valid hh for an LN03 is 2550), so as to force the code + 939 below to re-output the true hh. What are the implications of this kludge? + 940 Would it not be more reasonable to have instead an hhset variable?]] */ + 941 + 942 /* A stack of hvxyzw values is kept; the stack pointer is called s. + 943 [[Again, it would be better to make this stack a linked list.]] */ + 944 + 945 #define STACKSIZE 100 + 946 + 947 GLOBAL long hstack[STACKSIZE], vstack[STACKSIZE], xstack[STACKSIZE], + 948 ystack[STACKSIZE], zstack[STACKSIZE], wstack[STACKSIZE]; + 949 GLOBAL int hhstack[STACKSIZE], vvstack[STACKSIZE]; + 950 GLOBAL int s; + 951 + 952 /* DVI files specify distances in units of 2^-16 points. When translating + 953 to a device-specific format, it is necessary to round the DVI distances to + 954 pixel units. This is done by means of the pixel_round macro. + 955 + 956 However, rather than using this macro in the straightforward way, rounding + 957 is often performed by more elaborate techniques, which we call "Stanford + 958 rules" (after John Le Carre's "Moscow rules"). These rules make use of a + 959 parameter MAX_DRIFT, which is roughly the maximum number of pixels that + 960 things are allowed to deviate from straightforward rounding. */ + 961 + 962 #define pixel_round(x) ((int) ((x<0) ? \ + 963 (conv*(x)-0.5) : (conv*(x)+0.5))) + 964 + 965 #define MAX_DRIFT 2 + 966 + 967 /* Pass2 reads the dvi file and interprets the commands in it, usually by + 968 calling other routines. The interpretation generally consists of writing + 969 something into the ln3 file, updating the current fonts and positions, and + 970 possibly updating the stack. */ + 971 + 972 int pass2() + 973 { + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 19 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + 974 1 int i,j; + 975 1 long int p; + 976 1 unsigned int k; + 977 1 + 978 1 if (read_preamble() != 0) { + 979 2 printf(bad_DVI_message); + 980 2 return(1); + 981 2 } + 982 1 + 983 1 curf = 0; + 984 1 ln3p = 0; + 985 1 s = 0; + 986 1 vpset = 0; + 987 1 hh_old = 30000; + 988 1 + 989 1 /* Skip pages until the desired starting page is reached. A nonzero value + 990 1 is returned if the starting page is never encountered. */ + 991 1 + 992 1 if (skip_pages() != 0) return(0); + 993 1 + 994 1 for (;;) { + 995 2 if feof(dvifile) { + 996 3 printf(bad_DVI_message); + 997 3 return(1); } + 998 2 k = getc(dvifile); + 999 2 if (k == post) return(0); + 1000 2 if (k >= undefined_command) { + 1001 3 printf(bad_DVI_message); + 1002 3 return(1); } + 1003 2 + 1004 2 p = first_par(k); + 1005 2 + 1006 2 /* If the opcode is an "implicit parameter" opcode, either set_char_n and + 1007 2 fnt_num_n, we change it to an explicit parameter opcode to make the case + 1008 2 jumps more reasonable. */ + 1009 2 + 1010 2 if (k >= set_char_0 && k < set_char_0+128) k = set1; + 1011 2 if (k >= fnt_num_0 && k < fnt_num_0+64) k = fnt1; + 1012 2 + 1013 2 j = do_command(k,p); + 1014 2 if (j == 2) return(0); /* done with the required number of pages */ + 1015 2 else if (j == 1) return(1); /* error encountered, stop */ + 1016 2 + 1017 2 } + 1018 1 } + 1019 + 1020 /* Read from the DVI file until the starting page condition is met. Return + 1021 1 if something goes wrong, or if the DVI file comes to an end. This + 1022 function is copied quite closely from DVItype. */ + 1023 + 1024 int skip_pages() { + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 20 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + 1025 1 + 1026 1 unsigned int k; + 1027 1 int i; + 1028 1 long p,first_page; + 1029 1 char startp; + 1030 1 + 1031 1 for (;;) { + 1032 2 if (feof(dvifile)) return(1); + 1033 2 k = getc(dvifile); + 1034 2 if (k == post) return(1); + 1035 2 p = first_par(k); + 1036 2 if (k >= set_char_0 && k < set_char_0+128) k = set1; + 1037 2 if (k >= fnt_num_0 && k < fnt_num_0+64) k = fnt1; + 1038 2 + 1039 2 switch (k) { + 1040 3 case bop: + 1041 3 startp = 1; + 1042 3 for (i=0; i<10; i++) { + 1043 4 four_bytes; + 1044 4 if (i == 0) first_page = lcx.l; + 1045 4 if (i < how_many_counts && use_count[i] && + 1046 4 lcx.l != start_page[i]) startp = 0; + 1047 4 } + 1048 3 four_bytes; + 1049 3 if (startp != 0) { + 1050 4 v = 0; vv = 0; h = 0; hh = 0; + 1051 4 printf("\n [%ld]",first_page); + 1052 4 num_pages = 1; return(0); } + 1053 3 break; + 1054 3 case set_rule: + 1055 3 case put_rule: + 1056 3 four_bytes; + 1057 3 break; + 1058 3 four_cases(fnt_def1) + 1059 3 i = define_font(p); + 1060 3 if (i != 0) return(1); + 1061 3 break; + 1062 3 four_cases(xxx1) + 1063 3 for (; p>0; p--) getc(dvifile); + 1064 3 break; + 1065 3 default: + 1066 3 break; + 1067 3 } + 1068 2 } + 1069 1 return(0); + 1070 1 } + 1071 + 1072 /* Do_command performs the DVI command of code k, assuming the "first + 1073 parameter" is p. It is assumed that k is not one of set_char0 through + 1074 set_char127. */ + 1075 + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 21 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + 1076 int do_command(k,p) + 1077 int k; + 1078 long p; + 1079 { + 1080 1 int i,j,l,lnf; + 1081 1 + 1082 1 switch (k) { + 1083 2 four_cases(fnt_def1) + 1084 2 define_font_pass2(); + 1085 2 break; + 1086 2 + 1087 2 /* [[In processing the put and set DVI commands, no check is made that the + 1088 2 character being set actually exists in the font. This can lead to messy + 1089 2 errors, like access violations or garbage values when one tries to find + 1090 2 that character's width. Neither is any check made that the horizontal and + 1091 2 vertical positions fall within the page.]] */ + 1092 2 + 1093 2 four_cases(put1) + 1094 2 four_cases(set1) + 1095 2 if (!vpset) { + 1096 3 fprintf(outfile,"\n\033[%dd\033[%d`",vv+voff,hh+hoff); + 1097 3 ln3p = 16; + 1098 3 vpset = 1; + 1099 3 hh_old = hh; + 1100 3 } + 1101 2 if (hh_old != hh) { + 1102 3 if (hh > hh_old) fprintf(outfile,"\033[%da",hh-hh_old); + 1103 3 else fprintf(outfile,"\033[%d`",hh+hoff); + 1104 3 ln3p += 7; + 1105 3 } + 1106 2 putc(txfa[curf] -> chu[p],outfile); + 1107 2 inc_ln3p(1); + 1108 2 if (k >= put1) { + 1109 3 hh_old = hh; + 1110 3 break; + 1111 3 } + 1112 2 h += font_width[curf][p]; + 1113 2 + 1114 2 /* In rounding h to generate the pixel-position hh, Stanford rules (see + 1115 2 above) come into play. We set the new hh (horizontal position in pixels) to + 1116 2 the value obtained by adding the pixel width of the character being set to + 1117 2 the current position. We then correct this value so that it does not exceed + 1118 2 the rounded version of the true position by more than MAX_DRIFT pixels. + 1119 2 + 1120 2 Note that if we did not apply Stanford rules here, or equivalently if we + 1121 2 set MAX_DRIFT to zero, many more set-X-position commands would appear in + 1122 2 the output. */ + 1123 2 + 1124 2 hh += chw[txf2lnf[curf]][txfa[curf] -> chu[p]]; + 1125 2 hh_old = hh; + 1126 2 l = pixel_round(h); + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 22 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + 1127 2 if (hh-l > MAX_DRIFT) hh = l+MAX_DRIFT; + 1128 2 else if (l-hh > MAX_DRIFT) hh = l-MAX_DRIFT; + 1129 2 break; + 1130 2 + 1131 2 four_cases(fnt1) + 1132 2 set_curf(p); + 1133 2 lnf = txf2lnf[curf]; + 1134 2 if (useno[lnf] == -1) { + 1135 3 useno[whouses[maxfontnos]] = -1; + 1136 3 useno[lnf] = maxfontnos; + 1137 3 whouses[maxfontnos] = lnf; + 1138 3 fprintf(outfile,"\033P1;1%d}%16s\033\\",maxfontnos, + 1139 3 fname[lnf]); + 1140 3 inc_ln3p(26); + 1141 3 } + 1142 2 fprintf(outfile,"\033[1%dm",useno[lnf]); + 1143 2 inc_ln3p(5); + 1144 2 break; + 1145 2 + 1146 2 case set_rule: + 1147 2 case put_rule: + 1148 2 + 1149 2 /* When converting rule dimensions to pixel dimensions, we do not follow + 1150 2 Stanford rules. Rather, we just round the true positions to obtain the + 1151 2 pixel positions. This avoids unsightly gaps between rules. [[It should not + 1152 2 cause much of a problem with typical rule applications (ruled tables, + 1153 2 fraction bars)...but perhaps with large delimiters there might be some + 1154 2 difficulty. This needs more thought...]] */ + 1155 2 + 1156 2 four_bytes; + 1157 2 if (p >= 0 && lcx.l >= 0) + 1158 2 do_rule(pixel_round(h), + 1159 2 pixel_round(v-p),pixel_round(h+lcx.l), + 1160 2 pixel_round(v)); + 1161 2 if (k == set_rule) { + 1162 3 h += lcx.l; + 1163 3 hh = pixel_round(h); + 1164 3 } + 1165 2 break; + 1166 2 + 1167 2 case push: + 1168 2 s++; + 1169 2 if (s == STACKSIZE) { + 1170 3 printf("\n Stack too deep for Dvi2ln3"); + 1171 3 return(1); + 1172 3 } + 1173 2 xstack[s] = x; + 1174 2 ystack[s] = y; + 1175 2 vstack[s] = v; + 1176 2 hstack[s] = h; + 1177 2 vvstack[s] = vv; + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 23 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + 1178 2 hhstack[s] = hh; + 1179 2 wstack[s] = w; + 1180 2 zstack[s] = z; + 1181 2 break; + 1182 2 + 1183 2 case pop: + 1184 2 if (s == 0) { + 1185 3 printf(bad_DVI_message); + 1186 3 return(1); + 1187 3 } + 1188 2 if (vv != vvstack[s]) vpset = 0; + 1189 2 x = xstack[s]; + 1190 2 y = ystack[s]; + 1191 2 v = vstack[s]; + 1192 2 h = hstack[s]; + 1193 2 vv = vvstack[s]; + 1194 2 hh = hhstack[s]; + 1195 2 w = wstack[s]; + 1196 2 z = zstack[s]; + 1197 2 s--; + 1198 2 break; + 1199 2 + 1200 2 /* Right now there are no \special's defined, so when we get a \special, we + 1201 2 just skip over it. */ + 1202 2 + 1203 2 four_cases(xxx1) + 1204 2 for (; p != 0; p--) getc(dvifile); + 1205 2 break; + 1206 2 + 1207 2 case bop: + 1208 2 + 1209 2 /* If we've done the required number of pages, we'll skip the rest of the + 1210 2 DVI file. If not, type the first parameter of bop on the user's terminal + 1211 2 the way TeX does, to give an indication of progress. */ + 1212 2 + 1213 2 if (num_pages == max_pages) return(2); + 1214 2 v = 0; vv = 0; h = 0; hh = 0; + 1215 2 vpset = 0; hh_old = 100000; + 1216 2 four_bytes; + 1217 2 if (num_pages%12 == 0) printf("\n"); + 1218 2 printf(" [%ld]",lcx.ul); + 1219 2 num_pages++; + 1220 2 for (i = 0; i<40; i++) getc(dvifile); + 1221 2 break; + 1222 2 + 1223 2 case eop: + 1224 2 fprintf(outfile,"\n\f"); + 1225 2 ln3p = 0; + 1226 2 break; + 1227 2 + 1228 2 /* Now we have to consider the cases for pure motion. */ + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 24 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + 1229 2 + 1230 2 four_cases(right1) + 1231 2 set_h(h+p); + 1232 2 break; + 1233 2 four_cases(x1) + 1234 2 x = p; + 1235 2 case x0: + 1236 2 set_h(h+x); + 1237 2 break; + 1238 2 four_cases(y1) + 1239 2 y = p; + 1240 2 case y0: + 1241 2 set_v(v+y); + 1242 2 break; + 1243 2 four_cases(w1) + 1244 2 w = p; + 1245 2 case w0: + 1246 2 set_h(h+w); + 1247 2 break; + 1248 2 four_cases(z1) + 1249 2 z = p; + 1250 2 case z0: + 1251 2 set_v(v+z); + 1252 2 break; + 1253 2 four_cases(down1) + 1254 2 set_v(v+p); + 1255 2 break; + 1256 2 + 1257 2 } + 1258 1 return(0); + 1259 1 } + 1260 + 1261 /* Set_curf sets the current font to external number p. Note that the + 1262 current font is maintained as an internal font number. */ + 1263 + 1264 int set_curf(p) + 1265 int p; + 1266 { + 1267 1 to_ext[nf] = p; + 1268 1 curf = 0; + 1269 1 while (to_ext[curf] != p) { curf++; } + 1270 1 } + 1271 + 1272 /* Define_font processes a font definition from the DVI file. The TFM file + 1273 for the font is read at this point from the directory TEX$FONTS. */ + 1274 + 1275 int define_font(e) + 1276 int e; + 1277 { + 1278 1 int i; + 1279 1 unsigned char p,n; + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 25 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + 1280 1 if (e == MAXTEXFONTS) { printf("\n Too many fonts for Dvi2ln3"); + 1281 2 return(1); } + 1282 1 txfa[nf] = malloc(sizeof(struct txf)); + 1283 1 to_ext[nf] = e; + 1284 1 four_bytes; + 1285 1 four_bytes; + 1286 1 txfa[nf] -> scaled_size = lcx.l; + 1287 1 four_bytes; + 1288 1 txfa[nf] -> design_size = lcx.l; + 1289 1 for (i=0; i<256; i++) txfa[nf] -> chu[i] = '\0'; + 1290 1 p = getc(dvifile); n = getc(dvifile); + 1291 1 font_name[nf] = malloc(p+n+1); + 1292 1 for (i=0; i scaled_size <= 0 || txfa[nf] -> scaled_size >= + 1296 1 8*8*8*8*8*8*8*8*8) { + 1297 2 printf("\n Font %s has a bad scaled size",font_name[nf]); + 1298 2 return(1); + 1299 2 } + 1300 1 if (txfa[nf] -> design_size <= 0 || txfa[nf] -> design_size >= + 1301 1 8*8*8*8*8*8*8*8*8) { + 1302 2 printf("\n Font %s has a bad design size",font_name[nf]); + 1303 2 return(1); + 1304 2 } + 1305 1 + 1306 1 /* We follow DVItype and compute for each font a "space" parameter which is + 1307 1 one-sixth of the scaled design size. This parameter is used in rounding the + 1308 1 horizontal position to pixels according to "Stanford rules." See the + 1309 1 function set_h below. */ + 1310 1 + 1311 1 txfa[nf] -> space = txfa[nf] -> scaled_size/6; + 1312 1 + 1313 1 i = read_tfm_file(); + 1314 1 if (i != 0) return(i); + 1315 1 nf++; + 1316 1 return(0); + 1317 1 + 1318 1 } + 1319 + 1320 /* TFM files, like the DVI file, are read with getc, foolish as that may + 1321 seem. We use the same overlays that are used for merging DVI bytes into + 1322 longwords. However, since the TFM file consists of longwords, only + 1323 tfm_longword is need. [[This is also VAX dependent. It would not be + 1324 possible to use stdio's longword reading function getw here, because the + 1325 bytes have to be reversed.]] */ + 1326 + 1327 #define tfm_longword { lcx.uc[3] = getc(tfmfile); \ + 1328 lcx.uc[2] = getc(tfmfile); lcx.uc[1] = getc(tfmfile); \ + 1329 lcx.uc[0] = getc(tfmfile); } + 1330 + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 26 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + 1331 /* Read_tfm_file obtains the character widths from the TFM file + 1332 corresponding to font nf. */ + 1333 + 1334 int read_tfm_file() { + 1335 1 + 1336 1 int i,lh,nw; + 1337 1 int info[256]; + 1338 1 long z,alpha,beta; + 1339 1 long width[256]; + 1340 1 + 1341 1 open_tfm_file(); + 1342 1 if (tfmfile == NULL) { + 1343 2 printf("\n Can't open TFM file for font %s",font_name[nf]); + 1344 2 return(1); } + 1345 1 + 1346 1 /* The TFM format is described in some issue of the TUGBoat (TeX users' + 1347 1 group newsletter), and in the comments to the program TFtoPL. Here we + 1348 1 summarize those aspects of TFM format that are relevant to the task of + 1349 1 extracting the widths of the characters. + 1350 1 + 1351 1 The first 24 bytes of a TFM file contain twelve 16-bit integers that give + 1352 1 the lengths of the various subsequent portions of the file. The ones + 1353 1 relevant to our purposes are LH, length of the header data, BC, the + 1354 1 smallest character code in the font, EC, the largest character code in the + 1355 1 font, and NW, number of words in the width table. So, we read those right + 1356 1 now, and then skip over the remainder, and then over a set of LH longwords + 1357 1 called the "header." */ + 1358 1 + 1359 1 tfm_longword; + 1360 1 lh = 256*lcx.uc[1] + lcx.uc[0]; + 1361 1 tfm_longword; + 1362 1 txfa[nf] -> bc = 256*lcx.uc[3] + lcx.uc[2]; + 1363 1 txfa[nf] -> ec = 256*lcx.uc[1] + lcx.uc[0]; + 1364 1 tfm_longword; + 1365 1 nw = 256*lcx.uc[3] + lcx.uc[2]; + 1366 1 if (txfa[nf] -> bc > 255 || txfa[nf] -> ec > 255 || + 1367 1 txfa[nf] -> bc > txfa[nf] -> ec || nw > 256) { + 1368 2 printf("\n Bad TFM file for font %s",font_name[nf]); + 1369 2 return(1); + 1370 2 } + 1371 1 + 1372 1 for(i=0; i ec-txfa[nf] -> bc+1; i++) { + 1380 2 tfm_longword; + 1381 2 if (lcx.uc[3] >= nw) { + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 27 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + 1382 3 printf("\n Bad TFM file for font %s",font_name[nf]); + 1383 3 return(1); + 1384 3 } + 1385 2 info[i] = lcx.uc[3]; + 1386 2 } + 1387 1 + 1388 1 /* The widths are stored in a rather strange format known as a "fix-word." + 1389 1 A nonnegative width is expressed in "fix-word" format by expressing it in + 1390 1 units of 2^-20 times the design size. A negative width is expressed in + 1391 1 "fix-word" format by expressing its negative in those units, and then + 1392 1 changing the most significant byte to 255. + 1393 1 + 1394 1 One needs to convert these widths into DVI units, multiplying by the scaled + 1395 1 design size according to a certain arcane algorithm. The algorithm is + 1396 1 copied from DVItype, to which we refer the reader for an explanation. */ + 1397 1 + 1398 1 z = txfa[nf] -> scaled_size; + 1399 1 alpha = 16*z; beta = 16; + 1400 1 while (z >= 4*(8*8*8*8*8*8*8)) { z = z/2; beta = beta/2; } + 1401 1 for(i=0; i ec+1)); + 1415 1 + 1416 1 for (i=0; i bc; i++) font_width[nf][i] = 0; + 1417 1 for (i=txfa[nf] -> bc; i <= txfa[nf] -> ec; i++) + 1418 1 font_width[nf][i] = width[info[i-txfa[nf] -> bc]]; + 1419 1 return(0); + 1420 1 } + 1421 + 1422 /* Open_tfm_file finds and opens the tfm file corresponding to a font nf. + 1423 The global file variable tfmfile is used to hold the file pointer. [[This + 1424 function will not work if the TFM file lies over the net on a VMS V3.x + 1425 host, because C file opens do not work in such circumstances. The problem + 1426 can be ignored, because eventually there should be no VMS V3.x hosts + 1427 left.]] */ + 1428 + 1429 int open_tfm_file () { + 1430 1 + 1431 1 int jext,jnam; + 1432 1 char filespec[FILESPECLEN]; + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 28 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + 1433 1 + 1434 1 find_VMS_filename(font_name[nf],&jnam,&jext); + 1435 1 filespec[0] = '\0'; + 1436 1 + 1437 1 /* If there is no directory part, fill in using the logical tex$fonts */ + 1438 1 + 1439 1 if (jnam == 0) strcpy(filespec,"tex$fonts:"); + 1440 1 strcat(filespec,font_name[nf]); + 1441 1 + 1442 1 /* if there is no extension, add the extension ".tfm" */ + 1443 1 + 1444 1 if (font_name[nf][jext] == '\0') strcat(filespec,".tfm"); + 1445 1 tfmfile = fopen(filespec,"r"); + 1446 1 + 1447 1 } + 1448 + 1449 /* Define_font_pass2 skips a font definition from the DVI file. */ + 1450 + 1451 int define_font_pass2() + 1452 { + 1453 1 unsigned char p,n; + 1454 1 int i; + 1455 1 four_bytes; + 1456 1 four_bytes; + 1457 1 four_bytes; + 1458 1 p = getc(dvifile); n = getc(dvifile); + 1459 1 for (i=0; i xx1) { j = xx0; xx0 = xx1; xx1 = j; } + 1479 1 if (yy0 > yy1) { j = yy0; yy0 = yy1; yy1 = j; } + 1480 1 + 1481 1 if ((yy1 != yy0 && xx1 != xx0)) { + 1482 2 fprintf(outfile,"\033[1;%d;%d;%d;%d!|", + 1483 2 xx0,yy0,yy1-yy0,xx1-xx0); + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 29 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + 1484 2 inc_ln3p(25); + 1485 2 } + 1486 1 } + 1487 + 1488 /* Set_v is called to execute vertical-position-altering commands, other + 1489 than pops. It modifies v and vv, and outputs the vertical position to the + 1490 LN3 file. We don't follow Stanford rules here. They sometimes set the + 1491 vertical position in pixels vv to something other than the rounded value of + 1492 v. Not following Stanford rules implies, for example, that the relative + 1493 vertical positions of an accent and its accentee may differ by one pixel + 1494 according to how the baseline of the accentee gets rounded. [[This should + 1495 perhaps be fixed.]] */ + 1496 + 1497 int set_v(v1) + 1498 int v1; + 1499 { + 1500 1 int l; + 1501 1 + 1502 1 l = pixel_round(v1); + 1503 1 v = v1; + 1504 1 vv = l; + 1505 1 vpset = 0; + 1506 1 } + 1507 + 1508 /* Set_h is called whenever a DVI command is encountered that alters the + 1509 horizonal position, other than a set_char, set_rule or pop. It sets h to + 1510 the new value, and alters hh according to Stanford rules, printing the new + 1511 hh in the LN3 file. */ + 1512 + 1513 int set_h(new_h) + 1514 int new_h; + 1515 { + 1516 1 int l,old_hh; + 1517 1 + 1518 1 old_hh = hh; + 1519 1 l = pixel_round(new_h); + 1520 1 if (txfa[curf] == 0 || new_h-h >= txfa[curf] -> space + 1521 1 || new_h-h <= -4*txfa[curf] -> space) hh = l; + 1522 1 else { + 1523 2 hh += pixel_round(new_h-h); + 1524 2 if (hh-l > MAX_DRIFT) hh = l+MAX_DRIFT; + 1525 2 else if (hh-l < -MAX_DRIFT) hh = l-MAX_DRIFT; + 1526 2 } + 1527 1 h = new_h; + 1528 1 return(0); + 1529 1 } + + + +Command Line +------------ + +DVI2LN3 14-OCT-1985 13:19:13 VAX C V2.0-003 Page 30 +V1.0 14-OCT-1985 13:19:01 USER$4:[TEX.LN03.SOURCES]DVI2LN3.C;40 (1) + + +CC/DEB/LIS DVI2LN3 + diff --git a/dviware/ln03/rose/dvi2ln3nft.c b/dviware/ln03/rose/dvi2ln3nft.c new file mode 100644 index 0000000000..dd6e0983b1 --- /dev/null +++ b/dviware/ln03/rose/dvi2ln3nft.c @@ -0,0 +1,1145 @@ +/* This file contains those portions of Dvi2ln3 that create font loads. It +is still being developed... + +Copyright (c) 1983, 1984, 1985, 1986 by Digital Equipment Corporation. +Author: Flavio Rose, ...!decwrl!dec-rhea!dec-dvinci!rose. + +Development chronology: + +11/28/84: Initial version in PL/I. Finished 11/30/84. + 3/4/85: C translation, a prelude to writing DVI2LN3. + 5/7/85: Finally got around to debugging the C translation! + 6/5/85: Convert to work with Dvi2ln3 -- minor changes. + 6/18/85: Try not to use big input array. + 6/22/85: Cleanup, try to identify longs. +11/12/85: Changed to read PXLs rather than LN03 format files. Old file + called dvi2ln3nft, now renamed to dvi2ln3pxl. +11/15/85: More optimized PXL reading -- use lnf instead of the pxlbuf + when reading rasters. Return just status value from add_txf_..., + use ras_len_added to communicate size. Facilitate error + recovery with copy_ersatz_char. LN03 file reading functionality + woven back in. + 1/16/86: Embarrassing bug, forgot to close the nftf after done with it. + 3/28/86: Conditionalization for Ultrix. + 4/7/86: After moving this to 4.3bsd at MIT, a couple more + fixes to the portability. + +*/ + +/* INTRODUCTION: When writing an LN03 driver for TeX, it must be kept in +mind that the LN03 has limited font storage capability. The standard LN03 +has just 27k bytes, and two 128k byte RAM cartridges may be added. + +For this reason, when we convert a DVI file to LN03 form, we build a +special font load that has just the glyphs that the DVI file needs. This +allows very complex files, e.g. the first nine chapters of the +Metafontbook, to be printed on LN03s that have just one extra RAM +cartridge. This approach does, however, consume considerable resources in +the VAX to build those font loads. */ + +/* The following is customary boilerplate. */ + +#ifdef vms +#include stdio +#else +#include +#endif + +/* In VMS we declare external variables to be globalref. +This is not really necessary, just an old habit. */ + +#ifdef vms +#define GLOBAL globaldef +#define EXTERN globalref +#else +#define GLOBAL +#define EXTERN extern +#endif + +/* The following symbols are declared compatibly with those in the file +Dvi2ln3.c. */ + +#define maxnfonts 31 +#define MAXTEXFONTS 100 +#define FILESPECLEN 252 +#define leftfirst 33 +#define leftlast 126 +#define rightfirst 161 +#define rightlast 254 + +EXTERN FILE *outfile; +EXTERN int lastch[maxnfonts]; +EXTERN unsigned char chw[maxnfonts][256]; + +struct txf { unsigned char chu[256]; int bc, ec; long space, design_size, + scaled_size; int nchs; }; +EXTERN struct txf *txfa[MAXTEXFONTS+1]; +EXTERN long int *font_width[MAXTEXFONTS+1]; + +EXTERN char *font_name[MAXTEXFONTS+1]; +EXTERN float conv, unmag_conv; + +#ifndef vms +char *getenv(); +#endif + +/* The LN03 font load we build is buffered in a fixed-size area, slightly +smaller than the maximum amount of font memory available on an LN03. [[The +code should be changed to chain fixed-size buffers, so font loads of +unlimited size can be handled, subject only to memory availability. On +systems with limited memory, it may be desirable to use a disk file instead +of this buffer.]] */ + +#define OBUFLEN 2*256*256 +GLOBAL unsigned char lnf[OBUFLEN]; + +/* While constructing the font load, we keep track of the length of the +"character definitions area" in ras_len. We also have to keep track of the +raster size measured in three different ways, as psize (portrait), lsize +(landscape), and msize (mixed). This is required to fill certain fields in +the font load. */ + +GLOBAL long int ras_len,psize,lsize,msize; + +/* The font load that we construct consists of a number of LN03 fonts. Each +of these contains up to 94 glyphs. They may be "left fonts", so their +glyphs are invoked with codes 33 through 126; or they may be "right fonts" +that respond to codes 161 through 254. + +The font load that we construct is made up of alternating left and right +fonts (sometimes called "font pairs"). A TeX font (represented by a txf +record) is added to a font pair. It may be split between the left and right +halves of the pair. + +The variable using_r keeps track of whether we are using a right font. */ + +GLOBAL char using_r; + +GLOBAL unsigned int nft_first_ch,nft_last_ch,chardir_offset; +GLOBAL int lnf_chardir,ras_beg; +GLOBAL long ras_len_added; + +GLOBAL int pxlf,nftf; + +/* The purpose of add_txf_to_lnf is to read the PXL or LN03 font file +corresponding to TeX font txfno and add its rasters to the font pair +referred to by lnfno. The function returns 0 if all went well, and various +negative numbers to indicate problems. The number of bytes added to the +font load is returned in the global ras_len_added. */ + +int add_txf_to_lnf(lnfno,txfno) +int lnfno,txfno; +{ + int i,j,k,l,width; + int first_txfc,last_txfc; + char first_txf,last_txf; + + ras_len_added = 0; + + if (txfno < 0 || txfno > MAXTEXFONTS || txfa[txfno] == 0 || + lnfno < 0 || lnfno > maxnfonts) { + printf("\nDvi2ln3 internal error, bad txfno or lnfno"); + goto error_return; + } + +/* Now, compute first_txfc and last_txfc, the first and last characters +codes to be copied from the TeX font. */ + + first_txfc = -1; last_txfc = -1; + for (i=0; i<256; i++) { + if (txfa[txfno] -> chu[i] != 0) { + if (first_txfc == -1) first_txfc = i; + last_txfc = i; + } + } + if (first_txfc == -1 || last_txfc == -1) return(0); + +/* Tell user what font is being loaded */ + + printf("\nLoading font %s",font_name[txfno]); + k = (1500.0*conv*txfa[txfno] -> scaled_size)/ + (unmag_conv*txfa[txfno] -> design_size) + 0.5; + l = ((float)k)/15.0 + 0.5; + if (l != 100) printf(" (magnified %d%%)",l); + +/* Now open the file from which we are getting rasters. We look first for a +PXL file, then for an LN03 format font file (NFT file). */ + + pxlf = -1; + nftf = -1; + open_nft_file(txfno); + if (nftf == -1) open_pxl_file(txfno); + +/* If neither a PXL file nor an LN03 format file could be opened, warn the +user. The font load will be filled in with blanks nonetheless. */ + + if (pxlf == -1 && nftf == -1) + printf("\n Couldn't find good font file: using blanks"); + +/* Now replace first_txfc and last_txfc by the character codes into which +they are going to be copied. */ + + first_txfc = txfa[txfno] -> chu[first_txfc]; + last_txfc = txfa[txfno] -> chu[last_txfc]; + +/* Determine if this is the first or last TeX font that is being copied +into the current LN03 font pair. */ + + first_txf = (first_txfc == leftfirst); + last_txf = (last_txfc == lastch[lnfno]); + +/* If this is the first TeX font for the current LN03 font pair, then we +have to initialize the LN03 font load buffer. The initialization routine +computes where the rasters begin in the output buffer, puts in the blanks, +etc. */ + + if (first_txf) { + using_r = 0; + initialize_lnf(lnfno); + } + +/* Now go through all the characters in the TeX font and copy their rasters +into the appropriate positions in the LN03 font pair. When we copy the the +last rasters into the left font, we write the font out and then a comma to +separate it from the next font. [[Fencepost error?]] */ + + for (i=0; i<256; i++) { + if (txfa[txfno] -> chu[i] != 0) { + j = txfa[txfno] -> chu[i]; + if (!using_r && j >= rightfirst) { + write_lnf(); + fprintf(outfile,"\n,"); + using_r = 1; + initialize_lnf(lnfno); + } + if (pxlf != -1) { + k = copy_pxl_char(i,j,lnfno); + if (k != 0) { + close(pxlf); + pxlf = -1; + } + } else if (nftf != -1) { + k = copy_nft_char(i,j,lnfno); + if (k != 0) { + close(nftf); + nftf = -1; + } + } + if (pxlf == -1 && nftf == -1) { + width = font_width[txfno][i]*conv+0.5; + k = copy_ersatz_char(j,lnfno,width); + } + } + } + + if (nftf != -1) close(nftf); + if (pxlf != -1) close(pxlf); + +/* If this is the last TeX font being added to this LN03 font pair, write +out the current font (right or left) from the pair. */ + + if (last_txf) write_lnf(); + +/* Type and return the incremental amount of space that the TeX font being +added takes up in the output font load. */ + + ras_len_added += 4*(txfa[txfno] -> nchs); + printf(", %d bytes",ras_len_added); + + return(0); + +error_return: + return(-1); + +} + +/* A buffer is used to hold the directory part of the PXL file. */ + +#define PXLBUFSIZE 4*517 + +GLOBAL unsigned char pxlbuf[PXLBUFSIZE]; +GLOBAL long pxllen; + +/* The value pxlconv is computed to be the correct conversion factor from the +widths in the PXL file, which are expressed in units of 2^-20 times the +design size, to pixels. */ + +GLOBAL float pxlconv; + +/* As usual when dealing with TeX files, we have to rearrange bytes in +an overlay to combine them into longwords. The reason for this is that +bytes in TeX files are combined into longwords the opposite way from how +the VAX combines them. + +Hence, the following overlay and macro: */ + +GLOBAL union lc { unsigned long int ul; + long int l; + unsigned char c[4]; } lcy; + +#define copy_from_lnf(i) lcy.c[0] = lnf[i]; lcy.c[1] = lnf[i+1]; \ + lcy.c[2] = lnf[i+2]; lcy.c[3] = lnf[i+3] +#define copy_to_lnf(i) lnf[i] = lcy.c[0]; lnf[i+1] = lcy.c[1]; \ + lnf[i+2] = lcy.c[2] ; lnf[i+3] = lcy.c[3] +#define copy_from_pxl(_x) { lcy.c[3] = pxlbuf[_x]; \ + lcy.c[2] = pxlbuf[(_x)+1]; lcy.c[1] = pxlbuf[(_x)+2]; \ + lcy.c[0] = pxlbuf[(_x)+3]; } + +/* open_pxl_file reads the last 517 longwords of the PXL file into the +pxlbuf. */ + +int open_pxl_file(txfno) +int txfno; +{ + + long i,j; + float two_to_the_20th = 0x100000; + int k,l,jnam,jext,target; + char fullspec[FILESPECLEN]; +#ifndef vms + char *pxldir; +#endif + + find_filename(font_name[txfno],&jnam,&jext); + + fullspec[0] = '\0'; +#ifdef vms + if (jnam == 0) strcpy(fullspec,"TEX$PXLDIR:"); +#else + if (jnam == 0) { + pxldir = getenv("TEX_PXLDIR"); + strcpy(fullspec,pxldir); + strcat(fullspec,"/"); + } +#endif + strcat(fullspec,font_name[txfno]); + k = (1500.0*conv*txfa[txfno] -> scaled_size)/ + (unmag_conv*txfa[txfno] -> design_size) + 0.5; + l = strlen(fullspec); + sprintf(&fullspec[l],".%dpxl\0",k); + + pxllen = 0; + pxlf = open(fullspec,0); + if (pxlf == -1) return(1); + + lseek(pxlf,-517*4,2); + i = read(pxlf,pxlbuf,517*4); + if (i != 517*4) { + printf("\n Error while reading PXL file"); + close(pxlf); + pxlf = -1; + return(1); + } + pxllen = 4*517; + +/* Now that we have read the PXL file, check that it is in correct format +by looking for a trailing ID byte of 1001. */ + + copy_from_pxl(pxllen-4); + if (lcy.ul != 1001) { + printf("\n Error while reading PXL file"); + close(pxlf); + pxlf = -1; + return(1); + } + +/* If the format is correct, derive a scale factor for the widths. */ + + copy_from_pxl(pxllen-12); + pxlconv = lcy.ul; + copy_from_pxl(pxllen-16); + pxlconv = (pxlconv/two_to_the_20th)*(lcy.ul/5.0) + *(1.0/(72.27*two_to_the_20th)); + return(0); + +} + +GLOBAL unsigned char rev_byte[256] = { + 0,128,64,192,32,160,96,224, + 16,144,80,208,48,176,112,240, + 8,136,72,200,40,168,104,232, + 24,152,88,216,56,184,120,248, + 4,132,68,196,36,164,100,228, + 20,148,84,212,52,180,116,244, + 12,140,76,204,44,172,108,236, + 28,156,92,220,60,188,124,252, + 2,130,66,194,34,162,98,226, + 18,146,82,210,50,178,114,242, + 10,138,74,202,42,170,106,234, + 26,154,90,218,58,186,122,250, + 6,134,70,198,38,166,102,230, + 22,150,86,214,54,182,118,246, + 14,142,78,206,46,174,110,238, + 30,158,94,222,62,190,126,254, + 1,129,65,193,33,161,97,225, + 17,145,81,209,49,177,113,241, + 9,137,73,201,41,169,105,233, + 25,153,89,217,57,185,121,249, + 5,133,69,197,37,165,101,229, + 21,149,85,213,53,181,117,245, + 13,141,77,205,45,173,109,237, + 29,157,93,221,61,189,125,253, + 3,131,67,195,35,163,99,227, + 19,147,83,211,51,179,115,243, + 11,139,75,203,43,171,107,235, + 27,155,91,219,59,187,123,251, + 7,135,71,199,39,167,103,231, + 23,151,87,215,55,183,119,247, + 15,143,79,207,47,175,111,239, + 31,159,95,223,63,191,127,255 + }; + +#define pxl_word(_x) (pxlbuf[_x]*256+pxlbuf[(_x)+1]) +#define signed_pxl_word(_x) ((pxl_word(_x)>0x8000) ? \ + (pxl_word(_x)-0x10000) : pxl_word(_x)) + +/* Copy_pxl_char copies the rasters and character directory information +corresponding to code from in the PXL file, into the to position of the +LN03 font load buffer. */ + +int copy_pxl_char(from,to,lnfno) +unsigned char from,to; +int lnfno; +{ + + unsigned long ds,rs,i,j,def_start; + unsigned int rows,cols,k,l,m,n; + int xoffset, yoffset; + int width; + char all_blank; + +/* Check if the character code from is in the right range for the PXL file. +*/ + + if (from > 127) return(1); + +/* Locate the definition and the rasters for from in the PXL file. */ + + ds = 16*from; + copy_from_pxl(ds+8); + rs = 4*lcy.ul; + cols = pxl_word(ds); rows = pxl_word(ds+2); + +/* If a glyph has no rasters, an "undocumented feature" of the LN03 seems +to cause the glyph to be printed incorrectly. Because of this, we set the +number of rows and columns to 1, and put in a blank byte (below). */ + + all_blank = ((rows == 0) & (cols == 0)) | rs == 0; + if (all_blank) { + cols = 1; + rows = 1; + } + +/* Compute the width of the glyph in pixels, the xoffset, and the yoffset. +*/ + + copy_from_pxl(ds+12); + width = pxlconv*lcy.ul+0.5; + xoffset = signed_pxl_word(ds+4); + yoffset = signed_pxl_word(ds+6); + chw[lnfno][to] = width; + +/* Check that we have enough room left in the LN03 font load buffer. Fudge +factor of 3 added because the read below may read too much. */ + + def_start = ras_beg+ras_len; + if (def_start+rows*((cols+7)/32)+24+3 > OBUFLEN) { + printf("\nNo more room in LN03 font load buffer (%ld bytes long)", + OBUFLEN); + return(1); + } + +/* Clear the character definition area in the LN03 font load buffer. */ + + for(i=0; i<24+rows*((cols+7)/8); i++) + lnf[def_start+i] = 0; + +/* Set the fields in the first six longwords of the LN03 font load +character definition. The first assignment sets the so-called "flag flag", +which must be always be set according to the Common Font File Format. A +conversion factor of 24 is used in converting pixel values, because the +values are supposed to be in centipoints in the LN03 font load, and if we +assume there are 300 pixels in an inch, then there are 7200 centipoints in +an inch. */ + + lnf[def_start+3] = 0x80; + lcy.ul = 24*width; + copy_to_lnf(def_start+4); + lcy.l = -24*xoffset; + copy_to_lnf(def_start+8); + lcy.l = -24*yoffset; + copy_to_lnf(def_start+12); + +/* The rasters are always placed in portrait into the LN03 font load, with +no use of run-length encoding. Thus, the orient field in the raster format +will be 0, and the Type 1 field is set to 0x81. */ + + lnf[def_start+17] = 0x81; + lnf[def_start+20] = rows%256; + lnf[def_start+21] = rows/256; + lnf[def_start+22] = cols%256; + lnf[def_start+23] = cols/256; + +/* Now we copy the rasters themselves. As we do so, we have to reverse +the bits within each byte. */ + + k = (cols+31)/32; + n = (cols+7)/8; + lseek(pxlf,rs,0); + if (!all_blank) { + for (l=0; l j) ? i : j; + + return(0); +} + +/* Write a blank character of specified width (in pixels) into LN03 font +load buffer. Also, set the chw array. [[This function is a bit excessive. +If we couldn't find a character's rasters, it would suffice just to leave +the character locator blank.]] */ + +int copy_ersatz_char(to,lnfno,width) +unsigned char to; +int lnfno,width; +{ + + unsigned long ds,rs,i,j,def_start; + unsigned int rows,cols,k,l,m,n; + + cols = 1; + rows = 1; + chw[lnfno][to] = width; + +/* Check that we have enough room left in the LN03 font load buffer. Return +silently if not. */ + + def_start = ras_beg+ras_len; + if (def_start+rows*((cols+7)/32)+24 > OBUFLEN) return(1); + +/* Clear the character definition area in the LN03 font load buffer. */ + + for(i=0; i<24+rows*((cols+7)/8); i++) + lnf[def_start+i] = 0; + lnf[def_start+3] = 0x80; + lcy.ul = 24*width; + copy_to_lnf(def_start+4); + +/* The rasters are always placed in portrait into the LN03 font load, with +[no use of run-length encoding. Thus, the orient field in the raster format +will be 0, and the Type 1 field is set to 0x81. */ + + lnf[def_start+17] = 0x81; + lnf[def_start+20] = rows%256; + lnf[def_start+21] = rows/256; + lnf[def_start+22] = cols%256; + lnf[def_start+23] = cols/256; + +/* Set the character locator, increment the LN03 font load buffer length, +and recompute the three sizes. */ + + n = (cols+7)/8; + lcy.l = def_start; + if (to <= leftlast) i = to-leftfirst; else i = to-rightfirst; + copy_to_lnf(lnf_chardir+4*i); + ras_len += 24+rows*n; + ras_len_added += 24+rows*n; + if (ras_len%2 == 1) { + lnf[ras_beg+ras_len] = 0; + ras_len++; + ras_len_added++; + } + + i = rows*((cols+7)/8); + psize += i; + j = ((rows+7)/8)*cols; + lsize += j; + msize += (i > j) ? i : j; + + return(0); +} + +/* The opening part of each NFT file is copied into the array nfta. +Nftlen keeps track of how much of the NFT file we have read. Nftf +is the file descriptor used to do the reading. */ + +GLOBAL unsigned char nfta[480+1024]; +GLOBAL long nftlen; + +#define copy_from_nft(i) lcy.c[0] = nfta[i]; lcy.c[1] = nfta[i+1]; \ + lcy.c[2] = nfta[i+2]; lcy.c[3] = nfta[i+3] + +/* Open_nft_file opens the NFT file and reads the opening part into the NFT +array. */ + +int open_nft_file(txfno) +int txfno; +{ + int k,l,jnam,jext,target; + char fullspec[FILESPECLEN]; +#ifndef vms + char *ln3dir; +#endif + + find_filename(font_name[txfno],&jnam,&jext); + + fullspec[0] = '\0'; +#ifdef vms + if (jnam == 0) strcpy(fullspec,"TEX$LN03DIR:"); +#else + if (jnam == 0) { + ln3dir = getenv("TEX_LN03DIR"); + strcpy(fullspec,ln3dir); + strcat(fullspec,"/"); + } +#endif + strcat(fullspec,font_name[txfno]); + k = (100.0*conv*txfa[txfno] -> scaled_size)/ + (unmag_conv*txfa[txfno] -> design_size) + 0.5; + if (k == 100) strcat(fullspec,".nft"); + else { + l = strlen(fullspec); + if (k < 1000) sprintf(&fullspec[l],".%03d\0",k); + else sprintf(&fullspec[l],".%d\0",k); + } + + nftlen = 0; + nftf = open(fullspec,0); + if (nftf == -1) return(1); + + if (read_nft_with_retry(nfta,480) != 0) { + close(nftf); + nftf = -1; + return(1); + } + +/* The NFT file might be random, or it might be a Common Font File Format +file that isn't loadable into an LN03. So, we make a few checks. + +The second longword must be 'FONT'. */ + + if (nfta[4] != 'F' || nfta[5] != 'O' || nfta[6] != 'N' + || nfta[7] != 'T') { + printf(" -- Bad NFT file, lacks FONT."); + close(nftf); + nftf = -1; + return(1); + } + +/* We also check that there are a full 16 bytes of character parameters. If +there are fewer, we give up: LN03s need all sixteen, and it's too hard to +figure out how to give the missing ones reasonable values. + +Throughout this program, we define some constants beginning with fnt__ +which define byte offsets into the nft file. [[The long prefixes of these +may cause some trouble if one's C compiler does not recognize too many +significant characters in identifiers.]] */ + +#define fnt__l_parameters_size 200 + + copy_from_nft(fnt__l_parameters_size); + if (lcy.l != 16) { + printf(" -- bad NFT file, not enough character parameters"); + close(nftf); + nftf = -1; + return(1); + } + +/* Set the variable that tells us the starting location of the +character directory. */ + + chardir_offset = 480; + +/* Figure out what the first and last character codes in the NFT file are. +*/ + +#define fnt__l_first_character 164 + + copy_from_nft(fnt__l_first_character); + nft_first_ch = lcy.l; + copy_from_nft(fnt__l_first_character+4); + nft_last_ch = lcy.l; + +/* We must have 0 <= nft_first_ch <= nft_last_ch <= 255, otherwise we +give up on the NFT file. */ + + if (!((0 <= nft_first_ch) && (nft_first_ch <= nft_last_ch) && + (nft_last_ch <= 255))) { + printf(" -- bad NFT file, bad character range."); + close(nftf); + nftf = -1; + return(1); + } + +/* Now read the character directory into the nfta. */ + + target = chardir_offset+4*(nft_last_ch+1-nft_first_ch); + if (read_nft_with_retry(&nfta[480],target) != 0) { + close(nftf); + nftf = -1; + return(1); + } + return(0); +} + +/* Copy_nft_char copies the character parameters and rasters corresponding +to the from argument out of the NFT file and into the LN03 font buffer. It +also updates the chw (character width) array. */ + +int copy_nft_char(from,to,lnfno) +unsigned char from,to; +int lnfno; +{ + + int rows,columns,quo; + long i,j,len,def_start,target; + +/* Replace from by the first character code if the NFT file has no rasters +for code from. If this is done, the output will of course be mangled. The +user has already been warned above, so no further message is needed. */ + + if (from < nft_first_ch) from = nft_first_ch; + if (from > nft_last_ch) from = nft_last_ch; + +/* First we need to determine def_start, the byte offset of the character +definition for code from in the NFT file */ + + copy_from_nft(chardir_offset+(from-nft_first_ch)*4); + def_start = lcy.l; + +/* If the locator is earlier in the file, just give up. Otherwise, assume +it's good, continue and give a vague error message is something goes wrong. +*/ + + if (def_start < nftlen || read_nft_until(def_start) != 0) { + printf("\n LN03 font file bad, using blanks"); + return(1); + } + +/* Read the first 24 bytes of character data. */ + + def_start = ras_beg+ras_len; + if (read_nft_with_retry(&lnf[def_start],nftlen+24) != 0) return(1); + +/* Now we need to check that the rasters are uncompressed. LN03s can't +accept compressed rasters, and this program isn't clever enough to +decompress them. */ + + if (lnf[def_start+17] != 129) { + printf("\n LN03 font file bad, using blanks"); + return(1); + } + +/* Fill in the chw array (which holds character widths). Centipoint to +pixel conversion is necessary (there are 24 centipoints in a pixel), with +rounding (hence the 12). */ + + copy_from_lnf(def_start+4); + chw[lnfno][to] = (lcy.l+12)/24; + +/* NFT files may contain character widths which are not integral numbers of +pixels. It is necessary to round such values to pixels when copying into +the final font load -- if sent unrounded to the LN03, the widths will be +truncated and positions will be off in the printed output. */ + + lcy.l = 24*chw[lnfno][to]; + copy_to_lnf(def_start+4); + +/* Now we need to compute the size of the rasters, and copy that number of +bytes into the LN03 font buffer. */ + + rows = lnf[def_start+20]+256*lnf[def_start+21]; + columns = lnf[def_start+22]+256*lnf[def_start+23]; + +/* We have to update psize, lsize and msize to fill slots in the format. */ + + quo = rows/8; + if (rows != quo*8) quo++; + i = quo*columns; + lsize += quo*columns; + quo = columns/8; + if (columns != quo*8) quo++; + psize += quo*rows; + if (i > quo*rows) msize += i; else msize += quo*rows; + +/* Now do the actual copy. We have to ensure that the rasters are +word-aligned in the font load (where one word = 2 bytes, of course). */ + + if (lnf[def_start+16] % 2 == 0) len = quo*rows; else len = i; + if (read_nft_with_retry(&lnf[def_start+24],nftlen+len) != 0) + return(1); + lcy.l = def_start; + if (to <= leftlast) i = to-leftfirst; else i = to-rightfirst; + copy_to_lnf(lnf_chardir+4*i); + ras_len += len+24; + ras_len_added += len+24; + if (ras_len % 2 != 0) { + lnf[ras_beg+ras_len] = 0; + ras_len++; + ras_len_added++; + } + return(0); + +} + +int read_nft_with_retry(where,upto) +long upto; +char *where; +{ + long i,target; + int l; + + i = 0; + while (nftlen < upto) { + target = upto-nftlen; + l = read(nftf,&where[i],target); + if (l <= 0) { + printf("\n LN03 font file bad, using blanks"); + return(1); + } + nftlen += l; + i += l; + } + return(0); +} + +int read_nft_until(pos) +long pos; +{ + char bit_bucket[512]; + int l; + long target; + + while (nftlen < pos) { + target = pos-nftlen; + if (target > 512) target = 512; + l = read(nftf,bit_bucket,target); + if (l <= 0) { + printf("\n LN03 font file bad, using blanks"); + return(1); + } + nftlen += l; + } + return(0); +} + +GLOBAL unsigned char preline[96]; + +/* write_lnf performs the last fixups to the LN03 font buffer and dumps it, +sixelized, into the output file. */ + +int write_lnf (){ + + long i,j,k,rem,quo,ma; + +/* We now have to fix a number of slots: size of file, length of rasters, +final 'FONT', psize, lsize, msize. */ + + lcy.l = ras_beg+ras_len+8; + copy_to_lnf(0); + copy_to_lnf(lcy.l-8); + lnf[lcy.l-4] = 'F'; + lnf[lcy.l-3] = 'O'; + lnf[lcy.l-2] = 'N'; + lnf[lcy.l-1] = 'T'; + +/* Clear out remaining bytes up to 96 more. */ + + j = 96*((lcy.l+95)/96); + for (i=lcy.l; i quo*96) quo++; + + for (i=0; i>2; + sixel_line[ix] = 63+w; + ix++; + w = (v&3)<<4; + v = preline[i+1]; + w |= v>>4; + sixel_line[ix] = 63+w; + ix++; + w = (v&15)<<2; + v = preline[i+2]; + w |= v>>6; + sixel_line[ix] = 63+w; + ix++; + w = v&63; + sixel_line[ix] = 63+w; + ix++; + } + fprintf(outfile,"\n%s",sixel_line); +} + +/* Initializes the LN03 font buffer. */ + +int initialize_lnf(lnfno) +int lnfno; +{ + int i,j; + +/* The following array holds reasonable values for bytes 0-479 of an LN03 +format font. These bytes were copied from a font load which the LN03 was +known to accept. The font loads generated by this program are initialized +using these values. Some of them are overwritten later, however. */ + + static char good_opening[512] = { + 104,38,0,0,70,79,78,84, + 1,0,0,0,31,0,0,0, + 20,0,0,0,85,48,48,48, + 48,48,48,48,48,50,83,75, + 48,48,71,71,48,48,48,49, + 85,90,90,90,90,48,50,70, + 48,48,48,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 181,7,9,0,11,0,14,0, + 0,0,0,0,104,0,0,0, + 252,0,0,0,124,0,0,0, + 100,1,0,0,120,1,0,0, + 224,1,0,0,4,0,0,0, + 88,3,0,0,0,0,0,0, + 92,3,0,0,48,0,0,0, + 92,3,0,0,0,0,0,0, + 140,3,0,0,212,34,0,0, + 140,3,0,0,33,0,0,0, + 126,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 32,0,0,0,168,0,0,0, + 16,0,0,0,94,0,0,0, + 0,0,0,0,94,0,0,0, + 0,0,0,0,94,0,0,0, + 0,0,0,0,236,25,0,0, + 54,25,0,0,14,27,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,2,0,0,0, + 7,0,0,0,92,3,0,0, + 7,0,0,0,99,3,0,0, + 16,0,0,0,106,3,0,0, + 16,0,0,0,122,3,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 10,0,0,0,244,1,0,0, + 0,0,24,0,16,0,0,0, + 16,0,0,0,1,0,1,0, + 1,0,1,0,0,0,1,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 30,0,0,0,20,0,0,0, + 196,255,255,255,20,0,0,0, + 106,255,255,255,20,0,0,0, + 0,0,1,0,0,0,30,0, + 166,255,255,255,0,0,0,0, + 40,0,0,0,0,0,0,0, + 60,0,0,0,240,0,0,0, + 60,0,0,0,100,0,0,0, + 240,0,0,0,120,0,0,0, + 40,0,0,0,120,0,0,0, + 96,255,255,255,136,255,255,255, + 186,255,255,255,240,0,0,0, + 76,255,255,255,60,0,0,0, + 160,0,0,0,120,0,0,0, + 20,0,0,0,20,0,0,0, + 140,3,0,0,194,3,0,0, + 244,3,0,0,160,4,0,0, + 254,4,0,0,162,5,0,0, + 46,6,0,0,84,6,0,0}; + int pool_beg; + +/* The character directory always begins at position 480 in the Common +Font File Format. */ + + lnf_chardir = 480; + ras_len = 0; + psize = 0; + lsize = 0; + msize = 0; + +/* Copy the good values into the lnf array */ + + for (i=0; i<480; i++) + lnf[i] = good_opening[i]; + +/* Set the last character if necessary */ + +#define fnt__l_first_character 164 + + if (lastch[lnfno] < leftlast && !using_r) + lnf[fnt__l_first_character+4] = lastch[lnfno]; + if (using_r) + lnf[fnt__l_first_character+4] = lastch[lnfno]-rightfirst+ + leftfirst; + +/* Set the character counts */ + +#define fnt__l_infile_locators 204 +#define fnt__l_character_definitions 212 +#define fnt__l_raster_count 220 + + i = lnf[fnt__l_first_character+4]- + lnf[fnt__l_first_character]+1; + ras_beg = lnf_chardir + 4*i + 4 + 48; + lnf[fnt__l_infile_locators] = i; + lnf[fnt__l_character_definitions] = i; + lnf[fnt__l_raster_count] = i; + lnf[ras_beg-52] = lnf[ras_beg-51] = lnf[ras_beg-50] = + lnf[ras_beg-49] = 0; + +/* Set the font file id. This id is a 31-byte string. We make it depend on +the lnfno number, and on whether this is a left or right font. +Specifically, the first seven bytes are U0000nn where nn is lnfno possibly +with a leading zero. The character set part of the ID is 1O if using_r, +otherwise the default from good_opening. */ + +#define fnt__t_font_file_id 20 + + lnf[fnt__t_font_file_id+5] = lnfno/10+'0'; + lnf[fnt__t_font_file_id+6] = lnfno % 10 + '0'; + if (using_r) lnf[fnt__t_font_file_id+20] = 'O'; + +/* We now have to set some fields in the font format that are pointers to +where other fields begin. These pointers depend on the number of glyphs we +are placing in the font file. */ + +#define fnt__a_subset_tables 128 + + lcy.l = lnf_chardir+4*i; + copy_to_lnf(fnt__a_subset_tables); + + lcy.l = lcy.l+4; + copy_to_lnf(fnt__a_subset_tables+8); + copy_to_lnf(fnt__a_subset_tables+16); + + lcy.l = lcy.l+48; + copy_to_lnf(fnt__a_subset_tables+24); + +#define fnt__a_char_definitions 160 + + copy_to_lnf(fnt__a_char_definitions); + +/* Set up the string pool region of the font load (48 bytes). The only +tricky part here is the character set designator at the very beginning of +the pool. Left fonts use one designator, right fonts another. [[More +explanation is needed.]] */ + + pool_beg = ras_beg-48; + + lnf[pool_beg] = '0'; + lnf[pool_beg+1] = using_r ? '<':'B'; + lnf[pool_beg+2] = '\011'; /* ascii tab */ + lnf[pool_beg+3] = 'Z'; + lnf[pool_beg+4] = 'Z'; + lnf[pool_beg+5] = 'Z'; + lnf[pool_beg+6] = 'Z'; + +/* For reasons that are beyond my comprehension, the Common Font File +Format requires us to copy the first seven characters of the font file id +into one piece of the string pool, and the first sixteen into another +place. */ + + for (i=1; i<8; i++) + lnf[pool_beg+7+i-1] = lnf[fnt__t_font_file_id+i-1]; + for (i=1; i<17; i++) + lnf[pool_beg+7+7+i-1] = ' '; + for (i=1; i<17; i++) + lnf[pool_beg+7+7+16+i-1] = lnf[fnt__t_font_file_id+i-1]; + lnf[pool_beg+46] = lnf[pool_beg+47] = 0; + +/* Now make string descriptors point into the string pool. */ + +#define fnt__a_char_set 260 +#define fnt__a_family_id 268 +#define fnt__a_family_name 276 +#define fnt__a_font_id 284 + + lcy.l = pool_beg; + copy_to_lnf(fnt__a_char_set); + lcy.l = pool_beg+7; + copy_to_lnf(fnt__a_family_id); + lcy.l = pool_beg+7+7; + copy_to_lnf(fnt__a_family_name); + lcy.l = pool_beg+7+7+16; + copy_to_lnf(fnt__a_font_id); + +/* Mercifully, all remaining font file slots that we can fill now are +already good as received from good_opening. */ + +} diff --git a/dviware/ln03/rose/ffc.pas b/dviware/ln03/rose/ffc.pas new file mode 100644 index 0000000000..e33f4bd03d --- /dev/null +++ b/dviware/ln03/rose/ffc.pas @@ -0,0 +1,277 @@ +{4:}PROGRAM FFC(INPUT,OUTPUT,LN03FILE,PXLFILE,OUTFILE);LABEL{5:} +9998,9999;{:5}TYPE{6:}EIGHTBITS=0..255; +BYTEBLOCK=PACKED ARRAY[0..511]OF EIGHTBITS; +BYTEFILE=PACKED FILE OF BYTEBLOCK;{:6}VAR{7:}INLINE:VARYING[513]OF CHAR; +ILP,ISTART,ILLEN:INTEGER;VERB:INTEGER;{:7}{11:}LN03FILE:BYTEFILE; +LN03COUNT,LN03LEN,I:INTEGER; +LBUF:PACKED RECORD CASE BOOLEAN OF FALSE:(C:PACKED ARRAY[0..((512*512)-1 +)]OF CHAR);TRUE:(B:PACKED ARRAY[0..511]OF BYTEBLOCK);END;{:11}{15:} +PXLFILE:BYTEFILE;PXLCOUNT,PXLLEN:INTEGER; +PBUF:PACKED RECORD CASE BOOLEAN OF FALSE:(C:PACKED ARRAY[0..((512*512)-1 +)]OF CHAR);TRUE:(B:PACKED ARRAY[0..511]OF BYTEBLOCK);END;{:15}{22:} +DEFSTART,RASSTART:INTEGER;J,K,L,M,N:INTEGER; +VISIBLEBYTE:PACKED ARRAY[1..8]OF CHAR;{:22}{31:} +CHARXDEFOFFS,STRINGPOOLSI,STRINGXPOOLO:INTEGER; +PSIZE,LSIZE,MSIZE:INTEGER;FIRSTCHAR,LASTCHAR,NUMCHARS:INTEGER; +ALLBLANK:BOOLEAN;ZCHAR,TFMWIDTH,XOFFSET,YOFFSET:INTEGER;DSIZE,MAG:REAL; +{:31}{39:}FONTIDSTRING:PACKED ARRAY[1..31]OF CHAR;{:39}{44:} +POINTS:INTEGER;{:44}{47:}OUTFILE:BYTEFILE;{:47}{8:} +FUNCTION COMMANDVERB:INTEGER;VAR I:INTEGER;BEGIN{9:} +WHILE(ILP<=ILLEN)AND(INLINE[ILP]=' ')DO ILP:=ILP+1;ISTART:=ILP; +WHILE(ILP<=ILLEN)AND(INLINE[ILP]<>' ')DO ILP:=ILP+1; +FOR I:=ISTART TO ILP-1 DO BEGIN IF(INLINE[I]>='A')AND(INLINE[I]<='Z') +THEN INLINE[I]:=CHR(ORD(INLINE[I])+ORD('a')-ORD('A'))END;{:9} +IF INDEX(SUBSTR(INLINE,ISTART,ILP-ISTART),'rln03')=1 THEN COMMANDVERB:=1 +ELSE IF INDEX(SUBSTR(INLINE,ISTART,ILP-ISTART),'tln03long')=1 THEN +COMMANDVERB:=3 ELSE IF INDEX(SUBSTR(INLINE,ISTART,ILP-ISTART), +'tln03word')=1 THEN COMMANDVERB:=4 ELSE IF INDEX(SUBSTR(INLINE,ISTART, +ILP-ISTART),'tln03')=1 THEN COMMANDVERB:=2 ELSE IF INDEX(SUBSTR(INLINE, +ISTART,ILP-ISTART),'rpxl')=1 THEN COMMANDVERB:=5 ELSE IF INDEX(SUBSTR( +INLINE,ISTART,ILP-ISTART),'tpxllong')=1 THEN COMMANDVERB:=7 ELSE IF +INDEX(SUBSTR(INLINE,ISTART,ILP-ISTART),'tpxlword')=1 THEN COMMANDVERB:=8 +ELSE IF INDEX(SUBSTR(INLINE,ISTART,ILP-ISTART),'tpxl')=1 THEN +COMMANDVERB:=6 ELSE IF INDEX(SUBSTR(INLINE,ISTART,ILP-ISTART),'toln03x') +=1 THEN COMMANDVERB:=11 ELSE IF INDEX(SUBSTR(INLINE,ISTART,ILP-ISTART), +'toln03')=1 THEN COMMANDVERB:=9 ELSE IF INDEX(SUBSTR(INLINE,ISTART,ILP- +ISTART),'wln03')=1 THEN COMMANDVERB:=10 ELSE IF INDEX(SUBSTR(INLINE, +ISTART,ILP-ISTART),'exit')=1 THEN COMMANDVERB:=99 ELSE COMMANDVERB:=0 +END;{:8}{19:}FUNCTION GETFIXNUM:INTEGER;LABEL 1;VAR X,X1:INTEGER; +NEGATIVE:BOOLEAN;BEGIN X1:=0;NEGATIVE:=FALSE; +WHILE(ILP<=ILLEN)AND(INLINE[ILP]=' ')DO ILP:=ILP+1; +IF ILP>ILLEN THEN GOTO 1;IF INLINE[ILP]='-'THEN BEGIN NEGATIVE:=TRUE; +ILP:=ILP+1 END; +IF(ILP>ILLEN)OR(INLINE[ILP]<'0')OR(INLINE[ILP]>'9')THEN GOTO 1;X1:=0; +WHILE(INLINE[ILP]>='0')AND(INLINE[ILP]<='9')DO BEGIN X1:=10*X1+ORD( +INLINE[ILP])-ORD('0');ILP:=ILP+1;IF ILP>ILLEN THEN GOTO 1;END;1:X:=X1; +IF NEGATIVE THEN X:=-X;GETFIXNUM:=X END;{:19}{25:} +PROCEDURE BINREP(V:INTEGER);VAR CNT,REM,QUO:INTEGER; +BEGIN VISIBLEBYTE:='........';QUO:=V; +FOR CNT:=1 TO 8 DO BEGIN REM:=QUO MOD 2;QUO:=QUO DIV 2; +IF REM<>0 THEN VISIBLEBYTE[CNT]:='B'END;END;{:25}{27:} +PROCEDURE REVBINREP(V:INTEGER);VAR CNT,REM,QUO:INTEGER; +BEGIN VISIBLEBYTE:='........';QUO:=V; +FOR CNT:=1 TO 8 DO BEGIN REM:=QUO MOD 2;QUO:=QUO DIV 2; +IF REM<>0 THEN VISIBLEBYTE[9-CNT]:='B'END;END;{:27}{34:} +FUNCTION SIGNEDPXLWOR(INDEX:INTEGER):INTEGER; +BEGIN IF ORD(PBUF.C[INDEX])>=128 THEN SIGNEDPXLWOR:=(ORD(PBUF.C[(INDEX) ++1])+256*ORD(PBUF.C[INDEX]))-65536 ELSE SIGNEDPXLWOR:=(ORD(PBUF.C[(INDEX +)+1])+256*ORD(PBUF.C[INDEX]))END; +PROCEDURE SETLN03LONG(INDEX,VALUE:INTEGER);VAR NEGATIVE:BOOLEAN; +A,B,C,D,CARRY:INTEGER; +BEGIN IF VALUE<0 THEN NEGATIVE:=TRUE ELSE NEGATIVE:=FALSE; +IF NEGATIVE THEN VALUE:=-VALUE;A:=VALUE MOD 256; +B:=(VALUE DIV 256)MOD 256;C:=(VALUE DIV(256*256))MOD 256; +D:=VALUE DIV(256*256*256);IF NEGATIVE THEN BEGIN CARRY:=0;A:=256-A; +IF A=256 THEN BEGIN A:=0;CARRY:=1 END;B:=255+CARRY-B; +IF B=256 THEN B:=0 ELSE CARRY:=0;C:=255+CARRY-C; +IF C=256 THEN C:=0 ELSE CARRY:=0;D:=255+CARRY-D;IF D=256 THEN D:=0 END; +LBUF.C[INDEX]:=CHR(A);LBUF.C[INDEX+1]:=CHR(B);LBUF.C[INDEX+2]:=CHR(C); +LBUF.C[INDEX+3]:=CHR(D)END;{:34}{36:}FUNCTION REVERSEBYTE(U:CHAR):CHAR; +VAR CNT,RV:INTEGER;BEGIN BINREP(ORD(U));RV:=0; +FOR CNT:=1 TO 8 DO IF VISIBLEBYTE[CNT]='B'THEN RV:=1+2*RV ELSE RV:=2*RV; +REVERSEBYTE:=CHR(RV)END;{:36} +BEGIN WRITELN('Font File Converter, Version 3');WRITELN;{10:} +9998:WRITELN;WRITE('FFC>');READLN(INLINE); +IF LENGTH(INLINE)=513 THEN BEGIN WRITELN('Command line too long'); +GOTO 9998 END;INLINE:=INLINE+' ';ILP:=1;ILLEN:=LENGTH(INLINE); +VERB:=COMMANDVERB;IF VERB=0 THEN BEGIN WRITELN('No such command'); +GOTO 9998 END ELSE{12:} +IF VERB=1 THEN BEGIN WHILE(ILP<=ILLEN)AND(INLINE[ILP]=' ')DO ILP:=ILP+1; +ISTART:=ILP;WHILE(ILP<=ILLEN)AND(INLINE[ILP]<>' ')DO ILP:=ILP+1; +OPEN(LN03FILE,SUBSTR(INLINE,ISTART,ILP-ISTART),readonly,error:=continue) +;IF STATUS(LN03FILE)>0 THEN BEGIN WRITELN('Couldn''t open file'); +GOTO 9998 END;RESET(LN03FILE);{13:}LN03COUNT:=0; +WHILE(NOT EOF(LN03FILE))AND(LN03COUNT<512)DO BEGIN READ(LN03FILE,LBUF.B[ +LN03COUNT]);LN03COUNT:=LN03COUNT+1;END;LN03LEN:=LN03COUNT*512; +CLOSE(LN03FILE);{14:}IF LN03LEN<16 THEN WRITELN('LN03 file too short'); +IF(LBUF.C[4]<>'F')OR(LBUF.C[5]<>'O')OR(LBUF.C[6]<>'N')OR(LBUF.C[7]<>'T') +THEN WRITELN('Second longword not FONT'){:14}{:13}END{:12}{16:} +ELSE IF VERB=5 THEN BEGIN WHILE(ILP<=ILLEN)AND(INLINE[ILP]=' ')DO ILP:= +ILP+1;ISTART:=ILP;WHILE(ILP<=ILLEN)AND(INLINE[ILP]<>' ')DO ILP:=ILP+1; +OPEN(PXLFILE,SUBSTR(INLINE,ISTART,ILP-ISTART),readonly,error:=continue); +IF STATUS(PXLFILE)>0 THEN BEGIN WRITELN('Couldn''t open file'); +GOTO 9998 END;RESET(PXLFILE);{17:}PXLCOUNT:=0; +WHILE(NOT EOF(PXLFILE))AND(PXLCOUNT<512)DO BEGIN READ(PXLFILE,PBUF.B[ +PXLCOUNT]);PXLCOUNT:=PXLCOUNT+1;END;PXLLEN:=PXLCOUNT*512;CLOSE(PXLFILE); +{18:} +IF NOT(PXLLEN MOD 4=0)THEN WRITELN('PXL file length not multiple of 4'); +IF(ORD(PBUF.C[(0)+3])+(256*(ORD(PBUF.C[(0)+2])+256*(ORD(PBUF.C[(0)+1]) ++256*ORD(PBUF.C[0])))))<>1001 THEN WRITELN('Initial PXL format id wrong' +);I:=PXLLEN-4; +WHILE(I>=PXLLEN-512)DO BEGIN IF(ORD(PBUF.C[(I)+3])+(256*(ORD(PBUF.C[(I) ++2])+256*(ORD(PBUF.C[(I)+1])+256*ORD(PBUF.C[I])))))=1001 THEN BEGIN +PXLLEN:=I+4;I:=-1 END ELSE I:=I-4 END; +IF PXLLEN<16 THEN WRITELN('PXL file too short'); +IF(ORD(PBUF.C[(PXLLEN-4)+3])+(256*(ORD(PBUF.C[(PXLLEN-4)+2])+256*(ORD( +PBUF.C[(PXLLEN-4)+1])+256*ORD(PBUF.C[PXLLEN-4])))))<>1001 THEN WRITELN( +'Final PXL format id wrong');{:18}{:17}END{:16}{21:} +ELSE IF VERB=2 THEN BEGIN WHILE(ILP<=ILLEN)AND(INLINE[ILP]=' ')DO ILP:= +ILP+1; +IF ILP>ILLEN THEN BEGIN WRITELN('You have to say what character to type' +);GOTO 9998 END; +IF(INLINE[ILP]='''')AND(ILP(ORD(LBUF.C[168])+(256*(ORD(LBUF. +C[(168)+1])+256*(ORD(LBUF.C[(168)+2])+256*ORD(LBUF.C[(168)+3]))))))THEN +BEGIN WRITELN('No such character');GOTO 9998 END; +I:=4*(I-(ORD(LBUF.C[164])+(256*(ORD(LBUF.C[(164)+1])+256*(ORD(LBUF.C[( +164)+2])+256*ORD(LBUF.C[(164)+3]))))))+(ORD(LBUF.C[120])+(256*(ORD(LBUF. +C[(120)+1])+256*(ORD(LBUF.C[(120)+2])+256*ORD(LBUF.C[(120)+3])))));{23:} +IF LBUF.C[I+3]>=CHR(128)THEN BEGIN WRITELN( +'Indirect locators not supported');GOTO 9998 END; +DEFSTART:=ORD(LBUF.C[I])+256*(ORD(LBUF.C[I+1])+256*ORD(LBUF.C[(I+1)+1])) +;IF DEFSTART=0 THEN BEGIN WRITELN('Locator is zero');GOTO 9998 END; +RASSTART:=DEFSTART+(ORD(LBUF.C[200])+(256*(ORD(LBUF.C[(200)+1])+256*(ORD +(LBUF.C[(200)+2])+256*ORD(LBUF.C[(200)+3]))))); +WRITELN(' ma = ',RASSTART:1); +IF RASSTART>((512*512)-1)THEN BEGIN WRITELN( +'Character outside piece of file read');GOTO 9998 END{:23};{24:} +WRITELN('width ',(((ORD(LBUF.C[DEFSTART+4])+(256*(ORD(LBUF.C[(DEFSTART+4 +)+1])+256*(ORD(LBUF.C[(DEFSTART+4)+2])+256*ORD(LBUF.C[(DEFSTART+4)+3]))) +)))/24.0):5:1,' pixels'); +IF ORD(LBUF.C[RASSTART+1])<>129 THEN BEGIN WRITELN( +'Run length encoding not supported');GOTO 9998 END; +IF ODD(ORD(LBUF.C[RASSTART]))THEN BEGIN WRITELN('landscape'); +I:=(ORD(LBUF.C[RASSTART+4])+256*ORD(LBUF.C[(RASSTART+4)+1])); +J:=(ORD(LBUF.C[RASSTART+6])+256*ORD(LBUF.C[(RASSTART+6)+1]))END ELSE +BEGIN WRITELN('portrait'); +I:=(ORD(LBUF.C[RASSTART+6])+256*ORD(LBUF.C[(RASSTART+6)+1])); +J:=(ORD(LBUF.C[RASSTART+4])+256*ORD(LBUF.C[(RASSTART+4)+1]))END; +WRITELN(I:1,' rows ',J:1,' columns');K:=I DIV 8;IF I<>8*K THEN K:=K+1; +FOR L:=0 TO J-1 DO BEGIN FOR M:=0 TO K-1 DO BEGIN BINREP(ORD(LBUF.C[ +RASSTART+8+K*L+M]));WRITE(VISIBLEBYTE)END;WRITELN END{:24}END{:21}{26:} +ELSE IF VERB=6 THEN BEGIN WHILE(ILP<=ILLEN)AND(INLINE[ILP]=' ')DO ILP:= +ILP+1; +IF ILP>ILLEN THEN BEGIN WRITELN('You have to say what character to type' +);GOTO 9998 END; +IF(INLINE[ILP]='''')AND(ILP127)THEN BEGIN WRITELN('No such character'); +GOTO 9998 END;DEFSTART:=PXLLEN-4*517+16*I; +RASSTART:=4*(ORD(PBUF.C[(DEFSTART+8)+3])+(256*(ORD(PBUF.C[(DEFSTART+8)+2 +])+256*(ORD(PBUF.C[(DEFSTART+8)+1])+256*ORD(PBUF.C[DEFSTART+8]))))); +WRITELN(' rasters at ',RASSTART:1); +IF RASSTART>PXLLEN THEN BEGIN WRITELN('Rasters outside file'); +GOTO 9998 END;I:=(ORD(PBUF.C[(DEFSTART)+1])+256*ORD(PBUF.C[DEFSTART])); +J:=(ORD(PBUF.C[(DEFSTART+2)+1])+256*ORD(PBUF.C[DEFSTART+2])); +WRITELN(I:1,' columns ',J:1,' rows');K:=I DIV 32;IF I<>32*K THEN K:=K+1; +FOR L:=0 TO J-1 DO BEGIN FOR M:=0 TO K-1 DO BEGIN REVBINREP(ORD(PBUF.C[ +RASSTART+4*K*L+4*M]));WRITE(VISIBLEBYTE); +REVBINREP(ORD(PBUF.C[RASSTART+4*K*L+4*M+1]));WRITE(VISIBLEBYTE); +REVBINREP(ORD(PBUF.C[RASSTART+4*K*L+4*M+2]));WRITE(VISIBLEBYTE); +REVBINREP(ORD(PBUF.C[RASSTART+4*K*L+4*M+3]));WRITE(VISIBLEBYTE)END; +WRITELN END END{:26}{28:}ELSE IF VERB=3 THEN BEGIN I:=GETFIXNUM; +IF(I>=0)AND(I=0)AND(I=0)AND(I=0)AND(IPXLLEN THEN BEGIN WRITELN('Rasters outside file for ',ZCHAR: +1);GOTO 9998 END; +TFMWIDTH:=(ORD(PBUF.C[(DEFSTART+12)+3])+(256*(ORD(PBUF.C[(DEFSTART+12)+2 +])+256*(ORD(PBUF.C[(DEFSTART+12)+1])+256*ORD(PBUF.C[DEFSTART+12]))))); +DSIZE:=(ORD(PBUF.C[(PXLLEN-12)+3])+(256*(ORD(PBUF.C[(PXLLEN-12)+2])+256* +(ORD(PBUF.C[(PXLLEN-12)+1])+256*ORD(PBUF.C[PXLLEN-12]))))); +MAG:=(ORD(PBUF.C[(PXLLEN-16)+3])+(256*(ORD(PBUF.C[(PXLLEN-16)+2])+256*( +ORD(PBUF.C[(PXLLEN-16)+1])+256*ORD(PBUF.C[PXLLEN-16]))))); +DSIZE:=(DSIZE/(1048576))*(MAG/1500.0);XOFFSET:=SIGNEDPXLWOR(DEFSTART+4); +YOFFSET:=SIGNEDPXLWOR(DEFSTART+6); +SETLN03LONG(LN03LEN+4,ROUND((DSIZE*7200.0*TFMWIDTH)/((1048576)*72.27))); +SETLN03LONG(LN03LEN+8,-24*XOFFSET);SETLN03LONG(LN03LEN+12,-24*YOFFSET); +{:33}{35:}LBUF.C[LN03LEN+17]:=CHR(129); +I:=(ORD(PBUF.C[(DEFSTART)+1])+256*ORD(PBUF.C[DEFSTART])); +J:=(ORD(PBUF.C[(DEFSTART+2)+1])+256*ORD(PBUF.C[DEFSTART+2])); +ALLBLANK:=(I=0)AND(J=0);IF ALLBLANK THEN BEGIN I:=1;J:=1 END; +LBUF.C[LN03LEN+20]:=CHR(J MOD 256);LBUF.C[LN03LEN+21]:=CHR(J DIV 256); +LBUF.C[LN03LEN+22]:=CHR(I MOD 256);LBUF.C[LN03LEN+23]:=CHR(I DIV 256); +K:=I DIV 32;IF I<>32*K THEN K:=K+1;N:=I DIV 8;IF I<>8*N THEN N:=N+1; +IF NOT ALLBLANK THEN FOR L:=0 TO J-1 DO FOR M:=0 TO N-1 DO LBUF.C[ +LN03LEN+24+N*L+M]:=REVERSEBYTE(PBUF.C[RASSTART+4*K*L+M]); +SETLN03LONG(480+4*(ZCHAR-FIRSTCHAR),LN03LEN);LN03LEN:=LN03LEN+24+J*N; +IF ODD(LN03LEN)THEN LN03LEN:=LN03LEN+1;PSIZE:=PSIZE+J*N;K:=J DIV 8; +IF J<>8*K THEN K:=K+1;LSIZE:=LSIZE+I*K; +IF I*K>J*N THEN MSIZE:=MSIZE+I*K ELSE MSIZE:=MSIZE+J*N;{:35}END;{:32}; +{37:}IF LN03LEN MOD 4<>0 THEN LN03LEN:=LN03LEN+(4-(LN03LEN MOD 4)); +LN03LEN:=LN03LEN+8;SETLN03LONG(0,LN03LEN); +SETLN03LONG(LN03LEN-8,LN03LEN);LBUF.C[4]:='F';LBUF.C[LN03LEN-4]:='F'; +LBUF.C[5]:='O';LBUF.C[LN03LEN-3]:='O';LBUF.C[6]:='N'; +LBUF.C[LN03LEN-2]:='N';LBUF.C[7]:='T';LBUF.C[LN03LEN-1]:='T';{:37}{38:} +LBUF.C[8]:=CHR(1);LBUF.C[12]:=CHR(31);LBUF.C[16]:=CHR(20); +FONTIDSTRING:='U000000002SK00GG0001UZZZZ02F000'; +FOR I:=1 TO 31 DO LBUF.C[20+I-1]:=FONTIDSTRING[I]; +LBUF.C[88]:=CHR(1973 MOD 256);LBUF.C[89]:=CHR(1973 DIV 256); +LBUF.C[90]:=CHR(9);LBUF.C[92]:=CHR(11);LBUF.C[94]:=CHR(14);{:38}{40:} +SETLN03LONG(100,104);SETLN03LONG(104,252);SETLN03LONG(108,124); +SETLN03LONG(112,356);SETLN03LONG(116,4*NUMCHARS);SETLN03LONG(120,480); +SETLN03LONG(124,4);SETLN03LONG(128,480+4*NUMCHARS); +SETLN03LONG(136,480+4*NUMCHARS+4);SETLN03LONG(140,STRINGPOOLSI); +SETLN03LONG(144,480+4*NUMCHARS+4); +SETLN03LONG(152,480+4*NUMCHARS+4+STRINGPOOLSI); +SETLN03LONG(156,LN03LEN-8-CHARXDEFOFFS);SETLN03LONG(160,CHARXDEFOFFS); +{:40}{41:}SETLN03LONG(164,FIRSTCHAR);SETLN03LONG(168,LASTCHAR); +SETLN03LONG(192,32);SETLN03LONG(196,168);SETLN03LONG(200,16); +SETLN03LONG(204,NUMCHARS);SETLN03LONG(212,NUMCHARS); +SETLN03LONG(220,NUMCHARS);SETLN03LONG(228,PSIZE);SETLN03LONG(232,LSIZE); +SETLN03LONG(236,MSIZE);{:41}{42:}SETLN03LONG(252,2);SETLN03LONG(256,7); +SETLN03LONG(260,STRINGXPOOLO);LBUF.C[STRINGXPOOLO]:='0'; +LBUF.C[STRINGXPOOLO+1]:='B';LBUF.C[STRINGXPOOLO+2]:=CHR(9); +LBUF.C[STRINGXPOOLO+3]:='Z';LBUF.C[STRINGXPOOLO+4]:='Z'; +LBUF.C[STRINGXPOOLO+5]:='Z';LBUF.C[STRINGXPOOLO+6]:='Z'; +SETLN03LONG(264,7);SETLN03LONG(268,STRINGXPOOLO+7); +FOR I:=1 TO 7 DO LBUF.C[STRINGXPOOLO+7+I-1]:=FONTIDSTRING[I]; +SETLN03LONG(272,16);SETLN03LONG(276,STRINGXPOOLO+14); +FOR I:=1 TO 16 DO LBUF.C[STRINGXPOOLO+14+I-1]:=' ';SETLN03LONG(280,16); +SETLN03LONG(284,STRINGXPOOLO+30); +FOR I:=1 TO 16 DO LBUF.C[STRINGXPOOLO+30+I-1]:=FONTIDSTRING[I];{:42} +{43:} +I:=(ORD(PBUF.C[(PXLLEN-12)+3])+(256*(ORD(PBUF.C[(PXLLEN-12)+2])+256*(ORD +(PBUF.C[(PXLLEN-12)+1])+256*ORD(PBUF.C[PXLLEN-12]))))); +POINTS:=I DIV(1048576);K:=(10000*I MOD(1048576))DIV(1048576); +LBUF.C[304]:=CHR(POINTS MOD 256);LBUF.C[305]:=CHR(POINTS DIV 256); +LBUF.C[306]:=CHR(K MOD 256);LBUF.C[307]:=CHR(K DIV 256); +IF K>4999 THEN POINTS:=POINTS+1;SETLN03LONG(308,50*POINTS);{:43}{45:} +LBUF.C[314]:=CHR(24);LBUF.C[316]:=CHR(16);LBUF.C[320]:=CHR(16); +LBUF.C[324]:=CHR(1);LBUF.C[326]:=CHR(1);LBUF.C[328]:=CHR(1); +LBUF.C[330]:=CHR(1);LBUF.C[334]:=CHR(1);{:45}{46:} +SETLN03LONG(360,12*POINTS);SETLN03LONG(364,8*POINTS); +SETLN03LONG(368,-25*POINTS);SETLN03LONG(372,8*POINTS); +SETLN03LONG(376,-60*POINTS);SETLN03LONG(380,8*POINTS); +LBUF.C[386]:=CHR(1);LBUF.C[390]:=CHR(POINTS*12 MOD 256); +LBUF.C[391]:=CHR(POINTS*12 DIV 256);SETLN03LONG(392,-36*POINTS); +SETLN03LONG(400,16*POINTS);SETLN03LONG(408,24*POINTS); +SETLN03LONG(412,20*POINTS);SETLN03LONG(416,80*POINTS); +SETLN03LONG(420,25*POINTS);SETLN03LONG(424,100*POINTS); +SETLN03LONG(428,50*POINTS);SETLN03LONG(432,10*POINTS); +SETLN03LONG(436,35*POINTS);SETLN03LONG(440,-64*POINTS); +SETLN03LONG(444,-50*POINTS);SETLN03LONG(448,-35*POINTS); +SETLN03LONG(452,100*POINTS);SETLN03LONG(456,-65*POINTS); +SETLN03LONG(460,35*POINTS);SETLN03LONG(464,65*POINTS); +SETLN03LONG(468,35*POINTS);SETLN03LONG(472,10*POINTS); +SETLN03LONG(476,10*POINTS);{:46}END{:30}{48:} +ELSE IF VERB=10 THEN BEGIN WHILE(ILP<=ILLEN)AND(INLINE[ILP]=' ')DO ILP:= +ILP+1; +IF ILP>ILLEN THEN BEGIN WRITELN('You must specify a file to write into') +;GOTO 9998 END;ISTART:=ILP; +WHILE(ILP<=ILLEN)AND(INLINE[ILP]<>' ')DO ILP:=ILP+1; +OPEN(OUTFILE,SUBSTR(INLINE,ISTART,ILP-ISTART),error:=continue); +IF STATUS(OUTFILE)<>0 THEN BEGIN WRITELN('couldn''t open',SUBSTR(INLINE, +ISTART,ILP-ISTART));GOTO 9998 END;REWRITE(OUTFILE);I:=LN03LEN DIV 512; +IF LN03LEN<>I*512 THEN I:=I+1; +FOR J:=0 TO I-1 DO WRITE(OUTFILE,LBUF.B[J]);CLOSE(OUTFILE)END{:48}{49:} +ELSE IF VERB=99 THEN GOTO 9999{:49};GOTO 9998;9999:{:10}END.{:4} diff --git a/dviware/ln03/rose/ffc.web b/dviware/ln03/rose/ffc.web new file mode 100644 index 0000000000..eaa79d69a9 --- /dev/null +++ b/dviware/ln03/rose/ffc.web @@ -0,0 +1,991 @@ +% This program interconverts files between TeX and LN03 font file formats. + +% Copyright (c) 1984, 1985 by Digital Equipment Corporation. +% UNDER DEVELOPMENT +% Version 0.0, early December 1984, initial functionality +% Version 0.0a, fixes by Scott Robinson to make input more efficient +% Version 0.1, late December, fixed bug: magnification field is no +% longer ignored in PXL to LN03 conversion. +% Version 2, April-June 1985, a lot of random fixes. +% Version 3, January 1986, tln03 prints width. + +% Here is TeX material that gets inserted after \input webmac +\def\hang{\hangindent 3em\indent\ignorespaces} +\font\ninerm=amr9 + +\def\title{Font File Converter} +\def\contentspagenumber{1} +\def\topofcontents{\null + \def\titlepage{F} % include headline on the contents page + \def\rheader{\mainfont\hfil \contentspagenumber} + \vfill + \centerline{\titlefont The Font File Converter} + \vskip 15pt + \centerline{(Version 3, January 1986)} + \vfill} +\def\botofcontents{\vfill + \centerline{\hsize 5in\baselineskip9pt + \vbox{\ninerm\noindent + Copyright 1984, 1985, 1986 by Digital Equipment Corporation.}}} +\pageno=\contentspagenumber \advance\pageno by 1 + +@* Introduction. The purpose of the Font File Converter (FFC) program is to +convert font files from the \TeX\ \.{PXL} format to the DEC Common Font +File Format. The program takes interactive commands from the terminal. +Right now, its conversion capability is quite limited, and the files FFC +produces are essentially usable only with the accompanying LN03 driver for +\TeX. + +A |banner| string is defined to identify the version: + +@d banner=='Font File Converter, Version 3' + +@ FFC is written in the Web language, but the underlying Pascal is +\hbox{VAX--11} Pascal, and no effort has been made to make anything +portable@^portability@>. In particular, it is assumed that Pascal strings +are ASCII strings. + +We do, however, use the ``standard'' Web name for the default in a +|case| statement: + +@f othercases == else +@d othercases == otherwise + +@ Detailed instructions for using FFC are given in a separate document. The +LN03 and \.{PXL} file formats are also described separately. + +The LN03 accepts font files in the DEC Common Font File Format. However, it +only reads certain fields of that format. FFC fills enough of these fields +to make the font files it generates acceptable to the LN03, when these +files are first massaged by the accompanying \TeX\ driver software. It +cannot be assumed that FFC fills all fields in the Common Font File Format +correctly. Neither can it be assumed that the files it generates are +acceptable to other software or devices that use the DEC Common Font File +Format. + +@ The overall structure of FFC is given below. + +@p +program FFC (input, output, ln03_file, pxl_file, outfile); + label @@/ + type @@/ + var @@/ + @@/ +begin + writeln(banner); writeln;@/ + @@/ +end. + +@ There are two global labels, |final_end| for use when the program finishes, +and |cmd_prompt| for use when a command comes to an end: + +@d final_end = 9999 +@d cmd_prompt = 9998 + +@= + cmd_prompt, final_end; + +@ We define a file type |byte_file| for files consisting of 512-byte +blocks. This definition was introduced by Scott Robinson for efficiency +reasons. It is unclear at this point how this Pascal definition restricts +our ability to work with font files of the various types that can exist +in a Vax/VMS file system. + +@= +@!eight_bits=0..255; +@!byte_block=packed array [0..511] of eight_bits; +@!byte_file=packed file of byte_block; {files that contain binary data} + +@* Command input. The user's command lines are read into a buffer called +|inline|. The variables |ilp| and |istart| are used to point into it, +while |illen| keeps track of its length. The variable |verb| holds an +integer code representing the command verb. + +@d the_char == inline[ilp] +@d the_substr == substr(inline,istart,ilp-istart) + +@= +@!inline: varying[513] of char; +@!ilp,istart,illen :integer; +@!verb :integer; + +@ Each command consists of a verb, a space, and arguments. The command +handling procedure itself parses the arguments from |inline|. The verbs are +converted into integer values by the function |command_verb|. That +function is now coded inefficiently; it should eventually be implemented +using a hash table. + +@d nonesuch = 0 { there is no such command } +@d rln03 = 1 { read LN03 format file } +@d tln03 = 2 { type LN03 character rasters } +@d tln03long = 3 { type a longword from the LN03 file } +@d tln03word = 4 { type a word from the LN03 file } +@d rpxl = 5 { read \.{PXL} format file } +@d tpxl = 6 { type \.{PXL} character rasters } +@d tpxllong = 7 { type a longword from the \.{PXL} file } +@d tpxlword = 8 { type a word from the \.{PXL} file } +@d toln03 = 9 { convert the \.{PXL} file to an LN03 file } +@d wln03 = 10 { write the LN03 buffer out onto a file } +@d toln03x = 11 { convert the \.{PXL} file to an ``extended'' LN03 file } +@d exit = 99 { leave FFC } + +@= +function command_verb :integer; + var i :integer; + begin + + @@/ + if index(the_substr,'rln03') = 1 then command_verb := rln03 + else if index(the_substr,'tln03long') = 1 then command_verb := tln03long + else if index(the_substr,'tln03word') = 1 then command_verb := tln03word + else if index(the_substr,'tln03') = 1 then command_verb := tln03 + else if index(the_substr,'rpxl') = 1 then command_verb := rpxl + else if index(the_substr,'tpxllong') = 1 then command_verb := tpxllong + else if index(the_substr,'tpxlword') = 1 then command_verb := tpxlword + else if index(the_substr,'tpxl') = 1 then command_verb := tpxl + else if index(the_substr,'toln03x') = 1 then command_verb := toln03x + else if index(the_substr,'toln03') = 1 then command_verb := toln03 + else if index(the_substr,'wln03') = 1 then command_verb := wln03 + else if index(the_substr,'exit') = 1 then command_verb := exit + else command_verb := nonesuch + end; + +@ To pick out the command verb, we frequently use two parsing macros, +|skipb| and |skipnb|, which skip over blanks and non-blanks respectively in +the |inline| string, advancing the index variable |ilp| as they go. + +@d skipb == while (ilp <= illen) and (the_char = ' ') do ilp := ilp+1 +@d skipnb == while (ilp <= illen) and (the_char <> ' ') do ilp := ilp+1 + +@= +skipb; istart := ilp; skipnb;@/ +for i := istart to ilp-1 do begin + if (inline[i] >= 'A') and (inline[i] <= 'Z') then + inline[i] := chr(ord(inline[i])+ord('a')-ord('A')) +end; + +@ The main loop of the program is a loop of reading and executing commands: + +@d cmd_error(#) == begin writeln(#); goto cmd_prompt end + +@= +cmd_prompt: + writeln; + write('FFC>'); + readln(inline);@/ + if length(inline) = 513 then cmd_error('Command line too long');@/ + inline := inline+' '; + ilp := 1; + illen := length(inline);@/ + verb := command_verb;@/ + if verb = nonesuch then cmd_error('No such command')@/ + else @;@/ + goto cmd_prompt; +final_end: + +@* Reading LN03 format files. We read the entire LN03 file into a single +large buffer: + +@d ln03_blocks = 512 +@d ln03_buf_size == ((ln03_blocks*512)-1) +@d ln03_buf == l_buf.c + +@= +@!ln03_file: byte_file; +@!ln03_count,ln03_len,i: integer; +@!l_buf: packed record + case boolean of + false: (c: packed array[0..ln03_buf_size] of char); + true: (b: packed array [0..ln03_blocks-1] of byte_block); + end; + +@ The file name is obtained from |inline|: + +@= +if verb = rln03 then begin + skipb; + istart := ilp; + skipnb;@/ + open(ln03_file,the_substr,@=readonly@>,@=error:=continue@>); + if status(ln03_file) > 0 then cmd_error('Couldn''t open file'); + reset(ln03_file); + @ +end + +@ The LN03 file is read into |inline|, line by line, and copied into the +|ln03_buf|: + +@= +ln03_count:=0; +while (not eof(ln03_file)) and (ln03_count < ln03_blocks) do + begin + read(ln03_file,l_buf.b[ln03_count]); + ln03_count:=ln03_count+1; + end; +ln03_len:=ln03_count*512; +close(ln03_file); +@ + +@ It would be desirable to check@^checking@> the LN03 file just read in, to +warn the user about anomalies. For the moment, though, we just look at the +opening two longwords. There are lots of other things we would like to do, +for example: check that all character locators and string descriptors point +into the right ranges, check that character definitions and strings in the +pool are in order, check that every character definition has the ``flag +flag'' set, check that character definitions are aligned and do not +overlap. + +@d ln03_long(#) == (ord(ln03_buf[#]) + (256*(ord(ln03_buf[(#)+1]) + + 256*(ord(ln03_buf[(#)+2]) + + 256*ord(ln03_buf[(#)+3]))))) + +@d ln03_word(#) == (ord(ln03_buf[#]) + 256*ord(ln03_buf[(#)+1])) + +@= +if ln03_len < 16 then writeln('LN03 file too short'); +if (ln03_buf[4] <> 'F') or (ln03_buf[5] <> 'O') or (ln03_buf[6] <> 'N') or + (ln03_buf[7] <> 'T') then writeln('Second longword not FONT') + +@* Reading PXL format files. The \.{PXL} format is simple. Again we read +the entire file into a single large buffer: + +@d pxl_blocks = 512 +@d pxl_buf_size == ((pxl_blocks*512)-1) +@d pxl_buf == p_buf.c + +@= +@!pxl_file: byte_file; +@!pxl_count,pxl_len: integer; +@!p_buf: packed record + case boolean of + false: (c: packed array[0..pxl_buf_size] of char); + true: (b: packed array [0..pxl_blocks-1] of byte_block); + end; + +@ The file name is obtained from |inline|: + +@= +else if verb = rpxl then begin + skipb; + istart := ilp; + skipnb;@/ + open(pxl_file,the_substr,@=readonly@>,@=error:=continue@>); + if status(pxl_file) > 0 then cmd_error('Couldn''t open file'); + reset(pxl_file); + @ +end + +@ The \.{PXL} file is read into |inline|, line by line, and copied into the +|pxl_buf|: + +@= +pxl_count:=0; +while (not eof(pxl_file)) and (pxl_count < pxl_blocks) do + begin + read(pxl_file,p_buf.b[pxl_count]); + pxl_count:=pxl_count+1; + end; +pxl_len:=pxl_count*512; +close(pxl_file); +@ + +@ As was the case for the LN03 format file, we would also like to +check@^checks@> the \.{PXL} file just read in, to warn the user about +anomalies. + +On VMS systems, \.{PXL} files are usually padded with extra longwords at +the end so their length is a multiple of 512. Thus, we search backwards +from the end of the file, looking for the ID longword (value 1001), which +marks the real end of the file. We only search through the last 512 bytes, +however. + +The definitions of |pxl_long| and |pxl_word| take into account the fact +that the bytes in \.{PXL} file longwords are reversed with respect to the +normal VAX ordering. + +@d pxl_long(#) == (ord(pxl_buf[(#)+3]) + (256*(ord(pxl_buf[(#)+2]) + + 256*(ord(pxl_buf[(#)+1]) + + 256*ord(pxl_buf[#]))))) + +@d pxl_word(#) == (ord(pxl_buf[(#)+1]) + 256*ord(pxl_buf[#])) + +@= +if not (pxl_len mod 4 = 0) then writeln('PXL file length not multiple of 4'); +if pxl_long(0) <> 1001 then writeln('Initial PXL format id wrong'); +i := pxl_len-4; +while (i >= pxl_len-512) do begin + if pxl_long(i) = 1001 then begin + pxl_len := i+4; + i := -1 + end else i := i-4 +end; +if pxl_len < 16 then writeln('PXL file too short'); +if pxl_long(pxl_len-4) <> 1001 then writeln('Final PXL format id wrong'); + +@* Typing the character rasters. When FFC gets a raster typing command, it +may read a character number from |inline| using the function |getfixnum|. + +@= + function getfixnum :integer; + label 1; + var x,x1 :integer; + negative :boolean; + + begin + x1 := 0; + negative := false; + skipb; + if ilp > illen then goto 1; + if the_char = '-' then begin + negative := true; + ilp := ilp+1 + end; + + if (ilp > illen) or (the_char < '0') or (the_char > '9') + then goto 1; + + x1 := 0; + while (the_char >= '0') and (the_char <= '9') do begin + x1 := 10*x1 + ord(the_char) - ord('0'); + ilp := ilp+1; + if ilp > illen then goto 1; + end; + + 1: + x := x1; + if negative then x := -x; + getfixnum := x + + end; + +@ The rasters corresponding to a character are stored in the area of the +LN03 file called the character definitions area. This area is pointed to by +entries in the character directory. The location of the character directory +is specified in the font file header. We define symbolic names for all the +offsets in the font file header: + +@d nob_offset = 0 +@d font_offset = nob_offset+4 +@d version_offset = font_offset+4 +@d id_offset = version_offset+4 +@d id_string_offset = id_offset + 8 +@d revision_offset = id_string_offset + 64 +@d date_offset = revision_offset + 4 +@d attributes_offset = date_offset + 12 +@d parameters_offset = attributes_offset + 8 +@d chardir_offset = parameters_offset + 8 +@d segment_list_offset = chardir_offset + 8 +@d future_info_offset = segment_list_offset + 8 +@d string_pool_offset = future_info_offset + 8 +@d kern_info_offset = string_pool_offset + 8 +@d chardefs_offset = kern_info_offset + 8 +@d charcount_offset = chardefs_offset + 8 +@d organization_flags_offset = charcount_offset + 32 +@d size_of_char_params_offset = organization_flags_offset + 4 +@d raster_expansion_info_offset = size_of_char_params_offset + 4 + +@ With these definitions, we figure out which character the user wants us +to display, determine where its locator is in the character directory, and +display the rasters. + +@= +else if verb = tln03 then begin + skipb; + if ilp > illen then cmd_error('You have to say what character to type'); + if (the_char = '''') and (ilp < illen) then i := ord(inline[ilp+1]) + else i := getfixnum; + if (i < ln03_long(charcount_offset)) or + (i > ln03_long(charcount_offset+4)) + then cmd_error('No such character'); + i := 4*(i-ln03_long(charcount_offset))+ln03_long(chardir_offset+4); + @; + @ +end + +@ The variable |def_start| is the location in the file where the character +definition begins. The rasters themselves begin a few bytes down from +there, at |ras_start|. The array |visible_byte| is used to hold the visible +form of a byte from the raster. + +@= +@!def_start, ras_start: integer; +@!j,k,l,m,n: integer; { scratch variables } +@!visible_byte: packed array[1..8] of char; + +@ The character definition we are seeking is pointed to by a character +locator@^character locators@> in the character directory portion of the +LN03 file. + +In this version of FFC, we only support locators that point directly into +the file. The LN03 format also allows ``indirect'' locators that point to +other files, or to another locator. These are distinguished by a high bit 1 +in the locator longword, whence the test |ln03_buf[i+3] >= chr(@"80)| +below. + +@= + if ln03_buf[i+3] >= chr(@"80) + then cmd_error('Indirect locators not supported'); + def_start := ord(ln03_buf[i])+256*ln03_word(i+1); + if def_start = 0 then cmd_error('Locator is zero'); + ras_start := def_start+ln03_long(size_of_char_params_offset); + writeln(' ma = ',ras_start:1); + if ras_start > ln03_buf_size + then cmd_error('Character outside piece of file read') + +@ The LN03 format allows the raster to be stored in a number of ways. The +rasters may be placed in one of eight different ``orientations,'' +corresponding to repeated $90$ degree orthogonal rotation and mirroring. +When we type out the rasters, we just show things the way they are in the +file. All we need to know is if the orientation is landscape or portrait, +which can be tested by determining of the orientation value is odd or even. + +In addition to the different orientations, the format supports run length +encoding@^run length encoding@>. The current version of FFC does not, +however. We therefore require that the ``Type1'' field in the rasters equal +|@"81|, which indicates no run length encoding: + +@= + writeln('width ',((ln03_long(def_start+4))/24.0):5:1,' pixels'); + if ord(ln03_buf[ras_start+1]) <> @"81 + then cmd_error('Run length encoding not supported'); + if odd(ord(ln03_buf[ras_start])) then begin { landscape } + writeln('landscape'); + i := ln03_word(ras_start+4); + j := ln03_word(ras_start+6) + end else begin { portrait } + writeln('portrait'); + i := ln03_word(ras_start+6); + j := ln03_word(ras_start+4) + end; + writeln(i:1,' rows ',j:1,' columns'); + + k := i div 8; + if i <> 8*k then k := k+1; + for l := 0 to j-1 do begin + for m := 0 to k-1 do begin + binrep(ord(ln03_buf[ras_start+8+k*l+m])); + write(visible_byte) + end; + writeln + end + +@ The |binrep| procedure used in the preceding section writes the visible +representation of a bitmap byte into the array |visible_byte|. The visible +representation is binary, padded out to a width of 8, using a `\.{B}' to +represent 1 and a period `\.{.}' to represent 0. + +@= +procedure binrep (v: integer); + var cnt, rem, quo: integer; +begin + visible_byte := '........'; + quo := v; + for cnt := 1 to 8 do begin + rem := quo mod 2; + quo := quo div 2; + if rem <> 0 then visible_byte[cnt] := 'B' + end; +end; + +@ The code up to now has been concerned with typing rasters from LN03 +files. \.{PXL} files are similar but simpler. The orientation is always +portrait. The directory information is always located at a fixed position +with respect to the end of the file. + +@= +else if verb = tpxl then begin + skipb; + if ilp > illen then cmd_error('You have to say what character to type'); + if (the_char = '''') and (ilp < illen) then i := ord(inline[ilp+1]) + else i := getfixnum; + if (i < 0) or (i > 127) then cmd_error('No such character'); + def_start := pxl_len - 4*517 + 16*i; + ras_start := 4*pxl_long(def_start+8); + writeln(' rasters at ',ras_start:1); + if ras_start > pxl_len then cmd_error('Rasters outside file'); + i := pxl_word(def_start); + j := pxl_word(def_start+2); + writeln(i:1,' columns ',j:1,' rows'); + k := i div 32; + if i <> 32*k then k := k+1; + for l := 0 to j-1 do begin + for m := 0 to k-1 do begin + rev_binrep(ord(pxl_buf[ras_start+4*k*l+4*m])); + write(visible_byte); + rev_binrep(ord(pxl_buf[ras_start+4*k*l+4*m+1])); + write(visible_byte); + rev_binrep(ord(pxl_buf[ras_start+4*k*l+4*m+2])); + write(visible_byte); + rev_binrep(ord(pxl_buf[ras_start+4*k*l+4*m+3])); + write(visible_byte) + end; + writeln + end +end + +@ A different |binrep| procedure is wanted here, one that puts the +bits into |visible_byte| in opposite order: + +@= +procedure rev_binrep (v: integer); + var cnt, rem, quo: integer; +begin + visible_byte := '........'; + quo := v; + for cnt := 1 to 8 do begin + rem := quo mod 2; + quo := quo div 2; + if rem <> 0 then visible_byte[9-cnt] := 'B' + end; +end; + + +@* Typing raw data from the file. For preliminary debugging purposes, it is +useful to have the ability to type raw data from a font file. This is the +purpose of the following simple code: + +@= +else if verb = tln03long then begin + i := getfixnum; + if (i >= 0) and (i < ln03_len) then writeln(ln03_long(i):1) + else writeln('Location not in file') +end +else if verb = tln03word then begin + i := getfixnum; + if (i >= 0) and (i < ln03_len) then writeln(ln03_word(i)) + else writeln('Location not in file') +end +else if verb = tpxllong then begin + i := getfixnum; + if (i >= 0) and (i < pxl_len) then writeln(pxl_long(i):1) + else writeln('Location not in file') +end +else if verb = tpxlword then begin + i := getfixnum; + if (i >= 0) and (i < pxl_len) then writeln(pxl_word(i)) + else writeln('Location not in file') +end + +@* Conversion to LN03 form. When converting a font from \.{PXL} to LN03 +form, in addition to converting the character rasters, we have to fill +in a number of font parameter slots. These slots are located in the +first three areas of the font file. We already defined offset constants +into the first area, the font file header. Here are some offsets into the +other two areas, the ``font attributes'' and the ``font parameters.'' + +@d flags_offset = raster_expansion_info_offset + 48 +@d strings_offset = flags_offset + 4 +@d type_size_offset = strings_offset + 48 +@d foundry_offset = type_size_offset + 36 +@d param_flags_offset = foundry_offset + 16 +@d lining_offset = param_flags_offset + 4 +@d subsup_offset = lining_offset + 32 +@d hspace_offset = subsup_offset + 16 +@d vspace_offset = hspace_offset + 32 +@d charxdir_offset = vspace_offset + 40 + +@ When we are asked to convert to LN03 form, we first clear the |ln03_buf|, +then we convert the rasters, and finally we fill the parameters. For the +moment, to comply with the LN03 format's restriction to 94 characters, we +only convert characters 33 through 126 of the \.{PXL} file. The rest are +discarded. If the command is \.{toln03x}, however, the entire 128 +characters are copied, violating the LN03 format standard. + +@= +else if (verb = toln03) or (verb = toln03x) then begin + for i := 0 to ln03_buf_size do ln03_buf[i] := chr(0); + if verb = toln03 then begin first_char := 33; last_char := 126 end + else begin first_char := 0; last_char := 127 end; + num_chars := last_char-first_char+1; + @; + @ +end + +@ We have to know where to put the rasters as we convert them, which means +we have to know where the ``character definitions'' area begins in the LN03 +file. That area comes after the character directory (4 bytes per +character), the table of font segments (4 bytes, to indicate there are +no font segments), the future info section (empty), the string pool, +and the kerning info (empty). + +The string pool has to contain the character set designator (7 bytes), type +family ID (7 bytes), type family name, Font ID (16 bytes), type category, +foundry, font designer, and segment names. For the moment, converted files +have a 16-byte type family name and empty type category, foundry, font +designer and segment names. The total length is 46 bytes, rounded up to 48 +bytes. + +To fill some slots in the LN03 format, we have to add up the sizes of the +rasters in three different ways---portrait, landscape and +``mixed''---whence the variables |psize|, |lsize| and |msize|. + +@= +@!charxdef_offset,string_pool_size,stringx_pool_offset: integer; +@!psize,lsize,msize: integer; +@!first_char,last_char,num_chars: integer; +@!all_blank: boolean; +@!zchar,tfm_width,x_offset,y_offset: integer; +@!dsize,mag: real; + +@ The |charxdef_offset| can be computed from the information above. (We +could have defined this offset as a constant, but want to leave ourselves a +little more flexibility.) + +@= + string_pool_size := 48; + stringx_pool_offset := charxdir_offset+4*num_chars+4; + charxdef_offset := stringx_pool_offset+string_pool_size; + ln03_len := charxdef_offset; + psize := 0; lsize := 0; msize := 0; + for zchar := first_char to last_char do + begin @ end; + +@ When converting for a single character, we first fill in the ``flag +flag'' of the character, which the format requires us to set. Then we copy +the nominal width, left bearing and raster baseline. + +The LN03 format demands that these dimensions be converted to +``centipoints,'' where a ``centipoint@^centipoint (unit of measure)@>'' is +defined to be one 7200$^{\rm th}$ of an inch. The nominal width is stored +in the \.{PXL} file as a fraction of the magnification times design size. +The magnification, multiplied by five times the dots per inch (in our case +1500), is stored in the fourth-from-last longword of the \.{PXL} file. The +design size is stored in the third-from-last longword in units of $2^{-20}$ +``points,'' a ``point'' being defined as one 72.27$^{\rm th}$ of an inch. + +The left bearing and raster baseline are stored in pixel units in the +\.{PXL} file and in centipoints in the LN03 file, so the conversion +factor is $7200/300 = 24$. + +@d two_to_the_20th == (@"100000) + +@= + ln03_buf[ln03_len+3] := chr(@"80); + def_start := pxl_len - 4*517 + 16*zchar; + ras_start := 4*pxl_long(def_start+8); + if ras_start > pxl_len then cmd_error('Rasters outside file for ', + zchar:1); + tfm_width := pxl_long(def_start+12); + dsize := pxl_long(pxl_len-12); + mag := pxl_long(pxl_len-16); + dsize := (dsize/two_to_the_20th)*(mag/1500.0); + x_offset := signed_pxl_word(def_start+4); + y_offset := signed_pxl_word(def_start+6); + set_ln03_long(ln03_len+4,round((dsize*7200.0*tfm_width)/ + (two_to_the_20th*72.27))); + set_ln03_long(ln03_len+8,-24*x_offset); + set_ln03_long(ln03_len+12,-24*y_offset); + +@ Even though we're not trying to make this program portable, we do +the word and longword computations by hand, instead of using overlays. + +@= + function signed_pxl_word (index: integer) :integer; + begin + if ord(pxl_buf[index]) >= @"80 then + signed_pxl_word := pxl_word(index) - @"10000 + else signed_pxl_word := pxl_word(index) + end; + + procedure set_ln03_long (index, value: integer); + var negative: boolean; + a,b,c,d,carry: integer; + begin + if value < 0 then negative := true else negative := false; + if negative then value := -value; + a := value mod 256; + b := (value div 256) mod 256; + c := (value div (256*256)) mod 256; + d := value div (256*256*256); + if negative then begin + carry := 0; + a := 256-a; + if a = 256 then begin a := 0; carry := 1 end; + b := 255+carry-b; + if b = 256 then b := 0 else carry := 0; + c := 255+carry-c; + if c = 256 then c := 0 else carry := 0; + d := 255+carry-d; + if d = 256 then d := 0 + end; + ln03_buf[index] := chr(a); + ln03_buf[index+1] := chr(b); + ln03_buf[index+2] := chr(c); + ln03_buf[index+3] := chr(d) + end; + +@ The rasters are always placed in portrait into the LN03 file, with no use +of run-length encoding, so the ``orient'' field of the raster format is 0, +and the ``Type1'' field is @"81. We copy the rasters byte by byte from the +\.{PXL} buffer, reversing each byte. At the end we store the raster address +in the character directory and increment the |pxl_len| variable, making +sure that all character definitions fall on even-byte boundaries. We also +increment the size variables. + +If the rasters for a character are completely blank, an ``undocumented +feature'' of the LN03 seems to cause things to go wrong. Thus, in that +case, we set height and width to 1, and put in a blank byte. + +@= + ln03_buf[ln03_len+17] := chr(@"81); + i := pxl_word(def_start); + j := pxl_word(def_start+2); + all_blank := (i = 0) and (j = 0); + if all_blank then begin i := 1; j := 1 end; + ln03_buf[ln03_len+20] := chr(j mod 256); + ln03_buf[ln03_len+21] := chr(j div 256); + ln03_buf[ln03_len+22] := chr(i mod 256); + ln03_buf[ln03_len+23] := chr(i div 256); + k := i div 32; + if i <> 32*k then k := k+1; + n := i div 8; + if i <> 8*n then n := n+1; + if not all_blank then + for l := 0 to j-1 do + for m := 0 to n-1 do + ln03_buf[ln03_len+24+n*l+m] := + reverse_byte(pxl_buf[ras_start+4*k*l+m]); + set_ln03_long(charxdir_offset+4*(zchar-first_char),ln03_len); + ln03_len := ln03_len+24+j*n; + if odd(ln03_len) then ln03_len := ln03_len+1;@/ + { now update the size counts } + psize := psize+j*n; + k := j div 8; + if j <> 8*k then k := k+1; + lsize := lsize+i*k; + if i*k > j*n then msize := msize+i*k else msize := msize+j*n; + +@ It is necessary to use a function |reverse_byte| to reverse the bits in +going from the \.{PXL} to the LN03 raster format. It would be faster to do +this with a 256-byte string. + +@= + function reverse_byte (u: char) : char; + var cnt,rv :integer; + begin + binrep(ord(u)); + rv := 0; + for cnt := 1 to 8 do + if visible_byte[cnt] = 'B' then rv := 1 + 2*rv + else rv := 2*rv; + reverse_byte := chr(rv) + end; + +@* Filling in the LN03 parameters. Once the rasters are transferred from +\.{PXL} to LN03 format, we have to fill in the endless LN03 parameters, +using the offsets defined above. We will only fill parameters that are not +left at zero, since we already initialized the |ln03_buf| to zero above. We +start off with the header and trailer, placing |'FONT'| and the |ln03_len| +in the opening and closing longwords. + +@= + if ln03_len mod 4 <> 0 then ln03_len := ln03_len + (4 - (ln03_len mod 4)); + ln03_len := ln03_len+8; { for trailer } + set_ln03_long(0,ln03_len); + set_ln03_long(ln03_len-8,ln03_len); + ln03_buf[4] := 'F'; + ln03_buf[ln03_len-4] := 'F'; + ln03_buf[5] := 'O'; + ln03_buf[ln03_len-3] := 'O'; + ln03_buf[6] := 'N'; + ln03_buf[ln03_len-2] := 'N'; + ln03_buf[7] := 'T'; + ln03_buf[ln03_len-1] := 'T'; + +@ There follow the version number of the format (always 1), the font file +ID (always the value indicated below), the revision number of the font +(always 0), and the date and time record (always 2:00 {\eightrm P.M.}, +September 11, 1973). Eventually the user will be able to set the font file +ID with a command, and the time will come from the timestamp on the \.{PXL} +file. + +@= + ln03_buf[version_offset] := chr(1); + ln03_buf[id_offset] := chr(31); + ln03_buf[id_offset+4] := chr(id_offset+8); + font_id_string := 'U000000002SK00GG0001UZZZZ02F000'; + for i := 1 to 31 do ln03_buf[id_string_offset+i-1] := + font_id_string[i]; + ln03_buf[date_offset] := chr(1973 mod 256); + ln03_buf[date_offset+1] := chr(1973 div 256); + ln03_buf[date_offset+2] := chr(9); + ln03_buf[date_offset+4] := chr(11); + ln03_buf[date_offset+6] := chr(14); + +@ Oops, we forgot to declare the |font_id_string|: + +@= +@!font_id_string: packed array [1..31] of char; + +@ After the date and time come the various pointers into the file. + +@= + set_ln03_long(attributes_offset,param_flags_offset-flags_offset); + set_ln03_long(attributes_offset+4,flags_offset); + set_ln03_long(parameters_offset,charxdir_offset-param_flags_offset); + set_ln03_long(parameters_offset+4,param_flags_offset); + set_ln03_long(chardir_offset,4*num_chars); + set_ln03_long(chardir_offset+4,charxdir_offset); + set_ln03_long(segment_list_offset,4); + set_ln03_long(segment_list_offset+4,charxdir_offset+4*num_chars); + set_ln03_long(future_info_offset+4,charxdir_offset+4*num_chars+4); + set_ln03_long(string_pool_offset,string_pool_size); + set_ln03_long(string_pool_offset+4,charxdir_offset+4*num_chars+4); + set_ln03_long(kern_info_offset+4,charxdir_offset+4*num_chars+4+ + string_pool_size); + set_ln03_long(chardefs_offset,ln03_len-8-charxdef_offset); + set_ln03_long(chardefs_offset+4,charxdef_offset); + +@ Next come the eight longwords of character count information, the +``organization'' flags, the size of character parameters, and the raster +expansion information. + +@= + set_ln03_long(charcount_offset,first_char); { first character } + set_ln03_long(charcount_offset+4,last_char); { last character } + set_ln03_long(charcount_offset+28,32); { space encoding } + set_ln03_long(charcount_offset+32,@"A8); { ``organization'' flags } + set_ln03_long(charcount_offset+36,16); { size of character params. } + set_ln03_long(raster_expansion_info_offset,num_chars); { in file locator count } + set_ln03_long(raster_expansion_info_offset+8,num_chars); { number of character defs. } + set_ln03_long(raster_expansion_info_offset+16,num_chars); { number of rasters } + set_ln03_long(raster_expansion_info_offset+24,psize); + set_ln03_long(raster_expansion_info_offset+28,lsize); + set_ln03_long(raster_expansion_info_offset+32,msize); + +@ Next come the font attributes. These include a number of strings that +have to be placed in the string pool. Of the flags, we set the Roman one +only. The character set designator is always set to |'0B'|, tab, |'ZZZZ'|. +Again, eventually the user will have commands to set these. + +@= + set_ln03_long(flags_offset,2); { flags } + set_ln03_long(flags_offset+4,7); { length of character set designator } + set_ln03_long(flags_offset+8,stringx_pool_offset); + ln03_buf[stringx_pool_offset] := '0'; + ln03_buf[stringx_pool_offset+1] := 'B'; + ln03_buf[stringx_pool_offset+2] := chr(9); + ln03_buf[stringx_pool_offset+3] := 'Z'; + ln03_buf[stringx_pool_offset+4] := 'Z'; + ln03_buf[stringx_pool_offset+5] := 'Z'; + ln03_buf[stringx_pool_offset+6] := 'Z'; + set_ln03_long(flags_offset+12,7); { length of type family ID } + set_ln03_long(flags_offset+16,stringx_pool_offset+7); + for i := 1 to 7 do + ln03_buf[stringx_pool_offset+7+i-1] := font_id_string[i]; + set_ln03_long(flags_offset+20,16); { length of type family name } + set_ln03_long(flags_offset+24,stringx_pool_offset+7+7); + for i := 1 to 16 do + ln03_buf[stringx_pool_offset+7+7+i-1] := ' '; + set_ln03_long(flags_offset+28,16); { length of font id } + set_ln03_long(flags_offset+32,stringx_pool_offset+7+7+16); + for i := 1 to 16 do + ln03_buf[stringx_pool_offset+7+7+16+i-1] := font_id_string[i]; + +@ The type size is given in the \.{PXL} file in units of $2^{-20}$ points; +we have to translate it to points. The average character width is +arbitrarily set to half the point size (which means we multiply it by 50 to +convert it to centipoints). + +@= + i := pxl_long(pxl_len-12); + points := i div two_to_the_20th; + k := (10000*i mod two_to_the_20th) div two_to_the_20th; + ln03_buf[type_size_offset] := chr(points mod 256); + ln03_buf[type_size_offset+1] := chr(points div 256); + ln03_buf[type_size_offset+2] := chr(k mod 256); + ln03_buf[type_size_offset+3] := chr(k div 256); + if k > 4999 then points := points+1; + set_ln03_long(type_size_offset+4,50*points); + +@ We need to declare |points|, by the way, which stores the pointsize of +the font as an integer. + +@= +@!points: integer; + +@ Next come the resolution, weight, horizontal proportion, horizontal +proportion fraction, aspect ratio and character up vector. + +@= + ln03_buf[type_size_offset+10] := chr(24); { hocus-pocus means 300 dpi } + ln03_buf[type_size_offset+12] := chr(16); { weight is ``regular'' } + ln03_buf[type_size_offset+16] := chr(16); { horizontal proportion is regular} + ln03_buf[type_size_offset+20] := chr(1); + ln03_buf[type_size_offset+22] := chr(1);@/ + ln03_buf[type_size_offset+24] := chr(1); { aspect ratio is 1/1} + ln03_buf[type_size_offset+26] := chr(1); + ln03_buf[type_size_offset+30] := chr(1); { character up vector } + +@ The third and last step of the filling process handles the font +parameters, which are mostly supposed to be in ``centipoints.'' Eventually +some of these will be obtained from the \.{TFM} file, but for the moment we +wing it, guessing them all from the point size |points|. + +The flag longword that begins the font parameter section can conveniently +be left empty. The slant is not guessed, but always set to zero. As you can +see, the values of the horizontal and vertical spacing parameters are +fairly random, but should not lead to impossibly poor output. + +@= + set_ln03_long(lining_offset,12*points); { underline offset } + set_ln03_long(lining_offset+4,8*points); { underline thickness } + set_ln03_long(lining_offset+8,-25*points); { strike through offset } + set_ln03_long(lining_offset+12,8*points); { strike through thickness } + set_ln03_long(lining_offset+16,-60*points); { overline offset } + set_ln03_long(lining_offset+20,8*points); { overline thickness } + ln03_buf[lining_offset+26] := chr(1); { slant (always 0) } + ln03_buf[lining_offset+30] := chr(points*12 mod 256); { shadow vector } + ln03_buf[lining_offset+31] := chr(points*12 div 256); + set_ln03_long(subsup_offset,-36*points); + set_ln03_long(subsup_offset+8,16*points); + set_ln03_long(hspace_offset,24*points); { center line } + set_ln03_long(hspace_offset+4,20*points); { minimum space width } + set_ln03_long(hspace_offset+8,80*points); { maximum space width } + set_ln03_long(hspace_offset+12,25*points); { width of space } + set_ln03_long(hspace_offset+16,100*points); { width of em } + set_ln03_long(hspace_offset+20,50*points); { width of en } + set_ln03_long(hspace_offset+24,10*points); { width of thinspace } + set_ln03_long(hspace_offset+28,35*points); { width of digit } + set_ln03_long(vspace_offset,-64*points); { top line } + set_ln03_long(vspace_offset+4,-50*points); { floating accent line } + set_ln03_long(vspace_offset+8,-35*points); { half line } + set_ln03_long(vspace_offset+12,100*points); { total vertical size } + set_ln03_long(vspace_offset+16,-65*points); { above baseline } + set_ln03_long(vspace_offset+20,35*points); { below baseline } + set_ln03_long(vspace_offset+24,65*points); { cap H height } + set_ln03_long(vspace_offset+28,35*points); { small x height } + set_ln03_long(vspace_offset+32,10*points); { white space above tallest } + set_ln03_long(vspace_offset+36,10*points); { white space below deepest } + +@* Writing the LN03 file. It seems to be conventional to store LN03 format +font files as 512-byte fixed length record VAX files. For this reason, we +declare |outfile| to be this type of file: + +@= +@!outfile: byte_file; + +@ The writing simply consists of putting chunks of the |ln03_buf| out +into |outfile|. + +@= +else if verb = wln03 then begin + skipb; + if ilp > illen then cmd_error('You must specify a file to write into'); + istart := ilp; skipnb; + open(outfile,the_substr,@=error:=continue@>); + if status(outfile) <> 0 then cmd_error('couldn''t open',the_substr); + rewrite(outfile); + i := ln03_len div 512; + if ln03_len <> i*512 then i := i+1; + for j := 0 to i-1 do + write(outfile,l_buf.b[j]); + close(outfile) +end + +@* Leaving the program. If the user types an |exit| command, we leave: + +@= +else if verb = exit then goto final_end + +@* Index. This is the standard Web index to all identifiers. diff --git a/dviware/ln03/rose/forpxl.fdl b/dviware/ln03/rose/forpxl.fdl new file mode 100644 index 0000000000..121208c1c5 --- /dev/null +++ b/dviware/ln03/rose/forpxl.fdl @@ -0,0 +1,4 @@ +IDENT "14-NOV-1985 11:21:24 VAX-11 FDL Editor" + +RECORD + CARRIAGE_CONTROL none diff --git a/dviware/ln03/rose/ln03bis.mem b/dviware/ln03/rose/ln03bis.mem new file mode 100644 index 0000000000..813bc399e9 --- /dev/null +++ b/dviware/ln03/rose/ln03bis.mem @@ -0,0 +1,632 @@ +The purpose of this file is to explain how to print TeX +files on your LN03 laser printer. To do this, you must have +at least one optional RAM cartridge in your LN03. + +The TeX to LN03 driver has been changed substantially +compared to the ones in previous distributions. Error +reporting has been revamped, and the driver now reads PXL +format font files as well as LN03 format font files. + +The TeX-to-LN03 driver described here requires VAX/VMS V4.2. +(It has also been tested on Ultrix-32 V1.2 and on 4.3bsd +Unix; see section 12, "Unix", below.) + +Most of the things described below probably also work on +VAX/VMS V4.0 or V4.1, if you do your linking on a system +which has VAX C installed. + + +0. BILL OF MATERIALS + +The present file is: + + ln03.mem + +These are the files that comprise the TeX to LN03 driver: + + dvi2ln3.c + dvi2ln3nft.c + specials.c + clink.opt + +These other files comprise an auxiliary program that can be +helpful: + + newffc.c + +Depending on circumstances, you may have received .obj files +corresponding to the different .c's, or you may need to +regenerate them using a C compiler. + + + +1. INSTALLATION + +The basic steps to install the DVI to LN03 driver are as follows: + + A. Link the driver program. + + B. Set up your font raster directories. + + C. Have users set up certain definitions in their login.com, or put + them in the system login file. + +No VMS privileges are needed to install the driver. + + +STEP A, LINKING DVI2LN3. Type: + + $ link dvi2ln3,dvi2ln3nft,specials,clink/opt + + +STEP B, PXL FILES. If you don't already have a collection of font +files in PXL format, you need to assemble one. The usual way to +get PXL files is either off a TeX tape, or by running the GFtoPXL +program which is supplied with Metafont. + +Your PXL fonts must have extensions .yyyyPXL, where yyyy is the +magnification times 1500. For example, the fonts that are at 100% +magnification have extension .1500PXL, and those that are at 120% +magnification have extension .1800PXL. Be sure, of course, that +the fonts are suitable for 300 dot per inch printers, because +that's what the LN03 is. + +VMS allows two files to have the same data bytes, which are +interpreted in different ways depending on the "record format", +"record attributes", and "record size". There are many +possibilities for these parameters. Dvi2ln3 has been tested with +PXL files of the following two types: + + record format: stream_LF + +or + + record format: fixed, record size: 4 + +You determine these characteristics of a given file by doing a +VMS DIRECTORY /FULL on the file. + +I believe the files come off the TeX tape in the second format. +If for some reason, your PXL files are not in one of these +formats, you should test dvi2ln3 to see if it works. If it +doesn't, you will have to convert your files somehow. Please +consult section 9 below for some hints on how to do this. + + +STEP C, DEFINITIONS. Everyone who uses the DVI to LN03 converter +must have the following definitions: + + $ dvi2ln3 == "$tex$:dvi2ln3" + $ define tex$pxldir + +The logical names tex$ and tex$fonts are also needed; these +should be defined as for running TeX itself. + + + +2. USING THE DVI TO LN03 DRIVER + +To convert foo.dvi to an LN03 format file (extension .ln3), type + + $ dvi2ln3 foo + +Print the file foo.ln3 on your LN03 by saying + + $ print/nofeed/queue= foo.ln3 + +This assumes your system manager has set up the LN03 as a spooled +device with queuename . The /nofeed is very important, +for if you omit it, you may get unwanted page breaks in your +output file. + + + +3. COMMAND LINE OPTIONS FOR DVI2LN3 + +The DVI2LN3 program has some options. These are typed on the +command line, after the file name FOO, and separated from it by +at least one space. + + /S=page number - the output file will only contain the pages in + the DVI file that start at the given page number. The + page number is the value of counter 0. + + /N=number of pages - the output file will only contain that many + pages from the DVI file. + +For example, to cause only pages 20 through 22 of FOO to be +converted to LN03 form, say + + $ DVI2LN3 FOO /S=20 /N=3 + + /H= - print the file at a horizontal offset of + pixels, i.e., moved right that many pixels. (There are 300 pixels to + the inch.) + + /V= - print the file at a vertical offset of + pixels, i.e., moved down that many pixels. + +The values given with /V and /H are ADDED to the TeX parameters +\hoffset and \voffset; they do not replace these parameters. + + /L - print the entire file in landscape mode (with text running + along the long direction of the paper). The size of the text + is not changed. Thus you have only about 8 inches from top to + bottom - make sure your .tex file does not produce pages which + are longer than that. + + + +4. WARNINGS ABOUT THE LN03 DRIVER + +Now, some caveats and warnings about the LN03 driver for TeX. + +The driver is copyrighted data of Digital Equipment Corporation. +Because Digital makes this software available for free, it does +not promise that the software works or does anything. + +A different, supported TeX to LN03 driver may be available from +Kellerman and Smith in Portland, Oregon. + +The most common problem people encounter when first using the +LN03 support is forgetting to print the .ln3 files with the +/nofeed qualifier. This can cause a page of output to be split +into two or more pages. + +There are some limitations to the LN03 support: + + - Your LN03 should have at least one RAM cartridge plugged in. + Otherwise, it is unlikely that any but the smallest documents + will print successfully. + + - The landscape support is very recent. + + - The code that reads PXL files is relatively recent. (Formerly, + the driver read LN03 format files only.) + + - One cannot access the preloaded or ROM fonts in an LN03. + + - DVI2LN3 has limitations on the size of a font load, which + may be exceeded by TeX files. This rarely occurs. + + - The LN03 also has limitations on the complexity of a page, which + may be exceeded by TeX files. This is very rare. + + - Very large fonts such as AMINCH cannot be handled. (The LN03 can't + handle them anyway.) + + - For TeX's \magstephalf, the PXL files should have + extension .1642PXL. I believe this to be the + correct extension, but some distributions give + the \magstephalf fonts extension .1643PXL. + + - The VMS spooler for the LN03 has to be set up properly with + $ SET TERMINAL and $ SET QUEUE commands. Here are some settings + that have been found to work: + +Terminal queue LN03$B12, on BOSTON$TTE6: + /BASE_PRIORITY=4 /DEFAULT=(FEED) /NOENABLE_GENERIC + /FORM=DEFAULT Lowercase /OWNER=[SYSTEM] /PROTECTION=(S:E,O:D,G:R,W:RW) + /SCHEDULE=(NOSIZE) /SEPARATE=(FLAG,RESET=(PORTRAIT)) + +Terminal: _TTE6: Device_Type: Unknown Owner: SYMBIONT_0001 + Username: SYSTEM +Terminal Characteristics: + Interactive Echo Type_ahead No Escape + No Hostsync TTsync Lowercase No Tab + No Wrap Scope No Remote Eightbit + No Broadcast No Readsync Form Fulldup + No Modem No Local_echo No Autobaud No Hangup + No Brdcstmbx No DMA No Altypeahd Set_speed + No Line Editing Overstrike editing No Fallback No Dialup + No Secure server Disconnect No Pasthru No Syspassword + No SIXEL Graphics No Soft Characters No Printer Port Numeric Keypad + No ANSI_CRT No Regis No Block_mode No Advanced_video + No Edit_mode No DEC_CRT No DEC_CRT2 +Device spooled to _CECIL$DUA7: + + +6. MORE ABOUT FONTS + +If you should acquire LN03-format fonts by some means other than +PXL file manipulation, you can use them with dvi2ln3. Just put +them in a directory and define a logical tex$ln03dir to point to +them. + +You will need to get TFM files for those fonts by some means. The +NEWFFC program can help you (a little). If you have a font +foo.ln03, and you want to know what the character with code xx +looks like in that font, you can type: + + $ run newffc + + FFC>rnft foo.ln03 + FFC>tnftr xx + [Types rasters and tells you the width of the character] + FFC>exit + $ + +Using the raster width information, you can then compose a PL +format file, which can then be converted to TFM format by running +the PLtoTF program on it. PLtoTF is distributed with TeX. + +If you have a VT125, VT240 or VT241 terminal, you can type pnftr +instead of tnftr; that plots the rasters on the screen using the +terminal's graphics capabilities. + +To link newffc, type + + $ link newffc,clink/opt + +or else + + $ link newffc,sys$library:vaxcrtl/lib + + +7. \special COMMANDS + +DVI2LN3 interprets certain \special commands. + +Right now, the following \special's are implemented: + + ln03:defpoint integer ( [dimension] , [dimension] ) + ln03:connect integer [/ integer] integer [/ integer] [dimension] + ln03:plotfile filename + ln03:resetpoints integer integer + +A dimension is a number with optional decimal point, followed by +one of pt, in, pc, cm, mm, bp, dd, cc, and mi. + +The peculiar syntax of these commands is due to a request to +emulate certain commands invented by Textset, Inc. (Ann Arbor, +Michigan). + +Ln03:plotfile includes the named file literally in the .LN3 +output file. No parsing whatsoever of the file is done, nor are +any defaults applied to the filename. + +The remaining specials work with an array of 255 points, numbered +1 to 255. Each point is a location on the paper. Initially, the +array is uninitialized; and any contiguous segment of the array +may be returned to the uninitialized state using ln03:resetpoints +a b, which uninitializes points a through b inclusive. + +A point value may be assigned to a particular position in the +array using ln03:defpoint. In using ln03:defpoint, one may +specify the coordinates of the point, or one may omit either the +x- or the y-coordinate or both, in which case they are taken to +be the current values at the time the \special call occurs. + +The ln03:connect special is used to draw a rule connecting two +points. The two points must have either the same x-coordinate or +the same y- coordinate. The optional dimension is the thickness +of the rule; if none is specified, the rule is 2 pixels thick. + + +8. DVI2LN3 ERROR MESSAGES + +Dvi2ln3 internal error, bad txfno or lnfno + + Indicates a bug in dvi2ln3. + +Couldn't find good font file: using blanks + + There was neither an LN03 format font file nor a PXL format font + file for the specified font and magnification. Dvi2ln3 is making + a font load which replaces all the glyphs in that font with blanks + of the appropriate width. Check that the font file directories + TEX$LN03DIR or TEX$PXLDIR exist and are readable to you. + +Error while reading PXL file + + There was some problem reading the PXL file for the specified + font and magnification. Perhaps the file is not in correct + format. + +No more room in LN03 font load buffer (xxx bytes long) + + Dvi2ln3 is trying to build a font load, and the font load has + become so large that it has exceeded the size of a buffer in + the program. The probable cause of this is that your document + uses one or more very large fonts. Dvi2ln3 is not designed + to work with fonts larger than 36pt. + +-- Bad NFT file, lacks FONT. +-- bad NFT file, not enough character parameters +-- bad NFT file, bad character range. +LN03 font file bad, using blanks + + The LN03 font file found for the specified font has some + problem (probably it is not in the right format). Dvi2ln3 + will build a font load in which the glyphs for that font + are replaced by appropriately sized blanks. Use NEWFFC to + examine the LN03 font file and track down what might be + wrong with it. + +Usage: Dvi2ln3 + + You have called dvi2ln3 without giving it a parameter + (the name of the file it has to process). + +Couldn't open dvi file +Couldn't rewind dvi file. + + Dvi2ln3 is having trouble accessing the dvi file you + have asked it to read. Check that the file exists and + that you have read access to it. + + You could also get this message if you forgot the + space between the dvi file and the options on the + command line. E.g. if you typed dvi2ln3 foo/h=10 + then dvi2ln3 would try to open a file named "foo/h=10" + and would obviously fail in the attempt. + +Bad DVI file - check it with DVItype + + There is something wrong with the dvi file which Dvi2ln3 + is trying to read. Run DVItype on that file to find out + what is wrong. Since TeX writes correct DVI files, it is + unlikely you will get this message... + +Couldn't open output file + + Dvi2ln3 couldn't open the .ln3 file it is trying to + create. Perhaps you don't have write access in the + current directory; perhaps your disk quota is exceeded. + +Can't construct a font load: +Dvi file uses too many glyphs from too many different fonts. + + The LN03 has limits on how many glyphs and fonts it can + handle. Dvi2ln3 tries to make best use of the LN03 within + those limits. However, if you get the above message, it + means Dvi2ln3 has been unable to figure out how to print + your file within those limits. Solution: print your file + a few pages at a time using the /s and /n command line + options. If this problem occurs even when you try to print + just a single page, then you will have to simplify that page. + +Font xxx uses > 188 characters. Can't handle that. + + Fonts could have as many as 256 characters. However, dvi2ln3 + assumes you will only use 188 of them in any one document. + If you get tris message, try to print your file a few pages + at a time. + +Stack too deep for Dvi2ln3 + + The dvi file has a stack, and Dvi2ln3 is designed only + to allow that stack to go 100 entries deep. This is essentially a + design error in the program. Solution: recompile dvi2ln3 with + a larger STACKSIZE parameter. + +Too many fonts for Dvi2ln3 + + Dvi2ln3 is designed to handle only 100 fonts in your document. + Again this is essentially a desing error in the program. + Solution: recompile dvi2ln3 with a larger MAXTEXFONTS + parameter. + +Font xxx has a bad scaled size +Font xxx has a bad design size + + This indicates a bad DVI file format. + +Can't open TFM file for font xxx + + If you use a font named foo, there has to exist a file + foo.tfm in tex$fonts. If you get the above message, + make sure that file exists and is readable to you. + +Bad TFM file for font xxx + + The TFM file is in a bad format. Check it with + the TFtoPL program, which will tell you what is + wrong with it. + +\special too long (over xxx bytes). + + \special's are limited to a certain length (2048 bytes + or something like that). There is no need for a \special + to be anything like that long, so if you get this + message, obviously you have coded the \special in + some weird way. + +Unrecognized option 'xxx' ignored in \special command + + This means you have a \special with a command ln03:xxx + and xxx means nothing to dvi2ln3. + +Invalid point number (xxx) + + The \special's that deal with points are only designed + to handle 255 of them, numbered 1 to 255. If you get + the above message, it means you have probably tried + to use a point number outside the range 1 to 255. + +Unable to open plotfile xxx + + You used the ln03:plotfile \special, but dvi2ln3 was + incapable of reading the plotfile you told it to read. + +No such unit of measure: xxx + + You have used xxx in a context in which \special syntax + is expecting a unit of measure (such as "in", "cm", "pt"). + +Can't connect along a diagonal. + + The ln03:connect \special can only connect two points which + are either at the same horizontal coordinate or at the + same vertical coordinate. + + +ERRORS THAT DVI2LN3 DOES NOT CATCH. There are a number of +possible errors in processing your document that Dvi2ln3 +does not catch. You have to detect them by looking at the +printed output. + +These include: + + errors in the use of TeX commands to achieve the formatting effects + you desire (of course); + + misuse of the /h= and /v= command line options in such a way that + margins are too small or text material is set off the page; + + errors in font files that cause rasters to be wrong (e.g. if + a font file has rasters for a "2" in the position where there ought + to be a "1"); + + gross discrepancies between the raster font files and the .tfm + files; + + certain font file format errors in which a font file contains bad + pointers. + +In general, if any part of your document seems to look wrong, +check that you are using TeX correctly, then check carefully +which fonts are involved in the part that comes out wrong. + + +9. PXL FILE CONVERSION + +If your PXL files are not in one of the acceptable record formats +described in section 1, you will need to perform some conversion. +There are many possibilities, so we can only suggest one approach +that may be helpful. This approach seems to work if your PXL +files were written by GFtoPXL. + +(a) Link the newffc program by saying: + + $ link newffc,clink/opt + +or else + + $ link newffc,sys$library:vaxcrtl/lib + +(b) Convert the resulting file to stream_LF as follows: + + $ run newffc + + FFC> rpxl foo.pxl + FFC> wstr foo.pxl + FFC> exit + $ + +(c) You can also check out your PXL file using newffc. + + $ run newffc + + FFC> rpxl foo.pxl + FFC> txplr nn + [types rasters corresponding to character code nn on terminal] + + +10. NEWFFC COMMANDS + + EXIT + The obvious (control-Z also works) + + RPXL + Read a PXL file into memory. The code tries to + accomodate a wide range of VMS file formats. + + TPXLR + Type the rasters for character code from + the PXL file currently in memory + + PPXLR + Plot the rasters for PXL character + using the "sixel" protocol accepted by + VT125, VT240 and VT241 terminals + + TPXLL + Type the longword at offset in the + PXL file currently in memory + + SPXLL + Set the longword at offset to value + in the PXL file currently in memory. + is read in HEXADECIMAL (this being + considered the most convenient...). + + WSTR + Write the PXL file currently in memory onto + the file , in stream_LF format as + desired by the LN03 and LaserWriter support. + + INITNFT + Initialize the in-memory buffer for LN03 font files + with information appropriate to an LN03 file + accomodating characters from to . + Note: the only truly legal values are 33 and 126. + + CPTONFT + Copy characters from the PXL file in memory to + the LN03 file in memory, beginning at + in the PXL file and going up to . Characters + are put at the lowest available codes in the + LN03 file. + + RNFT + Read unsixelized LN03 format font file into buffer + + WNFT + Write the LN03 font file in memory to a file + . The file written out is not sixelized. + + TNFTR + Type the rasters for LN03 character, specified + as a decimal ascii code + + PNFTR + Plot the rasters for LN03 character + using the "sixel" protocol accepted by + VT125, VT240 and VT241 terminals + + TNFTL + Type longword of LN03 file buffer at given + byte + + SNFTL + Set longword of LN03 file buffer at given + byte to stated in hex. + + + +11. BUG REPORTS + +Please report any bugs you may find. You may phone (617) +467-7545, send Arpanet mail to Rose%dvinci.dec@decwrl.arpa, or +Usenet mail to ...!decwrl!dec-rhea!dec-dvinci!rose. The best way +to report a bug is to mail the TeX file that evokes it together +with a description of what is wrong with the printed output. + +If you should wish to port this software to operating systems +other than VAX/VMS, please do not hesitate to contact me. + + +12. UNIX + +The sources for dvi2ln3 and newffc may be recompiled under +Unix on a VAX, and will probably run there. This has been +tried and tested (to a limited extent) under Ultrix-32 and +4.3bsd. + +When running under Unix, Dvi2ln3 expects three "environment +variables" to be defined: + + TEX_FONTS wherever the tfms are + TEX_LN03DIR wherever the LN03 format font files are + TEX_PXLDIR wherever the PXL format files are + +Define these with setenv. + +You may need to modify dvi2ln3 and newffc to run on your +Unix system. In particular, if your Unix runs on a 68000 or +PC RT or something like that, you may have to make serious +modifications. Look in particular at all C "union" +constructs in the source; the code that manipulates them may +need to be redefined because of the machine architecture +(this is necessary, e.g., on a 68000). diff --git a/dviware/ln03/rose/ln03topp.pli b/dviware/ln03/rose/ln03topp.pli new file mode 100644 index 0000000000..30ff2bf13d --- /dev/null +++ b/dviware/ln03/rose/ln03topp.pli @@ -0,0 +1,1255 @@ +/* + +This program is LN03Topp, which converts the output of DVI2LNG to LN03 +format files. Copyright (c) 1984 by Digital Equipment Corporation. Author: +Flavio Rose, UHCLEM::ROSE. + +This program is UNDER DEVELOPMENT... + +Development chronology: + +11/26/84: Started coding. Changed filenames. +11/28/84: New algorithm for allocation of TeX fonts to LN03 font slots +11/29/84: Extensive changes in TOPPNFT. NBLANKS reduced to 0, perhaps + temporarily, to simplify font stuff. +11/30/84: Fixed opening escape sequences. +5/6/85: Corrected bug in placement of comma "," inside font load +5/18/85: Corrected longstanding bugs, which also existed in Topp: + xpos and ypos are initialized to 0 rather than to dxof, + dyof; and their are not reset on a NEWPAGE. + + +*/ + +%REPLACE false BY '0'B; +%REPLACE true BY '1'B; + +ln03topp: PROCEDURE OPTIONS(MAIN); + + DCL (strip,frontstrip) EXTERNAL ENTRY (CHAR (*)) + RETURNS (CHAR (*)), + cvis EXTERNAL ENTRY (FIXED) RETURNS (CHAR (*)); + DCL upcase EXTERNAL ENTRY (CHAR (*)) RETURNS (CHAR (*)); + DCL add_txf_to_lnf EXTERNAL ENTRY(FIXED,FIXED,CHAR(*),FILE) + RETURNS(FIXED); + +/* Debugging info */ + + DCL debug FILE; + DCL debugwid FIXED; + DCL debugflag BIT; + debugflag = false; + debugwid = 0; + +/* input file, output file, include file */ + + DCL (outf,inf,incfile) FILE; + DCL (infnam,outfnam) CHAR(150) VARYING; + DCL reading_from_incfile BIT; + reading_from_incfile = false; + + ON UNDEFINEDFILE (inf) BEGIN; + PUT SKIP LIST('No such file: ' || infnam); + GOTO terminal_eof; + END; + + ON UNDEFINEDFILE (outf) BEGIN; + PUT SKIP LIST('Couldn''t open: ' || outfnam); + GOTO terminal_eof; + END; + + ON ENDFILE (inf) BEGIN; + CLOSE FILE(inf); + GOTO end_of_input; + END; + +/* Define as constants. In general this source file should not +contain any ascii control characters; instead we use byte(). */ + + DCL (esc,tab) CHAR(1); + esc = byte(27); + tab = byte(9); + +/* Banner string */ + + PUT SKIP LIST ('LN03Topp 2'); + +/* Get input and output files from command line. */ + + %INCLUDE $stsdef; + DCL lib$get_foreign ENTRY (CHAR(*) VARYING, CHAR(*) VARYING, + FIXED(15),FIXED) OPTIONS(VARIABLE) RETURNS(FIXED); + DCL indir CHAR(150) VARYING; + DCL (jj,jnam,jext,dxof,dyof) FIXED; + +/* Unlike Topp, this driver conforms to the TeX requirement that drivers +imaging onto 8 1/2 x 11 inch paper place the (0,0) point of the DVI file +one inch horizontally and vertically offset from the upper left corner of +the paper. Hence we initialize the following offset variables, which may be +reset by command line options. */ + + dxof = 300; + dyof = 300; + +/* ilp = input line ptr, illen = input line length, incsave = place to save +rest of line when {INCLUDE} is encountered. */ + + %REPLACE inbufsize BY 2048; + DCL inline CHAR(inbufsize) VARYING; + DCL incsave CHAR(inbufsize) VARYING; + DCL tch CHAR(1); + DCL (illen,ilp,i,istart,istart2,zch) FIXED; + + sts$value = lib$get_foreign(inline,,,0); + + IF ^sts$success THEN DO; + PUT SKIP EDIT ('Usage: ln03topp ') (A); + GOTO terminal_eof; + END; + + inline = inline || ' '; + illen = length(inline); + ilp = 1; + CALL skipb; + IF ilp > illen THEN DO; + PUT SKIP EDIT ('Usage: ln03topp ') (A); + GOTO terminal_eof; + END; + istart = ilp; + CALL skipnb; + infnam = substr(inline,istart,ilp-istart); + OPEN FILE(inf) TITLE(infnam) + ENVIRONMENT(Default_file_name('FOO.LNG')); + + jnam = istart; + DO jj = ilp-1 TO istart BY -1; + IF substr(inline,jj,1) = ':' | + substr(inline,jj,1) = ']' | + substr(inline,jj,1) = '>' + THEN DO; + jnam = jj+1; + GOTO found_jnam; + END; + END; + +found_jnam: + +/* We need to remember the directory of the input filespec, so that we can +open {INCLUDE} files in the same directory. Thus, we stash that directory +in INDIR. */ + + indir = substr(inline,istart,jnam-istart); + jext = ilp; + DO jj = jnam TO ilp-1; + IF substr(inline,jj,1) = '.' | + substr(inline,jj,1) = ';' + THEN DO; + jext = jj; + GOTO found_jext; + END; + END; + +found_jext: + +/* The output file is placed in the current default directory; i.e., we get +rid of the directory part and just use the name part of the input filespec. +*/ + + outfnam = substr(inline,jnam,jext-jnam) || '.LN3'; + + OPEN FILE(outf) OUTPUT TITLE(outfnam) + ENVIRONMENT(Default_file_name('FOO.LN3')); + +/* Read any options from the command line. There are two possible options, +/H= and /V=, which serve to locate the (0,0) point of the DVI file on the +paper. */ + + CALL skipb; + DO WHILE (ilp <= illen-2); + IF substr(inline,ilp,3) = '/H=' THEN DO; + ilp = ilp+3; + jj = -1; + CALL getfixnum(jj); + dxof = jj; + END; ELSE IF substr(inline,ilp,3) = '/V=' THEN DO; + jj = -1; + ilp = ilp+3; + CALL getfixnum(jj); + dyof = jj; + END; ELSE CALL skipnb; + CALL skipb; + END; + +/* Globals: there are many of these + + font information */ + + %REPLACE maxnfonts BY 21; /* so I am told */ + %REPLACE maxtexfonts BY 100; + %REPLACE maxfontnos BY 9; + %REPLACE nblanks BY 0; + DCL (curf,fsize,totsize,chunkcnt) FIXED; + DCL curtxf PTR; + DCL lastch(0:maxnfonts) FIXED GLOBALDEF; + DCL chw(0:maxnfonts,0:255) FIXED GLOBALDEF; + DCL ftime(0:maxnfonts) FIXED; + + fsize = 0; + totsize = 0; + curf = 0; + curtxf = Null(); + chw = 0; + ftime = 0; + chunkcnt = 0; + +/* An LN03 "font" actually consists of two LN03 font loads, one to be +placed in character positions 33 to 126, the other in positions 161 to 254. +There are no raster size limitations on LN03 fonts, other than those +imposed by this program (those should eventually be removed). */ + + %REPLACE leftfirst BY 33; + %REPLACE rightfirst BY 161; + %REPLACE leftlast BY 126; + %REPLACE rightlast BY 254; + +/* TXF is a record structure describing a TeX font. TXFA is an array of TXF +records. TXF2LNF describes the mapping between TeX fonts and LN03 "fonts". +*/ + + DCL 1 txf BASED, + 2 nchs FIXED, + 2 chu(0:255) CHAR(1); + DCL txfa(0:maxtexfonts) PTR GLOBALDEF; + DCL txf2lnf(0:maxtexfonts) FIXED; + + txfa = Null(); + txf2lnf = -1; + +/* WHBLANKS identifies the locations of the fixed width blanks in the LN03 +fonts. FNAME is the font file ID of each LN03 font. For the moment, +however, we do not use WHBLANKS. */ + +/* DCL whblanks(0:maxnfonts,1:nblanks) FIXED GLOBALDEF; */ + DCL fname(0:maxnfonts) CHAR(31) GLOBALDEF; + +/* whblanks = -1;*/ + fname = 'U000000002SK00GG0001UZZZZ02F000'; + DO i = 0 TO MIN(maxnfonts,9); + substr(fname(i),7,1) = cvis(i); + END; + DO i = 10 TO maxnfonts; + substr(fname(i),6,2) = cvis(i); + END; + +/* The LN03 select-graphic-rendition numbers 0-9 have to be allocated among +the fonts. The USENO array keeps track of which number a font is allowed to +use, -1 if none is currently allocated. The WHOUSES array says which font +is using a number. */ + + DCL (useno(0:maxnfonts),whouses(0:maxfontnos)) FIXED; + + useno = -1; + whouses = -1; + +/* The landscape bit is for future reference; currently LN03Topp does not +support landscape printing */ + + DCL landscape BIT; + + landscape = false; + + DCL (maxrmar,maxbmar) FIXED; + maxrmar = 2550; + maxbmar = 3300; + +/* In the following, 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[3300t +means the "maximum length" of the paper is 3300 pixels. */ + + PUT EDIT (esc || 'c') (A) FILE(outf); + PUT EDIT (esc || '[?27h' || esc || '[11h' || esc || '[7 I' + || esc || '[?52h' || esc || '[3300t') + (A) FILE(outf); + +/* A count of pages is plotted out on the terminal to give users an +indication of progress. */ + + DCL pageno FIXED; + pageno = 1; + +/* Current x and y positions: always in pixels. */ + + DCL (xpos,ypos) FIXED; + xpos = dxof; + ypos = dyof; + +/* User definable command area: This is left over from the LNF program +whence Topp and then LN03Topp are derived. This stuff should be taken out. +*/ + + %REPLACE udcsize BY 4096; + DCL 1 udcr BASED, + 2 (udcname,udcnamelen,udcvalue,udcvaluelen) FIXED, + 2 next PTR; + DCL udclist PTR; + DCL udcarea CHAR(udcsize); + DCL udcarray(udcsize) CHAR(1) BASED (addr(udcarea)); + DCL udcaptr FIXED; + + udclist = Null(); + udcaptr = 1; + /* Predefine some commands */ + IF define_command('LB','{CHAR123}') THEN; + IF define_command('RB','{CHAR125}') THEN; + +/* Page storage: we save up a page before outputting it to minimize the +complexity of the page for the LN03. Since the capacity limitations of the +LN03, unlike those of the LN01, are nowhere defined, it is unclear whether +the transformations we perform are actually useful. */ + +/* The page is stored as a set of characters in the PBUF, plus a collection +of lists of "chunks". The lists are indexed by Y-position, using the array +CHLS. Each chunk is a sequence of characters that can be written without +backspacing or changing vertical position. */ + + %REPLACE pbufsize BY 65536; + DCL pbuf(0:pbufsize) CHAR(1); + DCL chls(0:3300) PTR; /* 3300 is maximum value of maxbmar */ + +/* The CHUNK record keeps track of a chunk, giving the X position at which +it starts and ends (XS, XE), the index of where its characters start and +end in PBUF (IS, IE), plus the TeX font in which it is set (FS). */ + + DCL 1 chunk BASED, + 2 (xs,xe,is,ie,fs) FIXED, + 2 next PTR; + +/* Chunk records are allocated from a free list. PBUFI keeps track of how +much of PBUF is being used. CHUNKMAX is a count of how many chunks are +allocated (not used for anything). */ + + DCL (free_chunk_list,curchunk) PTR; + DCL (pbufi,chunkmax) FIXED; + DCL top_of_page BIT; + + pbufi = 0; + chunkmax = 0; + free_chunk_list = Null(); + chls = Null(); + curchunk = Null(); + top_of_page = false; + +/* This is the main loop: */ + + DO WHILE (true); + CALL read_inline; + + illen = length(inline); + ilp = 1; + istart2 = 1; + + DO WHILE (ilp <= illen); + tch = substr(inline,ilp,1); + IF tch = '{' THEN DO; + IF istart2 < ilp THEN CALL ord_text(substr(inline, + istart2,ilp-istart2)); + CALL handle_command; + istart2 = ilp; + END; ELSE ilp = ilp+1; + END; + IF istart2 < ilp THEN CALL ord_text(substr(inline,istart2,ilp- + istart2)); + END; + +end_of_input: + ; + +abort_job: + PUT EDIT (esc || 'c') (A) FILE(outf); + CLOSE FILE(outf); + +terminal_eof: + RETURN; + +/* Decipher command from inline and then execute it */ + + handle_command: PROCEDURE; + DCL (j,k,fno) FIXED; + DCL (command,name) CHAR(16) VARYING; + + ON UNDEFINEDFILE (incfile) BEGIN; + PUT SKIP LIST('No such file:' || substr(inline,istart, + ilp-istart)); + GOTO windup_command; + END; + + istart = ilp+1; + ilp = istart; + DO WHILE ('A' <= substr(inline,ilp,1) & + substr(inline,ilp,1) <= 'Z'); + ilp = ilp+1; + END; + command = substr(inline,istart,ilp-istart); + IF command = 'HPA' | command = 'X' THEN DO; + k = -1; + CALL getfixnum(k); + k = k+dxof; + xpos = k; + END; ELSE IF command = 'VPA' THEN DO; + j = 0; + CALL getfixnum(j); + j = j+dyof; + CALL finish_chunk; + ypos = j; + END; ELSE IF command = 'NOFILL' THEN; + /* ignore, always in nofill mode */ + ELSE IF command = 'DEBUG' THEN debugflag = true; + ELSE IF command = 'WLN' THEN CALL process_wln; + ELSE IF command = 'NODEBUG' THEN debugflag = false; + ELSE IF command = '' THEN DO; + CALL findcb2; + ilp = ilp+1; + END; ELSE IF command = 'NEWPAGE' THEN DO; + CALL finish_chunk; + CALL finish_page; + xpos = dxof; + ypos = dyof; + END; ELSE IF command = 'FO' THEN DO; + CALL getfixnum(fno); + IF fno < 0 | fno > maxtexfonts THEN CALL error1 + ('Bad font number ' || cvis(fno) || ' in FO command.'); + IF txfa(fno) = Null() THEN CALL error1 + ('Font number ' || cvis(fno) || ' not present.'); + CALL finish_chunk; + curf = fno; + curtxf = txfa(fno); + END; ELSE IF command = 'INCLUDE' THEN DO; + IF reading_from_incfile THEN CALL + error1('{INCLUDE}s can''t be nested.'); + CALL skipb; + istart = ilp; + CALL skipnb2; + OPEN FILE (incfile) TITLE (substr(inline,istart,ilp-istart)) + ENVIRONMENT(Default_file_name(indir || 'FOO.LNG')); + reading_from_incfile = true; + CALL findcb; + ilp = ilp+1; + IF rest_of_inline_blank() THEN incsave = ''; + ELSE incsave = substr(inline,ilp,illen-ilp); + ilp = illen+1; + END; ELSE IF command = 'LMAR' | command = 'RMAR' | + command = 'TMAR' | command = 'BMAR' THEN; + ELSE IF command = 'RULEA' THEN DO; + DCL (x0,y0,x1,y1,temp) FIXED; + + CALL getfixnum(x0); + CALL getfixnum(y0); + CALL getfixnum(x1); + CALL getfixnum(y1); + x0 = min(x0+dxof,maxrmar); + x1 = min(x1+dxof,maxrmar); + x0 = max(x0,0); + x1 = max(x1,0); + y0 = min(y0+dyof,maxbmar); + y1 = min(y1+dyof,maxbmar); + y0 = max(y0,0); + y1 = max(y1,0); + IF x0 > x1 THEN DO; temp = x0; x0 = x1; x1 = temp; END; + IF y0 > y1 THEN DO; temp = y0; y0 = y1; y1 = temp; END; + + IF top_of_page THEN DO; + top_of_page = false; + PUT EDIT (byte(12)) (A) FILE(outf); + END; + +/* All rules are put at the beginning of the page, a separate line for each +one. A vertical positioning command is necessary because otherwise the LN03 +would keep on advancing the vertical position as more rules are set, in +response to the end of line carriage returns. */ + + IF y1 ^= y0 & x1 ^= x0 THEN DO; + IF landscape + THEN PUT SKIP EDIT (esc || '[100d' || + esc || '[0;' || cvis(y0) || ';' || + cvis(x0) || ';' || cvis(y1-y0) || ';' || + cvis(x1-x0) || '!|') (A) FILE(outf); + ELSE PUT SKIP EDIT (esc || '[100d' || + esc || '[1;' || cvis(x0) || ';' || + cvis(y0) || ';' || cvis(y1-y0) || ';' || + cvis(x1-x0) || '!|') (A) FILE(outf); + END; + + END; ELSE IF command = 'CHAR' THEN DO; + j = 0; + CALL getfixnum(j); + CALL ord_text(byte(j)); + END; ELSE IF command = 'CU' THEN DO; + CALL getfixnum(fno); + IF fno < 0 | fno > maxtexfonts THEN CALL error1 + ('Bad font number ' || cvis(fno) || ' in CU command.'); + CALL skipb; + IF txfa(fno) = Null() THEN + ALLOCATE txf SET (txfa(fno)); + txfa(fno) -> chu = byte(0); + j = 0; + k = 0; + DO WHILE (substr(inline,ilp,1) ^= '}' & substr(inline,ilp,1) + ^= ' '); + IF substr(inline,ilp,1) = '1' THEN DO; + txfa(fno) -> chu(j) = byte(1); + k = k+1; + END; + j = j+1; + ilp = ilp+1; + END; + txfa(fno) -> txf.nchs = k; + + END; ELSE IF command = 'DEF' THEN DO; + /* Definition of a user defined command : very delicate */ + + CALL skipb; + IF ilp > illen THEN CALL error1('DEF has no parameters.'); + IF substr(inline,ilp,1) ^= '{' THEN DO; + CALL findcb2; + CALL error1('DEF syntax is {DEF{command}value}.'); + END; + ilp = ilp+1; + istart = ilp; + DO WHILE ('A' <= substr(inline,ilp,1) & substr(inline,ilp,1) + <= 'Z'); + ilp = ilp+1; + END; + IF substr(inline,ilp,1) ^= '}' THEN DO; + CALL findcb; + ilp = ilp+1; + CALL findcb2; + CALL error1('DEF syntax is {DEF{command}value}.'); + END; + IF ilp = istart | ilp-istart > 16 THEN CALL error1 + ('DEF ignored, new command name blank or too long.'); + k = ilp; + ilp = ilp+1; + CALL findcb2; + IF ^define_command(substr(inline,istart,k-istart), + substr(inline,k+1,ilp-k-1)) + THEN CALL bad_error('User command area exhausted.'); + END; ELSE IF command ^= '' THEN DO; + DCL p PTR; + + DO p = udclist REPEAT p -> udcr.next WHILE (p ^= Null()); + IF command = substr(udcarea,p -> udcname,p -> udcnamelen) + THEN DO; + CALL findcb; + ilp = ilp+1; + IF p -> udcvaluelen + illen-ilp+1 > inbufsize THEN + CALL error1 ('Input buffer size exceeded, ' || + 'user command ' || command || ' ignored.'); + /* Put Udc in stream to be executed */ + inline = substr(udcarea,p -> udcvalue, + p -> udcvaluelen) || substr(inline,ilp, + illen-ilp+1); + illen = length(inline); + ilp = 1; + RETURN; + END; + END; + CALL error1 ('No such command: ' || command); + END; + + windup_command: + CALL findcb; + ilp = ilp+1; + RETURN; + + findcb2: PROCEDURE; + DCL cbc FIXED; + + cbc = 0; + DO WHILE (ilp <= illen); + IF substr(inline,ilp,1) = '{' THEN cbc = cbc+1; + ELSE IF substr(inline,ilp,1) = '}' THEN cbc = cbc-1; + IF cbc < 0 THEN RETURN; + ilp = ilp+1; + END; + + END findcb2; + + error1: PROCEDURE(str); + DCL str CHAR(*); + + PUT SKIP EDIT (str) (A); + GOTO windup_command; + + END error1; + + bad_error: PROCEDURE(str); + DCL str CHAR(*); + + PUT SKIP EDIT (str) (A); + GOTO abort_job; + + END bad_error; + + END handle_command; + + + finish_chunk: PROCEDURE; + + curchunk = Null(); + + END finish_chunk; + +/* skip over blanks in inline */ + + skipb: PROCEDURE; + + DO WHILE (ilp <= illen); + IF substr(inline,ilp,1) ^= ' ' THEN RETURN; + ilp = ilp+1; + END; + + END skipb; + +/* skip over characters other than ' ' and '}'. */ + + skipnb2: PROCEDURE; + + DO WHILE (ilp <= illen); + IF substr(inline,ilp,1) = ' ' + | substr(inline,ilp,1) = '}' THEN RETURN; + ilp = ilp+1; + END; + + END skipnb2; + + skipnb: PROCEDURE; + + DO WHILE (ilp <= illen); + IF substr(inline,ilp,1) = ' ' THEN RETURN; + ilp = ilp+1; + END; + + END skipnb; + +/* Read a fixnum from inline and put it in x. If can't find one then x is +left unchanged. */ + + getfixnum: PROCEDURE (x); + DCL (x,x1) FIXED; + DCL negative BIT; + + negative = false; + IF ilp > illen THEN RETURN; + CALL skipb; + IF substr(inline,ilp,1) = '-' THEN DO; + negative = true; + ilp = ilp+1; + END; + + IF ilp > illen | substr(inline,ilp,1) < '0' + | substr(inline,ilp,1) > '9' + THEN RETURN; + + x1 = 0; + DO WHILE(substr(inline,ilp,1) >= '0' & + substr(inline,ilp,1) <= '9'); /* cheat */ + x1 = 10*x1 + RANK(substr(inline,ilp,1)) - RANK('0'); + ilp = ilp+1; + IF ilp > illen THEN GOTO gotnum; + END; + + gotnum: + x = x1; + IF negative THEN x = -x; + RETURN; + + END getfixnum; + +/* find close bracket } */ + + findcb: PROCEDURE; + + IF ilp >= illen THEN RETURN; + DO WHILE (ilp < illen & substr(inline,ilp,1) ^= '}'); + ilp = ilp+1; + END; + + END findcb; + +/* determine if rest of inline is blank */ + + rest_of_inline_blank: PROCEDURE RETURNS (BIT); + DCL j FIXED; + + IF ilp > illen THEN RETURN (true); + j = ilp; + DO WHILE (j <= illen); + IF (substr(inline,j,1) ^= ' ' + & substr(inline,j,1) ^= tab) THEN RETURN(false); + j = j+1; + END; + RETURN(true); + + END rest_of_inline_blank; + +/* The following procedure is still called 'process_wln', even though the +file extensions now default to '.nft' rather than '.tln'. Magnified font +extensions still have to be numeric... */ + + process_wln: PROCEDURE; + DCL (j,k,l,fno,maxfno,chsize) FIXED; + DCL font_selected BIT; + DCL (txfns(0:maxtexfonts),txfne(0:maxtexfonts)) FIXED; + +/* Destroy all traces of preceding fonts */ + + totsize = 0; + chsize = 0; +/* whblanks = -1;*/ + useno = -1; + whouses = -1; + txfns = -1; + txfne = -1; + maxfno = 0; + PUT SKIP EDIT(esc || 'P0;1;1y') (A) FILE(outf); + +/* Read the font names and numbers from inline. Because LN03 fontnames can +be very long, this will probably have to be changed to read from more than +one line. For 100 fonts, 2048 characters in the line is not enough. */ + + CALL skipb; + + DO WHILE (substr(inline,ilp,1) ^= '}' & ilp < illen); + istart = ilp; + CALL skipnb2; + j = ilp; + fno = 0; + CALL getfixnum(fno); + IF fno < 0 | fno > maxtexfonts THEN DO; + PUT SKIP EDIT ('Bad font no.: ' || cvis(fno)) (A); + GOTO abort_job; + END; + txfns(fno) = istart; + txfne(fno) = j; + IF fno > maxfno THEN maxfno = fno; + IF txfa(fno) = Null() THEN DO; + ALLOCATE txf SET(txfa(fno)); + DO k = 0 TO 127; + txfa(fno) -> chu(k) = byte(1); + END; + DO k = 128 TO 255; + txfa(fno) -> chu(k) = byte(0); + END; + +/* The default assumption, if the input contains no CU command for a given +font, is that only characters 0-127 are used. For efficiency's sake this is +not actually checked as the characters are read in and translated. */ + + txfa(fno) -> nchs = 128; + END; + IF txfa(fno) -> nchs > 182 THEN GOTO need_empty_slots; + chsize = chsize + txfa(fno) -> nchs; + CALL skipb; + END; + +/* Now we have to allocate TeX fonts (TXFs) to LN03 fonts (LNFs) and +perform the actual load. The goal is to use as few slots as possible, where +an LNF with <= 94 characters is one slot, and an LNF with > 94 but <= 188 +characters is two slots. + +As in the LN01 case, the allocation problem seems to be some sort of hard +bin packing problem. (Proof of NP-hardness, anyone?) So we use a best fit +heuristic: + +1. Find the unassigned largest TXF. If none, exit. + +2. Allocate an LNF for it. + +3. Find the largest TXF that fits in what is left of that LNF. + + 3.1. If none exists, go to 1. + 3.2. If one exists, put it in the LNF and go back to 3. + +The TXFORD array will contain the TXF numbers in the order that they are +assigned. TXFCNT keeps track of how many TXFs have been assigned so far. */ + + DCL (lnfcnt,txfcnt,the_txf,txf_size,lnfleft) FIXED; + DCL txford(0:maxtexfonts) FIXED; + + lnfcnt = 0; + txfcnt = 0; + txford = -1; + + + + DO WHILE (true); + +/* Find largest unassigned TXF */ + + lnfleft = rightlast-rightfirst+1+leftlast-leftfirst+1-nblanks; + txf_size = -1; + DO j = 0 TO maxtexfonts; + IF txfa(j) ^= Null() & txf2lnf(j) = -1 + & txfa(j) -> nchs > txf_size THEN DO; + txf_size = txfa(j) -> nchs; + the_txf = j; + END; + END; + IF txf_size <= 0 THEN GOTO assignment_done; + IF lnfcnt > maxnfonts THEN GOTO too_complex; + IF txf_size > lnfleft THEN GOTO need_empty_slots; + +/* Now allocate new LNF and put TXF in it */ + + txf2lnf(the_txf) = lnfcnt; + txford(txfcnt) = the_txf; + txfcnt = txfcnt+1; + k = leftfirst-1; + DO j = 0 TO 255; + IF txfa(the_txf) -> chu(j) ^= byte(0) THEN DO; + k = k+1; + IF k = leftlast+1 THEN k = rightfirst; + lnfleft = lnfleft-1; + txfa(the_txf) -> chu(j) = byte(k); + END; + END; + lastch(lnfcnt) = k; + +/* Now try to fill the remaining part of the LNF using other TeX fonts */ + + DO WHILE (true); + + txf_size = -1; + DO j = 0 TO maxtexfonts; + IF txfa(j) ^= Null() & txf2lnf(j) = -1 + & txfa(j) -> nchs > txf_size + & txfa(j) -> nchs <= lnfleft THEN DO; + txf_size = txfa(j) -> nchs; + the_txf = j; + END; + END; + IF txf_size <= 0 THEN GOTO current_lnf_exhausted; + + txf2lnf(the_txf) = lnfcnt; + txford(txfcnt) = the_txf; + txfcnt = txfcnt+1; + k = lastch(lnfcnt); + DO j = 0 TO 255; + IF txfa(the_txf) -> chu(j) ^= byte(0) THEN DO; + k = k+1; + lnfleft = lnfleft-1; + IF k = leftlast+1 THEN k = rightfirst; + txfa(the_txf) -> chu(j) = byte(k); + END; + END; + lastch(lnfcnt) = k; + END; + + current_lnf_exhausted: + lnfcnt = lnfcnt+1; + END; + +assignment_done: + +/* At this point the array TXF2LNF is properly initialized, as are LASTCH +and TXFORD. It remains to actually generate the desired font load. This has +to be done carefully, since characters may only be added to an LNF in +ascending order. */ + + DO j = 0 TO txfcnt-1; + k = txford(j); + IF j ^= 0 & txf2lnf(k) ^= txf2lnf(txford(j-1)) THEN PUT SKIP + EDIT (',') (A) FILE(outf); + totsize = totsize+add_txf_to_lnf(txf2lnf(k),k, + substr(inline,txfns(k), + txfne(k)-txfns(k)),outf); + END; + +/* At this point we need to write a message saying how long the font load +is overall. That comes from TOTSIZE plus an overhead factor that depends on +how many LNFs there are and whether any of them don't use the right half of +the code chart. */ + + PUT SKIP EDIT (';LN03Topp 2 font load' || esc || '\') (A) FILE(outf); + IF landscape THEN DO; + maxrmar = 3300; + maxbmar = 2550; +/* PUT EDIT(esc || 'c') (A) FILE(outf);*/ + PUT EDIT (esc || '[1;3300s' || esc || '[2550t' || + esc || '[1;2550r') + (A) FILE(outf); + END; ELSE DO; + maxbmar = 3300; + maxrmar = 2550; +/* PUT EDIT(esc || 'c') (A) FILE(outf);*/ + PUT EDIT(esc || '[1;2550s' || esc || '[3300t' || + esc || '[1;3300r') + (A) FILE(outf); + END; + font_selected = false; + DO j = 0 TO MIN(maxfontnos,lnfcnt-1); + useno(j) = j; + whouses(j) = j; + PUT EDIT + (esc || 'P1;1' || cvis(j) || '}' || + substr(fname(j),1,16) || esc || '\') (A) + FILE(outf); + IF ^font_selected THEN DO; + PUT EDIT (esc || '[1' || cvis(j) || 'm') (A) + FILE(outf); + font_selected = true; + END; + END; + + RETURN; + + too_complex: + PUT SKIP EDIT ('Can''t construct usable font load: input ' || + 'too complex') (A); + GOTO abort_job; + + need_empty_slots: + PUT SKIP EDIT ('Font ' || cvis(fno) || ' uses >182 characters.' + || ' LN03Topp can''t handle that.') (A); + GOTO abort_job; + + rasters_too_large: + PUT SKIP EDIT ('The required rasters from font ' || cvis(fno) || + ' are too large for this preliminary LN03Topp to handle.') (A); + GOTO abort_job; + + END process_wln; + + /* insert ordinary text into page */ + ord_text: PROCEDURE (c); + DCL c CHAR(*); + DCL (c1,c2) CHAR(1); + DCL (t,j,zch) FIXED; + + t = length(c); + IF t = 0 THEN RETURN; + IF xpos < 0 | xpos > maxrmar | ypos < 0 | ypos > 3300 THEN DO; + PUT SKIP EDIT ('"') (A); + DO j = 1 TO t; + IF substr(c,j,1) >= ' ' THEN PUT EDIT + (substr(c,j,1)) (A); + ELSE PUT EDIT ('.') (A); + END; + PUT EDIT ('" set off paper ') (A); + IF xpos < 0 | xpos > maxrmar THEN PUT EDIT ('(X = ' || cvis(xpos) + || ') ') (A); + IF ypos < 0 | ypos > 3300 THEN PUT EDIT ('(Y = ' || cvis(ypos) + || ') ') (A); + IF xpos < 0 THEN xpos = 0; ELSE xpos = maxrmar; + IF ypos < 0 THEN ypos = 0; ELSE ypos = 3300; + END; + IF curchunk = Null() THEN DO; + CALL new_chunk; + curchunk -> chunk.xs = xpos; + curchunk -> chunk.xe = xpos; + curchunk -> chunk.is = pbufi; + END; + IF xpos < curchunk -> chunk.xe THEN DO; + CALL finish_chunk; + CALL new_chunk; + curchunk -> chunk.xs = xpos; + curchunk -> chunk.is = pbufi; + END; ELSE IF xpos > curchunk -> chunk.xe + THEN CALL move_forward(xpos-curchunk -> chunk.xe); + IF pbufi+t >= pbufsize THEN DO; + PUT SKIP EDIT('Topp capacity exceeded: ' || + 'too much stuff on one page.') (A); + GOTO abort_job; + END; + DO j = 1 TO t; + c2 = substr(c,j,1); + zch = rank(c2); + c1 = curtxf -> chu(zch); + zch = rank(c1); + pbuf(pbufi+j-1) = c1; + xpos = xpos+chw(txf2lnf(curf),zch); + END; + pbufi = pbufi+t; + curchunk -> chunk.xe = xpos; + curchunk -> chunk.ie = pbufi; + + END ord_text; + + finish_page: PROCEDURE; + %REPLACE maxprch BY 175; + %REPLACE maxtotch BY 200; + DCL (i,j,xmax,xleft,nprch,ntotch) FIXED; + DCL (pt,pt2,pt3,pt4,obufp,lis) PTR; + DCL obuf CHAR(400) BASED (obufp); + DCL found BIT; + + PUT EDIT ('[' || cvis(pageno) || '] ') (A); + IF top_of_page THEN DO; + top_of_page = false; + PUT EDIT(byte(12)) (A) FILE(outf); + END; + + /* Now we have to write out all the chunks */ + /* For now we will write them in a simple fashion */ + DO i = 0 TO 3300; + IF chls(i) ^= Null() THEN DO; + /* MXO stuff has been omitted here */ + lis = Null(); + DO WHILE (chls(i) ^= Null()); + xleft = 1000000000; /* a very high value */ + /* Make LIS be a list of nonoverlapping chunks */ + DO WHILE (true); + pt2 = Null(); + pt3 = Null(); + xmax = -1; + DO pt = chls(i) REPEAT pt -> chunk.next + WHILE (pt ^= Null()); + IF pt -> chunk.xe > xmax + & pt -> chunk.xe <= xleft THEN DO; + xmax = pt -> chunk.xe; + pt3 = pt; + pt4 = pt2; + END; + pt2 = pt; + END; + IF pt3 = Null() THEN GOTO print_lis; + IF pt4 = Null() THEN chls(i) = chls(i) -> chunk.next; + ELSE pt4 -> chunk.next = pt4 -> chunk.next + -> chunk.next; + pt3 -> chunk.next = lis; + lis = pt3; + xleft = pt3 -> chunk.xs; + END; + print_lis: + IF lis = Null() THEN GOTO next_i; + DO WHILE (lis ^= Null()); + /* Print as many chunks from LIS as will fit + on one line; split last chunk if necessary */ + nprch = 0; + ntotch = 0; + PUT SKIP FILE(outf); + CALL escape_seq_outf(esc || '[' || cvis(i) || 'd'); + pt = lis; + pt2 = Null(); + DO WHILE (pt ^= Null()); + pt3 = pt; + CALL print_pt; + IF pt ^= Null() THEN GOTO finished_lis; + pt = pt3 -> chunk.next; + pt2 = pt3; + END; + finished_lis: + IF pt2 ^= Null() THEN DO; + pt2 -> chunk.next = free_chunk_list; + free_chunk_list = lis; + lis = pt; + END; + END; + END; + END; + next_i: + END; + pbufi = 0; + PUT EDIT (byte(10)) (A) FILE(outf); + top_of_page = true; + pageno = pageno+1; + + move_forward_outf: PROCEDURE (dist,font); + DCL (dist,font) FIXED; + DCL sdist CHAR(12) VARYING; + + sdist = cvis(dist); + CALL escape_seq_outf(esc || '[' || sdist || 'a'); + ntotch = ntotch+3+length(sdist); + + END move_forward_outf; + + escape_seq_outf: PROCEDURE (c); + DCL c CHAR(*); + DCL t FIXED; + + t = length(c); + ntotch = ntotch+t; + PUT EDIT (c) (A) FILE(outf); + + END escape_seq_outf; + + print_pt: PROCEDURE; + + DCL (chunklen,escix,uselen,base,i,j,k,font) FIXED; + + /* This procedure prints as much of pt as there + is room left on the line for and deletes that + piece of pt */ + + base = pt -> chunk.is; + chunklen = pt -> chunk.ie - pt -> chunk.is; + uselen = min(chunklen,maxtotch-ntotch); + uselen = min(uselen,maxprch-nprch); + + IF uselen < 1 THEN RETURN; /* shouldn't be, but... */ + + +/* We must ensure that PT is not split in the middle of an escape +sequence */ + + IF uselen ^= chunklen THEN DO; + escix = -1; + DO i = 0 TO uselen-1; + IF pbuf(pt -> chunk.is+i) = esc THEN + escix = i; + END; + IF escix ^= -1 & uselen-escix <= 8 THEN DO; + DO i = escix TO uselen-1; + IF pbuf(pt -> chunk.is+i) = 'a' THEN + GOTO no_problem; + END; + uselen = escix; + END; + END; + no_problem: + + font = txf2lnf(pt -> chunk.fs); + IF useno(font) = -1 THEN DO; + useno(whouses(maxfontnos)) = -1; + useno(font) = maxfontnos; + whouses(maxfontnos) = font; + CALL escape_seq_outf(esc || + 'P1;1' || cvis(maxfontnos) || '}' || + substr(fname(font),1,16) || esc || '\'); + END; + + CALL escape_seq_outf(esc || '[1' || + cvis(useno(font)) || 'm'); + IF pt = lis THEN CALL escape_seq_outf(esc || '[' + || cvis(pt -> chunk.xs) || '`'); + ELSE DO; + j = pt -> chunk.xs - pt2 -> chunk.xe; + IF j ^= 0 THEN CALL move_forward_outf(j, + font); + END; + obufp = addr(pbuf(pt -> chunk.is)); + PUT EDIT (substr(obuf,1,uselen)) (A) FILE(outf); + nprch = nprch+uselen; + ntotch = ntotch+uselen; + IF uselen = chunklen THEN pt = Null(); + ELSE DO; + k = base; + DO WHILE (k <= base+uselen-1); + IF pbuf(k) ^= esc THEN pt -> chunk.xs = pt -> + chunk.xs+chw(font,rank(pbuf(k))); + ELSE DO; + i = 0; + k = k+2; + DO WHILE (pbuf(k) ^= 'a'); + i = i*10 + rank(pbuf(k))-rank('0'); + k = k+1; + IF k > base+uselen-1 THEN PUT SKIP + EDIT ('Topp internal error.') (A); + END; + pt -> chunk.xs = pt -> chunk.xs+i; + END; + k = k+1; + END; + pt -> chunk.is = pt -> chunk.is+uselen; + END; + + END print_pt; + + END finish_page; + + define_command: PROCEDURE(name,value) RETURNS(BIT); + DCL (name,value) CHAR(*); + DCL p PTR; + DCL (nl,vl) FIXED; + + nl = length(name); + vl = length(value); + IF udcaptr+nl+vl > udcsize THEN RETURN(false); + DO p = udclist REPEAT p -> udcr.next WHILE (p ^= Null()); + IF name = substr(udcarea,p -> udcname,p -> udcnamelen) + THEN GOTO found; + END; + ALLOCATE udcr SET (p); + p -> udcr.next = udclist; + udclist = p; + p -> udcname = udcaptr; + udcaptr = udcaptr+nl; + p -> udcnamelen = nl; + substr(udcarea,p -> udcname,p -> udcnamelen) = name; + p -> udcvaluelen = 0; + p -> udcvalue = udcaptr; + found: + IF vl = 0 THEN RETURN(true); + /* IF possible fit command in existing area */ + IF vl >= p -> udcvaluelen + THEN DO; + p -> udcvalue = udcaptr; + udcaptr = udcaptr+vl; + END; + p -> udcvaluelen = vl; + substr(udcarea,p -> udcvalue,p -> udcvaluelen) = value; + RETURN(true); + + END define_command; + + read_inline: PROCEDURE; + + ON ENDFILE (incfile) BEGIN; + CLOSE FILE (incfile); + reading_from_incfile = false; + IF incsave = '' THEN GOTO once_again; + ELSE DO; + inline = incsave; + GOTO return_label; + END; + END; + + once_again: + IF reading_from_incfile THEN GET EDIT (inline) (A(511)) + FILE(incfile); + ELSE GET EDIT (inline) (A(511)) FILE(inf); + + return_label: + RETURN; + + END read_inline; + + move_forward: PROCEDURE (dist); + DCL (dist,i) FIXED; + DCL sdist CHAR(12) VARYING; + + sdist = esc || '[' || cvis(dist) || 'a'; + + IF pbufi+length(sdist) >= pbufsize THEN DO; + PUT SKIP EDIT('LN03Topp capacity exceeded: ' || + 'too much stuff on one page.') (A); + GOTO abort_job; + END; + DO i = 1 TO length(sdist); + pbuf(pbufi+i-1) = substr(sdist,i,1); + END; + pbufi = pbufi+length(sdist); + + END move_forward; + + new_chunk: PROCEDURE; + + IF free_chunk_list = Null() THEN DO; + ALLOCATE chunk SET (curchunk); + chunkmax = chunkmax+1; + END; ELSE DO; + curchunk = free_chunk_list; + free_chunk_list = free_chunk_list -> chunk.next; + END; + curchunk -> chunk.fs = curf; + curchunk -> chunk.next = chls(ypos); + chls(ypos) = curchunk; + chunkcnt = chunkcnt+1; + ftime(txf2lnf(curf)) = chunkcnt; + + END new_chunk; + +END ln03topp; diff --git a/dviware/ln03/rose/lnfinc.pli b/dviware/ln03/rose/lnfinc.pli new file mode 100644 index 0000000000..c8cafe8ff6 --- /dev/null +++ b/dviware/ln03/rose/lnfinc.pli @@ -0,0 +1,35 @@ +cvis: PROCEDURE (i) RETURNS (CHAR (*)); + DCL i FIXED; + + RETURN (frontstrip(CHAR (i))); +END cvis; + +strip: PROCEDURE (t) RETURNS (CHAR (*)); + DCL i FIXED, + t CHAR (*); + + DO i = Length (t) TO 1 BY -1; + IF substr (t,i,1) ^= ' ' + THEN RETURN (substr (t,1,i)); + END; + RETURN (''); +END strip; + +frontstrip: PROCEDURE (t) RETURNS (CHAR (*)); + DCL i FIXED, + t CHAR (*); + + DO i = 1 TO Length (t); + IF substr (t,i,1) ^= ' ' + THEN RETURN (substr (t,i)); + END; + RETURN (''); +END frontstrip; + +upcase: PROCEDURE (text) RETURNS (CHAR (*)); + DCL text CHAR (*); + + RETURN (translate (text, + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', + 'abcdefghijklmnopqrstuvwxyz')); +END upcase; diff --git a/dviware/ln03/rose/newffc.c b/dviware/ln03/rose/newffc.c new file mode 100644 index 0000000000..3e748ebec3 --- /dev/null +++ b/dviware/ln03/rose/newffc.c @@ -0,0 +1,1293 @@ +/* This program is the second version of FFC, a font file converter. It +performs certain auxiliary file management functions related to the DVI to +LN03 translator. + +Copyright (c) 1984, 1985, 1986 by Digital Equipment Corporation, Maynard, +Massachusetts. Author: Flavio Rose, ...!decwrl!dec-rhea!dec-dvinci!rose. + +This program is being developed. It is quite incomplete. + +3/7/86 Add hack in handle_rpxl to read rms files. + Version 5. + +3/14/86 Additional fixes: tnftl, snftl, tnftr, rnft. Version 6. + +3/19/86 ppxlr, pnftr. Version 7. + +4/1/86 Fixed bug in snftl -- was writing the bytes + in reverse into the nft buffer. Version 8. + +*/ + +#ifdef vms +#include stdio +#include ctype +#include fab +#include rmsdef +#else +#include +#include +#endif + +/* In VMS we declare external variables to be globalref. +This is not really necessary, just an old habit. */ + +#ifdef vms +#define GLOBAL globaldef +#define EXTERN globalref +#else +#define GLOBAL +#define EXTERN extern +#endif + +/* User typein is read into an array called inline. The pointers istart and +ilp are used to keep track of a position in inline. */ + +GLOBAL char inline[513]; +GLOBAL int ilp,istart; +GLOBAL char *help_string = +"\n Available commands:\ +\n exit\ +\n rpxl tpxlr tpxll spxll wstr ppxlr\ +\n rnft tnftr tnftl snftl wnft pnftr\ +\n initnft cptonft"; + +#define skipb for(; inline[ilp]==' '; ilp++); +#define skipnb for(; inline[ilp]!='\0' && inline[ilp]!=' '; ilp++); + +/* The main program of FFC is an interactive loop that receives commands +from the user's terminal and writes replies. */ + +main() { + + printf("\n Font File Converter 8\n"); + + for(;;) { + printf("\nFFC> "); + gets(inline); + if (feof(stdin)) goto exit_label; + + ilp = 0; skipb; istart = ilp; + for (; inline[ilp]!='\0' && inline[ilp]!=' '; ilp++) +#ifdef vms + inline[ilp] = tolower(inline[ilp]); +#else + ; +#endif + + if (strncmp(&inline[istart],"rpxl",4) == 0) handle_rpxl(); + else if (strncmp(&inline[istart],"rnft",4) == 0) handle_rnft(); + else if (strncmp(&inline[istart],"tpxlr",5) == 0) + handle_tpxlr(0); + else if (strncmp(&inline[istart],"ppxlr",5) == 0) + handle_tpxlr(1); + else if (strncmp(&inline[istart],"tnftr",5) == 0) + handle_tnftr(0); + else if (strncmp(&inline[istart],"pnftr",5) == 0) + handle_tnftr(1); + else if (strncmp(&inline[istart],"tpxll",5) == 0) + handle_tpxll(); + else if (strncmp(&inline[istart],"tnftl",5) == 0) + handle_tnftl(); + else if (strncmp(&inline[istart],"spxll",5) == 0) + handle_spxll(); + else if (strncmp(&inline[istart],"snftl",5) == 0) + handle_snftl(); + else if (strncmp(&inline[istart],"initnft",7) == 0) + handle_initnft(); + else if (strncmp(&inline[istart],"cptonft",7) == 0) + handle_cptonft(); + else if (strncmp(&inline[istart],"wnft",4) == 0) + handle_wnft(); + else if (strncmp(&inline[istart],"wstr",4) == 0) + handle_wstr(); + else if (strncmp(&inline[istart],"exit",4) == 0) + goto exit_label; + else if (inline[istart] == '?') printf(help_string); + else { + inline[ilp] = '\0'; + printf("\nNo such command: '%s'",&inline[istart]); + } + + } + +exit_label: + ; +} + +/* In VMS file specifications have a maximum length, which is convenient in +sizing character arrays that are to hold them. Thus, the following +definition. [[In Unix, there is no such convenience, so the scheme needs to +be changed. Sigh.]] */ + +#define FILESPECLEN 252 + +/* PXL and LN03 format (NFT) files are simply read into memory and edited +there. [[This is probably not reasonable on a personal computer, because of +the 8088 segment size limit and the overall 640k memory cap.]] */ + +#define PXLBUFSIZE 512*256 +#define NFTBUFSIZE 512*256 + +GLOBAL unsigned char pxlbuf[PXLBUFSIZE]; +GLOBAL unsigned char nftbuf[NFTBUFSIZE]; +GLOBAL long pxllen, nftlen; + +/* The value conv is computed to be the correct conversion factor from the +widths in the PXL file, which are expressed in units of 2^-20 times the +design size, to pixels. */ + +GLOBAL float conv; + +/* As usual when dealing with TeX files, we have to rearrange bytes in +an overlay to combine them into longwords. The reason for this is that +bytes in TeX files are combined into longwords the opposite way from how +the VAX combines them. + +Hence, the following overlay and macro: [[It ought to work on 8088s too, +but not on 68000s.]] */ + +GLOBAL union lc { unsigned long int ul; + long int l; + unsigned char c[4]; } lcx; + +#define copy_from_pxl(_x) { lcx.c[3] = pxlbuf[_x]; \ + lcx.c[2] = pxlbuf[(_x)+1]; lcx.c[1] = pxlbuf[(_x)+2]; \ + lcx.c[0] = pxlbuf[(_x)+3]; } + +/* Handle_rpxl handles an rpxl command, which orders FFC to read a PXL file +into the pxlbuf. + +To speed up the operation of this program, the reading is done with Unix +I/O. In VMS only, we open the file twice, once to find out its record +attributes, and again to actually read it. The record attributes are +relevant because in some cases we have to explicitly discard carriage +returns depending on them. + +[[The VAX C RTL fstat function should allow us to avoid this double open, +but doesn't seem to work properly.]] */ + +int handle_rpxl() { + + long i,j; + int pxlf; + float two_to_the_20th; +#ifdef vms + char discard; +#endif + + skipb; istart = ilp; skipnb; + inline[ilp] = '\0'; +#ifdef vms + discard = VMS_file_check(&inline[istart],".pxl"); +#endif + pxlf = open_input_file(&inline[istart],".pxl"); + if (pxlf == -1) { + printf("\nUnable to open file %s",&inline[istart]); + return(1); + } + pxllen = 0; + while (1) { + j = PXLBUFSIZE-pxllen; + if (j > 65535) j = 65535; + i = read(pxlf,&pxlbuf[pxllen],j); + if (i < 0) { + printf("\nError while reading PXL file."); + close(pxlf); + return(1); + } + if (i == 0) break; + pxllen += i; +#ifdef vms + if (discard != 0) pxllen--; +#endif + } + if (i != 0) { + printf("\nPXL file too large for FFC's buffer (%d bytes long)", + PXLBUFSIZE-1); + close(pxlf); + return(1); + } + close(pxlf); + +/* Now that we have read the PXL file, check that it is in correct format +by looking for a trailing ID byte of 1001. */ + + if (locate_pxldir() != 0) return(1); + +/* If the format is correct, derive the design size and magnification from +the final longwords of the PXL file and print them. */ + + copy_from_pxl(pxllen-12); + conv = lcx.ul; + two_to_the_20th = 0x100000; + printf("\nDesign size %.2f points",conv/two_to_the_20th); + copy_from_pxl(pxllen-16); + conv = (conv/two_to_the_20th)*(lcx.ul/5.0)*(1.0/(72.27*two_to_the_20th)); + printf("\nPixels per em = %.1f",conv*two_to_the_20th); + printf("\nMagnification = %.3f (at 300 dpi)",lcx.ul/1500.0); + +} + +#define copy_to_nft(_x) { nftbuf[_x] = lcx.c[0]; \ + nftbuf[(_x)+1] = lcx.c[1]; nftbuf[(_x)+2] = lcx.c[2]; \ + nftbuf[(_x)+3] = lcx.c[3]; } +#define copy_from_nft(_x) { lcx.c[0] = nftbuf[_x]; \ + lcx.c[1] = nftbuf[(_x)+1]; lcx.c[2] = nftbuf[(_x)+2]; \ + lcx.c[3] = nftbuf[(_x)+3]; } + +GLOBAL int nft_first,nft_last,nft_next_code; + +int handle_rnft() { + + long i,j; + int nftf; + float two_to_the_20th; +#ifdef vms + char discard; +#endif + + skipb; istart = ilp; skipnb; + inline[ilp] = '\0'; +#ifdef vms + discard = VMS_file_check(&inline[istart],".nft"); +#endif + nftf = open_input_file(&inline[istart],".nft"); + if (nftf == -1) { + printf("\nUnable to open file %s",&inline[istart]); + return(1); + } + nftlen = 0; + while (1) { + j = NFTBUFSIZE-nftlen; + if (j > 65535) j = 65535; + i = read(nftf,&nftbuf[nftlen],j); + if (i < 0) { + printf("\nError while reading NFT file."); + close(nftf); + return(1); + } + if (i == 0) break; + nftlen += i; +#ifdef vms + if (discard != 0) nftlen--; +#endif + } + if (i != 0) { + printf("\nNFT file too large for FFC's buffer (%d bytes long)", + NFTBUFSIZE-1); + close(nftf); + return(1); + } + close(nftf); + printf("\n %d bytes read",nftlen); + +#define fnt__l_first_character 164 + + copy_from_nft(fnt__l_first_character); + nft_first = lcx.ul; + copy_from_nft(fnt__l_first_character+4); + nft_last = lcx.ul; + printf("\n First character %d, last character %d",nft_first,nft_last); + return(0); + +} + +int open_input_file (s,ext) +char s[], ext[]; +{ + char fs[FILESPECLEN]; + int jnam,jext; + + strcpy(fs,s); + find_filename(fs,&jnam,&jext); + if (fs[jext] == '\0') strcat(fs,ext); + return(open(fs,0,0)); + +} + +#ifdef vms +int VMS_file_check (s,ext) +char s[], ext[]; +{ + char fs[FILESPECLEN]; + int jnam,jext,rv,i; + struct FAB the_fab; + + strcpy(fs,s); + find_filename(fs,&jnam,&jext); + if (fs[jext] == '\0') strcat(fs,ext); + the_fab = cc$rms_fab; + (the_fab).fab$l_fna = fs; + (the_fab).fab$b_fns = strlen(fs); + (the_fab).fab$b_fac = FAB$M_BIO; + i = sys$open(&(the_fab)); + if (i % 2 == 0) return(0); + rv = 0; + if (the_fab.fab$b_rat == FAB$M_CR && the_fab.fab$b_rfm == FAB$C_VAR) + rv = 1; + sys$close(the_fab); + return(rv); + +} +#endif + +/* Find_filename finds the filename part of a VMS 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 has now been fixed to handle Ultrix +as well.]] */ + +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; +} + +/* PXL files have a "directory" at the end. Locate_pxldir searches for the +PXL id 1001, starting at the end of the PXL file. The directory is 517 +longwords back of there. If locate_pxldir can't find the PXL id, it outputs +an error message. */ + +GLOBAL long pxldir; + +int locate_pxldir () { + + long i; + + pxldir = 0; + if (pxllen < 517*4) { + printf("\nPXL file too short, must be at least 517 longwords."); + return(1); + } + if (pxllen%4 != 0) { + printf("\nPXL file length should be multiple of 4."); + pxllen -= pxllen%4; + } + + for (i=pxllen-4; i>0; i-=4) { + copy_from_pxl(i); + if (lcx.ul == 1001) { + pxllen = i+4; + if (pxllen < 517*4) { + printf("\nPXL file too short, must be at least 517 longwords"); + return(1); + } + pxldir = pxllen-517*4; + printf("\n%d bytes read.",pxllen); + return(0); + } + } + printf("\nUnable to find directory in PXL file."); + return(1); +} + +/* The tpxll command instructs FFC to type a longword from the PXL file. */ + +int handle_tpxll() { + + long i; + + i = atoi(&inline[ilp]); + if (i < 0 || i > pxllen-4) { + printf("\nRequested location %ld lies outside PXL file.",i); + return(1); + } else { + copy_from_pxl(i); + printf("\n%ld: %10lu = %%x\"%08lx\"",i,lcx.ul,lcx.ul); + return(0); + } +} + +/* The tnftl command instructs FFC to type a longword from the nft file. */ + +int handle_tnftl() { + + long i; + + i = atoi(&inline[ilp]); + if (i < 0 || i > nftlen-4) { + printf("\nRequested location %ld lies outside NFT file.",i); + return(1); + } else { + copy_from_nft(i); + printf("\n%ld: %10lu = %%x\"%08lx\"",i,lcx.ul,lcx.ul); + return(0); + } +} + +/* The spxll command sets a longword in the pxl file to a value, expressed +in HEXADECIMAL. */ + +int handle_spxll() +{ + long i; + + skipb; + i = atoi(&inline[ilp]); + if (i < 0 || i > pxllen-4) { + printf("\nRequested location %d lies outside PXL file.",i); + return(1); + } + skipnb; + copy_from_pxl(i); + sscanf(&inline[ilp],"%X",&lcx.ul); + pxlbuf[i] = lcx.c[3]; pxlbuf[i+1] = lcx.c[2]; + pxlbuf[i+2] = lcx.c[1]; pxlbuf[i+3] = lcx.c[0]; + printf("\n%ld: %10lu = %%x\"%08lx\"",i,lcx.ul,lcx.ul); + return(0); +} + +/* The snftl command sets a longword in the nft file to a value, expressed +in HEXADECIMAL. */ + +int handle_snftl() +{ + long i; + + skipb; + i = atoi(&inline[ilp]); + if (i < 0 || i > nftlen-4) { + printf("\nRequested location %d lies outside NFT file.",i); + return(1); + } + skipnb; + copy_from_nft(i); + sscanf(&inline[ilp],"%X",&lcx.ul); + nftbuf[i+3] = lcx.c[3]; nftbuf[i+2] = lcx.c[2]; + nftbuf[i+1] = lcx.c[1]; nftbuf[i] = lcx.c[0]; + printf("\n%ld: %10lu = %%x\"%08lx\"",i,lcx.ul,lcx.ul); + return(0); +} + +#define pxl_word(_x) (pxlbuf[_x]*256+pxlbuf[(_x)+1]) +#define signed_pxl_word(_x) ((pxl_word(_x)>0x8000) ? \ + (pxl_word(_x)-0x10000) : pxl_word(_x)) + +GLOBAL char visible_byte[9],sixel_line[401]; + +/* Handle_tpxlr handles the tpxlr and ppxlr commands, which direct FFC to +type or plot the rasters corresponding to a character code in the PXL file. +The parameter how determines what to do: type if how = 0, plot if how = 1. + +Plotting is done using the VT125/VT240 sixel protocol. VT100 ANSI escape +sequences are used to clear the screen and set the current screen position, +in order to keep the sixels from overwriting text. If the user's terminal +can't handle these protocols, a hopefully small amount of gobbledygook will +be displayed. [[On the VT125, text will eventually begin to scroll over the +last sixels drawn; the user must clear the screen manually.]] + +We display not just the rasters themselves, but also the directory +information for the character. This information comprises the byte offset +of the rasters within the PXL file; the number of rows and columns in the +rasters; the location of the reference point of the glyph with respect to +the upper left corner of the rasters; and the width of the glyph. */ + +int handle_tpxlr (how) +int how; +{ + + int code; + unsigned int rows,cols,i,j,k,l,m,col_longs; + long ds,rs; + unsigned long wid; + + if (pxldir == 0) { + printf("\nCan't display rasters because there isn't a good PXL"); + printf(" file in the PXL buffer."); + return(1); + } + + code = atoi(&inline[ilp]); + if (code < 0 || code > 127) { + printf("\nCharacter code must be between 0 and 127"); + return(1); + } + +/* Determine the location of the rasters within the PXL file. */ + + ds = pxldir+16*code; + copy_from_pxl(ds+8); + rs = 4*lcx.ul; + if (rs == 0) { + printf("\nNo rasters for code %d",code); + return(0); + } + if (how == 0 || rs > pxllen) printf("\n Rasters begin at %d",rs); + if (rs > pxllen) { + printf("\n ... outside the PXL file"); + return(1); + } + +/* Compute the remaining directory information for the glyph. */ + + cols = pxl_word(ds); rows = pxl_word(ds+2); + copy_from_pxl(ds+12); + wid = lcx.ul; + col_longs = (cols+31)/32; + +/* Plot as sixels if that is required. */ + + if (how == 1) { + printf("\033[2J"); /* erase entire screen */ + printf("\033Pq"); /* go into sixel mode */ + for (i=0; i 1) { + sixel_buf[sbp] = '!'; + if (howmany < 5) { + sixel_buf[sbp+1] = 2*howmany+'0'; + sbp += 2; + } else if (howmany < 50) { + sixel_buf[sbp+1] = (2*howmany)/10+'0'; + sixel_buf[sbp+2] = (2*howmany)%10+'0'; + sbp += 3; + } else { + sixel_buf[sbp+1] = (2*howmany)/100+'0'; + sixel_buf[sbp+2] = ((2*howmany)%100)/10+'0'; + sixel_buf[sbp+3] = (2*howmany)%10+'0'; + sbp += 4; + } + sixel_buf[sbp++] = last+63; + } + last = sixel_line[i]; + howmany = 1; + } + } + sixel_buf[sbp] = 0; + printf("\n%s-",sixel_buf); + +} + + +/* Place the reversed binary representation of v in the visible_byte +array, using dots . for 0s and 8s for 1s. */ + +int rev_binrep (v) +int v; +{ + int cnt,rem,quo; + + strcpy(visible_byte,"........"); + quo = v; + for (cnt=0; cnt<8; cnt++) { + rem = quo%2; quo = quo/2; + if (rem != 0) visible_byte[7-cnt] = '8'; + } +} + +int handle_tnftr (how) +int how; +{ + + int code; + int rows,columns,quo; + long i,j,k,l,m,def_start,xoff,yoff,col_bytes; + + code = atoi(&inline[ilp]); + + if (code < nft_first || code > nft_last) { + printf("\n No such character."); + return(1); + } + +/* First we need to determine def_start, the byte offset of the character +definition for code from in the NFT file */ + + copy_from_nft(480+(code-nft_first)*4); + def_start = lcx.l; + + if (def_start == 0) { + printf("\n No such character -- zero locator."); + return(1); + } + +/* Now we need to check that the rasters are uncompressed. LN03s can't +accept compressed rasters, and this program isn't clever enough to +understand them either. */ + + if (nftbuf[def_start+17] != 129) { + printf("\n Can't handle compressed rasters."); + return(1); + } + + copy_from_nft(def_start+4); + + if (nftbuf[def_start+16] % 2 == 0) { + rows = nftbuf[def_start+20]+256*nftbuf[def_start+21]; + columns = nftbuf[def_start+22]+256*nftbuf[def_start+23]; + } else { + columns = nftbuf[def_start+20]+256*nftbuf[def_start+21]; + rows = nftbuf[def_start+22]+256*nftbuf[def_start+23]; + } + col_bytes = columns/8; + if (columns != 8*col_bytes) col_bytes++; + + if (how == 1) { + printf("\033[2J"); /* erase entire screen */ + printf("\033Pq"); /* go into sixel mode */ + for (i=0; i 255 || c2 < 0 || c2 > 255 || c1 > c2) { + printf("\n Bad character code range: [%d, %d]",c1,c2); + return(1); + } + nft_first = c1; nft_last = c2; + init_nft(); + buffer_fixedp = 0; + return(0); +} + +int init_nft() +{ + int i; + +/* The following array holds reasonable values for bytes 0-479 of an NFT +file. These bytes were copied from a font load which the LN03 was known to +accept. The NFT files generated by this program are initialized using these +values. Some of these get overwritten later, however. */ + + static char good_opening[512] = { + 104,38,0,0,70,79,78,84, + 1,0,0,0,31,0,0,0, + 20,0,0,0,85,48,48,48, + 48,48,48,48,48,50,83,75, + 48,48,71,71,48,48,48,49, + 85,90,90,90,90,48,50,70, + 48,48,48,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 181,7,9,0,11,0,14,0, + 0,0,0,0,104,0,0,0, + 252,0,0,0,124,0,0,0, + 100,1,0,0,120,1,0,0, + 224,1,0,0,4,0,0,0, + 88,3,0,0,0,0,0,0, + 92,3,0,0,48,0,0,0, + 92,3,0,0,0,0,0,0, + 140,3,0,0,212,34,0,0, + 140,3,0,0,33,0,0,0, + 126,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 32,0,0,0,168,0,0,0, + 16,0,0,0,94,0,0,0, + 0,0,0,0,94,0,0,0, + 0,0,0,0,94,0,0,0, + 0,0,0,0,236,25,0,0, + 54,25,0,0,14,27,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,2,0,0,0, + 7,0,0,0,92,3,0,0, + 7,0,0,0,99,3,0,0, + 16,0,0,0,106,3,0,0, + 16,0,0,0,122,3,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 10,0,0,0,244,1,0,0, + 0,0,24,0,16,0,0,0, + 16,0,0,0,1,0,1,0, + 1,0,1,0,0,0,1,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 30,0,0,0,20,0,0,0, + 196,255,255,255,20,0,0,0, + 106,255,255,255,20,0,0,0, + 0,0,1,0,0,0,30,0, + 166,255,255,255,0,0,0,0, + 40,0,0,0,0,0,0,0, + 60,0,0,0,240,0,0,0, + 60,0,0,0,100,0,0,0, + 240,0,0,0,120,0,0,0, + 40,0,0,0,120,0,0,0, + 96,255,255,255,136,255,255,255, + 186,255,255,255,240,0,0,0, + 76,255,255,255,60,0,0,0, + 160,0,0,0,120,0,0,0, + 20,0,0,0,20,0,0,0, + 140,3,0,0,194,3,0,0, + 244,3,0,0,160,4,0,0, + 254,4,0,0,162,5,0,0, + 46,6,0,0,84,6,0,0}; + int pool_beg,nft_chardir; + +/* The character directory always begins at position 480 in the Common +Font File Format. */ + + nft_chardir = 480; + +/* Copy the good values into nftbuf */ + + for (i=0; i<480; i++) + nftbuf[i] = good_opening[i]; + for (i=480; i<480+(nft_last-nft_first+1)*4; i++) + nftbuf[i] = 0; + +/* Set the first and last character codes */ + + nftbuf[fnt__l_first_character] = nft_first; + nftbuf[fnt__l_first_character+4] = nft_last; + +#define fnt__l_char_directory 116 + + lcx.ul = 4*(nft_last-nft_first+1); + copy_to_nft(fnt__l_char_directory); + +/* Set the character counts */ + +#define fnt__l_infile_locators 204 +#define fnt__l_character_definitions 212 +#define fnt__l_raster_count 220 + + i = nft_last-nft_first+1; + nftlen = nft_chardir+4*i+4+48; + nftbuf[fnt__l_infile_locators] = i; + nftbuf[fnt__l_character_definitions] = i; + nftbuf[fnt__l_raster_count] = i; + +/* We now have to set some fields in the font format that are pointers to +where other fields begin. These pointers depend on the number of glyphs we +are placing in the font file. */ + +#define fnt__a_subset_tables 128 + + lcx.ul = nft_chardir+4*i; + copy_to_nft(fnt__a_subset_tables); + + lcx.ul = lcx.ul+4; + copy_to_nft(fnt__a_subset_tables+8); + copy_to_nft(fnt__a_subset_tables+16); + + lcx.ul = lcx.ul+48; + copy_to_nft(fnt__a_subset_tables+24); + +#define fnt__a_char_definitions 160 + + copy_to_nft(fnt__a_char_definitions); + +/* Set up the string pool (48 bytes). */ + + pool_beg = nftlen-48; + strncpy(&nftbuf[pool_beg],"0B\tZZZZ",7); + +/* For reasons that are beyond my comprehension, the Format requires us to +copy the first seven characters of the font file id into one piece of the +string pool, and the first sixteen into another place. */ + +#define fnt__t_font_file_id 20 + + for (i=1; i<8; i++) + nftbuf[pool_beg+7+i-1] = nftbuf[fnt__t_font_file_id+i-1]; + for (i=1; i<17; i++) + nftbuf[pool_beg+7+7+i-1] = ' '; + for (i=1; i<17; i++) + nftbuf[pool_beg+7+7+16+i-1] = nftbuf[fnt__t_font_file_id+i-1]; + +/* Now make string descriptors point into the string pool. */ + +#define fnt__a_char_set 260 +#define fnt__a_family_id 268 +#define fnt__a_family_name 276 +#define fnt__a_font_id 284 + + lcx.ul = pool_beg; + copy_to_nft(fnt__a_char_set); + lcx.ul = pool_beg+7; + copy_to_nft(fnt__a_family_id); + lcx.ul = pool_beg+7+7; + copy_to_nft(fnt__a_family_name); + lcx.ul = pool_beg+7+7+16; + copy_to_nft(fnt__a_font_id); + + nft_next_code = nft_first; + +#define fnt__l_portrait_byte_count 228 +#define fnt__l_landscape_byte_count 232 +#define fnt__l_mixed_byte_count 236 + + lcx.ul = 0; + copy_to_nft(fnt__l_portrait_byte_count); + copy_to_nft(fnt__l_landscape_byte_count); + copy_to_nft(fnt__l_mixed_byte_count); + +} + +/* Cptonft copies one or more glyphs from the PXL file to the NFT file +buffer. It reads from the command line two codes. Beginning at the first +code and proceeding sequentially, it copies glyphs. As cptonft copies, it +updates nftlen and nft_next_code to reflect what is going on, as well as +the portrait, landscape and mixed sizes. */ + +int handle_cptonft () { + + int i,c1,c2; + + skipb; + c1 = atoi(&inline[ilp]); + skipnb; skipb; + c2 = atoi(&inline[ilp]); + + if (c1 < 0 || c1 > 127 || c2 < 0 || c2 > 127 || c1 > c2) { + printf("\nBad range of codes: [%d, %d]",c1,c2); + return(1); + } + if (nft_next_code > nft_last) { + printf("\nCan't copy more glyphs -- no slots left in NFT file."); + return(1); + } + if (pxldir == 0) { + printf("\nCan't copy because there isn't a good PXL file in memory."); + return(1); + } + if (c2-c1+1 > nft_last+1-nft_next_code) { + c2 = c1+nft_last-nft_next_code; + printf("\nCopying only up to code %d",c2); + printf("\n -- no slots left for more glyphs in the NFT file."); + } + + if (buffer_fixedp) { + nftlen -= 8; + buffer_fixedp = 0; + } + + for(i=c1; i<=c2; i++) + if (copy_glyph(i) != 0) return(1); + return(0); +} + +GLOBAL unsigned char rev_byte[256] = { + 0,128,64,192,32,160,96,224, + 16,144,80,208,48,176,112,240, + 8,136,72,200,40,168,104,232, + 24,152,88,216,56,184,120,248, + 4,132,68,196,36,164,100,228, + 20,148,84,212,52,180,116,244, + 12,140,76,204,44,172,108,236, + 28,156,92,220,60,188,124,252, + 2,130,66,194,34,162,98,226, + 18,146,82,210,50,178,114,242, + 10,138,74,202,42,170,106,234, + 26,154,90,218,58,186,122,250, + 6,134,70,198,38,166,102,230, + 22,150,86,214,54,182,118,246, + 14,142,78,206,46,174,110,238, + 30,158,94,222,62,190,126,254, + 1,129,65,193,33,161,97,225, + 17,145,81,209,49,177,113,241, + 9,137,73,201,41,169,105,233, + 25,153,89,217,57,185,121,249, + 5,133,69,197,37,165,101,229, + 21,149,85,213,53,181,117,245, + 13,141,77,205,45,173,109,237, + 29,157,93,221,61,189,125,253, + 3,131,67,195,35,163,99,227, + 19,147,83,211,51,179,115,243, + 11,139,75,203,43,171,107,235, + 27,155,91,219,59,187,123,251, + 7,135,71,199,39,167,103,231, + 23,151,87,215,55,183,119,247, + 15,143,79,207,47,175,111,239, + 31,159,95,223,63,191,127,255 + }; + +/* Copy_glyph copies the rasters and character directory information +corresponding to code i in the PXL file, into the nft_next_code position of +the NFT file buffer. */ + +int copy_glyph(code) +int code; +{ + + unsigned long ds,rs,i,j; + unsigned int rows,cols,k,l,m,n; + int xoffset, yoffset; + float width; + char all_blank; + +/* Locate the definition and the rasters for code in the PXL file. Check +that the rasters are indeed within the pxl file. [[This check may need to +be modified if we implement commands to add rasters to the pxl file.]] */ + + ds = pxldir+16*code; + copy_from_pxl(ds+8); + rs = 4*lcx.ul; + cols = pxl_word(ds); rows = pxl_word(ds+2); + if (rs+rows*4*((cols+31)/32) > pxllen) { + printf("\nPXL file entry for code %d points outside file",code); + printf("\nCopy to NFT file terminated before code %d",nft_next_code); + return(1); + } + +/* If a glyph has no rasters, an "undocumented feature" of the LN03 seems +to cause the glyph to be printed incorrectly. Because of this, we set the +number of rows and columns to 1, and put in a blank byte (below). */ + + all_blank = (rows == 0) & (cols == 0); + if (all_blank) { + cols = 1; + rows = 1; + } + +/* Check that we have enough room left in the NFT buffer. */ + + if (nftlen+rows*((cols+7)/32)+24 > NFTBUFSIZE) { + printf("\nNo more room in NFT file buffer (%ld bytes long)", + NFTBUFSIZE); + printf("\nCopy to NFT file terminated before code %d",nft_next_code); + return(1); + } + +/* Compute the width of the glyph in pixels, the xoffset, and the yoffset. +*/ + + copy_from_pxl(ds+12); + width = conv*lcx.ul; + xoffset = signed_pxl_word(ds+4); + yoffset = signed_pxl_word(ds+6); + +/* Clear the character definition area in the NFT file buffer. */ + + for(i=0; i<24+rows*((cols+7)/8); i++) + nftbuf[nftlen+i] = 0; + +/* Set the fields in the first six longwords of the NFT character +definition. The first assignment sets the so-called "flag flag", which must +be always be set according to the DEC Common Font File Format. A conversion +factor of 24 is used in converting pixel values, because the values are +supposed to be in centipoints in the NFT file, and if we assume there are +300 pixels in an inch, then there are 7200 centipoints in an inch. +[[Eventually, the resolution of the printer will have to be settable!]] */ + + nftbuf[nftlen+3] = 0x80; + lcx.ul = 24*width+0.5; + copy_to_nft(nftlen+4); + lcx.l = -24*xoffset; + copy_to_nft(nftlen+8); + lcx.l = -24*yoffset; + copy_to_nft(nftlen+12); + +/* The rasters are always placed in portrait into the NFT file, with no +use of run-length encoding. Thus, the orient field in the raster format +will be 0, and the Type 1 field is set to 0x81. */ + + nftbuf[nftlen+17] = 0x81; + nftbuf[nftlen+20] = rows%256; + nftbuf[nftlen+21] = rows/256; + nftbuf[nftlen+22] = cols%256; + nftbuf[nftlen+23] = cols/256; + +/* Now we copy the rasters themselves. As we do so, we have to reverse +the bits within each byte. */ + + k = (cols+31)/32; + n = (cols+7)/8; + if (!all_blank) + for (l=0; l j) ? i : j; + copy_to_nft(fnt__l_mixed_byte_count); + + nft_next_code++; + + return(0); +} + +/* The wnft command writes the contents of an NFT buffer into a file. +It is necessary to do some fixup on the buffer the first time this +is done. */ + +int handle_wnft() { + + int nftf; + unsigned long i; + + skipb; istart = ilp; skipnb; + inline[ilp] = '\0'; + + nftf = open_output_file(&inline[istart],".nft"); + if (nftf == -1) { + printf("\nUnable to open NFT file %s",&inline[istart]); + return(1); + } + +/* At this point we have to clean up a few fields before writing +the file. */ + +#define fnt__l_char_definitions_length 156 + + if (!buffer_fixedp) { + lcx.ul = nftlen-(480+(nft_last-nft_first+1)*4+48+4); + copy_to_nft(fnt__l_char_definitions_length); + + nftlen += 8; + lcx.ul = nftlen; + copy_to_nft(0); + copy_to_nft(nftlen-8); + nftbuf[nftlen-4] = 'F'; + nftbuf[nftlen-3] = 'O'; + nftbuf[nftlen-2] = 'N'; + nftbuf[nftlen-1] = 'T'; + buffer_fixedp = 0; + } + +/* Pad the file out to a multiple of 512 bytes */ + + if (nftlen%512 != 0) + for (i=0; i<512-nftlen%512; i++) + nftbuf[nftlen+i] = 0; + +/* Now for the actual writing */ + + for (i=0; i 512) target = 512; + if (write(strf,&pxlbuf[i],target) == -1) { + printf("\nError writing PXL file."); + close(strf); + return(1); + } + } + + close(strf); + return(0); +} + +int open_output_file (s,ext) +char s[], ext[]; +{ + char fs[FILESPECLEN]; + int jnam,jext; + + strcpy(fs,s); + find_filename(fs,&jnam,&jext); + if (fs[jext] == '\0') strcat(fs,ext); +#ifdef vms + return(creat(fs,0,"rfm=fix","mrs=512")); +#else + return(creat(fs,0700)); +#endif + +} + diff --git a/dviware/ln03/rose/older_driver.mem b/dviware/ln03/rose/older_driver.mem new file mode 100644 index 0000000000..c1350ea850 --- /dev/null +++ b/dviware/ln03/rose/older_driver.mem @@ -0,0 +1,84 @@ +AN OLDER DRIVER (NOW OBSOLETE) + +If you are running under an old version of VMS (before 4.2), +you may not be able to get dvi2ln3 to work because you don't +have the C run time library. In that case, as a backup, we +supply an older driver, which is considerably slower than +dvi2ln3. + +The older driver is supplied as + + dvi2lng.web, dvi2lng.ch, dvi2lng.obj + ln03topp.pli, ln03topp.obj, toppnft.pli, toppnft.obj, + lnfinc.pli, lnfinc.obj + ffc.web, ffc.ch, ffc.obj + +To get executables, relink: + + $ link dvi2lng + $ link ln03topp,toppnft,lnfinc + $ link ffc + +The old driver doesn't read PXL files, so all PXL files have +to be converted to the TEX$LN03DIR format files by the +following recipe: + + $ run ffc + + Font File Converter + + FFC> rpxl foo.yyyyPXL + FFC> toln03x + FFC> wln03 foo.xxx + FFC> exit + $ + +Here yyyy/15 = xxx, and xxx% is the magnification of the +font. If the font is not magnified, so that yyyy = 1500, +then xxx must be NFT. + +The way to invoke the driver is different, also. You define +two VMS symbols + + $ dvi2lng == "$disk:[directory]dvi2lng" + $ ln03topp == "$disk:[directory]ln03topp" + +To convert foo.dvi to foo.ln3, you say + + $ dvi2lng foo + $ ln03topp foo + +In addition to foo.ln3, this creates the useless files +foo.typ, foo.lnh and foo.lng which you should delete. + +The Dvi2lng program takes the options /N and /S of the +Dvi2ln3 program. The Ln03Topp program takes the options /H +and /V of the Dvi2ln3 program. There is no option for +printing in landscape. + +If you need to relink, the commands are as follows: + + $ link dvi2lng + $ link ln03topp,toppnft,lnfinc + +The FFC commands are: + + rpxl Read pxl file + rln03 Read ln03 font file + tln03 Type the rasters for LN03 character, specified + as a decimal ascii code, or as the character + itself preceded by a single quote ' + tpxl Type the rasters for PXL character + toln03 Convert PXL file to LN03 format, converting + only the 94 characters with codes 33-126. The + converted file is held in memory, and must be + written out with a separate wln03 command. + toln03x Convert PXL file to LN03 font file, converting + all 128 characters + wln03 Write an LN03 file + tln03long These commands type longwords or words from the PXL + tln03word and LN03 files last read in, or the versions + tpxllong generated via the conversion command. The + tpxlword is a decimal number of bytes from the beginning of + the file. + exit Leave the FFC program diff --git a/dviware/ln03/rose/picmode.pli b/dviware/ln03/rose/picmode.pli new file mode 100644 index 0000000000..4169256a7c --- /dev/null +++ b/dviware/ln03/rose/picmode.pli @@ -0,0 +1,529 @@ +%REPLACE false BY '0'B; +%REPLACE true BY '1'B; + +/* + +The purpose of this program is to provide a standalone version of LNF's +PICmode, outputting a TeX file which can be \input into a TeX document. +Copyright (c) 1984 by Digital Equipment Corporation. Author: Flavio +Rose. UNDER DEVELOPMENT. + +*/ + +picmode: PROCEDURE OPTIONS(MAIN); + + DCL (strip,frontstrip) EXTERNAL ENTRY (CHAR (*)) + RETURNS (CHAR (*)), + cvis EXTERNAL ENTRY (FIXED) RETURNS (CHAR (*)); + DCL upcase EXTERNAL ENTRY (CHAR (*)) RETURNS (CHAR (*)); + DCL read_wln_file EXTERNAL ENTRY(FIXED,CHAR(*),FILE) RETURNS(BIT); + + /* Debugging info */ + DCL debug FILE; + DCL debugwid FIXED; + DCL debugflag BIT; + debugflag = false; + debugwid = 0; + + /* input file, output file, wln file, include file */ + DCL (outf,inf) FILE; + DCL (infnam,outfnam) CHAR(150) VARYING; + + ON UNDEFINEDFILE (inf) BEGIN; + PUT SKIP LIST('No such file: ' || infnam); + GOTO terminal_eof; + END; + + ON UNDEFINEDFILE (outf) BEGIN; + PUT SKIP LIST('Couldn''t open: ' || outfnam); + GOTO terminal_eof; + END; + + /* Define as constants. In general this source file should + not contain any ascii control characters; instead we use byte(). */ + DCL (esc,tab) CHAR(1); + esc = byte(27); + tab = byte(9); + + /* Heading */ + PUT SKIP LIST ('PICmode 1.0'); + /* Hack command line */ + %REPLACE obufsize BY 512; + %REPLACE inbufsize BY 512; + DCL ob CHAR(obufsize); + DCL inline CHAR(inbufsize) VARYING; + DCL tch CHAR(1); + DCL (illen,obp,ilp,i,istart,zch) FIXED; + + %INCLUDE $stsdef; + DCL lib$get_foreign ENTRY (CHAR(*) VARYING, CHAR(*) VARYING, + FIXED(15),FIXED) OPTIONS(VARIABLE) RETURNS(FIXED); + DCL rms$_eof FIXED GLOBALREF VALUE; + DCL defdir CHAR(150) VARYING; + DCL (jj,jdir,jext) FIXED; + + sts$value = lib$get_foreign(inline,,,0); + + IF ^sts$success THEN DO; + PUT SKIP EDIT ('Usage: picmode ') (A); + GOTO terminal_eof; + END; + + inline = inline || ' '; + illen = length(inline); + ilp = 1; + CALL skipb; + IF ilp > illen THEN DO; + PUT SKIP EDIT ('Usage: picmode ') (A); + GOTO terminal_eof; + END; + istart = ilp; + CALL skipnb2; + infnam = substr(inline,istart,ilp-istart); + OPEN FILE(inf) TITLE(infnam) + ENVIRONMENT(Default_file_name('FOO.PMD')); + + jdir = istart; + DO jj = ilp-1 TO istart BY -1; + IF substr(inline,jj,1) = ':' | + substr(inline,jj,1) = ']' | + substr(inline,jj,1) = '>' + THEN DO; + jdir = jj+1; + GOTO found_jdir; + END; + END; + +found_jdir: + defdir = substr(inline,istart,jdir-istart); + jext = ilp; + DO jj = jdir TO ilp-1; + IF substr(inline,jj,1) = '.' | + substr(inline,jj,1) = ';' + THEN DO; + jext = jj; + GOTO found_jext; + END; + END; + +found_jext: + outfnam = substr(inline,jdir,jext-jdir) || '.TEX'; + + OPEN FILE(outf) OUTPUT TITLE(outfnam) + ENVIRONMENT(Default_file_name('FOO.TEX')); + +/* Globals: + + font information + picmode uses just one font + but we use these for compatibility with LNFWLN */ + + DCL curf FIXED; + DCL (firstch(0:9),lastch(0:9),fht(0:9)) FIXED GLOBALDEF; + DCL chw(0:9,0:255) FIXED GLOBALDEF; + DCL fname(0:9) CHAR(20) GLOBALDEF; + DCL font_present(0:9) BIT GLOBALDEF; + + curf = 0; + chw = 0; + font_present = false; + + /* character classification for PIC mode */ + DCL ztyp(0:255) FIXED(7); + ztyp = 0; + ztyp(rank('+')) = 1; + ztyp(rank('-')) = 2; + ztyp(rank('|')) = 3; + ztyp(rank('v')) = 4; + ztyp(rank('<')) = 5; + ztyp(rank('>')) = 6; + ztyp(rank('^')) = 7; + ztyp(rank('/')) = 8; + ztyp(rank('\')) = 9; + ztyp(rank('#')) = 10; + ztyp(rank('X')) = 11; + + DCL horp(0:11) BIT ALIGNED INIT(false,true,true,false, + true,false,false,true,true,true,true,false); + DCL verp(0:11) BIT ALIGNED INIT(false,true,false,true, + false,true,true,false,true,true,true,false); + DCL arrowp(0:11) BIT ALIGNED INIT(false,false,false,false, + true,true,true,true,false,false,false,false); + DCL slant(0:11) BIT ALIGNED INIT(false,false,false,false, + false,true,true,false,true,true,false,true); + PUT EDIT ('\vbox{\font\amgr=AMGR at 10truept\baselineskip0.1466667truein' || + '\lineskiplimit-\maxdimen') (A) FILE(outf); + PUT SKIP EDIT ('\catcode`\-=\active\catcode`\~=\active' || + '\def~{{\char32}}\def-{{\char1}}%') (A) FILE(outf); + CALL process_pic; + PUT EDIT ('}') (A) FILE(outf); + +abort_job: + CLOSE FILE(inf); + + +terminal_eof: + RETURN; + + process_pic: PROCEDURE; + DCL ils(3) CHAR(inbufsize) VARYING; + DCL (temp,prev,curr,next,quo,rem) FIXED; + DCL last_line BIT; + + ils(1) = ''; + last_line = false; + prev = 1; + curr = 2; + next = 3; + IF ^read_line_for_pic(2) THEN RETURN; /* pic is empty */ + IF ^read_line_for_pic(3) THEN last_line = true; + DO WHILE (true); + CALL output_pic_line; + IF last_line THEN DO; + obp = 0; + RETURN; + END; + temp = prev; + prev = curr; + curr = next; + next = temp; + IF ^read_line_for_pic(next) THEN last_line = true; + END; + + read_line_for_pic: PROCEDURE (which) RETURNS (BIT); + DCL (which,true_ilp) FIXED; + + ON ENDFILE (inf) GOTO end_of_inf; + + ils(which) = ''; + GET EDIT (inline) (A(511)) FILE(inf); + + inline = inline || ' '; + illen = length(inline); + /* For PICs, we attempt to untabify input lines */ + true_ilp = 1; + DO ilp = 1 TO illen-1; + IF substr(inline,ilp,1) ^= tab + THEN DO; + ils(which) = ils(which) || substr(inline,ilp,1); + true_ilp = true_ilp+1; + END; + ELSE DO; + quo = DIVIDE(true_ilp-1,8,31); + rem = true_ilp-1-quo*8; + ils(which) = ils(which) || copy(' ',8-rem); + true_ilp = true_ilp+8-rem; + END; + END; + RETURN(true); + + end_of_inf: + CLOSE FILE(inf); + RETURN(false); + + END read_line_for_pic; + + output_pic_line: PROCEDURE; + DCL (iz,prevl,currl,nextl,icnt,nbors(8)) FIXED; + DCL (zch,tch) CHAR; + DCL cnt_to_char_plus(0:15) FIXED STATIC INIT( + 43,161,160,164,161,161,165,177, + 160,163,161,176,162,178,175,174); + DCL cnt_to_char_sharp(0:15) FIXED STATIC INIT( + 35,161,160,186,161,161,187,177, + 160,185,161,176,184,178,175,174); + DCL (xtra1,xtra2) CHAR(inbufsize) VARYING; + DCL (xtra1used,xtra2used,present(8)) BIT ALIGNED; + + xtra1used = false; + xtra2used = false; + xtra1 = ''; + xtra2 = ''; + obp = 0; + prevl = length(ils(prev)); + currl = length(ils(curr)); + nextl = length(ils(next)); + DO iz = 1 TO currl; + zch = substr(ils(curr),iz); + IF ztyp(rank(zch)) ^= 0 THEN CALL det_nbors; + IF ztyp(rank(zch)) = 0 THEN tch = zch; + ELSE IF zch = '-' THEN DO; + IF ztyp(nbors(1)) ^= 0 | ztyp(nbors(3)) ^= 0 + THEN tch = byte(161); + ELSE tch = '-'; + END; ELSE IF zch = '|' THEN DO; + IF ztyp(nbors(2)) ^= 0 | ztyp(nbors(4)) ^= 0 + THEN tch = byte(160); + ELSE tch = '|'; + END; ELSE IF zch = '+' THEN DO; + icnt = 0; + IF horp(ztyp(nbors(1))) THEN icnt = icnt+1; + IF verp(ztyp(nbors(2))) THEN icnt = icnt+2; + IF horp(ztyp(nbors(3))) THEN icnt = icnt+4; + IF verp(ztyp(nbors(4))) THEN icnt = icnt+8; + IF nbors(1) = rank('<') THEN DO; + IF verp(ztyp(nbors(5))) | verp(ztyp(nbors(8))) + THEN icnt = icnt+1; + END; + IF nbors(2) = rank('^') THEN DO; + IF horp(ztyp(nbors(5))) | horp(ztyp(nbors(6))) + THEN icnt = icnt+2; + END; + IF nbors(3) = rank('>') THEN DO; + IF verp(ztyp(nbors(6))) | verp(ztyp(nbors(7))) + THEN icnt = icnt+4; + END; + IF nbors(4) = rank('v') THEN DO; + IF horp(ztyp(nbors(7))) | horp(ztyp(nbors(8))) + THEN icnt = icnt+8; + END; + tch = byte(cnt_to_char_plus(icnt)); + END; ELSE IF zch = 'v' | zch = '^' THEN DO; + IF (horp(ztyp(nbors(1))) & + ^arrowp(ztyp(nbors(1)))) + | (horp(ztyp(nbors(3))) & + ^arrowp(ztyp(nbors(3)))) + THEN DO; + IF zch = 'v' THEN tch = byte(181); + ELSE tch = byte(182); + END; ELSE tch = zch; + END; ELSE IF zch = '<' THEN DO; + IF (verp(ztyp(nbors(2))) & + ^arrowp(ztyp(nbors(2)))) + | (verp(ztyp(nbors(4))) & + ^arrowp(ztyp(nbors(4)))) + THEN tch = byte(179); + ELSE IF (nbors(6) = rank('/') + | nbors(6) = rank('>') | nbors(7) = rank('\') + | nbors(7) = rank('>')) + THEN DO; + tch = byte(173); + CALL superpose(byte(172)); + IF horp(ztyp(nbors(1))) THEN + CALL superpose(byte(167)); + END; ELSE tch = zch; + END; ELSE IF zch = '>' THEN DO; + IF (verp(ztyp(nbors(2))) & + ^arrowp(ztyp(nbors(2)))) + | (verp(ztyp(nbors(4))) & + ^arrowp(ztyp(nbors(4)))) + THEN tch = byte(180); + ELSE IF (nbors(8) = rank('/') + | nbors(5) = rank('<') | nbors(5) = rank('\') + | nbors(8) = rank('<')) + THEN DO; + tch = byte(170); + CALL superpose(byte(171)); + IF horp(ztyp(nbors(3))) THEN + CALL superpose(byte(169)); + END; ELSE tch = zch; + END; ELSE IF zch = '/' THEN DO; + present = false; + IF nbors(6) = rank('/') | nbors(6) = rank('>') + | nbors(6) = rank('X') | nbors(3) = rank('\') + THEN present(6) = true; + IF nbors(8) = rank('/') | nbors(8) = rank('<') + | nbors(8) = rank('X') | nbors(1) = rank('\') + THEN present(8) = true; + IF ^(present(6) | present(8)) THEN DO; + tch = zch; + GOTO break; + END; + IF present(6) & present(8) THEN tch = byte(188); + ELSE IF present(6) THEN tch = byte(172); + ELSE IF present(8) THEN tch = byte(170); + IF horp(ztyp(nbors(1))) & ^slant(ztyp(nbors(1))) + THEN present(1) = true; + IF horp(ztyp(nbors(3))) & ^slant(ztyp(nbors(3))) + THEN present(3) = true; + IF present(1) & present(3) THEN CALL superpose( + byte(161)); + ELSE IF present(1) THEN CALL superpose(byte(167)); + ELSE IF present(3) THEN CALL superpose(byte(169)); + END; ELSE IF zch = '\' THEN DO; + present = false; + IF nbors(5) = rank('\') | nbors(5) = rank('<') + | nbors(5) = rank('X') | nbors(3) = rank('/') + THEN present(5) = true; + IF nbors(7) = rank('\') | nbors(7) = rank('>') + | nbors(7) = rank('X') | nbors(1) = rank('/') + THEN present(7) = true; + IF ^(present(5) | present(7)) THEN DO; + tch = zch; + GOTO break; + END; + IF horp(ztyp(nbors(1))) & ^slant(ztyp(nbors(1))) + THEN present(1) = true; + IF horp(ztyp(nbors(3))) & ^slant(ztyp(nbors(3))) + THEN present(3) = true; + IF present(5) & present(7) THEN tch = byte(189); + ELSE IF present(5) THEN tch = byte(171); + ELSE IF present(7) THEN tch = byte(173); + IF present(1) & present(3) THEN CALL superpose( + byte(161)); + ELSE IF present(1) THEN CALL superpose(byte(167)); + ELSE IF present(3) THEN CALL superpose(byte(169)); + END; ELSE IF zch = '#' THEN DO; + icnt = 0; + IF horp(ztyp(nbors(1))) THEN icnt = icnt+1; + IF verp(ztyp(nbors(2))) THEN icnt = icnt+2; + IF horp(ztyp(nbors(3))) THEN icnt = icnt+4; + IF verp(ztyp(nbors(4))) THEN icnt = icnt+8; + IF nbors(1) = rank('<') THEN DO; + IF verp(ztyp(nbors(5))) | verp(ztyp(nbors(8))) + THEN icnt = icnt+1; + END; + IF nbors(2) = rank('^') THEN DO; + IF horp(ztyp(nbors(5))) | horp(ztyp(nbors(6))) + THEN icnt = icnt+2; + END; + IF nbors(3) = rank('>') THEN DO; + IF verp(ztyp(nbors(6))) | verp(ztyp(nbors(7))) + THEN icnt = icnt+4; + END; + IF nbors(4) = rank('v') THEN DO; + IF horp(ztyp(nbors(7))) | horp(ztyp(nbors(8))) + THEN icnt = icnt+8; + END; + tch = byte(cnt_to_char_sharp(icnt)); + END; ELSE IF zch = 'X' THEN DO; + IF nbors(5) = rank('\') & nbors(6) = rank('/') & + nbors(7) = rank('\') & nbors(8) = rank('/') + THEN DO; + tch = byte(188); + CALL superpose(byte(189)); + END; ELSE tch = zch; + END; ELSE tch = zch; + break: + obp = obp+1; + substr(ob,obp,1) = tch; + END; + + IF xtra1used THEN PUT SKIP EDIT ('\hbox{\rlap{%') (A) FILE(outf); + CALL really_output(substr(ob,1,obp)); + IF xtra1used THEN DO; + PUT EDIT ('}%') (A) FILE(outf); + IF xtra2used THEN PUT SKIP EDIT ('\rlap{%') (A) FILE(outf); + CALL really_output(xtra1); + IF xtra2used THEN DO; + PUT EDIT ('}%') (A) FILE(outf); + CALL really_output(xtra2); + END; + PUT EDIT ('}') (A) FILE(outf); + END; + + det_nbors: PROCEDURE; + DCL space_rank FIXED; + + space_rank = rank(' '); + IF iz = 1 THEN nbors(1) = space_rank; + ELSE nbors(1) = rank(substr(ils(curr),iz-1,1)); + IF iz = 1 | iz-1 > prevl THEN nbors(5) = space_rank; + ELSE nbors(5) = rank(substr(ils(prev),iz-1,1)); + IF iz > prevl THEN nbors(2) = space_rank; + ELSE nbors(2) = rank(substr(ils(prev),iz,1)); + IF iz+1 > prevl THEN nbors(6) = space_rank; + ELSE nbors(6) = rank(substr(ils(prev),iz+1,1)); + IF iz = currl THEN nbors(3) = space_rank; + ELSE nbors(3) = rank(substr(ils(curr),iz+1,1)); + IF iz = 1 | iz-1 > nextl THEN nbors(8) = space_rank; + ELSE nbors(8) = rank(substr(ils(next),iz-1,1)); + IF iz > nextl THEN nbors(4) = space_rank; + ELSE nbors(4) = rank(substr(ils(next),iz,1)); + IF iz+1 > nextl THEN nbors(7) = space_rank; + ELSE nbors(7) = rank(substr(ils(next),iz+1,1)); + + END det_nbors; + + superpose: PROCEDURE (x); + DCL x CHAR; + + IF ^xtra1used THEN DO; + xtra1 = copy(' ',obp+1); + substr(xtra1,obp+1,1) = x; + xtra1used = true; + END; ELSE IF length(xtra1) < obp+1 + THEN xtra1 = xtra1 || copy(' ',obp-length(xtra1)) || x; + ELSE IF substr(xtra1,obp+1,1) = ' ' + THEN substr(xtra1,obp+1,1) = x; + ELSE IF ^xtra2used THEN DO; + xtra2 = copy(' ',obp+1); + substr(xtra2,obp+1,1) = x; + xtra2used = true; + END; ELSE IF length(xtra2) < obp+1 + THEN xtra2 = xtra2 || copy(' ',obp-length(xtra2)) || x; + ELSE substr(xtra2,obp+1,1) = x; + + END superpose; + + really_output: PROCEDURE (who); + + DCL who CHAR(*) VARYING; + DCL (i,j,k) FIXED; + DCL (tch,tcat) CHAR(1); + DCL cats(32:126) CHAR(1) STATIC INIT + ('e',(2)('o'),(4)('e'),(6)('o'),'e',(46)('o'), + 'e','o',(2)('e'),(27)('o'),'e','o',(2)('e')); + + j = length(who); + + PUT SKIP EDIT ('\hbox{\amgr ') (A) FILE(outf); + k = 0; + DO i = 1 to j; + tch = substr(who,i,1); + IF rank(tch) < 32 | (rank(tch) > 126 & + rank(tch) < 160) + THEN tch = ' '; + k = k+1; + IF tch = ' ' THEN PUT EDIT ('~') (A) FILE(outf); + ELSE IF tch = byte(161) THEN PUT EDIT ('-') (A) FILE(outf); + ELSE IF rank(tch) >= 160 THEN DO; + PUT EDIT ('{\char' || cvis(rank(tch)-160) || '}') + (A) FILE(outf); + k = k+7; + END; ELSE DO; + tcat = cats(rank(tch)); + IF tcat = 'o' THEN PUT EDIT (tch) (A) FILE(outf); + ELSE DO; + PUT EDIT ('{\char' || cvis(rank(tch)) || '}') + (A) FILE(outf); + k = k+7; + END; + END; + IF k > 100 THEN DO; + PUT EDIT ('%') (A) FILE(outf); + PUT SKIP FILE(outf); + k = 0; + END; + + END; + PUT EDIT ('}') (A) FILE(outf); + + END really_output; + + END output_pic_line; + + END process_pic; + + /* skip over blanks in infile */ + skipb: PROCEDURE; + + DO WHILE (ilp <= illen); + IF substr(inline,ilp,1) ^= ' ' THEN RETURN; + ilp = ilp+1; + END; + + END skipb; + + /* skip over characters other than ' ' and '}'. */ + skipnb2: PROCEDURE; + + DO WHILE (ilp <= illen); + IF substr(inline,ilp,1) = ' ' + | substr(inline,ilp,1) = '}' THEN RETURN; + ilp = ilp+1; + END; + + END skipnb2; + +END picmode; diff --git a/dviware/ln03/rose/specials.c b/dviware/ln03/rose/specials.c new file mode 100644 index 0000000000..1cfb0bb471 --- /dev/null +++ b/dviware/ln03/rose/specials.c @@ -0,0 +1,480 @@ +/* This file contains the code that implements the handling of \special's +in Dvi2ln3. + +Copyright (c) 1985 by Digital Equipment Corporation. Author: Flavio Rose, +(617) 467-7545, ...ucbvax!decwrl!dec-rhea!dec-dvinci!rose. + +Right now, the following \special's are implemented: + +ln03:defpoint fixnum ( [dimension] , [dimension] ) +ln03:connect fixnum [/ fixnum] fixnum [/ fixnum] +ln03:plotfile filename +ln03:resetpoints fixnum fixnum + +A dimension is a number with optional decimal point, followed by one of pt, +in, pc, cm, mm, bp, dd, cc, and mi. + +We try to mimic the functionality of DVIAPS, a program that drives the +Autologic Micro-5 typesetter, written by Textset Inc. of Ann Arbor, +Michigan. This has been done on the basis of user-level documentation +supplied by Textset. This code does not contain any Textset-proprietary +information. + +\special's are parsed case-insensitively. + +Revision history: + +10/8/85 Created file, wrote, tested code for ln03:plotfile + +10/16/85 ln03:resetpoints, ln03:defpoint, ln03:connect + +12/12/85 Corrected bug: ln03:plotfile does not update LN03's + position to the latest from the DVI file. + +*/ + +#ifdef vms +#include stdio +#include ctype +#include math +#include file +#else +#include +#include +#include +#endif + +/* In VMS we declare external variables to be globalref. +This is not really necessary, just an old habit. */ + +#ifdef vms +#define GLOBAL globaldef +#define EXTERN globalref +#else +#define GLOBAL +#define EXTERN extern +#endif + +#define NUMSPECIALS 4 + +GLOBAL char *specialnames[NUMSPECIALS] = { "defpoint", + "connect", "plotfile", "resetpoints" } ; + +EXTERN FILE *dvifile,*outfile; + +/* There are two top-level routines for handling specials, one to be +invoked during pass1, the other to be invoked during pass2. The parameter +that is passed is the size of the \special string. */ + +int do_special_pass1 (p) +int p; +{ + for (; p != 0; p--) getc(dvifile); + return(0); +} + +/* Specials get put in a buffer for easier parsing. The buffer is a little +longer than needed to make some things simpler. [[This ought to be +cleaner.]] */ + +#define MAXSPECIAL 1000 + +GLOBAL char sb[MAXSPECIAL+7]; +GLOBAL int sbp,cstart; + +/* Do_special_pass2 gets called from the main program to perform special +processing in pass2, the pass in which stuff actually gets written out to +the LN3 output file. The parameter p is the length of the special. */ + +int do_special_pass2 (p) +int p; +{ + char c; + int i,j; + +/* Skip whitespace in input */ + + sbp = 0; + while (p != 0) { + c = getc(dvifile); + p--; + if (!isspace(c)) { + sb[sbp] = c; + sbp = 1; + break; + } + } + if (sbp == 0) return(1); + +/* Now we have non-whitespace, read the rest of the special, or as much as +will fit in the buffer. Lowercase the stuff as it is read in. */ + + for (; p != 0; p--) { + sb[sbp] = tolower(getc(dvifile)); + sbp++; + if (sbp > MAXSPECIAL) break; + } + +/* Put a null as sentinel at the end of the special. */ + + sb[sbp] = 0; + +/* Determine whether the special pertains to the ln03, in which case sbpf +will contain "ln03" followed by whitespace or a colon. */ + + if (strncmp(sb,"ln03",sizeof("ln03")-1) != 0) return(1); + sbp = sizeof("ln03")-1; + +/* Skip whitespace and one colon */ + + while (isspace(sb[sbp])) sbp++; + if (sb[sbp] != ':') return(1); + sbp++; + +/* Now, it might be that the special was too long for the special buffer, +so check that out and issue an error message. */ + + if (p != 0) { + printf("\n \special too long (over %d bytes).",MAXSPECIAL); + for (; p != 0; p--) getc(dvifile); + return(1); + } + +/* Now determine if the special command is one of those which the driver is +supposed to recognize. As in the DVIAPS program, only the first six bytes +of the command are significant, so plotfile could be written plotfi and +defpoint could be written defpoi. */ + + while (isspace(sb[sbp])) sbp++; + cstart = sbp; + while (!isspace(sb[sbp]) && sb[sbp] != '\0') sbp++; + sb[sbp] = 0; + sbp++; + + for (i = 0; i MAXPOINTS) { + printf(special_mess,"defpoint"); + printf("\n Invalid point number (%d)",which); + return(1); + } + while (isspace(sb[sbp]) || sb[sbp] == ',') sbp++; + hh_val = hh; + vv_val = vv; + if (sb[sbp] != '(') goto record_point; + sbp++; + while (isspace(sb[sbp])) sbp++; + if (sb[sbp] == '\0') goto record_point; + if (sb[sbp] == ',') sbp++; + else { + scan_dimension(&hh_val); + while (isspace(sb[sbp])) sbp++; + if (sb[sbp] == ',') sbp++; + else goto record_point; + } + while(isspace(sb[sbp])) sbp++; + if (sb[sbp] != ')' && sb[sbp] != '\0') scan_dimension(&vv_val); +record_point: + point_hh[which-1] = hh_val; + point_vv[which-1] = vv_val; + point_present[which-1] = 1; + return(0); +} + +EXTERN long first_counter; + +int do_connect_pass2() +{ + int a1,b1,a2,b2,w; + + scan_xpoint(&a1,&b1); + while (isspace(sb[sbp]) || sb[sbp] == ',') sbp++; + scan_xpoint(&a2,&b2); + while (isspace(sb[sbp]) || sb[sbp] == ',') sbp++; + w = 2; /* default width is two pixels ~ 0.4 points */ + if (sb[sbp] != '\0') scan_dimension(&w); + + if (first_counter%2 == 0) connect_points(b1,b2,w); + else connect_points(a1,a2,w); + + return(0); +} + +EXTERN int ln3p,vpset,hh_old; + +int do_plotfile_pass2() +{ + char buf[512]; + int i,j; + char c; + +/* Read filename into array. */ + + while (isspace(sb[sbp])) sbp++; + i = sbp; + while (!isspace(sb[sbp]) && sb[sbp] != '\0') sbp++; + sb[sbp] = 0; + +/* Try to open the file. [[What is the status of O_RDONLY under Unix? Is +that a 4.2bsd hack that it would be best to leave out?]] */ + +#ifdef vms + j = open(&sb[i],O_RDONLY,0); +#else + j = open(&sb[i],0,0); +#endif + if (j == -1) { + printf("\n Unable to open plotfile %s",&sb[i]); + return(1); + } + +/* In executing the plotfile special, always emit escape sequences to place +the LN03 at the current position of the DVI file, even if it would seem +that the LN03 is already there. We do this in order to be able to emit a +newline at this point. Emitting a newline at this point keeps the line +length of the .ln3 file to <= 16 characters more than the line length of +the plotfile. */ + + fprintf(outfile,"\n\033[%dd\033[%d`",vv+voff,hh+hoff); + +/* Read stuff from the plotfile, write it to the output file. [[Could this +cause problem with one record being split into two?]] */ + + while((i = read(j,buf,512)) > 0) + fwrite(buf,i,1,outfile); + close(j); + +/* Now, set the variables ln3p, vpset and hh_old to indicate to the caller +that its recorded value of the current position of the LN03 is no longer +correct. This will make the caller issue absolute positioning commands +before doing any further output to the dvifile. */ + + ln3p = 0; + vpset = 0; + hh_old = 30000; + return(0); +} + + +/* Scan_fixnum reads an integer off sb[], starting at sbp and advancing sbp +to the first character past a valid integer. The integer is returned in i. +*/ + +int scan_fixnum(i) +long *i; +{ + int sbp_save; + + sbp_save = sbp; + *i = atol(&sb[sbp]); + while(isspace(sb[sbp])) sbp++; + if (sb[sbp] == '+' || sb[sbp] == '-') sbp++; + while (isdigit(sb[sbp])) sbp++; + return(sbp == sbp_save); +} + + +/* Scan_flonum reads a flonum (without exponential notation) off sb[], +starting at sbp and advancing sbp to the first character past a valid +flonum. The flonum is returned in x. [[Unfortunately, it is impossible to +use atof or sscanf to implement this function, because they don't allow +flonums like ".3" which don't have any digits before the decimal point.]] +*/ + +int scan_flonum(x) +float *x; +{ + float j,frac; + char negative; + int sbp_save; + + sbp_save = sbp; + negative = 0; + j = 0.0; + while (isspace(sb[sbp])) sbp++; + if (sb[sbp] == '-') { negative = 1; sbp++; } + else if (sb[sbp] == '+') sbp++; + while (isdigit(sb[sbp])) { + j = 10.0*j + ((float)(sb[sbp] - '0')); + sbp++; + } + if (sb[sbp] == '.') { + sbp++; + frac = 0.1; + while (isdigit(sb[sbp])) { + j += frac*((float)(sb[sbp] - '0')); + frac *= 0.1; + sbp++; + } + } + if (sbp != sbp_save) { + *x = negative ? (-j) : j; + return(0); + } else return(1); + +} + + +/* Scan_dimension tries to parse a dimension off sb[], advancing sbp over +what it can parse. The dimension is converted to pixels and returned in +val. If the unit isn't recognizable, scan_dimension prints an error +message, returns 1 and leaves val unchanged. */ + +int scan_dimension(val) +int *val; +{ + float x; + int i; + + x = 0.0; + scan_flonum(&x); + while (isspace(sb[sbp])) sbp++; + for (i = 0; i MAXPOINTS || !point_present[b1-1]) { + printf(special_mess,&sb[cstart]); + printf("\n Invalid point number (%d)",b1); + return(1); + } + if (b2 < 1 || b2 > MAXPOINTS || !point_present[b2-1]) { + printf(special_mess,&sb[cstart]); + printf("\n Invalid point number (%d)",b2); + return(1); + } + + halfw = w/2; + if (point_hh[b1-1] == point_hh[b2-1]) + do_rule(point_hh[b1-1]-halfw, + point_vv[b1-1],point_hh[b1-1]+w-1-halfw, + point_vv[b2-1]); + else if (point_vv[b1-1] == point_vv[b2-1]) + do_rule(point_hh[b1-1], + point_vv[b1-1]-halfw,point_hh[b2-1], + point_vv[b1-1]+w-1-halfw); + else { + printf(special_mess,&sb[cstart]); + printf("\n Can't connect along a diagonal."); + return(1); + } + return(0); +} + +int do_resetpoints () +{ + int a,b; + + a = 0; + scan_fixnum(&a); + b = 0; + scan_fixnum(&b); + + if (0 < a && a <= b && b <= MAXPOINTS) + for (; a <= b; a++) point_present[a] = 0; + else if (0 < a && a <= MAXPOINTS) + point_present[a] = 0; + return(0); +} diff --git a/dviware/ln03/rose/toppnft.pli b/dviware/ln03/rose/toppnft.pli new file mode 100644 index 0000000000..0ea9b4dd53 --- /dev/null +++ b/dviware/ln03/rose/toppnft.pli @@ -0,0 +1,654 @@ +%REPLACE true BY '1'B; +%REPLACE false BY '0'B; +%REPLACE maxnfonts BY 21; +%REPLACE maxtexfonts BY 100; +%REPLACE nblanks BY 0; +%REPLACE leftfirst BY 33; +%REPLACE leftlast BY 126; +%REPLACE rightfirst BY 161; +%REPLACE rightlast BY 254; + +/* This file contains those portions of LN03Topp that deal directly with +the font file format (.NFT files). It is under development... + +Development chronology: + +11/28/84: Initial version. Wrote COPY_CHAR. + +11/29/84: GOOD_OPENING. Second thoughts about whole interface. + Merge the three functions into one. + +Copyright (c) 1983, 1984 by Digital Equipment Corporation. */ + +/* The purpose of ADD_TXF_TO_LNF is to read an NFT file corresponding to +TeX font TXFNO and place its rasters into the output font buffer. It +returns the number of bytes by which the NFT file incremented the size of +the output file, or a negative value to indicate lossage. */ + +add_txf_to_lnf: PROCEDURE(lnfno,txfno,nftfname,outf) RETURNS(FIXED); + + DCL nftfname CHAR(*); + DCL (txfno,lnfno) FIXED; + DCL outf FILE; + + DCL (strip,frontstrip) EXTERNAL ENTRY (CHAR (*)) + RETURNS (CHAR (*)), + cvis EXTERNAL ENTRY (FIXED) RETURNS (CHAR (*)); + + DCL lastch(0:maxnfonts) FIXED GLOBALREF; + DCL chw(0:maxnfonts,0:255) FIXED GLOBALREF; + + DCL 1 txf BASED, + 2 nchs FIXED, + 2 chu(0:255) CHAR(1); + DCL txfa(0:maxtexfonts) PTR GLOBALREF; + +/* The buffer for the output fonts is currently of fixed size. Eventually +it should be possible to chain a lot of these together so output fonts of +unlimited size can be handled, subject only to virtual memory availability. +*/ + + %REPLACE obuflen BY 131120; + DCL lnf(0:obuflen) CHAR(1) STATIC; + DCL (ras_len,psize,lsize,msize) FIXED STATIC; + DCL using_r BIT STATIC; + +/* Out of laziness, we read the entire input NFT file into a big array and +then copy it. Obviously this is foolish; we should read it block by block +only, and even use "random reading" if the RMS file type is suitable. */ + + DCL nfta(0:obuflen) CHAR(1); + DCL (i,j,k,nftlen) FIXED; + + IF txfno < 0 | txfno > maxtexfonts | txfa(txfno) = Null() THEN + GOTO error_return; + IF lnfno < 0 | lnfno > maxnfonts THEN GOTO error_return; + + PUT SKIP EDIT ('Loading font ' || nftfname) (A); + + nftlen = 0; + CALL read_into_nfta; + +/* The NFT file comes to us in bytes. We need ways to understand it as +words or longwords. When we need to parse some bytes as something, we copy +them into the following overlaid variables. Note that unsigned quantities +still require fixing. */ + + DCL longword FIXED; + DCL chars CHAR(4) BASED (Addr(longword)); + +/* We make exactly one gratuitous test of NFT validity: the second longword +must be 'FONT'. */ + + IF nfta(4) ^= 'F' | nfta(5) ^= 'O' | nfta(6) ^= 'N' | nfta(7) ^= 'T' + THEN GOTO bad_format; + +/* We also have to check that there are a full 16 bytes of character +parameters. If there are fewer, we give up: it's too hard to figure out how +to give the missing ones reasonable values. Maybe in the next version... */ + + %REPLACE fnt$l_parameters_size BY 200; + CALL nft_copy(fnt$l_parameters_size); + IF longword ^= 16 THEN GOTO bad_format; + +/* Figure out where the character directory in the NFT file begins */ + + %REPLACE fnt$a_char_directory BY 120; + DCL chardir_offset FIXED; + +/* CHARDIR_OFFSET should always equal 480. But we read it off the file +anyway. */ + + CALL nft_copy(fnt$a_char_directory); + chardir_offset = longword; + IF chardir_offset <= 0 | chardir_offset > nftlen + THEN GOTO bad_format; + +/* Figure out what the lowest character in the NFT file is */ + + %REPLACE fnt$l_first_character BY 164; + DCL nft_first_ch FIXED; + + nft_first_ch = rank(nfta(fnt$l_first_character)); + +/* Now, determine if this is the first or last TXF which is being copied +into this file. */ + + DCL (first_txfc,last_txfc) FIXED; + DCL (first_txf,last_txf) BIT; + + first_txfc = -1; last_txfc = -1; + DO i = 0 TO 255; + IF txfa(txfno) -> chu(i) ^= byte(0) THEN DO; + IF first_txfc = -1 THEN first_txfc = rank(txfa(txfno) -> chu(i)); + last_txfc = rank(txfa(txfno) -> chu(i)); + END; + END; + + IF first_txfc = -1 | last_txfc = -1 THEN DO; + PUT SKIP EDIT ('LN03Topp internal error - empty TXF passed to ' || + 'ADD_TXF_TO_LNF') (A); + GOTO error_return; + END; + + first_txf = (first_txfc = leftfirst+nblanks); + last_txf = (last_txfc = lastch(lnfno)); + +/* If this is the first TXF, then we have to initialize the font buffer */ + + IF first_txf THEN DO; + using_r = false; + CALL initialize_lnf; + END; + +/* The initialization routine computes where the rasters begin in the +output buffer, puts in the blanks, etc. */ + + DCL (lnf_chardir,ras_beg) FIXED STATIC; + DCL ras_len_added FIXED; + + ras_len_added = 0; + +/* Now go through all the characters in the TeX font and copy them into the +right position */ + + DO i = 0 TO 255; + IF txfa(txfno) -> chu(i) ^= byte(0) + THEN DO; + j = rank(txfa(txfno) -> chu(i)); + IF ^using_r & j >= rightfirst THEN DO; + CALL write_lnf; + PUT SKIP EDIT (',') (A) FILE(outf); + using_r = true; + CALL initialize_lnf; + END; + CALL copy_char(i,j); + END; + END; + +/* If this is the last TXF for this LNF, write out the LNF. */ + + IF last_txf THEN CALL write_lnf; + + +/* What we have to return is the incremental amount of space that the TXF +takes up in the output font */ + + PUT EDIT (' with ' || cvis(ras_len_added+4*(txfa(txfno) -> nchs+nblanks)) + || ' bytes of rasters ') (A); + + RETURN(ras_len_added+4*(txfa(txfno) -> nchs+nblanks)); + +error_return: + RETURN(-1); + +rasters_too_big: + RETURN(-2); + +bad_format: + RETURN(-3); + + read_into_nfta: PROCEDURE; + + DCL nftf FILE; + DCL nftline CHAR(512) VARYING; + + ON ENDFILE (nftf) GOTO end_of_nftfile; + ON UNDEFINEDFILE (nftf) BEGIN; + PUT SKIP LIST('No such file:' || nftfname); + GOTO error_return; + END; + + nftlen = 0; + OPEN FILE (nftf) TITLE (nftfname) + ENVIRONMENT(Default_file_name('TEX$LN03DIR:AMR10.NFT')) + RECORD; + + DO WHILE (true); + + READ FILE(nftf) INTO (nftline); + IF nftlen+length(nftline) > obuflen THEN DO; + PUT SKIP EDIT ('NFT file ' || nftfname || ' too large') + (A); + GOTO error_return; + END; + DO i = 1 TO length(nftline); + nfta(nftlen+i-1) = substr(nftline,i,1); + END; + nftlen = nftlen+length(nftline); + + END; + + end_of_nftfile: + CLOSE FILE (nftf); + + END read_into_nfta; + +/* Copy the character corresponding to FROM out of NFTA and into the LNFR; +update the CHW array. */ + + copy_char: PROCEDURE (from,to); + DCL (from,to,i,j) FIXED; + DCL (def_start,rows,columns,quo,len) FIXED; + +/* First we need to determine where the character definition for FROM +begins in the NFTA array */ + + CALL nft_copy(chardir_offset+(from-nft_first_ch)*4); + def_start = longword; + +/* For the moment, if there is "no such character", we just stop. +Eventually we should substitute some blank character or something. */ + + IF def_start < chardir_offset | def_start > nftlen THEN + GOTO bad_format; + +/* Now we need to check that the rasters are uncompressed. */ + + IF nfta(def_start+17) ^= byte(129) THEN DO; + PUT SKIP EDIT ('Can''t handle compressed rasters') (A); + GOTO bad_format; + END; + +/* Fill in the CHW array. Gutenberg to pixel conversion is necessary (there +are 24 gutenbergs in a pixel), with rounding (hence the 12). */ + + CALL nft_copy(def_start+4); + chw(lnfno,to) = DIVIDE(longword+12,24,31); + +/* Because of the LN03's rounding algorithm, it is necessary also to +change the value being copied to the rounded value */ + + longword = 24*chw(lnfno,to); + nfta(def_start+4) = substr(chars,1,1); + nfta(def_start+5) = substr(chars,2,1); + nfta(def_start+6) = substr(chars,3,1); + nfta(def_start+7) = substr(chars,4,1); + +/* Now we need to compute the size of the rasters, and copy that number of +bytes into LNF as the case may be. */ + + rows = rank(nfta(def_start+20))+256*rank(nfta(def_start+21)); + columns = rank(nfta(def_start+22))+256*rank(nfta(def_start+23)); + +/* We have to update PSIZE, LSIZE and MSIZE to fill slots in the format. */ + + quo = DIVIDE(rows,8,31); + IF rows ^= quo*8 THEN quo = quo+1; + i = quo*columns; + lsize = lsize+quo*columns; + quo = DIVIDE(columns,8,31); + IF columns ^= quo*8 THEN quo = quo+1; + psize = psize+quo*rows; + IF i > quo*rows THEN msize = msize+i; ELSE msize = msize+quo*rows; + +/* Now do the actual copy */ + + IF MOD(rank(nfta(def_start+16)),2) = 0 THEN len = quo*rows; + ELSE len = i; + len = len+24; + DO i = 0 TO len-1; + lnf(ras_beg+ras_len+i) = nfta(def_start+i); + END; + longword = ras_len+ras_beg; + IF to <= leftlast THEN i = to-leftfirst; ELSE i = to-rightfirst; + lnf(lnf_chardir+4*i) = substr(chars,1,1); + lnf(lnf_chardir+4*i+1) = substr(chars,2,1); + lnf(lnf_chardir+4*i+2) = substr(chars,3,1); + lnf(lnf_chardir+4*i+3) = substr(chars,4,1); + ras_len = ras_len+len; + ras_len_added = ras_len_added+len; + IF MOD(ras_len,2) ^= 0 THEN DO; + ras_len = ras_len+1; + ras_len_added = ras_len_added+1; + END; + + END copy_char; + +/* It would be much more efficient if the following were a macro. Later on +maybe we'll do the macro expansion "by hand" in the code. */ + + nft_copy: PROCEDURE (index); + DCL index FIXED; + + substr(chars,1,1) = nfta(index); + substr(chars,2,1) = nfta(index+1); + substr(chars,3,1) = nfta(index+2); + substr(chars,4,1) = nfta(index+3); + + END nft_copy; + +/* write_lnf performs the last fixups to the lnf buffer and dumps it, +sixelized, into the OUTF. */ + + write_lnf: PROCEDURE; + + DCL preline CHAR(96); + DCL (i,j,k,rem,quo,ma) FIXED; + +/* We now have to fix a number of slots: size of file, length of rasters, +final 'FONT', psize, lsize, msize. */ + + longword = ras_beg+ras_len+8; + lnf(0) = substr(chars,1,1); + lnf(1) = substr(chars,2,1); + lnf(2) = substr(chars,3,1); + lnf(3) = substr(chars,4,1); + lnf(longword-8) = substr(chars,1,1); + lnf(longword-7) = substr(chars,2,1); + lnf(longword-6) = substr(chars,3,1); + lnf(longword-5) = substr(chars,4,1); + lnf(longword-4) = 'F'; + lnf(longword-3) = 'O'; + lnf(longword-2) = 'N'; + lnf(longword-1) = 'T'; + +/* Length of rasters */ + + %REPLACE fnt$l_char_definitions_length BY 156; + longword = ras_len; + lnf(fnt$l_char_definitions_length) = substr(chars,1,1); + lnf(fnt$l_char_definitions_length+1) = substr(chars,2,1); + lnf(fnt$l_char_definitions_length+2) = substr(chars,3,1); + lnf(fnt$l_char_definitions_length+3) = substr(chars,4,1); + + %REPLACE fnt$l_portrait_byte_count BY 228; + %REPLACE fnt$l_landscape_byte_count BY 232; + %REPLACE fnt$l_mixed_byte_count BY 236; + + longword = psize; + lnf(fnt$l_portrait_byte_count) = substr(chars,1,1); + lnf(fnt$l_portrait_byte_count+1) = substr(chars,2,1); + lnf(fnt$l_portrait_byte_count+2) = substr(chars,3,1); + lnf(fnt$l_portrait_byte_count+3) = substr(chars,4,1); + + longword = lsize; + lnf(fnt$l_landscape_byte_count) = substr(chars,1,1); + lnf(fnt$l_landscape_byte_count+1) = substr(chars,2,1); + lnf(fnt$l_landscape_byte_count+2) = substr(chars,3,1); + lnf(fnt$l_landscape_byte_count+3) = substr(chars,4,1); + + longword = msize; + lnf(fnt$l_mixed_byte_count) = substr(chars,1,1); + lnf(fnt$l_mixed_byte_count+1) = substr(chars,2,1); + lnf(fnt$l_mixed_byte_count+2) = substr(chars,3,1); + lnf(fnt$l_mixed_byte_count+3) = substr(chars,4,1); + +/* Now sixelize and write the contents of LNF. */ + + CALL sixelize_and_write(ras_beg+ras_len+8); + + sixelize_and_write: PROCEDURE (howmuch); + DCL (howmuch,quo,i,j) FIXED; + + quo = DIVIDE(howmuch,96,31); + IF howmuch > quo*96 THEN quo = quo+1; + + DO i = 1 TO quo; + DO j = 1 TO 96; + substr(preline,j,1) = lnf(96*(i-1)+j-1); + END; + CALL write_preline; + END; + + END sixelize_and_write; + + write_preline: PROCEDURE; + DCL sixel_line CHAR(128) VARYING; + DCL (ix,pllen) FIXED; + + pllen = 96; + + ix = 1; + sixel_line = copy('?',128); + DO i = 1 TO pllen BY 3; + DCL cha CHAR(1); + DCL chb BIT(8) BASED (addr(cha)); + DCL chc FIXED(7) BASED (addr(cha)); + DCL ocha CHAR(1); + DCL ochb BIT(8) BASED(addr(ocha)); + + chc = 0; + ocha = substr(preline,i,1); + substr(chb,1,6) = substr(ochb,3,6); + chc = chc + 63; + substr(sixel_line,ix,1) = cha; + ix = ix+1; + chc = 0; + substr(chb,5,2) = substr(ochb,1,2); + ocha = substr(preline,i+1,1); + substr(chb,1,4) = substr(ochb,5,4); + chc = chc + 63; + substr(sixel_line,ix,1) = cha; + ix = ix+1; + chc = 0; + substr(chb,3,4) = substr(ochb,1,4); + ocha = substr(preline,i+2,1); + substr(chb,1,2) = substr(ochb,7,2); + chc = chc + 63; + substr(sixel_line,ix,1) = cha; + ix = ix+1; + chc = 0; + substr(chb,1,6) = substr(ochb,1,6); + chc = chc + 63; + substr(sixel_line,ix,1) = cha; + ix = ix+1; + END; + PUT SKIP EDIT (sixel_line) (A) FILE(outf); + + END write_preline; + + END write_lnf; + +/* Initializes the LNF buffer. */ + + initialize_lnf: PROCEDURE; + + DCL (i,j) FIXED; + +/* The following array holds good values for bytes 0-479 of an LN03 format +font. */ + + DCL good_opening(0:511) FIXED STATIC INIT( + 104,38,0,0,70,79,78,84, + 1,0,0,0,31,0,0,0, + 20,0,0,0,85,48,48,48, + 48,48,48,48,48,50,83,75, + 48,48,71,71,48,48,48,49, + 85,90,90,90,90,48,50,70, + 48,48,48,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 181,7,9,0,11,0,14,0, + 0,0,0,0,104,0,0,0, + 252,0,0,0,124,0,0,0, + 100,1,0,0,120,1,0,0, + 224,1,0,0,4,0,0,0, + 88,3,0,0,0,0,0,0, + 92,3,0,0,48,0,0,0, + 92,3,0,0,0,0,0,0, + 140,3,0,0,212,34,0,0, + 140,3,0,0,33,0,0,0, + 126,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 32,0,0,0,168,0,0,0, + 16,0,0,0,94,0,0,0, + 0,0,0,0,94,0,0,0, + 0,0,0,0,94,0,0,0, + 0,0,0,0,236,25,0,0, + 54,25,0,0,14,27,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,2,0,0,0, + 7,0,0,0,92,3,0,0, + 7,0,0,0,99,3,0,0, + 16,0,0,0,106,3,0,0, + 16,0,0,0,122,3,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 10,0,0,0,244,1,0,0, + 0,0,24,0,16,0,0,0, + 16,0,0,0,1,0,1,0, + 1,0,1,0,0,0,1,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0, + 30,0,0,0,20,0,0,0, + 196,255,255,255,20,0,0,0, + 106,255,255,255,20,0,0,0, + 0,0,1,0,0,0,30,0, + 166,255,255,255,0,0,0,0, + 40,0,0,0,0,0,0,0, + 60,0,0,0,240,0,0,0, + 60,0,0,0,100,0,0,0, + 240,0,0,0,120,0,0,0, + 40,0,0,0,120,0,0,0, + 96,255,255,255,136,255,255,255, + 186,255,255,255,240,0,0,0, + 76,255,255,255,60,0,0,0, + 160,0,0,0,120,0,0,0, + 20,0,0,0,20,0,0,0, + 140,3,0,0,194,3,0,0, + 244,3,0,0,160,4,0,0, + 254,4,0,0,162,5,0,0, + 46,6,0,0,84,6,0,0); + + lnf_chardir = 480; /* Fixed */ + + /* Clear out LNF */ + + lnf = byte(0); + ras_len = 0; + psize = 0; + lsize = 0; + msize = 0; + + /* Copy the good values into LNF */ + + DO i = 0 TO 479; + lnf(i) = byte(good_opening(i)); + END; + + /* Set the last character if necessary */ + + IF lastch(lnfno) < leftlast & ^using_r + THEN lnf(fnt$l_first_character+4) = byte(lastch(lnfno)); + IF using_r + THEN lnf(fnt$l_first_character+4) = byte(lastch(lnfno)-rightfirst+ + leftfirst); + + /* Set the character counts */ + + %REPLACE fnt$l_infile_locators BY 204; + %REPLACE fnt$l_character_definitions BY 212; + %REPLACE fnt$l_raster_count BY 220; + + i = rank(lnf(fnt$l_first_character+4))- + rank(lnf(fnt$l_first_character))+1; + ras_beg = lnf_chardir + 4*i + 4 + 48; + lnf(fnt$l_infile_locators) = byte(i); + lnf(fnt$l_character_definitions) = byte(i); + lnf(fnt$l_raster_count) = byte(i); + +/* Set the font file id. The font family is dependent on the value of +LNFNO, U0000nn where nn is LNFNO possibly with a leading zero. The +character set is 1O if USING_R, otherwise the default from GOOD_OPENING. */ + + %REPLACE fnt$t_font_file_id BY 20; + + lnf(fnt$t_font_file_id+5) = byte(DIVIDE(lnfno,10,31)+rank('0')); + lnf(fnt$t_font_file_id+6) = byte(MOD(lnfno,10)+rank('0')); + IF using_r + THEN lnf(fnt$t_font_file_id+20) = 'O'; + +/* Set various offsets which are dependent on the number of characters in +the font file. */ + + %REPLACE fnt$a_subset_tables BY 128; + longword = lnf_chardir+4*i; + lnf(fnt$a_subset_tables) = substr(chars,1,1); + lnf(fnt$a_subset_tables+1) = substr(chars,2,1); + lnf(fnt$a_subset_tables+2) = substr(chars,3,1); + lnf(fnt$a_subset_tables+3) = substr(chars,4,1); + + longword = longword+4; + lnf(fnt$a_subset_tables+8) = substr(chars,1,1); + lnf(fnt$a_subset_tables+9) = substr(chars,2,1); + lnf(fnt$a_subset_tables+10) = substr(chars,3,1); + lnf(fnt$a_subset_tables+11) = substr(chars,4,1); + lnf(fnt$a_subset_tables+16) = substr(chars,1,1); + lnf(fnt$a_subset_tables+17) = substr(chars,2,1); + lnf(fnt$a_subset_tables+18) = substr(chars,3,1); + lnf(fnt$a_subset_tables+19) = substr(chars,4,1); + + longword = longword+48; + lnf(fnt$a_subset_tables+24) = substr(chars,1,1); + lnf(fnt$a_subset_tables+25) = substr(chars,2,1); + lnf(fnt$a_subset_tables+26) = substr(chars,3,1); + lnf(fnt$a_subset_tables+27) = substr(chars,4,1); + + %REPLACE fnt$a_char_definitions BY 160; + lnf(fnt$a_char_definitions) = substr(chars,1,1); + lnf(fnt$a_char_definitions+1) = substr(chars,2,1); + lnf(fnt$a_char_definitions+2) = substr(chars,3,1); + lnf(fnt$a_char_definitions+3) = substr(chars,4,1); + +/* Set up the string pool (48 bytes). */ + + DCL pool_beg FIXED; + + pool_beg = ras_beg-48; + + lnf(pool_beg) = '0'; + IF using_r THEN lnf(pool_beg+1) = '<'; ELSE lnf(pool_beg+1) = 'B'; + lnf(pool_beg+2) = byte(9); + lnf(pool_beg+3) = 'Z'; + lnf(pool_beg+4) = 'Z'; + lnf(pool_beg+5) = 'Z'; + lnf(pool_beg+6) = 'Z'; + + DO i = 1 TO 7; + lnf(pool_beg+7+i-1) = lnf(fnt$t_font_file_id+i-1); + END; + DO i = 1 TO 16; + lnf(pool_beg+7+7+i-1) = ' '; + END; + DO i = 1 TO 16; + lnf(pool_beg+7+7+16+i-1) = lnf(fnt$t_font_file_id+i-1); + END; + +/* Now make string descriptors point into the string pool. */ + %REPLACE fnt$a_char_set BY 260; + %REPLACE fnt$a_family_id BY 268; + %REPLACE fnt$a_family_name BY 276; + %REPLACE fnt$a_font_id BY 284; + + longword = pool_beg; + lnf(fnt$a_char_set) = substr(chars,1,1); + lnf(fnt$a_char_set+1) = substr(chars,2,1); + lnf(fnt$a_char_set+2) = substr(chars,3,1); + lnf(fnt$a_char_set+3) = substr(chars,4,1); + longword = pool_beg+7; + lnf(fnt$a_family_id) = substr(chars,1,1); + lnf(fnt$a_family_id+1) = substr(chars,2,1); + lnf(fnt$a_family_id+2) = substr(chars,3,1); + lnf(fnt$a_family_id+3) = substr(chars,4,1); + longword = pool_beg+7+7; + lnf(fnt$a_family_name) = substr(chars,1,1); + lnf(fnt$a_family_name+1) = substr(chars,2,1); + lnf(fnt$a_family_name+2) = substr(chars,3,1); + lnf(fnt$a_family_name+3) = substr(chars,4,1); + longword = pool_beg+7+7+16; + lnf(fnt$a_font_id) = substr(chars,1,1); + lnf(fnt$a_font_id+1) = substr(chars,2,1); + lnf(fnt$a_font_id+2) = substr(chars,3,1); + lnf(fnt$a_font_id+3) = substr(chars,4,1); + +/* Mercifully, all remaining font file slots that we can fill now are +already good as received from GOOD_OPENING. */ + + END initialize_lnf; + +END add_txf_to_lnf; -- cgit v1.2.3