diff options
Diffstat (limited to 'dviware/ln03/rose/newffc.c')
-rw-r--r-- | dviware/ln03/rose/newffc.c | 1293 |
1 files changed, 1293 insertions, 0 deletions
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 <stdio.h> +#include <ctype.h> +#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<rows; i+=6) { + for (j=0; j<cols; j++) sixel_line[j] = 0; + for (j=i; j<rows && j<i+6; j++) { + m = (1<<(j-i)); + for (k=0; 8*k<cols; k++) { + rev_binrep(pxlbuf[rs+4*col_longs*j+k]); + for (l=0; l<8; l++) + if (visible_byte[l] == '8') + sixel_line[8*k+l] |= m; + } + } + output_sixel_line(cols); + } + printf("\033\\"); /* leave sixel mode */ + printf("\033[%d;1H",(rows/10)+1); /* position cursor after sixels */ + printf("\n Rasters begin at %d",rs); + } + + printf("\n %d rows, %d columns",rows,cols); + printf("\n width %.2f pixels",conv*wid); + printf("\n xoffset %d, yoffset %d",signed_pxl_word(ds+4), + signed_pxl_word(ds+6)); + +/* Now print out the rasters themselves. Compute k as the number of +longwords required to hold each row of rasters. */ + + if (how == 0) { + for (l=0; l<rows; l++) { + putc('\n',stdout); + for (m=0; 8*m<cols; m++) { + rev_binrep(pxlbuf[rs+4*col_longs*l+m]); + printf(visible_byte); + } + } + } +} + +/* Optimization of this to run-length encode the output isn't really +necessary at this stage. But it's fun to do anyway. */ + +output_sixel_line(length) +int length; +{ + int i,howmany,sbp; + char last,sixel_buf[802]; + + last = 0; + howmany = 0; + sbp = 0; + sixel_line[length] = 0; + for (i=0; i<=length; i++) { + if (sixel_line[i] == last) howmany++; + else { + if (howmany == 1) { + sixel_buf[sbp] = 63+last; + sixel_buf[sbp+1] = 63+last; + sbp += 2; + } else if (howmany > 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<rows; i+=6) { + for (j=0; j<columns; j++) sixel_line[j] = 0; + for (j=i; j<rows && j<i+6; j++) { + m = (1<<(j-i)); + for (k=0; 8*k<columns; k++) { + binrep(nftbuf[def_start+24+col_bytes*j+k]); + for (l=0; l<8; l++) + if (visible_byte[l] == '8') + sixel_line[8*k+l] |= m; + } + } + output_sixel_line(columns); + } + printf("\033\\"); /* leave sixel mode */ + printf("\033[%d;1H",(rows/10)+1); /* position cursor after sixels */ + } + + printf("\n Rasters begin at %d",def_start+24); + if (nftbuf[def_start+16] % 2 == 0) printf("\n stored portrait"); + else printf("\n stored landscape"); + printf("\n %d rows, %d columns",rows,columns); + printf("\n width %.2f pixels",((double)lcx.l)/24.0); + copy_from_nft(def_start+8); + xoff = lcx.l; + copy_from_nft(def_start+12); + yoff = lcx.l; + printf("\n xoffset %.2f, yoffset %.2f",-((double)xoff)/24.0, + -((double)yoff)/24.0); + +/* Now do the actual typing. */ + +/* writeln(i:1,' rows ',j:1,' columns'); */ + + if (how == 1) return(0); + for (l = 0; l < rows; l++) { + printf("\n"); + for (m = 0; m < col_bytes; m++) { + binrep(nftbuf[def_start+24+col_bytes*l+m]); + printf("%s",visible_byte); + } + } + + return(0); + +} + +/* Place the reversed binary representation of v in the visible_byte +array, using dots . for 0s and 8s for 1s. */ + +int 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[cnt] = '8'; + } +} + +GLOBAL char buffer_fixedp; + +/* The initnft command reads two character codes from the command line. If +both are acceptable, it initializes the nft buffer to hold reasonable +values for an nft file containing glyphs for codes between the two read +from the command line. */ + +int handle_initnft() { + + int c1,c2; + + skipb; + c1 = atoi(&inline[ilp]); + skipnb; skipb; + c2 = atoi(&inline[ilp]); + + if (c1 < 0 || c1 > 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<rows; l++) + for (m=0; m<n; m++) + nftbuf[nftlen+24+n*l+m] = rev_byte[pxlbuf[rs+4*k*l+m]]; + +/* Set the character locator, increment the nft length, and recompute +the three sizes. */ + + lcx.ul = nftlen; + copy_to_nft(480+4*(nft_next_code-nft_first)); + nftlen += 24+rows*n; + if (nftlen%2 == 1) nftlen++; + + i = rows*((cols+7)/8); + copy_from_nft(fnt__l_portrait_byte_count); + lcx.ul += i; + copy_to_nft(fnt__l_portrait_byte_count); + j = ((rows+7)/8)*cols; + copy_from_nft(fnt__l_landscape_byte_count); + lcx.ul += j; + copy_to_nft(fnt__l_landscape_byte_count); + copy_from_nft(fnt__l_mixed_byte_count); + lcx.ul += (i > 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<nftlen; i+=512) + if (write(nftf,&nftbuf[i],512) == -1) { + printf("\nError writing NFT file."); + close(nftf); + return(1); + } + + close(nftf); + return(1); + +} + +/* The wstr command writes the PXL buffer into a file. Under VMS, the file +has stream record format. This is the best format for storing TeX-style +"binary" files under VMS. */ + +int handle_wstr() +{ + + int strf; + char fs[FILESPECLEN]; + int jnam,jext; + unsigned long i,target; + + if (pxllen == 0) { + printf("\n There is no PXL file in memory."); + return(1); + } + + skipb; istart = ilp; skipnb; + inline[ilp] = '\0'; + + strcpy(fs,&inline[istart]); + find_filename(fs,&jnam,&jext); + if (fs[jext] == '\0') strcat(fs,".pxl"); + strf = creat(fs,0700); + if (strf == -1) { + printf("\nUnable to open PXL file %s",&inline[istart]); + return(1); + } + for (i=0; i<pxllen; i+=512) { + target = pxllen-i; + if (target > 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 + +} + |