summaryrefslogtreecommitdiff
path: root/dviware/ln03/rose/newffc.c
diff options
context:
space:
mode:
Diffstat (limited to 'dviware/ln03/rose/newffc.c')
-rw-r--r--dviware/ln03/rose/newffc.c1293
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
+
+}
+