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