/* FPRINT - Fancy printer. Outputs a text file to the extended LA34 using the desired character font. Uses some external font file (???.FNT). A Christopher Hall fecit -- April, 1984 -added Formfeed processing -added skip at end to align forms for next run -Beware FPRINT doesn't check for "no space" during writes B.Eiben February 1985 */ #include #define DEBUG 0 /* Debug assembly switch */ #define DEBUG1 0 #define EOF 0 /* End-of-file return value */ #define FNTSIZ 128 /* Max number of chars in a font */ #define NUMMUL 50 /* Max number of multigraphs ditto */ #define LINLEN 80 /* Longest input line that can be processed */ #define FRESIZ 20000 /* Size of free space, in characters */ #define PARSIZ 200 /* Max number of characters not output yet */ #define OUTSEC 10 /* Number of sectors in output string */ #define MAXHGT 6 /* Maximum height of a character */ #define NUMFNT 5 /* Number of fonts that can be read in */ #define XTS 1 /* Flag: Don't follow this char with a space */ /* Calls to BIOS */ #define CHKTTY 2 /* See if there's TTY input */ #define TTYIN 3 /* Read TTY input */ #define LSTOUT 5 /* Send character to printer */ /* Directives that can get into linchr[] */ #define FNT 1 /* Set to the primary font */ #define AF1 2 /* Set to 1st alternate font */ #define AF2 3 /* Set to 2nd alternate font */ #define AF3 4 /* Set to 3rd alternate font */ #define AF4 5 /* Set to 4th alternate font */ #define TAB 9 /* Move to the next tab stop (must be 9) */ #define SPC 10 /* Change inter-character spacing */ #define CLEAR "\033[H\033[J" /* Clear screen and move home */ struct fnt { char *fstart; /* Start of freespace for this font */ char *fend; /* End of freespace for this font (+1) */ char fheight; /* Height of character (*6) */ char finspac; /* Number of spaces between characters */ char finlins; /* Number of lines between lines */ char *fchars[MAXHGT][FNTSIZ]; /* The character definitions */ char fchrlen[FNTSIZ]; /* Lengths of each character */ char fchrflg[FNTSIZ]; /* Characters' flags */ }; struct fnt font[NUMFNT]; /* Define areas for all the fonts */ int i,j; /* Scratch counters */ char length; /* Length of this character */ char height; /* Height of characters, for font in effect */ char inspac; /* Number of graphic spaces to put between chars */ char inlins; /* Number of extra lines between lines of text */ int rlwid; /* Real width of the line of output */ int lwid; /* Width of a line of output, including lmar */ int jcflag; /* Flag: Center next line (also, # spaces to lead) */ char jfflag; /* Flag: Justify next line left and right */ char flflag; /* Flag: Justify fill */ char prflag; /* Flag: This is the start of a paragraph */ char nbflag; /* Flag: Don't put a blank line between paragraphs */ char jfwds; /* Number of extra spaces to put between each word */ char jxwds,jxw; /* Number of words which get extra space, justifying */ int pind; /* Paragraph indent (in spaces) for justifys */ char jhead; /* Char to put at start of pps of justified text */ char lwords; /* Number of words in string to justify */ int lchars; /* Total length of characters ditto */ int positn; /* Position in the line being analyzed */ int lmar; /* Left margin set by user */ int tabpos[10]; /* Columns where tabs are set */ char tabtop; /* Index of highest tab in use */ char flags; /* Flags for this character */ int index; /* Index into character tables */ char *chrlen; /* Ditto lengths */ char *chrflg; /* Ditto flags */ char *mulnam[NUMMUL]; /* Names of multigraphs */ char multop; /* Index where to put new multigraph */ char linchr[PARSIZ]; /* Indices for the line that's being output */ char *lincpt; /* Pointer to where to add indices to linchr */ char *linstt; /* Pointer to start of indices of latest-read line */ int fntbas; /* Offset of base of current font */ int iobuf[BUFSIZ]; /* Buffer for reading font file */ int iobufi[BUFSIZ]; /* Buffer for reading text file */ int iobufo[BUFSIZ]; /* Buffer for writing printer output file */ char blnkln; /* Flag: latest line processed is blank */ char gotifl; /* Flag: got an input file */ char sttifl; /* Flag: got input file in run command */ char filstg[100]; /* String to hold a line from a font file */ char *fptr,fchr; /* Pointer into, character from, filstg */ char instg[100]; /* Input string */ char *iptr,ichr; /* Pointer into, character from, instg */ char outstg[OUTSEC*SECSIZ]; /* String of output text */ char *optr,ochr; /* Pointer into, character from, outstg */ char *topmem; /* Highest usable address */ char *freptr; /* Pointer into free space */ char frespc[FRESIZ]; /* Free space */ /* FRESPC must be the last external so it can expand */ /* Arbitrarily if necessary */ main(argc,argv) char **argv; { freptr = frespc; /* Init freespace pointer */ multop = 0; /* Clear count of multigraphs */ fntbas = gotifl = 0; /* Clear got-an-input-file flag */ rlwid = lwid = 1000; /* Start with a good line width */ printf("%sFont printer -- A Christopher Hall/B.E., 2/85\n",CLEAR); topmem = topofmem() - 400; if (argc == 2) if (getifl(argv[1])) sttifl = 1; /* Find input file */ if (fcreat("FPRINT.TXT",iobufo) == ERROR) { printf("\007Can't open output file\n"); exit(); } /* Now read from the user's file, if given, or ask him to type lines at the terminal. Translate them line-by-line to character indices, then output height lines of translation to the output file. */ linstt = linchr; /* Point to start of index array */ fputs("\033P1q----\n",iobufo); /* Get into graphics mode */ printf("Type lines to translate. End with \"Control-Z CRLF\"\n\n"); while (1) { /* Read lines from file or screen */ lincpt = linstt; /* Set up pointer for storing text */ if (gotifl) { /* Read input file line */ if (EOF == fgets(instg,iobufi)) { fclose(iobufi); /* Close the input file */ gotifl = 0; /* Say no longer using file */ *instg = 127; /* Don't output this time */ if (sttifl) break; } else { printf("*%s",instg); /* Echo the line */ for (iptr=instg-1; *++iptr != '\n';); *iptr = 0; /* Remove CRLF */ } } else { /* If no file, let him type longhand */ printf("*"); /* Prompt to show program is ready */ getline(instg,LINLEN); /* Read a line */ } if ((ichr = *instg) == 26) break; /* Exit on ^Z */ if (ichr == 127) continue; /* Just loop on EOF */ blnkln = (ichr) ? 0 : 1; /* Set flag if line blank, else clr */ strcat(instg," "); /* Add a trailing space */ transl(); /* Translate the line */ if (*linstt) { /* If any text was typed */ if ((jfflag == 1) && (jcflag == 0)) justif(); else { if (!blnkln) { if (jcflag) center(); /* Center it, if wanted */ typout(); /* Output the line */ } else typblnk(); /* Else just output a blank line */ } } } /* Loop to get another line */ if (linstt != linchr) { /* At end, purge buffer */ linstt = linchr; /* If there's anything there */ jxwds = jfwds = 0; /* Don't add any extra spacing */ typout(); } fputs("----\033\\\014\n\032",iobufo); /* Get out of graphics , end w. FF */ fclose(iobufo); /* Close the output file; done */ if (!sttifl){ printf("\nOutput to printer (y,n): "); iptr = gets(instg); if (toupper(*iptr) == 'Y') { /* Output to printer, if wanted */ if ((j = open("FPRINT.TXT",0)) == ERROR) { printf("\007Can't find FPRINT.TXT\n"); exit(); } while ((i = read(j,outstg,OUTSEC)) > 0) list(outstg,i); } } else{ if ((j = open("FPRINT.TXT",0)) == ERROR) { printf("\007Can't find FPRINT.TXT\n"); exit(); } else printf("\nNow Printing ...\n"); while ((i = read(j,outstg,OUTSEC)) > 0) list(outstg,i); } } /* GETFONT - Read the given font file from disk */ getfont(sfont,fnt) char *sfont; { int height,i,j,k,diff,base,hgt; char *sptr,*dptr; fptr = filstg; /* Copy filspec to filstg; end with null */ while (((fchr = *sfont++) != ' ') && (fchr != 0)) *fptr++ = fchr; *fptr = 0; strcat(filstg,".FNT"); /* Append the file type */ if (fopen(filstg,iobuf) == ERROR) { printf("\007Can't find font file %s\n",filstg); return; } getfnl(); /* First look for height field - read a line */ if (0 == (height = atoi(filstg))) { printf("\007Font doesn't begin with height\n"); return; } font[fnt].fheight = height; getfnl(); /* Read a line from the file */ if (0 == (font[fnt].finspac = atoi(filstg))) { printf("\007Font doesn't contain space-between-letters line\n"); return; } getfnl(); /* Read a line from the file */ if (0 == (font[fnt].finlins = atoi(filstg))) { printf("\007Font doesn't contain lines-between-lines line\n"); return; } /* If this font was previously defined and is not the last font in freespace, recover its space. */ #if DEBUG printf("Shuffle: freptr=%x Font end=%x\n",freptr,font[fnt].fend); #endif if (font[fnt].fstart) if (font[fnt].fend == freptr) freptr = font[fnt].fstart; else { base = sptr = font[fnt].fend; diff = dptr = font[fnt].fstart; diff = base - diff; while (sptr < freptr) *dptr++ = *sptr++; #if DEBUG printf("Shuffling. Old freptr=%x new=%x\n",freptr,dptr); printf("Diff=%d pointer difference=%d\n",diff,(freptr-dptr)); #endif freptr = dptr; /* Here, base==address above which to shuffle; diff==distance to shuffle */ for (i=0; i= base) { #if DEBUG printf("Shuffling font %d\n",i); #endif hgt = font[i].fheight; for (j=0; j topmem) { /* Error - no room */ printf("\007Not read--Not enough memory left\n"); freptr = font[fnt].fstart; font[fnt].fstart = 0; goto Done; } } } /* End processing for this character definition */ font[fnt].fend = freptr; Done: fclose(iobuf); /* Close the font file */ #if DEBUG printf("%d bytes of freespace in use\n",freptr-frespc); printf("Length of font: %d\n",(font[fnt].fend-font[fnt].fstart)); #endif } /* SETFNT - Set up the given font as the current one */ setfnt(fnt) { fntbas = fnt; /* Set up all the current-font variables */ height = font[fnt].fheight; inspac = font[fnt].finspac; inlins = font[fnt].finlins; chrlen = font[fnt].fchrlen; chrflg = font[fnt].fchrflg; } /* DIREC - Handle a line of formatting directives */ direc(dstg) char *dstg; { char dch; switch(toupper(*dstg)) { /* Switch on the directive */ case 'A': /* Use alternate font */ i = *(dstg+1) - '1'; if ((i >= NUMFNT) || ((i != 0) && (!font[i].fheight))) { printf("\007No such alternate font\n"); break; } if (lincpt != linchr) *lincpt++ = i + 1; else setfnt(i); /* Set up alt or save in string */ break; case 'B': /* Put blank line between paragraphs */ nbflag = 0; break; case 'C': /* Center the next line */ jcflag = 1; /* Set flag to do so */ break; case 'F': /* Set up a new font */ if ((i = *(dstg+1) - '1') >= NUMFNT) { printf("\007Bad font number\n"); break; } getfont(dstg+2,i); /* Read in the new font */ if (!i) setfnt(0); /* Make sure primary font's current */ break; case 'J': /* Justify line(s) */ switch(toupper(*(dstg+1))) { /* Switch on the 2nd char */ case 'H': /* Set justify header */ if ((jhead = *(dstg+2)) == 'N') jhead = 1; break; case 'U': /* Justify, no-fill */ flflag = 0; goto juscom; /* Join common justify code */ case 'F': /* Justify, fill */ flflag = 1; juscom: lwords = 0; /* Clear count of words */ jfflag = prflag = 1; lchars = pind; /* Init count of characters */ break; default: printf("\007"); } break; case 'L': /* Set inter-line spacing */ if (0 == (i = atoi(dstg+1))) printf("\007Bad inter-line spacing value\n"); else inlins = i; break; case 'M': /* Set left margin */ lmar = atoi(dstg+1) * chrlen[32]; if ((lwid = rlwid - lmar) <= 0) lwid = 1500; break; case 'N': /* No - something */ switch(toupper(*(dstg+1))) { /* Switch on the 2nd char */ case 'A': /* No alternate font */ if (lincpt != linchr) *lincpt++ = FNT; else setfnt(0); /* Set up font or save in string */ break; case 'B': /* No blank line between paragraphs */ nbflag = 1; break; case 'H': /* No justify header */ jhead = 0; break; case 'J': /* No justify */ jfflag = flflag = 0; /* Clear the justify flags */ break; case 'T': /* No tab (un-set it) */ if (toupper(*(dstg+3)) == 'S') { /* Clear all tabs */ tabtop = 0; break; } i = atoi(dstg+3); /* Else read the value */ for (j=0; j> 1; /* Save count of leading spaces */ if (jcflag < 0) jcflag = 0; /* Don't try it if negative */ if (fntbas != fb) setfnt(fb); /* Reset font, if changed */ } /* JUSTIF - Count the length of the line and the number of words. Set up jfwds with number of extra spaces to add between each word, jxwds with the number of words which get an extra space. For now, assumes there's only one space between each word. */ justif() { int lc; char *lincps; /* Pointer for storing characters */ char *linwrd; /* Start of the latest word */ int fb; fb = fntbas; /* Save starting fntbas */ jxwds = jfwds = 0; /* Clear number of spaces to add */ if (blnkln) { /* If blank line typed */ if (linstt != linchr) { /* If anything in buffer */ linstt = linchr; /* Output it */ typout(); } if (!nbflag) typblnk(); /* Follow with a blank line, maybe */ lwords = 0; /* Clear count of words */ prflag = 1; lchars = pind; /* Init count of characters */ return; /* Done */ } lincps = lincpt = linstt; /* Init pointers */ linstt = linchr; /* Point to start of buffer */ lc = lchars - chrlen[' '] - inspac - inspac; /* Set up char count */ while (*lincpt == ' ') lincpt++; /* Skip leading spaces */ linwrd = lincpt; /* Init pointers */ while (ichr = *lincpt++) { if (ichr < ' ') { /* Skip over directives */ *lincps++ = ichr; /* Save in output string */ if (chkdir(ichr,lincpt)) *lincps++ = *lincpt++; continue; /* Skip to end of while-loop */ } if (ichr == ' ') { /* If end of a word, count it */ do *lincps++ = ichr = *linwrd++; while (ichr != ' '); /* Copy entire word */ lwords++; /* Count one more word */ while (*lincpt == ' ') lincpt++; /* Skip extra spcs */ linwrd = lincpt; /* Say the next word starts here */ lc = lchars - inspac; /* Save count as of word start */ } lchars += chrlen[ichr] + inspac; /* Count length */ if (lchars >= lwid) { /* If text is long enough, output it */ *(lincps-1) = 0; /* End the output text with a null */ /* If filling, find number of extra spaces to put between each word (jfwds) plus number of words which get one more extra space (jxwds). */ if (flflag) { jxwds = (jfwds = lwid-lc) % --lwords; jfwds /= lwords; } if (jfwds > lwid) jfwds = jxwds = 0; if (fntbas != fb) setfnt(fb); /* Reset font, if chgd */ typout(); fb = fntbas; /* If font changed, make permanent */ lwords = lchars = 0; /* Clear counts of words, chars */ lincpt = linwrd; /* Continue looking, from that word */ lincps = linchr; /* Point to buffer's start */ } } *(linstt = lincps) = 0; /* Done - point to end of remaining text */ } /* TYPOUT - Output the sequences whose indices are in linchr[]. */ typout() { int h,i,j,k; char schr; char *cpt; int fb; int positn; fb = fntbas; /* Save starting fntbas */ for (h=0; h 9) { j++; k -= 10; } if (j) /* Output 10's, if any */ i = i - outseq(h,j+'0') - inspac; i = i - outseq(h,k+'0') - inspac; k = '.'; /* Follow with a dot */ } /* Output header */ i = i - outseq(h,k) - inspac; } } if (i > 0) while (i--) *optr++ = '?'; /* Output extra spaces */ lincpt = linstt; /* Point to start of indices */ while (schr = *lincpt++) { /* Loop to encode each character */ if (schr < ' ') { /* If got a directive */ if ((schr == TAB) && (tabtop > 0)) { k = 10000; /* Find smallest valid tab */ for (i=0; i positn) if (j < k) k = j; if (k != 10000) { /* If got setting, move */ k -= positn; positn += k; while (k--) *optr++ = '?'; } } lincpt += chkdir(schr,lincpt); continue; /* Skip rest of this while-loop */ } positn += outseq(h,schr) + inspac; /* Output char */ } if (*(optr-1) == '?') { /* If the line ends with blanks */ while (*--optr == '?'); /* Delete them */ optr++; } *optr = 0; /* End with a null */ if (optr != outstg) { /* If there's anything left */ optr = outstg; /* Point to start of string */ i = 1; /* Set up first character */ schr = *optr++; do { /* Group duplicates as a repeat */ ochr = *optr++; /* Get a character */ if (ochr == schr) i++; /* If duplicate, count it */ else { /* Else output saved character(s) */ if (i < 4) while (i--) putc(schr,iobufo); else fprintf(iobufo,"!%d%c",i,schr); i = 1; /* Set count back to 1 */ schr = ochr; /* Save new character */ } } while (ochr); } fputs("-\n",iobufo); /* Move to the next line */ } if (prflag && jfflag && jhead) if (jhead < 32) jhead++; prflag = jcflag = 0; /* Clear centering and indent flags */ if (inlins > 1) { /* At end do spacing between lines */ for (i=1; i 0) { spaces++; jxw--; } } if (!(chrflg[index] && XTS)) spaces += inspac; /* Space btwn chars */ while (spaces--) *optr++ = '?'; /* Output desired spaces */ return (chrlen[index]); /* Return the length of the character */ } /* GETFNL - Read a line from the file. Skip comments (line starts with ";;") Returns EOF if end of file found. Also, chr is set to the first character of the line and ptr is set to point to the start of the line. */ int getfnl() { while (1) { if (EOF == (fptr = fgets(filstg,iobuf))) return(EOF); if ((fchr = *fptr) == '\n') continue; /* Skip blank lines */ if (fchr != ';') break; /* Approve all but ";;" lines */ if (*(fptr+1) != ';') break; } return(!EOF); /* Say it's not EOF yet */ } /* CHKDIR - Check and act on directive from linchr. Call with directive character (dchr) and line pointer (dptr). Returns number of characters minus 1 in directive. */ int chkdir(dchr,dptr) char dchr, *dptr; { switch (dchr) { case FNT: /* Set up primary font */ case AF1: /* Set up alternate font */ case AF2: case AF3: case AF4: setfnt(dchr-1); break; case SPC: /* Change inter-character spacing */ inspac = *dptr; /* To the value next in the line */ return(1); /* Tell the caller to skip that value */ case TAB: /* Move to tab stop (handled in TYPOUT) */ default: /* There better not be anything else */ break; } return(0); /* Tell the caller not to skip anything */ } /* LIST - Output to printer secs*SECSIZ characters from text. */ list(text,secs) char *text; { char chr; int i; secs *= SECSIZ; /* Convert sector count into character count */ for (i=0; i