/* Ditroff driver */ #ifndef lint static char *rcs = "$Header: nf.c.backup,v 1.2 88/02/03 08:52:15 simpson Exp $"; #endif /* $Log: nf.c.backup,v $ Revision 1.2 88/02/03 08:52:15 simpson added tpic support Revision 1.1 88/01/15 13:04:37 simpson initial release Revision 0.3 88/01/06 08:46:06 simpson corrected determination of charexists Revision 0.2 87/12/18 11:37:32 simpson added spline and ellipse support Revision 0.1 87/12/11 18:31:04 simpson beta test */ #include #include #include #include #include #include #include #include #include #include #include "fontnode.h" #include "fontinfo.h" #include "constants.h" #include "dev.h" #define FONTDIR "--FONTDIR--" #define DEVNAME "qms" /* Name given to -T option*/ /* Cast for accessing LocalInfo */ #define LI(p) ((struct LocalInfo *)p->localinfo) #define UNITWIDTH 10 /* Same as in DESC file */ typedef struct { double x, y; } COORDINATE; struct FontState { int pointsize; int font; }; struct Stack { struct FontState fontstate; int h, v; }; struct LocalInfo { char name[21]; /* Name of font */ int pointsize; int qmsheight; /* Height to give QMS printer */ int qmsbaseline; /* Baseline height to give QMS printer */ char pathname[81]; /* Full pathname in file system */ Boolean charexists[256];/* True if there is such a character */ short bitmapsize[2][256]; /* Width & height of each char bitmap */ short widths[256]; /* True width of each char in pixels */ long maptable[160]; /* Encoding of troff special sequences */ short maptablesize; /* # of entries in map table */ }; char EOFName[101]; /* Used by pkeofsocleanup & desceofsocleanup */ char *Whoami; /* argv[0] */ char *Model; /* Model of printer being used */ char Orientation = 'P'; char MountTable[51][21]; /* Max of 50 different fonts in table */ char *Xxxstring; /* String found in extension commands */ char *Pxxxstring; /* Pointer used by the lexical analyzer */ char PKDir[101]; /* Directory PK fonts are in */ int MaxBlocks; /* # of free blocks w/out ram or rom fonts */ int CurRamBlocks; /* # of blocks used by ram fonts */ int CurRomBlocks; /* # of blocks used by rom fonts */ int DownLoadFNum; /* Number of font currently being downloaded */ int Origin[2]; /* Origin of a postprocessor graph in pixels */ FILE *ReadLine; /* Debugger port tty */ struct sigvec SigStruct; struct FontNode *FontList; /* Contains all fonts & their attributes */ extern char *Host, *User; extern FILE *Accting; extern Boolean Accounting; extern int NumPages; main(argc, argv) int argc; char *argv[]; { Boolean found, loadnametable(), setnewid(); extern int optind; extern char *optarg; int *intptr, *tempintptr; int c; int romlist[41]; /* List of rom font #s */ int simplyexit(), callcleanup(); void qmsfntfree(), cleanup(), seteoffunction(), process(), troffeofsocleanup(), adjust(); PROFILE_VALUE *v, *getbindingvalue(); struct qmsram *raminfo; struct qmsfnt *fntinfo; struct fontnode *p; struct FontNode *createfontlist(); #ifdef DEBUG char *malloc(), orien; int i, fontno, size; FILE *f; struct fontnode *fn; #endif Whoami = argv[0]; while ((c = getopt(argc, argv, "x:y:n:h:w:l:i:")) != EOF) switch (c) { case 'x': if (atoi(optarg) > 2550) Orientation = 'L'; break; case 'h': Host = optarg; break; case 'n': User = optarg; break; case 'y': case 'w': case 'l': case 'i': break; default: exit(2); } SigStruct.sv_handler = simplyexit; SigStruct.sv_mask = 0; SigStruct.sv_onstack = 0; (void)sigvec(SIGINT, &SigStruct, (struct sigvec *)NULL); if (optind < argc) { Accounting = TRUE; if (!(Accting = fopen(argv[optind], "a"))) { fprintf(stderr, "%s: cannot open accounting file %s\n", Whoami, argv[optind]); Accounting = FALSE; } } if (!(v = getbindingvalue("model")) || v->class != PROFILE_STRING && v->class != PROFILE_OTHER) { fprintf(stderr, "%s: model binding missing or invalid in configuration file\n", Whoami); exit(2); } Model = v->value.s; fputs(QUICON, stdout); printf("%s^Z%s%s", CLEAROVERLAY, CLEARAOVERLAY, ENDCMD); fputs(QUICOFF, stdout); (void)fflush(stdout); if (!(v = getbindingvalue("readline")) || v->class != PROFILE_STRING && v->class != PROFILE_OTHER) { fprintf(stderr, "%s: readline binding missing or invalid in configuration file\n", Whoami); exit(2); } if (!(ReadLine = fopen(v->value.s, "r"))) { fprintf(stderr, "%s: could not open %s for reading\n", Whoami, v->value.s); exit(2); } #ifdef DEBUG raminfo = (struct qmsram *)malloc((unsigned)sizeof(struct qmsram)); raminfo->TR = 401; raminfo->AR = 387; raminfo->FR = 13; raminfo->OR = 0; #else qmsopen(fileno(stdout), fileno(ReadLine)); if (!(raminfo = qmsram())) { fprintf(stderr, "%s: could not get printer ram info\n", Whoami); exit(2); } #endif MaxBlocks = raminfo->AR + raminfo->FR; /* Save 5 block for filling with tpic */ MaxBlocks -= 5; #ifdef DEBUG fntinfo = (struct qmsfnt *)malloc((unsigned)sizeof(struct qmsfnt)); fntinfo->ram = fntinfo->rom = NULL; for (i = 0; i < 13; i++) { switch (i) { case 0: fontno = 521; orien = 'L'; break; case 1: fontno = 522; orien = 'L'; break; case 2: fontno = 523; orien = 'L'; break; case 3: fontno = 524; orien = 'L'; break; case 4: fontno = 1100; orien = 'P'; break; case 5: fontno = 1103; orien = 'P'; break; case 6: fontno = 1200; orien = 'P'; break; case 7: fontno = 1204; orien = 'P'; break; case 8: fontno = 1217; orien = 'L'; case 9: fontno = 7009; orien = 'P'; break; case 10: fontno = 7010; orien = 'P'; break; case 11: fontno = 7036; orien = 'P'; break; case 12: fontno = 7037; orien = 'P'; break; } fn = (struct fontnode *)malloc((unsigned)sizeof(struct fontnode)); fn->next = fntinfo->rom, fntinfo->rom = fn; fn->orientation = orien; fn->number = fontno; fn->bytes = 1024; /* Rom fonts occupy one block */ fn->version = '0'; fn->class = '1'; } /* For testing, ramfonts contains the already loaded fonts. It should * consist of lines containing two numbers and a letter, the first being * the font number, the second being the font size, and the third letter * is an orientation. The orientation should be the character immediately * after the size of the font. */ if (f = fopen("ramfonts", "r")) { /* File is optional for testing */ while (fscanf(f, "%d%d%c", &fontno, &size, &orien) == 3) { fn = (struct fontnode *)malloc((unsigned)sizeof(struct fontnode)); fn->next = fntinfo->ram, fntinfo->ram = fn; fn->orientation = orien; fn->number = fontno; fn->bytes = size; fn->version = '0'; fn->class = '1'; raminfo->AR -= CEILING(size / 1024.0); raminfo->FR += CEILING(size / 1024.0); } (void)fclose(f); } #else if (!(fntinfo = qmsfnt())) { fprintf(stderr, "%s: could not get printer font info\n", Whoami); exit(2); } #endif for (CurRomBlocks = 0, p = fntinfo->rom; p; p = p->next) CurRomBlocks += CEILING(p->bytes / (double)1024); CurRamBlocks = raminfo->FR - CurRomBlocks; /* Make an array of rom font #s */ for (p = fntinfo->rom, intptr = romlist; p; p = p->next) { for (tempintptr = romlist, found = FALSE; tempintptr < intptr; tempintptr++) if (*tempintptr == p->number) found = TRUE; if (!found) *intptr++ = p->number; } *intptr = 0; if (EQ(Model, "QMS800")) (void)sprintf(PKDir, "%s/wbfonts", FONTDIR); else (void)sprintf(PKDir, "%s/wwfonts", FONTDIR); if (!loadnametable(PKDir, romlist, 10001)) { fprintf(stderr, "%s: could not open font directory %s\n", Whoami, PKDir); exit(2); } FontList = createfontlist(fntinfo); qmsfntfree(fntinfo); if (!setnewid(Host, User)) { fprintf(stderr, "%s: could not change user id to %s\n", Whoami, User); exit(2); /* This is fatal bud */ } SigStruct.sv_handler = callcleanup; (void)sigvec(SIGINT, &SigStruct, (struct sigvec *)NULL); fputs(QUICON, stdout); if (Orientation == 'P') fputs(PORTRAIT, stdout); else fputs(LANDSCAPE, stdout); printf("%s%c%c", TEXTPROC, '0', '0'); printf("%s00000%05d", INITMARGVERT, Orientation == 'P' ? 11 * 1000 : (int)(8.5 * 1000)); printf("%s00000%05d", INITMARGHORZ, Orientation == 'P' ? (int)(8.5 * 1000) : 11 * 1000); printf("%s0000", CHARSPACING); fputs(FREEOFF, stdout); seteoffunction(troffeofsocleanup); process(); cleanup(FontList, SUCCEED); } /* Main routine that interprets the troff file */ void process() { int specialfont = 4; /* Loc of S font in mount table */ int c, d, n; int realhpxl = 0, realvpxl = 0, virthpxl = 0, virtvpxl = 0; /*Virt & real cursor locs - pxls*/ Boolean switchedtospecial = FALSE;/* T if we switch to Special font */ Boolean firstpage = TRUE, fontselected = FALSE, download(), makeroom(); char *malloc(), *getstring(), *push(), *pop(), *strcpy(), *s, *findpkfont(), extension[1000], *cgets(), *extractinteger(); void endoflist(), spline(); double radius, anglestart, angleend, decimalanglestart, a, b, decimalangleend, controlpoints[37][3], curvepoints[500][3]; COORDINATE start, end, center, cur, new; struct Stack *tempstack; struct FontNode *fonttolist(); struct FontNode *curnode = NULL; /* Current font ditroff has selected */ struct FontNode *oldnode; /* 4 saving when trying special font */ /* Current font ditroff has selected */ struct FontState current; /* For saving font when trying the special font */ struct FontState oldcurrent; current.font = current.pointsize = 0; bzero((char *)MountTable, sizeof(MountTable)); while (TRUE) { /* A non-returning function is called to exit */ switch (c = getnonblank(stdin)) { case 's': current.pointsize = getinteger(stdin); curnode = fonttolist(MountTable[current.font], current.pointsize); endoflist(&FontList, curnode); fontselected = FALSE; putchar('\r'); /* Ends the pass */ printf("%s00000%s", TAB, ENDCMD); printf("%s00000%s", JUSTIFYMARGIN, ENDCMD); realhpxl = realvpxl = 0; break; case 'f': current.font = getinteger(stdin); curnode = fonttolist(MountTable[current.font], current.pointsize); endoflist(&FontList, curnode); fontselected = FALSE; putchar('\r'); /* Ends the pass */ printf("%s00000%s", TAB, ENDCMD); printf("%s00000%s", JUSTIFYMARGIN, ENDCMD); realhpxl = realvpxl = 0; break; case 'c': /* Character at current location */ c = cgetchar(); /* If we couldn't find the font, don't print anything since we * don't know how to increment the real & virtual pixel locations. */ if (!curnode || !curnode->localinfo || !LI(curnode)->charexists[c]) { oldcurrent = current; current.font = specialfont; oldnode = curnode; curnode = fonttolist(MountTable[current.font], current.pointsize); if (curnode && curnode->localinfo && LI(curnode)->charexists[c]) { endoflist(&FontList, curnode); fontselected = FALSE; putchar('\r'); printf("%s00000%s", TAB, ENDCMD); printf("%s00000%s", JUSTIFYMARGIN, ENDCMD); realhpxl = realvpxl = 0; switchedtospecial = TRUE; } else { current = oldcurrent; curnode = oldnode; continue; } } adjust(&realhpxl, &realvpxl, virthpxl, virtvpxl); if (!(curnode->flags & LOADED)) { if (!makeroom(FontList, MaxBlocks, &CurRamBlocks, CurRomBlocks, curnode->blocksize)) { fprintf(stderr, "%s: could not free %d blocks for font %s\n", Whoami, curnode->blocksize, LI(curnode)->pathname); goto trytocontinue1; } if (!download(curnode)) goto trytocontinue1; realhpxl = realvpxl = 0; adjust(&realhpxl, &realvpxl, virthpxl, virtvpxl); } if (!fontselected) { printf("%s%d%s", DEFFONT, curnode->qmsnumber, ENDCMD); fontselected = TRUE; } /* For fonts with width but no bitmap, check the size of the * raster. The QMS will not print (or download) a character with * width and no bitmap so we must not print characters that are not * in the font. If you do, you will get the lowest character in * the font. */ trytocontinue1: if (LI(curnode)->bitmapsize[0][c] != 0 && LI(curnode)->bitmapsize[1][c] != 0) { if (c == '^' || c <= 32 || c >= 127) printf("%s%02X", SPECIAL, c); else (void)putchar(c); realhpxl += LI(curnode)->widths[c]; } if (switchedtospecial) { /* Switch back */ switchedtospecial = FALSE; current = oldcurrent; curnode = oldnode; fontselected = FALSE; } break; case 'C': s = getstring(stdin); if (!curnode || !curnode->localinfo || (c = lookup(LI(curnode)->maptable, LI(curnode)->maptablesize, s)) == -1 || !LI(curnode)->charexists[c = LI(curnode)->maptable[c] >> 24 & 0xFF]) { oldcurrent = current; current.font = specialfont; oldnode = curnode; curnode = fonttolist(MountTable[current.font], current.pointsize); if (curnode && curnode->localinfo && (c = lookup(LI(curnode)->maptable, LI(curnode)->maptablesize, s)) != -1 && LI(curnode)->charexists[c = LI(curnode)->maptable[c] >> 24 & 0xFF]) { endoflist(&FontList, curnode); fontselected = FALSE; putchar('\r'); printf("%s00000%s", TAB, ENDCMD); printf("%s00000%s", JUSTIFYMARGIN, ENDCMD); realhpxl = realvpxl = 0; switchedtospecial = TRUE; } else { current = oldcurrent; curnode = oldnode; continue; } } adjust(&realhpxl, &realvpxl, virthpxl, virtvpxl); if (!(curnode->flags & LOADED)) { if (!makeroom(FontList, MaxBlocks, &CurRamBlocks, CurRomBlocks, curnode->blocksize)) { fprintf(stderr, "%s: could not free %d blocks for font %s\n", Whoami, curnode->blocksize, LI(curnode)->pathname); goto trytocontinue2; } if (!download(curnode)) goto trytocontinue2; realhpxl = realvpxl = 0; adjust(&realhpxl, &realvpxl, virthpxl, virtvpxl); } if (!fontselected) { printf("%s%d%s", DEFFONT, curnode->qmsnumber, ENDCMD); fontselected = TRUE; } trytocontinue2: if (LI(curnode)->bitmapsize[0][c] != 0 && LI(curnode)->bitmapsize[1][c] != 0) { if (c == '^' || c <= 32 || c >= 127) printf("%s%02X", SPECIAL, c); else (void)putchar(c); realhpxl += LI(curnode)->widths[c]; } if (switchedtospecial) { /* Switch back */ switchedtospecial = FALSE; current = oldcurrent; curnode = oldnode; fontselected = FALSE; } break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': virthpxl += (c - '0') * 10 + (cgetchar() - '0'); c = cgetchar(); if (!curnode || !curnode->localinfo || !LI(curnode)->charexists[c]) { oldcurrent = current; current.font = specialfont; oldnode = curnode; curnode = fonttolist(MountTable[current.font], current.pointsize); if (curnode && curnode->localinfo && LI(curnode)->charexists[c]) { endoflist(&FontList, curnode); fontselected = FALSE; putchar('\r'); printf("%s00000%s", TAB, ENDCMD); printf("%s00000%s", JUSTIFYMARGIN, ENDCMD); realhpxl = realvpxl = 0; switchedtospecial = TRUE; } else { current = oldcurrent; curnode = oldnode; continue; } } adjust(&realhpxl, &realvpxl, virthpxl, virtvpxl); if (!(curnode->flags & LOADED)) { if (!makeroom(FontList, MaxBlocks, &CurRamBlocks, CurRomBlocks, curnode->blocksize)) { fprintf(stderr, "%s: could not free %d blocks for font %s\n", Whoami, curnode->blocksize, LI(curnode)->pathname); goto trytocontinue3; } if (!download(curnode)) goto trytocontinue3; realhpxl = realvpxl = 0; adjust(&realhpxl, &realvpxl, virthpxl, virtvpxl); } if (!fontselected) { printf("%s%d%s", DEFFONT, curnode->qmsnumber, ENDCMD); fontselected = TRUE; } trytocontinue3: if (LI(curnode)->bitmapsize[0][c] != 0 && LI(curnode)->bitmapsize[1][c] != 0) { if (c == '^' || c <= 32 || c >= 127) printf("%s%02X", SPECIAL, c); else (void)putchar(c); realhpxl += LI(curnode)->widths[c]; } if (switchedtospecial) { /* Switch back */ switchedtospecial = FALSE; current = oldcurrent; curnode = oldnode; fontselected = FALSE; } break; case 'p': /* Begin a new page */ (void)getinteger(stdin); /* Ignore page number */ realhpxl = realvpxl = virthpxl = virtvpxl = 0; printf("%s%05d%s", TAB, 0, ENDCMD); printf("%s%05d%s", JUSTIFYMARGIN, 0, ENDCMD); if (!firstpage) fputs(FORMFEED, stdout), NumPages++; else firstpage = FALSE; break; case 'w': /* Appears between words - ignore */ break; case 'H': /* Absolute horizontal */ virthpxl = getinteger(stdin); break; case 'h': /* Relative horizontal */ virthpxl += getinteger(stdin); break; case 'V': /* Absolute vertical */ virtvpxl = getinteger(stdin); break; case 'v': /* Relative vertical */ virtvpxl += getinteger(stdin); break; case 'n': /* At end of line */ (void)getinteger(stdin); /* Amount of space before line */ (void)getinteger(stdin); /* Amount of space after line */ break; case '{': /* Push stack */ tempstack = (struct Stack *)malloc(sizeof(struct Stack)); tempstack->fontstate.pointsize = current.pointsize; tempstack->fontstate.font = current.font; tempstack->h = virthpxl, tempstack->v = virtvpxl; (void)push((char *)&tempstack); break; case '}': /* Pop stack */ tempstack = (struct Stack *)pop(); current.pointsize = tempstack->fontstate.pointsize; current.font = tempstack->fontstate.font; virthpxl = tempstack->h, virtvpxl = tempstack->v; curnode = fonttolist(MountTable[current.font], current.pointsize); endoflist(&FontList, curnode); free((char *)tempstack); fontselected = FALSE; putchar('\r'); /* Ends the pass */ printf("%s00000%s", TAB, ENDCMD); printf("%s00000%s", JUSTIFYMARGIN, ENDCMD); realhpxl = realvpxl = 0; break; case '#': /* Comment */ while (cgetchar() != '\n') ; break; case 'D': /* Graphics drawing commands */ switch (c = cgetchar()) { case 'l': /* Line */ adjust(&realhpxl, &realvpxl, virthpxl, virtvpxl); start.x = virthpxl, start.y = virtvpxl; end.x = start.x + getinteger(stdin), end.y = start.y + getinteger(stdin); /* I don't know what this next character is. It is not * documented. */ while ((c = cgetchar()) != '\n'); ; fputs(VECTORON, stdout); printf("%s%05d:%05d", PENUP, ROUND(virthpxl/(double)RESOLUTION*1000), ROUND(virtvpxl/(double)RESOLUTION*1000)); printf("%s03", PENWIDTH); printf("%s%05d:%05d", PENDOWN, ROUND(end.x / RESOLUTION * 1000), ROUND(end.y / RESOLUTION * 1000)); fputs(VECTOROFF, stdout); printf("%s00000%s00000%s\r", TAB, JUSTIFYMARGIN, ENDCMD); virthpxl = ROUND(end.x), virtvpxl = ROUND(end.y); realhpxl = realvpxl = 0; break; case 'c': /* Circle */ d = getinteger(stdin); printf("%s%c%05d%c%05d%05d%03d%03d%02d%s", ARC, virthpxl+.5*d>=0.0?'+':'-', ROUND((virthpxl+.5*d)/RESOLUTION *1000.0), virtvpxl>=0?'+':'-', ROUND(virtvpxl/(double)RESOLUTION*1000.0), ROUND(.5*d/RESOLUTION*1000.0), 0,0,3,ENDCMD); printf("%s00000%s00000%s", TAB, JUSTIFYMARGIN, ENDCMD); realhpxl = realvpxl = 0; virthpxl += d; break; case 'e': /* Ellipse */ /* Ellipses satisfy the equation (x^2)/(a^2)+(y^2)/(b^2)=1 * where 'a' is the length of the semimajor axis and 'b' is * the length of the semiminor axis. We divide each quadrant * into 200 line segments and connect the line segments. */ a = getinteger(stdin) / 2.0 / RESOLUTION, /* In inches */ b = getinteger(stdin) / 2.0 / RESOLUTION; center.x = virthpxl / (double)RESOLUTION + a, center.y = virtvpxl / (double)RESOLUTION; cur.x = a, cur.y = 0.0; /* cur and new are */ fputs(VECTORON, stdout); /* relative to the origin */ printf("%s03", PENWIDTH); for (n = 1; n <= 200; n++, cur = new) { new.x = a*cos((n/200.0)*(PI/2.0)), new.y = b*sin((n/200.0)*(PI/2.0)); /* First quadrant */ printf("%s%05d:%05d", PENUP, ROUND((center.x+cur.x)*1000.0), ROUND((center.y+cur.y)*1000.0)); printf("%s%05d:%05d", PENDOWN, ROUND((center.x+new.x)*1000.0), ROUND((center.y+new.y)*1000.0)); /* Second quadrant */ printf("%s%05d:%05d", PENUP, ROUND((center.x-cur.x)*1000.0), ROUND((center.y+cur.y)*1000.0)); printf("%s%05d:%05d", PENDOWN, ROUND((center.x-new.x)*1000.0), ROUND((center.y+new.y)*1000.0)); /* Third quadrant */ printf("%s%05d:%05d", PENUP, ROUND((center.x-cur.x)*1000.0), ROUND((center.y-cur.y)*1000.0)); printf("%s%05d:%05d", PENDOWN, ROUND((center.x-new.x)*1000.0), ROUND((center.y-new.y)*1000.0)); /* Fourth quadrant */ printf("%s%05d:%05d", PENUP, ROUND((center.x+cur.x)*1000.0), ROUND((center.y-cur.y)*1000.0)); printf("%s%05d:%05d", PENDOWN, ROUND((center.x+new.x)*1000.0), ROUND((center.y-new.y)*1000.0)); } fputs(VECTOROFF, stdout); printf("%s00000%s00000\r", TAB, JUSTIFYMARGIN, ENDCMD); virthpxl += ROUND(2.0 * a * RESOLUTION); realhpxl = realvpxl = 0; break; case 'a': /* Arc */ start.x = virthpxl, start.y = virtvpxl; center.x = virthpxl + getinteger(stdin), center.y = virtvpxl + getinteger(stdin); end.x = center.x + getinteger(stdin), end.y = center.y + getinteger(stdin); radius = sqrt(pow(start.x - center.x, 2.0) + pow(start.y - center.y, 2.0)); /* Ditroff uses reverse cartesian coordinate system */ anglestart = atan2(start.x - center.x, center.y - start.y); angleend = atan2(end.x - center.x, center.y - end.y); anglestart -= PI / 2.0; angleend -= PI / 2.0; if (anglestart < 0) anglestart += 2 * PI; if (angleend < 0) angleend += 2 * PI; decimalanglestart = angleend / PI * 500.0; decimalangleend = anglestart / PI * 500.0; printf("%s%c%05d%c%05d%05d%03d%03d%02d%s", DECIMALARC, center.x>0?'+':'-', ROUND(center.x/RESOLUTION*1000.0), center.y>0?'+':'-', ROUND(center.y/RESOLUTION*1000.0), ROUND(radius / RESOLUTION * 1000.0), ROUND(decimalanglestart)>=1000?0:ROUND(decimalanglestart), ROUND(decimalangleend)>=1000?0:ROUND(decimalangleend), 3, ENDCMD); printf("%s00000%s00000%s", TAB, JUSTIFYMARGIN, ENDCMD); realhpxl = realvpxl = 0; virthpxl = ROUND(end.x), virtvpxl = ROUND(end.y); break; case '~': /* Squiggly line */ (void)cgets(extension); s = extension; n = 0; controlpoints[n][0] = virthpxl; controlpoints[n][1] = virtvpxl; controlpoints[n][2] = 0.0; while (s = extractinteger(s, &c)) { if (!(s = extractinteger(s, &d))) { fprintf(stderr, "%s: odd number of spline points given\n", Whoami); break; } n++; controlpoints[n][0] = controlpoints[n-1][0] + c; controlpoints[n][1] = controlpoints[n-1][1] + d; controlpoints[n][2] = 0.0; /* Ignore z axis */ } spline(controlpoints, n, curvepoints, 499, 3); /* 2nd degree */ fputs(VECTORON, stdout); printf("%s%05d:%05d", PENUP, ROUND(curvepoints[0][0]/RESOLUTION*1000.0), ROUND(curvepoints[0][1]/RESOLUTION*1000.0)); printf("%s03", PENWIDTH); for (c = 1; c <= 499; c++) printf("%s%05d:%05d", PENDOWN, ROUND(curvepoints[c][0]/RESOLUTION*1000.0), ROUND(curvepoints[c][1]/RESOLUTION*1000.0)); fputs(VECTOROFF, stdout); printf("%s00000%s00000%s\r", TAB, JUSTIFYMARGIN, ENDCMD); virthpxl = ROUND(curvepoints[n][0]), virtvpxl = ROUND(curvepoints[n][1]); realhpxl = realvpxl = 0; break; default: fprintf(stderr, "%s: invalid ditroff draw command %c\n", Whoami, c); fputs(FORMFEED, stdout), NumPages++; cleanup(FontList, 2); break; } break; case 'x': /* Device dependent commands */ switch (c = getnonblank(stdin)) { case 'i': /* Init - do nothing */ while (!isspace(cgetchar())) /* Find next blank */ ; break; case 'T': /* Name of typesetter. -T option */ if (!EQ(DEVNAME, s = getstring(stdin))) { fprintf(stderr,"%s: %s input given to ditroff filter\n", Whoami, s); cleanup(FontList, 2); } break; case 'r': /* Resolution */ while (!isspace(getchar())) ; if (getinteger(stdin) != RESOLUTION) { fprintf(stderr, "%s: ditroff input resolution != %d\n", Whoami, RESOLUTION); cleanup(FontList, 2); } /* Order of evaluation is immaterial */ if (getinteger(stdin) != 1 || getinteger(stdin) != 1) { fprintf(stderr, "%s: incorrect ditroff input increments\n", Whoami); cleanup(FontList, 2); } break; case 'p': /* Pause */ while (!isspace(cgetchar())) ; break; case 's': /* Stop */ while ((c = getchar()) != EOF) /* Standard I/O getchar */ ; callcleanup(); break; case 't': /* Trailer */ while (!isspace(cgetchar())) ; break; case 'f': /* Load font into mount table */ while (!isspace(cgetchar())) ; c = getinteger(stdin); s = getstring(stdin); (void)strcpy(MountTable[c], s); /* The special font must be named S */ if (EQ(s, "S")) specialfont = c; if (!findpkfont(s, 10)) /* Just check for font, any size. */ fprintf(stderr, "%s: could not find font %s at any magnification\n", Whoami, s); break; case 'H': /* Height - QMS can't do */ while (!isspace(cgetchar())) ; (void)getinteger(stdin); break; case 'S': /* Slant - QMS can't do */ while (!isspace(cgetchar())) ; (void)getinteger(stdin); break; case 'X': /* Extensions */ (void)cgets(extension); adjust(&realhpxl, &realvpxl, virthpxl, virtvpxl); Pxxxstring = Xxxstring = extension; Origin[0] = virthpxl, Origin[1] = virtvpxl; (void)yyparse(); fputs(QUICON, stdout); if (Orientation == 'P') fputs(PORTRAIT, stdout); else fputs(LANDSCAPE, stdout); printf("%s%c%c", TEXTPROC, '0', '0'); printf("%s00000%05d", INITMARGVERT, Orientation == 'P' ? 11 * 1000 : (int)(8.5 * 1000)); printf("%s00000%05d", INITMARGHORZ, Orientation == 'P' ? (int)(8.5 * 1000) : 11 * 1000); printf("%s0000", CHARSPACING); realhpxl = realvpxl = 0; break; default: fprintf(stderr, "%s: invalid ditroff x command %c\n", Whoami, c); fputs(FORMFEED, stdout), NumPages++; cleanup(FontList, 2); break; } break; default: fprintf(stderr, "%s: invalid ditroff command %c\n", Whoami, c); fputs(FORMFEED, stdout), NumPages++; cleanup(FontList, 2); break; } } } /* Returns a pointer to a node on the FontList with the matching name, * pointsize and orientation or NULL if not found. */ struct FontNode *getnodebyname(head, name, ptsize, or) struct FontNode *head; char *name; int ptsize; int or; { struct FontNode *p; for (p = head; p; p = p->next) if (p->localinfo && LI(p)->pointsize == ptsize && (p->flags & PORT ? 'P' : 'L') == or && EQ(LI(p)->name, name)) return p; return NULL; } /* Adds a new font to the font list. All the fields in the LocalInfo * structure are filled in. If the font is loaded on startup, the blocksize * is left as is; otherwise, the blocksize is estimated. */ struct FontNode *fonttolist(font, pointsize) char *font; int pointsize; { long fontstructoffset; /* Offset at beginning of font structure */ long funnycharoffset;/* Offset before funny_char_index_table */ long ftell(); int qmsfontnum, mag, ds, i, c, fontindex, encodecompare(); short size, index; char *fullfontpath, fontname[21], sfontname[21], *tail(), *malloc(), descfilename[81], *findpkfont(); Boolean extractinfo(); void seteoffunction(), pkeofsocleanup(), desceofsocleanup(), troffeofsocleanup(); FILE *f; struct dev devheader; struct font fontheader; struct FontNode *fn, *getfontnode(); struct FontInfo *fi, *getfontinfo(); if (strlen(font) == 0 || pointsize == 0) /* One of the two has not */ return NULL; /* been filled in yet. */ /* If this works, we don't need to search the font directory */ if (fn = getnodebyname(FontList, font, pointsize, Orientation)) return fn; if (!(fullfontpath = findpkfont(font, pointsize))) return NULL; /* Try to continue */ qmsfontnum = getnumfromtable(tail(fullfontpath)); assert(qmsfontnum > 0); if (!(fn = getfontnode(FontList, qmsfontnum, Orientation))) { bzero((char *)(fn = (struct FontNode *)malloc((unsigned) sizeof(struct FontNode))), sizeof(struct FontNode)); fn->next = FontList, FontList = fn; } if (fn->localinfo) /* This font is already on the list */ return fn; else bzero(fn->localinfo = malloc((unsigned)sizeof(struct LocalInfo)), sizeof(struct LocalInfo)); fn->flags |= RAM; if (Orientation == 'P') fn->flags |= PORT; fn->qmsnumber = qmsfontnum; (void)strcpy(LI(fn)->name, font); (void)strcpy(LI(fn)->pathname, fullfontpath); (void)extractinfo(tail(LI(fn)->pathname), fontname, sfontname, &ds, &mag); LI(fn)->pointsize = ROUND(mag / (double)RESOLUTION * UNITWIDTH); (void)strcpy(EOFName, fullfontpath); seteoffunction(pkeofsocleanup); if (!(fi = getfontinfo(fullfontpath, (EQ(Model, "QMS800") || EQ(Model, "QMS1500")) && Orientation == 'P' || (!EQ(Model, "QMS800") && !EQ(Model, "QMS1500")) && Orientation == 'L' ? 'X' : 'Y'))) { FontList = FontList->next; /* Bad PK file or not readable */ fprintf(stderr, "%s: could not open or bad PK file %s\n", Whoami, fullfontpath); free(fn->localinfo), free((char *)fn); return NULL; } if (!(fn->flags & PRELOADED)) fn->blocksize = fi->blocksize; seteoffunction(troffeofsocleanup); LI(fn)->qmsheight = fi->qmsheight; LI(fn)->qmsbaseline = fi->qmsbaseline; for (i = 0; i < 256; i++) { if (fi->chararray[i].tfm > 0 || (fi->chararray[i].w > 0 && fi->chararray[i].h > 0)) LI(fn)->charexists[i] = TRUE; else LI(fn)->charexists[i] = FALSE; LI(fn)->widths[i] = ROUND(fi->chararray[i].tfm * ((fi->ds / (double)FIX) / FIX) / PPI * RESOLUTION * ((double)LI(fn)->pointsize / UNITWIDTH)); LI(fn)->bitmapsize[0][i] = fi->chararray[i].w; LI(fn)->bitmapsize[1][i] = fi->chararray[i].h; } (void)sprintf(descfilename, "%s/%s", FONTDIR, "DESC.out"); LI(fn)->maptablesize = 0; if (!(f = fopen(descfilename, "r"))) { /* Couldn't access DESC.out! */ static Boolean printed = FALSE; if (!printed) { /* Only print error message once */ fprintf(stderr, "%s: could not open %s file \n", Whoami, descfilename); printed = TRUE; } return fn; } (void)strcpy(EOFName, descfilename); seteoffunction(desceofsocleanup); (void)cfread((char *)&devheader, sizeof(struct dev), 1, f); (void)cfread((char *)&size, sizeof(short), 1, f); while (size) (void)cfread((char *)&size, sizeof(short), 1, f); funnycharoffset = ftell(f); assert(devheader.nchtab <= 160); (void)fseek(f, (long)devheader.nchtab * sizeof(short) + devheader.lchname, 1); for (fontstructoffset = ftell(f); (i = fread((char *)&fontheader, sizeof(struct font), 1, f)) == 1 && !EQ(LI(fn)->name, fontheader.namefont); (void)fseek(f, 3L * fontheader.nwfont + 96 + devheader.nchtab, 1), fontstructoffset = ftell(f)) ; if (i != 1) { /* font not found */ (void)fclose(f); seteoffunction(troffeofsocleanup); return fn; } for (i = 0; i < devheader.nchtab; i++) { (void)fseek(f, fontstructoffset + sizeof(struct font) + 3 * fontheader.nwfont + 96 + i, 0); if ((fontindex = cgetc(f)) == 0) continue; (void)fseek(f, funnycharoffset + i * sizeof(short), 0); (void)cfread((char *)&index, sizeof(short), 1, f); (void)fseek(f, funnycharoffset + devheader.nchtab * sizeof(short) + index, 0); /* The special strings are encoded, put in the maptable and * sorted for fast lookup using a binary search. The encoding must * preserve the uniqueness of the strings. Assuming special * sequences are 3 bytes or less, we can put the bytes of the strings * in the 3 low order bytes of the maptable[] word and use * the high order byte to store the position in the font. */ LI(fn)->maptable[LI(fn)->maptablesize] = 0; while ((c = cgetc(f)) != '\0') LI(fn)->maptable[LI(fn)->maptablesize] = LI(fn)->maptable[LI(fn)->maptablesize] << 8 | c; LI(fn)->maptable[LI(fn)->maptablesize] &= 0xFFFFFF;/*Keep low 3 bytes*/ (void)fseek(f, fontstructoffset + sizeof(struct font) + 2 * fontheader.nwfont + fontindex, 0); LI(fn)->maptable[LI(fn)->maptablesize] |= cgetc(f) << 24; /* Put font*/ LI(fn)->maptablesize++; /* pos in top byte */ } (void)fclose(f); seteoffunction(troffeofsocleanup); qsort((char *)(LI(fn)->maptable), LI(fn)->maptablesize, sizeof(long), encodecompare); return fn; } /* Returns the full pathname of the font whose size most closely matches that * passed as a parameter. Returns NULL if it can't open the directory or it * cannot find the font at any magnification. The return value is static and * overwritten with each call. */ char *findpkfont(fontname, pointsize) char *fontname; int pointsize; { int closestnumber = MAX_INTEGER; int desiredmagnification = ROUND(RESOLUTION * pointsize / (double)UNITWIDTH); static char returnvalue[101]; DIR *dirp; struct direct *direntry; char dirfname[81], dirsfname[81]; Boolean extractinfo(); int dirdsize, dirmag; returnvalue[0] = '\0'; if (dirp = opendir(PKDir)) { for (direntry = readdir(dirp); direntry; direntry = readdir(dirp)) { if (direntry->d_namlen < 5 || !extractinfo(direntry->d_name, dirfname, dirsfname, &dirdsize, &dirmag) || !EQ(dirfname, fontname)) continue; if (ABS(dirmag - desiredmagnification) < closestnumber) { closestnumber = ABS(dirmag - desiredmagnification); (void)sprintf(returnvalue, "%s/%s", PKDir, direntry->d_name); } } closedir(dirp); } if (strlen(returnvalue) > 0) return returnvalue; return NULL; } /* Adjusts printer coordinates so they correspond to ditroff's coordinates. It * adjusts the real coordinates if necessary. */ void adjust(realh, realv, virth, virtv) int *realh, *realv, virth, virtv; { if (*realh != virth) { printf("%s%05d%s", TAB, ROUND(virth / (double)RESOLUTION * 1000.0), ENDCMD); *realh = virth; } if (*realv != virtv) { printf("%s%05d%s", JUSTIFYMARGIN, ROUND(virtv / (double)RESOLUTION * 1000.0), ENDCMD); *realv = virtv; } } /* Compares two encodings of troff special sequences */ int encodecompare(one, two) long *one, *two; { return (*one & 0xFFFFFF) == (*two & 0xFFFFFF) ? 0 : (*one & 0xFFFFFF) < (*two & 0xFFFFFF) ? -1 : 1; } /* Looks up a special sequence in the maptable and returns the position * found. It returns -1 if not found. This routine uses a binary search. */ int lookup(table, numvalues, key) long table[]; int numvalues; char *key; { int start = 0, end = numvalues - 1, midpoint; long keyencoded; /* An encoded version of the key */ char *p; for (p = key, keyencoded = 0; p && *p; p++) keyencoded = (keyencoded << 8) | *p; while (start <= end) { midpoint = (start + end) / 2; if ((keyencoded & 0xFFFFFF) == (table[midpoint] & 0xFFFFFF)) return midpoint; if ((keyencoded & 0xFFFFFF) > (table[midpoint] & 0xFFFFFF)) start = midpoint + 1; else end = midpoint - 1; } return -1; } /* Downloads a font */ Boolean download(fn) struct FontNode *fn; { struct CharInfo *ci; char *tail(), *strcpy(); void resetpkfile(), seteoffunction(), downloadpkeofsocleanup(), troffeofsocleanup(); int downloadinterrupt(), callcleanup(); int downloadtype, result, i, truebyteswide, bytestooutput, row, bytes; if (!fn || fn->flags & LOADED || !(fn->flags & RAM) || (fn->flags & PORT ? 'P' : 'L') != Orientation) return FALSE; resetpkfile(); downloadtype = ((EQ(Model, "QMS800") || EQ(Model, "QMS1500")) && Orientation == 'P' || (!EQ(Model, "QMS800") && !EQ(Model, "QMS1500")) && Orientation == 'L' ? 'X' : 'Y'); DownLoadFNum = fn->qmsnumber; (void)sigblock(SIGINT); /* Temporarily block interrupts */ SigStruct.sv_handler = downloadinterrupt; (void)sigvec(SIGINT, &SigStruct, (struct sigvec *)NULL); (void)strcpy(EOFName, LI(fn)->pathname); seteoffunction(downloadpkeofsocleanup); /* #defining ASCIILOAD causes ASCII characters to be used for the download * sequence. Twice as many characters must be sent but it is useful for * looking at the output when debugging. Also, you can actually see the * bitmaps in the output. ASCII loading must be used when you can't get * hardware flow control to work. Far out. */ #ifdef ASCIILOAD fputs(FREEFORM, stdout); #else fputs(EIGHTBITON, stdout); #endif printf("%s%05d%c0%-4.4s%03d%03dT", DOWNLOAD, fn->qmsnumber, Orientation, tail(LI(fn)->pathname), LI(fn)->qmsheight, LI(fn)->qmsbaseline); (void)sigsetmask(sigblock(0) & ~SIGINT); /* Unblock interrupts */ while ((result = getnextcharinfo(LI(fn)->pathname, downloadtype, &ci)) != 1) switch (result) { case 2: fprintf(stderr, "%s: could not open %s\n", Whoami, LI(fn)->pathname); return FALSE; case 3: fprintf(stderr, "%s: %s is not a PK file\n", Whoami, LI(fn)->pathname); return FALSE; case 4: fprintf(stderr, "%s: %s PK version is incorrect\n", Whoami, LI(fn)->pathname); return FALSE; case 0: /* Ok. Got a bitmap */ if (ci->h == 0 || ci->w == 0) continue; putchar(','); printf("%02X%03d", ci->cc, LI(fn)->widths[ci->cc]); if (downloadtype == 'X') { printf("%03d%03d", ci->h, ci->w); printf("%c%03d", LI(fn)->qmsbaseline - ci->voff >= 0 ? '+' : '-', ABS(LI(fn)->qmsbaseline - ci->voff)); printf("%c%03d", -ci->hoff >= 0 ? '+' : '-', ABS(-ci->hoff)); } else { printf("%03d%03d", ci->w, ci->h); printf("%c%03d", -ci->hoff >= 0 ? '+' : '-', ABS(ci->hoff)); printf("%c%03d", (LI(fn)->qmsheight - LI(fn)->qmsbaseline) - (ci->h - ci->voff) >= 0 ? '+' : '-', ABS((LI(fn)->qmsheight - LI(fn)->qmsbaseline) - (ci->h - ci->voff))); i = ci->w, ci->w = ci->h, ci->h = i; /* Swaparoo! */ } truebyteswide = ci->w + 7 >> 3; /* >> divides by 8 */ bytestooutput = (ci->w + 15 >> 4) * 2; /* >> divides by 16 */ #ifdef ASCIILOAD for (row = 0; row < ci->h; row++) { #else for (row = 0; row < ci->h; row++) #endif for (bytes = 0; bytes < bytestooutput; bytes++) { if (bytes == truebyteswide - 1) *(ci->bitmap + row * truebyteswide + bytes) &= 0xFF<<7-(ci->w+7)%8; if (bytes < truebyteswide) { i = *(ci->bitmap + row * truebyteswide + bytes) & 0xFF; #ifdef ASCIILOAD printf("%c%c", "0123456789ABCDEF"[i >> 4], "0123456789ABCDEF"[i & 0xF]); #else if (i == '^') printf("^^"); else (void)putchar(i); #endif } else #ifdef ASCIILOAD printf("00"); #else (void)putchar(0); #endif } #ifdef ASCIILOAD putchar('\n'); } #endif break; } /* End switch */ #ifdef ASCIILOAD printf("%s%s", ENDCMD, FREEOFF); #else printf("%s%s", ENDCMD, EIGHTBITOFF); #endif putchar('\r'); /* Ends the pass */ (void)sigblock(SIGINT); printf("%s00000%s", TAB, ENDCMD); printf("%s00000%s", JUSTIFYMARGIN, ENDCMD); SigStruct.sv_handler = callcleanup; (void)sigvec(SIGINT, &SigStruct, (struct sigvec *)NULL); seteoffunction(troffeofsocleanup); CurRamBlocks += fn->blocksize; fn->flags |= LOADED; (void)sigsetmask(sigblock(0) & ~SIGINT); return TRUE; } /* The following are routines called when a SIGINT is received or EOF is * unexpectedly encountered when reading a file. */ simplyexit() { exit(SUCCEED); } callcleanup() { void cleanup(); fputs(FORMFEED, stdout), NumPages++; cleanup(FontList, SUCCEED); /* Interrupting a program is not an error */ } void troffeofsocleanup() { fprintf(stderr, "%s: unexpected EOF when reading ditroff file\n", Whoami); fputs(FORMFEED, stdout), NumPages++; cleanup(FontList, 2); } void pkeofsocleanup() { fprintf(stderr, "%s: unexpected EOF when reading PK file %s\n", Whoami, EOFName); fputs(FORMFEED, stdout), NumPages++; cleanup(FontList, 2); } void desceofsocleanup() { fprintf(stderr, "%s: unexpected EOF when reading DESC.out file %s\n", Whoami, EOFName); fputs(FORMFEED, stdout), NumPages++; cleanup(FontList, 2); } downloadinterrupt() { fputs(ENDCMD, stdout); #ifdef ASCIILOAD fputs(FREEOFF, stdout); #else fputs(EIGHTBITOFF, stdout); #endif printf("%s%05d%c%s", DOWNLOAD, DownLoadFNum, Orientation, ENDCMD); callcleanup(); } void downloadpkeofsocleanup() { fputs(ENDCMD, stdout); #ifdef ASCIILOAD fputs(FREEOFF, stdout); #else fputs(EIGHTBITOFF, stdout); #endif printf("%s%05d%c%s", DOWNLOAD, DownLoadFNum, Orientation, ENDCMD); pkeofsocleanup(); } #include "xxx.c"