diff options
Diffstat (limited to 'dviware/quicspool/src/nf.c_backup')
-rw-r--r-- | dviware/quicspool/src/nf.c_backup | 1329 |
1 files changed, 1329 insertions, 0 deletions
diff --git a/dviware/quicspool/src/nf.c_backup b/dviware/quicspool/src/nf.c_backup new file mode 100644 index 0000000000..544b2cf126 --- /dev/null +++ b/dviware/quicspool/src/nf.c_backup @@ -0,0 +1,1329 @@ +/* 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 <stdio.h> +#include <signal.h> +#include <math.h> +#include <assert.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/dir.h> +#include <local/standard.h> +#include <local/qms.h> +#include <local/profile.h> +#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" |