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