/* 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 }