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 */ 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" 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 static void account(void); 578 static void addchar(int); 579 static void addoctal(int); 580 static void arguments(void); 581 static void charlib(int); 582 static void conv(FILE *); 583 static void devcntrl(FILE *); 584 static void documentfonts(void); 585 static void done(void); 586 static void endline(void); 587 static void endstring(void); 588 void endtext(void); 589 static void fontinit(void); 590 static void fontprint(int); 591 static void getdevmap(void); 592 static void header(void); 593 void hgoto(int); 594 static void hmot(int); 595 static void init_signals(void); 596 static void loaddefault(void); 597 static void loadfont(int, char *, char *); 598 static void loadspecial(void); 599 static void options(void); 600 static void oput(int); 601 static void put1(int); 602 static void put1s(char *); 603 static void redirect(int); 604 void reset(void); 605 void resetpos(void); 606 static void setfont(int); 607 static void setpaths(char *); 608 static void setsize(int); 609 static void setup(void); 610 static void starttext(void); 611 static void t_charht(int); 612 static void t_fp(int, char *, char *); 613 static void t_init(void); 614 static void t_newline(void); 615 static void t_page(int); 616 static void t_reset(int); 617 void t_sf(void); 618 static void t_slant(int); 619 static void t_trailer(void); 620 void vgoto(int); 621 static void vmot(int); 622 623 624 /*****************************************************************************/ 625 626 627 int 628 main(int agc, char *agv[]) 629 { 630 631 /* 632 * 633 * A program that translates troff output into PostScript. All the input files 634 * must have been formatted for the same device, which doesn't necessarily have to 635 * be *realdev. If there's more than one input file, each begins on a new page. 636 * 637 */ 638 639 640 argc = agc; /* global so everyone can use them */ 641 argv = agv; 642 643 prog_name = argv[0]; /* just for error messages */ 644 645 init_signals(); /* sets up interrupt handling */ 646 header(); /* PostScript file structuring comments */ 647 options(); /* command line options */ 648 arguments(); /* translate all the input files */ 649 done(); /* add trailing comments etc. */ 650 account(); /* job accounting data */ 651 652 return (x_stat); /* everything probably went OK */ 653 654 } /* End of main */ 655 656 657 /*****************************************************************************/ 658 659 660 static void 661 init_signals(void) 662 { 663 void interrupt(); /* signal handler */ 664 665 /* 666 * 667 * Make sure we handle interrupts. 668 * 669 */ 670 671 672 if ( signal(SIGINT, interrupt) == SIG_IGN ) { 673 signal(SIGINT, SIG_IGN); 674 signal(SIGQUIT, SIG_IGN); 675 signal(SIGHUP, SIG_IGN); 676 } else { 677 signal(SIGHUP, interrupt); 678 signal(SIGQUIT, interrupt); 679 } /* End else */ 680 681 signal(SIGTERM, interrupt); 682 683 } /* End of init_signals */ 684 685 686 /*****************************************************************************/ 687 688 static void 689 header(void) 690 { 691 692 693 int ch; /* return value from getopt() */ 694 int old_optind = optind; /* for restoring optind - should be 1 */ 695 696 697 /* 698 * 699 * Scans the option list looking for things, like the prologue file, that we need 700 * right away but could be changed from the default. Doing things this way is an 701 * attempt to conform to Adobe's latest file structuring conventions. In particular 702 * they now say there should be nothing executed in the prologue, and they have 703 * added two new comments that delimit global initialization calls. Once we know 704 * where things really are we write out the job header, follow it by the prologue, 705 * and then add the ENDPROLOG and BEGINSETUP comments. 706 * 707 */ 708 709 710 while ( (ch = getopt(argc, argv, optnames)) != EOF ) 711 if ( ch == 'L' ) 712 setpaths(optarg); 713 else if ( ch == '?' ) 714 error(FATAL, ""); 715 716 optind = old_optind; /* get ready for option scanning */ 717 718 fprintf(stdout, "%s", NONCONFORMING); 719 fprintf(stdout, "%s %s\n", VERSION, PROGRAMVERSION); 720 fprintf(stdout, "%s %s\n", DOCUMENTFONTS, ATEND); 721 fprintf(stdout, "%s %s\n", PAGES, ATEND); 722 fprintf(stdout, "%s", ENDCOMMENTS); 723 724 if ( cat(prologue) == FALSE ) 725 error(FATAL, "can't read %s", prologue); 726 727 fprintf(stdout, "%s", ENDPROLOG); 728 fprintf(stdout, "%s", BEGINSETUP); 729 fprintf(stdout, "mark\n"); 730 731 } /* End of header */ 732 733 734 /*****************************************************************************/ 735 736 737 static void 738 options(void) 739 { 740 int ch; /* name returned by getopt() */ 741 742 extern char *optarg; /* option argument set by getopt() */ 743 extern int optind; 744 745 /* 746 * 747 * Reads and processes the command line options. There are, without a doubt, too 748 * many options! 749 * 750 */ 751 752 753 while ( (ch = getopt(argc, argv, optnames)) != EOF ) { 754 755 switch ( ch ) { 756 757 case 'a': /* aspect ratio */ 758 fprintf(stdout, "/aspectratio %s def\n", optarg); 759 break; 760 761 case 'c': /* number of copies */ 762 copies = atoi(optarg); 763 fprintf(stdout, "/#copies %s store\n", optarg); 764 break; 765 766 case 'e': /* change the encoding scheme */ 767 if ( (encoding = atoi(optarg)) < 0 || encoding > MAXENCODING ) 768 encoding = DFLTENCODING; 769 realencoding = encoding; 770 break; 771 772 case 'm': /* magnification */ 773 fprintf(stdout, "/magnification %s def\n", optarg); 774 break; 775 776 case 'n': /* forms per page */ 777 formsperpage = atoi(optarg); 778 fprintf(stdout, "%s %s\n", FORMSPERPAGE, optarg); 779 fprintf(stdout, "/formsperpage %s def\n", optarg); 780 break; 781 782 case 'o': /* output page list */ 783 out_list(optarg); 784 break; 785 786 case 'p': /* landscape or portrait mode */ 787 if ( *optarg == 'l' ) 788 fprintf(stdout, "/landscape true def\n"); 789 else fprintf(stdout, "/landscape false def\n"); 790 break; 791 792 case 't': /* just for compatibility */ 793 break; 794 795 case 'w': /* line width for drawing */ 796 fprintf(stdout, "/linewidth %s def\n", optarg); 797 break; 798 799 case 'x': /* shift horizontally */ 800 fprintf(stdout, "/xoffset %s def\n", optarg); 801 break; 802 803 case 'y': /* and vertically on the page */ 804 fprintf(stdout, "/yoffset %s def\n", optarg); 805 break; 806 807 case 'A': /* force job accounting */ 808 case 'J': 809 if ( (fp_acct = fopen(optarg, "a")) == NULL ) 810 error(FATAL, "can't open accounting file %s", optarg); 811 break; 812 813 case 'C': /* copy file to straight to output */ 814 if ( cat(optarg) == FALSE ) 815 error(FATAL, "can't read %s", optarg); 816 break; 817 818 case 'F': /* font table directory */ 819 fontdir = optarg; 820 break; 821 822 case 'H': /* host resident font directory */ 823 hostfontdir = optarg; 824 break; 825 826 case 'L': /* PostScript prologue file */ 827 setpaths(optarg); /* already been done in header() */ 828 break; 829 830 case 'O': /* turn picture inclusion off */ 831 picflag = OFF; 832 break; 833 834 case 'P': /* PostScript pass through */ 835 fprintf(stdout, "%s\n", optarg); 836 break; 837 838 case 'R': /* special global or page level request */ 839 saverequest(optarg); 840 break; 841 842 case 'S': /* horizontal position error */ 843 if ( (pointslop = atof(optarg)) < 0 ) 844 pointslop = 0; 845 break; 846 847 case 'T': /* target printer */ 848 realdev = optarg; 849 break; 850 851 case 'D': /* debug flag */ 852 debug = ON; 853 tf = stdout; 854 break; 855 856 case 'I': /* ignore FATAL errors */ 857 ignore = ON; 858 break; 859 860 case '?': /* don't know the option */ 861 error(FATAL, ""); 862 break; 863 864 default: 865 error(FATAL, "missing case for option %c", ch); 866 break; 867 868 } /* End switch */ 869 } /* End while */ 870 871 argc -= optind; /* get ready for non-options args */ 872 argv += optind; 873 874 } /* End of options */ 875 876 877 /*****************************************************************************/ 878 879 880 static void 881 setpaths(char *name) 882 /* string that followed the -L option */ 883 { 884 char *path; /* start of the pathname */ 885 886 /* 887 * 888 * Extends the -L option to permit run time modification of pathnames that were 889 * fixed or didn't exist in previous versions of dpost. For example, the PostScript 890 * drawing procedures have been moved out of *prologue and put in *drawfile. The 891 * new syntax can be either -Lfile or -Lname:file. If the "name:" prefix is omitted 892 * file will be used as the prologue, otherwise name should be one of "prologue", 893 * "font", "draw", "color", or "form" and is used to select the pointer that gets 894 * set to string "file". 895 * 896 */ 897 898 899 for ( path = name; *path; path++ ) 900 if ( *path == ':' || *path == ' ' ) { 901 while ( *path == ':' || *path == ' ' ) path++; 902 break; 903 } /* End if */ 904 905 if ( *path == '\0' ) /* didn't find a "name:" prefix */ 906 path = name; 907 908 if ( path == name || strncmp(name, "prologue", strlen("prologue")) == 0 ) 909 prologue = path; 910 else if ( strncmp(name, "draw", strlen("draw")) == 0 ) 911 drawfile = path; 912 else if ( strncmp(name, "color", strlen("color")) == 0 ) 913 colorfile = path; 914 else if ( strncmp(name, "form", strlen("form")) == 0 ) 915 formfile = path; 916 else if ( strncmp(name, "baseline", strlen("baseline")) == 0 ) 917 baselinefile = path; 918 919 } /* End of setpaths */ 920 921 922 /*****************************************************************************/ 923 924 925 static void 926 setup(void) 927 { 928 929 /* 930 * Handles things that must be done after the options are read but before the 931 * input files are processed. Called from t_init() after an "x init" command is 932 * read, because we need the resolution before we can generate the call to the 933 * setup procedure defined in *prologue. Only allowing one call to setup assumes 934 * all the input files have been prepared for the same device. 935 * 936 */ 937 938 939 writerequest(0, stdout); /* global requests eg. manual feed */ 940 fprintf(stdout, "/resolution %d def\n", res); 941 fprintf(stdout, "setup\n"); 942 fprintf(stdout, "%d setdecoding\n", encoding); 943 944 if ( formsperpage > 1 ) { /* followed by stuff for multiple pages */ 945 if ( cat(formfile) == FALSE ) 946 error(FATAL, "can't read %s", formfile); 947 fprintf(stdout, "%d setupforms\n", formsperpage); 948 } /* End if */ 949 950 fprintf(stdout, "%s", ENDSETUP); 951 952 } /* End of setup */ 953 954 955 /*****************************************************************************/ 956 957 958 static void 959 arguments(void) 960 { 961 FILE *fp; /* next input file */ 962 963 /* 964 * 965 * Makes sure all the non-option command line arguments are processed. If we get 966 * here and there aren't any arguments left, or if '-' is one of the input files 967 * we'll translate stdin. 968 * 969 */ 970 971 972 if ( argc < 1 ) 973 conv(stdin); 974 else 975 while ( argc > 0 ) { 976 if ( strcmp(*argv, "-") == 0 ) 977 fp = stdin; 978 else if ( (fp = fopen(*argv, "r")) == NULL ) 979 error(FATAL, "can't open %s", *argv); 980 conv(fp); 981 if ( fp != stdin ) 982 fclose(fp); 983 argc--; 984 argv++; 985 } /* End while */ 986 987 } /* End of arguments */ 988 989 990 /*****************************************************************************/ 991 992 993 static void 994 done(void) 995 { 996 997 /* 998 * 999 * Finished with all the input files, so mark the end of the pages with a TRAILER 1000 * comment, make sure the last page prints, and add things like the DOCUMENTFONTS 1001 * and PAGES comments that can only be determined after all the input files have 1002 * been read. 1003 * 1004 */ 1005 1006 1007 fprintf(stdout, "%s", TRAILER); 1008 fprintf(stdout, "done\n"); 1009 1010 if ( temp_file != NULL ) { 1011 if ( docfonts > 0 ) { 1012 cat(temp_file); 1013 putc('\n', stdout); 1014 } /* End if */ 1015 unlink(temp_file); 1016 } /* End if */ 1017 1018 fprintf(stdout, "%s %d\n", PAGES, printed); 1019 1020 } /* End of done */ 1021 1022 1023 /*****************************************************************************/ 1024 1025 1026 static void 1027 account(void) 1028 { 1029 1030 /* 1031 * 1032 * Writes an accounting record to *fp_acct provided it's not NULL. Accounting is 1033 * requested using the -A or -J options. 1034 * 1035 */ 1036 1037 if ( fp_acct != NULL ) 1038 fprintf(fp_acct, " print %d\n copies %d\n", printed, copies); 1039 1040 } /* End of account */ 1041 1042 1043 /*****************************************************************************/ 1044 1045 1046 static void 1047 conv(FILE *fp) 1048 /* next input file */ 1049 { 1050 int c; /* usually first char in next command */ 1051 int m, n, n1, m1; /* when we need to read integers */ 1052 char str[50]; /* for special chars and font numbers */ 1053 1054 1055 /* 1056 * 1057 * Controls the translation of troff's device independent output language into 1058 * PostScript. The call to t_page() that prints the last page is made when we 1059 * exit the loop, but probably belongs in t_trailer(). 1060 * 1061 */ 1062 1063 1064 redirect(-1); /* only do output after a page command */ 1065 lineno = 1; /* line in current file */ 1066 1067 while ((c = getc(fp)) != EOF) { 1068 1069 switch (c) { 1070 1071 case '\n': /* just count this line */ 1072 lineno++; 1073 break; 1074 1075 case ' ': /* when input is text */ 1076 case 0: /* occasional noise creeps in */ 1077 break; 1078 1079 case '0': case '1': case '2': case '3': case '4': 1080 case '5': case '6': case '7': case '8': case '9': 1081 /* two motion digits plus a character */ 1082 hmot((c-'0')*10 + getc(fp)-'0'); 1083 put1(getc(fp)); 1084 break; 1085 1086 case 'c': /* single ascii character */ 1087 put1(getc(fp)); 1088 break; 1089 1090 case 'C': /* special character */ 1091 fscanf(fp, "%s", str); 1092 put1s(str); 1093 break; 1094 1095 case 'N': /* character at position n */ 1096 fscanf(fp, "%d", &m); 1097 endtext(); 1098 oput(m); 1099 break; 1100 1101 case 'D': /* drawing functions */ 1102 endtext(); 1103 getdraw(); 1104 if ( size != lastsize ) 1105 t_sf(); 1106 switch ((c=getc(fp))) { 1107 case 'p': /* draw a path */ 1108 while (fscanf(fp, "%d %d", &n, &m) == 2) 1109 drawline(n, m); 1110 lineno++; 1111 break; 1112 1113 case 'l': /* draw a line */ 1114 fscanf(fp, "%d %d %c", &n, &m, &n1); 1115 drawline(n, m); 1116 break; 1117 1118 case 'c': /* circle */ 1119 fscanf(fp, "%d", &n); 1120 drawcirc(n); 1121 break; 1122 1123 case 'e': /* ellipse */ 1124 fscanf(fp, "%d %d", &m, &n); 1125 drawellip(m, n); 1126 break; 1127 1128 case 'a': /* counter-clockwise arc */ 1129 case 'A': /* clockwise arc */ 1130 fscanf(fp, "%d %d %d %d", &n, &m, &n1, &m1); 1131 drawarc(n, m, n1, m1, c); 1132 break; 1133 1134 case 'q': /* spline without end points */ 1135 drawspline(fp, 1); 1136 lineno++; 1137 break; 1138 1139 case '~': /* wiggly line */ 1140 drawspline(fp, 2); 1141 lineno++; 1142 break; 1143 1144 default: 1145 error(FATAL, "unknown drawing function %c", c); 1146 break; 1147 } /* End switch */ 1148 break; 1149 1150 case 's': /* use this point size */ 1151 fscanf(fp, "%d", &n); /* ignore fractional sizes */ 1152 setsize(t_size(n)); 1153 break; 1154 1155 case 'f': /* use font mounted here */ 1156 fscanf(fp, "%s", str); 1157 setfont(t_font(str)); 1158 break; 1159 1160 case 'H': /* absolute horizontal motion */ 1161 fscanf(fp, "%d", &n); 1162 hgoto(n); 1163 break; 1164 1165 case 'h': /* relative horizontal motion */ 1166 fscanf(fp, "%d", &n); 1167 hmot(n); 1168 break; 1169 1170 case 'w': /* word space */ 1171 break; 1172 1173 case 'V': /* absolute vertical position */ 1174 fscanf(fp, "%d", &n); 1175 vgoto(n); 1176 break; 1177 1178 case 'v': /* relative vertical motion */ 1179 fscanf(fp, "%d", &n); 1180 vmot(n); 1181 break; 1182 1183 case 'p': /* new page */ 1184 fscanf(fp, "%d", &n); 1185 t_page(n); 1186 break; 1187 1188 case 'n': /* end of line */ 1189 while ( (c = getc(fp)) != '\n' && c != EOF ) ; 1190 t_newline(); 1191 lineno++; 1192 break; 1193 1194 case '#': /* comment */ 1195 while ( (c = getc(fp)) != '\n' && c != EOF ) ; 1196 lineno++; 1197 break; 1198 1199 case 'x': /* device control function */ 1200 devcntrl(fp); 1201 lineno++; 1202 break; 1203 1204 default: 1205 error(FATAL, "unknown input character %o %c", c, c); 1206 done(); 1207 1208 } /* End switch */ 1209 1210 } /* End while */ 1211 1212 t_page(-1); /* print the last page */ 1213 endtext(); 1214 1215 } /* End of conv */ 1216 1217 1218 /*****************************************************************************/ 1219 1220 1221 static void 1222 devcntrl(FILE *fp) 1223 /* current input file */ 1224 { 1225 1226 1227 char str[50], buf[256], str1[50]; 1228 int c, n; 1229 1230 1231 /* 1232 * 1233 * Called from conv() to process the rest of a device control function. There's 1234 * a whole family of them and they all start with the string "x ", which we've 1235 * already read. The "x X ..." commands are an extensible (and device dependent) 1236 * family that we use here for things like picture inclusion. Unrecognized device 1237 * control commands are ignored. 1238 * 1239 */ 1240 1241 1242 fscanf(fp, "%s", str); /* get the control function name */ 1243 1244 switch ( str[0] ) { /* only the first character counts */ 1245 1246 case 'i': /* initialize */ 1247 t_init(); 1248 break; 1249 1250 case 'T': /* device name */ 1251 fscanf(fp, "%s", devname); 1252 getdevmap(); 1253 strcpy(devname, realdev); 1254 break; 1255 1256 case 't': /* trailer */ 1257 t_trailer(); 1258 break; 1259 1260 case 'p': /* pause -- can restart */ 1261 t_reset('p'); 1262 break; 1263 1264 case 's': /* stop */ 1265 t_reset('s'); 1266 break; 1267 1268 case 'r': /* resolution assumed when prepared */ 1269 fscanf(fp, "%d", &res); 1270 break; 1271 1272 case 'f': /* load font in a position */ 1273 fscanf(fp, "%d %s", &n, str); 1274 fgets(buf, sizeof buf, fp); /* in case there's a filename */ 1275 ungetc('\n', fp); /* fgets() goes too far */ 1276 str1[0] = '\0'; /* in case there's nothing to come in */ 1277 sscanf(buf, "%s", str1); 1278 loadfont(n, mapdevfont(str), str1); 1279 break; 1280 1281 /* these don't belong here... */ 1282 case 'H': /* char height */ 1283 fscanf(fp, "%d", &n); 1284 t_charht(n); 1285 break; 1286 1287 case 'S': /* slant */ 1288 fscanf(fp, "%d", &n); 1289 t_slant(n); 1290 break; 1291 1292 case 'X': /* copy through - from troff */ 1293 fscanf(fp, " %[^: \n]:", str); 1294 fgets(buf, sizeof(buf), fp); 1295 ungetc('\n', fp); 1296 if ( strcmp(str, "PI") == 0 || strcmp(str, "PictureInclusion") == 0 ) 1297 picture(buf); 1298 else if ( strcmp(str, "InlinePicture") == 0 ) 1299 inlinepic(fp, buf); 1300 else if ( strcmp(str, "BeginPath") == 0 ) 1301 beginpath(buf, FALSE); 1302 else if ( strcmp(str, "DrawPath") == 0 ) 1303 drawpath(buf, FALSE); 1304 else if ( strcmp(str, "BeginObject") == 0 ) 1305 beginpath(buf, TRUE); 1306 else if ( strcmp(str, "EndObject") == 0 ) 1307 drawpath(buf, TRUE); 1308 else if ( strcmp(str, "NewBaseline") == 0 ) 1309 newbaseline(buf); 1310 else if ( strcmp(str, "DrawText") == 0 ) 1311 drawtext(buf); 1312 else if ( strcmp(str, "SetText") == 0 ) 1313 settext(buf); 1314 else if ( strcmp(str, "SetColor") == 0 ) { 1315 newcolor(buf); 1316 setcolor(); 1317 } else if ( strcmp(str, "PS") == 0 || strcmp(str, "PostScript") == 0 ) { 1318 endtext(); 1319 /* xymove(hpos, vpos); ul90-22006 */ 1320 fprintf(tf, "%s", buf); 1321 } /* End else */ 1322 break; 1323 } /* End switch */ 1324 1325 while ( (c = getc(fp)) != '\n' && c != EOF ) ; 1326 1327 } /* End of devcntrl */ 1328 1329 1330 /*****************************************************************************/ 1331 1332 1333 static void 1334 fontinit(void) 1335 { 1336 int fin; /* for reading the DESC.out file */ 1337 char *filebase; /* the whole thing goes here */ 1338 int i; /* loop index */ 1339 1340 1341 /* 1342 * 1343 * Reads *realdev's DESC.out file and uses what's there to initialize things like 1344 * the list of available point sizes. Old versions of the program used *devname's 1345 * DESC.out file to initialize nfonts, but that meant we needed to have *devname's 1346 * binary font files available for emulation. That restriction has been removed 1347 * and we now set nfonts using the "x font" commands in the input file, so by the 1348 * time we get here all we really need is *realdev. In fact devcntrl() reads the 1349 * device name from the "x T ..." command, but almost immediately replaces it with 1350 * string *realdev so we end up using *realdev's DESC.out file. Later on (in 1351 * t_font()) we mount all of *realdev's special fonts after the last legitimate 1352 * font position, just to be sure device emulation works reasonably well - there's 1353 * no guarantee *devname's special fonts match what's needed when *realdev's tables 1354 * are used. 1355 * 1356 */ 1357 1358 1359 sprintf(temp, "%s/dev%s/DESC.out", fontdir, devname); 1360 if ( (fin = open(temp, 0)) < 0 ) 1361 error(FATAL, "can't open tables for %s", temp); 1362 1363 read(fin, &dev, sizeof(struct dev)); 1364 1365 nfonts = 0; /* was dev.nfonts - now set in t_fp() */ 1366 nsizes = dev.nsizes; 1367 nchtab = dev.nchtab; 1368 unitwidth = dev.unitwidth; 1369 1370 if ( (filebase = malloc(dev.filesize)) == NULL ) 1371 error(FATAL, "no memory for description file"); 1372 1373 read(fin, filebase, dev.filesize); /* all at once */ 1374 close(fin); 1375 1376 pstab = (short *) filebase; 1377 chtab = pstab + nsizes + 1; 1378 chname = (char *) (chtab + nchtab); 1379 fsize = 3 * 255 + nchtab + 128 - 32 + sizeof(struct Font); 1380 1381 for ( i = 1; i <= NFONT; i++ ) { /* so loadfont() knows nothing's there */ 1382 fontbase[i] = NULL; 1383 widthtab[i] = codetab[i] = fitab[i] = NULL; 1384 } /* End for */ 1385 1386 if ( (downloaded = (char *) calloc(nchtab + 128, sizeof(char))) == NULL ) 1387 error(FATAL, "no memory"); 1388 1389 } /* End of fontinit */ 1390 1391 1392 /*****************************************************************************/ 1393 1394 1395 static void 1396 loadfont(int n, char *s, char *s1) 1397 /* n - load this font position */ 1398 /* s - with the .out file for this font */ 1399 /* s1 - taken from here - possibly */ 1400 { 1401 int fin; /* for reading *s.out file */ 1402 int nw; /* number of width table entries */ 1403 1404 1405 /* 1406 * 1407 * Loads font position n with the binary font file for *s.out provided it's not 1408 * already there. If *s1 is NULL or points to the empty string we read files from 1409 * directory *fontdir/dev*devname, otherwise directory *s1 is used. If the first 1410 * open fails we try to map font *s into one we expect will be available, and then 1411 * we try again. 1412 * 1413 */ 1414 1415 1416 if ( n < 0 || n > NFONT ) /* make sure it's a legal position */ 1417 error(FATAL, "illegal fp command %d %s", n, s); 1418 1419 if ( fontbase[n] != NULL && strcmp(s, fontbase[n]->namefont) == 0 ) 1420 return; 1421 1422 if ( s1 == NULL || s1[0] == '\0' ) 1423 sprintf(temp, "%s/dev%s/%s.out", fontdir, devname, s); 1424 else sprintf(temp, "%s/%s.out", s1, s); 1425 1426 if ( (fin = open(temp, 0)) < 0 ) { 1427 sprintf(temp, "%s/dev%s/%s.out", fontdir, devname, mapfont(s)); 1428 if ( (fin = open(temp, 0)) < 0 ) 1429 error(FATAL, "can't open font table %s", temp); 1430 } /* End if */ 1431 1432 if ( fontbase[n] != NULL ) /* something's already there */ 1433 free(fontbase[n]); /* so release the memory first */ 1434 1435 fontbase[n] = (struct Font *) malloc(fsize); 1436 if ( fontbase[n] == NULL ) 1437 error(FATAL, "Out of space in loadfont %s", s); 1438 1439 read(fin, fontbase[n], fsize); 1440 close(fin); 1441 1442 if ( smnt == 0 && fontbase[n]->specfont == 1 ) 1443 smnt = n; 1444 1445 nw = fontbase[n]->nwfont & BMASK; 1446 widthtab[n] = (char *) fontbase[n] + sizeof(struct Font); 1447 codetab[n] = (char *) widthtab[n] + 2 * nw; 1448 fitab[n] = (char *) widthtab[n] + 3 * nw; 1449 1450 t_fp(n, fontbase[n]->namefont, fontbase[n]->intname); 1451 1452 if ( debug == ON ) 1453 fontprint(n); 1454 1455 } /* End of loadfont */ 1456 1457 1458 /*****************************************************************************/ 1459 1460 1461 static void 1462 loadspecial(void) 1463 { 1464 char *p; /* for next binary font file */ 1465 int nw; /* width entries in next font */ 1466 int i; /* loop index */ 1467 1468 1469 /* 1470 * 1471 * Loads all the special fonts after the last legal font position. Mostly used 1472 * for device emulation, but we'll do it no matter what. Needed because there's 1473 * no consistency in special fonts across different devices, and relying on having 1474 * them mounted in the input file doesn't guarantee the whole collection will be 1475 * there. The special fonts are determined and mounted using the copy of the 1476 * DESC.out file that's been read into memory. Initially had this stuff at the 1477 * end of fontinit(), but we now don't know nfonts until much later. 1478 * 1479 */ 1480 1481 1482 if ( gotspecial == FALSE ) 1483 for ( i = 1, p = chname + dev.lchname; i <= dev.nfonts; i++ ) { 1484 nw = *p & BMASK; 1485 if ( ((struct Font *) p)->specfont == 1 ) 1486 loadfont(++nfonts, ((struct Font *)p)->namefont, NULL); 1487 p += 3 * nw + dev.nchtab + 128 - 32 + sizeof(struct Font); 1488 } /* End for */ 1489 1490 gotspecial = TRUE; 1491 1492 } /* End of loadspecial */ 1493 1494 1495 /*****************************************************************************/ 1496 char *defaultFonts[] = 1497 { "R", "I", "B", "BI", "CW", "H", "HB", "HX", "S1", "S", NULL }; 1498 1499 static void 1500 loaddefault(void) 1501 { 1502 int i; 1503 1504 for (i = 0; defaultFonts[i] != NULL ; i++) 1505 loadfont(++nfonts, defaultFonts[i], NULL); 1506 } 1507 1508 1509 static void 1510 fontprint(int i) 1511 /* font's index in fontbase[] */ 1512 { 1513 int j, n; 1514 char *p; 1515 1516 1517 /* 1518 * 1519 * Debugging routine that dumps data about the font mounted in position i. 1520 * 1521 */ 1522 1523 1524 fprintf(tf, "font %d:\n", i); 1525 1526 p = (char *) fontbase[i]; 1527 n = fontbase[i]->nwfont & BMASK; 1528 1529 fprintf(tf, "base=0%o, nchars=%d, spec=%d, name=%s, widtab=0%o, fitab=0%o\n", 1530 p, n, fontbase[i]->specfont, fontbase[i]->namefont, widthtab[i], fitab[i]); 1531 1532 fprintf(tf, "widths:\n"); 1533 for ( j = 0; j <= n; j++ ) { 1534 fprintf(tf, " %2d", widthtab[i][j] & BMASK); 1535 if ( j % 20 == 19 ) putc('\n', tf); 1536 } /* End for */ 1537 1538 fprintf(tf, "\ncodetab:\n"); 1539 for ( j = 0; j <= n; j++ ) { 1540 fprintf(tf, " %2d", codetab[i][j] & BMASK); 1541 if ( j % 20 == 19 ) putc('\n', tf); 1542 } /* End for */ 1543 1544 fprintf(tf, "\nfitab:\n"); 1545 for ( j = 0; j <= dev.nchtab + 128-32; j++ ) { 1546 fprintf(tf, " %2d", fitab[i][j] & BMASK); 1547 if ( j % 20 == 19 ) putc('\n', tf); 1548 } /* End for */ 1549 1550 putc('\n', tf); 1551 1552 } /* End of fontprint */ 1553 1554 1555 /*****************************************************************************/ 1556 1557 1558 char * 1559 mapfont(char *name) 1560 /* troff wanted this font */ 1561 { 1562 int i; /* loop index */ 1563 1564 1565 /* 1566 * 1567 * If loadfont() can't find font *name we map it into something else that should 1568 * be available and return a pointer to the new name. Used mostly for emulating 1569 * devices like the APS-5. 1570 * 1571 */ 1572 1573 1574 for ( i = 0; fontmap[i].name != NULL; i++ ) 1575 if ( strcmp(name, fontmap[i].name) == 0 ) 1576 return(fontmap[i].use); 1577 1578 switch ( *++name ) { 1579 case 'I': 1580 return("I"); 1581 1582 case 'B': 1583 return("B"); 1584 1585 case 'X': 1586 return("BI"); 1587 1588 default: 1589 return("R"); 1590 } /* End switch */ 1591 1592 } /* End of mapfont */ 1593 1594 1595 /*****************************************************************************/ 1596 1597 1598 static void 1599 getdevmap(void) 1600 { 1601 1602 1603 FILE *fp; /* for reading the device fontmap file */ 1604 int i = 0; /* number of mapping pairs we've read */ 1605 int c; /* for skipping lines */ 1606 1607 1608 /* 1609 * 1610 * Looks for the device font mapping file *fontdir/dev*realdev/fontmaps/devname. 1611 * The file, if it exists, should be an ASCII file containing pairs of one or two 1612 * character font names per line. The first name is the font troff will be asking 1613 * for and the second is the one we'll use. Comments are lines that begin with 1614 * a '#' as the first non-white space character on a line. The devfontmap list 1615 * ends with a member that has the empty string in the name field. 1616 * 1617 */ 1618 1619 1620 sprintf(temp, "%s/dev%s/fontmaps/%s", fontdir, realdev, devname); 1621 1622 if ( devfontmap == NULL && (fp = fopen(temp, "r")) != NULL ) { 1623 devfontmap = (Devfontmap *) malloc(10 * sizeof(Devfontmap)); 1624 1625 while ( fscanf(fp, "%s", temp) != EOF ) { 1626 if ( temp[0] != '#' && strlen(temp) < 3 ) 1627 if ( fscanf(fp, "%s", &temp[3]) == 1 && strlen(&temp[3]) < 3 ) { 1628 strcpy((devfontmap + i)->name, temp); 1629 strcpy((devfontmap + i)->use, &temp[3]); 1630 if ( ++i % 10 == 0 ) 1631 devfontmap = (Devfontmap *) realloc(devfontmap, (i + 10) * sizeof(Devfontmap)); 1632 } /* End if */ 1633 while ( (c = getc(fp)) != '\n' && c != EOF ) ; 1634 } /* End while */ 1635 1636 (devfontmap + i)->name[0] = '\0'; /* end the list we just read */ 1637 fclose(fp); 1638 } /* End if */ 1639 1640 } /* End of getdevmap */ 1641 1642 1643 /*****************************************************************************/ 1644 1645 1646 char * 1647 mapdevfont(char *str) 1648 { 1649 int i; 1650 1651 1652 /* 1653 * 1654 * Called immediately before loadfont() after an 'x font' command is recognized. 1655 * Takes the font name that troff asked for, looks it up in the devfontmap list, 1656 * and returns the mapped name to the caller. No mapping is done if the devfontmap 1657 * list is empty or font *str isn't found in the list. 1658 * 1659 */ 1660 1661 1662 if ( devfontmap != NULL ) 1663 for ( i = 0; (devfontmap + i)->name[0] != '\0'; i++ ) 1664 if ( strcmp((devfontmap + i)->name, str) == 0 ) 1665 return((devfontmap + i)->use); 1666 1667 return(str); 1668 1669 } /* End of mapdevfont */ 1670 1671 1672 /*****************************************************************************/ 1673 1674 1675 void 1676 reset(void) 1677 { 1678 1679 /* 1680 * 1681 * Resets the variables that keep track of the printer's current position, font, 1682 * and size. Typically used after a restore/save pair (eg. when we finish with a 1683 * page) to make sure we force the printer back into sync (in terms of the font 1684 * and current point) before text is printed. 1685 * 1686 */ 1687 1688 1689 lastx = -(slop + 1); 1690 lasty = -1; 1691 lastfont = lastsize = -1; 1692 1693 } /* End of reset */ 1694 1695 1696 /*****************************************************************************/ 1697 1698 1699 void 1700 resetpos(void) 1701 { 1702 1703 1704 /* 1705 * 1706 * Resets the variables that keep track of the printer's current position. Used 1707 * when there's a chance we've lost track of the printer's current position or 1708 * done something that may have wiped it out, and we want to force dpost to set 1709 * the printer's position before printing text or whatever. For example stroke or 1710 * fill implicitly do a newpath, and that wipes out the current point, unless the 1711 * calls were bracketed by a gsave/grestore pair. 1712 * 1713 */ 1714 1715 1716 lastx = -(slop + 1); 1717 lasty = -1; 1718 1719 } /* End of resetpos */ 1720 1721 1722 /*****************************************************************************/ 1723 1724 1725 static void 1726 t_init(void) 1727 { 1728 static int initialized = FALSE; /* only do most things once */ 1729 1730 1731 /* 1732 * 1733 * Called from devcntrl() after an "x init" command is read. Things only work if 1734 * we've already seen the "x res" command, and much of the stuff, including the 1735 * call to setup, should only be done once. Restricting everything to one call of 1736 * setup (ie. the one in the prologue) means all the input files must have been 1737 * formatted for the same device. 1738 * 1739 */ 1740 1741 1742 endtext(); /* moved - for cat'ed troff files */ 1743 1744 if ( initialized == FALSE ) { /* only do this stuff once per job */ 1745 fontinit(); 1746 gotspecial = FALSE; 1747 widthfac = (float) res /dev.res; 1748 slop = pointslop * res / POINTS + .5; 1749 rvslop = res * .025; 1750 setup(); 1751 initialized = TRUE; 1752 } /* End if */ 1753 1754 hpos = vpos = 0; /* upper left corner */ 1755 setsize(t_size(10)); /* start somewhere */ 1756 reset(); /* force position and font stuff - later */ 1757 1758 } /* End of t_init */ 1759 1760 1761 /*****************************************************************************/ 1762 1763 1764 static void 1765 t_page(int pg) 1766 /* troff's current page number */ 1767 { 1768 static int lastpg = 0; /* last one we started - for ENDPAGE */ 1769 1770 1771 /* 1772 * 1773 * Called whenever we've finished the last page and want to get ready for the 1774 * next one. Also used at the end of each input file, so we have to be careful 1775 * about what's done. The first time through (up to the redirect(pg) call) output 1776 * goes to /dev/null because of the redirect(-1) call made in conv(). 1777 * 1778 * Adobe now recommends that the showpage operator occur after the page level 1779 * restore so it can be easily redefined to have side-effects in the printer's VM. 1780 * Although it seems reasonable I haven't implemented it, because it makes other 1781 * things, like selectively setting manual feed or choosing an alternate paper 1782 * tray, clumsy - at least on a per page basis. 1783 * 1784 */ 1785 1786 1787 if ( tf == stdout ) /* count the last page */ 1788 printed++; 1789 1790 endtext(); /* print the last line? */ 1791 1792 fprintf(tf, "cleartomark\n"); 1793 fprintf(tf, "showpage\n"); 1794 fprintf(tf, "restore\n"); 1795 fprintf(tf, "%s %d %d\n", ENDPAGE, lastpg, printed); 1796 1797 redirect(pg); 1798 1799 fprintf(tf, "%s %d %d\n", PAGE, pg, printed+1); 1800 fprintf(tf, "save\n"); 1801 fprintf(tf, "mark\n"); 1802 writerequest(printed+1, tf); 1803 fprintf(tf, "%d pagesetup\n", printed+1); 1804 setcolor(); 1805 1806 lastpg = pg; /* for the next ENDPAGE comment */ 1807 hpos = vpos = 0; /* get ready for the next page */ 1808 reset(); /* force position and font stuff - later */ 1809 1810 seenpage = TRUE; 1811 1812 } /* End of t_page */ 1813 1814 1815 /*****************************************************************************/ 1816 1817 1818 static void 1819 t_newline(void) 1820 { 1821 1822 1823 /* 1824 * 1825 * Just finished the last line. All we do is set the horizontal position to 0, 1826 * although even that probably isn't necessary. 1827 * 1828 */ 1829 1830 1831 hpos = 0; 1832 1833 } /* End of t_newline */ 1834 1835 1836 /*****************************************************************************/ 1837 1838 1839 int 1840 t_size(int n) 1841 /* convert this to an internal size */ 1842 { 1843 int i; /* loop index */ 1844 1845 1846 /* 1847 * 1848 * Converts a point size into an internal size that can be used as an index into 1849 * pstab[]. The internal size is one plus the index of the least upper bound of 1850 * n in pstab[], or nsizes if n is larger than all the listed sizes. 1851 * 1852 */ 1853 1854 1855 if ( n <= pstab[0] ) 1856 return(1); 1857 else if (n >= pstab[nsizes-1]) 1858 return(nsizes); 1859 1860 for ( i = 0; n > pstab[i]; i++ ) ; 1861 1862 return(i+1); 1863 1864 } /* End of t_size */ 1865 1866 1867 /*****************************************************************************/ 1868 1869 1870 static void 1871 setsize(int n) 1872 /* new internal size */ 1873 { 1874 1875 1876 /* 1877 * 1878 * Now using internal size n, where pstab[n-1] is the best available approximation 1879 * to the size troff asked for. 1880 * 1881 */ 1882 1883 1884 size = n; 1885 1886 } /* End of setsize */ 1887 1888 1889 /*****************************************************************************/ 1890 1891 1892 static void 1893 t_fp(int n, char *s, char *si) 1894 /* n - this position */ 1895 /* s - now has this font mounted */ 1896 /* si - its internal number */ 1897 1898 1899 { 1900 1901 1902 /* 1903 * 1904 * Updates nfonts and the array that keeps track of the mounted fonts. Called from 1905 * loadfont() after an "x font pos font" command is read, and if pos is larger than 1906 * the current value assigned to nfonts we set gotspecial to FALSE to make sure 1907 * t_font() loads all the special fonts after the last legitimate font position. 1908 * 1909 */ 1910 1911 1912 fontname[n].name = s; 1913 fontname[n].number = atoi(si); 1914 1915 if ( n == lastfont ) /* force a call to t_sf() */ 1916 lastfont = -1; 1917 1918 if ( n > nfonts ) { /* got more positions */ 1919 nfonts = n; 1920 gotspecial = FALSE; 1921 } /* End if */ 1922 1923 } /* End of t_fp */ 1924 1925 1926 /*****************************************************************************/ 1927 1928 int 1929 t_font(char *s) 1930 /* use font in this position next */ 1931 { 1932 int n; 1933 1934 1935 /* 1936 * 1937 * Converts the string *s into an integer and checks to make sure it's a legal 1938 * font position. Also arranges to mount all the special fonts after the last 1939 * legitimate font (by calling loadspecial()), provided it hasn't already been 1940 * done. 1941 * 1942 */ 1943 1944 1945 n = atoi(s); 1946 1947 if ( seenpage == TRUE ) { 1948 if ( n < 0 || n > nfonts ) 1949 error(FATAL, "illegal font position %d", n); 1950 1951 if ( gotspecial == FALSE ) 1952 loadspecial(); 1953 } /* End if */ 1954 1955 return(n); 1956 1957 } /* End of t_font */ 1958 1959 1960 /*****************************************************************************/ 1961 1962 1963 static void 1964 setfont(int n) 1965 /* use the font mounted here */ 1966 { 1967 1968 1969 /* 1970 * 1971 * troff wants to use the font that's been mounted in position n. All we do here 1972 * is update the variable that keeps track of the current position. PostScript 1973 * font changes are handled in t_sf(), and are only generated right before we're 1974 * ready to print or draw something. 1975 * 1976 */ 1977 1978 1979 if ( n < 0 || n > NFONT ) 1980 error(FATAL, "illegal font %d", n); 1981 if ( fontname[n].name == NULL && fontname[n].number == 0) 1982 loaddefault(); 1983 if ( fontname[n].name == NULL && fontname[n].number == 0) 1984 error(FATAL, 1985 "font %d not loaded: check 'dpost' input for 'x font %d XXX' before 'f%d'", 1986 n, n, n); 1987 1988 font = n; 1989 1990 } /* End of setfont */ 1991 1992 1993 /*****************************************************************************/ 1994 1995 void 1996 t_sf(void) 1997 { 1998 int fnum; /* internal font number */ 1999 2000 2001 /* 2002 * 2003 * Called whenever we need to use a new font or size. Only done right before we 2004 * print a character. The seenfonts[] array keeps track of the fonts we've used. 2005 * Helps manage host resident fonts and the DOCUMENTFONTS comment that's put out 2006 * at the end of the job. The array is indexed by internal number. Only works for 2007 * fonts that have internal numbers less than or equal to MAXINTERNAL. 2008 * 2009 */ 2010 2011 2012 if ( fontname[font].name == NULL ) 2013 return; 2014 2015 endtext(); 2016 2017 if ( (fnum = fontname[font].number) > MAXINTERNAL || fnum < 0 ) 2018 fnum = 0; 2019 2020 if ( fnum > 0 && seenfonts[fnum] == 0 && hostfontdir != NULL ) { 2021 sprintf(temp, "%s/%s", hostfontdir, fontname[font].name); 2022 if ( access(temp, 04) == 0 ) 2023 doglobal(temp); 2024 } /* End if */ 2025 2026 if ( tf == stdout ) { 2027 lastfont = font; 2028 lastsize = size; 2029 if ( seenfonts[fnum] == 0 ) 2030 documentfonts(); 2031 seenfonts[fnum] = 1; 2032 } /* End if */ 2033 2034 fprintf(tf, "%d %s f\n", pstab[size-1], fontname[font].name); 2035 2036 if ( fontheight != 0 || fontslant != 0 ) 2037 fprintf(tf, "%d %d changefont\n", fontslant, (fontheight != 0) ? fontheight : pstab[size-1]); 2038 2039 } /* End of t_sf */ 2040 2041 2042 /*****************************************************************************/ 2043 2044 2045 static void 2046 t_charht(int n) 2047 /* use this as the character height */ 2048 { 2049 2050 /* 2051 * 2052 * Remembers the requested height, from 'x H n'. Forces a call to t_sf(), which 2053 * is where the real work is done, by setting lastfont to -1. 2054 * 2055 */ 2056 2057 fontheight = (n == pstab[size-1]) ? 0 : n; 2058 lastfont = -1; 2059 2060 } /* End of t_charht */ 2061 2062 2063 /*****************************************************************************/ 2064 2065 2066 static void 2067 t_slant(int n) 2068 /* slant characters this many degrees */ 2069 { 2070 2071 /* 2072 * 2073 * Remembers the requested slant, from 'x X n'. Forces a call to t_sf(), which 2074 * is where the real work is done, by setting lastfont to -1. 2075 * 2076 */ 2077 2078 fontslant = n; 2079 lastfont = -1; 2080 2081 } /* End of t_slant */ 2082 2083 2084 /*****************************************************************************/ 2085 2086 2087 static void 2088 t_reset(int c) 2089 /* pause or restart */ 2090 { 2091 2092 /* 2093 * 2094 * Found an "x stop" or "x pause" command. Although nothing's done here we could 2095 * add code to reset everything so dpost could handle multiple files formatted for 2096 * different devices. 2097 * 2098 */ 2099 2100 2101 } /* End of t_reset */ 2102 2103 2104 /*****************************************************************************/ 2105 2106 2107 static void 2108 t_trailer(void) 2109 { 2110 2111 /* 2112 * 2113 * Called after we find an "x trailer" in the input file. Forcing out the last 2114 * page is done at the end of conv(), but probably belongs here. 2115 * 2116 */ 2117 2118 2119 endtext(); 2120 2121 } /* End of t_trailer */ 2122 2123 2124 /*****************************************************************************/ 2125 2126 2127 void 2128 hgoto(int n) 2129 /* new horizontal position */ 2130 { 2131 2132 2133 /* 2134 * 2135 * Want to be at this absolute horizontal position next. Actual motion commands 2136 * are generated in oput(), charlib(), and the drawing routines. 2137 * 2138 */ 2139 2140 2141 hpos = n; 2142 2143 } /* End of hgoto */ 2144 2145 2146 /*****************************************************************************/ 2147 2148 2149 static void 2150 hmot(int n) 2151 /* move this far horizontally */ 2152 { 2153 2154 /* 2155 * 2156 * Handles relative horizontal motion. troff's current positon, as recorded in 2157 * in hpos, is changed by n units. Usually called right before we're supposed to 2158 * print a character. 2159 * 2160 */ 2161 2162 2163 hpos += n; 2164 2165 } /* End of hmot */ 2166 2167 2168 /*****************************************************************************/ 2169 2170 2171 void 2172 vgoto(int n) 2173 /* new vertical position */ 2174 { 2175 2176 /* 2177 * 2178 * Moves vertically in troff's coordinate system to absolute position n. 2179 * 2180 */ 2181 2182 2183 vpos = n; 2184 2185 } /* End of vgoto */ 2186 2187 2188 /*****************************************************************************/ 2189 2190 2191 static void 2192 vmot(int n) 2193 /* move this far vertically */ 2194 { 2195 2196 /* 2197 * 2198 * Handles relative vertical motion of n units in troff's coordinate system. 2199 * 2200 */ 2201 2202 2203 vpos += n; 2204 2205 } /* End of vmot */ 2206 2207 2208 /*****************************************************************************/ 2209 2210 2211 void 2212 xymove(int x, int y) 2213 /* this is where we want to be */ 2214 { 2215 2216 /* 2217 * 2218 * Makes sure the post-processor and printer agree about the current position. 2219 * 2220 */ 2221 2222 2223 hgoto(x); 2224 vgoto(y); 2225 2226 fprintf(tf, "%d %d m\n", hpos, vpos); 2227 2228 lastx = hpos; 2229 lasty = vpos; 2230 2231 } /* End of xymove */ 2232 2233 2234 /*****************************************************************************/ 2235 2236 2237 static void 2238 put1s(char *s) 2239 /* find and print this character */ 2240 { 2241 static int i = 0; /* last one we found - usually */ 2242 2243 /* 2244 * 2245 * *s points to the start of a two character string that represents one of troff's 2246 * special characters. To print it we first look for *s in the chname[] array using 2247 * chtab[i] to find the string representing character i in chname[]. If the lookup 2248 * is successful we add 128 to i and ask put1() to finish printing the character. 2249 * We remember the index where the last character was found because requests to 2250 * print a special character often come in bunches (eg. drawing lines with \(ru). 2251 * 2252 */ 2253 2254 2255 if ( strcmp(s, &chname[chtab[i]]) != 0 ) 2256 for ( i = 0; i < nchtab; i++ ) 2257 if ( strcmp(&chname[chtab[i]], s) == 0 ) 2258 break; 2259 2260 if ( i < nchtab ) 2261 put1(i + 128); 2262 else i = 0; 2263 2264 } /* End of put1s */ 2265 2266 2267 /*****************************************************************************/ 2268 2269 2270 static void 2271 put1(int c) 2272 /* want to print this character */ 2273 { 2274 2275 int i; /* character code from fitab */ 2276 int j; /* number of fonts we've checked so far */ 2277 int k; /* font we're currently looking at */ 2278 char *pw; /* font widthtab and */ 2279 char *p; /* and codetab where c was found */ 2280 int code; /* code used to get c printed */ 2281 int ofont; /* font when we started */ 2282 2283 2284 /* 2285 * 2286 * Arranges to have character c printed. If c < 128 it's a simple ASCII character, 2287 * otherwise it's a special character. Things done here have to agree with the way 2288 * the font tables were built by makedev, and work as follows. First we subtract 2289 * 32 from c because the tables don't record the non-graphic ASCII characters. 2290 * If fitab[k][c] isn't zero the character is on font k and the value is an index 2291 * that can be used to recover width and character code data from the other two 2292 * tables. If fitab[k][c] is zero the character isn't defined on font k and we 2293 * check the next font, which is found as follows. The current font is the first 2294 * one we check, and it's followed by a circular search of all the remaining fonts 2295 * that starts with the first special font and skips font position 0. If character 2296 * c is found somewhere besides the current font we change to that font and use 2297 * fitab[k][c] to locate missing data in the other two tables. The width of the 2298 * character can be found at widthtab[k][c] while codetab[k][c] is whatever we 2299 * need to tell the printer to have character c printed. lastc records the real 2300 * name of the character because it's lost by the time oput() gets called but 2301 * charlib() may need it. 2302 * 2303 * Took all the debugging stuff out because at least this part of the program is 2304 * reasonably solid. 2305 * 2306 */ 2307 2308 2309 lastc = c; /* charlib() needs the name not the code */ 2310 if ( (c -= 32) <= 0 ) /* probably never happens */ 2311 return; 2312 2313 k = ofont = font; 2314 2315 if ( (i = fitab[k][c] & BMASK) != 0 ) { /* it's on this font */ 2316 p = codetab[font]; 2317 pw = widthtab[font]; 2318 } else if ( smnt > 0 ) { /* on special (we hope) */ 2319 for ( k=smnt, j=0; j <= nfonts; j++, k = (k+1) % (nfonts+1) ) { 2320 if ( k == 0 ) continue; 2321 if ( (i = fitab[k][c] & BMASK) != 0 ) { 2322 p = codetab[k]; 2323 pw = widthtab[k]; 2324 setfont(k); 2325 break; 2326 } /* End if */ 2327 } /* End for */ 2328 } /* End else */ 2329 2330 if ( i != 0 && (code = p[i] & BMASK) != 0 ) { 2331 lastw = widthfac * (((pw[i] & BMASK) * pstab[size-1] + unitwidth/2) / unitwidth); 2332 oput(code); 2333 } /* End if */ 2334 2335 if ( font != ofont ) 2336 setfont(ofont); 2337 2338 } /* End of put1 */ 2339 2340 2341 /*****************************************************************************/ 2342 2343 2344 static void 2345 oput(int c) 2346 /* want to print this character */ 2347 { 2348 2349 /* 2350 * 2351 * Arranges to print the character whose code is c in the current font. All the 2352 * actual positioning is done here, in charlib(), or in the drawing routines. 2353 * 2354 */ 2355 2356 2357 if ( textcount > MAXSTACK ) /* don't put too much on the stack? */ 2358 endtext(); 2359 2360 if ( font != lastfont || size != lastsize ) 2361 t_sf(); 2362 2363 if ( vpos != lasty ) 2364 endline(); 2365 2366 starttext(); 2367 2368 if ( ABS(hpos - lastx) > slop ) 2369 endstring(); 2370 2371 if ( isascii(c) && isprint(c) ) 2372 switch ( c ) { 2373 case '(': 2374 case ')': 2375 case '\\': 2376 addchar('\\'); 2377 2378 default: 2379 addchar(c); 2380 } /* End switch */ 2381 else if ( c > 040 ) 2382 addoctal(c); 2383 else charlib(c); 2384 2385 lastx += lastw; 2386 2387 } /* End of oput */ 2388 2389 2390 /*****************************************************************************/ 2391 2392 2393 static void 2394 starttext(void) 2395 { 2396 2397 /* 2398 * Called whenever we want to be sure we're ready to start collecting characters 2399 * for the next call to PostScript procedure t (ie. the one that prints them). If 2400 * textcount is positive we've already started, so there's nothing to do. The more 2401 * complicated encoding schemes save text strings in the strings[] array and need 2402 * detailed information about the strings when they're written to the output file 2403 * in endtext(). 2404 * 2405 */ 2406 2407 2408 if ( textcount < 1 ) { 2409 switch ( encoding ) { 2410 case 0: 2411 case 1: 2412 putc('(', tf); 2413 break; 2414 2415 case 2: 2416 case 3: 2417 strptr = strings; 2418 spacecount = 0; 2419 line[1].str = strptr; 2420 line[1].dx = 0; 2421 line[1].spaces = 0; 2422 line[1].start = hpos; 2423 line[1].width = 0; 2424 break; 2425 2426 case MAXENCODING+1: /* reverse video */ 2427 if ( lastend == -1 ) 2428 lastend = hpos; 2429 putc('(', tf); 2430 break; 2431 2432 case MAXENCODING+2: /* follow a funny baseline */ 2433 putc('(', tf); 2434 break; 2435 } /* End switch */ 2436 textcount = 1; 2437 lastx = stringstart = hpos; 2438 } /* End if */ 2439 2440 } /* End of starttext */ 2441 2442 2443 /*****************************************************************************/ 2444 2445 2446 void 2447 endtext(void) 2448 { 2449 2450 int i; /* loop index */ 2451 2452 2453 /* 2454 * 2455 * Generates a call to the PostScript procedure that processes all the text we've 2456 * accumulated - provided textcount is positive. 2457 * 2458 */ 2459 2460 if ( textcount > 0 ) { /* started working on some text */ 2461 switch ( encoding ) { 2462 case 0: 2463 fprintf(tf, ")%d t\n", stringstart); 2464 break; 2465 2466 case 1: 2467 fprintf(tf, ")%d %d t\n", stringstart, lasty); 2468 break; 2469 2470 case 2: 2471 *strptr = '\0'; 2472 line[textcount].width = lastx - line[textcount].start; 2473 if ( spacecount != 0 || textcount != 1 ) { 2474 for ( i = textcount; i > 0; i-- ) 2475 fprintf(tf, "(%s)%d %d", line[i].str, line[i].spaces, line[i].width); 2476 fprintf(tf, " %d %d %d t\n", textcount, stringstart, lasty); 2477 } else fprintf(tf, "(%s)%d %d w\n", line[1].str, stringstart, lasty); 2478 break; 2479 2480 case 3: 2481 *strptr = '\0'; 2482 if ( spacecount != 0 || textcount != 1 ) { 2483 for ( i = textcount; i > 0; i-- ) 2484 fprintf(tf, "(%s)%d", line[i].str, line[i].dx); 2485 fprintf(tf, " %d %d %d t\n", textcount, stringstart, lasty); 2486 } else fprintf(tf, "(%s)%d %d w\n", line[1].str, stringstart, lasty); 2487 break; 2488 2489 case MAXENCODING+1: 2490 fprintf(tf, ")%d ", stringstart); 2491 fprintf(tf, "%d %d drawrvbox ", lastend - rvslop, (int)(lastx + .5) + rvslop); 2492 fprintf(tf, "t\n", stringstart); 2493 lastend = (lastx + .5) + 2 * rvslop; 2494 break; 2495 2496 case MAXENCODING+2: 2497 fprintf(tf, ")%d %d t\n", stringstart, lasty); 2498 break; 2499 } /* End switch */ 2500 } /* End if */ 2501 2502 textcount = 0; 2503 2504 } /* End of endtext */ 2505 2506 2507 /*****************************************************************************/ 2508 2509 2510 static void 2511 endstring(void) 2512 { 2513 int dx; 2514 2515 /* 2516 * 2517 * Horizontal positions are out of sync. End the last open string, adjust the 2518 * printer's position, and start a new string. Assumes we've already started 2519 * accumulating text. 2520 * 2521 */ 2522 2523 2524 switch ( encoding ) { 2525 case 0: 2526 case 1: 2527 fprintf(tf, ")%d(", stringstart); 2528 textcount++; 2529 lastx = stringstart = hpos; 2530 break; 2531 2532 case 2: 2533 case 3: 2534 dx = hpos - lastx; 2535 if ( spacecount++ == 0 ) 2536 line[textcount].dx = dx; 2537 if ( line[textcount].dx != dx ) { 2538 *strptr++ = '\0'; 2539 line[textcount].width = lastx - line[textcount].start; 2540 line[++textcount].str = strptr; 2541 *strptr++ = ' '; 2542 line[textcount].dx = dx; 2543 line[textcount].start = lastx; 2544 line[textcount].width = 0; 2545 line[textcount].spaces = 1; 2546 } else { 2547 *strptr++ = ' '; 2548 line[textcount].spaces++; 2549 } /* End else */ 2550 lastx += dx; 2551 break; 2552 2553 case MAXENCODING+1: 2554 fprintf(tf, ")%d(", stringstart); 2555 textcount++; 2556 lastx = stringstart = hpos; 2557 break; 2558 2559 case MAXENCODING+2: 2560 endtext(); 2561 starttext(); 2562 break; 2563 2564 } /* End switch */ 2565 2566 } /* End of endstring */ 2567 2568 2569 /*****************************************************************************/ 2570 2571 2572 static void 2573 endline(void) 2574 { 2575 2576 /* 2577 * 2578 * The vertical position has changed. Dump any accumulated text, then adjust 2579 * the printer's vertical position. 2580 * 2581 */ 2582 2583 2584 endtext(); 2585 2586 if ( encoding == 0 || encoding == MAXENCODING+1 ) 2587 fprintf(tf, "%d %d m\n", hpos, vpos); 2588 2589 lastx = stringstart = lastend = hpos; 2590 lasty = vpos; 2591 2592 } /* End of endline */ 2593 2594 2595 /*****************************************************************************/ 2596 2597 2598 static void 2599 addchar(int c) 2600 /* next character in current string */ 2601 { 2602 2603 /* 2604 * 2605 * Does whatever is needed to add character c to the current string. 2606 * 2607 */ 2608 2609 2610 switch ( encoding ) { 2611 case 0: 2612 case 1: 2613 putc(c, tf); 2614 break; 2615 2616 case 2: 2617 case 3: 2618 *strptr++ = c; 2619 break; 2620 2621 case MAXENCODING+1: 2622 case MAXENCODING+2: 2623 putc(c, tf); 2624 break; 2625 } /* End switch */ 2626 2627 } /* End of addchar */ 2628 2629 2630 /*****************************************************************************/ 2631 2632 2633 static void 2634 addoctal(int c) 2635 /* add it as an octal escape */ 2636 { 2637 2638 2639 /* 2640 * 2641 * Adds c to the current string as an octal escape \ddd. 2642 * 2643 */ 2644 2645 2646 switch ( encoding ) { 2647 case 0: 2648 case 1: 2649 fprintf(tf, "\\%o", c); 2650 break; 2651 2652 case 2: 2653 case 3: 2654 sprintf(strptr, "\\%o", c); 2655 strptr += strlen(strptr); 2656 break; 2657 2658 case MAXENCODING+1: 2659 case MAXENCODING+2: 2660 fprintf(tf, "\\%o", c); 2661 break; 2662 } /* End switch */ 2663 2664 } /* End of addoctal */ 2665 2666 2667 /*****************************************************************************/ 2668 2669 2670 static void 2671 charlib(int code) 2672 /* either 1 or 2 */ 2673 { 2674 char *name; /* name of the character */ 2675 char tname[10]; /* in case it's a single ASCII character */ 2676 2677 2678 /* 2679 * 2680 * Called from oput() for characters having codes less than 040. Special files 2681 * that define PostScript procedures for certain characters can be found in 2682 * directory *fontdir/devpost/charlib. If there's a file that has the same name as 2683 * the character we're trying to print it's copied to the output file, otherwise 2684 * nothing, except some positioning, is done. 2685 * 2686 * All character definitions are only made once. Subsequent requests to print the 2687 * character generate a call to a procedure that begins with the prefix build_ and 2688 * ends with the character's name. Special characters that are assigned codes 2689 * other than 1 are assumed to have additional data files that should be copied 2690 * to the output file immediately after the build_ call. Those data files should 2691 * end in the suffix .map, and usually will be a hex representation of a bitmap. 2692 * 2693 */ 2694 2695 2696 endtext(); 2697 2698 if ( lastc < 128 ) { /* just a simple ASCII character */ 2699 sprintf(tname, "%.3o", lastc); 2700 name = tname; 2701 } else name = &chname[chtab[lastc - 128]]; 2702 2703 if ( downloaded[lastc] == 0 ) { 2704 sprintf(temp, "%s/dev%s/charlib/%s", fontdir, realdev, name); 2705 if ( access(temp, 04) == 0 && doglobal(temp) == TRUE ) { 2706 downloaded[lastc] = 1; 2707 t_sf(); 2708 } /* End if */ 2709 } /* End if */ 2710 2711 if ( downloaded[lastc] == 1 ) { 2712 xymove(hpos, vpos); 2713 fprintf(tf, "%d build_%s\n", (int) lastw, name); 2714 if ( code != 1 ) { /* get the bitmap or whatever */ 2715 sprintf(temp, "%s/dev%s/charlib/%s.map", fontdir, realdev, name); 2716 if ( access(temp, 04) == 0 && tf == stdout ) 2717 cat(temp); 2718 } /* End if */ 2719 fprintf(tf, "%d %d m\n", stringstart = hpos + lastw, vpos); 2720 } /* End if */ 2721 2722 } /* End of charlib */ 2723 2724 2725 /*****************************************************************************/ 2726 2727 2728 int 2729 doglobal(char *name) 2730 /* copy this to the output - globally */ 2731 { 2732 int val = FALSE; /* returned to the caller */ 2733 2734 2735 /* 2736 * 2737 * Copies file *name to the output file and brackets it with whatever commands are 2738 * needed to have it exported to the global environment. TRUE is returned if we 2739 * successfully add file *name to the output file. 2740 * 2741 */ 2742 2743 2744 if ( tf == stdout ) { 2745 endtext(); 2746 fprintf(tf, "cleartomark restore\n"); 2747 fprintf(tf, "%s", BEGINGLOBAL); 2748 val = cat(name); 2749 fprintf(tf, "%s", ENDGLOBAL); 2750 fprintf(tf, "save mark\n"); 2751 reset(); 2752 } /* End if */ 2753 2754 return(val); 2755 2756 } /* End of doglobal */ 2757 2758 2759 /*****************************************************************************/ 2760 2761 2762 static void 2763 documentfonts(void) 2764 { 2765 FILE *fp_in; /* PostScript font name read from here */ 2766 FILE *fp_out; /* and added to this file */ 2767 2768 2769 /* 2770 * 2771 * Whenever a new font is used we try to record the appropriate PostScript font 2772 * name in *temp_file for the DOCUMENTFONTS comment that's put out in done(). 2773 * By default PostScript font names are found in /usr/lib/font/devpost. Fonts 2774 * that have a .name file are recorded in *temp_file. The first string in that 2775 * file is expected to be that font's (long) PostScript name. 2776 * 2777 */ 2778 2779 2780 if ( temp_file == NULL ) /* generate a temp file name */ 2781 if ( (temp_file = tempnam(TEMPDIR, "dpost")) == NULL ) 2782 return; 2783 2784 sprintf(temp, "%s/dev%s/%s.name", fontdir, realdev, fontname[font].name); 2785 2786 if ( (fp_in = fopen(temp, "r")) != NULL ) { 2787 if ( (fp_out = fopen(temp_file, "a")) != NULL ) { 2788 if ( fscanf(fp_in, "%s", temp) == 1 ) { 2789 if ( docfonts++ == 0 ) 2790 fprintf(fp_out, "%s", DOCUMENTFONTS); 2791 else if ( (docfonts - 1) % 8 == 0 ) 2792 fprintf(fp_out, "\n%s", CONTINUECOMMENT); 2793 fprintf(fp_out, " %s", temp); 2794 } /* End if */ 2795 fclose(fp_out); 2796 } /* End if */ 2797 fclose(fp_in); 2798 } /* End if */ 2799 2800 } /* End of documentfonts */ 2801 2802 2803 /*****************************************************************************/ 2804 2805 2806 static void 2807 redirect(int pg) 2808 /* next page we're printing */ 2809 { 2810 static FILE *fp_null = NULL; /* if output is turned off */ 2811 2812 2813 /* 2814 * 2815 * If we're not supposed to print page pg, tf will be directed to /dev/null, 2816 * otherwise output goes to stdout. 2817 * 2818 */ 2819 2820 2821 if ( pg >= 0 && in_olist(pg) == ON ) 2822 tf = stdout; 2823 else if ( (tf = fp_null) == NULL ) 2824 tf = fp_null = fopen("/dev/null", "w"); 2825 2826 } /* End of redirect */ 2827