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