|
|
1.1 ! root 1: /* ! 2: * ! 3: * dpost - troff post-processor for PostScript printers. ! 4: * ! 5: * A program that translates output generated by the device independent troff ! 6: * into PostScript. Much was borrowed from dimpress and dps (formally dlzw), ! 7: * and even though the code has changed, credit has to be given to Richard ! 8: * Flood for his early work on the PostScript driver. ! 9: * ! 10: * The big change is in the font table routines. The old binary format and ! 11: * makedev are gone. dpost and troff now read ASCII tables, and both skip ! 12: * unrecognized entries in the ASCII tables. That means problems, like where ! 13: * to put the real name of the PostScript font, have disappeared. The added ! 14: * flexibility means some overhead translating the ASCII tables, but the ! 15: * overhead isn't too bad. ! 16: * ! 17: * dpost can also now calculate a reasonably tight BoundingBox, which helps ! 18: * picture inclusion. The calculations, by default, are disabled. Couldn't ! 19: * justify the overhead for a comment, particularly one that's only needed ! 20: * occasionally. Use the -B option to get the comment. ! 21: * ! 22: * Output produced by dpost is still nonconforming. Definitions made in pages ! 23: * and exported to the job's global environment are the primary problem. It's ! 24: * an efficient approach, but means pages are not independent. Violations are ! 25: * bracketed by %%BeginGlobal and %%EndGlobal comments and can be pulled into ! 26: * the prologue by utility programs (like postreverse) that recognize the new ! 27: * comments. ! 28: * ! 29: * The program handles files formatted for any device, although the best and ! 30: * most efficient output is generated when the font and description files ! 31: * match PostScript's resident fonts. Emulation is relatively expensive, and ! 32: * can produce output files that are more than twice the size of the input ! 33: * files. ! 34: * ! 35: * Several different methods can be used to encode lines of text. What's done ! 36: * depends on the value assigned to encoding. Print time should decrease as ! 37: * encoding increases (up to MAXENCODING). Setting encoding to 3 (or higher) ! 38: * is not normally recommended. It's fast and produces very compact output, ! 39: * but rounding errors in troff's width tables can accumulate and lead to a ! 40: * ragged right margin. encoding can be changed on the command line using the ! 41: * -e option. ! 42: * ! 43: * PostScript fonts don't support all of troff's characters. Some are built ! 44: * by special PostScript procedures in directory *fontdir/devpost/charlib. ! 45: * The charlib approach is not meant to replace user defined fonts. It was ! 46: * a quick implementation designed to handle characters that aren't used ! 47: * often - charlib should not be overused! The charlib lookup is triggered ! 48: * when a character in a font table is assigned a code less than 32. ! 49: * ! 50: * Most defaults are set in the prologue, but can be changed by options. The ! 51: * -P option passes arbitrary PostScript into the setup section of the output ! 52: * file. It can be used to set (or change) values that can't be accessed by ! 53: * other options. For example, ! 54: * ! 55: * dpost -P'/useclippath false def' file > file.ps ! 56: * ! 57: * defines useclippath to be false. Everything passed through using the -P ! 58: * (-C to copy a file) options become part of the job's global environment. ! 59: * Definitions override defaults in the prologue. ! 60: * ! 61: * dpost expects to find the following procedures in the prologue: ! 62: * ! 63: * setup ! 64: * ! 65: * mark ... setup - ! 66: * ! 67: * Initialization procedure mainly responsible for setting up an ! 68: * appropriate coordinate system. ! 69: * ! 70: * pagesetup ! 71: * ! 72: * page pagesetup - ! 73: * ! 74: * Called at the start of each page, immediately after the page ! 75: * level save. Argument is the current page number. ! 76: * ! 77: * setdecoding ! 78: * ! 79: * num setdecoding - ! 80: * ! 81: * Select the decoding procedure used to print text strings encoded ! 82: * by dpost. num is whatever has been assigned to encoding. ! 83: * ! 84: * f ! 85: * ! 86: * size font f - ! 87: * ! 88: * Set the font and size used for character imaging. The font name ! 89: * argument is (normally) the name troff used. Mapping to the real ! 90: * PostScript font name is made using the fontname field in the ! 91: * ASCII width tables. ! 92: * ! 93: * m ! 94: * ! 95: * x y m - ! 96: * ! 97: * Move to point (x, y). Not used for positioning words in text ! 98: * strings. ! 99: * ! 100: * t ! 101: * ! 102: * mark text t mark ! 103: * ! 104: * Everything on the stack (up to the mark) is treated as a line ! 105: * of text to be decoded and printed. What's on the stack depends ! 106: * on encoding. ! 107: * ! 108: * w ! 109: * ! 110: * string x y w - ! 111: * ! 112: * Print a single word starting at position (x, y). Only used in ! 113: * the more complicated encoding schemes, like the ones based on ! 114: * widthshow. ! 115: * ! 116: * done ! 117: * ! 118: * Make sure the last page prints. Always called, but only needed ! 119: * when printing more than one page on each sheet of paper. ! 120: * ! 121: * output language from troff: ! 122: * all numbers are character strings ! 123: * ! 124: * sn size in points ! 125: * fn font as number from 1-n ! 126: * cx ascii character x ! 127: * Cxyz funny char xyz. terminated by white space ! 128: * Hn go to absolute horizontal position n ! 129: * Vn go to absolute vertical position n (down is positive) ! 130: * hn go n units horizontally (relative) ! 131: * vn ditto vertically ! 132: * nnc move right nn, then print c (exactly 2 digits!) ! 133: * (this wart is an optimization that shrinks output file size ! 134: * about 35% and run-time about 15% while preserving ascii-ness) ! 135: * Dt ...\n draw operation 't': ! 136: * Dl x y line from here by x,y ! 137: * Dc d circle of diameter d with left side here ! 138: * De x y ellipse of axes x,y with left side here ! 139: * Da x1 y1 x2 y2 arc counter-clockwise from current point (x, y) to ! 140: * (x + x1 + x2, y + y1 + y2) ! 141: * D~ x y x y ... wiggly line by x,y then x,y ... ! 142: * nb a end of line (information only -- no action needed) ! 143: * b = space before line, a = after ! 144: * p new page begins -- set v to 0 ! 145: * #...\n comment ! 146: * x ...\n device control functions: ! 147: * x i init ! 148: * x T s name of device is s ! 149: * x r n h v resolution is n/inch ! 150: * h = min horizontal motion, v = min vert ! 151: * x p pause (can restart) ! 152: * x s stop -- done forever ! 153: * x t generate trailer ! 154: * x f n s font position n contains font s ! 155: * x H n set character height to n ! 156: * x S n set slant to N ! 157: * ! 158: * Subcommands like "i" are often spelled out like "init". ! 159: * ! 160: */ ! 161: ! 162: #include <stdio.h> ! 163: #include <fcntl.h> ! 164: #include <signal.h> ! 165: #include <math.h> ! 166: #include <ctype.h> ! 167: #include <time.h> ! 168: ! 169: #include "comments.h" /* structuring comments */ ! 170: #include "gen.h" /* general purpose definitions */ ! 171: #include "path.h" /* prologue and a few other files */ ! 172: #include "ext.h" /* external variable declarations */ ! 173: #include "font.h" /* font table definitions */ ! 174: #include "dpost.h" /* a few definitions just used here */ ! 175: #include "motion.h" /* positioning macros */ ! 176: ! 177: char *prologue = DPOST; /* the PostScript prologue */ ! 178: char *colorfile = COLOR; /* color support */ ! 179: char *drawfile = DRAW; /* drawing routines */ ! 180: char *formfile = FORMFILE; /* multiple pages on each sheet */ ! 181: char *baselinefile = BASELINE; /* for text along curved baseline */ ! 182: ! 183: char *fontdir = FONTDIR; /* font table directories */ ! 184: char *hostfontdir = NULL; /* host resident font directory */ ! 185: ! 186: char *realdev = DEVNAME; /* use these width tables */ ! 187: char devname[20] = ""; /* job formatted for this device */ ! 188: int emulate = FALSE; /* TRUE if devname != realdev */ ! 189: Fontmap fontmap[] = FONTMAP; /* font translation table - emulation */ ! 190: ! 191: int copies = 1; /* copies of each sheet */ ! 192: int printed = 0; /* pages processed and printed */ ! 193: int formsperpage = 1; /* pages on each sheet of paper */ ! 194: int picflag = ON; /* enable/disable picture inclusion */ ! 195: ! 196: int encoding = DFLTENCODING; /* how text is translated to PostScript */ ! 197: int realencoding = DFLTENCODING; /* where we started */ ! 198: int maxencoding = MAXENCODING; /* max that users can select */ ! 199: ! 200: int landscape = FALSE; /* for BoundingBox calculations only */ ! 201: double magnification = 1.0; ! 202: double xoffset = 0.0; ! 203: double yoffset = 0.0; ! 204: ! 205: int smnt; /* special fonts start here */ ! 206: int devres; /* device resolution */ ! 207: int unitwidth; /* and unitwidth - from DESC file */ ! 208: ! 209: char downloaded[MAXCH+32]; /* status of charlib characters */ ! 210: ! 211: int nfonts = 0; /* number of font positions */ ! 212: int size = 10; /* current point size */ ! 213: int font = 0; /* and font position */ ! 214: int hpos = 0; /* where troff wants to be */ ! 215: int vpos = 0; ! 216: float lastw = 0; /* width of the last input character */ ! 217: int lastc = 0; /* its name (or index) - for charlib() */ ! 218: ! 219: int fontheight = 0; /* points from x H ... */ ! 220: int fontslant = 0; /* angle from x S ... */ ! 221: ! 222: int res; /* resolution assumed in input file */ ! 223: float widthfac = 1.0; /* for emulation = res/devres */ ! 224: ! 225: int lastsize = -1; /* for tracking printer's current size */ ! 226: int lastfont = -1; /* current font */ ! 227: float lastx = -1; /* and current position */ ! 228: int lasty = -1; ! 229: int lastend; /* where last character on this line was */ ! 230: ! 231: int seenpage = FALSE; /* expect fonts are now all mounted */ ! 232: int gotspecial = FALSE; /* append special fonts - emulation */ ! 233: ! 234: float pointslop = SLOP; /* horizontal error in points */ ! 235: int slop; /* and machine units */ ! 236: int rvslop; /* to extend box in reverse video mode */ ! 237: ! 238: int textcount = 0; /* strings accumulated so far */ ! 239: int stringstart = 0; /* where the next one starts */ ! 240: int spacecount = 0; /* spaces in current string */ ! 241: ! 242: Line line[MAXSTACK+3]; /* data about words accumulated so far */ ! 243: char strings[STRINGSPACE]; /* strings temporarily saved here */ ! 244: char *strptr; /* next free slot in strings[] */ ! 245: ! 246: FILE *tf = NULL; /* most output goes here */ ! 247: FILE *fp_acct = NULL; /* accounting file */ ! 248: ! 249: char *optnames = "a:c:e:m:n:o:p:tw:x:y:A:BC:J:F:H:L:OP:R:S:T:DI"; ! 250: ! 251: extern int gotcolor; /* read *colorfile when TRUE */ ! 252: extern Font fonts[]; /* data about every font we see */ ! 253: extern Font *mount[]; /* troff mounts fonts here */ ! 254: ! 255: /*****************************************************************************/ ! 256: ! 257: main(agc, agv) ! 258: ! 259: int agc; ! 260: char *agv[]; ! 261: ! 262: { ! 263: ! 264: /* ! 265: * ! 266: * Translates output from troff into PostScript. Input files must be formatted ! 267: * for the same device. Each input file begins on a new page. ! 268: * ! 269: */ ! 270: ! 271: argc = agc; /* global so everyone can use them */ ! 272: argv = agv; ! 273: ! 274: prog_name = argv[0]; /* for error messages */ ! 275: ! 276: init_signals(); /* interrupt handling */ ! 277: header(); /* structuring comments */ ! 278: options(); /* command line options */ ! 279: arguments(); /* translate the input files */ ! 280: done(); /* add trailing comments etc. */ ! 281: account(); /* job accounting data */ ! 282: ! 283: exit(x_stat); ! 284: ! 285: } /* End of main */ ! 286: ! 287: /*****************************************************************************/ ! 288: ! 289: init_signals() ! 290: ! 291: { ! 292: ! 293: int interrupt(); ! 294: ! 295: /* ! 296: * ! 297: * Make sure we handle interrupts. ! 298: * ! 299: */ ! 300: ! 301: if ( signal(SIGINT, interrupt) == SIG_IGN ) { ! 302: signal(SIGINT, SIG_IGN); ! 303: signal(SIGQUIT, SIG_IGN); ! 304: signal(SIGHUP, SIG_IGN); ! 305: } else { ! 306: signal(SIGHUP, interrupt); ! 307: signal(SIGQUIT, interrupt); ! 308: } /* End else */ ! 309: ! 310: signal(SIGTERM, interrupt); ! 311: ! 312: } /* End of init_signals */ ! 313: ! 314: /*****************************************************************************/ ! 315: ! 316: header() ! 317: ! 318: { ! 319: ! 320: int ch; ! 321: int old_optind = optind; ! 322: ! 323: /* ! 324: * ! 325: * Scan the option list for things needed now (e.g. prologue file), but could ! 326: * be changed from defaults. An attempt to follow to Adobe's 2.0 structuring ! 327: * conventions. ! 328: * ! 329: */ ! 330: ! 331: while ( (ch = getopt(argc, argv, optnames)) != EOF ) ! 332: if ( ch == 'L' ) ! 333: setpaths(optarg); ! 334: else if ( ch == 'B' ) ! 335: dobbox = TRUE; ! 336: else if ( ch == '?' ) ! 337: error(FATAL, ""); ! 338: ! 339: optind = old_optind; /* restored for options() */ ! 340: ! 341: fprintf(stdout, "%s", NONCONFORMING); ! 342: fprintf(stdout, "%s %s\n", VERSION, PROGRAMVERSION); ! 343: fprintf(stdout, "%s %s\n", DOCUMENTFONTS, ATEND); ! 344: fprintf(stdout, "%s %s\n", PAGES, ATEND); ! 345: if ( dobbox == TRUE ) ! 346: fprintf(stdout, "%s %s\n", BOUNDINGBOX, ATEND); ! 347: fprintf(stdout, "%s", ENDCOMMENTS); ! 348: ! 349: if ( cat(prologue) == FALSE ) ! 350: error(FATAL, "can't read %s", prologue); ! 351: ! 352: if ( DOROUND ) ! 353: cat(ROUNDPAGE); ! 354: ! 355: fprintf(stdout, "%s", ENDPROLOG); ! 356: fprintf(stdout, "%s", BEGINSETUP); ! 357: fprintf(stdout, "mark\n"); ! 358: ! 359: } /* End of header */ ! 360: ! 361: /*****************************************************************************/ ! 362: ! 363: options() ! 364: ! 365: { ! 366: ! 367: int ch; ! 368: ! 369: extern char *optarg; ! 370: extern int optind; ! 371: ! 372: /* ! 373: * ! 374: * Command line options - there are too many! ! 375: * ! 376: */ ! 377: ! 378: while ( (ch = getopt(argc, argv, optnames)) != EOF ) { ! 379: switch ( ch ) { ! 380: case 'a': /* aspect ratio */ ! 381: fprintf(stdout, "/aspectratio %s def\n", optarg); ! 382: break; ! 383: ! 384: case 'c': /* number of copies */ ! 385: copies = atoi(optarg); ! 386: fprintf(stdout, "/#copies %s store\n", optarg); ! 387: break; ! 388: ! 389: case 'e': /* select the encoding scheme */ ! 390: if ( (encoding = atoi(optarg)) < 0 || encoding > MAXENCODING ) ! 391: encoding = DFLTENCODING; ! 392: realencoding = encoding; ! 393: break; ! 394: ! 395: case 'm': /* magnification */ ! 396: magnification = atof(optarg); ! 397: fprintf(stdout, "/magnification %s def\n", optarg); ! 398: break; ! 399: ! 400: case 'n': /* forms per page */ ! 401: formsperpage = atoi(optarg); ! 402: fprintf(stdout, "%s %s\n", FORMSPERPAGE, optarg); ! 403: fprintf(stdout, "/formsperpage %s def\n", optarg); ! 404: break; ! 405: ! 406: case 'o': /* output page list */ ! 407: out_list(optarg); ! 408: break; ! 409: ! 410: case 'p': /* landscape or portrait mode */ ! 411: landscape = (*optarg == 'l') ? TRUE : FALSE; ! 412: if ( landscape == TRUE ) ! 413: fprintf(stdout, "/landscape true def\n"); ! 414: else fprintf(stdout, "/landscape false def\n"); ! 415: break; ! 416: ! 417: case 't': /* compatibility */ ! 418: break; ! 419: ! 420: case 'w': /* line width - for drawing */ ! 421: fprintf(stdout, "/linewidth %s def\n", optarg); ! 422: break; ! 423: ! 424: case 'x': /* shift horizontally */ ! 425: xoffset = atof(optarg); ! 426: fprintf(stdout, "/xoffset %s def\n", optarg); ! 427: break; ! 428: ! 429: case 'y': /* shift vertically */ ! 430: yoffset = atof(optarg); ! 431: fprintf(stdout, "/yoffset %s def\n", optarg); ! 432: break; ! 433: ! 434: case 'A': /* job accounting */ ! 435: case 'J': ! 436: if ( (fp_acct = fopen(optarg, "a")) == NULL ) ! 437: error(FATAL, "can't open accounting file %s", optarg); ! 438: break; ! 439: ! 440: case 'B': /* enable BoundingBox calculations */ ! 441: dobbox = TRUE; ! 442: fprintf(stdout, "/rotation 1 def\n"); ! 443: fprintf(stdout, "/gotpagebbox true def\n"); ! 444: break; ! 445: ! 446: case 'C': /* copy file to output */ ! 447: if ( cat(optarg) == FALSE ) ! 448: error(FATAL, "can't read %s", optarg); ! 449: break; ! 450: ! 451: case 'F': /* font table directory */ ! 452: fontdir = optarg; ! 453: break; ! 454: ! 455: case 'H': /* host resident font directory */ ! 456: hostfontdir = optarg; ! 457: break; ! 458: ! 459: case 'L': /* prologue file */ ! 460: setpaths(optarg); /* already been done in header() */ ! 461: break; ! 462: ! 463: case 'O': /* disable picture inclusion */ ! 464: picflag = OFF; ! 465: break; ! 466: ! 467: case 'P': /* copy string to output */ ! 468: fprintf(stdout, "%s\n", optarg); ! 469: break; ! 470: ! 471: case 'R': /* global or page level request */ ! 472: saverequest(optarg); ! 473: break; ! 474: ! 475: case 'S': /* horizontal position error */ ! 476: if ( (pointslop = atof(optarg)) < 0 ) ! 477: pointslop = 0; ! 478: break; ! 479: ! 480: case 'T': /* target printer */ ! 481: realdev = optarg; ! 482: break; ! 483: ! 484: case 'D': /* debug flag */ ! 485: debug = ON; ! 486: tf = stdout; ! 487: break; ! 488: ! 489: case 'I': /* ignore FATAL errors */ ! 490: ignore = ON; ! 491: break; ! 492: ! 493: case '?': /* don't know the option */ ! 494: error(FATAL, ""); ! 495: break; ! 496: ! 497: default: ! 498: error(FATAL, "missing case for option %c", ch); ! 499: break; ! 500: } /* End switch */ ! 501: } /* End while */ ! 502: ! 503: argc -= optind; ! 504: argv += optind; ! 505: ! 506: } /* End of options */ ! 507: ! 508: /*****************************************************************************/ ! 509: ! 510: setpaths(name) ! 511: ! 512: char *name; ! 513: ! 514: { ! 515: ! 516: char *path; ! 517: ! 518: /* ! 519: * ! 520: * Extends the -L option to permit modification of more than just the prologue ! 521: * file pathname. Syntax is -Lpath or -Lname:path. For debugging and development ! 522: * only! ! 523: * ! 524: */ ! 525: ! 526: for ( path = name; *path; path++ ) ! 527: if ( *path == ':' || *path == ' ' ) { ! 528: while ( *path == ':' || *path == ' ' ) path++; ! 529: break; ! 530: } /* End if */ ! 531: ! 532: if ( *path == '\0' ) /* didn't find "name:" prefix */ ! 533: path = name; ! 534: ! 535: if ( path == name || strncmp(name, "prologue", strlen("prologue")) == 0 ) ! 536: prologue = path; ! 537: else if ( strncmp(name, "draw", strlen("draw")) == 0 ) ! 538: drawfile = path; ! 539: else if ( strncmp(name, "color", strlen("color")) == 0 ) ! 540: colorfile = path; ! 541: else if ( strncmp(name, "form", strlen("form")) == 0 ) ! 542: formfile = path; ! 543: else if ( strncmp(name, "baseline", strlen("baseline")) == 0 ) ! 544: baselinefile = path; ! 545: ! 546: } /* End of setpaths */ ! 547: ! 548: /*****************************************************************************/ ! 549: ! 550: setup() ! 551: ! 552: { ! 553: ! 554: double t; ! 555: ! 556: /* ! 557: * ! 558: * Job and BoundingBox initialization. Called once from t_init() - must know ! 559: * the resolution before generating the PostScript call to setup. ! 560: * ! 561: */ ! 562: ! 563: writerequest(0, stdout); /* global requests e.g. manual feed */ ! 564: fprintf(stdout, "/resolution %d def\n", res); ! 565: fprintf(stdout, "setup\n"); ! 566: fprintf(stdout, "%d setdecoding\n", realencoding); ! 567: ! 568: if ( formsperpage > 1 ) { /* multiple pages */ ! 569: if ( cat(formfile) == FALSE ) ! 570: error(FATAL, "can't read %s", formfile); ! 571: fprintf(stdout, "%d setupforms\n", formsperpage); ! 572: } /* End if */ ! 573: ! 574: fprintf(stdout, "%s", ENDSETUP); ! 575: ! 576: if ( dobbox == TRUE ) { /* ctm[] - must agree with prologue */ ! 577: translate(pagewidth/2.0, pageheight/2.0); ! 578: if ( landscape == TRUE ) { ! 579: rotate(90.0); ! 580: t = pagewidth; ! 581: pagewidth = pageheight; ! 582: pageheight = t; ! 583: } /* End if */ ! 584: translate(-pagewidth/2.0, pageheight/2.0); ! 585: translate(72.0 * xoffset, -72.0 * yoffset); ! 586: scale(magnification, magnification); ! 587: scale(72.0/devres, 72.0/devres); ! 588: } /* End if */ ! 589: ! 590: } /* End of setup */ ! 591: ! 592: /*****************************************************************************/ ! 593: ! 594: arguments() ! 595: ! 596: { ! 597: ! 598: FILE *fp; ! 599: ! 600: /* ! 601: * ! 602: * Everything else is an input file. No arguments or '-' means stdin. ! 603: * ! 604: */ ! 605: ! 606: if ( argc < 1 ) ! 607: conv(stdin); ! 608: else ! 609: while ( argc > 0 ) { ! 610: if ( strcmp(*argv, "-") == 0 ) ! 611: fp = stdin; ! 612: else if ( (fp = fopen(*argv, "r")) == NULL ) ! 613: error(FATAL, "can't open %s", *argv); ! 614: conv(fp); ! 615: if ( fp != stdin ) ! 616: fclose(fp); ! 617: argc--; ! 618: argv++; ! 619: } /* End while */ ! 620: ! 621: } /* End of arguments */ ! 622: ! 623: /*****************************************************************************/ ! 624: ! 625: done() ! 626: ! 627: { ! 628: ! 629: int i; ! 630: int n; ! 631: ! 632: /* ! 633: * ! 634: * Force out the last page and add trailing comments. ! 635: * ! 636: */ ! 637: ! 638: fprintf(stdout, "%s", TRAILER); ! 639: fprintf(stdout, "done\n"); ! 640: fprintf(stdout, "%s %d\n", PAGES, printed); ! 641: ! 642: for ( i = 0, n = 0; i < MAXFONTS+1; i++ ) ! 643: if ( (fonts[i].flags & USED) && fonts[i].fontname != NULL ) { ! 644: if ( n++ == 0 ) ! 645: fprintf(stdout, "%s", DOCUMENTFONTS); ! 646: else if ( (n - 1) % 8 == 0 ) ! 647: fprintf(stdout, "\n%s", CONTINUECOMMENT); ! 648: fprintf(stdout, " %s", fonts[i].fontname); ! 649: } /* End if */ ! 650: if ( n > 0 ) ! 651: putc('\n', stdout); ! 652: ! 653: if ( dobbox == TRUE ) ! 654: writebbox(stdout, BOUNDINGBOX, 10); ! 655: ! 656: } /* End of done */ ! 657: ! 658: /*****************************************************************************/ ! 659: ! 660: account() ! 661: ! 662: { ! 663: ! 664: /* ! 665: * ! 666: * Accounting record to fp_acct - provided it's not NULL. ! 667: * ! 668: */ ! 669: ! 670: if ( fp_acct != NULL ) ! 671: fprintf(fp_acct, " print %d\n copies %d\n", printed, copies); ! 672: ! 673: } /* End of account */ ! 674: ! 675: /*****************************************************************************/ ! 676: ! 677: conv(fp) ! 678: ! 679: register FILE *fp; ! 680: ! 681: { ! 682: ! 683: register int c; ! 684: int m, n, n1, m1; ! 685: char str[50]; ! 686: ! 687: /* ! 688: * ! 689: * Read troff output from file fp and translate it into PostScript. The final ! 690: * t_page() call means input files start on a new page. ! 691: * ! 692: */ ! 693: ! 694: redirect(-1); /* do output only after a page command */ ! 695: lineno = 1; ! 696: ! 697: while ((c = getc(fp)) != EOF) { ! 698: switch (c) { ! 699: case '\n': /* just count this line */ ! 700: lineno++; ! 701: break; ! 702: ! 703: case ' ': /* when input is text */ ! 704: case 0: /* occasional noise creeps in */ ! 705: break; ! 706: ! 707: case '0': case '1': case '2': case '3': case '4': ! 708: case '5': case '6': case '7': case '8': case '9': ! 709: /* two motion digits plus a character */ ! 710: hmot((c-'0')*10 + getc(fp)-'0'); ! 711: put1(getc(fp)); ! 712: break; ! 713: ! 714: case 'c': /* single ascii character */ ! 715: put1(getc(fp)); ! 716: break; ! 717: ! 718: case 'C': /* special character */ ! 719: fscanf(fp, "%s", str); ! 720: put1(chindex(str)); ! 721: break; ! 722: ! 723: case 'N': /* character at position n */ ! 724: fscanf(fp, "%d", &m); ! 725: flushtext(); ! 726: oput(m); ! 727: break; ! 728: ! 729: case 'D': /* drawing functions */ ! 730: flushtext(); ! 731: getdraw(); ! 732: if ( size != lastsize ) ! 733: t_sf(); ! 734: switch ((c=getc(fp))) { ! 735: case 'p': /* draw a path */ ! 736: while (fscanf(fp, "%d %d", &n, &m) == 2) ! 737: drawline(n, m); ! 738: lineno++; ! 739: break; ! 740: ! 741: case 'l': /* draw a line */ ! 742: fscanf(fp, "%d %d %c", &n, &m, &n1); ! 743: drawline(n, m); ! 744: break; ! 745: ! 746: case 'c': /* circle */ ! 747: fscanf(fp, "%d", &n); ! 748: drawcirc(n); ! 749: break; ! 750: ! 751: case 'e': /* ellipse */ ! 752: fscanf(fp, "%d %d", &m, &n); ! 753: drawellip(m, n); ! 754: break; ! 755: ! 756: case 'a': /* counter-clockwise arc */ ! 757: case 'A': /* clockwise arc */ ! 758: fscanf(fp, "%d %d %d %d", &n, &m, &n1, &m1); ! 759: drawarc(n, m, n1, m1, c); ! 760: break; ! 761: ! 762: case 'q': /* spline without end points */ ! 763: drawspline(fp, 1); ! 764: lineno++; ! 765: break; ! 766: ! 767: case '~': /* wiggly line */ ! 768: drawspline(fp, 2); ! 769: lineno++; ! 770: break; ! 771: ! 772: default: ! 773: error(FATAL, "unknown drawing function %c", c); ! 774: break; ! 775: } /* End switch */ ! 776: break; ! 777: ! 778: case 's': /* use this point size */ ! 779: fscanf(fp, "%d", &size); /* ignore fractional sizes */ ! 780: break; ! 781: ! 782: case 'f': /* use font mounted here */ ! 783: fscanf(fp, "%s", str); ! 784: setfont(t_font(str)); ! 785: break; ! 786: ! 787: case 'H': /* absolute horizontal motion */ ! 788: fscanf(fp, "%d", &n); ! 789: hgoto(n); ! 790: break; ! 791: ! 792: case 'h': /* relative horizontal motion */ ! 793: fscanf(fp, "%d", &n); ! 794: hmot(n); ! 795: break; ! 796: ! 797: case 'w': /* word space */ ! 798: break; ! 799: ! 800: case 'V': /* absolute vertical position */ ! 801: fscanf(fp, "%d", &n); ! 802: vgoto(n); ! 803: break; ! 804: ! 805: case 'v': /* relative vertical motion */ ! 806: fscanf(fp, "%d", &n); ! 807: vmot(n); ! 808: break; ! 809: ! 810: case 'p': /* new page */ ! 811: fscanf(fp, "%d", &n); ! 812: t_page(n); ! 813: break; ! 814: ! 815: case 'n': /* end of line */ ! 816: while ( (c = getc(fp)) != '\n' && c != EOF ) ; ! 817: hgoto(0); ! 818: lineno++; ! 819: break; ! 820: ! 821: case '#': /* comment */ ! 822: while ( (c = getc(fp)) != '\n' && c != EOF ) ; ! 823: lineno++; ! 824: break; ! 825: ! 826: case 'x': /* device control function */ ! 827: devcntrl(fp); ! 828: lineno++; ! 829: break; ! 830: ! 831: default: ! 832: error(FATAL, "unknown input character %o %c", c, c); ! 833: done(); ! 834: } /* End switch */ ! 835: } /* End while */ ! 836: ! 837: t_page(-1); /* print the last page */ ! 838: flushtext(); ! 839: ! 840: } /* End of conv */ ! 841: ! 842: /*****************************************************************************/ ! 843: ! 844: devcntrl(fp) ! 845: ! 846: FILE *fp; ! 847: ! 848: { ! 849: ! 850: char str[50], buf[256], str1[50]; ! 851: int c, n; ! 852: ! 853: /* ! 854: * ! 855: * Interpret device control commands, ignoring any we don't recognize. The ! 856: * "x X ..." commands are a device dependent collection generated by troff's ! 857: * \X'...' request. ! 858: * ! 859: */ ! 860: ! 861: fscanf(fp, "%s", str); ! 862: ! 863: switch ( str[0] ) { ! 864: case 'f': /* load font in a position */ ! 865: fscanf(fp, "%d %s", &n, str); ! 866: fgets(buf, sizeof buf, fp); /* in case there's a filename */ ! 867: ungetc('\n', fp); /* fgets() goes too far */ ! 868: str1[0] = '\0'; /* in case there's nothing to come in */ ! 869: sscanf(buf, "%s", str1); ! 870: loadfont(n, str, str1); ! 871: break; ! 872: ! 873: case 'i': /* initialize */ ! 874: t_init(); ! 875: break; ! 876: ! 877: case 'p': /* pause */ ! 878: break; ! 879: ! 880: case 'r': /* resolution assumed when prepared */ ! 881: fscanf(fp, "%d", &res); ! 882: break; ! 883: ! 884: case 's': /* stop */ ! 885: case 't': /* trailer */ ! 886: flushtext(); ! 887: break; ! 888: ! 889: case 'H': /* char height */ ! 890: fscanf(fp, "%d", &n); ! 891: t_charht(n); ! 892: break; ! 893: ! 894: case 'S': /* slant */ ! 895: fscanf(fp, "%d", &n); ! 896: t_slant(n); ! 897: break; ! 898: ! 899: case 'T': /* device name - set emulating here */ ! 900: fscanf(fp, "%s", devname); ! 901: emulate = strcmp(devname, realdev) ? TRUE : FALSE; ! 902: break; ! 903: ! 904: case 'X': /* copy through - from troff */ ! 905: fscanf(fp, " %[^: \n]:", str); ! 906: fgets(buf, sizeof(buf), fp); ! 907: ungetc('\n', fp); ! 908: if ( strcmp(str, "PI") == 0 || strcmp(str, "PictureInclusion") == 0 ) ! 909: picture(buf); ! 910: else if ( strcmp(str, "InlinePicture") == 0 ) ! 911: inlinepic(fp, buf); ! 912: else if ( strcmp(str, "BeginPath") == 0 ) ! 913: beginpath(buf, FALSE); ! 914: else if ( strcmp(str, "DrawPath") == 0 ) ! 915: drawpath(buf, FALSE); ! 916: else if ( strcmp(str, "BeginObject") == 0 ) ! 917: beginpath(buf, TRUE); ! 918: else if ( strcmp(str, "EndObject") == 0 ) ! 919: drawpath(buf, TRUE); ! 920: else if ( strcmp(str, "NewBaseline") == 0 ) ! 921: newbaseline(buf); ! 922: else if ( strcmp(str, "DrawText") == 0 ) ! 923: drawtext(buf); ! 924: else if ( strcmp(str, "SetText") == 0 ) ! 925: settext(buf); ! 926: else if ( strcmp(str, "SetColor") == 0 ) { ! 927: newcolor(buf); ! 928: setcolor(); ! 929: } else if ( strcmp(str, "PS") == 0 || strcmp(str, "PostScript") == 0 ) { ! 930: flushtext(); ! 931: xymove(hpos, vpos); ! 932: fprintf(tf, "%s", buf); ! 933: } /* End else */ ! 934: break; ! 935: } /* End switch */ ! 936: ! 937: while ( (c = getc(fp)) != '\n' && c != EOF ) ; ! 938: ! 939: } /* End of devcntrl */ ! 940: ! 941: /*****************************************************************************/ ! 942: ! 943: loadfont(m, f, dir) ! 944: ! 945: int m; ! 946: char *f; ! 947: char *dir; ! 948: ! 949: { ! 950: ! 951: char path[150]; ! 952: ! 953: /* ! 954: * ! 955: * Load position m with font f. Font file pathname is *fontdir/dev*realdev/*f ! 956: * or *dir/*f, if dir isn't empty. Use mapfont() to replace the missing font ! 957: * if we're emulating another device, dir is empty, and the first mount fails. ! 958: * ! 959: */ ! 960: ! 961: if ( dir[0] == '\0' ) ! 962: sprintf(path, "%s/dev%s/%s", fontdir, realdev, f); ! 963: else sprintf(path, "%s/%s", dir, f); ! 964: ! 965: if ( mountfont(path, m) == -1 ) { ! 966: if ( dir[0] == '\0' ) { ! 967: sprintf(path, "%s/dev%s/%s", fontdir, realdev, mapfont(f)); ! 968: if ( mountfont(path, m) == -1 ) { ! 969: sprintf(path, "%s/dev%s/%s", fontdir, realdev, f); ! 970: error(FATAL, "can't load %s at %d", path, m); ! 971: } /* End if */ ! 972: } else error(FATAL, "can't load %s at %d", path, m); ! 973: } /* End if */ ! 974: ! 975: if ( smnt == 0 && mount[m]->specfont ) ! 976: smnt = m; ! 977: ! 978: if ( m == lastfont ) /* force a call to t_sf() */ ! 979: lastfont = -1; ! 980: ! 981: if ( m > nfonts ) { /* got more positions */ ! 982: nfonts = m; ! 983: gotspecial = FALSE; ! 984: } /* End if */ ! 985: ! 986: } /* End of loadfont */ ! 987: ! 988: /*****************************************************************************/ ! 989: ! 990: char *mapfont(name) ! 991: ! 992: char *name; ! 993: ! 994: { ! 995: ! 996: int i; ! 997: ! 998: /* ! 999: * ! 1000: * Map a missing font name into one that should be available. Only used when ! 1001: * we're emulating another device and the first mount fails. Consider deleting ! 1002: * this routine. ! 1003: * ! 1004: */ ! 1005: ! 1006: for ( i = 0; fontmap[i].name != NULL; i++ ) ! 1007: if ( strcmp(name, fontmap[i].name) == 0 ) ! 1008: return(fontmap[i].use); ! 1009: ! 1010: switch ( *++name ) { ! 1011: case 'I': return("I"); ! 1012: case 'B': return("B"); ! 1013: case 'X': return("BI"); ! 1014: default: return("R"); ! 1015: } /* End switch */ ! 1016: ! 1017: } /* End of mapfont */ ! 1018: ! 1019: /*****************************************************************************/ ! 1020: ! 1021: loadspecial() ! 1022: ! 1023: { ! 1024: ! 1025: /* ! 1026: * ! 1027: * Fix - later. ! 1028: * ! 1029: */ ! 1030: ! 1031: gotspecial = TRUE; ! 1032: ! 1033: } /* End of loadspecial */ ! 1034: ! 1035: /*****************************************************************************/ ! 1036: ! 1037: t_init() ! 1038: ! 1039: { ! 1040: ! 1041: char path[150]; ! 1042: static int initialized = FALSE; ! 1043: ! 1044: /* ! 1045: * ! 1046: * Finish initialization - just read an "x init" command. Assumes we already ! 1047: * know the input file resolution. ! 1048: * ! 1049: */ ! 1050: ! 1051: flushtext(); /* moved - for cat'ed troff files */ ! 1052: ! 1053: if ( initialized == FALSE ) { ! 1054: sprintf(path, "%s/dev%s/DESC", fontdir, realdev); ! 1055: if ( getdesc(path) == -1 ) ! 1056: error(FATAL, "can't open %s", path); ! 1057: nfonts = 0; ! 1058: gotspecial = FALSE; ! 1059: widthfac = (float) res /devres; ! 1060: slop = pointslop * res / POINTS + .5; ! 1061: rvslop = res * .025; ! 1062: setup(); ! 1063: initialized = TRUE; ! 1064: } /* End if */ ! 1065: ! 1066: hpos = vpos = 0; ! 1067: size = 10; ! 1068: reset(); ! 1069: ! 1070: } /* End of t_init */ ! 1071: ! 1072: /*****************************************************************************/ ! 1073: ! 1074: t_page(pg) ! 1075: ! 1076: int pg; ! 1077: ! 1078: { ! 1079: ! 1080: static int lastpg = 0; ! 1081: ! 1082: /* ! 1083: * ! 1084: * Finish the previous page and get ready for the next one. End page output ! 1085: * goes to /dev/null at the start of each input file. Start page output goes ! 1086: * to /dev/null at the end of each input file. ! 1087: * ! 1088: * Consider doing showpage after page level restore (as Adobe recommends). If ! 1089: * the order is changed use restore() and save(). forms.ps will likely also ! 1090: * need fixing. ! 1091: * ! 1092: */ ! 1093: ! 1094: if ( tf == stdout ) ! 1095: printed++; ! 1096: ! 1097: flushtext(); /* just in case */ ! 1098: ! 1099: fprintf(tf, "cleartomark\n"); ! 1100: fprintf(tf, "showpage\n"); ! 1101: fprintf(tf, "saveobj restore\n"); ! 1102: if ( dobbox == TRUE ) ! 1103: writebbox(tf, PAGEBOUNDINGBOX, 10); ! 1104: fprintf(tf, "%s %d %d\n", ENDPAGE, lastpg, printed); ! 1105: ! 1106: redirect(pg); ! 1107: ! 1108: fprintf(tf, "%s %d %d\n", PAGE, pg, printed+1); ! 1109: if ( dobbox == TRUE ) ! 1110: fprintf(tf, "%s %s\n", PAGEBOUNDINGBOX, ATEND); ! 1111: fprintf(tf, "/saveobj save def\n"); ! 1112: fprintf(tf, "mark\n"); ! 1113: writerequest(printed+1, tf); ! 1114: fprintf(tf, "%d pagesetup\n", printed+1); ! 1115: ! 1116: if ( encoding != realencoding ) ! 1117: fprintf(tf, "%d setdecoding\n", encoding); ! 1118: ! 1119: if ( gotcolor == TRUE ) ! 1120: setcolor(); ! 1121: ! 1122: lastpg = pg; /* for the next ENDPAGE comment */ ! 1123: hpos = vpos = 0; /* get ready for the next page */ ! 1124: reset(); /* force position and font stuff - later */ ! 1125: ! 1126: seenpage = TRUE; ! 1127: ! 1128: } /* End of t_page */ ! 1129: ! 1130: /*****************************************************************************/ ! 1131: ! 1132: t_font(s) ! 1133: ! 1134: char *s; ! 1135: ! 1136: { ! 1137: ! 1138: int n; ! 1139: ! 1140: /* ! 1141: * ! 1142: * Converts the string *s into an integer and checks to make sure it's a legal ! 1143: * font position. Also arranges to mount all the special fonts after the last ! 1144: * legitimate font (by calling loadspecial()), provided it hasn't already been ! 1145: * done. ! 1146: * ! 1147: */ ! 1148: ! 1149: n = atoi(s); ! 1150: ! 1151: if ( seenpage == TRUE ) { ! 1152: if ( n < 0 || n > nfonts ) ! 1153: error(FATAL, "illegal font position %d", n); ! 1154: ! 1155: if ( gotspecial == FALSE ) ! 1156: loadspecial(); ! 1157: } /* End if */ ! 1158: ! 1159: return(n); ! 1160: ! 1161: } /* End of t_font */ ! 1162: ! 1163: /*****************************************************************************/ ! 1164: ! 1165: setfont(m) ! 1166: ! 1167: int m; ! 1168: ! 1169: { ! 1170: ! 1171: /* ! 1172: * ! 1173: * Use the font mounted at position m. Bounds checks are probably unnecessary. ! 1174: * Changing the font and size used by the printer is handled in t_sf(). ! 1175: * ! 1176: */ ! 1177: ! 1178: if ( m < 0 || m > MAXFONTS ) ! 1179: error(FATAL, "illegal font %d", m); ! 1180: font = m; ! 1181: ! 1182: } /* End of setfont */ ! 1183: ! 1184: /*****************************************************************************/ ! 1185: ! 1186: t_sf() ! 1187: ! 1188: { ! 1189: ! 1190: Font *fpos; ! 1191: char temp[150]; ! 1192: ! 1193: /* ! 1194: * ! 1195: * Force a new font or size. Generates name definitions for fonts that haven't ! 1196: * been named, grabs host resident font files and keeps track of the fonts used ! 1197: * by this job. When necessary also adjusts the font's height and slant. Should ! 1198: * only be called immediately before printing a character. ! 1199: * ! 1200: */ ! 1201: ! 1202: if ( tf == stdout && mounted(font) ) { ! 1203: flushtext(); ! 1204: ! 1205: fpos = mount[font]; ! 1206: if ( (fpos->flags & USED) == 0 ) { ! 1207: if ( (fpos->flags & NAMED) == 0 && fpos->fontname != NULL ) { ! 1208: sprintf(temp, "/%s /%s def\n", fpos->name, fpos->fontname); ! 1209: exportstring(temp); ! 1210: fpos->flags |= NAMED; /* unnecessary */ ! 1211: } /* End if */ ! 1212: ! 1213: if ( hostfontdir != NULL ) { ! 1214: sprintf(temp, "%s/%s", hostfontdir, fpos->name); ! 1215: exportfile(temp); ! 1216: } /* End if */ ! 1217: } /* End if */ ! 1218: ! 1219: fprintf(tf, "%d %s f\n", size, fpos->name); ! 1220: if ( fontheight != 0 || fontslant != 0 ) ! 1221: fprintf(tf, "%d %d changefont\n", fontslant, (fontheight != 0) ? fontheight : size); ! 1222: ! 1223: lastfont = font; ! 1224: lastsize = size; ! 1225: fpos->flags |= USED; ! 1226: } /* End if */ ! 1227: ! 1228: } /* End of t_sf */ ! 1229: ! 1230: /*****************************************************************************/ ! 1231: ! 1232: t_charht(n) ! 1233: ! 1234: int n; ! 1235: ! 1236: { ! 1237: ! 1238: /* ! 1239: * ! 1240: * Set character height to n points. Disabled if n is 0 or the current size. ! 1241: * ! 1242: */ ! 1243: ! 1244: fontheight = (n == size) ? 0 : n; ! 1245: lastfont = -1; ! 1246: ! 1247: } /* End of t_charht */ ! 1248: ! 1249: /*****************************************************************************/ ! 1250: ! 1251: t_slant(n) ! 1252: ! 1253: int n; ! 1254: ! 1255: { ! 1256: ! 1257: /* ! 1258: * ! 1259: * Set slant to n degrees. Disable slanting if n is 0. ! 1260: * ! 1261: */ ! 1262: ! 1263: fontslant = n; ! 1264: lastfont = -1; ! 1265: ! 1266: } /* End of t_slant */ ! 1267: ! 1268: /*****************************************************************************/ ! 1269: ! 1270: xymove(x, y) ! 1271: ! 1272: int x, y; ! 1273: ! 1274: { ! 1275: ! 1276: /* ! 1277: * ! 1278: * Make the the printer and post-processor agree about the current position. ! 1279: * ! 1280: */ ! 1281: ! 1282: flushtext(); ! 1283: ! 1284: hgoto(x); ! 1285: vgoto(y); ! 1286: ! 1287: fprintf(tf, "%d %d m\n", hpos, vpos); ! 1288: ! 1289: lastx = hpos; ! 1290: lasty = vpos; ! 1291: ! 1292: } /* End of xymove */ ! 1293: ! 1294: /*****************************************************************************/ ! 1295: ! 1296: put1(c) ! 1297: ! 1298: register int c; ! 1299: ! 1300: { ! 1301: ! 1302: register int i; ! 1303: register int j; ! 1304: register int k; ! 1305: int code; ! 1306: int ofont; ! 1307: ! 1308: /* ! 1309: * ! 1310: * Print character c. ASCII character if c < 128, otherwise it's special. Look ! 1311: * for c in the current font, then in all others starting at the first special ! 1312: * font. Save c in lastc so it's available when oput() runs. Restore original ! 1313: * font before leaving. ! 1314: * ! 1315: */ ! 1316: ! 1317: lastc = c; /* charlib() needs name not code */ ! 1318: if ( (c -= 32) <= 0 ) ! 1319: return; ! 1320: ! 1321: k = ofont = font; ! 1322: ! 1323: if ( (i = onfont(lastc, k)) == -1 && smnt > 0 ) ! 1324: for ( k = smnt, j = 0; j < nfonts; j++, k = k % nfonts + 1 ) { ! 1325: if ( (i = onfont(lastc, k)) != -1 ) { ! 1326: setfont(k); ! 1327: break; ! 1328: } /* End if */ ! 1329: } /* End for */ ! 1330: ! 1331: if ( i != -1 && (code = mount[k]->wp[i].code) != 0 ) { ! 1332: lastw = widthfac * ((mount[k]->wp[i].wid * size + unitwidth/2) / unitwidth); ! 1333: oput(code); ! 1334: } /* End if */ ! 1335: ! 1336: if ( font != ofont ) ! 1337: setfont(ofont); ! 1338: ! 1339: } /* End of put1 */ ! 1340: ! 1341: /*****************************************************************************/ ! 1342: ! 1343: oput(c) ! 1344: ! 1345: int c; ! 1346: ! 1347: { ! 1348: ! 1349: double llx, lly, urx, ury; /* boundingbox corners */ ! 1350: ! 1351: /* ! 1352: * ! 1353: * Arranges to print the character whose code is c in the current font. All the ! 1354: * actual positioning is done here, in charlib(), or in the drawing routines. ! 1355: * ! 1356: */ ! 1357: ! 1358: if ( textcount > MAXSTACK ) /* don't put too much on the stack? */ ! 1359: flushtext(); ! 1360: ! 1361: if ( font != lastfont || size != lastsize ) ! 1362: t_sf(); ! 1363: ! 1364: if ( vpos != lasty ) ! 1365: endline(); ! 1366: ! 1367: starttext(); ! 1368: ! 1369: if ( ABS(hpos - lastx) > slop ) ! 1370: endstring(); ! 1371: ! 1372: if ( isascii(c) && isprint(c) ) ! 1373: switch ( c ) { ! 1374: case '(': ! 1375: case ')': ! 1376: case '\\': ! 1377: addchar('\\'); ! 1378: ! 1379: default: ! 1380: addchar(c); ! 1381: } /* End switch */ ! 1382: else if ( c > 040 ) ! 1383: addoctal(c); ! 1384: else charlib(c); ! 1385: ! 1386: if ( dobbox == TRUE ) { ! 1387: llx = lastx; ! 1388: lly = -(vpos + 0.5 * (devres * size / 72.0)); ! 1389: urx = lastx + lastw; ! 1390: ury = -(vpos - (devres * size / 72.0)); ! 1391: cover(llx, lly); ! 1392: cover(urx, ury); ! 1393: } /* End if */ ! 1394: ! 1395: lastx += lastw; ! 1396: ! 1397: } /* End of oput */ ! 1398: ! 1399: /*****************************************************************************/ ! 1400: ! 1401: starttext() ! 1402: ! 1403: { ! 1404: ! 1405: /* ! 1406: * Called whenever we want to be sure we're ready to start collecting characters ! 1407: * for the next call to PostScript procedure t (ie. the one that prints them). If ! 1408: * textcount is positive we've already started, so there's nothing to do. The more ! 1409: * complicated encoding schemes save text strings in the strings[] array and need ! 1410: * detailed information about the strings when they're written to the output file ! 1411: * in flushtext(). ! 1412: * ! 1413: */ ! 1414: ! 1415: if ( textcount < 1 ) { ! 1416: switch ( encoding ) { ! 1417: case 0: ! 1418: case 1: ! 1419: putc('(', tf); ! 1420: break; ! 1421: ! 1422: case 2: ! 1423: case 3: ! 1424: strptr = strings; ! 1425: spacecount = 0; ! 1426: line[1].str = strptr; ! 1427: line[1].dx = 0; ! 1428: line[1].spaces = 0; ! 1429: line[1].start = hpos; ! 1430: line[1].width = 0; ! 1431: break; ! 1432: ! 1433: case MAXENCODING+1: /* reverse video */ ! 1434: if ( lastend == -1 ) ! 1435: lastend = hpos; ! 1436: putc('(', tf); ! 1437: break; ! 1438: ! 1439: case MAXENCODING+2: /* follow a funny baseline */ ! 1440: putc('(', tf); ! 1441: break; ! 1442: } /* End switch */ ! 1443: ! 1444: textcount = 1; ! 1445: lastx = stringstart = hpos; ! 1446: } /* End if */ ! 1447: ! 1448: } /* End of starttext */ ! 1449: ! 1450: /*****************************************************************************/ ! 1451: ! 1452: flushtext() ! 1453: ! 1454: { ! 1455: ! 1456: int i; ! 1457: ! 1458: /* ! 1459: * ! 1460: * Generates a call to the PostScript procedure that processes all the text we've ! 1461: * accumulated - provided textcount is positive. ! 1462: * ! 1463: */ ! 1464: ! 1465: if ( textcount > 0 ) { ! 1466: switch ( encoding ) { ! 1467: case 0: ! 1468: fprintf(tf, ")%d t\n", stringstart); ! 1469: break; ! 1470: ! 1471: case 1: ! 1472: fprintf(tf, ")%d %d t\n", stringstart, lasty); ! 1473: break; ! 1474: ! 1475: case 2: ! 1476: *strptr = '\0'; ! 1477: line[textcount].width = lastx - line[textcount].start; ! 1478: if ( spacecount != 0 || textcount != 1 ) { ! 1479: for ( i = textcount; i > 0; i-- ) ! 1480: fprintf(tf, "(%s)%d %d", line[i].str, line[i].spaces, line[i].width); ! 1481: fprintf(tf, " %d %d %d t\n", textcount, stringstart, lasty); ! 1482: } else fprintf(tf, "(%s)%d %d w\n", line[1].str, stringstart, lasty); ! 1483: break; ! 1484: ! 1485: case 3: ! 1486: *strptr = '\0'; ! 1487: if ( spacecount != 0 || textcount != 1 ) { ! 1488: for ( i = textcount; i > 0; i-- ) ! 1489: fprintf(tf, "(%s)%d", line[i].str, line[i].dx); ! 1490: fprintf(tf, " %d %d %d t\n", textcount, stringstart, lasty); ! 1491: } else fprintf(tf, "(%s)%d %d w\n", line[1].str, stringstart, lasty); ! 1492: break; ! 1493: ! 1494: case MAXENCODING+1: ! 1495: fprintf(tf, ")%d ", stringstart); ! 1496: fprintf(tf, "%d %d drawrvbox ", lastend - rvslop, (int)(lastx + .5) + rvslop); ! 1497: fprintf(tf, "t\n", stringstart); ! 1498: lastend = (lastx + .5) + 2 * rvslop; ! 1499: break; ! 1500: ! 1501: case MAXENCODING+2: ! 1502: fprintf(tf, ")%d %d t\n", stringstart, lasty); ! 1503: break; ! 1504: } /* End switch */ ! 1505: } /* End if */ ! 1506: ! 1507: textcount = 0; ! 1508: ! 1509: } /* End of flushtext */ ! 1510: ! 1511: /*****************************************************************************/ ! 1512: ! 1513: endstring() ! 1514: ! 1515: { ! 1516: ! 1517: int dx; ! 1518: ! 1519: /* ! 1520: * ! 1521: * Horizontal positions are out of sync. End the last open string, adjust the ! 1522: * printer's position, and start a new string. Assumes we've already started ! 1523: * accumulating text. ! 1524: * ! 1525: */ ! 1526: ! 1527: switch ( encoding ) { ! 1528: case 0: ! 1529: case 1: ! 1530: fprintf(tf, ")%d(", stringstart); ! 1531: textcount++; ! 1532: lastx = stringstart = hpos; ! 1533: break; ! 1534: ! 1535: case 2: ! 1536: case 3: ! 1537: dx = hpos - lastx; ! 1538: if ( spacecount++ == 0 ) ! 1539: line[textcount].dx = dx; ! 1540: if ( line[textcount].dx != dx ) { ! 1541: *strptr++ = '\0'; ! 1542: line[textcount].width = lastx - line[textcount].start; ! 1543: line[++textcount].str = strptr; ! 1544: *strptr++ = ' '; ! 1545: line[textcount].dx = dx; ! 1546: line[textcount].start = lastx; ! 1547: line[textcount].width = 0; ! 1548: line[textcount].spaces = 1; ! 1549: } else { ! 1550: *strptr++ = ' '; ! 1551: line[textcount].spaces++; ! 1552: } /* End else */ ! 1553: lastx += dx; ! 1554: break; ! 1555: ! 1556: case MAXENCODING+1: ! 1557: fprintf(tf, ")%d(", stringstart); ! 1558: textcount++; ! 1559: lastx = stringstart = hpos; ! 1560: break; ! 1561: ! 1562: case MAXENCODING+2: ! 1563: flushtext(); ! 1564: starttext(); ! 1565: break; ! 1566: } /* End switch */ ! 1567: ! 1568: } /* End of endstring */ ! 1569: ! 1570: /*****************************************************************************/ ! 1571: ! 1572: endline() ! 1573: ! 1574: { ! 1575: ! 1576: /* ! 1577: * ! 1578: * The vertical position has changed. Dump any accumulated text, then adjust ! 1579: * the printer's vertical position. ! 1580: * ! 1581: */ ! 1582: ! 1583: flushtext(); ! 1584: ! 1585: if ( encoding == 0 || encoding == MAXENCODING+1 ) ! 1586: fprintf(tf, "%d %d m\n", hpos, vpos); ! 1587: ! 1588: lastx = stringstart = lastend = hpos; ! 1589: lasty = vpos; ! 1590: ! 1591: } /* End of endline */ ! 1592: ! 1593: /*****************************************************************************/ ! 1594: ! 1595: addchar(c) ! 1596: ! 1597: int c; ! 1598: ! 1599: { ! 1600: ! 1601: /* ! 1602: * ! 1603: * Does whatever is needed to add character c to the current string. ! 1604: * ! 1605: */ ! 1606: ! 1607: switch ( encoding ) { ! 1608: case 0: ! 1609: case 1: ! 1610: putc(c, tf); ! 1611: break; ! 1612: ! 1613: case 2: ! 1614: case 3: ! 1615: *strptr++ = c; ! 1616: break; ! 1617: ! 1618: case MAXENCODING+1: ! 1619: case MAXENCODING+2: ! 1620: putc(c, tf); ! 1621: break; ! 1622: } /* End switch */ ! 1623: ! 1624: } /* End of addchar */ ! 1625: ! 1626: /*****************************************************************************/ ! 1627: ! 1628: addoctal(c) ! 1629: ! 1630: int c; ! 1631: ! 1632: { ! 1633: ! 1634: /* ! 1635: * ! 1636: * Add c to the current string as an octal escape. ! 1637: * ! 1638: */ ! 1639: ! 1640: switch ( encoding ) { ! 1641: case 0: ! 1642: case 1: ! 1643: fprintf(tf, "\\%o", c); ! 1644: break; ! 1645: ! 1646: case 2: ! 1647: case 3: ! 1648: sprintf(strptr, "\\%o", c); ! 1649: strptr += strlen(strptr); ! 1650: break; ! 1651: ! 1652: case MAXENCODING+1: ! 1653: case MAXENCODING+2: ! 1654: fprintf(tf, "\\%o", c); ! 1655: break; ! 1656: } /* End switch */ ! 1657: ! 1658: } /* End of addoctal */ ! 1659: ! 1660: /*****************************************************************************/ ! 1661: ! 1662: charlib(code) ! 1663: ! 1664: int code; /* either 1 or 2 */ ! 1665: ! 1666: { ! 1667: ! 1668: char *name; /* name of the character */ ! 1669: char tname[10]; /* in case it's a single ASCII character */ ! 1670: char temp[150]; ! 1671: ! 1672: /* ! 1673: * ! 1674: * Called from oput() for characters having codes less than 040. Special files ! 1675: * that define PostScript procedures for certain characters can be found in ! 1676: * directory *fontdir/devpost/charlib. If there's a file that has the same name as ! 1677: * the character we're trying to print it's copied to the output file, otherwise ! 1678: * nothing, except some positioning, is done. ! 1679: * ! 1680: * All character definitions are only made once. Subsequent requests to print the ! 1681: * character generate a call to a procedure that begins with the prefix build_ and ! 1682: * ends with the character's name. Special characters that are assigned codes ! 1683: * other than 1 are assumed to have additional data files that should be copied ! 1684: * to the output file immediately after the build_ call. Those data files should ! 1685: * end in the suffix .map, and usually will be a hex representation of a bitmap. ! 1686: * ! 1687: */ ! 1688: ! 1689: flushtext(); ! 1690: ! 1691: if ( lastc < 128 ) { /* just a simple ASCII character */ ! 1692: sprintf(tname, "%.3o", lastc); ! 1693: name = tname; ! 1694: } else name = chname(lastc); ! 1695: ! 1696: if ( downloaded[lastc] == 0 ) { ! 1697: sprintf(temp, "%s/dev%s/charlib/%s", fontdir, realdev, name); ! 1698: if ( exportfile(temp) == TRUE ) { ! 1699: downloaded[lastc] = 1; ! 1700: t_sf(); ! 1701: } /* End if */ ! 1702: } /* End if */ ! 1703: ! 1704: if ( downloaded[lastc] == 1 ) { ! 1705: xymove(hpos, vpos); ! 1706: fprintf(tf, "%d build_%s\n", (int) lastw, name); ! 1707: if ( code != 1 ) { /* get the bitmap or whatever */ ! 1708: sprintf(temp, "%s/dev%s/charlib/%s.map", fontdir, realdev, name); ! 1709: if ( access(temp, 04) == 0 && tf == stdout ) ! 1710: cat(temp); ! 1711: } /* End if */ ! 1712: fprintf(tf, "%d %d m\n", stringstart = hpos + lastw, vpos); ! 1713: } /* End if */ ! 1714: ! 1715: } /* End of charlib */ ! 1716: ! 1717: /*****************************************************************************/ ! 1718: ! 1719: reset() ! 1720: ! 1721: { ! 1722: ! 1723: /* ! 1724: * ! 1725: * Reset variables that keep track of the printer's current position, size and ! 1726: * font. Eventually forces things back in sync before oput() prints the next ! 1727: * character. ! 1728: * ! 1729: */ ! 1730: ! 1731: lastx = -(slop + 1); ! 1732: lasty = -1; ! 1733: lastfont = lastsize = -1; ! 1734: ! 1735: } /* End of reset */ ! 1736: ! 1737: /*****************************************************************************/ ! 1738: ! 1739: resetpos() ! 1740: ! 1741: { ! 1742: ! 1743: /* ! 1744: * ! 1745: * Reset the position tracking variables. Forces oput() to get positions back ! 1746: * in sync before printing the next character. ! 1747: * ! 1748: */ ! 1749: ! 1750: lastx = -(slop + 1); ! 1751: lasty = -1; ! 1752: ! 1753: } /* End of resetpos */ ! 1754: ! 1755: /*****************************************************************************/ ! 1756: ! 1757: save() ! 1758: ! 1759: { ! 1760: ! 1761: /* ! 1762: * ! 1763: * Save the current PostScript environment. Initialize things that may have ! 1764: * disappeared after the preceeding restore. ! 1765: * ! 1766: */ ! 1767: ! 1768: fprintf(tf, "/saveobj save def\n"); ! 1769: fprintf(tf, "mark\n"); ! 1770: ! 1771: if ( encoding != realencoding ) ! 1772: fprintf(tf, "%d setdecoding\n", encoding); ! 1773: ! 1774: if ( gotcolor == TRUE ) /* prevent getcolor() recursion */ ! 1775: setcolor(); ! 1776: ! 1777: } /* End of save */ ! 1778: ! 1779: /*****************************************************************************/ ! 1780: ! 1781: restore() ! 1782: ! 1783: { ! 1784: ! 1785: /* ! 1786: * ! 1787: * Restore the previous PostScript environment. ! 1788: * ! 1789: */ ! 1790: ! 1791: flushtext(); ! 1792: fprintf(tf, "cleartomark\n"); ! 1793: fprintf(tf, "saveobj restore\n"); ! 1794: reset(); ! 1795: ! 1796: } /* End of restore */ ! 1797: ! 1798: /*****************************************************************************/ ! 1799: ! 1800: exportfile(path) ! 1801: ! 1802: char *path; ! 1803: ! 1804: { ! 1805: ! 1806: int val = FALSE; ! 1807: ! 1808: /* ! 1809: * ! 1810: * Exports the contents of file path to the global environment. Returns TRUE ! 1811: * if we're doing output (i.e. tf == stdout) and the copy worked. ! 1812: * ! 1813: */ ! 1814: ! 1815: if ( tf == stdout && access(path, 04) == 0 ) { ! 1816: restore(); ! 1817: fprintf(tf, "%s", BEGINGLOBAL); ! 1818: val = cat(path); ! 1819: fprintf(tf, "%s", ENDGLOBAL); ! 1820: save(); ! 1821: } /* End if */ ! 1822: ! 1823: return(val); ! 1824: ! 1825: } /* End of exportfile */ ! 1826: ! 1827: /*****************************************************************************/ ! 1828: ! 1829: exportstring(str) ! 1830: ! 1831: char *str; ! 1832: ! 1833: { ! 1834: ! 1835: /* ! 1836: * ! 1837: * Exports string str to the global environment. No return value needed yet. ! 1838: * ! 1839: */ ! 1840: ! 1841: if ( tf == stdout && str != NULL && *str != '\0' ) { ! 1842: restore(); ! 1843: fprintf(tf, "%s", BEGINGLOBAL); ! 1844: fprintf(tf, "%s", str); ! 1845: fprintf(tf, "%s", ENDGLOBAL); ! 1846: save(); ! 1847: } /* End if */ ! 1848: ! 1849: } /* End of exportstring */ ! 1850: ! 1851: /*****************************************************************************/ ! 1852: ! 1853: redirect(pg) ! 1854: ! 1855: int pg; ! 1856: ! 1857: { ! 1858: ! 1859: static FILE *fp_null = NULL; ! 1860: ! 1861: /* ! 1862: * ! 1863: * If we're not supposed to print page pg, tf will be directed to /dev/null, ! 1864: * otherwise output goes to stdout. ! 1865: * ! 1866: */ ! 1867: ! 1868: if ( pg >= 0 && in_olist(pg) == ON ) ! 1869: tf = stdout; ! 1870: else if ( (tf = fp_null) == NULL ) ! 1871: tf = fp_null = fopen("/dev/null", "w"); ! 1872: ! 1873: } /* End of redirect */ ! 1874: ! 1875: /*****************************************************************************/ ! 1876:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.