|
|
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[100]; ! 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, name) ! 948: ! 949: int m; ! 950: char *f; ! 951: char *name; ! 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 name, if name isn't empty. Use mapfont() to replace the missing font ! 961: * if we're emulating another device, name is empty, and the first mount ! 962: * fails. ! 963: * ! 964: */ ! 965: ! 966: if ( name[0] == '\0' ) ! 967: sprintf(path, "%s/dev%s/%s", fontdir, realdev, f); ! 968: else sprintf(path, "%s", name); ! 969: ! 970: if ( mountfont(path, m) == -1 ) { ! 971: if ( name[0] == '\0' ) { ! 972: sprintf(path, "%s/dev%s/%s", fontdir, realdev, mapfont(f)); ! 973: if ( mountfont(path, m) == -1 ) { ! 974: sprintf(path, "%s/dev%s/%s", fontdir, realdev, f); ! 975: error(FATAL, "can't load %s at %d", path, m); ! 976: } /* End if */ ! 977: } else error(FATAL, "can't load %s at %d", path, m); ! 978: } /* End if */ ! 979: ! 980: if ( smnt == 0 && mount[m]->specfont ) ! 981: smnt = m; ! 982: ! 983: if ( m == lastfont ) /* force a call to t_sf() */ ! 984: lastfont = -1; ! 985: ! 986: if ( m > nfonts ) { /* got more positions */ ! 987: nfonts = m; ! 988: gotspecial = FALSE; ! 989: } /* End if */ ! 990: ! 991: } /* End of loadfont */ ! 992: ! 993: /*****************************************************************************/ ! 994: ! 995: char *mapfont(name) ! 996: ! 997: char *name; ! 998: ! 999: { ! 1000: ! 1001: int i; ! 1002: ! 1003: /* ! 1004: * ! 1005: * Map a missing font name into one that should be available. Only used when ! 1006: * we're emulating another device and the first mount fails. Consider deleting ! 1007: * this routine. ! 1008: * ! 1009: */ ! 1010: ! 1011: for ( i = 0; fontmap[i].name != NULL; i++ ) ! 1012: if ( strcmp(name, fontmap[i].name) == 0 ) ! 1013: return(fontmap[i].use); ! 1014: ! 1015: switch ( *++name ) { ! 1016: case 'I': return("I"); ! 1017: case 'B': return("B"); ! 1018: case 'X': return("BI"); ! 1019: default: return("R"); ! 1020: } /* End switch */ ! 1021: ! 1022: } /* End of mapfont */ ! 1023: ! 1024: /*****************************************************************************/ ! 1025: ! 1026: loadspecial() ! 1027: ! 1028: { ! 1029: ! 1030: /* ! 1031: * ! 1032: * Fix - later. ! 1033: * ! 1034: */ ! 1035: ! 1036: gotspecial = TRUE; ! 1037: ! 1038: } /* End of loadspecial */ ! 1039: ! 1040: /*****************************************************************************/ ! 1041: ! 1042: t_init() ! 1043: ! 1044: { ! 1045: ! 1046: char path[150]; ! 1047: static int initialized = FALSE; ! 1048: ! 1049: /* ! 1050: * ! 1051: * Finish initialization - just read an "x init" command. Assumes we already ! 1052: * know the input file resolution. ! 1053: * ! 1054: */ ! 1055: ! 1056: flushtext(); /* moved - for cat'ed troff files */ ! 1057: ! 1058: if ( initialized == FALSE ) { ! 1059: if ( strcmp(devname, realdev) ) { ! 1060: sprintf(path, "%s/dev%s/DESC", fontdir, devname); ! 1061: if ( checkdesc(path) ) ! 1062: realdev = devname; ! 1063: } /* End if */ ! 1064: ! 1065: sprintf(path, "%s/dev%s/DESC", fontdir, realdev); ! 1066: if ( getdesc(path) == -1 ) ! 1067: error(FATAL, "can't open %s", path); ! 1068: nfonts = 0; ! 1069: gotspecial = FALSE; ! 1070: widthfac = (float) res /devres; ! 1071: slop = pointslop * res / POINTS + .5; ! 1072: rvslop = res * .025; ! 1073: setup(); ! 1074: initialized = TRUE; ! 1075: } /* End if */ ! 1076: ! 1077: hpos = vpos = 0; ! 1078: size = 10; ! 1079: reset(); ! 1080: ! 1081: } /* End of t_init */ ! 1082: ! 1083: /*****************************************************************************/ ! 1084: ! 1085: t_page(pg) ! 1086: ! 1087: int pg; ! 1088: ! 1089: { ! 1090: ! 1091: static int lastpg = 0; ! 1092: ! 1093: /* ! 1094: * ! 1095: * Finish the previous page and get ready for the next one. End page output ! 1096: * goes to /dev/null at the start of each input file. Start page output goes ! 1097: * to /dev/null at the end of each input file. ! 1098: * ! 1099: * Consider doing showpage after page level restore (as Adobe recommends). If ! 1100: * the order is changed use restore() and save(). forms.ps will likely also ! 1101: * need fixing. ! 1102: * ! 1103: */ ! 1104: ! 1105: if ( tf == stdout ) ! 1106: printed++; ! 1107: ! 1108: flushtext(); /* just in case */ ! 1109: ! 1110: fprintf(tf, "cleartomark\n"); ! 1111: fprintf(tf, "showpage\n"); ! 1112: fprintf(tf, "saveobj restore\n"); ! 1113: if ( dobbox == TRUE ) ! 1114: writebbox(tf, PAGEBOUNDINGBOX, 10); ! 1115: fprintf(tf, "%s %d %d\n", ENDPAGE, lastpg, printed); ! 1116: ! 1117: redirect(pg); ! 1118: ! 1119: fprintf(tf, "%s %d %d\n", PAGE, pg, printed+1); ! 1120: if ( dobbox == TRUE ) ! 1121: fprintf(tf, "%s %s\n", PAGEBOUNDINGBOX, ATEND); ! 1122: fprintf(tf, "/saveobj save def\n"); ! 1123: fprintf(tf, "mark\n"); ! 1124: writerequest(printed+1, tf); ! 1125: fprintf(tf, "%d pagesetup\n", printed+1); ! 1126: ! 1127: if ( encoding != realencoding ) ! 1128: fprintf(tf, "%d setdecoding\n", encoding); ! 1129: ! 1130: if ( gotcolor == TRUE ) ! 1131: setcolor(); ! 1132: ! 1133: lastpg = pg; /* for the next ENDPAGE comment */ ! 1134: hpos = vpos = 0; /* get ready for the next page */ ! 1135: reset(); /* force position and font stuff - later */ ! 1136: ! 1137: seenpage = TRUE; ! 1138: ! 1139: } /* End of t_page */ ! 1140: ! 1141: /*****************************************************************************/ ! 1142: ! 1143: t_font(s) ! 1144: ! 1145: char *s; ! 1146: ! 1147: { ! 1148: ! 1149: int n; ! 1150: ! 1151: /* ! 1152: * ! 1153: * Converts the string *s into an integer and checks to make sure it's a legal ! 1154: * font position. Also arranges to mount all the special fonts after the last ! 1155: * legitimate font (by calling loadspecial()), provided it hasn't already been ! 1156: * done. ! 1157: * ! 1158: */ ! 1159: ! 1160: n = atoi(s); ! 1161: ! 1162: if ( seenpage == TRUE ) { ! 1163: if ( n < 0 || n > nfonts ) ! 1164: error(FATAL, "illegal font position %d", n); ! 1165: ! 1166: if ( gotspecial == FALSE ) ! 1167: loadspecial(); ! 1168: } /* End if */ ! 1169: ! 1170: return(n); ! 1171: ! 1172: } /* End of t_font */ ! 1173: ! 1174: /*****************************************************************************/ ! 1175: ! 1176: setfont(m) ! 1177: ! 1178: int m; ! 1179: ! 1180: { ! 1181: ! 1182: /* ! 1183: * ! 1184: * Use the font mounted at position m. Bounds checks are probably unnecessary. ! 1185: * Changing the font and size used by the printer is handled in t_sf(). ! 1186: * ! 1187: */ ! 1188: ! 1189: if ( m < 0 || m > MAXFONTS ) ! 1190: error(FATAL, "illegal font %d", m); ! 1191: font = m; ! 1192: ! 1193: } /* End of setfont */ ! 1194: ! 1195: /*****************************************************************************/ ! 1196: ! 1197: t_sf() ! 1198: ! 1199: { ! 1200: ! 1201: Font *fpos; ! 1202: char temp[150]; ! 1203: ! 1204: /* ! 1205: * ! 1206: * Force a new font or size. Generates name definitions for fonts that haven't ! 1207: * been named, grabs host resident font files and keeps track of the fonts used ! 1208: * by this job. When necessary also adjusts the font's height and slant. Should ! 1209: * only be called immediately before printing a character. ! 1210: * ! 1211: */ ! 1212: ! 1213: if ( tf == stdout && mounted(font) ) { ! 1214: flushtext(); ! 1215: ! 1216: fpos = mount[font]; ! 1217: if ( (fpos->flags & USED) == 0 ) { ! 1218: if ( (fpos->flags & NAMED) == 0 && fpos->fontname != NULL ) { ! 1219: sprintf(temp, "/%s /%s def\n", fpos->name, fpos->fontname); ! 1220: exportstring(temp); ! 1221: fpos->flags |= NAMED; /* unnecessary */ ! 1222: } /* End if */ ! 1223: ! 1224: if ( hostfontdir != NULL ) { ! 1225: sprintf(temp, "%s/%s", hostfontdir, fpos->name); ! 1226: exportfile(temp); ! 1227: } /* End if */ ! 1228: } /* End if */ ! 1229: ! 1230: fprintf(tf, "%d %s f\n", size, fpos->name); ! 1231: if ( fontheight != 0 || fontslant != 0 ) ! 1232: fprintf(tf, "%d %d changefont\n", fontslant, (fontheight != 0) ? fontheight : size); ! 1233: ! 1234: lastfont = font; ! 1235: lastsize = size; ! 1236: fpos->flags |= USED; ! 1237: } /* End if */ ! 1238: ! 1239: } /* End of t_sf */ ! 1240: ! 1241: /*****************************************************************************/ ! 1242: ! 1243: t_charht(n) ! 1244: ! 1245: int n; ! 1246: ! 1247: { ! 1248: ! 1249: /* ! 1250: * ! 1251: * Set character height to n points. Disabled if n is 0 or the current size. ! 1252: * ! 1253: */ ! 1254: ! 1255: fontheight = (n == size) ? 0 : n; ! 1256: lastfont = -1; ! 1257: ! 1258: } /* End of t_charht */ ! 1259: ! 1260: /*****************************************************************************/ ! 1261: ! 1262: t_slant(n) ! 1263: ! 1264: int n; ! 1265: ! 1266: { ! 1267: ! 1268: /* ! 1269: * ! 1270: * Set slant to n degrees. Disable slanting if n is 0. ! 1271: * ! 1272: */ ! 1273: ! 1274: fontslant = n; ! 1275: lastfont = -1; ! 1276: ! 1277: } /* End of t_slant */ ! 1278: ! 1279: /*****************************************************************************/ ! 1280: ! 1281: xymove(x, y) ! 1282: ! 1283: int x, y; ! 1284: ! 1285: { ! 1286: ! 1287: /* ! 1288: * ! 1289: * Make the the printer and post-processor agree about the current position. ! 1290: * ! 1291: */ ! 1292: ! 1293: flushtext(); ! 1294: ! 1295: hgoto(x); ! 1296: vgoto(y); ! 1297: ! 1298: fprintf(tf, "%d %d m\n", hpos, vpos); ! 1299: ! 1300: lastx = hpos; ! 1301: lasty = vpos; ! 1302: ! 1303: } /* End of xymove */ ! 1304: ! 1305: /*****************************************************************************/ ! 1306: ! 1307: put1(c) ! 1308: ! 1309: register int c; ! 1310: ! 1311: { ! 1312: ! 1313: register int i; ! 1314: register int j; ! 1315: register int k; ! 1316: int code; ! 1317: int ofont; ! 1318: ! 1319: /* ! 1320: * ! 1321: * Print character c. ASCII if c < ALPHABET, otherwise it's special. Look for ! 1322: * c in the current font, then in others starting at the first special font. ! 1323: * Save c in lastc so it's available when oput() runs. Restore original font ! 1324: * before leaving. ! 1325: * ! 1326: */ ! 1327: ! 1328: lastc = c; /* charlib() needs name not code */ ! 1329: if ( (c -= 32) <= 0 ) ! 1330: return; ! 1331: ! 1332: k = ofont = font; ! 1333: ! 1334: if ( (i = onfont(lastc, k)) == -1 && smnt > 0 ) ! 1335: for ( k = smnt, j = 0; j < nfonts; j++, k = k % nfonts + 1 ) { ! 1336: if ( (i = onfont(lastc, k)) != -1 ) { ! 1337: setfont(k); ! 1338: break; ! 1339: } /* End if */ ! 1340: } /* End for */ ! 1341: ! 1342: if ( i != -1 && (code = mount[k]->wp[i].code) != 0 ) { ! 1343: lastw = widthfac * (((int)mount[k]->wp[i].wid * size + unitwidth/2) / unitwidth); ! 1344: oput(code); ! 1345: } /* End if */ ! 1346: ! 1347: if ( font != ofont ) ! 1348: setfont(ofont); ! 1349: ! 1350: } /* End of put1 */ ! 1351: ! 1352: /*****************************************************************************/ ! 1353: ! 1354: oput(c) ! 1355: ! 1356: int c; ! 1357: ! 1358: { ! 1359: ! 1360: double llx, lly, urx, ury; /* boundingbox corners */ ! 1361: ! 1362: /* ! 1363: * ! 1364: * Arranges to print the character whose code is c in the current font. All the ! 1365: * actual positioning is done here, in charlib(), or in the drawing routines. ! 1366: * ! 1367: */ ! 1368: ! 1369: if ( textcount > MAXSTACK ) /* don't put too much on the stack? */ ! 1370: flushtext(); ! 1371: ! 1372: if ( font != lastfont || size != lastsize ) ! 1373: t_sf(); ! 1374: ! 1375: if ( vpos != lasty ) ! 1376: endline(); ! 1377: ! 1378: starttext(); ! 1379: ! 1380: if ( ABS(hpos - lastx) > slop ) ! 1381: endstring(); ! 1382: ! 1383: if ( isascii(c) && isprint(c) ) ! 1384: switch ( c ) { ! 1385: case '(': ! 1386: case ')': ! 1387: case '\\': ! 1388: addchar('\\'); ! 1389: ! 1390: default: ! 1391: addchar(c); ! 1392: } /* End switch */ ! 1393: else if ( c > 040 ) ! 1394: addoctal(c); ! 1395: else charlib(c); ! 1396: ! 1397: if ( dobbox == TRUE ) { ! 1398: llx = lastx; ! 1399: lly = -(vpos + 0.5 * (devres * size / 72.0)); ! 1400: urx = lastx + lastw; ! 1401: ury = -(vpos - (devres * size / 72.0)); ! 1402: cover(llx, lly); ! 1403: cover(urx, ury); ! 1404: } /* End if */ ! 1405: ! 1406: lastx += lastw; ! 1407: ! 1408: } /* End of oput */ ! 1409: ! 1410: /*****************************************************************************/ ! 1411: ! 1412: starttext() ! 1413: ! 1414: { ! 1415: ! 1416: /* ! 1417: * Called whenever we want to be sure we're ready to start collecting characters ! 1418: * for the next call to PostScript procedure t (ie. the one that prints them). If ! 1419: * textcount is positive we've already started, so there's nothing to do. The more ! 1420: * complicated encoding schemes save text strings in the strings[] array and need ! 1421: * detailed information about the strings when they're written to the output file ! 1422: * in flushtext(). ! 1423: * ! 1424: */ ! 1425: ! 1426: if ( textcount < 1 ) { ! 1427: switch ( encoding ) { ! 1428: case 0: ! 1429: case 1: ! 1430: putc('(', tf); ! 1431: break; ! 1432: ! 1433: case 2: ! 1434: case 3: ! 1435: strptr = strings; ! 1436: spacecount = 0; ! 1437: line[1].str = strptr; ! 1438: line[1].dx = 0; ! 1439: line[1].spaces = 0; ! 1440: line[1].start = hpos; ! 1441: line[1].width = 0; ! 1442: break; ! 1443: ! 1444: case MAXENCODING+1: /* reverse video */ ! 1445: if ( lastend == -1 ) ! 1446: lastend = hpos; ! 1447: putc('(', tf); ! 1448: break; ! 1449: ! 1450: case MAXENCODING+2: /* follow a funny baseline */ ! 1451: putc('(', tf); ! 1452: break; ! 1453: } /* End switch */ ! 1454: ! 1455: textcount = 1; ! 1456: lastx = stringstart = hpos; ! 1457: } /* End if */ ! 1458: ! 1459: } /* End of starttext */ ! 1460: ! 1461: /*****************************************************************************/ ! 1462: ! 1463: flushtext() ! 1464: ! 1465: { ! 1466: ! 1467: int i; ! 1468: ! 1469: /* ! 1470: * ! 1471: * Generates a call to the PostScript procedure that processes all the text we've ! 1472: * accumulated - provided textcount is positive. ! 1473: * ! 1474: */ ! 1475: ! 1476: if ( textcount > 0 ) { ! 1477: switch ( encoding ) { ! 1478: case 0: ! 1479: fprintf(tf, ")%d t\n", stringstart); ! 1480: break; ! 1481: ! 1482: case 1: ! 1483: fprintf(tf, ")%d %d t\n", stringstart, lasty); ! 1484: break; ! 1485: ! 1486: case 2: ! 1487: *strptr = '\0'; ! 1488: line[textcount].width = lastx - line[textcount].start; ! 1489: if ( spacecount != 0 || textcount != 1 ) { ! 1490: for ( i = textcount; i > 0; i-- ) ! 1491: fprintf(tf, "(%s)%d %d", line[i].str, line[i].spaces, line[i].width); ! 1492: fprintf(tf, " %d %d %d t\n", textcount, stringstart, lasty); ! 1493: } else fprintf(tf, "(%s)%d %d w\n", line[1].str, stringstart, lasty); ! 1494: break; ! 1495: ! 1496: case 3: ! 1497: *strptr = '\0'; ! 1498: if ( spacecount != 0 || textcount != 1 ) { ! 1499: for ( i = textcount; i > 0; i-- ) ! 1500: fprintf(tf, "(%s)%d", line[i].str, line[i].dx); ! 1501: fprintf(tf, " %d %d %d t\n", textcount, stringstart, lasty); ! 1502: } else fprintf(tf, "(%s)%d %d w\n", line[1].str, stringstart, lasty); ! 1503: break; ! 1504: ! 1505: case MAXENCODING+1: ! 1506: fprintf(tf, ")%d ", stringstart); ! 1507: fprintf(tf, "%d %d drawrvbox ", lastend - rvslop, (int)(lastx + .5) + rvslop); ! 1508: fprintf(tf, "t\n", stringstart); ! 1509: lastend = (lastx + .5) + 2 * rvslop; ! 1510: break; ! 1511: ! 1512: case MAXENCODING+2: ! 1513: fprintf(tf, ")%d %d t\n", stringstart, lasty); ! 1514: break; ! 1515: } /* End switch */ ! 1516: } /* End if */ ! 1517: ! 1518: textcount = 0; ! 1519: ! 1520: } /* End of flushtext */ ! 1521: ! 1522: /*****************************************************************************/ ! 1523: ! 1524: endstring() ! 1525: ! 1526: { ! 1527: ! 1528: int dx; ! 1529: ! 1530: /* ! 1531: * ! 1532: * Horizontal positions are out of sync. End the last open string, adjust the ! 1533: * printer's position, and start a new string. Assumes we've already started ! 1534: * accumulating text. ! 1535: * ! 1536: */ ! 1537: ! 1538: switch ( encoding ) { ! 1539: case 0: ! 1540: case 1: ! 1541: fprintf(tf, ")%d(", stringstart); ! 1542: textcount++; ! 1543: lastx = stringstart = hpos; ! 1544: break; ! 1545: ! 1546: case 2: ! 1547: case 3: ! 1548: dx = hpos - lastx; ! 1549: if ( spacecount++ == 0 ) ! 1550: line[textcount].dx = dx; ! 1551: if ( line[textcount].dx != dx ) { ! 1552: *strptr++ = '\0'; ! 1553: line[textcount].width = lastx - line[textcount].start; ! 1554: line[++textcount].str = strptr; ! 1555: *strptr++ = ' '; ! 1556: line[textcount].dx = dx; ! 1557: line[textcount].start = lastx; ! 1558: line[textcount].width = 0; ! 1559: line[textcount].spaces = 1; ! 1560: } else { ! 1561: *strptr++ = ' '; ! 1562: line[textcount].spaces++; ! 1563: } /* End else */ ! 1564: lastx += dx; ! 1565: break; ! 1566: ! 1567: case MAXENCODING+1: ! 1568: fprintf(tf, ")%d(", stringstart); ! 1569: textcount++; ! 1570: lastx = stringstart = hpos; ! 1571: break; ! 1572: ! 1573: case MAXENCODING+2: ! 1574: flushtext(); ! 1575: starttext(); ! 1576: break; ! 1577: } /* End switch */ ! 1578: ! 1579: } /* End of endstring */ ! 1580: ! 1581: /*****************************************************************************/ ! 1582: ! 1583: endline() ! 1584: ! 1585: { ! 1586: ! 1587: /* ! 1588: * ! 1589: * The vertical position has changed. Dump any accumulated text, then adjust ! 1590: * the printer's vertical position. ! 1591: * ! 1592: */ ! 1593: ! 1594: flushtext(); ! 1595: ! 1596: if ( encoding == 0 || encoding == MAXENCODING+1 ) ! 1597: fprintf(tf, "%d %d m\n", hpos, vpos); ! 1598: ! 1599: lastx = stringstart = lastend = hpos; ! 1600: lasty = vpos; ! 1601: ! 1602: } /* End of endline */ ! 1603: ! 1604: /*****************************************************************************/ ! 1605: ! 1606: addchar(c) ! 1607: ! 1608: int c; ! 1609: ! 1610: { ! 1611: ! 1612: /* ! 1613: * ! 1614: * Does whatever is needed to add character c to the current string. ! 1615: * ! 1616: */ ! 1617: ! 1618: switch ( encoding ) { ! 1619: case 0: ! 1620: case 1: ! 1621: putc(c, tf); ! 1622: break; ! 1623: ! 1624: case 2: ! 1625: case 3: ! 1626: *strptr++ = c; ! 1627: break; ! 1628: ! 1629: case MAXENCODING+1: ! 1630: case MAXENCODING+2: ! 1631: putc(c, tf); ! 1632: break; ! 1633: } /* End switch */ ! 1634: ! 1635: } /* End of addchar */ ! 1636: ! 1637: /*****************************************************************************/ ! 1638: ! 1639: addoctal(c) ! 1640: ! 1641: int c; ! 1642: ! 1643: { ! 1644: ! 1645: /* ! 1646: * ! 1647: * Add c to the current string as an octal escape. ! 1648: * ! 1649: */ ! 1650: ! 1651: switch ( encoding ) { ! 1652: case 0: ! 1653: case 1: ! 1654: fprintf(tf, "\\%o", c); ! 1655: break; ! 1656: ! 1657: case 2: ! 1658: case 3: ! 1659: sprintf(strptr, "\\%o", c); ! 1660: strptr += strlen(strptr); ! 1661: break; ! 1662: ! 1663: case MAXENCODING+1: ! 1664: case MAXENCODING+2: ! 1665: fprintf(tf, "\\%o", c); ! 1666: break; ! 1667: } /* End switch */ ! 1668: ! 1669: } /* End of addoctal */ ! 1670: ! 1671: /*****************************************************************************/ ! 1672: ! 1673: charlib(code) ! 1674: ! 1675: int code; /* either 1 or 2 */ ! 1676: ! 1677: { ! 1678: ! 1679: char *name; /* name of the character */ ! 1680: char tname[10]; /* in case it's a single ASCII character */ ! 1681: char temp[150]; ! 1682: ! 1683: /* ! 1684: * ! 1685: * Called from oput() for characters having codes less than 040. Special files ! 1686: * that define PostScript procedures for certain characters can be found in ! 1687: * directory *fontdir/devpost/charlib. If there's a file that has the same name as ! 1688: * the character we're trying to print it's copied to the output file, otherwise ! 1689: * nothing, except some positioning, is done. ! 1690: * ! 1691: * All character definitions are only made once. Subsequent requests to print the ! 1692: * character generate a call to a procedure that begins with the prefix build_ and ! 1693: * ends with the character's name. Special characters that are assigned codes ! 1694: * other than 1 are assumed to have additional data files that should be copied ! 1695: * to the output file immediately after the build_ call. Those data files should ! 1696: * end in the suffix .map, and usually will be a hex representation of a bitmap. ! 1697: * ! 1698: */ ! 1699: ! 1700: flushtext(); ! 1701: ! 1702: if ( lastc < ALPHABET ) { /* ASCII character */ ! 1703: sprintf(tname, "%.3o", lastc); ! 1704: name = tname; ! 1705: } else name = chname(lastc); ! 1706: ! 1707: if ( downloaded[lastc] == 0 ) { ! 1708: sprintf(temp, "%s/dev%s/charlib/%s", fontdir, realdev, name); ! 1709: if ( exportfile(temp) == TRUE ) { ! 1710: downloaded[lastc] = 1; ! 1711: t_sf(); ! 1712: } /* End if */ ! 1713: } /* End if */ ! 1714: ! 1715: if ( downloaded[lastc] == 1 ) { ! 1716: xymove(hpos, vpos); ! 1717: fprintf(tf, "%d build_%s\n", (int) lastw, name); ! 1718: if ( code != 1 ) { /* get the bitmap or whatever */ ! 1719: sprintf(temp, "%s/dev%s/charlib/%s.map", fontdir, realdev, name); ! 1720: if ( access(temp, 04) == 0 && tf == stdout ) ! 1721: cat(temp); ! 1722: } /* End if */ ! 1723: fprintf(tf, "%d %d m\n", stringstart = hpos + lastw, vpos); ! 1724: } /* End if */ ! 1725: ! 1726: } /* End of charlib */ ! 1727: ! 1728: /*****************************************************************************/ ! 1729: ! 1730: reset() ! 1731: ! 1732: { ! 1733: ! 1734: /* ! 1735: * ! 1736: * Reset variables that keep track of the printer's current position, size and ! 1737: * font. Eventually forces things back in sync before oput() prints the next ! 1738: * character. ! 1739: * ! 1740: */ ! 1741: ! 1742: lastx = -(slop + 1); ! 1743: lasty = -1; ! 1744: lastfont = lastsize = -1; ! 1745: ! 1746: } /* End of reset */ ! 1747: ! 1748: /*****************************************************************************/ ! 1749: ! 1750: resetpos() ! 1751: ! 1752: { ! 1753: ! 1754: /* ! 1755: * ! 1756: * Reset the position tracking variables. Forces oput() to get positions back ! 1757: * in sync before printing the next character. ! 1758: * ! 1759: */ ! 1760: ! 1761: lastx = -(slop + 1); ! 1762: lasty = -1; ! 1763: ! 1764: } /* End of resetpos */ ! 1765: ! 1766: /*****************************************************************************/ ! 1767: ! 1768: save() ! 1769: ! 1770: { ! 1771: ! 1772: /* ! 1773: * ! 1774: * Save the current PostScript environment. Initialize things that may have ! 1775: * disappeared after the preceeding restore. ! 1776: * ! 1777: */ ! 1778: ! 1779: fprintf(tf, "/saveobj save def\n"); ! 1780: fprintf(tf, "mark\n"); ! 1781: ! 1782: if ( encoding != realencoding ) ! 1783: fprintf(tf, "%d setdecoding\n", encoding); ! 1784: ! 1785: if ( gotcolor == TRUE ) /* prevent getcolor() recursion */ ! 1786: setcolor(); ! 1787: ! 1788: } /* End of save */ ! 1789: ! 1790: /*****************************************************************************/ ! 1791: ! 1792: restore() ! 1793: ! 1794: { ! 1795: ! 1796: /* ! 1797: * ! 1798: * Restore the previous PostScript environment. ! 1799: * ! 1800: */ ! 1801: ! 1802: flushtext(); ! 1803: fprintf(tf, "cleartomark\n"); ! 1804: fprintf(tf, "saveobj restore\n"); ! 1805: reset(); ! 1806: ! 1807: } /* End of restore */ ! 1808: ! 1809: /*****************************************************************************/ ! 1810: ! 1811: exportfile(path) ! 1812: ! 1813: char *path; ! 1814: ! 1815: { ! 1816: ! 1817: int val = FALSE; ! 1818: ! 1819: /* ! 1820: * ! 1821: * Exports the contents of file path to the global environment. Returns TRUE ! 1822: * if we're doing output (i.e. tf == stdout) and the copy worked. ! 1823: * ! 1824: */ ! 1825: ! 1826: if ( tf == stdout && access(path, 04) == 0 ) { ! 1827: restore(); ! 1828: fprintf(tf, "%s", BEGINGLOBAL); ! 1829: val = cat(path); ! 1830: fprintf(tf, "%s", ENDGLOBAL); ! 1831: save(); ! 1832: } /* End if */ ! 1833: ! 1834: return(val); ! 1835: ! 1836: } /* End of exportfile */ ! 1837: ! 1838: /*****************************************************************************/ ! 1839: ! 1840: exportstring(str) ! 1841: ! 1842: char *str; ! 1843: ! 1844: { ! 1845: ! 1846: /* ! 1847: * ! 1848: * Exports string str to the global environment. No return value needed yet. ! 1849: * ! 1850: */ ! 1851: ! 1852: if ( tf == stdout && str != NULL && *str != '\0' ) { ! 1853: restore(); ! 1854: fprintf(tf, "%s", BEGINGLOBAL); ! 1855: fprintf(tf, "%s", str); ! 1856: fprintf(tf, "%s", ENDGLOBAL); ! 1857: save(); ! 1858: } /* End if */ ! 1859: ! 1860: } /* End of exportstring */ ! 1861: ! 1862: /*****************************************************************************/ ! 1863: ! 1864: redirect(pg) ! 1865: ! 1866: int pg; ! 1867: ! 1868: { ! 1869: ! 1870: static FILE *fp_null = NULL; ! 1871: ! 1872: /* ! 1873: * ! 1874: * If we're not supposed to print page pg, tf will be directed to /dev/null, ! 1875: * otherwise output goes to stdout. ! 1876: * ! 1877: */ ! 1878: ! 1879: if ( pg >= 0 && in_olist(pg) == ON ) ! 1880: tf = stdout; ! 1881: else if ( (tf = fp_null) == NULL ) ! 1882: tf = fp_null = fopen("/dev/null", "w"); ! 1883: ! 1884: } /* End of redirect */ ! 1885: ! 1886: /*****************************************************************************/ ! 1887:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.