1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 1994 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 31 #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.2 */ 32 33 /* 34 * 35 * dpost - troff post-processor for PostScript printers. 36 * 37 * A program that translates output generated by the device independent troff 38 * into PostScript. Much was borrowed from dimpress and dps (formally dlzw), 39 * and even though the code has been changed, credit has to be given to Richard 40 * Flood for his early work on the PostScript driver. 41 * 42 * Among the most interesting new features are color support (see devcntrl() and 43 * file color.c) and code to handle complex paths pieced together using any of the 44 * standard drawing commands (see devcntrl() and file draw.c). Reverse video mode 45 * has also been included as a special case of the color support. Two encoding 46 * schemes based on widthshow are also new additions. The safe one is obtained when 47 * you set encoding to 2 (eg. using the -e2 option). The slightly faster method 48 * is obtained by setting encoding to 3 (eg. using the -e3 option), although it's 49 * not recommended. Rounding errors in character widths can accumulate and become 50 * quite noticeable by the time you get to the right margin. More often than not 51 * you end up getting a ragged right margin. 52 * 53 * The program handles files formatted for any device, although the best and 54 * most efficient output is generated when the font and description files match 55 * PostScript's resident fonts. Device emulation is relatively expensive, and 56 * can produce output files that are more than twice the size of the input files. 57 * In most cases output files will be smaller than input files, perhaps by up to 58 * 40 percent, although the results you get depend on what you're doing and the 59 * text encoding you're using. You'll get the worst results if you're emulating 60 * another device, using special bitmap characters, like the logo, or doing lots 61 * of vertical motion or drawing. 62 * 63 * PostScript fonts don't support all of troff's characters, so some have to 64 * be built by special PostScript procedures. Those routines can be found in 65 * *fontdir/devpost/charlib, and are only used when we try to print a character 66 * that has been assigned a code less than 32. Definitions are only made the 67 * first time each character is used. Subsequent requests to print the character 68 * only generate a call to the PostScript procedure that's been copied to the 69 * output file. For example you'll find a file called sq in directory 70 * *fontdir/devpost/charlib. It defines a PostScript procedure called build_sq 71 * that's called whenever we need to print a square. Special characters that 72 * have been assigned a code of 2 are expected to come in two pieces. The 73 * definition part and bitmap part (or whatever). The definition is only made 74 * once, but the contents of the character's .map file are copied to the output 75 * file each time, immediately after charlib() generates the call to the 76 * PostScript procedure (build_?? ) that builds the character. That's typically 77 * how logos built from bitmaps would be handled. 78 * 79 * Several different methods can be used to encode lines of text. What's done 80 * depends on the value assigned to encoding. Print time should decrease as 81 * encoding increases (up to MAXENCODING). Setting encoding to 0, which should 82 * probably be the default, produces output essentially identical to the original 83 * version of dpost. It's the slowest but most stable method of encoding lines of 84 * text, and won't be bothered by rounding errors in the font width tables that 85 * could become noticeable by the time you get to the end of a line. Other schemes 86 * seem to work, but aren't well tested and are not guaranteed for all possible 87 * jobs. encoding can be changed on the command line using the -e option. Part of 88 * the support for different encoding schemes was to move control of all text 89 * related output to separate routines. It makes dpost work harder, but changing 90 * things is easy. For example adding stuff to support widthshow took less than 91 * an hour. 92 * 93 * According to Adobe's structuring conventions, the output produced by dpost is 94 * still nonconforming. Global definitions that are occasionally made in individual 95 * pages are the primary problem. Among other things they handle downloading host 96 * resident fonts and defining special characters not generally available on 97 * PostScript printers. The approach used here works on a demand basis and violates 98 * page independence. A definition is made once in the first page that needs it 99 * and is bracketed by PostScript code that ensures the definition is exported to 100 * the global environment where it will be available for use by all the pages that 101 * follow. Simple changes, like downloading definitions the first time they're 102 * used in each page, restores page independence but wouldn't be an efficient 103 * solution. Other approaches are also available, but every one I've considered 104 * sacrifices much in efficiency - just to maintain page independence. I'll leave 105 * things be for now. Global definitions made in individual pages are bracketed 106 * by %%BeginGlobal and %%EndGlobal comments and can easily be pulled out of 107 * individual pages and put in the prologue by utility programs like postreverse. 108 * 109 * I've also added code that handles the DOCUMENTFONTS comment, although it's 110 * only produced for those fonts in directory /usr/lib/font/devpost that have an 111 * associated .name file. The first string in a .name file should be the (long) 112 * PostScript name (eg. Times-Roman in R.name). For now everything else in the 113 * .name file is ignored, although that may also change. You'll find .name files 114 * for all the supported fonts in the devpost source directory, although they may 115 * not be installed in /usr/lib/font/devpost. 116 * 117 * The PostScript prologue is copied from *prologue before any of the input files 118 * are translated. The program expects the following procedures are avaliable: 119 * 120 * setup 121 * 122 * mark ... setup - 123 * 124 * Handles special initialization stuff that depends on how the program 125 * was called. Expects to find a mark followed by key/value pairs on the 126 * stack. The def operator is applied to each pair up to the mark, then 127 * the default state is set up. An 'x res' command must preceed the 128 * 'x init' command! 129 * 130 * pagesetup 131 * 132 * page pagesetup - 133 * 134 * Called at the start of each page, immediately after the page level 135 * save, to do special initialization on a per page basis. Right now the 136 * only argument is the current page number, and actually nothing of any 137 * importance is currently done. 138 * 139 * setdecoding 140 * 141 * num setdecoding - 142 * 143 * Selects the text decoding procedure (ie. what's assigned to PostScript 144 * procedure t) from the decodingdefs array defined in the prologue. num 145 * should be the value assigned to variable encoding (in dpost) and will 146 * remain constant throughout a job, unless special features, like reverse 147 * video printing, are requested. The text encoding scheme can be set on 148 * the command line using the -e option. Print time and the size of the 149 * output file will usually decrease as the value assigned to encoding 150 * increases. 151 * 152 * f 153 * 154 * size font f - 155 * 156 * Selects the size and font to be used for character imaging. Font names 157 * are defined, in *prologue, so they agree with the one or two character 158 * names used by troff. 159 * 160 * m 161 * 162 * x y m - 163 * 164 * Moves to point (x, y). Normally only used when the vertical position 165 * changes. Horizontal positioning between words (or letters) is handled 166 * in procedure t (below). 167 * 168 * t 169 * 170 * mark text t mark 171 * 172 * Processes everything on the stack, up to the mark, as a single line 173 * of text to be printed at a fixed vertical position. What's put out as 174 * text depends on the encoding scheme. Setting encoding to 0 produces 175 * output essentially identical to the original version of dpost. In that 176 * case everything on the stack, up to a mark, is interpreted (from top 177 * down) as an absolute horizontal position and a string to be printed at 178 * that point. For example the stack might look like, 179 * 180 * mark(this)1000(is)1100(an)1200(example)1300 t 181 * 182 * Procedure t would go through the stack, up to the mark, adjusting the 183 * horizontal position before printing each string. In other encoding 184 * schemes, like the one based on widthshow, strings containing several 185 * space separated words would appear on the stack, and each one would be 186 * preceeded by a number that's expected to be added to the width of a 187 * space. For example we might have, 188 * 189 * mark(an example)30(this is)40 2 1000 2000 t 190 * 191 * where (1000, 2000) is where the first string starts and 2 is the repeat 192 * count (ie. number of string and space pairs on the stack). 193 * 194 * w 195 * 196 * string x y w - 197 * 198 * Prints a single word starting at position (x, y). Only used in the more 199 * complicated encoding schemes (eg. the ones based on widthshow). 200 * 201 * done 202 * 203 * Makes sure the last page is printed. Only needed when we're printing 204 * more than one page on each sheet of paper. 205 * 206 * The PostScript procedures that support troff's drawing commands have been moved 207 * out of *prologue and put in a separate file (ie. DRAW as defined in path.h). 208 * The procedures are used by the routines in file draw.c, and are copied to the 209 * output file at most once and only when needed. Yet another convenient violation 210 * of page independence. If you don't approve append *drawfile to *prologue and 211 * make sure *drawfile can't be read when DPOST runs. 212 * 213 * Many default values, like the magnification and orientation, are defined in 214 * the prologue, which is where they belong. If they're changed (by options), an 215 * appropriate definition is made after the prologue is added to the output file. 216 * The -P option passes arbitrary PostScript through to the output file. Among 217 * other things it can be used to set (or change) values that can't be accessed by 218 * other options. 219 * 220 * 221 * output language from troff: 222 * all numbers are character strings 223 * 224 * sn size in points 225 * fn font as number from 1-n 226 * cx ascii character x 227 * Cxyz funny char xyz. terminated by white space 228 * Hn go to absolute horizontal position n 229 * Vn go to absolute vertical position n (down is positive) 230 * hn go n units horizontally (relative) 231 * vn ditto vertically 232 * nnc move right nn, then print c (exactly 2 digits!) 233 * (this wart is an optimization that shrinks output file size 234 * about 35% and run-time about 15% while preserving ascii-ness) 235 * Dt ...\n draw operation 't': 236 * Dl x y line from here by x,y 237 * Dc d circle of diameter d with left side here 238 * De x y ellipse of axes x,y with left side here 239 * Da x1 y1 x2 y2 arc counter-clockwise from current point (x, y) to 240 * (x + x1 + x2, y + y1 + y2) 241 * D~ x y x y ... wiggly line by x,y then x,y ... 242 * nb a end of line (information only -- no action needed) 243 * b = space before line, a = after 244 * p new page begins -- set v to 0 245 * #...\n comment 246 * x ...\n device control functions: 247 * x i init 248 * x T s name of device is s 249 * x r n h v resolution is n/inch 250 * h = min horizontal motion, v = min vert 251 * x p pause (can restart) 252 * x s stop -- done forever 253 * x t generate trailer 254 * x f n s font position n contains font s 255 * x H n set character height to n 256 * x S n set slant to N 257 * 258 * Subcommands like "i" are often spelled out like "init". 259 * 260 */ 261 262 263 #include <stdio.h> 264 #include <fcntl.h> 265 #include <signal.h> 266 #include <math.h> 267 #include <ctype.h> 268 #include <time.h> 269 270 #include "comments.h" /* PostScript file structuring comments */ 271 #include "gen.h" /* general purpose definitions */ 272 #include "path.h" /* for the prologue and a few other files */ 273 #include "ext.h" /* external variable definitions */ 274 #include "dev.h" /* typesetter and font descriptions */ 275 #include "dpost.h" /* a few definitions just used here */ 276 277 278 char *prologue = DPOST; /* the basic PostScript prologue */ 279 char *colorfile = COLOR; /* things needed for color support */ 280 char *drawfile = DRAW; /* and drawing */ 281 char *formfile = FORMFILE; /* stuff for multiple pages per sheet */ 282 char *baselinefile = BASELINE; 283 284 char *fontdir = FONTDIR; /* binary device directories found here */ 285 char *hostfontdir = NULL; /* host resident font directory */ 286 287 int formsperpage = 1; /* page images on each piece of paper */ 288 int copies = 1; /* and this many copies of each sheet */ 289 int picflag = ON; /* enable/disable picture inclusion */ 290 291 292 /* 293 * 294 * encoding selects the encoding scheme used to output lines of text. Change it 295 * to something other than 0 at your own risk. The other methods seem to work but 296 * aren't well tested and are not guaranteed. Some special features, like reverse 297 * video, may temporarily change the encoding scheme and reset it to realencoding 298 * when done. 299 * 300 */ 301 302 303 int encoding = DFLTENCODING; 304 int realencoding = DFLTENCODING; 305 int maxencoding = MAXENCODING; 306 307 308 /* 309 * 310 * seenfonts[] keeps track of the fonts we've used, based on internal numbers. It 311 * helps manage host resident fonts and the DOCUMENTFONTS comment, but only works 312 * if all fonts have internal numbers less than MAXINTERNAL. *docfonts counts the 313 * number of font names we've recorded in *temp_file. If it's positive routine 314 * done() adds *temp_file to the output file before quitting. 315 * 316 */ 317 318 319 char seenfonts[MAXINTERNAL+1]; 320 int docfonts = 0; 321 322 323 /* 324 * 325 * devname[] is the device troff used when the job was formatted, while *realdev 326 * is combined with *fontdir and used to locate the font and device tables that 327 * that control the translation of the input files into PostScript. *realdev can 328 * be changed using the -T option, but if you do you may end up getting garbage. 329 * The character code field must agree with PostScript's font encoding and font 330 * names must be properly mapped into PostScript font names in the prologue. 331 * 332 */ 333 334 335 char devname[20] = ""; /* job is formatted for this printer */ 336 char *realdev = DEVNAME; /* a good description of target printer */ 337 338 339 /* 340 * 341 * Standard things that come from binary font and description files for *realdev. 342 * Most are initialized in fontinit() or loadfont(). 343 * 344 */ 345 346 347 struct dev dev; /* DESC.out starts this way */ 348 struct Font *fontbase[NFONT+1]; /* FONT.out files begin this way */ 349 short *pstab; /* list of available sizes */ 350 int nsizes = 1; /* and the number of sizes in that list */ 351 int smnt; /* index of first special font */ 352 int nchtab; /* number of special character names */ 353 int fsize; /* max size of a font files in bytes */ 354 int unitwidth; /* set to dev.unitwidth */ 355 char *chname; /* special character strings */ 356 short *chtab; /* used to locate character names */ 357 char *fitab[NFONT+1]; /* locates char info on each font */ 358 char *widthtab[NFONT+1]; /* character width data for each font */ 359 char *codetab[NFONT+1]; /* and codes to get characters printed */ 360 361 362 /* 363 * 364 * Special characters missing from standard PostScript fonts are defined by files 365 * in directory *fontdir/devpost/charlib. Files have the same names as the troff 366 * special character names (for now at least) and each one defines a PostScript 367 * procedure that begins with the prefix build_ and ends with the character's 368 * name. 369 * 370 * For example, the routine used to build character \(12, would be build_12. 371 * downloaded[] points to an array, allocated in fontinit(), that keeps track of 372 * the characters that have already been defined - so we only do it once. 373 * 374 */ 375 376 377 char *downloaded; /* nonzero means it's been downloaded */ 378 379 380 /* 381 * 382 * Variables that keep track of troff's requests. All are set from values in the 383 * input files. nfonts is adjusted in t_fp() as new fonts are mounted. 384 * 385 */ 386 387 388 int nfonts = 0; /* number of font positions */ 389 int size = 1; /* current size - internal value */ 390 int font = 0; /* font position we're using now */ 391 int hpos = 0; /* where troff wants to be - horizontally */ 392 int vpos = 0; /* same but vertically */ 393 float lastw = 0; /* width of the last input character */ 394 int lastc = 0; /* and its name (or index) */ 395 396 int fontheight = 0; /* points from x H ... */ 397 int fontslant = 0; /* angle from x S ... */ 398 399 int res; /* resolution assumed in input file */ 400 float widthfac = 1.0; /* for emulation = res/dev.res */ 401 402 403 /* 404 * 405 * Remember some of the same things, but this time for the printer. lastend is only 406 * used when we're doing reverse video, and is where the last character on the 407 * current line was printed. 408 * 409 */ 410 411 412 int lastsize = -1; /* last internal size we used */ 413 int lastfont = -1; /* last font we told printer about */ 414 float lastx = -1; /* printer's current position */ 415 int lasty = -1; 416 int lastend; /* where last character on this line was */ 417 418 419 /* 420 * 421 * fontname[] keeps track of the mounted fonts. Filled in (by t_fp()) from data 422 * in the binary font files. 423 * 424 */ 425 426 427 struct { 428 429 char *name; /* name of the font loaded here */ 430 int number; /* its internal number */ 431 432 } fontname[NFONT+1] = {NULL, 0}; 433 434 435 /* 436 * 437 * All the special fonts will be mounted after the last legitimate font position. 438 * It helps when we're translating files prepared for devices, like the 202, that 439 * have a different set of special fonts. The set of special fonts needed when 440 * *realdev's tables are used may not get mounted when we're emulating another 441 * device. gotspecial keeps track of whether we've done it yet. seenpage is set 442 * to TRUE after we've seen the first page command in the input file. It controls 443 * what's done in t_font() and is needed because nfonts is no longer set when the 444 * DESC.out file is read, but rather is updated from "x font" commands in the 445 * input files. 446 * 447 */ 448 449 450 int gotspecial = FALSE; 451 int seenpage = FALSE; 452 453 454 /* 455 * 456 * The amount of horizontal positioning error we accept controls both the size 457 * of the output file and the appearance of the printed text. It's probably most 458 * important when we're emulating other devices, like the APS-5. The error can be 459 * set using the -S option. It's converted from points to machine units in t_init() 460 * after the resolution is known. rvslop is also set in t_init() and only used to 461 * adjust the width of the box that's drawn around text when we're printing in 462 * reverse video mode. 463 * 464 */ 465 466 467 float pointslop = SLOP; /* horizontal error in points */ 468 int slop; /* and machine units */ 469 int rvslop; /* to extend box in reverse video mode */ 470 471 472 /* 473 * 474 * Characters are accumulated and saved in PostScript strings that are eventually 475 * processed by making a single call to procedure t. textcount counts the number 476 * of individual strings collected but not yet processed, and is primarily used to 477 * make sure PostScript's stack doesn't get too big. When textcount is positive 478 * we've started accumulating strings and need to generate a call to PostScript 479 * procedure t to process the text before anything else (like a font change) is 480 * done. 481 * 482 */ 483 484 485 int textcount = 0; /* strings accumulated so far */ 486 int stringstart = 0; /* where the next one starts */ 487 int spacecount = 0; /* spaces seen so far on current line */ 488 489 490 /* 491 * 492 * Things that can be used by text line encoding schemes that need to read and 493 * remember an entire line before doing any output. The strings that make up the 494 * line can be saved in array strings[] and accessed by fields in line[]. *strptr 495 * points to the next free slot in strings[]. 496 * 497 */ 498 499 500 char strings[STRINGSPACE]; 501 char *strptr; 502 Line line[MAXSTACK+3]; 503 504 505 /* 506 * 507 * When we're emulating another device we may want to map font name requests that 508 * come in as "x font pos name" commands into some other font name before anything 509 * else is done (ie. calling loadfont()). Font names can collide or we may just 510 * want to a mapping that depends on the device troff used to format the input 511 * files. devfontmap points to a structure that's filled in by getdevmap() if the 512 * mapping file /usr/lib/font/dev*realdev/fontmaps/devname exists. mapdevfont() 513 * then uses that table to translate font name requests into something else before 514 * loadfont() gets called. 515 * 516 * fontmap[] provides a simple minded translation that maps an unrecognized font 517 * name (in loadfont()) into another font name that we know will be available. It 518 * doesn't provide the fine control available with *devfontmap, but should be good 519 * enough for most jobs. Both structures are only needed when emulating another 520 * device using *realdev's font tables. 521 * 522 */ 523 524 525 Devfontmap *devfontmap = NULL; /* device level */ 526 Fontmap fontmap[] = FONTMAP; /* and general mapping tables - emulation */ 527 528 529 /* 530 * 531 * A few variables that are really only used if we're doing accounting. Designed 532 * for our use at Murray Hill and probably won't suit your needs. Changes should 533 * be easy and can be made in routine account(). 534 * 535 */ 536 537 538 int printed = 0; /* charge for this many pages */ 539 540 541 /* 542 * 543 * Output and accounting file definitions. The PostScript output always goes to 544 * stdout or /dev/null, while the accounting file can be selected using the -A 545 * option. 546 * 547 */ 548 549 550 FILE *tf = NULL; /* PostScript output goes here */ 551 FILE *fp_acct = NULL; /* accounting stuff written here */ 552 553 554 /* 555 * 556 * Need the list of valid options in header() and options(), so I've moved the 557 * definition here. 558 * 559 */ 560 561 562 char *optnames = "a:c:e:m:n:o:p:tw:x:y:A:C:J:F:H:L:OP:R:S:T:DI"; 563 564 565 /* 566 * 567 * Very temporary space that can be used to do things like building up pathnames 568 * immediately before opening a file. Contents may not be preserved across calls 569 * to subroutines defined in this file, so it probably should only be used in low 570 * level subroutines like loadfont() or fontinit() and nowhere else. 571 * 572 */ 573 574 575 char temp[150]; 576 577 578 /*****************************************************************************/ 579 580 581 main(agc, agv) 582 583 584 int agc; 585 char *agv[]; 586 587 588 { 589 590 591 /* 592 * 593 * A program that translates troff output into PostScript. All the input files 594 * must have been formatted for the same device, which doesn't necessarily have to 595 * be *realdev. If there's more than one input file, each begins on a new page. 596 * 597 */ 598 599 600 argc = agc; /* global so everyone can use them */ 601 argv = agv; 602 603 prog_name = argv[0]; /* just for error messages */ 604 605 init_signals(); /* sets up interrupt handling */ 606 header(); /* PostScript file structuring comments */ 607 options(); /* command line options */ 608 arguments(); /* translate all the input files */ 609 done(); /* add trailing comments etc. */ 610 account(); /* job accounting data */ 611 612 exit(x_stat); /* everything probably went OK */ 613 614 } /* End of main */ 615 616 617 /*****************************************************************************/ 618 619 620 init_signals() 621 622 623 { 624 625 626 void interrupt(); /* signal handler */ 627 628 629 /* 630 * 631 * Make sure we handle interrupts. 632 * 633 */ 634 635 636 if ( signal(SIGINT, interrupt) == SIG_IGN ) { 637 signal(SIGINT, SIG_IGN); 638 signal(SIGQUIT, SIG_IGN); 639 signal(SIGHUP, SIG_IGN); 640 } else { 641 signal(SIGHUP, interrupt); 642 signal(SIGQUIT, interrupt); 643 } /* End else */ 644 645 signal(SIGTERM, interrupt); 646 647 } /* End of init_signals */ 648 649 650 /*****************************************************************************/ 651 652 653 header() 654 655 656 { 657 658 659 int ch; /* return value from getopt() */ 660 int old_optind = optind; /* for restoring optind - should be 1 */ 661 662 663 /* 664 * 665 * Scans the option list looking for things, like the prologue file, that we need 666 * right away but could be changed from the default. Doing things this way is an 667 * attempt to conform to Adobe's latest file structuring conventions. In particular 668 * they now say there should be nothing executed in the prologue, and they have 669 * added two new comments that delimit global initialization calls. Once we know 670 * where things really are we write out the job header, follow it by the prologue, 671 * and then add the ENDPROLOG and BEGINSETUP comments. 672 * 673 */ 674 675 676 while ( (ch = getopt(argc, argv, optnames)) != EOF ) 677 if ( ch == 'L' ) 678 setpaths(optarg); 679 else if ( ch == '?' ) 680 error(FATAL, ""); 681 682 optind = old_optind; /* get ready for option scanning */ 683 684 fprintf(stdout, "%s", NONCONFORMING); 685 fprintf(stdout, "%s %s\n", VERSION, PROGRAMVERSION); 686 fprintf(stdout, "%s %s\n", DOCUMENTFONTS, ATEND); 687 fprintf(stdout, "%s %s\n", PAGES, ATEND); 688 fprintf(stdout, "%s", ENDCOMMENTS); 689 690 if ( cat(prologue) == FALSE ) 691 error(FATAL, "can't read %s", prologue); 692 693 fprintf(stdout, "%s", ENDPROLOG); 694 fprintf(stdout, "%s", BEGINSETUP); 695 fprintf(stdout, "mark\n"); 696 697 } /* End of header */ 698 699 700 /*****************************************************************************/ 701 702 703 options() 704 705 706 { 707 708 709 int ch; /* name returned by getopt() */ 710 711 extern char *optarg; /* option argument set by getopt() */ 712 extern int optind; 713 714 715 /* 716 * 717 * Reads and processes the command line options. There are, without a doubt, too 718 * many options! 719 * 720 */ 721 722 723 while ( (ch = getopt(argc, argv, optnames)) != EOF ) { 724 725 switch ( ch ) { 726 727 case 'a': /* aspect ratio */ 728 fprintf(stdout, "/aspectratio %s def\n", optarg); 729 break; 730 731 case 'c': /* number of copies */ 732 copies = atoi(optarg); 733 fprintf(stdout, "/#copies %s store\n", optarg); 734 break; 735 736 case 'e': /* change the encoding scheme */ 737 if ( (encoding = atoi(optarg)) < 0 || encoding > MAXENCODING ) 738 encoding = DFLTENCODING; 739 realencoding = encoding; 740 break; 741 742 case 'm': /* magnification */ 743 fprintf(stdout, "/magnification %s def\n", optarg); 744 break; 745 746 case 'n': /* forms per page */ 747 formsperpage = atoi(optarg); 748 fprintf(stdout, "%s %s\n", FORMSPERPAGE, optarg); 749 fprintf(stdout, "/formsperpage %s def\n", optarg); 750 break; 751 752 case 'o': /* output page list */ 753 out_list(optarg); 754 break; 755 756 case 'p': /* landscape or portrait mode */ 757 if ( *optarg == 'l' ) 758 fprintf(stdout, "/landscape true def\n"); 759 else fprintf(stdout, "/landscape false def\n"); 760 break; 761 762 case 't': /* just for compatibility */ 763 break; 764 765 case 'w': /* line width for drawing */ 766 fprintf(stdout, "/linewidth %s def\n", optarg); 767 break; 768 769 case 'x': /* shift horizontally */ 770 fprintf(stdout, "/xoffset %s def\n", optarg); 771 break; 772 773 case 'y': /* and vertically on the page */ 774 fprintf(stdout, "/yoffset %s def\n", optarg); 775 break; 776 777 case 'A': /* force job accounting */ 778 case 'J': 779 if ( (fp_acct = fopen(optarg, "a")) == NULL ) 780 error(FATAL, "can't open accounting file %s", optarg); 781 break; 782 783 case 'C': /* copy file to straight to output */ 784 if ( cat(optarg) == FALSE ) 785 error(FATAL, "can't read %s", optarg); 786 break; 787 788 case 'F': /* font table directory */ 789 fontdir = optarg; 790 break; 791 792 case 'H': /* host resident font directory */ 793 hostfontdir = optarg; 794 break; 795 796 case 'L': /* PostScript prologue file */ 797 setpaths(optarg); /* already been done in header() */ 798 break; 799 800 case 'O': /* turn picture inclusion off */ 801 picflag = OFF; 802 break; 803 804 case 'P': /* PostScript pass through */ 805 fprintf(stdout, "%s\n", optarg); 806 break; 807 808 case 'R': /* special global or page level request */ 809 saverequest(optarg); 810 break; 811 812 case 'S': /* horizontal position error */ 813 if ( (pointslop = atof(optarg)) < 0 ) 814 pointslop = 0; 815 break; 816 817 case 'T': /* target printer */ 818 realdev = optarg; 819 break; 820 821 case 'D': /* debug flag */ 822 debug = ON; 823 tf = stdout; 824 break; 825 826 case 'I': /* ignore FATAL errors */ 827 ignore = ON; 828 break; 829 830 case '?': /* don't know the option */ 831 error(FATAL, ""); 832 break; 833 834 default: 835 error(FATAL, "missing case for option %c", ch); 836 break; 837 838 } /* End switch */ 839 } /* End while */ 840 841 argc -= optind; /* get ready for non-options args */ 842 argv += optind; 843 844 } /* End of options */ 845 846 847 /*****************************************************************************/ 848 849 850 setpaths(name) 851 852 853 char *name; /* string that followed the -L option */ 854 855 856 { 857 858 859 char *path; /* start of the pathname */ 860 861 862 /* 863 * 864 * Extends the -L option to permit run time modification of pathnames that were 865 * fixed or didn't exist in previous versions of dpost. For example, the PostScript 866 * drawing procedures have been moved out of *prologue and put in *drawfile. The 867 * new syntax can be either -Lfile or -Lname:file. If the "name:" prefix is omitted 868 * file will be used as the prologue, otherwise name should be one of "prologue", 869 * "font", "draw", "color", or "form" and is used to select the pointer that gets 870 * set to string "file". 871 * 872 */ 873 874 875 for ( path = name; *path; path++ ) 876 if ( *path == ':' || *path == ' ' ) { 877 while ( *path == ':' || *path == ' ' ) path++; 878 break; 879 } /* End if */ 880 881 if ( *path == '\0' ) /* didn't find a "name:" prefix */ 882 path = name; 883 884 if ( path == name || strncmp(name, "prologue", strlen("prologue")) == 0 ) 885 prologue = path; 886 else if ( strncmp(name, "draw", strlen("draw")) == 0 ) 887 drawfile = path; 888 else if ( strncmp(name, "color", strlen("color")) == 0 ) 889 colorfile = path; 890 else if ( strncmp(name, "form", strlen("form")) == 0 ) 891 formfile = path; 892 else if ( strncmp(name, "baseline", strlen("baseline")) == 0 ) 893 baselinefile = path; 894 895 } /* End of setpaths */ 896 897 898 /*****************************************************************************/ 899 900 901 setup() 902 903 904 { 905 906 907 /* 908 * Handles things that must be done after the options are read but before the 909 * input files are processed. Called from t_init() after an "x init" command is 910 * read, because we need the resolution before we can generate the call to the 911 * setup procedure defined in *prologue. Only allowing one call to setup assumes 912 * all the input files have been prepared for the same device. 913 * 914 */ 915 916 917 writerequest(0, stdout); /* global requests eg. manual feed */ 918 fprintf(stdout, "/resolution %d def\n", res); 919 fprintf(stdout, "setup\n"); 920 fprintf(stdout, "%d setdecoding\n", encoding); 921 922 if ( formsperpage > 1 ) { /* followed by stuff for multiple pages */ 923 if ( cat(formfile) == FALSE ) 924 error(FATAL, "can't read %s", formfile); 925 fprintf(stdout, "%d setupforms\n", formsperpage); 926 } /* End if */ 927 928 fprintf(stdout, "%s", ENDSETUP); 929 930 } /* End of setup */ 931 932 933 /*****************************************************************************/ 934 935 936 arguments() 937 938 939 { 940 941 942 FILE *fp; /* next input file */ 943 944 945 /* 946 * 947 * Makes sure all the non-option command line arguments are processed. If we get 948 * here and there aren't any arguments left, or if '-' is one of the input files 949 * we'll translate stdin. 950 * 951 */ 952 953 954 if ( argc < 1 ) 955 conv(stdin); 956 else 957 while ( argc > 0 ) { 958 if ( strcmp(*argv, "-") == 0 ) 959 fp = stdin; 960 else if ( (fp = fopen(*argv, "r")) == NULL ) 961 error(FATAL, "can't open %s", *argv); 962 conv(fp); 963 if ( fp != stdin ) 964 fclose(fp); 965 argc--; 966 argv++; 967 } /* End while */ 968 969 } /* End of arguments */ 970 971 972 /*****************************************************************************/ 973 974 975 done() 976 977 978 { 979 980 981 /* 982 * 983 * Finished with all the input files, so mark the end of the pages with a TRAILER 984 * comment, make sure the last page prints, and add things like the DOCUMENTFONTS 985 * and PAGES comments that can only be determined after all the input files have 986 * been read. 987 * 988 */ 989 990 991 fprintf(stdout, "%s", TRAILER); 992 fprintf(stdout, "done\n"); 993 994 if ( temp_file != NULL ) { 995 if ( docfonts > 0 ) { 996 cat(temp_file); 997 putc('\n', stdout); 998 } /* End if */ 999 unlink(temp_file); 1000 } /* End if */ 1001 1002 fprintf(stdout, "%s %d\n", PAGES, printed); 1003 1004 } /* End of done */ 1005 1006 1007 /*****************************************************************************/ 1008 1009 1010 account() 1011 1012 1013 { 1014 1015 1016 /* 1017 * 1018 * Writes an accounting record to *fp_acct provided it's not NULL. Accounting is 1019 * requested using the -A or -J options. 1020 * 1021 */ 1022 1023 if ( fp_acct != NULL ) 1024 fprintf(fp_acct, " print %d\n copies %d\n", printed, copies); 1025 1026 } /* End of account */ 1027 1028 1029 /*****************************************************************************/ 1030 1031 1032 conv(fp) 1033 1034 1035 register FILE *fp; /* next input file */ 1036 1037 1038 { 1039 1040 1041 register int c; /* usually first char in next command */ 1042 int m, n, n1, m1; /* when we need to read integers */ 1043 char str[50]; /* for special chars and font numbers */ 1044 1045 1046 /* 1047 * 1048 * Controls the translation of troff's device independent output language into 1049 * PostScript. The call to t_page() that prints the last page is made when we 1050 * exit the loop, but probably belongs in t_trailer(). 1051 * 1052 */ 1053 1054 1055 redirect(-1); /* only do output after a page command */ 1056 lineno = 1; /* line in current file */ 1057 1058 while ((c = getc(fp)) != EOF) { 1059 1060 switch (c) { 1061 1062 case '\n': /* just count this line */ 1063 lineno++; 1064 break; 1065 1066 case ' ': /* when input is text */ 1067 case 0: /* occasional noise creeps in */ 1068 break; 1069 1070 case '0': case '1': case '2': case '3': case '4': 1071 case '5': case '6': case '7': case '8': case '9': 1072 /* two motion digits plus a character */ 1073 hmot((c-'0')*10 + getc(fp)-'0'); 1074 put1(getc(fp)); 1075 break; 1076 1077 case 'c': /* single ascii character */ 1078 put1(getc(fp)); 1079 break; 1080 1081 case 'C': /* special character */ 1082 fscanf(fp, "%s", str); 1083 put1s(str); 1084 break; 1085 1086 case 'N': /* character at position n */ 1087 fscanf(fp, "%d", &m); 1088 endtext(); 1089 oput(m); 1090 break; 1091 1092 case 'D': /* drawing functions */ 1093 endtext(); 1094 getdraw(); 1095 if ( size != lastsize ) 1096 t_sf(); 1097 switch ((c=getc(fp))) { 1098 case 'p': /* draw a path */ 1099 while (fscanf(fp, "%d %d", &n, &m) == 2) 1100 drawline(n, m); 1101 lineno++; 1102 break; 1103 1104 case 'l': /* draw a line */ 1105 fscanf(fp, "%d %d %c", &n, &m, &n1); 1106 drawline(n, m); 1107 break; 1108 1109 case 'c': /* circle */ 1110 fscanf(fp, "%d", &n); 1111 drawcirc(n); 1112 break; 1113 1114 case 'e': /* ellipse */ 1115 fscanf(fp, "%d %d", &m, &n); 1116 drawellip(m, n); 1117 break; 1118 1119 case 'a': /* counter-clockwise arc */ 1120 case 'A': /* clockwise arc */ 1121 fscanf(fp, "%d %d %d %d", &n, &m, &n1, &m1); 1122 drawarc(n, m, n1, m1, c); 1123 break; 1124 1125 case 'q': /* spline without end points */ 1126 drawspline(fp, 1); 1127 lineno++; 1128 break; 1129 1130 case '~': /* wiggly line */ 1131 drawspline(fp, 2); 1132 lineno++; 1133 break; 1134 1135 default: 1136 error(FATAL, "unknown drawing function %c", c); 1137 break; 1138 } /* End switch */ 1139 break; 1140 1141 case 's': /* use this point size */ 1142 fscanf(fp, "%d", &n); /* ignore fractional sizes */ 1143 setsize(t_size(n)); 1144 break; 1145 1146 case 'f': /* use font mounted here */ 1147 fscanf(fp, "%s", str); 1148 setfont(t_font(str)); 1149 break; 1150 1151 case 'H': /* absolute horizontal motion */ 1152 fscanf(fp, "%d", &n); 1153 hgoto(n); 1154 break; 1155 1156 case 'h': /* relative horizontal motion */ 1157 fscanf(fp, "%d", &n); 1158 hmot(n); 1159 break; 1160 1161 case 'w': /* word space */ 1162 break; 1163 1164 case 'V': /* absolute vertical position */ 1165 fscanf(fp, "%d", &n); 1166 vgoto(n); 1167 break; 1168 1169 case 'v': /* relative vertical motion */ 1170 fscanf(fp, "%d", &n); 1171 vmot(n); 1172 break; 1173 1174 case 'p': /* new page */ 1175 fscanf(fp, "%d", &n); 1176 t_page(n); 1177 break; 1178 1179 case 'n': /* end of line */ 1180 while ( (c = getc(fp)) != '\n' && c != EOF ) ; 1181 t_newline(); 1182 lineno++; 1183 break; 1184 1185 case '#': /* comment */ 1186 while ( (c = getc(fp)) != '\n' && c != EOF ) ; 1187 lineno++; 1188 break; 1189 1190 case 'x': /* device control function */ 1191 devcntrl(fp); 1192 lineno++; 1193 break; 1194 1195 default: 1196 error(FATAL, "unknown input character %o %c", c, c); 1197 done(); 1198 1199 } /* End switch */ 1200 1201 } /* End while */ 1202 1203 t_page(-1); /* print the last page */ 1204 endtext(); 1205 1206 } /* End of conv */ 1207 1208 1209 /*****************************************************************************/ 1210 1211 1212 devcntrl(fp) 1213 1214 1215 FILE *fp; /* current input file */ 1216 1217 1218 { 1219 1220 1221 char str[50], buf[256], str1[50]; 1222 int c, n; 1223 1224 1225 /* 1226 * 1227 * Called from conv() to process the rest of a device control function. There's 1228 * a whole family of them and they all start with the string "x ", which we've 1229 * already read. The "x X ..." commands are an extensible (and device dependent) 1230 * family that we use here for things like picture inclusion. Unrecognized device 1231 * control commands are ignored. 1232 * 1233 */ 1234 1235 1236 fscanf(fp, "%s", str); /* get the control function name */ 1237 1238 switch ( str[0] ) { /* only the first character counts */ 1239 1240 case 'i': /* initialize */ 1241 t_init(); 1242 break; 1243 1244 case 'T': /* device name */ 1245 fscanf(fp, "%s", devname); 1246 getdevmap(); 1247 strcpy(devname, realdev); 1248 break; 1249 1250 case 't': /* trailer */ 1251 t_trailer(); 1252 break; 1253 1254 case 'p': /* pause -- can restart */ 1255 t_reset('p'); 1256 break; 1257 1258 case 's': /* stop */ 1259 t_reset('s'); 1260 break; 1261 1262 case 'r': /* resolution assumed when prepared */ 1263 fscanf(fp, "%d", &res); 1264 break; 1265 1266 case 'f': /* load font in a position */ 1267 fscanf(fp, "%d %s", &n, str); 1268 fgets(buf, sizeof buf, fp); /* in case there's a filename */ 1269 ungetc('\n', fp); /* fgets() goes too far */ 1270 str1[0] = '\0'; /* in case there's nothing to come in */ 1271 sscanf(buf, "%s", str1); 1272 loadfont(n, mapdevfont(str), str1); 1273 break; 1274 1275 /* these don't belong here... */ 1276 case 'H': /* char height */ 1277 fscanf(fp, "%d", &n); 1278 t_charht(n); 1279 break; 1280 1281 case 'S': /* slant */ 1282 fscanf(fp, "%d", &n); 1283 t_slant(n); 1284 break; 1285 1286 case 'X': /* copy through - from troff */ 1287 fscanf(fp, " %[^: \n]:", str); 1288 fgets(buf, sizeof(buf), fp); 1289 ungetc('\n', fp); 1290 if ( strcmp(str, "PI") == 0 || strcmp(str, "PictureInclusion") == 0 ) 1291 picture(buf); 1292 else if ( strcmp(str, "InlinePicture") == 0 ) 1293 inlinepic(fp, buf); 1294 else if ( strcmp(str, "BeginPath") == 0 ) 1295 beginpath(buf, FALSE); 1296 else if ( strcmp(str, "DrawPath") == 0 ) 1297 drawpath(buf, FALSE); 1298 else if ( strcmp(str, "BeginObject") == 0 ) 1299 beginpath(buf, TRUE); 1300 else if ( strcmp(str, "EndObject") == 0 ) 1301 drawpath(buf, TRUE); 1302 else if ( strcmp(str, "NewBaseline") == 0 ) 1303 newbaseline(buf); 1304 else if ( strcmp(str, "DrawText") == 0 ) 1305 drawtext(buf); 1306 else if ( strcmp(str, "SetText") == 0 ) 1307 settext(buf); 1308 else if ( strcmp(str, "SetColor") == 0 ) { 1309 newcolor(buf); 1310 setcolor(); 1311 } else if ( strcmp(str, "PS") == 0 || strcmp(str, "PostScript") == 0 ) { 1312 endtext(); 1313 /* xymove(hpos, vpos); ul90-22006 */ 1314 fprintf(tf, "%s", buf); 1315 } /* End else */ 1316 break; 1317 } /* End switch */ 1318 1319 while ( (c = getc(fp)) != '\n' && c != EOF ) ; 1320 1321 } /* End of devcntrl */ 1322 1323 1324 /*****************************************************************************/ 1325 1326 1327 fontinit() 1328 1329 1330 { 1331 1332 1333 int fin; /* for reading the DESC.out file */ 1334 char *filebase; /* the whole thing goes here */ 1335 int i; /* loop index */ 1336 1337 1338 /* 1339 * 1340 * Reads *realdev's DESC.out file and uses what's there to initialize things like 1341 * the list of available point sizes. Old versions of the program used *devname's 1342 * DESC.out file to initialize nfonts, but that meant we needed to have *devname's 1343 * binary font files available for emulation. That restriction has been removed 1344 * and we now set nfonts using the "x font" commands in the input file, so by the 1345 * time we get here all we really need is *realdev. In fact devcntrl() reads the 1346 * device name from the "x T ..." command, but almost immediately replaces it with 1347 * string *realdev so we end up using *realdev's DESC.out file. Later on (in 1348 * t_font()) we mount all of *realdev's special fonts after the last legitimate 1349 * font position, just to be sure device emulation works reasonably well - there's 1350 * no guarantee *devname's special fonts match what's needed when *realdev's tables 1351 * are used. 1352 * 1353 */ 1354 1355 1356 sprintf(temp, "%s/dev%s/DESC.out", fontdir, devname); 1357 if ( (fin = open(temp, 0)) < 0 ) 1358 error(FATAL, "can't open tables for %s", temp); 1359 1360 read(fin, &dev, sizeof(struct dev)); 1361 1362 nfonts = 0; /* was dev.nfonts - now set in t_fp() */ 1363 nsizes = dev.nsizes; 1364 nchtab = dev.nchtab; 1365 unitwidth = dev.unitwidth; 1366 1367 if ( (filebase = malloc(dev.filesize)) == NULL ) 1368 error(FATAL, "no memory for description file"); 1369 1370 read(fin, filebase, dev.filesize); /* all at once */ 1371 close(fin); 1372 1373 pstab = (short *) filebase; 1374 chtab = pstab + nsizes + 1; 1375 chname = (char *) (chtab + nchtab); 1376 fsize = 3 * 255 + nchtab + 128 - 32 + sizeof(struct Font); 1377 1378 for ( i = 1; i <= NFONT; i++ ) { /* so loadfont() knows nothing's there */ 1379 fontbase[i] = NULL; 1380 widthtab[i] = codetab[i] = fitab[i] = NULL; 1381 } /* End for */ 1382 1383 if ( (downloaded = (char *) calloc(nchtab + 128, sizeof(char))) == NULL ) 1384 error(FATAL, "no memory"); 1385 1386 } /* End of fontinit */ 1387 1388 1389 /*****************************************************************************/ 1390 1391 1392 loadfont(n, s, s1) 1393 1394 1395 int n; /* load this font position */ 1396 char *s; /* with the .out file for this font */ 1397 char *s1; /* taken from here - possibly */ 1398 1399 1400 { 1401 1402 1403 int fin; /* for reading *s.out file */ 1404 int nw; /* number of width table entries */ 1405 1406 1407 /* 1408 * 1409 * Loads font position n with the binary font file for *s.out provided it's not 1410 * already there. If *s1 is NULL or points to the empty string we read files from 1411 * directory *fontdir/dev*devname, otherwise directory *s1 is used. If the first 1412 * open fails we try to map font *s into one we expect will be available, and then 1413 * we try again. 1414 * 1415 */ 1416 1417 1418 if ( n < 0 || n > NFONT ) /* make sure it's a legal position */ 1419 error(FATAL, "illegal fp command %d %s", n, s); 1420 1421 if ( fontbase[n] != NULL && strcmp(s, fontbase[n]->namefont) == 0 ) 1422 return; 1423 1424 if ( s1 == NULL || s1[0] == '\0' ) 1425 sprintf(temp, "%s/dev%s/%s.out", fontdir, devname, s); 1426 else sprintf(temp, "%s/%s.out", s1, s); 1427 1428 if ( (fin = open(temp, 0)) < 0 ) { 1429 sprintf(temp, "%s/dev%s/%s.out", fontdir, devname, mapfont(s)); 1430 if ( (fin = open(temp, 0)) < 0 ) 1431 error(FATAL, "can't open font table %s", temp); 1432 } /* End if */ 1433 1434 if ( fontbase[n] != NULL ) /* something's already there */ 1435 free(fontbase[n]); /* so release the memory first */ 1436 1437 fontbase[n] = (struct Font *) malloc(fsize); 1438 if ( fontbase[n] == NULL ) 1439 error(FATAL, "Out of space in loadfont %s", s); 1440 1441 read(fin, fontbase[n], fsize); 1442 close(fin); 1443 1444 if ( smnt == 0 && fontbase[n]->specfont == 1 ) 1445 smnt = n; 1446 1447 nw = fontbase[n]->nwfont & BMASK; 1448 widthtab[n] = (char *) fontbase[n] + sizeof(struct Font); 1449 codetab[n] = (char *) widthtab[n] + 2 * nw; 1450 fitab[n] = (char *) widthtab[n] + 3 * nw; 1451 1452 t_fp(n, fontbase[n]->namefont, fontbase[n]->intname); 1453 1454 if ( debug == ON ) 1455 fontprint(n); 1456 1457 } /* End of loadfont */ 1458 1459 1460 /*****************************************************************************/ 1461 1462 1463 loadspecial() 1464 1465 1466 { 1467 1468 1469 char *p; /* for next binary font file */ 1470 int nw; /* width entries in next font */ 1471 int i; /* loop index */ 1472 1473 1474 /* 1475 * 1476 * Loads all the special fonts after the last legal font position. Mostly used 1477 * for device emulation, but we'll do it no matter what. Needed because there's 1478 * no consistency in special fonts across different devices, and relying on having 1479 * them mounted in the input file doesn't guarantee the whole collection will be 1480 * there. The special fonts are determined and mounted using the copy of the 1481 * DESC.out file that's been read into memory. Initially had this stuff at the 1482 * end of fontinit(), but we now don't know nfonts until much later. 1483 * 1484 */ 1485 1486 1487 if ( gotspecial == FALSE ) 1488 for ( i = 1, p = chname + dev.lchname; i <= dev.nfonts; i++ ) { 1489 nw = *p & BMASK; 1490 if ( ((struct Font *) p)->specfont == 1 ) 1491 loadfont(++nfonts, ((struct Font *)p)->namefont, NULL); 1492 p += 3 * nw + dev.nchtab + 128 - 32 + sizeof(struct Font); 1493 } /* End for */ 1494 1495 gotspecial = TRUE; 1496 1497 } /* End of loadspecial */ 1498 1499 1500 /*****************************************************************************/ 1501 char *defaultFonts[] = 1502 { "R", "I", "B", "BI", "CW", "H", "HB", "HX", "S1", "S", NULL }; 1503 1504 loaddefault() 1505 { 1506 int i; 1507 1508 for (i = 0; defaultFonts[i] != NULL ; i++) 1509 loadfont(++nfonts, defaultFonts[i], NULL); 1510 } 1511 1512 1513 fontprint(i) 1514 1515 1516 int i; /* font's index in fontbase[] */ 1517 1518 1519 { 1520 1521 1522 int j, n; 1523 char *p; 1524 1525 1526 /* 1527 * 1528 * Debugging routine that dumps data about the font mounted in position i. 1529 * 1530 */ 1531 1532 1533 fprintf(tf, "font %d:\n", i); 1534 1535 p = (char *) fontbase[i]; 1536 n = fontbase[i]->nwfont & BMASK; 1537 1538 fprintf(tf, "base=0%o, nchars=%d, spec=%d, name=%s, widtab=0%o, fitab=0%o\n", 1539 p, n, fontbase[i]->specfont, fontbase[i]->namefont, widthtab[i], fitab[i]); 1540 1541 fprintf(tf, "widths:\n"); 1542 for ( j = 0; j <= n; j++ ) { 1543 fprintf(tf, " %2d", widthtab[i][j] & BMASK); 1544 if ( j % 20 == 19 ) putc('\n', tf); 1545 } /* End for */ 1546 1547 fprintf(tf, "\ncodetab:\n"); 1548 for ( j = 0; j <= n; j++ ) { 1549 fprintf(tf, " %2d", codetab[i][j] & BMASK); 1550 if ( j % 20 == 19 ) putc('\n', tf); 1551 } /* End for */ 1552 1553 fprintf(tf, "\nfitab:\n"); 1554 for ( j = 0; j <= dev.nchtab + 128-32; j++ ) { 1555 fprintf(tf, " %2d", fitab[i][j] & BMASK); 1556 if ( j % 20 == 19 ) putc('\n', tf); 1557 } /* End for */ 1558 1559 putc('\n', tf); 1560 1561 } /* End of fontprint */ 1562 1563 1564 /*****************************************************************************/ 1565 1566 1567 char *mapfont(name) 1568 1569 1570 char *name; /* troff wanted this font */ 1571 1572 1573 { 1574 1575 1576 int i; /* loop index */ 1577 1578 1579 /* 1580 * 1581 * If loadfont() can't find font *name we map it into something else that should 1582 * be available and return a pointer to the new name. Used mostly for emulating 1583 * devices like the APS-5. 1584 * 1585 */ 1586 1587 1588 for ( i = 0; fontmap[i].name != NULL; i++ ) 1589 if ( strcmp(name, fontmap[i].name) == 0 ) 1590 return(fontmap[i].use); 1591 1592 switch ( *++name ) { 1593 case 'I': 1594 return("I"); 1595 1596 case 'B': 1597 return("B"); 1598 1599 case 'X': 1600 return("BI"); 1601 1602 default: 1603 return("R"); 1604 } /* End switch */ 1605 1606 } /* End of mapfont */ 1607 1608 1609 /*****************************************************************************/ 1610 1611 1612 getdevmap() 1613 1614 1615 { 1616 1617 1618 FILE *fp; /* for reading the device fontmap file */ 1619 int i = 0; /* number of mapping pairs we've read */ 1620 int c; /* for skipping lines */ 1621 1622 1623 /* 1624 * 1625 * Looks for the device font mapping file *fontdir/dev*realdev/fontmaps/devname. 1626 * The file, if it exists, should be an ASCII file containing pairs of one or two 1627 * character font names per line. The first name is the font troff will be asking 1628 * for and the second is the one we'll use. Comments are lines that begin with 1629 * a '#' as the first non-white space character on a line. The devfontmap list 1630 * ends with a member that has the empty string in the name field. 1631 * 1632 */ 1633 1634 1635 sprintf(temp, "%s/dev%s/fontmaps/%s", fontdir, realdev, devname); 1636 1637 if ( devfontmap == NULL && (fp = fopen(temp, "r")) != NULL ) { 1638 devfontmap = (Devfontmap *) malloc(10 * sizeof(Devfontmap)); 1639 1640 while ( fscanf(fp, "%s", temp) != EOF ) { 1641 if ( temp[0] != '#' && strlen(temp) < 3 ) 1642 if ( fscanf(fp, "%s", &temp[3]) == 1 && strlen(&temp[3]) < 3 ) { 1643 strcpy((devfontmap + i)->name, temp); 1644 strcpy((devfontmap + i)->use, &temp[3]); 1645 if ( ++i % 10 == 0 ) 1646 devfontmap = (Devfontmap *) realloc(devfontmap, (i + 10) * sizeof(Devfontmap)); 1647 } /* End if */ 1648 while ( (c = getc(fp)) != '\n' && c != EOF ) ; 1649 } /* End while */ 1650 1651 (devfontmap + i)->name[0] = '\0'; /* end the list we just read */ 1652 fclose(fp); 1653 } /* End if */ 1654 1655 } /* End of getdevmap */ 1656 1657 1658 /*****************************************************************************/ 1659 1660 1661 char *mapdevfont(str) 1662 1663 1664 char *str; 1665 1666 1667 { 1668 1669 1670 int i; 1671 1672 1673 /* 1674 * 1675 * Called immediately before loadfont() after an 'x font' command is recognized. 1676 * Takes the font name that troff asked for, looks it up in the devfontmap list, 1677 * and returns the mapped name to the caller. No mapping is done if the devfontmap 1678 * list is empty or font *str isn't found in the list. 1679 * 1680 */ 1681 1682 1683 if ( devfontmap != NULL ) 1684 for ( i = 0; (devfontmap + i)->name[0] != '\0'; i++ ) 1685 if ( strcmp((devfontmap + i)->name, str) == 0 ) 1686 return((devfontmap + i)->use); 1687 1688 return(str); 1689 1690 } /* End of mapdevfont */ 1691 1692 1693 /*****************************************************************************/ 1694 1695 1696 reset() 1697 1698 1699 { 1700 1701 1702 /* 1703 * 1704 * Resets the variables that keep track of the printer's current position, font, 1705 * and size. Typically used after a restore/save pair (eg. when we finish with a 1706 * page) to make sure we force the printer back into sync (in terms of the font 1707 * and current point) before text is printed. 1708 * 1709 */ 1710 1711 1712 lastx = -(slop + 1); 1713 lasty = -1; 1714 lastfont = lastsize = -1; 1715 1716 } /* End of reset */ 1717 1718 1719 /*****************************************************************************/ 1720 1721 1722 resetpos() 1723 1724 1725 { 1726 1727 1728 /* 1729 * 1730 * Resets the variables that keep track of the printer's current position. Used 1731 * when there's a chance we've lost track of the printer's current position or 1732 * done something that may have wiped it out, and we want to force dpost to set 1733 * the printer's position before printing text or whatever. For example stroke or 1734 * fill implicitly do a newpath, and that wipes out the current point, unless the 1735 * calls were bracketed by a gsave/grestore pair. 1736 * 1737 */ 1738 1739 1740 lastx = -(slop + 1); 1741 lasty = -1; 1742 1743 } /* End of resetpos */ 1744 1745 1746 /*****************************************************************************/ 1747 1748 1749 t_init() 1750 1751 1752 { 1753 1754 1755 static int initialized = FALSE; /* only do most things once */ 1756 1757 1758 /* 1759 * 1760 * Called from devcntrl() after an "x init" command is read. Things only work if 1761 * we've already seen the "x res" command, and much of the stuff, including the 1762 * call to setup, should only be done once. Restricting everything to one call of 1763 * setup (ie. the one in the prologue) means all the input files must have been 1764 * formatted for the same device. 1765 * 1766 */ 1767 1768 1769 endtext(); /* moved - for cat'ed troff files */ 1770 1771 if ( initialized == FALSE ) { /* only do this stuff once per job */ 1772 fontinit(); 1773 gotspecial = FALSE; 1774 widthfac = (float) res /dev.res; 1775 slop = pointslop * res / POINTS + .5; 1776 rvslop = res * .025; 1777 setup(); 1778 initialized = TRUE; 1779 } /* End if */ 1780 1781 hpos = vpos = 0; /* upper left corner */ 1782 setsize(t_size(10)); /* start somewhere */ 1783 reset(); /* force position and font stuff - later */ 1784 1785 } /* End of t_init */ 1786 1787 1788 /*****************************************************************************/ 1789 1790 1791 t_page(pg) 1792 1793 1794 int pg; /* troff's current page number */ 1795 1796 1797 { 1798 1799 1800 static int lastpg = 0; /* last one we started - for ENDPAGE */ 1801 1802 1803 /* 1804 * 1805 * Called whenever we've finished the last page and want to get ready for the 1806 * next one. Also used at the end of each input file, so we have to be careful 1807 * about what's done. The first time through (up to the redirect(pg) call) output 1808 * goes to /dev/null because of the redirect(-1) call made in conv(). 1809 * 1810 * Adobe now recommends that the showpage operator occur after the page level 1811 * restore so it can be easily redefined to have side-effects in the printer's VM. 1812 * Although it seems reasonable I haven't implemented it, because it makes other 1813 * things, like selectively setting manual feed or choosing an alternate paper 1814 * tray, clumsy - at least on a per page basis. 1815 * 1816 */ 1817 1818 1819 if ( tf == stdout ) /* count the last page */ 1820 printed++; 1821 1822 endtext(); /* print the last line? */ 1823 1824 fprintf(tf, "cleartomark\n"); 1825 fprintf(tf, "showpage\n"); 1826 fprintf(tf, "restore\n"); 1827 fprintf(tf, "%s %d %d\n", ENDPAGE, lastpg, printed); 1828 1829 redirect(pg); 1830 1831 fprintf(tf, "%s %d %d\n", PAGE, pg, printed+1); 1832 fprintf(tf, "save\n"); 1833 fprintf(tf, "mark\n"); 1834 writerequest(printed+1, tf); 1835 fprintf(tf, "%d pagesetup\n", printed+1); 1836 setcolor(); 1837 1838 lastpg = pg; /* for the next ENDPAGE comment */ 1839 hpos = vpos = 0; /* get ready for the next page */ 1840 reset(); /* force position and font stuff - later */ 1841 1842 seenpage = TRUE; 1843 1844 } /* End of t_page */ 1845 1846 1847 /*****************************************************************************/ 1848 1849 1850 t_newline() 1851 1852 1853 { 1854 1855 1856 /* 1857 * 1858 * Just finished the last line. All we do is set the horizontal position to 0, 1859 * although even that probably isn't necessary. 1860 * 1861 */ 1862 1863 1864 hpos = 0; 1865 1866 } /* End of t_newline */ 1867 1868 1869 /*****************************************************************************/ 1870 1871 1872 t_size(n) 1873 1874 1875 int n; /* convert this to an internal size */ 1876 1877 1878 { 1879 1880 1881 int i; /* loop index */ 1882 1883 1884 /* 1885 * 1886 * Converts a point size into an internal size that can be used as an index into 1887 * pstab[]. The internal size is one plus the index of the least upper bound of 1888 * n in pstab[], or nsizes if n is larger than all the listed sizes. 1889 * 1890 */ 1891 1892 1893 if ( n <= pstab[0] ) 1894 return(1); 1895 else if (n >= pstab[nsizes-1]) 1896 return(nsizes); 1897 1898 for ( i = 0; n > pstab[i]; i++ ) ; 1899 1900 return(i+1); 1901 1902 } /* End of t_size */ 1903 1904 1905 /*****************************************************************************/ 1906 1907 1908 setsize(n) 1909 1910 1911 int n; /* new internal size */ 1912 1913 1914 { 1915 1916 1917 /* 1918 * 1919 * Now using internal size n, where pstab[n-1] is the best available approximation 1920 * to the size troff asked for. 1921 * 1922 */ 1923 1924 1925 size = n; 1926 1927 } /* End of setsize */ 1928 1929 1930 /*****************************************************************************/ 1931 1932 1933 t_fp(n, s, si) 1934 1935 1936 int n; /* this position */ 1937 char *s; /* now has this font mounted */ 1938 char *si; /* its internal number */ 1939 1940 1941 { 1942 1943 1944 /* 1945 * 1946 * Updates nfonts and the array that keeps track of the mounted fonts. Called from 1947 * loadfont() after an "x font pos font" command is read, and if pos is larger than 1948 * the current value assigned to nfonts we set gotspecial to FALSE to make sure 1949 * t_font() loads all the special fonts after the last legitimate font position. 1950 * 1951 */ 1952 1953 1954 fontname[n].name = s; 1955 fontname[n].number = atoi(si); 1956 1957 if ( n == lastfont ) /* force a call to t_sf() */ 1958 lastfont = -1; 1959 1960 if ( n > nfonts ) { /* got more positions */ 1961 nfonts = n; 1962 gotspecial = FALSE; 1963 } /* End if */ 1964 1965 } /* End of t_fp */ 1966 1967 1968 /*****************************************************************************/ 1969 1970 1971 t_font(s) 1972 1973 1974 char *s; /* use font in this position next */ 1975 1976 1977 { 1978 1979 1980 int n; 1981 1982 1983 /* 1984 * 1985 * Converts the string *s into an integer and checks to make sure it's a legal 1986 * font position. Also arranges to mount all the special fonts after the last 1987 * legitimate font (by calling loadspecial()), provided it hasn't already been 1988 * done. 1989 * 1990 */ 1991 1992 1993 n = atoi(s); 1994 1995 if ( seenpage == TRUE ) { 1996 if ( n < 0 || n > nfonts ) 1997 error(FATAL, "illegal font position %d", n); 1998 1999 if ( gotspecial == FALSE ) 2000 loadspecial(); 2001 } /* End if */ 2002 2003 return(n); 2004 2005 } /* End of t_font */ 2006 2007 2008 /*****************************************************************************/ 2009 2010 2011 setfont(n) 2012 2013 2014 int n; /* use the font mounted here */ 2015 2016 2017 { 2018 2019 2020 /* 2021 * 2022 * troff wants to use the font that's been mounted in position n. All we do here 2023 * is update the variable that keeps track of the current position. PostScript 2024 * font changes are handled in t_sf(), and are only generated right before we're 2025 * ready to print or draw something. 2026 * 2027 */ 2028 2029 2030 if ( n < 0 || n > NFONT ) 2031 error(FATAL, "illegal font %d", n); 2032 if ( fontname[n].name == NULL && fontname[n].number == 0) 2033 loaddefault(); 2034 if ( fontname[n].name == NULL && fontname[n].number == 0) 2035 error(FATAL, 2036 "font %d not loaded: check 'dpost' input for 'x font %d XXX' before 'f%d'", 2037 n, n, n); 2038 2039 font = n; 2040 2041 } /* End of setfont */ 2042 2043 2044 /*****************************************************************************/ 2045 2046 2047 t_sf() 2048 2049 2050 { 2051 2052 2053 int fnum; /* internal font number */ 2054 2055 2056 /* 2057 * 2058 * Called whenever we need to use a new font or size. Only done right before we 2059 * print a character. The seenfonts[] array keeps track of the fonts we've used. 2060 * Helps manage host resident fonts and the DOCUMENTFONTS comment that's put out 2061 * at the end of the job. The array is indexed by internal number. Only works for 2062 * fonts that have internal numbers less than or equal to MAXINTERNAL. 2063 * 2064 */ 2065 2066 2067 if ( fontname[font].name == NULL ) 2068 return; 2069 2070 endtext(); 2071 2072 if ( (fnum = fontname[font].number) > MAXINTERNAL || fnum < 0 ) 2073 fnum = 0; 2074 2075 if ( fnum > 0 && seenfonts[fnum] == 0 && hostfontdir != NULL ) { 2076 sprintf(temp, "%s/%s", hostfontdir, fontname[font].name); 2077 if ( access(temp, 04) == 0 ) 2078 doglobal(temp); 2079 } /* End if */ 2080 2081 if ( tf == stdout ) { 2082 lastfont = font; 2083 lastsize = size; 2084 if ( seenfonts[fnum] == 0 ) 2085 documentfonts(); 2086 seenfonts[fnum] = 1; 2087 } /* End if */ 2088 2089 fprintf(tf, "%d %s f\n", pstab[size-1], fontname[font].name); 2090 2091 if ( fontheight != 0 || fontslant != 0 ) 2092 fprintf(tf, "%d %d changefont\n", fontslant, (fontheight != 0) ? fontheight : pstab[size-1]); 2093 2094 } /* End of t_sf */ 2095 2096 2097 /*****************************************************************************/ 2098 2099 2100 t_charht(n) 2101 2102 2103 int n; /* use this as the character height */ 2104 2105 2106 { 2107 2108 2109 /* 2110 * 2111 * Remembers the requested height, from 'x H n'. Forces a call to t_sf(), which 2112 * is where the real work is done, by setting lastfont to -1. 2113 * 2114 */ 2115 2116 fontheight = (n == pstab[size-1]) ? 0 : n; 2117 lastfont = -1; 2118 2119 } /* End of t_charht */ 2120 2121 2122 /*****************************************************************************/ 2123 2124 2125 t_slant(n) 2126 2127 2128 int n; /* slant characters this many degrees */ 2129 2130 2131 { 2132 2133 2134 /* 2135 * 2136 * Remembers the requested slant, from 'x X n'. Forces a call to t_sf(), which 2137 * is where the real work is done, by setting lastfont to -1. 2138 * 2139 */ 2140 2141 fontslant = n; 2142 lastfont = -1; 2143 2144 } /* End of t_slant */ 2145 2146 2147 /*****************************************************************************/ 2148 2149 2150 t_reset(c) 2151 2152 2153 int c; /* pause or restart */ 2154 2155 2156 { 2157 2158 2159 /* 2160 * 2161 * Found an "x stop" or "x pause" command. Although nothing's done here we could 2162 * add code to reset everything so dpost could handle multiple files formatted for 2163 * different devices. 2164 * 2165 */ 2166 2167 2168 } /* End of t_reset */ 2169 2170 2171 /*****************************************************************************/ 2172 2173 2174 t_trailer() 2175 2176 2177 { 2178 2179 2180 /* 2181 * 2182 * Called after we find an "x trailer" in the input file. Forcing out the last 2183 * page is done at the end of conv(), but probably belongs here. 2184 * 2185 */ 2186 2187 2188 endtext(); 2189 2190 } /* End of t_trailer */ 2191 2192 2193 /*****************************************************************************/ 2194 2195 2196 hgoto(n) 2197 2198 2199 int n; /* new horizontal position */ 2200 2201 2202 { 2203 2204 2205 /* 2206 * 2207 * Want to be at this absolute horizontal position next. Actual motion commands 2208 * are generated in oput(), charlib(), and the drawing routines. 2209 * 2210 */ 2211 2212 2213 hpos = n; 2214 2215 } /* End of hgoto */ 2216 2217 2218 /*****************************************************************************/ 2219 2220 2221 hmot(n) 2222 2223 2224 int n; /* move this far horizontally */ 2225 2226 2227 { 2228 2229 2230 /* 2231 * 2232 * Handles relative horizontal motion. troff's current positon, as recorded in 2233 * in hpos, is changed by n units. Usually called right before we're supposed to 2234 * print a character. 2235 * 2236 */ 2237 2238 2239 hpos += n; 2240 2241 } /* End of hmot */ 2242 2243 2244 /*****************************************************************************/ 2245 2246 2247 vgoto(n) 2248 2249 2250 int n; /* new vertical position */ 2251 2252 2253 { 2254 2255 2256 /* 2257 * 2258 * Moves vertically in troff's coordinate system to absolute position n. 2259 * 2260 */ 2261 2262 2263 vpos = n; 2264 2265 } /* End of vgoto */ 2266 2267 2268 /*****************************************************************************/ 2269 2270 2271 vmot(n) 2272 2273 2274 int n; /* move this far vertically */ 2275 2276 2277 { 2278 2279 2280 /* 2281 * 2282 * Handles relative vertical motion of n units in troff's coordinate system. 2283 * 2284 */ 2285 2286 2287 vpos += n; 2288 2289 } /* End of vmot */ 2290 2291 2292 /*****************************************************************************/ 2293 2294 2295 xymove(x, y) 2296 2297 2298 int x, y; /* this is where we want to be */ 2299 2300 2301 { 2302 2303 2304 /* 2305 * 2306 * Makes sure the post-processor and printer agree about the current position. 2307 * 2308 */ 2309 2310 2311 hgoto(x); 2312 vgoto(y); 2313 2314 fprintf(tf, "%d %d m\n", hpos, vpos); 2315 2316 lastx = hpos; 2317 lasty = vpos; 2318 2319 } /* End of xymove */ 2320 2321 2322 /*****************************************************************************/ 2323 2324 2325 put1s(s) 2326 2327 2328 register char *s; /* find and print this character */ 2329 2330 2331 { 2332 2333 2334 static int i = 0; /* last one we found - usually */ 2335 2336 2337 /* 2338 * 2339 * *s points to the start of a two character string that represents one of troff's 2340 * special characters. To print it we first look for *s in the chname[] array using 2341 * chtab[i] to find the string representing character i in chname[]. If the lookup 2342 * is successful we add 128 to i and ask put1() to finish printing the character. 2343 * We remember the index where the last character was found because requests to 2344 * print a special character often come in bunches (eg. drawing lines with \(ru). 2345 * 2346 */ 2347 2348 2349 if ( strcmp(s, &chname[chtab[i]]) != 0 ) 2350 for ( i = 0; i < nchtab; i++ ) 2351 if ( strcmp(&chname[chtab[i]], s) == 0 ) 2352 break; 2353 2354 if ( i < nchtab ) 2355 put1(i + 128); 2356 else i = 0; 2357 2358 } /* End of put1s */ 2359 2360 2361 /*****************************************************************************/ 2362 2363 2364 put1(c) 2365 2366 2367 register int c; /* want to print this character */ 2368 2369 2370 { 2371 2372 2373 register int i; /* character code from fitab */ 2374 register int j; /* number of fonts we've checked so far */ 2375 register int k; /* font we're currently looking at */ 2376 char *pw; /* font widthtab and */ 2377 char *p; /* and codetab where c was found */ 2378 int code; /* code used to get c printed */ 2379 int ofont; /* font when we started */ 2380 2381 2382 /* 2383 * 2384 * Arranges to have character c printed. If c < 128 it's a simple ASCII character, 2385 * otherwise it's a special character. Things done here have to agree with the way 2386 * the font tables were built by makedev, and work as follows. First we subtract 2387 * 32 from c because the tables don't record the non-graphic ASCII characters. 2388 * If fitab[k][c] isn't zero the character is on font k and the value is an index 2389 * that can be used to recover width and character code data from the other two 2390 * tables. If fitab[k][c] is zero the character isn't defined on font k and we 2391 * check the next font, which is found as follows. The current font is the first 2392 * one we check, and it's followed by a circular search of all the remaining fonts 2393 * that starts with the first special font and skips font position 0. If character 2394 * c is found somewhere besides the current font we change to that font and use 2395 * fitab[k][c] to locate missing data in the other two tables. The width of the 2396 * character can be found at widthtab[k][c] while codetab[k][c] is whatever we 2397 * need to tell the printer to have character c printed. lastc records the real 2398 * name of the character because it's lost by the time oput() gets called but 2399 * charlib() may need it. 2400 * 2401 * Took all the debugging stuff out because at least this part of the program is 2402 * reasonably solid. 2403 * 2404 */ 2405 2406 2407 lastc = c; /* charlib() needs the name not the code */ 2408 if ( (c -= 32) <= 0 ) /* probably never happens */ 2409 return; 2410 2411 k = ofont = font; 2412 2413 if ( (i = fitab[k][c] & BMASK) != 0 ) { /* it's on this font */ 2414 p = codetab[font]; 2415 pw = widthtab[font]; 2416 } else if ( smnt > 0 ) { /* on special (we hope) */ 2417 for ( k=smnt, j=0; j <= nfonts; j++, k = (k+1) % (nfonts+1) ) { 2418 if ( k == 0 ) continue; 2419 if ( (i = fitab[k][c] & BMASK) != 0 ) { 2420 p = codetab[k]; 2421 pw = widthtab[k]; 2422 setfont(k); 2423 break; 2424 } /* End if */ 2425 } /* End for */ 2426 } /* End else */ 2427 2428 if ( i != 0 && (code = p[i] & BMASK) != 0 ) { 2429 lastw = widthfac * (((pw[i] & BMASK) * pstab[size-1] + unitwidth/2) / unitwidth); 2430 oput(code); 2431 } /* End if */ 2432 2433 if ( font != ofont ) 2434 setfont(ofont); 2435 2436 } /* End of put1 */ 2437 2438 2439 /*****************************************************************************/ 2440 2441 2442 oput(c) 2443 2444 2445 int c; /* want to print this character */ 2446 2447 2448 { 2449 2450 2451 /* 2452 * 2453 * Arranges to print the character whose code is c in the current font. All the 2454 * actual positioning is done here, in charlib(), or in the drawing routines. 2455 * 2456 */ 2457 2458 2459 if ( textcount > MAXSTACK ) /* don't put too much on the stack? */ 2460 endtext(); 2461 2462 if ( font != lastfont || size != lastsize ) 2463 t_sf(); 2464 2465 if ( vpos != lasty ) 2466 endline(); 2467 2468 starttext(); 2469 2470 if ( ABS(hpos - lastx) > slop ) 2471 endstring(); 2472 2473 if ( isascii(c) && isprint(c) ) 2474 switch ( c ) { 2475 case '(': 2476 case ')': 2477 case '\\': 2478 addchar('\\'); 2479 2480 default: 2481 addchar(c); 2482 } /* End switch */ 2483 else if ( c > 040 ) 2484 addoctal(c); 2485 else charlib(c); 2486 2487 lastx += lastw; 2488 2489 } /* End of oput */ 2490 2491 2492 /*****************************************************************************/ 2493 2494 2495 starttext() 2496 2497 2498 { 2499 2500 2501 /* 2502 * Called whenever we want to be sure we're ready to start collecting characters 2503 * for the next call to PostScript procedure t (ie. the one that prints them). If 2504 * textcount is positive we've already started, so there's nothing to do. The more 2505 * complicated encoding schemes save text strings in the strings[] array and need 2506 * detailed information about the strings when they're written to the output file 2507 * in endtext(). 2508 * 2509 */ 2510 2511 2512 if ( textcount < 1 ) { 2513 switch ( encoding ) { 2514 case 0: 2515 case 1: 2516 putc('(', tf); 2517 break; 2518 2519 case 2: 2520 case 3: 2521 strptr = strings; 2522 spacecount = 0; 2523 line[1].str = strptr; 2524 line[1].dx = 0; 2525 line[1].spaces = 0; 2526 line[1].start = hpos; 2527 line[1].width = 0; 2528 break; 2529 2530 case MAXENCODING+1: /* reverse video */ 2531 if ( lastend == -1 ) 2532 lastend = hpos; 2533 putc('(', tf); 2534 break; 2535 2536 case MAXENCODING+2: /* follow a funny baseline */ 2537 putc('(', tf); 2538 break; 2539 } /* End switch */ 2540 textcount = 1; 2541 lastx = stringstart = hpos; 2542 } /* End if */ 2543 2544 } /* End of starttext */ 2545 2546 2547 /*****************************************************************************/ 2548 2549 2550 endtext() 2551 2552 2553 { 2554 2555 int i; /* loop index */ 2556 2557 2558 /* 2559 * 2560 * Generates a call to the PostScript procedure that processes all the text we've 2561 * accumulated - provided textcount is positive. 2562 * 2563 */ 2564 2565 if ( textcount > 0 ) { /* started working on some text */ 2566 switch ( encoding ) { 2567 case 0: 2568 fprintf(tf, ")%d t\n", stringstart); 2569 break; 2570 2571 case 1: 2572 fprintf(tf, ")%d %d t\n", stringstart, lasty); 2573 break; 2574 2575 case 2: 2576 *strptr = '\0'; 2577 line[textcount].width = lastx - line[textcount].start; 2578 if ( spacecount != 0 || textcount != 1 ) { 2579 for ( i = textcount; i > 0; i-- ) 2580 fprintf(tf, "(%s)%d %d", line[i].str, line[i].spaces, line[i].width); 2581 fprintf(tf, " %d %d %d t\n", textcount, stringstart, lasty); 2582 } else fprintf(tf, "(%s)%d %d w\n", line[1].str, stringstart, lasty); 2583 break; 2584 2585 case 3: 2586 *strptr = '\0'; 2587 if ( spacecount != 0 || textcount != 1 ) { 2588 for ( i = textcount; i > 0; i-- ) 2589 fprintf(tf, "(%s)%d", line[i].str, line[i].dx); 2590 fprintf(tf, " %d %d %d t\n", textcount, stringstart, lasty); 2591 } else fprintf(tf, "(%s)%d %d w\n", line[1].str, stringstart, lasty); 2592 break; 2593 2594 case MAXENCODING+1: 2595 fprintf(tf, ")%d ", stringstart); 2596 fprintf(tf, "%d %d drawrvbox ", lastend - rvslop, (int)(lastx + .5) + rvslop); 2597 fprintf(tf, "t\n", stringstart); 2598 lastend = (lastx + .5) + 2 * rvslop; 2599 break; 2600 2601 case MAXENCODING+2: 2602 fprintf(tf, ")%d %d t\n", stringstart, lasty); 2603 break; 2604 } /* End switch */ 2605 } /* End if */ 2606 2607 textcount = 0; 2608 2609 } /* End of endtext */ 2610 2611 2612 /*****************************************************************************/ 2613 2614 2615 endstring() 2616 2617 2618 { 2619 2620 2621 int dx; 2622 2623 2624 /* 2625 * 2626 * Horizontal positions are out of sync. End the last open string, adjust the 2627 * printer's position, and start a new string. Assumes we've already started 2628 * accumulating text. 2629 * 2630 */ 2631 2632 2633 switch ( encoding ) { 2634 case 0: 2635 case 1: 2636 fprintf(tf, ")%d(", stringstart); 2637 textcount++; 2638 lastx = stringstart = hpos; 2639 break; 2640 2641 case 2: 2642 case 3: 2643 dx = hpos - lastx; 2644 if ( spacecount++ == 0 ) 2645 line[textcount].dx = dx; 2646 if ( line[textcount].dx != dx ) { 2647 *strptr++ = '\0'; 2648 line[textcount].width = lastx - line[textcount].start; 2649 line[++textcount].str = strptr; 2650 *strptr++ = ' '; 2651 line[textcount].dx = dx; 2652 line[textcount].start = lastx; 2653 line[textcount].width = 0; 2654 line[textcount].spaces = 1; 2655 } else { 2656 *strptr++ = ' '; 2657 line[textcount].spaces++; 2658 } /* End else */ 2659 lastx += dx; 2660 break; 2661 2662 case MAXENCODING+1: 2663 fprintf(tf, ")%d(", stringstart); 2664 textcount++; 2665 lastx = stringstart = hpos; 2666 break; 2667 2668 case MAXENCODING+2: 2669 endtext(); 2670 starttext(); 2671 break; 2672 2673 } /* End switch */ 2674 2675 } /* End of endstring */ 2676 2677 2678 /*****************************************************************************/ 2679 2680 2681 endline() 2682 2683 2684 { 2685 2686 2687 /* 2688 * 2689 * The vertical position has changed. Dump any accumulated text, then adjust 2690 * the printer's vertical position. 2691 * 2692 */ 2693 2694 2695 endtext(); 2696 2697 if ( encoding == 0 || encoding == MAXENCODING+1 ) 2698 fprintf(tf, "%d %d m\n", hpos, vpos); 2699 2700 lastx = stringstart = lastend = hpos; 2701 lasty = vpos; 2702 2703 } /* End of endline */ 2704 2705 2706 /*****************************************************************************/ 2707 2708 2709 addchar(c) 2710 2711 2712 int c; /* next character in current string */ 2713 2714 2715 { 2716 2717 2718 /* 2719 * 2720 * Does whatever is needed to add character c to the current string. 2721 * 2722 */ 2723 2724 2725 switch ( encoding ) { 2726 case 0: 2727 case 1: 2728 putc(c, tf); 2729 break; 2730 2731 case 2: 2732 case 3: 2733 *strptr++ = c; 2734 break; 2735 2736 case MAXENCODING+1: 2737 case MAXENCODING+2: 2738 putc(c, tf); 2739 break; 2740 } /* End switch */ 2741 2742 } /* End of addchar */ 2743 2744 2745 /*****************************************************************************/ 2746 2747 2748 addoctal(c) 2749 2750 2751 int c; /* add it as an octal escape */ 2752 2753 2754 { 2755 2756 2757 /* 2758 * 2759 * Adds c to the current string as an octal escape \ddd. 2760 * 2761 */ 2762 2763 2764 switch ( encoding ) { 2765 case 0: 2766 case 1: 2767 fprintf(tf, "\\%o", c); 2768 break; 2769 2770 case 2: 2771 case 3: 2772 sprintf(strptr, "\\%o", c); 2773 strptr += strlen(strptr); 2774 break; 2775 2776 case MAXENCODING+1: 2777 case MAXENCODING+2: 2778 fprintf(tf, "\\%o", c); 2779 break; 2780 } /* End switch */ 2781 2782 } /* End of addoctal */ 2783 2784 2785 /*****************************************************************************/ 2786 2787 2788 charlib(code) 2789 2790 2791 int code; /* either 1 or 2 */ 2792 2793 2794 { 2795 2796 2797 char *name; /* name of the character */ 2798 char tname[10]; /* in case it's a single ASCII character */ 2799 2800 2801 /* 2802 * 2803 * Called from oput() for characters having codes less than 040. Special files 2804 * that define PostScript procedures for certain characters can be found in 2805 * directory *fontdir/devpost/charlib. If there's a file that has the same name as 2806 * the character we're trying to print it's copied to the output file, otherwise 2807 * nothing, except some positioning, is done. 2808 * 2809 * All character definitions are only made once. Subsequent requests to print the 2810 * character generate a call to a procedure that begins with the prefix build_ and 2811 * ends with the character's name. Special characters that are assigned codes 2812 * other than 1 are assumed to have additional data files that should be copied 2813 * to the output file immediately after the build_ call. Those data files should 2814 * end in the suffix .map, and usually will be a hex representation of a bitmap. 2815 * 2816 */ 2817 2818 2819 endtext(); 2820 2821 if ( lastc < 128 ) { /* just a simple ASCII character */ 2822 sprintf(tname, "%.3o", lastc); 2823 name = tname; 2824 } else name = &chname[chtab[lastc - 128]]; 2825 2826 if ( downloaded[lastc] == 0 ) { 2827 sprintf(temp, "%s/dev%s/charlib/%s", fontdir, realdev, name); 2828 if ( access(temp, 04) == 0 && doglobal(temp) == TRUE ) { 2829 downloaded[lastc] = 1; 2830 t_sf(); 2831 } /* End if */ 2832 } /* End if */ 2833 2834 if ( downloaded[lastc] == 1 ) { 2835 xymove(hpos, vpos); 2836 fprintf(tf, "%d build_%s\n", (int) lastw, name); 2837 if ( code != 1 ) { /* get the bitmap or whatever */ 2838 sprintf(temp, "%s/dev%s/charlib/%s.map", fontdir, realdev, name); 2839 if ( access(temp, 04) == 0 && tf == stdout ) 2840 cat(temp); 2841 } /* End if */ 2842 fprintf(tf, "%d %d m\n", stringstart = hpos + lastw, vpos); 2843 } /* End if */ 2844 2845 } /* End of charlib */ 2846 2847 2848 /*****************************************************************************/ 2849 2850 2851 doglobal(name) 2852 2853 2854 char *name; /* copy this to the output - globally */ 2855 2856 2857 { 2858 2859 2860 int val = FALSE; /* returned to the caller */ 2861 2862 2863 /* 2864 * 2865 * Copies file *name to the output file and brackets it with whatever commands are 2866 * needed to have it exported to the global environment. TRUE is returned if we 2867 * successfully add file *name to the output file. 2868 * 2869 */ 2870 2871 2872 if ( tf == stdout ) { 2873 endtext(); 2874 fprintf(tf, "cleartomark restore\n"); 2875 fprintf(tf, "%s", BEGINGLOBAL); 2876 val = cat(name); 2877 fprintf(tf, "%s", ENDGLOBAL); 2878 fprintf(tf, "save mark\n"); 2879 reset(); 2880 } /* End if */ 2881 2882 return(val); 2883 2884 } /* End of doglobal */ 2885 2886 2887 /*****************************************************************************/ 2888 2889 2890 documentfonts() 2891 2892 2893 { 2894 2895 2896 FILE *fp_in; /* PostScript font name read from here */ 2897 FILE *fp_out; /* and added to this file */ 2898 2899 2900 /* 2901 * 2902 * Whenever a new font is used we try to record the appropriate PostScript font 2903 * name in *temp_file for the DOCUMENTFONTS comment that's put out in done(). 2904 * By default PostScript font names are found in /usr/lib/font/devpost. Fonts 2905 * that have a .name file are recorded in *temp_file. The first string in that 2906 * file is expected to be that font's (long) PostScript name. 2907 * 2908 */ 2909 2910 2911 if ( temp_file == NULL ) /* generate a temp file name */ 2912 if ( (temp_file = tempnam(TEMPDIR, "dpost")) == NULL ) 2913 return; 2914 2915 sprintf(temp, "%s/dev%s/%s.name", fontdir, realdev, fontname[font].name); 2916 2917 if ( (fp_in = fopen(temp, "r")) != NULL ) { 2918 if ( (fp_out = fopen(temp_file, "a")) != NULL ) { 2919 if ( fscanf(fp_in, "%s", temp) == 1 ) { 2920 if ( docfonts++ == 0 ) 2921 fprintf(fp_out, "%s", DOCUMENTFONTS); 2922 else if ( (docfonts - 1) % 8 == 0 ) 2923 fprintf(fp_out, "\n%s", CONTINUECOMMENT); 2924 fprintf(fp_out, " %s", temp); 2925 } /* End if */ 2926 fclose(fp_out); 2927 } /* End if */ 2928 fclose(fp_in); 2929 } /* End if */ 2930 2931 } /* End of documentfonts */ 2932 2933 2934 /*****************************************************************************/ 2935 2936 2937 redirect(pg) 2938 2939 2940 int pg; /* next page we're printing */ 2941 2942 2943 { 2944 2945 2946 static FILE *fp_null = NULL; /* if output is turned off */ 2947 2948 2949 /* 2950 * 2951 * If we're not supposed to print page pg, tf will be directed to /dev/null, 2952 * otherwise output goes to stdout. 2953 * 2954 */ 2955 2956 2957 if ( pg >= 0 && in_olist(pg) == ON ) 2958 tf = stdout; 2959 else if ( (tf = fp_null) == NULL ) 2960 tf = fp_null = fopen("/dev/null", "w"); 2961 2962 } /* End of redirect */ 2963 2964 2965 /*****************************************************************************/ 2966 2967