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