aboutsummaryrefslogtreecommitdiffstats
path: root/troff/troff.d/dpost.d
diff options
context:
space:
mode:
authorBaptiste Daroussin <bapt@FreeBSD.org>2016-10-06 21:30:09 +0000
committerBaptiste Daroussin <bapt@FreeBSD.org>2016-10-06 21:30:09 +0000
commitaa7798c94fa57f6c00fab4393c9fe91334864371 (patch)
tree61b5a60e9c086b1ba44b4718e7666304a8edab6f /troff/troff.d/dpost.d
downloadsrc-aa7798c94fa57f6c00fab4393c9fe91334864371.tar.gz
src-aa7798c94fa57f6c00fab4393c9fe91334864371.zip
Import heirloom doctools snapshot from git as of 161006vendor/heirloom-doctools/20161006
Notes
Notes: svn path=/vendor/heirloom-doctools/dist/; revision=306788 svn path=/vendor/heirloom-doctools/20161006/; revision=306789; tag=vendor/heirloom-doctools/20161006
Diffstat (limited to 'troff/troff.d/dpost.d')
-rw-r--r--troff/troff.d/dpost.d/Makefile.mk42
-rw-r--r--troff/troff.d/dpost.d/README53
-rw-r--r--troff/troff.d/dpost.d/afm.c32
-rw-r--r--troff/troff.d/dpost.d/asciitype.c59
-rw-r--r--troff/troff.d/dpost.d/asciitype.h60
-rw-r--r--troff/troff.d/dpost.d/color.c275
-rw-r--r--troff/troff.d/dpost.d/comments.h161
-rw-r--r--troff/troff.d/dpost.d/dpost.1258
-rw-r--r--troff/troff.d/dpost.d/dpost.c4836
-rw-r--r--troff/troff.d/dpost.d/dpost.h192
-rw-r--r--troff/troff.d/dpost.d/draw.c844
-rw-r--r--troff/troff.d/dpost.d/ext.h54
-rw-r--r--troff/troff.d/dpost.d/gen.h174
-rw-r--r--troff/troff.d/dpost.d/getopt.c222
-rw-r--r--troff/troff.d/dpost.d/glob.c56
-rw-r--r--troff/troff.d/dpost.d/makedev.c29
-rw-r--r--troff/troff.d/dpost.d/misc.c395
-rw-r--r--troff/troff.d/dpost.d/otf.c36
-rw-r--r--troff/troff.d/dpost.d/path.h61
-rw-r--r--troff/troff.d/dpost.d/pictures.c364
-rw-r--r--troff/troff.d/dpost.d/ps_include.c361
-rw-r--r--troff/troff.d/dpost.d/request.c182
-rw-r--r--troff/troff.d/dpost.d/request.h58
-rw-r--r--troff/troff.d/dpost.d/version.c3
24 files changed, 8807 insertions, 0 deletions
diff --git a/troff/troff.d/dpost.d/Makefile.mk b/troff/troff.d/dpost.d/Makefile.mk
new file mode 100644
index 000000000000..36847f46d999
--- /dev/null
+++ b/troff/troff.d/dpost.d/Makefile.mk
@@ -0,0 +1,42 @@
+BST = ../../../stuff/bst
+
+OBJ = dpost.o draw.o color.o pictures.o ps_include.o afm.o \
+ makedev.o glob.o misc.o request.o version.o getopt.o \
+ asciitype.o otf.o ../fontmap.o $(BST)/bst.o
+
+FLAGS = -I. -I.. -DFNTDIR='"$(FNTDIR)"' -DPSTDIR='"$(PSTDIR)"' $(EUC) \
+ $(DEFINES) -I../../../include -I.. -I$(BST)
+
+.c.o:
+ $(CC) $(CFLAGS) $(WARN) $(CPPFLAGS) $(FLAGS) -c $<
+
+all: dpost
+
+dpost: $(OBJ)
+ $(CC) $(CFLAGS) $(LDFLAGS) $(OBJ) $(LIBS) -o dpost
+
+install:
+ $(INSTALL) -c dpost $(ROOT)$(BINDIR)/dpost
+ $(STRIP) $(ROOT)$(BINDIR)/dpost
+ mkdir -p $(ROOT)$(MANDIR)/man1
+ $(INSTALL) -c -m 644 dpost.1 $(ROOT)$(MANDIR)/man1/dpost.1
+
+clean:
+ rm -f $(OBJ) dpost core log *~
+
+mrproper: clean
+
+color.o: color.c gen.h ext.h
+dpost.o: dpost.c comments.h gen.h path.h ext.h ../dev.h dpost.h ../afm.h \
+ asciitype.h
+draw.o: draw.c gen.h ext.h
+glob.o: glob.c gen.h
+misc.o: misc.c gen.h ext.h path.h asciitype.h
+pictures.o: pictures.c comments.h gen.h path.h
+ps_include.o: ps_include.c ext.h gen.h asciitype.h path.h
+request.o: request.c gen.h request.h path.h
+afm.o: afm.c ../dev.h ../afm.h ../afm.c
+otf.o: otf.c ../dev.h ../afm.h ../otf.c
+makedev.o: makedev.c ../dev.h ../makedev.c
+asciitype.o: asciitype.h
+version.o: version.c ../../version.c
diff --git a/troff/troff.d/dpost.d/README b/troff/troff.d/dpost.d/README
new file mode 100644
index 000000000000..a2ad48ed2f31
--- /dev/null
+++ b/troff/troff.d/dpost.d/README
@@ -0,0 +1,53 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License, Version 1.0 only
+# (the "License"). You may not use this file except in compliance
+# with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+Source code for a program that translates device independent troff output into
+PostScript.
+
+Several new text encoding schemes, based on widthshow, have been added. Each can
+be accessed using the -e option and often reduce print time by 20% or more. Level
+0 is the slowest but most stable choice. Level 2 encoding (which right now is the
+default) is fast and does a good job placing text and justifying the right margin.
+You can change the default encoding scheme by adjusting the definition of ENCODING
+in ../Makefile. Levels 0, 1, and 2 are the only reasonable defaults, but at present
+only level 0 is guaranteed. The new encoding schemes are not thoroughly tested,
+but passed the tests I ran.
+
+Other interesting features include color support, the ability to treat complex
+paths built from the standard drawing commands as single entities (eg. for filling
+a polygon with a color), and reverse video printing as a special case of color.
+Also added, although using it is far from trivial, is the ability to set text
+along an arbitrary baseline (see ../postscript/baseline.ps). All are accessed via
+special device control escapes (from routine devcntrl() in dpost.c).
+
+ASCII font and description files for many standard PostScript fonts can be found
+in ../font/devpost. They should be installed in /usr/lib/font/devpost, and are
+read when you add the -Tpost option to troff. A typical command line would be,
+
+ pic file | tbl | eqn | troff -mm -Tpost | dpost >file.ps
+
+while,
+
+ pic -T720 file | tbl | eqn -r720 | troff -mm -Tpost | dpost >file.ps
+
+should work if you're using old versions of eqn and pic.
+
diff --git a/troff/troff.d/dpost.d/afm.c b/troff/troff.d/dpost.d/afm.c
new file mode 100644
index 000000000000..260691c4d7d8
--- /dev/null
+++ b/troff/troff.d/dpost.d/afm.c
@@ -0,0 +1,32 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
+ *
+ * Sccsid @(#)afm.c 1.3 (gritter) 5/1/06
+ */
+
+#define DPOST
+#include "../afm.c"
+
+int NCHARS;
diff --git a/troff/troff.d/dpost.d/asciitype.c b/troff/troff.d/dpost.d/asciitype.c
new file mode 100644
index 000000000000..f7f3221730d4
--- /dev/null
+++ b/troff/troff.d/dpost.d/asciitype.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/* Sccsid @(#)asciitype.c 1.4 (gritter) 4/17/03 */
+
+#include "asciitype.h"
+
+const unsigned char class_char[] = {
+/* 000 nul 001 soh 002 stx 003 etx 004 eot 005 enq 006 ack 007 bel */
+ C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,
+/* 010 bs 011 ht 012 nl 013 vt 014 np 015 cr 016 so 017 si */
+ C_CNTRL,C_BLANK,C_WHITE,C_SPACE,C_SPACE,C_SPACE,C_CNTRL,C_CNTRL,
+/* 020 dle 021 dc1 022 dc2 023 dc3 024 dc4 025 nak 026 syn 027 etb */
+ C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,
+/* 030 can 031 em 032 sub 033 esc 034 fs 035 gs 036 rs 037 us */
+ C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,C_CNTRL,
+/* 040 sp 041 ! 042 " 043 # 044 $ 045 % 046 & 047 ' */
+ C_BLANK,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,
+/* 050 ( 051 ) 052 * 053 + 054 , 055 - 056 . 057 / */
+ C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,
+/* 060 0 061 1 062 2 063 3 064 4 065 5 066 6 067 7 */
+ C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,C_OCTAL,
+/* 070 8 071 9 072 : 073 ; 074 < 075 = 076 > 077 ? */
+ C_DIGIT,C_DIGIT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,
+/* 100 @ 101 A 102 B 103 C 104 D 105 E 106 F 107 G */
+ C_PUNCT,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,
+/* 110 H 111 I 112 J 113 K 114 L 115 M 116 N 117 O */
+ C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,
+/* 120 P 121 Q 122 R 123 S 124 T 125 U 126 V 127 W */
+ C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,C_UPPER,
+/* 130 X 131 Y 132 Z 133 [ 134 \ 135 ] 136 ^ 137 _ */
+ C_UPPER,C_UPPER,C_UPPER,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,
+/* 140 ` 141 a 142 b 143 c 144 d 145 e 146 f 147 g */
+ C_PUNCT,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,
+/* 150 h 151 i 152 j 153 k 154 l 155 m 156 n 157 o */
+ C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,
+/* 160 p 161 q 162 r 163 s 164 t 165 u 166 v 167 w */
+ C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,C_LOWER,
+/* 170 x 171 y 172 z 173 { 174 | 175 } 176 ~ 177 del */
+ C_LOWER,C_LOWER,C_LOWER,C_PUNCT,C_PUNCT,C_PUNCT,C_PUNCT,C_CNTRL
+};
diff --git a/troff/troff.d/dpost.d/asciitype.h b/troff/troff.d/dpost.d/asciitype.h
new file mode 100644
index 000000000000..5e0eef7f5c1e
--- /dev/null
+++ b/troff/troff.d/dpost.d/asciitype.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2003 Gunnar Ritter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute
+ * it freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ *
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ *
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+/* Sccsid @(#)asciitype.h 1.6 (gritter) 9/9/05 */
+
+/*
+ * Locale-independent character classes.
+ */
+enum {
+ C_CNTRL = 0000,
+ C_BLANK = 0001,
+ C_WHITE = 0002,
+ C_SPACE = 0004,
+ C_PUNCT = 0010,
+ C_OCTAL = 0020,
+ C_DIGIT = 0040,
+ C_UPPER = 0100,
+ C_LOWER = 0200
+};
+
+extern const unsigned char class_char[];
+
+#define asciichar(c) ((unsigned)(c) <= 0177)
+#define alnumchar(c) (asciichar(c)&&(class_char[c]&\
+ (C_DIGIT|C_OCTAL|C_UPPER|C_LOWER)))
+#define alphachar(c) (asciichar(c)&&(class_char[c]&(C_UPPER|C_LOWER)))
+#define blankchar(c) (asciichar(c)&&(class_char[c]&(C_BLANK)))
+#define cntrlchar(c) (asciichar(c)&&(class_char[c]==C_CNTRL)
+#define digitchar(c) (asciichar(c)&&(class_char[c]&(C_DIGIT|C_OCTAL)))
+#define lowerchar(c) (asciichar(c)&&(class_char[c]&(C_LOWER)))
+#define punctchar(c) (asciichar(c)&&(class_char[c]&(C_PUNCT)))
+#define spacechar(c) (asciichar(c)&&(class_char[c]&(C_BLANK|C_SPACE|C_WHITE)))
+#define upperchar(c) (asciichar(c)&&(class_char[c]&(C_UPPER)))
+#define whitechar(c) (asciichar(c)&&(class_char[c]&(C_BLANK|C_WHITE)))
+#define octalchar(c) (asciichar(c)&&(class_char[c]&(C_OCTAL)))
+#define graphchar(c) (asciichar(c)&&(class_char[c]&\
+ (C_UPPER|C_LOWER|C_DIGIT|C_OCTAL|C_PUNCT)))
+#define printchar(c) ((c)==' ' || (asciichar(c)&&(class_char[c]&\
+ (C_UPPER|C_LOWER|C_DIGIT|C_OCTAL|C_PUNCT))))
+
+#define upperconv(c) (lowerchar(c) ? (c)-'a'+'A' : (c))
+#define lowerconv(c) (upperchar(c) ? (c)-'A'+'a' : (c))
diff --git a/troff/troff.d/dpost.d/color.c b/troff/troff.d/dpost.d/color.c
new file mode 100644
index 000000000000..4568aec09177
--- /dev/null
+++ b/troff/troff.d/dpost.d/color.c
@@ -0,0 +1,275 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/* from OpenSolaris "color.c 1.5 05/06/08 SMI" SVr4.0 1.1 */
+
+/*
+ * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
+ *
+ * Sccsid @(#)color.c 1.5 (gritter) 11/29/05
+ */
+
+/*
+ *
+ * Routines that handle color requests passed through as device control commands
+ * in the form "x X SetColor:red". The following PostScript procedures are needed:
+ *
+ * _setcolor
+ *
+ * mark /color _setcolor mark
+ * mark /color1 /color2 _setcolor mark
+ *
+ * Called whenever we want to change PostScript's current color graphics
+ * state parameter. One or two color arguments can be given. In each case
+ * the colors are looked up in the PostScript colordict dictionary that's
+ * defined in *colorfile. Two named colors implies reverse video printing
+ * with the background given in /color2 and the text printed in /color1.
+ * Unknown colors are mapped into defaults - black for a single color and
+ * white on black for reverse video.
+ *
+ * drawrvbox
+ *
+ * leftx rightx drawrvbox -
+ *
+ * Fills a box that extends from leftx to rightx with the background color
+ * that was requested when _setcolor set things up for reverse video mode.
+ * The vertical extent of the box is determined using FontBBox just before
+ * the first string is printed, and the height remains in effect until
+ * there's an explicit color change. In otherwords font or size changes
+ * won't always produce correct result in reverse video mode.
+ *
+ * setdecoding
+ *
+ * num setdecoding -
+ *
+ * Selects the text decoding procedure (ie. what's assigned to PostScript
+ * procedure t) from the decodingdefs array defined in the prologue. num
+ * should be the value assigned to variable encoding (in dpost) and will
+ * remain constant throughout a job, unless special features, like reverse
+ * video printing, are requested. The text encoding scheme can be set on
+ * the command line using the -e option. Print time and the size of the
+ * output file will usually decrease as the value assigned to encoding
+ * increases.
+ *
+ *
+ * The recognized collection of "x X SetColor:" commands are:
+ *
+ * x X SetColor: selects black
+ * x X SetColor:color selects color
+ * x X SetColor:color1 on color2 reverse video
+ * x X SetColor:color1 color2 reverse video again
+ * x X SetColor:num1 num2 num3 rgb explicit rgb color request
+ * x X SetColor:num1 num2 num3 hsb explicit hsb color request
+ * x X SetColor:num1 num2 num3 num4 cmyk explicit cmyk color request
+ * x X SetColor:arbitrary PostScript commands
+ *
+ * In the last examples num1, num2, num3, and num4 should be numbers between 0 and
+ * 1 inclusive and are passed on as aguments to the approrpriate PostScript color
+ * command (eg. setrgbcolor). Unknown color names (ie. the ones that _setcolor
+ * doesn't find in colordict) are mapped into defaults. For one color the default
+ * is black, while for reverse video it's white text on a black background.
+ *
+ * dpost makes sure the current color is maintained across page boundaries, which
+ * may not be what you want if you're using a macro package like mm that puts out
+ * page footers and headers. Adding a color request to troff and keeping track of
+ * the color in each environment may be the best solution.
+ *
+ * To get reverse video printing follow the "x X SetColor:" command with two or
+ * three arguments. "x X SetColor:white on black" or "x X SetColor:white black"
+ * both produce white text on a black background. Any two colors named in colordict
+ * (in file *colorfile) can be chosen so "x X SetColor:yellow on blue" also works.
+ * Each reverse video mode request selects the vertical extent of the background
+ * box based on the font and size in use just before the first string is printed.
+ * Font and/or size changes aren't guaranteed to work properly in reverse video
+ * printing.
+ *
+ */
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "gen.h" /* general purpose definitions */
+#include "ext.h" /* external variable definitions */
+#include "global.h" /* global heirloom doctools definitions */
+
+#define DEFAULTCOLOR "black"
+
+static char color[500] = DEFAULTCOLOR; /* current color */
+static int gotcolor = FALSE; /* TRUE after *colorfile is downloaded */
+static int wantcolor = FALSE; /* TRUE if we really ask for a color */
+
+
+/*
+ *
+ * All these should be defined in dpost.c.
+ *
+ */
+
+
+extern int lastend;
+extern int encoding;
+extern int maxencoding;
+extern int realencoding;
+
+extern char *colorfile;
+extern FILE *tf;
+
+
+/*****************************************************************************/
+
+
+void
+getcolor(void)
+
+
+{
+
+
+/*
+ *
+ * Responsible for making sure the PostScript color procedures are downloaded from
+ * *colorfile. Done at most once per job, and only if the job really uses color.
+ * For now I've decided not to quit if we can't read the color file.
+ *
+ */
+
+
+ if ( gotcolor == FALSE && access(colorfile, 04) == 0 )
+ doglobal(colorfile);
+
+ if ( tf == stdout )
+ gotcolor = TRUE;
+
+} /* End of getcolor */
+
+
+/*****************************************************************************/
+
+
+void
+newcolor (
+ char *name /* of the color */
+)
+
+
+{
+
+
+ char *p; /* next character in *name */
+ int i; /* goes in color[i] */
+
+
+/*
+ *
+ * Converts *name to lower case and saves the result in color[] for use as the
+ * current color. The first time something other than DEFAULTCOLOR is requested
+ * sets wantcolor to TRUE. Characters are converted to lower case as they're put
+ * in color[] and we quit when we find a newline or get to the end of *name. The
+ * isupper() test is for Berkley systems.
+ *
+ */
+
+
+ for ( p = name; *p && (*p == ' ' || *p == ':'); p++ ) ;
+
+ for ( i = 0; i < sizeof(color) - 1 && *p != '\n' && *p; i++, p++ )
+ if ( isupper((int)*p) )
+ color[i] = tolower((int)*p);
+ else color[i] = *p;
+
+ if ( i == 0 )
+ n_strcpy(color, DEFAULTCOLOR, sizeof(color));
+ else color[i] = '\0';
+
+ if ( strcmp(color, DEFAULTCOLOR) != 0 )
+ wantcolor = TRUE;
+
+} /* End of newcolor */
+
+
+/*****************************************************************************/
+
+
+void
+setcolor(void)
+
+
+{
+
+
+ int newencoding; /* text encoding scheme that's needed */
+ char *p; /* for converting what's in color[] */
+
+
+/*
+ *
+ * Sets the color being used by the printer to whatever's stored as the current
+ * color (ie. the string in color[]). wantcolor is only set to TRUE if we've been
+ * through newcolor() and asked for something other than DEFAULTCOLOR (probably
+ * black). While in reverse video mode encoding gets set to maxencoding + 1 in
+ * dpost and 0 on the printer. Didn't see much point in trying to extend reverse
+ * video to all the different encoding schemes. realencoding is restored when we
+ * leave reverse video mode.
+ *
+ */
+
+
+ if ( wantcolor == TRUE ) {
+ endtext();
+ getcolor();
+
+ lastend = -1;
+ newencoding = realencoding;
+
+ if ( islower((int)color[0]) == 0 ) /* explicit rgb, hsb, or cmyk request */
+ fprintf(tf, "%s\n", color);
+ else {
+ putc('/', tf);
+ for ( p = color; *p && *p != ' '; p++ )
+ putc(*p, tf);
+ for ( ; *p && *p == ' '; p++ ) ;
+ if ( strncmp(p, "on ", 3) == 0 ) p += 3;
+ if ( *p != '\0' ) {
+ fprintf(tf, " /%s", p);
+ newencoding = maxencoding + 1;
+ } /* End if */
+ fprintf(tf, " _setcolor\n");
+ } /* End else */
+
+ if ( newencoding != encoding ) {
+ encoding = newencoding;
+ fprintf(tf, "%d setdecoding\n", encoding);
+ resetpos();
+ } /* End if */
+ } /* End if */
+
+} /* End of setcolor */
+
+
+/*****************************************************************************/
+
diff --git a/troff/troff.d/dpost.d/comments.h b/troff/troff.d/dpost.d/comments.h
new file mode 100644
index 000000000000..85482a030ce8
--- /dev/null
+++ b/troff/troff.d/dpost.d/comments.h
@@ -0,0 +1,161 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/* from OpenSolaris "comments.h 1.5 05/06/08 SMI" SVr4.0 1.1 */
+
+/*
+ * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
+ *
+ * Sccsid @(#)comments.h 1.5 (gritter) 8/23/05
+ */
+
+/*
+ *
+ * Currently defined file structuring comments from Adobe - plus a few others.
+ * Ones that end with a colon expect arguments, while those ending with a newline
+ * stand on their own. Truly overkill on Adobe's part and mine for including them
+ * all!
+ *
+ * All PostScript files should begin with a header that starts with one of the
+ * following comments.
+ *
+ */
+
+#define NONCONFORMING "%!PS\n"
+#define MINCONFORMING "%!PS-Adobe-\n"
+#define OLDCONFORMING "%!PS-Adobe-1.0\n"
+
+#define CONFORMING "%!PS-Adobe-3.0\n"
+#define CONFORMINGEPS "%!PS-Adobe-3.0 EPS\n"
+#define CONFORMINGQUERY "%!PS-Adobe-3.0 Query\n"
+#define CONFORMINGEXITSERVER "%!PS-Adobe-3.0 ExitServer\n"
+
+/*
+ *
+ * Header comments - immediately follow the appropriate document classification
+ * comment.
+ *
+ */
+
+#define TITLE "%%Title:"
+#define CREATOR "%%Creator:"
+#define CREATIONDATE "%%CreationDate:"
+#define FOR "%%For:"
+#define ROUTING "%%Routing:"
+#define BOUNDINGBOX "%%BoundingBox:"
+#define PAGES "%%Pages:"
+#define REQUIREMENTS "%%Requirements:"
+
+#define DOCUMENTFONTS "%%DocumentFonts:"
+#define DOCUMENTNEEDEDFONTS "%%DocumentNeededFonts:"
+#define DOCUMENTSUPPLIEDFONTS "%%DocumentSuppliedFonts:"
+#define DOCUMENTNEEDEDPROCSETS "%%DocumentNeededProcSets:"
+#define DOCUMENTSUPPLIEDPROCSETS "%%DocumentSuppliedProcSets:"
+#define DOCUMENTNEEDEDFILES "%%DocumentNeededFiles:"
+#define DOCUMENTSUPPLIEDFILES "%%DocumentSuppliedFiles:"
+#define DOCUMENTPAPERSIZES "%%DocumentPaperSizes:"
+#define DOCUMENTPAPERFORMS "%%DocumentPaperForms:"
+#define DOCUMENTPAPERCOLORS "%%DocumentPaperColors:"
+#define DOCUMENTPAPERWEIGHTS "%%DocumentPaperWeights:"
+#define DOCUMENTPRINTERREQUIRED "%%DocumentPrinterREquired:"
+#define ENDCOMMENTS "%%EndComments\n"
+#define ENDPROLOG "%%EndProlog\n"
+
+/*
+ *
+ * Body comments - can appear anywhere in a document.
+ *
+ */
+
+#define BEGINSETUP "%%BeginSetup\n"
+#define ENDSETUP "%%EndSetup\n"
+#define BEGINDOCUMENT "%%BeginDocument:"
+#define ENDDOCUMENT "%%EndDocument\n"
+#define BEGINFILE "%%BeginFile:"
+#define ENDFILE "%%EndFile\n"
+#define BEGINPROCSET "%%BeginProcSet:"
+#define ENDPROCSET "%%EndProcSet\n"
+#define BEGINBINARY "%%BeginBinary:"
+#define ENDBINARY "%%EndBinary\n"
+#define BEGINPAPERSIZE "%%BeginePaperSize:"
+#define ENDPAPERSIZE "%%EndPaperSize\n"
+#define BEGINFEATURE "%%BeginFeature:"
+#define ENDFEATURE "%%EndFeature\n"
+#define BEGINEXITSERVER "%%BeginExitServer:"
+#define ENDEXITSERVER "%%EndExitServer\n"
+#define TRAILER "%%Trailer\n"
+
+/*
+ *
+ * Page level comments - usually will occur once per page.
+ *
+ */
+
+#define PAGE "%%Page:"
+#define PAGEFONTS "%%PageFonts:"
+#define PAGEFILES "%%PageFiles:"
+#define PAGEBOUNDINGBOX "%%PageBoundingBox:"
+#define BEGINPAGESETUP "%%BeginPageSetup\n"
+#define BEGINOBJECT "%%BeginObject:"
+#define ENDOBJECT "%%EndObject\n"
+
+/*
+ *
+ * Resource requirements - again can appear anywhere in a document.
+ *
+ */
+
+#define INCLUDEFONT "%%IncludeFont:"
+#define INCLUDEPROCSET "%%IncludeProcSet:"
+#define INCLUDEFILE "%%IncludeFile:"
+#define EXECUTEFILE "%%ExecuteFile:"
+#define CHANGEFONT "%%ChangeFont:"
+#define PAPERFORM "%%PaparForm:"
+#define PAPERCOLOR "%%PaperColor:"
+#define PAPERWEIGHT "%%PaperWeight:"
+#define PAPERSIZE "%%PaperSize:"
+#define FEATURE "%%Feature:"
+#define ENDOFFILE "%%EOF\n"
+
+#define CONTINUECOMMENT "%%+"
+#define ATEND "(atend)"
+
+/*
+ *
+ * Some non-standard document comments. Global definitions are occasionally used
+ * in dpost and are marked by BEGINGLOBAL and ENDGLOBAL. The resulting document
+ * violates page independence, but can easily be converted to a conforming file
+ * using a utililty program.
+ *
+ */
+
+#define BEGINSCRIPT "%%BeginScript\n"
+#define BEGINGLOBAL "%%BeginGlobal\n"
+#define ENDGLOBAL "%%EndGlobal\n"
+#define ENDPAGE "%%EndPage:"
+#define FORMSPERPAGE "%%FormsPerPage:"
+#define CREATOR "%%Creator:"
+#define CREATIONDATE "%%CreationDate:"
+
diff --git a/troff/troff.d/dpost.d/dpost.1 b/troff/troff.d/dpost.d/dpost.1
new file mode 100644
index 000000000000..7a935f823d03
--- /dev/null
+++ b/troff/troff.d/dpost.d/dpost.1
@@ -0,0 +1,258 @@
+.\"
+.\" CDDL HEADER START
+.\"
+.\" The contents of this file are subject to the terms of the
+.\" Common Development and Distribution License (the "License").
+.\" You may not use this file except in compliance with the License.
+.\"
+.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+.\" or http://www.opensolaris.org/os/licensing.
+.\" See the License for the specific language governing permissions
+.\" and limitations under the License.
+.\"
+.\" When distributing Covered Code, include this CDDL HEADER in each
+.\" file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+.\" If applicable, add the following below this CDDL HEADER, with the
+.\" fields enclosed by brackets "[]" replaced with your own identifying
+.\" information: Portions Copyright [yyyy] [name of copyright owner]
+.\"
+.\" CDDL HEADER END
+.\" Copyright 1989 AT&T Copyright (c) 1996 Sun Microsystems, Inc. All Rights Reserved.
+.\"
+.\" Portions Copyright (c) 2007 Gunnar Ritter, Freiburg i. Br., Germany
+.\"
+.\" Sccsid @(#)dpost.1 1.11 (gritter) 2/7/07
+.\"
+.\" from OpenSolaris dpost 1 "9 Sep 1996" "SunOS 5.11" "User Commands"
+.TH DPOST 1 "2/7/07" "Heirloom Documentation Tools" "User Commands"
+.SH NAME
+dpost \- troff postprocessor for PostScript printers
+.SH SYNOPSIS
+.HP
+.ad l
+.nh
+\fBdpost\fR
+[\fB\-c\fR\ \fInum\fR]
+[\fB\-e\fR\ \fInum\fR]
+[\fB\-m\fR\ \fInum\fR]
+[\fB\-n\fR\ \fInum\fR]
+[\fB\-o\fR\ \fIlist\fR]
+[\fB\-p\fR\ \fImode\fR]
+[\fB\-w\fR\ \fInum\fR]
+[\fB\-x\fR\ \fInum\fR]
+[\fB\-y\fR\ \fInum\fR]
+[\fB\-F\fR\ \fIdir\fR]
+[\fB\-H\fR\ \fIdir\fR]
+[\fB\-L\fR\ \fIfile\fR]
+[\fB\-M\fR\ \fImarks\fR]
+[\fB\-O\fR]
+[\fB\-T\fR \fIname\fR]
+[\fIfile\fR] .\|.\|.
+.br
+.ad b
+.hy 1
+.SH DESCRIPTION
+\fIdpost\fR translates \fIfiles\fR created by
+\fItroff\fR(1)
+into PostScript and writes the results on the standard output.
+If no
+\fIfiles\fR are specified, or if \- is one of the input \fIfiles\fR,
+the standard input
+is read.
+The following options are accepted:
+.TP 15
+\fB\-c\fR\fI num\fR
+Print \fInum\fR copies of each page.
+By default
+only one copy is printed.
+.TP
+\fB\-e\fR\fI num\fR
+Sets the text encoding level to \fInum\fR.
+The recognized choices are
+digits between 0 and 5.
+\fB0\fR uses the PostScript \fBashow\fR operator, and produces
+output essentially identical to previous versions of \fIdpost\fR.
+\fB1\fR also uses \fBashow\fR but integrates motion commands
+with text commands.
+\fB2\fR uses the PostScript \fBawidthshow\fR operator,
+computing space widths in PostScript.
+\fB3\fR also uses \fBawidthshow\fR
+but computes space widths in \fIdpost\fR.
+\fB4\fR uses \fBashow\fR, storing position as differences.
+\fB5\fR emits the same commands as 4
+but in a binary PostScript Level 2 representation.
+The default is 3 with the \fBps\fR device.
+.TP
+\fB\-m\fR\fI num\fR
+Magnify each logical page by the factor \fInum\fR.
+Pages are scaled
+uniformly about the origin,
+which is located near the upper left corner of each page.
+The default
+magnification is \fB1.0\fR.
+.TP
+\fB\-n\fR\fI num\fR
+Print \fInum\fR logical pages on each piece of paper, where \fInum\fR
+can be any positive integer.
+By default, \fInum\fR is set to \fB1\fR.
+.TP
+\fB\-o\fR\fI list\fR
+Print those pages for which numbers are given in the comma-separated
+\fIlist\fR.
+The list
+contains single numbers \fIN\fR and ranges \fIN1\fR\fB\(mi\fR\fIN2.\fR
+A missing \fIN1\fR means the lowest
+numbered page, a missing \fIN2\fR means the highest.
+The page range is
+an expression of logical pages rather than physical sheets of paper.
+For example, if you are printing two logical
+pages to a sheet, and you specified a range of \fB4\fR, then two sheets
+of paper would print, containing four page layouts.
+If you specified a
+page range of \fB3-4\fR, when requesting
+two logical pages to a sheet; then \fIonly\fR page 3 and page 4 layouts
+would print, and they would appear on one physical sheet of paper.
+.TP
+\fB\-p\fR\fI mode\fR
+Print \fIfiles\fR in either \fBportrait\fR or \fBlandscape\fR \fImode\fR.
+Only
+the first character of \fImode\fR is significant.
+The default
+\fImode\fR is portrait.
+.TP
+\fB\-w\fR\fI num\fR
+Set the line width used to implement \fItroff\fR graphics commands to
+\fInum\fR
+points, where a point is approximately 1/72 of an inch.
+By default,
+\fInum\fR is set to \fB0.3\fR points.
+.TP
+\fB\-x\fR\fI num\fR
+Translate the origin \fInum\fR inches along the positive x axis.
+The
+default coordinate system
+has the origin fixed near the upper left corner of the page, with
+positive x to the right and positive y down the page.
+Positive
+\fInum\fR moves everything right.
+The default offset
+is \fB0\fR inches.
+.TP
+\fB\-y\fR\fI num\fR
+Translate the origin \fInum\fR inches along the positive y axis.
+Positive \fInum\fR moves text up the page.
+The default offset is
+\fB0\fR.
+.TP
+\fB\-F\fR\fI dir\fR
+Use \fIdir\fR as the font directory.
+The default \fIdir\fR is
+\fB/usr/ucblib/doctools/font\fR, and \fIdpost\fR reads binary font files from
+directory \fB/usr/ucblib/doctools/font/devps\fR.
+.TP
+\fB\-H\fR\fI dir\fR
+Use \fIdir\fR as the host resident font directory.
+Files in this
+directory should be complete
+PostScript font descriptions, and must be assigned a name that
+corresponds to the appropriate two-character \fItroff\fR font name.
+Each font file is copied to the output file only when needed
+and at most once during each job.
+There is no default directory.
+.TP
+\fB\-L\fR\fI file\fR
+Use \fIfile\fR as the PostScript prologue which, by default, is
+\fB/usr/lib/lp/postscript/dpost.ps\fR.
+.TP
+\fB\-M \fImarks\fR
+Print marks (in combination with the \fB\%trimat\fR \fItroff\fR request).
+Valid types of \fImarks\fR are:
+\fB\%cutmarks\fR,
+\fB\%registrationmarks\fR,
+\fB\%startargets\fR,
+\fB\%colorbars\fR,
+and
+\fB\%all\fR.
+Mark names can be abbreviated and combined by colons,
+e.g. \fB\-Mcut:reg\fR will print cut marks and registration marks.
+.TP
+\fB\-O\fR
+Disables PostScript picture inclusion.
+A recommended option when
+\fIdpost\fR is run by a spooler in a networked environment.
+.TP
+\fB\-T\fR\fI name\fR
+Use font files for device \fIname\fR as the best description of
+available PostScript fonts.
+By default, \fIname\fR is set to \fBps\fR and \fIdpost\fR reads
+files from \fB/usr/ucblib/doctools/font/devps\fR.
+.PP
+The \fIfiles\fR should be prepared by \fItroff\fR.
+The default font
+files in \fB/usr/ucblib/doctools/font/devps\fR produce the best output.
+They assume a resolution of 72000 dpi, and can be used to format files by
+adding the \fB\-Tps\fR option to the \fItroff\fR call.
+.PP
+\fIdpost\fR makes no assumptions about resolutions.
+The first
+\fBx\ res\fR command sets the resolution used to translate the input
+\fIfiles\fR, the \fBDESC\fR file, usually
+\fB/usr/ucblib/doctools/font/devps/DESC\fR,
+defines the resolution used in
+the binary font files, and the PostScript prologue is responsible for
+setting up an appropriate
+user coordinate system.
+.SH EXAMPLES
+.HP
+\fBpic \fR\fBfile\fR\fB | tbl | eqn | troff \fR\fB\-mm\fR\fB
+\fR\fB\-Tps\fR\fB | dpost\fR
+.SH FILES
+/usr/ucblib/doctools/font/devps/*
+.br
+/usr/ucblib/doctools/font/devpost/charlib/*
+.br
+/usr/ucblib/doctools/font/devpost/postscript/dpost.ps
+.br
+/usr/ucblib/doctools/font/devpost/postscript/color.ps
+.br
+/usr/ucblib/doctools/font/devpost/postscript/cutmarks.ps
+.br
+/usr/ucblib/doctools/font/devpost/postscript/draw.ps
+.br
+/usr/ucblib/doctools/font/devpost/postscript/forms.ps
+.br
+/usr/ucblib/doctools/font/devpost/postscript/ps.requests
+.br
+/usr/ucblib/doctools/tmac/pictures
+.br
+/usr/ucblib/doctools/tmac/color
+.SH SEE ALSO
+troff(1)
+.SH DIAGNOSTICS
+The following exit values are returned:
+.TP 10
+\fB\fB0\fR\fR
+Successful completion.
+.TP
+\fBnon-zero\fR
+An error occurred.
+.SH NOTES
+Although \fIdpost\fR can handle files formatted for any device,
+emulation is expensive and can easily double the print time and the
+size of the output file.
+No attempt has been made to
+implement the character sets or fonts available on all devices
+supported by \fItroff\fR.
+Missing characters will be replaced by white
+space, and unrecognized fonts will usually default to one
+of the Times fonts (that is, \fBR\fR, \fBI\fR, \fBB\fR, or \fBBI\fR).
+.PP
+An \fBx res\fR command must precede the first \fBx init\fR command,
+and all the input \fIfiles\fR should have been prepared for the same
+output device.
+.PP
+Use of the \fB\-T\fR option is not encouraged.
+Its only purpose is to
+enable the use of other PostScript font and device description files,
+that perhaps use different resolutions, character
+sets, or fonts.
diff --git a/troff/troff.d/dpost.d/dpost.c b/troff/troff.d/dpost.d/dpost.c
new file mode 100644
index 000000000000..f27d33cbd4f8
--- /dev/null
+++ b/troff/troff.d/dpost.d/dpost.c
@@ -0,0 +1,4836 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1994 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/* from OpenSolaris "dpost.c 1.11 05/06/08 SMI" SVr4.0 1.2 */
+
+/*
+ * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
+ *
+ * Sccsid @(#)dpost.c 1.176 (gritter) 8/19/08
+ */
+
+/*
+ *
+ * dpost - troff post-processor for PostScript printers.
+ *
+ * A program that translates output generated by the device independent troff
+ * into PostScript. Much was borrowed from dimpress and dps (formally dlzw),
+ * and even though the code has been changed, credit has to be given to Richard
+ * Flood for his early work on the PostScript driver.
+ *
+ * Among the most interesting new features are color support (see devcntrl() and
+ * file color.c) and code to handle complex paths pieced together using any of the
+ * standard drawing commands (see devcntrl() and file draw.c). Reverse video mode
+ * has also been included as a special case of the color support. Two encoding
+ * schemes based on widthshow are also new additions. The safe one is obtained when
+ * you set encoding to 2 (eg. using the -e2 option). The slightly faster method
+ * is obtained by setting encoding to 3 (eg. using the -e3 option), although it's
+ * not recommended. Rounding errors in character widths can accumulate and become
+ * quite noticeable by the time you get to the right margin. More often than not
+ * you end up getting a ragged right margin.
+ *
+ * The program handles files formatted for any device, although the best and
+ * most efficient output is generated when the font and description files match
+ * PostScript's resident fonts. Device emulation is relatively expensive, and
+ * can produce output files that are more than twice the size of the input files.
+ * In most cases output files will be smaller than input files, perhaps by up to
+ * 40 percent, although the results you get depend on what you're doing and the
+ * text encoding you're using. You'll get the worst results if you're emulating
+ * another device, using special bitmap characters, like the logo, or doing lots
+ * of vertical motion or drawing.
+ *
+ * PostScript fonts don't support all of troff's characters, so some have to
+ * be built by special PostScript procedures. Those routines can be found in
+ * *fontdir/devpost/charlib, and are only used when we try to print a character
+ * that has been assigned a code less than 32. Definitions are only made the
+ * first time each character is used. Subsequent requests to print the character
+ * only generate a call to the PostScript procedure that's been copied to the
+ * output file. For example you'll find a file called sq in directory
+ * *fontdir/devpost/charlib. It defines a PostScript procedure called build_sq
+ * that's called whenever we need to print a square. Special characters that
+ * have been assigned a code of 2 are expected to come in two pieces. The
+ * definition part and bitmap part (or whatever). The definition is only made
+ * once, but the contents of the character's .map file are copied to the output
+ * file each time, immediately after charlib() generates the call to the
+ * PostScript procedure (build_?? ) that builds the character. That's typically
+ * how logos built from bitmaps would be handled.
+ *
+ * Several different methods can be used to encode lines of text. What's done
+ * depends on the value assigned to encoding. Print time should decrease as
+ * encoding increases (up to MAXENCODING). Setting encoding to 0, which should
+ * probably be the default, produces output essentially identical to the original
+ * version of dpost. It's the slowest but most stable method of encoding lines of
+ * text, and won't be bothered by rounding errors in the font width tables that
+ * could become noticeable by the time you get to the end of a line. Other schemes
+ * seem to work, but aren't well tested and are not guaranteed for all possible
+ * jobs. encoding can be changed on the command line using the -e option. Part of
+ * the support for different encoding schemes was to move control of all text
+ * related output to separate routines. It makes dpost work harder, but changing
+ * things is easy. For example adding stuff to support widthshow took less than
+ * an hour.
+ *
+ * I've also added code that handles the DOCUMENTFONTS comment, although it's
+ * only produced for those fonts in directory /usr/lib/font/devpost that have an
+ * associated .name file. The first string in a .name file should be the (long)
+ * PostScript name (eg. Times-Roman in R.name). For now everything else in the
+ * .name file is ignored, although that may also change. You'll find .name files
+ * for all the supported fonts in the devpost source directory, although they may
+ * not be installed in /usr/lib/font/devpost.
+ *
+ * The PostScript prologue is copied from *prologue before any of the input files
+ * are translated. The program expects the following procedures are avaliable:
+ *
+ * setup
+ *
+ * mark ... setup -
+ *
+ * Handles special initialization stuff that depends on how the program
+ * was called. Expects to find a mark followed by key/value pairs on the
+ * stack. The def operator is applied to each pair up to the mark, then
+ * the default state is set up. An 'x res' command must preceed the
+ * 'x init' command!
+ *
+ * pagesetup
+ *
+ * page pagesetup -
+ *
+ * Called at the start of each page, immediately after the page level
+ * save, to do special initialization on a per page basis. Right now the
+ * only argument is the current page number, and actually nothing of any
+ * importance is currently done.
+ *
+ * setdecoding
+ *
+ * num setdecoding -
+ *
+ * Selects the text decoding procedure (ie. what's assigned to PostScript
+ * procedure t) from the decodingdefs array defined in the prologue. num
+ * should be the value assigned to variable encoding (in dpost) and will
+ * remain constant throughout a job, unless special features, like reverse
+ * video printing, are requested. The text encoding scheme can be set on
+ * the command line using the -e option. Print time and the size of the
+ * output file will usually decrease as the value assigned to encoding
+ * increases.
+ *
+ * f
+ *
+ * size font f -
+ *
+ * Selects the size and font to be used for character imaging. Font names
+ * are defined, in *prologue, so they agree with the one or two character
+ * names used by troff.
+ *
+ * m
+ *
+ * x y m -
+ *
+ * Moves to point (x, y). Normally only used when the vertical position
+ * changes. Horizontal positioning between words (or letters) is handled
+ * in procedure t (below).
+ *
+ * t
+ *
+ * mark text t mark
+ *
+ * Processes everything on the stack, up to the mark, as a single line
+ * of text to be printed at a fixed vertical position. What's put out as
+ * text depends on the encoding scheme. Setting encoding to 0 produces
+ * output essentially identical to the original version of dpost. In that
+ * case everything on the stack, up to a mark, is interpreted (from top
+ * down) as an absolute horizontal position and a string to be printed at
+ * that point. For example the stack might look like,
+ *
+ * mark(this)1000(is)1100(an)1200(example)1300 t
+ *
+ * Procedure t would go through the stack, up to the mark, adjusting the
+ * horizontal position before printing each string. In other encoding
+ * schemes, like the one based on widthshow, strings containing several
+ * space separated words would appear on the stack, and each one would be
+ * preceeded by a number that's expected to be added to the width of a
+ * space. For example we might have,
+ *
+ * mark(an example)30(this is)40 2 1000 2000 t
+ *
+ * where (1000, 2000) is where the first string starts and 2 is the repeat
+ * count (ie. number of string and space pairs on the stack).
+ *
+ * w
+ *
+ * string x y w -
+ *
+ * Prints a single word starting at position (x, y). Only used in the more
+ * complicated encoding schemes (eg. the ones based on widthshow).
+ *
+ * done
+ *
+ * Makes sure the last page is printed. Only needed when we're printing
+ * more than one page on each sheet of paper.
+ *
+ * The PostScript procedures that support troff's drawing commands have been moved
+ * out of *prologue and put in a separate file (ie. DRAW as defined in path.h).
+ * The procedures are used by the routines in file draw.c, and are copied to the
+ * prologue.
+ *
+ * Many default values, like the magnification and orientation, are defined in
+ * the prologue, which is where they belong. If they're changed (by options), an
+ * appropriate definition is made after the prologue is added to the output file.
+ * The -P option passes arbitrary PostScript through to the output file. Among
+ * other things it can be used to set (or change) values that can't be accessed by
+ * other options.
+ *
+ *
+ * output language from troff:
+ * all numbers are character strings
+ *
+ * sn size in points
+ * fn font as number from 1-n
+ * cx ascii character x
+ * Cxyz funny char xyz. terminated by white space
+ * Hn go to absolute horizontal position n
+ * Vn go to absolute vertical position n (down is positive)
+ * hn go n units horizontally (relative)
+ * vn ditto vertically
+ * nnc move right nn, then print c (exactly 2 digits!)
+ * (this wart is an optimization that shrinks output file size
+ * about 35% and run-time about 15% while preserving ascii-ness)
+ * Dt ...\n draw operation 't':
+ * Dl x y line from here by x,y
+ * Dc d circle of diameter d with left side here
+ * De x y ellipse of axes x,y with left side here
+ * Da x1 y1 x2 y2 arc counter-clockwise from current point (x, y) to
+ * (x + x1 + x2, y + y1 + y2)
+ * D~ x y x y ... wiggly line by x,y then x,y ...
+ * nb a end of line (information only -- no action needed)
+ * b = space before line, a = after
+ * p new page begins -- set v to 0
+ * #...\n comment
+ * x ...\n device control functions:
+ * x i init
+ * x T s name of device is s
+ * x r n h v resolution is n/inch
+ * h = min horizontal motion, v = min vert
+ * x p pause (can restart)
+ * x s stop -- done forever
+ * x t generate trailer
+ * x f n s font position n contains font s
+ * x H n set character height to n
+ * x S n set slant to N
+ *
+ * Subcommands like "i" are often spelled out like "init".
+ *
+ *
+ *
+ * To get dpost output conforming to Adobe's structuring conventions (DSC),
+ * all output is accumulated in temporary files first. When the document is
+ * completed, files that contain global data are output first, followed by
+ * regular commands, all surrounded by DSC comments. Speed problems, which
+ * were the reason why this was not done by previous versions of dpost, are
+ * no longer of concern in 2005 since several hundred pages of text are
+ * processed now in less than a second.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <math.h>
+#include <ctype.h>
+#include <time.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdarg.h>
+
+#include "comments.h" /* PostScript file structuring comments */
+#include "gen.h" /* general purpose definitions */
+#include "path.h" /* for the prologue and a few other files */
+#include "ext.h" /* external variable definitions */
+#include "dev.h" /* typesetter and font descriptions */
+#include "dpost.h" /* a few definitions just used here */
+#include "asciitype.h"
+#include "afm.h"
+#include "fontmap.h"
+
+
+#if defined (__GLIBC__) && defined (_IO_getc_unlocked)
+#undef getc
+#define getc(f) _IO_getc_unlocked(f)
+#endif
+#if defined (__GLIBC__) && defined (_IO_putc_unlocked)
+#undef putc
+#define putc(c, f) _IO_putc_unlocked(c, f)
+#endif
+
+
+char *progname;
+char *prologue = DPOST; /* the basic PostScript prologue */
+char *colorfile = COLOR; /* things needed for color support */
+char *drawfile = DRAW; /* and drawing */
+char *cutmarksfile = CUTMARKS;
+char *formfile = FORMFILE; /* stuff for multiple pages per sheet */
+char *baselinefile = BASELINE;
+
+char *fontdir = FONTDIR; /* binary device directories found here */
+char *hostfontdir = NULL; /* host resident font directory */
+
+int formsperpage = 1; /* page images on each piece of paper */
+int copies = 1; /* and this many copies of each sheet */
+int picflag = ON; /* enable/disable picture inclusion */
+
+
+/*
+ *
+ * encoding selects the encoding scheme used to output lines of text. Change it
+ * to something other than 0 at your own risk. The other methods seem to work but
+ * aren't well tested and are not guaranteed. Some special features, like reverse
+ * video, may temporarily change the encoding scheme and reset it to realencoding
+ * when done.
+ *
+ * Encoding 4 is new as of 9/8/05. It stores only the distances between words and
+ * thus saves a bit of output size. It is automatically enabled at high resolutions.
+ *
+ */
+
+
+int encoding = DFLTENCODING;
+int realencoding = DFLTENCODING;
+int maxencoding = MAXENCODING;
+int eflag;
+
+int LanguageLevel; /* PostScript output language level */
+static int Binary; /* PostScript output contains binary data */
+
+/*
+ *
+ * seenfonts[] keeps track of the fonts we've used, based on internal numbers. It
+ * helps manage host resident fonts and the DOCUMENTFONTS comment, but only works
+ * if all fonts have internal numbers less than MAXINTERNAL. *docfonts counts the
+ * number of font names we've recorded in *temp_file. If it's positive routine
+ * done() adds *temp_file to the output file before quitting.
+ *
+ */
+
+
+char seenfonts[MAXINTERNAL+1];
+int docfonts = 0;
+struct afmtab **afmfonts;
+int afmcount = 0;
+
+/*
+ *
+ * devname[] is the device troff used when the job was formatted, while *realdev
+ * is combined with *fontdir and used to locate the font and device tables that
+ * that control the translation of the input files into PostScript. *realdev can
+ * be changed using the -T option, but if you do you may end up getting garbage.
+ * The character code field must agree with PostScript's font encoding and font
+ * names must be properly mapped into PostScript font names in the prologue.
+ *
+ */
+
+
+#define devname troff_devname
+char devname[20] = ""; /* job is formatted for this printer */
+char *realdev = DEVNAME; /* a good description of target printer */
+
+
+/*
+ *
+ * Standard things that come from binary font and description files for *realdev.
+ * Most are initialized in fontinit() or loadfont().
+ *
+ */
+
+
+struct dev dev; /* DESC starts this way */
+struct Font **fontbase; /* FONT files begin this way */
+int *pstab; /* list of available sizes */
+int nsizes = 1; /* and the number of sizes in that list */
+int smnt; /* index of first special font */
+int nchtab; /* number of special character names */
+int fsize; /* max size of a font files in bytes */
+int unitwidth; /* set to dev.unitwidth */
+char *chname; /* special character strings */
+short *chtab; /* used to locate character names */
+unsigned short **fitab; /* locates char info on each font */
+int **fontab; /* character width data for each font */
+unsigned short **codetab; /* and codes to get characters printed */
+char **kerntab; /* for makefont() */
+
+
+/*
+ *
+ * Special characters missing from standard PostScript fonts are defined by files
+ * in directory *fontdir/devpost/charlib. Files have the same names as the troff
+ * special character names (for now at least) and each one defines a PostScript
+ * procedure that begins with the prefix build_ and ends with the character's
+ * name.
+ *
+ * For example, the routine used to build character \(12, would be build_12.
+ * downloaded[] points to an array, allocated in fontinit(), that keeps track of
+ * the characters that have already been defined - so we only do it once.
+ *
+ */
+
+
+char *downloaded; /* nonzero means it's been downloaded */
+
+
+/*
+ *
+ * Variables that keep track of troff's requests. All are set from values in the
+ * input files. nfonts is adjusted in t_fp() as new fonts are mounted.
+ *
+ */
+
+
+int nfonts = 0; /* number of font positions */
+int size = 1; /* current size - internal value */
+#define FRACTSIZE -23 /* if size == FRACTSIZE then ... */
+float fractsize = 0; /* fractional point size */
+int font = 0; /* font position we're using now */
+int subfont = 0; /* extra encoding vector */
+int hpos = 0; /* where troff wants to be - horizontally */
+int vpos = 0; /* same but vertically */
+float lastw = 0; /* width of the last input character */
+int track = 0; /* tracking hint from troff */
+int lasttrack = 0; /* previous tracking hint */
+int tracked; /* records need to flush track */
+int lastc = 0; /* and its name (or index) */
+
+int res; /* resolution assumed in input file */
+float widthfac = 1.0; /* for emulation = res/dev.res */
+float horscale = 1.0; /* horizontal font scaling */
+float lasthorscale = 1.0; /* last horizontal font scaling */
+int wordspace = 0; /* w command was last */
+
+
+/*
+ *
+ * Remember some of the same things, but this time for the printer. lastend is only
+ * used when we're doing reverse video, and is where the last character on the
+ * current line was printed.
+ *
+ */
+
+
+int lastsize = -1; /* last internal size we used */
+float lastfractsize = -1; /* last fractional size */
+int lastfont = -1; /* last font we told printer about */
+int lastsubfont = -1; /* last extra encoding vector */
+float lastx = -1; /* printer's current position */
+int lasty = -1;
+int savey = -1;
+int lastend; /* where last character on this line was */
+
+
+/*
+ *
+ * fontname[] keeps track of the mounted fonts. Filled in (by t_fp()) from data
+ * in the binary font files.
+ *
+ * When font metrics are directly read from AFM files, all characters that
+ * are not ASCII are put into the remaining positions in PostScript encoding
+ * vectors. Their position in these vectors in recorded in afm->encmap, and
+ * characters from troff are translated if necessary.
+ *
+ */
+
+
+struct {
+
+ struct afmtab *afm; /* AFM data, if any */
+ char *name; /* name of the font loaded here */
+ int number; /* its internal number */
+ float fontheight; /* points from x H ... */
+ int fontslant; /* angle from x S ... */
+
+
+} fontname[NFONT+1];
+
+
+/*
+ *
+ * All the special fonts will be mounted after the last legitimate font position.
+ * It helps when we're translating files prepared for devices, like the 202, that
+ * have a different set of special fonts. The set of special fonts needed when
+ * *realdev's tables are used may not get mounted when we're emulating another
+ * device. gotspecial keeps track of whether we've done it yet. seenpage is set
+ * to TRUE after we've seen the first page command in the input file. It controls
+ * what's done in t_font() and is needed because nfonts is no longer set when the
+ * DESC file is read, but rather is updated from "x font" commands in the
+ * input files. gotregular ensures that at least one regular font is mounted.
+ *
+ */
+
+
+int gotspecial = FALSE;
+int gotregular = FALSE;
+int seenpage = FALSE;
+
+
+/*
+ *
+ * The amount of horizontal positioning error we accept controls both the size
+ * of the output file and the appearance of the printed text. It's probably most
+ * important when we're emulating other devices, like the APS-5. The error can be
+ * set using the -S option. It's converted from points to machine units in t_init()
+ * after the resolution is known. rvslop is also set in t_init() and only used to
+ * adjust the width of the box that's drawn around text when we're printing in
+ * reverse video mode.
+ *
+ */
+
+
+float pointslop = SLOP; /* horizontal error in points */
+int Sflag; /* unless -S gives explicit slop */
+int slop; /* and machine units */
+int rvslop; /* to extend box in reverse video mode */
+
+
+/*
+ *
+ * Characters are accumulated and saved in PostScript strings that are eventually
+ * processed by making a single call to procedure t. textcount counts the number
+ * of individual strings collected but not yet processed, and is primarily used to
+ * make sure PostScript's stack doesn't get too big. When textcount is positive
+ * we've started accumulating strings and need to generate a call to PostScript
+ * procedure t to process the text before anything else (like a font change) is
+ * done.
+ *
+ */
+
+
+int textcount = 0; /* strings accumulated so far */
+int stringstart = 0; /* where the next one starts */
+int laststrstart = INT_MIN; /* save for optimization */
+int spacecount = 0; /* spaces seen so far on current line */
+int charcount = 0; /* characters on current line */
+
+
+/*
+ *
+ * Things that can be used by text line encoding schemes that need to read and
+ * remember an entire line before doing any output. The strings that make up the
+ * line can be saved in array strings[] and accessed by fields in line[]. *strptr
+ * points to the next free slot in strings[].
+ *
+ */
+
+
+char strings[STRINGSPACE];
+char *strptr;
+Line line[MAXSTACK+3];
+
+
+/*
+ *
+ * When we're emulating another device we may want to map font name requests that
+ * come in as "x font pos name" commands into some other font name before anything
+ * else is done (ie. calling loadfont()). Font names can collide or we may just
+ * want to a mapping that depends on the device troff used to format the input
+ * files. devfontmap points to a structure that's filled in by getdevmap() if the
+ * mapping file /usr/lib/font/dev*realdev/fontmaps/devname exists. mapdevfont()
+ * then uses that table to translate font name requests into something else before
+ * loadfont() gets called.
+ *
+ * fontmap[] provides a simple minded translation that maps an unrecognized font
+ * name (in loadfont()) into another font name that we know will be available. It
+ * doesn't provide the fine control available with *devfontmap, but should be good
+ * enough for most jobs. Both structures are only needed when emulating another
+ * device using *realdev's font tables.
+ *
+ */
+
+
+Devfontmap *devfontmap = NULL; /* device level */
+Fontmap fontmap[] = FONTMAP; /* and general mapping tables - emulation */
+
+
+/*
+ *
+ * Variables and functions for the pdfmark operator.
+ *
+ */
+static char *Author; /* DOCINFO /Author */
+static char *Title; /* DOCINFO /Title */
+static char *Subject; /* DOCINFO /Subject */
+static char *Keywords; /* DOCINFO /Keywords */
+static struct Bookmark {
+ char *Title; /* OUT /Title */
+ char *title; /* unencoded title */
+ int Count; /* OUT /Count */
+ int level; /* used to generate count */
+ int closed; /* the bookmark is closed initially */
+} *Bookmarks;
+static size_t nBookmarks;
+static double pagelength = 792; /* lenght of page in points */
+#define MAXBOOKMARKLEVEL 20
+
+static void orderbookmarks(void);
+
+static struct box {
+ int val[4];
+ int flag;
+} mediasize, bleedat, trimat, cropat;
+
+/*
+ *
+ * For the -M option.
+ *
+ */
+
+static enum {
+ M_NONE = 000,
+ M_CUT = 001,
+ M_STAR = 002,
+ M_REG = 004,
+ M_COL = 010,
+ M_ALL = 077
+} Mflag;
+
+static void setmarks(char *);
+
+
+/*
+ *
+ * A few variables that are really only used if we're doing accounting. Designed
+ * for our use at Murray Hill and probably won't suit your needs. Changes should
+ * be easy and can be made in routine account().
+ *
+ */
+
+
+int printed = 0; /* charge for this many pages */
+
+
+/*
+ *
+ * Output and accounting file definitions. The PostScript output always goes to
+ * stdout or /dev/null, while the accounting file can be selected using the -A
+ * option.
+ *
+ */
+
+
+FILE *tf = NULL; /* PostScript output goes here */
+FILE *gf = NULL; /* global data goes here */
+FILE *rf = NULL; /* resource data goes here */
+FILE *sf = NULL; /* supplied resource comments go here */
+FILE *nf = NULL; /* needed resource comments go here */
+FILE *pf = NULL; /* elements of _custompagesetup */
+int sfcount; /* count of supplied resources */
+int nfcount; /* count of needed resources */
+int ostdout; /* old standard output */
+FILE *fp_acct = NULL; /* accounting stuff written here */
+
+
+/*
+ *
+ * Very temporary space that can be used to do things like building up pathnames
+ * immediately before opening a file. Contents may not be preserved across calls
+ * to subroutines defined in this file, so it probably should only be used in low
+ * level subroutines like loadfont() or fontinit() and nowhere else.
+ *
+ */
+
+
+char temp[4096];
+
+/*****************************************************************************/
+
+static char *linkborderstyle;
+static char *ulinkborderstyle;
+
+static void sethorscale(char *);
+static void t_papersize(char *);
+static void t_cutat(const char *, struct box *, char *);
+static void t_track(char *);
+static void t_strack(void);
+static void t_pdfmark(char *);
+static void t_locale(char *);
+static void t_anchor(char *);
+static void t_link(char *);
+static void t_linkcolor(char *);
+static void t_linkborder(char *);
+static void t_ulink(char *);
+static void t_ulinkcolor(char *);
+static void t_ulinkborder(char *);
+static char *t_linkborderstyle(char *);
+
+static int mb_cur_max;
+
+/*****************************************************************************/
+
+
+int
+main(int agc, char *agv[])
+
+
+{
+ const char template[] = "/var/tmp/dpostXXXXXX";
+ char *tp;
+ FILE *fp;
+
+
+/*
+ *
+ * A program that translates troff output into PostScript. All the input files
+ * must have been formatted for the same device, which doesn't necessarily have to
+ * be *realdev. If there's more than one input file, each begins on a new page.
+ *
+ */
+
+ setlocale(LC_CTYPE, "");
+ mb_cur_max = MB_CUR_MAX;
+
+ ostdout = dup(1);
+ if (close(mkstemp(tp = strdup(template))) < 0 ||
+ freopen(tp, "r+", stdout) == NULL) {
+ perror(tp);
+ return 2;
+ }
+ unlink(tp);
+ if (close(mkstemp(tp = strdup(template))) < 0 ||
+ (gf = fopen(tp, "r+")) == NULL) {
+ perror(tp);
+ return 2;
+ }
+ unlink(tp);
+ if (close(mkstemp(tp = strdup(template))) < 0 ||
+ (rf = fopen(tp, "r+")) == NULL) {
+ perror(tp);
+ return 2;
+ }
+ unlink(tp);
+ if (close(mkstemp(tp = strdup(template))) < 0 ||
+ (sf = fopen(tp, "r+")) == NULL) {
+ perror(tp);
+ return 2;
+ }
+ unlink(tp);
+ if (close(mkstemp(tp = strdup(template))) < 0 ||
+ (nf = fopen(tp, "r+")) == NULL) {
+ perror(tp);
+ return 2;
+ }
+ unlink(tp);
+ if (close(mkstemp(tp = strdup(template))) < 0 ||
+ (pf = fopen(tp, "r+")) == NULL) {
+ perror(tp);
+ return 2;
+ }
+ unlink(tp);
+
+ argc = agc; /* global so everyone can use them */
+ argv = agv;
+
+ progname =
+ prog_name = argv[0]; /* just for error messages */
+
+ init_signals(); /* sets up interrupt handling */
+ options(); /* command line options */
+ arguments(); /* translate all the input files */
+ done(); /* add trailing comments etc. */
+
+ fp = fdopen(ostdout, "w");
+ header(fp); /* PostScript file structuring comments */
+
+ account(); /* job accounting data */
+ return(x_stat); /* everything probably went OK */
+
+} /* End of main */
+
+/*****************************************************************************/
+int
+putint(int n, FILE *fp)
+{
+ char buf[20];
+ int c = 0, i;
+
+/*
+ *
+ * Print an integer in PostScript binary token representation.
+ *
+ */
+ if (n >= -128 && n <= 127) {
+ buf[c++] = 136;
+ buf[c++] = n;
+ } else if (n >= -32768 && n <= 32767) {
+ buf[c++] = 134;
+ buf[c++] = (n&0xff00) >> 8;
+ buf[c++] = (n&0x00ff);
+ } else {
+ buf[c++] = 132;
+ buf[c++] = (n&0xff000000) >> 24;
+ buf[c++] = (n&0x00ff0000) >> 16;
+ buf[c++] = (n&0x0000ff00) >> 8;
+ buf[c++] = (n&0x000000ff);
+ }
+ for (i = 0; i < c; i++)
+ putc(buf[i]&0377, fp);
+ return c;
+}
+
+int
+putstring1(const char *sp, int n, FILE *fp)
+{
+/*
+ *
+ * Print a string in PostScript binary token representation.
+ *
+ */
+ putc(142, fp);
+ putc(n, fp);
+ fwrite(sp, 1, n, fp);
+ return n + 2;
+}
+
+int
+putstring(const char *sp, int n, FILE *fp)
+{
+ int c = 0, m;
+
+ do {
+ m = n > 250 ? 250 : n;
+ c += putstring1(sp, m, fp);
+ sp += m;
+ n -= m;
+ } while (n > 0);
+ return c;
+}
+
+/*****************************************************************************/
+
+
+void
+init_signals(void)
+
+
+{
+
+
+ void interrupt(int); /* signal handler */
+
+
+/*
+ *
+ * Make sure we handle interrupts.
+ *
+ */
+
+
+ if ( signal(SIGINT, interrupt) == SIG_IGN ) {
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+ } else {
+ signal(SIGHUP, interrupt);
+ signal(SIGQUIT, interrupt);
+ } /* End else */
+
+ signal(SIGTERM, interrupt);
+
+} /* End of init_signals */
+
+
+/*****************************************************************************/
+static char *
+pdfdate(time_t *tp, char *buf, size_t size)
+{
+ struct tm *tmptr;
+ int tzdiff, tzdiff_hour, tzdiff_min;
+
+ tzdiff = *tp - mktime(gmtime(tp));
+ tzdiff_hour = (int)(tzdiff / 60);
+ tzdiff_min = tzdiff_hour % 60;
+ tzdiff_hour /= 60;
+ tmptr = localtime(tp);
+ if (tmptr->tm_isdst > 0)
+ tzdiff_hour++;
+ snprintf(buf, size, "(D:%04d%02d%02d%02d%02d%02d%+03d'%02d')",
+ tmptr->tm_year + 1900,
+ tmptr->tm_mon + 1, tmptr->tm_mday,
+ tmptr->tm_hour, tmptr->tm_min, tmptr->tm_sec,
+ tzdiff_hour, tzdiff_min);
+ return buf;
+}
+/*****************************************************************************/
+
+static void
+pdfbox(const char *boxname, struct box *bp, FILE *fp, int perpage)
+{
+ double llx, lly, urx, ury;
+
+ if (bp->flag == 0)
+ return;
+ llx = bp->val[0] * 72.0 / res;
+ lly = pagelength - ((bp->val[1] + bp->val[3]) * 72.0 / res);
+ urx = (bp->val[0] + bp->val[2]) * 72.0 / res;
+ ury = pagelength - (bp->val[1] * 72.0 / res);
+ fprintf(gf, "/_%s [%g %g %g %g] def\n",
+ boxname, llx, lly, urx, ury);
+ if (perpage)
+ fprintf(fp,
+ "[ {ThisPage} 1 dict dup /%s _%s put /PUT pdfmark\n",
+ boxname, boxname);
+ else
+ fprintf(gf, "[ /%s _%s /PAGES pdfmark\n", boxname, boxname);
+}
+
+/*****************************************************************************/
+
+void
+header(FILE *fp)
+
+
+{
+
+/*
+ *
+ * Print the DSC header, followed by the data generated so far. This function
+ * is now called after all input has been processed.
+ *
+ */
+
+
+ struct Bookmark *bp;
+ time_t now;
+ int n;
+ double x = 0, y = 0;
+ char buf[4096];
+ char crdbuf[40];
+
+
+ time(&now);
+ if (mediasize.flag) {
+ x = mediasize.val[2] * 72.0 / res;
+ y = mediasize.val[3] * 72.0 / res;
+ }
+ fprintf(fp, "%s", CONFORMING);
+ fprintf(fp, "%s %s\n", CREATOR, creator);
+ fprintf(fp, "%s %s", CREATIONDATE, ctime(&now));
+ if (LanguageLevel > 1)
+ fprintf(fp, "%%%%LanguageLevel: %d\n", LanguageLevel);
+ if (Binary)
+ fprintf(fp, "%%%%DocumentData: Binary\n");
+ if ( temp_file != NULL ) {
+ if ( docfonts > 0 ) {
+ cat(temp_file, fp);
+ putc('\n', fp);
+ } /* End if */
+ unlink(temp_file);
+ } /* End if */
+ fprintf(fp, "%s %d\n", PAGES, printed);
+ if (mediasize.flag & 2)
+ fprintf(fp, "%%%%DocumentMedia: x%gy%g %g %g 0 () ()\n", x, y, x, y);
+
+ fflush(nf);
+ rewind(nf);
+ while ((n = fread(buf, 1, sizeof buf, nf)) > 0)
+ fwrite(buf, 1, n, fp);
+ fflush(sf);
+ rewind(sf);
+ while ((n = fread(buf, 1, sizeof buf, sf)) > 0)
+ fwrite(buf, 1, n, fp);
+ fprintf(fp, "%s", ENDCOMMENTS);
+
+ fprintf(fp, "%s\n", "%%BeginProlog");
+ if ( cat(prologue, fp) == FALSE )
+ error(FATAL, "can't read %s", prologue);
+ fflush(rf);
+ rewind(rf);
+ while ((n = fread(buf, 1, sizeof buf, rf)) > 0)
+ fwrite(buf, 1, n, fp);
+ fprintf(fp, "%s", ENDPROLOG);
+
+ fprintf(fp, "%s", BEGINSETUP);
+ fprintf(fp, "\
+[ /CreationDate %s\n\
+ /Creator (%s)\n", pdfdate(&now, crdbuf, sizeof crdbuf), creator);
+ if (Author)
+ fprintf(fp, " /Author %s\n", Author);
+ if (Title)
+ fprintf(fp, " /Title %s\n", Title);
+ if (Subject)
+ fprintf(fp, " /Subject %s\n", Subject);
+ if (Keywords)
+ fprintf(fp, " /Keywords %s\n", Keywords);
+ fprintf(fp, "/DOCINFO pdfmark\n");
+ if (Bookmarks) {
+ orderbookmarks();
+ for (bp = &Bookmarks[0]; bp < &Bookmarks[nBookmarks]; bp++) {
+ fprintf(fp, "[ /Title %s\n", bp->Title);
+ if (bp->Count)
+ fprintf(fp, " /Count %d\n", bp->closed ?
+ -bp->Count : bp->Count);
+ fprintf(fp, " /Dest /Bookmark$%d\n"
+ "/OUT pdfmark\n",
+ (int)(bp - &Bookmarks[0]));
+ }
+ }
+
+ fflush(pf);
+ rewind(pf);
+ fprintf(fp, "/_custompagesetup {\n");
+ pdfbox("TrimBox", &trimat, fp, 1);
+ pdfbox("BleedBox", &bleedat, fp, 1);
+ pdfbox("CropBox", &cropat, fp, 0);
+ while ((n = fread(buf, 1, sizeof buf, pf)) > 0)
+ fwrite(buf, 1, n, fp);
+ fprintf(fp, "} def\n");
+ fprintf(fp, "/_marks {\n");
+ if (Mflag & M_CUT)
+ fprintf(fp, "_cutmarks\n");
+ if (Mflag & M_REG)
+ fprintf(fp, "_regmarks\n");
+ if (Mflag & M_STAR)
+ fprintf(fp, "_startargets\n");
+ if (Mflag & M_COL)
+ fprintf(fp, "_colorbars\n");
+ fprintf(fp, "} def\n");
+
+ fflush(gf);
+ rewind(gf);
+ while ((n = fread(buf, 1, sizeof buf, gf)) > 0)
+ fwrite(buf, 1, n, fp);
+ if (mediasize.flag) {
+ fprintf(fp, "/pagebbox [0 0 %g %g] def\n", x, y);
+ fprintf(fp, "userdict /gotpagebbox true put\n");
+ if (mediasize.flag & 2)
+ fprintf(fp, "/setpagedevice where {pop "
+ "1 dict dup /PageSize [%g %g] put setpagedevice"
+ "} if\n", x, y);
+ }
+ fprintf(fp, "mark\n");
+
+ fflush(stdout);
+ rewind(stdout);
+ while ((n = fread(buf, 1, sizeof buf, stdout)) > 0)
+ fwrite(buf, 1, n, fp);
+
+ fprintf(fp, "%s", ENDOFFILE);
+
+} /* End of header */
+
+
+/*****************************************************************************/
+
+
+void
+options(void)
+
+
+{
+
+ const char optnames[] = "a:c:e:m:n:o:p:tw:x:y:A:C:J:F:H:L:M:OP:R:S:T:DI";
+
+ int ch; /* name returned by getopt() */
+
+
+/*
+ *
+ * Reads and processes the command line options. There are, without a doubt, too
+ * many options!
+ *
+ */
+
+
+ while ( (ch = getopt(argc, argv, optnames)) != EOF ) {
+
+ switch ( ch ) {
+
+ case 'a': /* aspect ratio */
+ fprintf(stdout, "/aspectratio %s def\n", optarg);
+ break;
+
+ case 'c': /* number of copies */
+ copies = atoi(optarg);
+ fprintf(stdout, "/#copies %s store\n", optarg);
+ break;
+
+ case 'e': /* change the encoding scheme */
+ if ( (encoding = atoi(optarg)) < 0 || encoding > MAXENCODING )
+ encoding = DFLTENCODING;
+ else
+ eflag = 1;
+ realencoding = encoding;
+ break;
+
+ case 'm': /* magnification */
+ fprintf(stdout, "/magnification %s def\n", optarg);
+ break;
+
+ case 'n': /* forms per page */
+ formsperpage = atoi(optarg);
+ fprintf(stdout, "%s %s\n", FORMSPERPAGE, optarg);
+ fprintf(stdout, "/formsperpage %s def\n", optarg);
+ break;
+
+ case 'o': /* output page list */
+ out_list(optarg);
+ break;
+
+ case 'p': /* landscape or portrait mode */
+ if ( *optarg == 'l' )
+ fprintf(stdout, "/landscape true def\n");
+ else fprintf(stdout, "/landscape false def\n");
+ break;
+
+ case 't': /* just for compatibility */
+ break;
+
+ case 'w': /* line width for drawing */
+ fprintf(stdout, "/linewidth %s def\n", optarg);
+ break;
+
+ case 'x': /* shift horizontally */
+ fprintf(stdout, "/xoffset %s def\n", optarg);
+ break;
+
+ case 'y': /* and vertically on the page */
+ fprintf(stdout, "/yoffset %s def\n", optarg);
+ break;
+
+ case 'A': /* force job accounting */
+ case 'J':
+ if ( (fp_acct = fopen(optarg, "a")) == NULL )
+ error(FATAL, "can't open accounting file %s", optarg);
+ break;
+
+ case 'C': /* copy file to straight to output */
+ if ( cat(optarg, stdout) == FALSE )
+ error(FATAL, "can't read %s", optarg);
+ break;
+
+ case 'F': /* font table directory */
+ fontdir = optarg;
+ break;
+
+ case 'H': /* host resident font directory */
+ hostfontdir = optarg;
+ break;
+
+ case 'L': /* PostScript prologue file */
+ setpaths(optarg);
+ break;
+
+ case 'M': /* print cut marks */
+ setmarks(optarg);
+ break;
+
+ case 'O': /* turn picture inclusion off */
+ picflag = OFF;
+ break;
+
+ case 'P': /* PostScript pass through */
+ fprintf(stdout, "%s\n", optarg);
+ break;
+
+ case 'R': /* special global or page level request */
+ saverequest(optarg);
+ break;
+
+ case 'S': /* horizontal position error */
+ if ( (pointslop = atof(optarg)) < 0 )
+ pointslop = 0;
+ Sflag = 1;
+ break;
+
+ case 'T': /* target printer */
+ realdev = optarg;
+ break;
+
+ case 'D': /* debug flag */
+ debug = ON;
+ tf = stdout;
+ break;
+
+ case 'I': /* ignore FATAL errors */
+ ignore = ON;
+ break;
+
+ case '?': /* don't know the option */
+ error(FATAL, "");
+ break;
+
+ default:
+ error(FATAL, "missing case for option %c", ch);
+ break;
+
+ } /* End switch */
+ } /* End while */
+
+ argc -= optind; /* get ready for non-options args */
+ argv += optind;
+
+ if (Mflag) {
+ FILE *otf = tf;
+ tf = stdout;
+ doglobal(cutmarksfile);
+ tf = otf;
+ }
+
+} /* End of options */
+
+
+/*****************************************************************************/
+
+
+void
+setpaths (
+ char *name /* string that followed the -L option */
+)
+
+
+{
+
+
+ char *path; /* start of the pathname */
+
+
+/*
+ *
+ * Extends the -L option to permit run time modification of pathnames that were
+ * fixed or didn't exist in previous versions of dpost. For example, the PostScript
+ * drawing procedures have been moved out of *prologue and put in *drawfile. The
+ * new syntax can be either -Lfile or -Lname:file. If the "name:" prefix is omitted
+ * file will be used as the prologue, otherwise name should be one of "prologue",
+ * "font", "draw", "color", or "form" and is used to select the pointer that gets
+ * set to string "file".
+ *
+ */
+
+
+ for ( path = name; *path; path++ )
+ if ( *path == ':' || *path == ' ' ) {
+ while ( *path == ':' || *path == ' ' ) path++;
+ break;
+ } /* End if */
+
+ if ( *path == '\0' ) /* didn't find a "name:" prefix */
+ path = name;
+
+ if ( path == name || strncmp(name, "prologue", strlen("prologue")) == 0 )
+ prologue = path;
+ else if ( strncmp(name, "draw", strlen("draw")) == 0 )
+ drawfile = path;
+ else if ( strncmp(name, "color", strlen("color")) == 0 )
+ colorfile = path;
+ else if ( strncmp(name, "form", strlen("form")) == 0 )
+ formfile = path;
+ else if ( strncmp(name, "baseline", strlen("baseline")) == 0 )
+ baselinefile = path;
+ else if ( strncmp(name, "cutmarks", strlen("cutmarks")) == 0 )
+ cutmarksfile = path;
+
+} /* End of setpaths */
+
+/*****************************************************************************/
+
+static int
+prefix(const char *str, const char *pfx)
+{
+ while (*pfx && *str == *pfx)
+ str++, pfx++;
+ return *str == 0;
+}
+
+static void
+setmarks(char *str)
+{
+ char *sp;
+ int c;
+
+ do {
+ for (sp = str; *sp && *sp != ':'; sp++);
+ c = *sp;
+ *sp = 0;
+ if (prefix(str, "cutmarks"))
+ Mflag |= M_CUT;
+ else if (prefix(str, "registrationmarks"))
+ Mflag |= M_REG;
+ else if (prefix(str, "startargets"))
+ Mflag |= M_STAR;
+ else if (prefix(str, "colorbars"))
+ Mflag |= M_COL;
+ else if (prefix(str, "all"))
+ Mflag |= M_ALL;
+ else
+ error(FATAL, "unknown mark: -M %s", str);
+ *sp = c;
+ str = &sp[1];
+ } while (c);
+}
+
+/*****************************************************************************/
+
+
+void
+setup(void)
+
+
+{
+
+
+/*
+ * Handles things that must be done after the options are read but before the
+ * input files are processed. Called from t_init() after an "x init" command is
+ * read, because we need the resolution before we can generate the call to the
+ * setup procedure defined in *prologue. Only allowing one call to setup assumes
+ * all the input files have been prepared for the same device.
+ *
+ */
+
+
+ writerequest(0, stdout); /* global requests eg. manual feed */
+ fprintf(stdout, "/resolution %d def\n", res);
+ fprintf(stdout, "setup\n");
+ fprintf(stdout, "%d setdecoding\n", encoding);
+
+ if ( formsperpage > 1 ) { /* followed by stuff for multiple pages */
+ if ( cat(formfile, stdout) == FALSE )
+ error(FATAL, "can't read %s", formfile);
+ fprintf(stdout, "%d setupforms\n", formsperpage);
+ } /* End if */
+
+ fprintf(stdout, "%s", ENDSETUP);
+
+} /* End of setup */
+
+
+/*****************************************************************************/
+
+
+void
+arguments(void)
+
+
+{
+
+
+ FILE *fp; /* next input file */
+
+
+/*
+ *
+ * Makes sure all the non-option command line arguments are processed. If we get
+ * here and there aren't any arguments left, or if '-' is one of the input files
+ * we'll translate stdin.
+ *
+ */
+
+
+ if ( argc < 1 )
+ conv(stdin);
+ else
+ while ( argc > 0 ) {
+ if ( strcmp(*argv, "-") == 0 )
+ fp = stdin;
+ else if ( (fp = fopen(*argv, "r")) == NULL )
+ error(FATAL, "can't open %s", *argv);
+ conv(fp);
+ if ( fp != stdin )
+ fclose(fp);
+ argc--;
+ argv++;
+ } /* End while */
+
+} /* End of arguments */
+
+
+/*****************************************************************************/
+
+
+void
+done(void)
+
+
+{
+
+/*
+ *
+ * Finished with all the input files, so mark the end of the pages with a TRAILER
+ * comment, make sure the last page prints, and add things like the DOCUMENTFONTS
+ * and PAGES comments that can only be determined after all the input files have
+ * been read.
+ *
+ */
+
+
+ fprintf(stdout, "%s", TRAILER);
+ fprintf(stdout, "done\n");
+
+} /* End of done */
+
+
+/*****************************************************************************/
+
+
+void
+account(void)
+
+
+{
+
+
+/*
+ *
+ * Writes an accounting record to *fp_acct provided it's not NULL. Accounting is
+ * requested using the -A or -J options.
+ *
+ */
+
+ if ( fp_acct != NULL )
+ fprintf(fp_acct, " print %d\n copies %d\n", printed, copies);
+
+} /* End of account */
+
+
+/*****************************************************************************/
+
+void
+conv(
+
+
+ register FILE *fp /* next input file */
+)
+
+
+{
+
+
+ register int c; /* usually first char in next command */
+ int m, n, n1, m1; /* when we need to read integers */
+ char str[4096]; /* for special chars and font numbers */
+ char b;
+
+
+/*
+ *
+ * Controls the translation of troff's device independent output language into
+ * PostScript. The call to t_page() that prints the last page is made when we
+ * exit the loop, but probably belongs in t_trailer().
+ *
+ */
+
+
+ redirect(-1); /* only do output after a page command */
+ lineno = 1; /* line in current file */
+
+ while ((c = getc(fp)) != EOF) {
+
+ switch (c) {
+
+ case '\n': /* just count this line */
+ lineno++;
+ break;
+
+ case ' ': /* when input is text */
+ case 0: /* occasional noise creeps in */
+ break;
+
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ /* two motion digits plus a character */
+ hmot((c-'0')*10 + getc(fp)-'0');
+ put1(getc(fp));
+ break;
+
+ case 'c': /* single ascii character */
+ put1(getc(fp));
+ break;
+
+ case 'C': /* special character */
+ sget(str, sizeof str, fp);
+ put1s(str);
+ break;
+
+ case 'N': /* character at position n */
+ fscanf(fp, "%d", &m);
+ endtext();
+ oput(m);
+ endtext();
+ break;
+
+ case 'D': /* drawing functions */
+ endtext();
+ getdraw();
+ if ( size != lastsize || (size == FRACTSIZE &&
+ fractsize != lastfractsize) ||
+ horscale != lasthorscale) {
+ subfont = 0;
+ t_sf(0);
+ }
+ switch ((c=getc(fp))) {
+ case 'p': /* draw a path */
+ while (fscanf(fp, "%d %d", &n, &m) == 2)
+ drawline(n, m);
+ lineno++;
+ break;
+
+ case 'P': /* solid polygon */
+ fprintf(tf, "newpath %d %d neg moveto\n", hpos,
+ vpos);
+ while (fscanf(fp, "%d %d", &n, &m) == 2) {
+ hpos += n;
+ vpos += m;
+ fprintf(tf, "%d %d neg lineto\n", hpos, vpos);
+ }
+ fprintf(tf, "closepath fill\n");
+ lineno++;
+ break;
+
+ case 'l': /* draw a line */
+ fscanf(fp, "%d %d %c", &n, &m, &b);
+ n1 = b;
+ drawline(n, m);
+ break;
+
+ case 'c': /* circle */
+ case 'C': /* filled circle */
+ fscanf(fp, "%d", &n);
+ drawcirc(n, c);
+ break;
+
+ case 'e': /* ellipse */
+ case 'E': /* filled ellipse */
+ fscanf(fp, "%d %d", &m, &n);
+ drawellip(m, n, c);
+ break;
+
+ case 'a': /* counter-clockwise arc */
+ case 'A': /* clockwise arc */
+ fscanf(fp, "%d %d %d %d", &n, &m, &n1, &m1);
+ drawarc(n, m, n1, m1, c);
+ break;
+
+ case 'q': /* spline without end points */
+ drawspline(fp, 1);
+ lineno++;
+ break;
+
+ case '~': /* wiggly line */
+ drawspline(fp, 2);
+ lineno++;
+ break;
+
+ case 't': /* set line width, ignore */
+ fscanf(fp, "%d %d", &m, &n);
+ hgoto(hpos + m);
+ lineno++;
+ break;
+
+ case 'F': /* color scheme, ignore */
+ case 'f': /* filling color, ignore */
+ fgets(str, sizeof str, fp);
+ lineno++;
+ break;
+
+ default:
+ error(FATAL, "unknown drawing function %c", c);
+ break;
+ } /* End switch */
+ break;
+
+ case 's': /* use this point size */
+ fscanf(fp, "%d", &n); /* ignore fractional sizes */
+ if (n != FRACTSIZE)
+ setsize(t_size(n), 0);
+ else {
+ float f;
+ fscanf(fp, "%f", &f);
+ setsize(FRACTSIZE, f);
+ }
+ break;
+
+ case 'f': /* use font mounted here */
+ sget(str, sizeof str, fp);
+ setfont(t_font(str));
+ break;
+
+ case 'H': /* absolute horizontal motion */
+ fscanf(fp, "%d", &n);
+ hgoto(n);
+ break;
+
+ case 'h': /* relative horizontal motion */
+ fscanf(fp, "%d", &n);
+ hmot(n);
+ break;
+
+ case 'w': /* word space */
+ wordspace++;
+ break;
+
+ case 'V': /* absolute vertical position */
+ fscanf(fp, "%d", &n);
+ vgoto(n);
+ break;
+
+ case 'v': /* relative vertical motion */
+ fscanf(fp, "%d", &n);
+ vmot(n);
+ break;
+
+ case 'p': /* new page */
+ fscanf(fp, "%d", &n);
+ t_page(n);
+ break;
+
+ case 'n': /* end of line */
+ while ( (c = getc(fp)) != '\n' && c != EOF ) ;
+ t_newline();
+ lineno++;
+ break;
+
+ case '#': /* comment */
+ while ( (c = getc(fp)) != '\n' && c != EOF ) ;
+ lineno++;
+ break;
+
+ case 'x': /* device control function */
+ devcntrl(fp);
+ lineno++;
+ break;
+
+ default:
+ error(FATAL, "unknown input character %o %c", c, c);
+ done();
+
+ } /* End switch */
+
+ } /* End while */
+
+ t_page(-1); /* print the last page */
+ endtext();
+
+} /* End of conv */
+
+
+/*****************************************************************************/
+
+void
+devcntrl(
+
+
+ FILE *fp /* current input file */
+)
+
+
+{
+
+
+ char str[4096], *buf, str1[4096];
+ int c, n, size;
+
+
+/*
+ *
+ * Called from conv() to process the rest of a device control function. There's
+ * a whole family of them and they all start with the string "x ", which we've
+ * already read. The "x X ..." commands are an extensible (and device dependent)
+ * family that we use here for things like picture inclusion. Unrecognized device
+ * control commands are ignored.
+ *
+ */
+
+
+ buf = malloc(size = 4096);
+ sget(str, sizeof str, fp); /* get the control function name */
+
+ switch ( str[0] ) { /* only the first character counts */
+
+ case 'i': /* initialize */
+ t_init();
+ break;
+
+ case 'T': /* device name */
+ sget(devname, sizeof devname, fp);
+ getdevmap();
+ /*
+ * This used to be "strcpy(devname, realdev);" but
+ * it does not work when DESC is a text file because
+ * the fonts are in a different directory.
+ */
+ if (dev.afmfonts || (devname[0] == 'p' && devname[1] == 's'))
+ realdev = devname;
+ else
+ n_strcpy(devname, realdev, sizeof(devname));
+ break;
+
+ case 't': /* trailer */
+ t_trailer();
+ break;
+
+ case 'p': /* pause -- can restart */
+ t_reset('p');
+ break;
+
+ case 's': /* stop */
+ t_reset('s');
+ break;
+
+ case 'r': /* resolution assumed when prepared */
+ fscanf(fp, "%d", &res);
+ break;
+
+ case 'f': /* load font in a position */
+ fscanf(fp, "%d", &n);
+ sget(str, sizeof str, fp);
+ fgets(buf, size, fp); /* in case there's a filename */
+ ungetc('\n', fp); /* fgets() goes too far */
+ str1[0] = '\0'; /* in case there's nothing to come in */
+ c = 0;
+ sscanf(buf, "%s %d", str1, &c);
+ loadfont(n, mapdevfont(str), str1, 0, c);
+ break;
+
+ /* these don't belong here... */
+ case 'H': /* char height */
+ fscanf(fp, "%d", &n);
+ if (n != FRACTSIZE)
+ t_charht(n, 0);
+ else {
+ float f;
+ fscanf(fp, "%f", &f);
+ t_charht(FRACTSIZE, f);
+ }
+ break;
+
+ case 'S': /* slant */
+ fscanf(fp, "%d", &n);
+ t_slant(n);
+ break;
+
+ case 'X': /* copy through - from troff */
+ do
+ c = getc(fp);
+ while (spacechar(c));
+ n = 0;
+ if (c != EOF) do {
+ if (n + 1 < sizeof str)
+ str[n++] = c;
+ c = getc(fp);
+ } while (c != EOF && !spacechar(c) && c != ':');
+ str[n] = 0;
+ if (c != ':')
+ ungetc(c, fp);
+ n = 0;
+ for (;;) {
+ fgets(&buf[n], size - n, fp);
+ if ((c = getc(fp)) != '+') {
+ ungetc(c, fp);
+ break;
+ }
+ while (buf[n])
+ n++;
+ if (size - n < 4096)
+ buf = realloc(buf, size += 4096);
+ lineno++;
+ }
+ if ( strcmp(str, "PI") == 0 || strcmp(str, "PictureInclusion") == 0 )
+ picture(buf);
+ else if ( strcmp(str, "InlinePicture") == 0 )
+ inlinepic(fp, buf);
+ else if ( strcmp(str, "SupplyFont") == 0 )
+ t_supply(buf);
+ else if ( strcmp(str, "PaperSize") == 0 )
+ t_papersize(buf);
+ else if ( strcmp(str, "TrimAt") == 0 )
+ t_cutat("Trim size", &trimat, buf);
+ else if ( strcmp(str, "BleedAt") == 0 )
+ t_cutat("Bleed size", &bleedat, buf);
+ else if ( strcmp(str, "CropAt") == 0 )
+ t_cutat("Crop size", &cropat, buf);
+ else if ( strcmp(str, "Track") == 0 )
+ t_track(buf);
+ else if ( strcmp(str, "PDFMark") == 0 )
+ t_pdfmark(buf);
+ else if ( strcmp(str, "LC_CTYPE") == 0 )
+ t_locale(buf);
+ else if ( strcmp(str, "Anchor") == 0 )
+ t_anchor(buf);
+ else if ( strcmp(str, "Link") == 0 )
+ t_link(buf);
+ else if ( strcmp(str, "SetLinkColor") == 0 )
+ t_linkcolor(buf);
+ else if ( strcmp(str, "SetLinkBorder") == 0 )
+ t_linkborder(buf);
+ else if ( strcmp(str, "SetBorderStyle") == 0 )
+ linkborderstyle = t_linkborderstyle(buf);
+ else if ( strcmp(str, "SetUBorderStyle") == 0 )
+ ulinkborderstyle = t_linkborderstyle(buf);
+ else if ( strcmp(str, "ULink") == 0 )
+ t_ulink(buf);
+ else if ( strcmp(str, "SetULinkColor") == 0 )
+ t_ulinkcolor(buf);
+ else if ( strcmp(str, "SetULinkBorder") == 0 )
+ t_ulinkborder(buf);
+ else if ( strcmp(str, "HorScale") == 0 )
+ sethorscale(buf);
+ else if ( strcmp(str, "BeginPath") == 0 )
+ beginpath(buf, FALSE);
+ else if ( strcmp(str, "DrawPath") == 0 )
+ drawpath(buf, FALSE);
+ else if ( strcmp(str, "BeginObject") == 0 )
+ beginpath(buf, TRUE);
+ else if ( strcmp(str, "EndObject") == 0 )
+ drawpath(buf, TRUE);
+ else if ( strcmp(str, "NewBaseline") == 0 )
+ newbaseline(buf);
+ else if ( strcmp(str, "DrawText") == 0 )
+ drawtext(buf);
+ else if ( strcmp(str, "SetText") == 0 )
+ settext(buf);
+ else if ( strcmp(str, "SetColor") == 0 ) {
+ newcolor(buf);
+ setcolor();
+ } else if ( strcmp(str, "Sync") == 0 ) {
+ if (tracked)
+ tracked = -1;
+ subfont = 0;
+ t_sf(1);
+ xymove(hpos, vpos);
+ } else if ( strcmp(str, "PSSetup") == 0 ) {
+ fprintf(gf, "%s", buf);
+ } else if ( strcmp(str, "PS") == 0 || strcmp(str, "PostScript") == 0 ) {
+ endtext();
+ /* xymove(hpos, vpos); ul90-22006 */
+ fprintf(tf, "%s", buf);
+ } /* End else */
+ goto done;
+ } /* End switch */
+
+ while ( (c = getc(fp)) != '\n' && c != EOF ) ;
+done:
+ free(buf);
+
+} /* End of devcntrl */
+
+
+/*****************************************************************************/
+
+
+void
+fontinit(void)
+
+
+{
+
+
+ char *descp; /* for reading the DESC file */
+ char *filebase; /* the whole thing goes here */
+ int i; /* loop index */
+
+
+/*
+ *
+ * Reads *realdev's DESC file and uses what's there to initialize things like
+ * the list of available point sizes. Old versions of the program used *devname's
+ * DESC file to initialize nfonts, but that meant we needed to have *devname's
+ * binary font files available for emulation. That restriction has been removed
+ * and we now set nfonts using the "x font" commands in the input file, so by the
+ * time we get here all we really need is *realdev. In fact devcntrl() reads the
+ * device name from the "x T ..." command, but almost immediately replaces it with
+ * string *realdev so we end up using *realdev's DESC file. Later on (in
+ * t_font()) we mount all of *realdev's special fonts after the last legitimate
+ * font position, just to be sure device emulation works reasonably well - there's
+ * no guarantee *devname's special fonts match what's needed when *realdev's tables
+ * are used.
+ *
+ */
+
+
+ snprintf(temp, sizeof temp, "%s/dev%s/FONTMAP", fontdir, devname);
+ rdftmap(temp);
+ snprintf(temp, sizeof temp, "%s/dev%s/DESC", fontdir, devname);
+ if ( (descp = readdesc(temp)) == 0 )
+ error(FATAL, "can't open tables for %s", temp);
+
+ memcpy(&dev, descp, sizeof dev);
+
+ nfonts = 0; /* was dev.nfonts - now set in t_fp() */
+ nsizes = dev.nsizes;
+ nchtab = dev.nchtab;
+ unitwidth = dev.unitwidth;
+
+ filebase = &descp[sizeof dev];
+
+ pstab = (int *) filebase;
+ chtab = (short *)(pstab + nsizes + 1);
+ chname = (char *) (chtab + nchtab);
+ fsize = 3 * 255 + nchtab + 128 - 32 + sizeof(struct Font);
+
+ fitab = calloc(NFONT+1, sizeof *fitab);
+ fontab = calloc(NFONT+1, sizeof *fontab);
+ codetab = calloc(NFONT+1, sizeof *codetab);
+ kerntab = calloc(NFONT+1, sizeof *kerntab);
+ fontbase = calloc(NFONT+1, sizeof *fontbase);
+
+ for ( i = 1; i <= NFONT; i++ ) { /* so loadfont() knows nothing's there */
+ fontbase[i] = NULL;
+ } /* End for */
+
+ if ( (downloaded = (char *) calloc(nchtab + 128, sizeof(char))) == NULL )
+ error(FATAL, "no memory");
+
+} /* End of fontinit */
+
+
+/*****************************************************************************/
+
+
+void
+loadfont (
+ int n, /* load this font position */
+ char *s, /* with the file for this font */
+ char *s1, /* taken from here - possibly */
+ int forcespecial, /* this is definitively a special font */
+ int spec /* map specification */
+)
+
+
+{
+
+
+ char *fpout = NULL; /* for reading *s file */
+ int fin; /* for reading *s.afm file */
+ int nw; /* number of width table entries */
+ char *p;
+ char *path;
+ size_t l;
+
+
+/*
+ *
+ * Loads font position n with the binary font file for *s provided it's not
+ * already there. If *s1 is NULL or points to the empty string we read files from
+ * directory *fontdir/dev*devname, otherwise directory *s1 is used. If the first
+ * open fails we try to map font *s into one we expect will be available, and then
+ * we try again.
+ *
+ */
+
+
+ if ( n < 0 || n > NFONT ) /* make sure it's a legal position */
+ error(FATAL, "illegal fp command %d %s", n, s);
+
+ if ( fontbase[n] != NULL && strcmp(s, fontbase[n]->namefont) == 0 )
+ return;
+
+ path = temp;
+ if (s1 && strchr(s1, '/') != NULL)
+ path = afmdecodepath(s1);
+ else if (s1 && strstr(s1, ".afm") != NULL)
+ snprintf(temp, sizeof temp, "%s/dev%s/%s", fontdir, devname, s1);
+ else if (strchr(s, '/') != NULL) {
+ path = afmdecodepath(s);
+ if (spec == 0 && s1)
+ spec = atoi(s1);
+ } else if (strstr(s, ".afm") != NULL) {
+ snprintf(temp, sizeof temp, "%s/dev%s/%s", fontdir, devname, s);
+ if (spec == 0 && s1)
+ spec = atoi(s1);
+ } else snprintf(temp, sizeof temp, "%s/dev%s/%s.afm", fontdir, devname, s);
+
+ if ( (fin = open(path, O_RDONLY)) >= 0 ) {
+ struct afmtab *a;
+ struct stat st;
+ char *contents;
+ int i;
+ if ((p = strrchr(s, '/')) == NULL)
+ p = s;
+ else
+ p++;
+ if (p[0] == 'S' && (p[1] == '\0' || (digitchar(p[1]&0377) &&
+ p[2] == '\0') || p[2] == '.'))
+ forcespecial = 1;
+ for (i = 0; i < afmcount; i++)
+ if (afmfonts[i] && strcmp(afmfonts[i]->path, path) == 0 &&
+ afmfonts[i]->spec == spec) {
+ a = afmfonts[i];
+ close(fin);
+ goto have;
+ }
+ if ((a = calloc(1, sizeof *a)) == NULL ||
+ fstat(fin, &st) < 0 ||
+ (contents = malloc(st.st_size+1)) == NULL ||
+ read(fin, contents, st.st_size) != st.st_size) {
+ free(a);
+ close(fin);
+ goto fail;
+ }
+ close(fin);
+ l = strlen(path) + 1;
+ a->path = malloc(l);
+ n_strcpy(a->path, path, l);
+ if (path != temp)
+ free(path);
+ a->file = s;
+ a->spec = spec;
+ if (afmget(a, contents, st.st_size) < 0) {
+ free(a);
+ free(contents);
+ goto fail;
+ }
+ free(contents);
+ afmfonts = realloc(afmfonts, (afmcount+1) * sizeof *afmfonts);
+ afmfonts[afmcount] = a;
+ snprintf(a->Font.intname, sizeof a->Font.intname,
+ "%d", dev.nfonts + ++afmcount);
+ if (forcespecial)
+ a->Font.specfont = 1;
+have: fontbase[n] = &a->Font;
+ fontab[n] = a->fontab;
+ codetab[n] = a->codetab;
+ fitab[n] = a->fitab;
+ t_fp(n, a->fontname, fontbase[n]->intname, a);
+ goto done;
+ }
+ if (strchr(s, '/') != NULL)
+ goto fail;
+ if ( s1 == NULL || s1[0] == '\0' )
+ snprintf(temp, sizeof temp, "%s/dev%s/%s", fontdir, devname, s);
+ else snprintf(temp, sizeof temp, "%s/%s", s1, s);
+
+ if ( access(temp, R_OK) < 0 )
+ snprintf(temp, sizeof temp, "%s/dev%s/%s",
+ fontdir, devname, mapfont(s));
+ if ((fpout = readfont(temp, &dev, 0)) == NULL)
+ fail: error(FATAL, "can't open font table %s", temp);
+
+ if ( fontbase[n] != NULL ) /* something's already there */
+ free(fontbase[n]); /* so release the memory first */
+
+ fontbase[n] = (struct Font *)fpout;
+
+ p = (char *) fontbase[n] + sizeof(struct Font);
+ nw = fontbase[n]->nwfont & BMASK;
+ makefont(n, p, NULL, p + 2 * nw, p + 3 * nw, nw);
+
+ t_fp(n, fontbase[n]->namefont, fontbase[n]->intname, NULL);
+
+done:
+ if ( smnt == 0 && (fontbase[n]->specfont == 1 || forcespecial) )
+ smnt = n;
+ if (fontbase[n]->specfont == 1 || forcespecial)
+ gotregular = TRUE;
+
+ if ( debug == ON )
+ fontprint(n);
+
+} /* End of loadfont */
+
+
+/*****************************************************************************/
+
+
+void
+loadspecial(void)
+
+
+{
+
+
+ char *p; /* for next binary font file */
+ int nw; /* width entries in next font */
+ int i; /* loop index */
+
+
+/*
+ *
+ * Loads all the special fonts after the last legal font position. Mostly used
+ * for device emulation, but we'll do it no matter what. Needed because there's
+ * no consistency in special fonts across different devices, and relying on having
+ * them mounted in the input file doesn't guarantee the whole collection will be
+ * there. The special fonts are determined and mounted using the copy of the
+ * DESC file that's been read into memory. Initially had this stuff at the
+ * end of fontinit(), but we now don't know nfonts until much later.
+ *
+ */
+
+ if ( gotregular == FALSE )
+ loadfont(++nfonts, ((struct Font *)(&chname[dev.lchname]))->namefont,
+ NULL, 0, 0);
+
+ if ( gotspecial == FALSE )
+ for ( i = 1, p = chname + dev.lchname; i <= dev.nfonts; i++ ) {
+ nw = *p & BMASK;
+ if ( ((struct Font *) p)->specfont == 1 )
+ loadfont(++nfonts, ((struct Font *)p)->namefont, NULL, 1, 0);
+ p += 3 * nw + dev.nchtab + 128 - 32 + sizeof(struct Font);
+ } /* End for */
+
+ gotregular = TRUE;
+ gotspecial = TRUE;
+
+} /* End of loadspecial */
+
+
+/*****************************************************************************/
+char *defaultFonts[] =
+ { "R", "I", "B", "BI", "CW", "H", "HB", "HX", "S1", "S", NULL };
+
+void
+loaddefault(void)
+{
+ int i;
+
+ for (i = 0; defaultFonts[i] != NULL ; i++)
+ loadfont(++nfonts, defaultFonts[i], NULL, defaultFonts[i][0] == 'S', 0);
+}
+
+
+void
+fontprint (
+ int i /* font's index in fontbase[] */
+)
+
+
+{
+
+
+ int j, n;
+ char *p;
+
+
+/*
+ *
+ * Debugging routine that dumps data about the font mounted in position i.
+ *
+ */
+
+
+ fprintf(tf, "font %d:\n", i);
+
+ p = (char *) fontbase[i];
+ n = fontbase[i]->nwfont & BMASK;
+
+ fprintf(tf, "base=0%lo, nchars=%d, spec=%d, name=%s, widtab=0%lo, fitab=0%lo\n",
+ (long)p, n, fontbase[i]->specfont, fontbase[i]->namefont, (long)fontab[i], (long)fitab[i]);
+
+ fprintf(tf, "widths:\n");
+ for ( j = 0; j <= n; j++ ) {
+ fprintf(tf, " %2d", fontab[i][j]);
+ if ( j % 20 == 19 ) putc('\n', tf);
+ } /* End for */
+
+ fprintf(tf, "\ncodetab:\n");
+ for ( j = 0; j <= n; j++ ) {
+ fprintf(tf, " %2d", codetab[i][j]);
+ if ( j % 20 == 19 ) putc('\n', tf);
+ } /* End for */
+
+ fprintf(tf, "\nfitab:\n");
+ for ( j = 0; j <= dev.nchtab + 128-32; j++ ) {
+ fprintf(tf, " %2d", fitab[i][j]);
+ if ( j % 20 == 19 ) putc('\n', tf);
+ } /* End for */
+
+ putc('\n', tf);
+
+} /* End of fontprint */
+
+
+/*****************************************************************************/
+
+
+char *
+mapfont (
+ char *name /* troff wanted this font */
+)
+
+
+{
+
+
+ int i; /* loop index */
+
+
+/*
+ *
+ * If loadfont() can't find font *name we map it into something else that should
+ * be available and return a pointer to the new name. Used mostly for emulating
+ * devices like the APS-5.
+ *
+ */
+
+
+ name = mapft(name);
+ for ( i = 0; fontmap[i].name != NULL; i++ )
+ if ( strcmp(name, fontmap[i].name) == 0 )
+ return(fontmap[i].use);
+
+ switch ( *++name ) {
+ case 'I':
+ return("I");
+
+ case 'B':
+ return("B");
+
+ case 'X':
+ return("BI");
+
+ default:
+ return("R");
+ } /* End switch */
+
+} /* End of mapfont */
+
+
+/*****************************************************************************/
+
+
+void
+getdevmap(void)
+
+
+{
+
+
+ FILE *fp; /* for reading the device fontmap file */
+ int i = 0; /* number of mapping pairs we've read */
+ int c; /* for skipping lines */
+
+
+/*
+ *
+ * Looks for the device font mapping file *fontdir/dev*realdev/fontmaps/devname.
+ * The file, if it exists, should be an ASCII file containing pairs of one or two
+ * character font names per line. The first name is the font troff will be asking
+ * for and the second is the one we'll use. Comments are lines that begin with
+ * a '#' as the first non-white space character on a line. The devfontmap list
+ * ends with a member that has the empty string in the name field.
+ *
+ */
+
+
+ snprintf(temp, sizeof temp, "%s/dev%s/fontmaps/%s",
+ fontdir, realdev, devname);
+
+ if ( devfontmap == NULL && (fp = fopen(temp, "r")) != NULL ) {
+ devfontmap = (Devfontmap *) malloc(10 * sizeof(Devfontmap));
+
+ while ( sget(temp, sizeof temp, fp) == 1 ) {
+ if ( temp[0] != '#' && strlen(temp) < 3 )
+ if ( sget(&temp[3], sizeof temp - 3, fp) == 1 &&
+ strlen(&temp[3]) < 3 ) {
+ n_strcpy((devfontmap + i)->name, temp,
+ sizeof(devfontmap->name));
+ n_strcpy((devfontmap + i)->use, &temp[3],
+ sizeof(devfontmap->use));
+ if ( ++i % 10 == 0 )
+ devfontmap = (Devfontmap *) realloc(devfontmap, (i + 10) * sizeof(Devfontmap));
+ } /* End if */
+ while ( (c = getc(fp)) != '\n' && c != EOF ) ;
+ } /* End while */
+
+ (devfontmap + i)->name[0] = '\0'; /* end the list we just read */
+ fclose(fp);
+ } /* End if */
+
+} /* End of getdevmap */
+
+
+/*****************************************************************************/
+
+
+char *
+mapdevfont(char *str)
+
+
+{
+
+
+ int i;
+
+
+/*
+ *
+ * Called immediately before loadfont() after an 'x font' command is recognized.
+ * Takes the font name that troff asked for, looks it up in the devfontmap list,
+ * and returns the mapped name to the caller. No mapping is done if the devfontmap
+ * list is empty or font *str isn't found in the list.
+ *
+ */
+
+
+ if ( devfontmap != NULL )
+ for ( i = 0; (devfontmap + i)->name[0] != '\0'; i++ )
+ if ( strcmp((devfontmap + i)->name, str) == 0 )
+ return((devfontmap + i)->use);
+
+ return(str);
+
+} /* End of mapdevfont */
+
+
+/*****************************************************************************/
+
+
+void
+reset(void)
+
+
+{
+
+
+/*
+ *
+ * Resets the variables that keep track of the printer's current position, font,
+ * and size. Typically used after a restore/save pair (eg. when we finish with a
+ * page) to make sure we force the printer back into sync (in terms of the font
+ * and current point) before text is printed.
+ *
+ */
+
+
+ lastx = -(slop + 1);
+ savey = lasty = -1;
+ lastfont = lastsubfont = lastsize = -1;
+ if (tracked)
+ tracked = -1;
+
+} /* End of reset */
+
+
+/*****************************************************************************/
+
+
+void
+resetpos(void)
+
+
+{
+
+
+/*
+ *
+ * Resets the variables that keep track of the printer's current position. Used
+ * when there's a chance we've lost track of the printer's current position or
+ * done something that may have wiped it out, and we want to force dpost to set
+ * the printer's position before printing text or whatever. For example stroke or
+ * fill implicitly do a newpath, and that wipes out the current point, unless the
+ * calls were bracketed by a gsave/grestore pair.
+ *
+ */
+
+
+ lastx = -(slop + 1);
+ savey = lasty = -1;
+
+} /* End of resetpos */
+
+
+/*****************************************************************************/
+
+
+void
+t_init(void)
+
+
+{
+
+
+ static int initialized = FALSE; /* only do most things once */
+
+
+/*
+ *
+ * Called from devcntrl() after an "x init" command is read. Things only work if
+ * we've already seen the "x res" command, and much of the stuff, including the
+ * call to setup, should only be done once. Restricting everything to one call of
+ * setup (ie. the one in the prologue) means all the input files must have been
+ * formatted for the same device.
+ *
+ */
+
+
+ endtext(); /* moved - for cat'ed troff files */
+
+ if ( initialized == FALSE ) { /* only do this stuff once per job */
+ fontinit();
+ gotspecial = FALSE;
+ gotregular = FALSE;
+ widthfac = (float) res /dev.res;
+ if (dev.afmfonts) {
+ if (Sflag == 0)
+ pointslop = 0;
+ }
+ if (eflag == 0)
+ realencoding = encoding = dev.encoding;
+ if (encoding == 5) {
+ LanguageLevel = MAX(LanguageLevel, 2);
+ Binary++;
+ }
+ slop = pointslop * res / POINTS + .5;
+ rvslop = res * .025;
+ setup();
+ initialized = TRUE;
+ } /* End if */
+
+ hpos = vpos = 0; /* upper left corner */
+ setsize(t_size(10), 0); /* start somewhere */
+ reset(); /* force position and font stuff - later */
+
+} /* End of t_init */
+
+
+/*****************************************************************************/
+
+void
+needresource(const char *s, ...)
+{
+ va_list ap;
+
+ if (nfcount++ == 0)
+ fprintf(nf, "%%%%DocumentNeededResources: ");
+ else
+ fprintf(nf, "%%%%+ ");
+ va_start(ap, s);
+ vfprintf(nf, s, ap);
+ va_end(ap);
+ putc('\n', nf);
+}
+
+
+static struct supplylist {
+ struct supplylist *next;
+ char *font;
+ char *file;
+ char *type;
+ int done;
+} *supplylist;
+
+void
+t_supply(char *font) /* supply a font */
+{
+ struct supplylist *sp;
+ char *np, *file, *type = NULL, c;
+
+ while (*font == ' ' || *font == '\t')
+ font++;
+ for (np = font; *np && *np != ' ' && *np != '\t' && *np != '\n'; np++);
+ if (*np == '\0' || *np == '\n')
+ return;
+ *np = '\0';
+ file = &np[1];
+ while (*file == ' ' || *file == '\t')
+ file++;
+ for (np = file; *np && *np != ' ' && *np != '\t' && *np != '\n'; np++);
+ c = *np;
+ *np = '\0';
+ if (c != '\0' && c != '\n') {
+ type = &np[1];
+ while (*type == ' ' || *type == '\t')
+ type++;
+ for (np = type; *np && *np != ' ' &&
+ *np != '\t' && *np != '\n'; np++);
+ *np = '\0';
+ }
+ for (sp = supplylist; sp; sp = sp->next)
+ if (strcmp(sp->font, font) == 0)
+ return;
+ sp = calloc(1, sizeof *sp);
+ sp->font = strdup(font);
+ sp->file = afmdecodepath(file);
+ sp->type = type && *type ? strdup(type) : NULL;
+ sp->next = supplylist;
+ supplylist = sp;
+}
+
+static unsigned long
+ple32(const char *cp)
+{
+ return (unsigned long)(cp[0]&0377) +
+ ((unsigned long)(cp[1]&0377) << 8) +
+ ((unsigned long)(cp[2]&0377) << 16) +
+ ((unsigned long)(cp[3]&0377) << 24);
+}
+
+static const char ps_adobe_font_[] = "%!PS-AdobeFont-";
+static const char ps_truetypefont[] = "%!PS-TrueTypeFont";
+static const char hex[] = "0123456789abcdef";
+
+static void
+supplypfb(char *font, char *path, FILE *fp)
+{
+ char buf[30];
+ long length;
+ int i, c = EOF, n, type = 0, lastc = EOF;
+
+ if (fread(buf, 1, 6, fp) != 6)
+ error(FATAL, "no data in %s", path);
+ if ((buf[0]&0377) != 0200 || (type = buf[1]) != 1)
+ error(FATAL, "invalid header in %s", path);
+ length = ple32(&buf[2]);
+ n = 0;
+ while (ps_adobe_font_[n] && --length > 0 && (c = getc(fp)) != EOF) {
+ if (c != ps_adobe_font_[n++])
+ error(FATAL, "file %s does not start with \"%s\"",
+ path, ps_adobe_font_);
+ }
+ while (--length > 0 && (c = getc(fp)) != EOF && c != '\r' && c != '\n');
+ if (c != '\n') {
+ if ((c = getc(fp)) != '\n')
+ ungetc(c, fp);
+ else
+ length--;
+ }
+ if (sfcount++ == 0)
+ fprintf(sf, "%%%%DocumentSuppliedResources: font %s\n", font);
+ else
+ fprintf(sf, "%%%%+ font %s\n", font);
+ fprintf(rf, "%%%%BeginResource: font %s\n", font);
+ for (;;) {
+ switch (type) {
+ case 1:
+ while (length > 0 && (c = getc(fp)) != EOF) {
+ length--;
+ switch (c) {
+ case '\r':
+ if ((c = getc(fp)) != '\n')
+ ungetc(c, fp);
+ else
+ length--;
+ putc('\n', rf);
+ lastc = '\n';
+ break;
+ case 0:
+ continue;
+ default:
+ putc(c, rf);
+ lastc = c;
+ }
+ }
+ if (c == EOF)
+ error(FATAL, "short text data in %s", path);
+ break;
+ case 2:
+ while (length) {
+ n = length > sizeof buf ? sizeof buf : length;
+ if (fread(buf, 1, n, fp) != n)
+ error(FATAL, "short binary data in %s", path);
+ for (i = 0; i < n; i++) {
+ putc(hex[(buf[i]&0360)>>4], rf);
+ putc(hex[buf[i]&017], rf);
+ }
+ putc('\n', rf);
+ lastc = '\n';
+ length -= n;
+ }
+ break;
+ case 3:
+ if (lastc != '\n')
+ putc('\n', rf);
+ fprintf(rf, "%%%%EndResource\n");
+ fclose(fp);
+ return;
+ default:
+ error(FATAL, "invalid header type %d in %s", path, type);
+ }
+ if ((n = fread(buf, 1, 6, fp)) != 6 && (buf[1] != 3 || n < 2))
+ error(FATAL, "missing header in %s", path);
+ if ((buf[0]&0377) != 0200)
+ error(FATAL, "invalid header in %s", path);
+ if ((type = buf[1]) != 3)
+ length = ple32(&buf[2]);
+ }
+}
+
+static void
+supplyotf(char *font, char *path, FILE *fp)
+{
+ static int cffcount;
+ struct stat st;
+ char *contents;
+ size_t size, offset, length;
+ int i;
+ int fsType;
+ const char StartData[] = " StartData ";
+
+ if (fstat(fileno(fp), &st) < 0)
+ error(FATAL, "cannot stat %s", path);
+ size = st.st_size;
+ contents = malloc(size);
+ if (fread(contents, 1, size, fp) != size)
+ error(FATAL, "cannot read %s", path);
+ fclose(fp);
+ if ((fsType = otfcff(path, contents, size, &offset, &length)) < 0) {
+ free(contents);
+ return;
+ }
+ /*
+ * Adobe Technical Note #5176, "The Compact Font Format
+ * Specification", Version 1.0, 12/4/2003, p. 53 proposes
+ * a weird syntax for CFF DSC comments ("ProcSet" etc.);
+ * Adobe Distiller 7 complains about it with DSC warnings
+ * enabled. What follows is an attempt to fix this.
+ */
+ if (cffcount++ == 0) {
+ fprintf(rf, "%%%%IncludeResource: procset FontSetInit 0 0\n");
+ needresource("procset FontSetInit 0 0");
+ }
+ if (sfcount++ == 0)
+ fprintf(sf, "%%%%DocumentSuppliedResources: font %s\n", font);
+ else
+ fprintf(sf, "%%%%+ font %s\n", font);
+ fprintf(rf, "%%%%BeginResource: font %s\n", font);
+ fprintf(rf, "/FontSetInit /ProcSet findresource begin\n");
+ if (encoding == 5) {
+ fprintf(rf, "%%%%BeginData: %ld Binary Bytes\n",
+ (long)(length + 13 + strlen(font) + 12));
+ fprintf(rf, "/%s %12ld StartData ", font, (long)length);
+ fwrite(&contents[offset], 1, length, rf);
+ fprintf(rf, "\n%%%%EndData\n");
+ } else {
+ fprintf(rf, "/%s %ld ", font, (long)length);
+ fprintf(rf, "currentfile /ASCIIHexDecode filter cvx exec\n");
+ for (i = 0; StartData[i]; i++) {
+ putc(hex[(StartData[i]&0360)>>4], rf);
+ putc(hex[StartData[i]&017], rf);
+ }
+ putc('\n', rf);
+ for (i = offset; i < offset+length; i++) {
+ putc(hex[(contents[i]&0360)>>4], rf);
+ putc(hex[contents[i]&017], rf);
+ if (i > offset && (i - offset + 1) % 34 == 0)
+ putc('\n', rf);
+ }
+ fprintf(rf, ">\n");
+ }
+ fprintf(rf, "%%%%EndResource\n");
+ free(contents);
+ LanguageLevel = MAX(LanguageLevel, 3);
+}
+
+static void
+supplyttf(char *font, char *path, FILE *fp)
+{
+ struct stat st;
+ char *contents;
+ size_t size;
+
+ if (fstat(fileno(fp), &st) < 0)
+ error(FATAL, "cannot stat %s", path);
+ size = st.st_size;
+ contents = malloc(size);
+ if (fread(contents, 1, size, fp) != size)
+ error(FATAL, "cannot read %s", path);
+ fclose(fp);
+ if (sfcount++ == 0)
+ fprintf(sf, "%%%%DocumentSuppliedResources: font %s\n", font);
+ else
+ fprintf(sf, "%%%%+ font %s\n", font);
+ fprintf(rf, "%%%%BeginResource: font %s\n", font);
+ otft42(font, path, contents, size, rf);
+ fprintf(rf, "%%%%EndResource\n");
+ free(contents);
+ LanguageLevel = MAX(LanguageLevel, 2);
+}
+
+static void
+supply1(char *font, char *file, char *type)
+{
+ FILE *fp;
+ char line[4096], c;
+
+ if (strchr(file, '/') == 0) {
+ snprintf(temp, sizeof temp, "%s/dev%s/%s.%s",
+ fontdir, devname, file, type);
+ file = temp;
+ }
+ if ((fp = fopen(file, "r")) == NULL)
+ error(FATAL, "can't open %s", file);
+ if (type == NULL) {
+ c = getc(fp);
+ ungetc(c, fp);
+ type = c == '\200' ? "pfb" : c == 'O' ? "otf" :
+ c == 0 || c == 't' ? "ttf" : "anything";
+ }
+ if (strcmp(type, "pfb") == 0) {
+ supplypfb(font, file, fp);
+ return;
+ }
+ if (strcmp(type, "otf") == 0) {
+ supplyotf(font, file, fp);
+ return;
+ }
+ if (strcmp(type, "ttf") == 0) {
+ supplyttf(font, file, fp);
+ return;
+ }
+ if (fgets(line, sizeof line, fp) == NULL)
+ error(FATAL, "missing data in %s", file);
+ if (strncmp(line, ps_adobe_font_, strlen(ps_adobe_font_)) &&
+ strncmp(line, ps_truetypefont, strlen(ps_truetypefont)))
+ error(FATAL, "file %s does not start with \"%s\" or \"%s\"",
+ file, ps_adobe_font_, ps_truetypefont);
+ if (sfcount++ == 0)
+ fprintf(sf, "%%%%DocumentSuppliedResources: font %s\n", font);
+ else
+ fprintf(sf, "%%%%+ font %s\n", font);
+ fprintf(rf, "%%%%BeginResource: font %s\n", font);
+ while (fgets(line, sizeof line, fp) != NULL)
+ fputs(line, rf);
+ fclose(fp);
+ fprintf(rf, "%%%%EndResource\n");
+}
+
+static void
+t_dosupply(const char *font)
+{
+ struct supplylist *sp;
+
+ for (sp = supplylist; sp; sp = sp->next)
+ if (strcmp(sp->font, font) == 0) {
+ if (sp->done == 0) {
+ supply1(sp->font, sp->file, sp->type);
+ sp->done = 1;
+ }
+ return;
+ }
+ needresource("font %s", font);
+}
+
+/*****************************************************************************/
+
+static void
+boxcmp(const char *name, struct box *bp, int a, int b, int c, int d)
+{
+ if (bp->flag && (a != bp->val[0] || b != bp->val[1] ||
+ c != bp->val[2] || d != bp->val[3]))
+ error(NON_FATAL, "%s has changed, using new values", name);
+}
+
+static void
+t_papersize(char *buf)
+{
+ int x, y, setmedia = 0;
+
+ if (sscanf(buf, "%d %d %d", &x, &y, &setmedia) < 2)
+ return;
+ boxcmp("Media size", &mediasize, 0, 0, x, y);
+ mediasize.val[2] = x;
+ mediasize.val[3] = y;
+ mediasize.flag |= 1;
+ if (setmedia)
+ mediasize.flag |= 2;
+ pagelength = y * 72.0 / res;
+}
+
+static void
+t_cutat(const char *name, struct box *bp, char *buf)
+{
+ int c[4], i;
+
+ if (sscanf(buf, "%d %d %d %d", &c[0], &c[1], &c[2], &c[3]) < 4)
+ return;
+ boxcmp(name, bp, c[0], c[1], c[2], c[3]);
+ for (i = 0; i < 4; i++)
+ bp->val[i] = c[i];
+ bp->flag |= 1;
+}
+
+/*****************************************************************************/
+void
+t_page (
+ int pg /* troff's current page number */
+)
+
+
+{
+
+
+ static int lastpg = 0; /* last one we started - for ENDPAGE */
+
+
+/*
+ *
+ * Called whenever we've finished the last page and want to get ready for the
+ * next one. Also used at the end of each input file, so we have to be careful
+ * about what's done. The first time through (up to the redirect(pg) call) output
+ * goes to /dev/null because of the redirect(-1) call made in conv().
+ *
+ * Adobe now recommends that the showpage operator occur after the page level
+ * restore so it can be easily redefined to have side-effects in the printer's VM.
+ * Although it seems reasonable I haven't implemented it, because it makes other
+ * things, like selectively setting manual feed or choosing an alternate paper
+ * tray, clumsy - at least on a per page basis.
+ *
+ */
+
+
+ if ( tf == stdout ) /* count the last page */
+ printed++;
+
+ endtext(); /* print the last line? */
+
+ fprintf(tf, "_marks\n");
+ fprintf(tf, "cleartomark\n");
+ fprintf(tf, "showpage\n");
+ fprintf(tf, "restore\n");
+ fprintf(tf, "%s %d %d\n", ENDPAGE, lastpg, printed);
+
+ redirect(pg);
+
+ fprintf(tf, "%s %d %d\n", PAGE, pg, printed+1);
+ fprintf(tf, "save\n");
+ fprintf(tf, "mark\n");
+ writerequest(printed+1, tf);
+ fprintf(tf, "%d pagesetup\n", printed+1);
+ setcolor();
+
+ lastpg = pg; /* for the next ENDPAGE comment */
+ hpos = vpos = 0; /* get ready for the next page */
+ reset(); /* force position and font stuff - later */
+
+ seenpage = TRUE;
+
+} /* End of t_page */
+
+
+/*****************************************************************************/
+
+
+void
+t_newline(void)
+
+
+{
+
+
+/*
+ *
+ * Just finished the last line. All we do is set the horizontal position to 0,
+ * although even that probably isn't necessary.
+ *
+ */
+
+
+ hpos = 0;
+
+} /* End of t_newline */
+
+
+/*****************************************************************************/
+
+
+int
+t_size (
+ int n /* convert this to an internal size */
+)
+
+
+{
+
+
+ int i; /* loop index */
+
+
+/*
+ *
+ * Converts a point size into an internal size that can be used as an index into
+ * pstab[]. The internal size is one plus the index of the least upper bound of
+ * n in pstab[], or nsizes if n is larger than all the listed sizes.
+ *
+ */
+
+
+ if ( n <= pstab[0] )
+ return(1);
+ else if (n >= pstab[nsizes-1])
+ return(nsizes);
+
+ for ( i = 0; n > pstab[i]; i++ ) ;
+
+ return(i+1);
+
+} /* End of t_size */
+
+
+/*****************************************************************************/
+
+
+void
+setsize (
+ int n, float f /* new internal size */
+)
+
+
+{
+
+
+/*
+ *
+ * Now using internal size n, where pstab[n-1] is the best available approximation
+ * to the size troff asked for.
+ *
+ */
+
+
+ size = n;
+ fractsize = f;
+ lasthorscale = horscale = 1.0;
+
+} /* End of setsize */
+
+
+/*****************************************************************************/
+
+
+void
+t_fp (
+ int n, /* this position */
+ char *s, /* now has this font mounted */
+ char *si, /* its internal number */
+ void *a
+)
+
+
+{
+
+
+/*
+ *
+ * Updates nfonts and the array that keeps track of the mounted fonts. Called from
+ * loadfont() after an "x font pos font" command is read, and if pos is larger than
+ * the current value assigned to nfonts we set gotspecial to FALSE to make sure
+ * t_font() loads all the special fonts after the last legitimate font position.
+ *
+ */
+
+
+ fontname[n].name = s;
+ fontname[n].number = atoi(si);
+ fontname[n].afm = a;
+
+ if ( n == lastfont ) /* force a call to t_sf() */
+ lastfont = lastsubfont = -1;
+
+ if ( n > nfonts ) { /* got more positions */
+ nfonts = n;
+ gotspecial = FALSE;
+ gotregular = FALSE;
+ } /* End if */
+
+} /* End of t_fp */
+
+
+/*****************************************************************************/
+
+
+int
+t_font (
+ char *s /* use font in this position next */
+)
+
+
+{
+
+
+ int n;
+
+
+/*
+ *
+ * Converts the string *s into an integer and checks to make sure it's a legal
+ * font position. Also arranges to mount all the special fonts after the last
+ * legitimate font (by calling loadspecial()), provided it hasn't already been
+ * done.
+ *
+ */
+
+
+ n = atoi(s);
+
+ if ( seenpage == TRUE ) {
+ if ( n < 0 || n > nfonts )
+ error(FATAL, "illegal font position %d", n);
+
+ if ( gotspecial == FALSE || gotregular == FALSE )
+ loadspecial();
+ } /* End if */
+
+ if (tracked)
+ tracked = -1;
+ track = 0;
+
+ return(n);
+
+} /* End of t_font */
+
+/*****************************************************************************/
+static void
+sethorscale(char *buf)
+{
+ horscale = atof(buf);
+}
+
+/*****************************************************************************/
+static void
+t_track(char *buf)
+{
+ int t;
+
+/*
+ * Handling of track kerning. troff provides this parameter as a hint
+ * only. dpost can use it in combination with the PostScript "ashow"
+ * operator. When the variable "track" is not zero, the printer is
+ * advised to perform tracking by the given amount. This relieves us
+ * of the need to adjust the character position explicitly after each
+ * character and thus greatly reduces the size of the output.
+ *
+ * Currently this is done in encodings 0, 4, and 5 only.
+ */
+
+ if (sscanf(buf, "%d", &t) != 1)
+ t = 0;
+ if (t != lasttrack) {
+ tracked = -1;
+ } else if (t && tracked != -1)
+ tracked = 1;
+ track = t;
+}
+
+static void
+t_strack(void)
+{
+ endtext();
+ fprintf(tf, "%d T\n", track);
+ if (tf == stdout) {
+ tracked = track != 0;
+ lasttrack = track;
+ }
+}
+
+/*****************************************************************************/
+
+
+void
+setfont (
+ int n /* use the font mounted here */
+)
+
+
+{
+
+
+/*
+ *
+ * troff wants to use the font that's been mounted in position n. All we do here
+ * is update the variable that keeps track of the current position. PostScript
+ * font changes are handled in t_sf(), and are only generated right before we're
+ * ready to print or draw something.
+ *
+ */
+
+
+ if ( n < 0 || n > NFONT )
+ error(FATAL, "illegal font %d", n);
+ if ( fontname[n].name == NULL && fontname[n].number == 0)
+ loaddefault();
+ if ( fontname[n].name == NULL && fontname[n].number == 0)
+ error(FATAL,
+ "font %d not loaded: check 'dpost' input for 'x font %d XXX' before 'f%d'",
+ n, n, n);
+
+ font = n;
+ subfont = 0;
+ lasthorscale = horscale = 1.0;
+
+} /* End of setfont */
+
+
+/*****************************************************************************/
+static void
+endvec(struct afmtab *a, int n)
+{
+ fprintf(gf, "] def\n");
+ fprintf(gf, "\
+/%s findfont\n\
+dup length dict begin\n\
+ {1 index /FID ne {def} {pop pop} ifelse} forall\n\
+ /Encoding Encoding-@%s@%d def\n\
+ currentdict\n\
+end\n",
+ a->fontname, a->Font.intname, n);
+ if (a->spec & SPEC_S) {
+ fprintf(gf, "/%s-tmp-@%s", a->fontname, a->Font.intname);
+ if (n) fprintf(gf, "@%d", n);
+ fprintf(gf, " exch definefont pop\n");
+ fprintf(gf, "_Sdefsadj\n");
+ fprintf(gf, "/%s-tmp-@%s", a->fontname, a->Font.intname);
+ if (n) fprintf(gf, "@%d", n);
+ fprintf(gf, " /%s-@%s", a->fontname, a->Font.intname);
+ if (n) fprintf(gf, "@%d", n);
+ fprintf(gf, " Sdefs cf\n");
+ fprintf(gf, "/%s-tmp-@%s", a->fontname, a->Font.intname);
+ if (n) fprintf(gf, "@%d", n);
+ fprintf(gf, " undefinefont\n");
+ } else if (a->spec & SPEC_S1) {
+ fprintf(gf, "/%s-tmp-@%s", a->fontname, a->Font.intname);
+ if (n) fprintf(gf, "@%d", n);
+ fprintf(gf, " exch definefont pop\n");
+ fprintf(gf, "/%s-tmp-@%s", a->fontname, a->Font.intname);
+ if (n) fprintf(gf, "@%d", n);
+ fprintf(gf, " /%s-@%s", a->fontname, a->Font.intname);
+ if (n) fprintf(gf, "@%d", n);
+ fprintf(gf, " S1defs cf\n");
+ fprintf(gf, "/%s-tmp-@%s", a->fontname, a->Font.intname);
+ if (n) fprintf(gf, "@%d", n);
+ fprintf(gf, " undefinefont\n");
+ } else if (n)
+ fprintf(gf, "/%s-@%s@%d exch definefont pop\n",
+ a->fontname, a->Font.intname, n);
+ else
+ fprintf(gf, "/%s-@%s exch definefont pop\n",
+ a->fontname, a->Font.intname);
+ fprintf(gf, "/@%s", a->Font.intname);
+ if (n)
+ fprintf(gf, "@%d", n);
+ fprintf(gf, " /%s-@%s", a->fontname, a->Font.intname);
+ if (n)
+ fprintf(gf, "@%d", n);
+ fprintf(gf, " def\n");
+ fprintf(gf, "/&%s", a->Font.intname);
+ if (n)
+ fprintf(gf, "@%d", n);
+ fprintf(gf, " {@%s", a->Font.intname);
+ if (n)
+ fprintf(gf, "@%d", n);
+ fprintf(gf, " F} bind def\n");
+}
+
+static void
+printencsep(int *colp)
+{
+ if (*colp >= 60) {
+ putc('\n', gf);
+ *colp = 0;
+ } else {
+ putc(' ', gf);
+ (*colp)++;
+ }
+}
+
+static int *
+printencvector(struct afmtab *a)
+{
+ int i, j, k, n, col = 0, s;
+ int *encmap = NULL;
+
+ fprintf(gf, "/Encoding-@%s@0 [\n", a->Font.intname);
+ col = 0;
+ /*
+ * First, write excess entries into the positions from 1 to 31
+ * for later squeezing of characters >= 0400.
+ */
+ s = 128 - 32;
+ encmap = calloc(256 + nchtab + a->nchars, sizeof *encmap);
+ col += fprintf(gf, "/.notdef");
+ printencsep(&col);
+ for (j = 1; j < 32; j++) {
+ while (s < a->nchars + 128 - 32 + nchtab &&
+ ((k = a->fitab[s]) == 0 ||
+ a->nametab[k] == NULL))
+ s++;
+ if (s < a->nchars + 128 - 32 + nchtab &&
+ (k = a->fitab[s]) != 0 &&
+ k < a->nchars &&
+ a->nametab[k] != NULL) {
+ encmap[s - 128 + 32] = j;
+ col += fprintenc(gf, a->nametab[k]);
+ printencsep(&col);
+ s++;
+ } else {
+ col += fprintf(gf, "/.notdef");
+ printencsep(&col);
+ }
+ }
+ col += fprintf(gf, "/space");
+ printencsep(&col);
+ for (i = 1; i < a->nchars + 128 - 32 + nchtab && i < 256 - 32; i++) {
+ if (i < 128 - 32 && (k = a->fitab[i]) != 0 && k < a->nchars &&
+ a->nametab[k] != NULL) {
+ col += fprintenc(gf, a->nametab[k]);
+ printencsep(&col);
+ } else {
+ while (s < a->nchars + 128 - 32 + nchtab &&
+ ((k = a->fitab[s]) == 0 ||
+ a->nametab[k] == NULL))
+ s++;
+ if (s < a->nchars + 128 - 32 + nchtab &&
+ (k = a->fitab[s]) != 0 &&
+ k < a->nchars &&
+ a->nametab[k] != NULL) {
+ encmap[s - 128 + 32] = i + 32;
+ col += fprintenc(gf, a->nametab[k]);
+ printencsep(&col);
+ s++;
+ } else {
+ col += fprintf(gf, "/.notdef");
+ printencsep(&col);
+ }
+ }
+ }
+ endvec(a, 0);
+ n = 1;
+ while (s < a->nchars + 128 - 32 + nchtab) {
+ fprintf(gf, "/Encoding-@%s@%d [\n", a->Font.intname, n);
+ col = 0;
+ for (i = 0; i < 256; i++) {
+ while (s < a->nchars + 128 - 32 + nchtab &&
+ ((k = a->fitab[s]) == 0 ||
+ a->nametab[k] == NULL))
+ s++;
+ if (s < a->nchars + 128 - 32 + nchtab &&
+ (k = a->fitab[s]) != 0 &&
+ k < a->nchars &&
+ a->nametab[k] != NULL) {
+ encmap[s - 128 + 32] = i | n << 8;
+ col += fprintenc(gf, a->nametab[k]);
+ printencsep(&col);
+ s++;
+ } else {
+ col += fprintf(gf, "/.notdef");
+ printencsep(&col);
+ }
+ }
+ endvec(a, n++);
+ }
+ return encmap;
+}
+/*****************************************************************************/
+
+
+void
+t_sf(int forceflush)
+
+
+{
+
+
+ int fnum; /* internal font number */
+ int cmd; /* command to execute */
+
+
+/*
+ *
+ * Called whenever we need to use a new font or size. Only done right before we
+ * print a character. The seenfonts[] array keeps track of the fonts we've used.
+ * Helps manage host resident fonts and the DOCUMENTFONTS comment that's put out
+ * at the end of the job. The array is indexed by internal number. Only works for
+ * fonts that have internal numbers less than or equal to MAXINTERNAL.
+ *
+ */
+
+
+ if ( fontname[font].name == NULL )
+ return;
+
+ endtext();
+
+ if ( (fnum = fontname[font].number) > MAXINTERNAL || fnum < 0 )
+ fnum = 0;
+
+ if ( fnum > 0 && seenfonts[fnum] == 0 && hostfontdir != NULL ) {
+ snprintf(temp, sizeof temp, "%s/%s", hostfontdir, fontname[font].name);
+ if ( access(temp, 04) == 0 )
+ doglobal(temp);
+ } /* End if */
+
+ cmd = 'f';
+ if (forceflush == 0) {
+ if (font == lastfont && subfont == lastsubfont)
+ cmd = 's';
+ else if (size == lastsize && fractsize == lastfractsize)
+ cmd = 'F';
+ }
+ if (horscale != 1.0)
+ cmd = 'h';
+ if ( tf == stdout ) {
+ lastfont = font;
+ lastsubfont = subfont;
+ lastsize = size;
+ lastfractsize = fractsize;
+ lasthorscale = horscale;
+ if ( seenfonts[fnum] == 0 ) {
+ documentfonts();
+ }
+ if (fontname[font].afm && fontname[font].afm->encmap == NULL)
+ fontname[font].afm->encmap = printencvector(fontname[font].afm);
+ seenfonts[fnum] = 1;
+ } /* End if */
+
+ if (cmd == 'f' || cmd == 's' || cmd == 'h') {
+ if (size != FRACTSIZE)
+ fprintf(tf, "%d ", pstab[size-1]);
+ else
+ fprintf(tf, "%g ", (double)fractsize);
+ }
+ if (fontname[font].afm && cmd == 'F') {
+ if (subfont)
+ fprintf(tf, "&%s@%d\n", fontname[font].afm->Font.intname, subfont);
+ else
+ fprintf(tf, "&%s\n", fontname[font].afm->Font.intname);
+ cmd = 0;
+ } else if (cmd == 'f' || cmd == 'F' || cmd == 'h') {
+ if (fontname[font].afm && subfont)
+ fprintf(tf, "@%s@%d ", fontname[font].afm->Font.intname, subfont);
+ else if (fontname[font].afm)
+ fprintf(tf, "@%s ", fontname[font].afm->Font.intname);
+ else
+ fprintf(tf, "%s ", fontname[font].name);
+ }
+ if (cmd == 'h')
+ fprintf(tf, "%g ", horscale);
+ if (cmd)
+ fprintf(tf, "%c\n", cmd);
+
+ if ( fontname[font].fontheight != 0 || fontname[font].fontslant != 0 ) {
+ if (size != FRACTSIZE)
+ fprintf(tf, "%d %g changefont\n", fontname[font].fontslant, (fontname[font].fontheight != 0) ? (double)fontname[font].fontheight : pstab[size-1]);
+ else
+ fprintf(tf, "%d %g changefont\n", fontname[font].fontslant, (fontname[font].fontheight != 0) ? (double)fontname[font].fontheight : (double)fractsize);
+ }
+
+ if (tracked < 0 || tracked > 0 && forceflush)
+ t_strack();
+
+} /* End of t_sf */
+
+
+/*****************************************************************************/
+
+
+void
+t_charht (
+ int n, float f /* use this as the character height */
+)
+
+
+{
+
+
+/*
+ *
+ * Remembers the requested height, from 'x H n'. Forces a call to t_sf(), which
+ * is where the real work is done, by setting lastfont to -1.
+ *
+ */
+
+ if (n == FRACTSIZE)
+ fontname[font].fontheight = f;
+ else
+ fontname[font].fontheight = (n == pstab[size-1]) ? 0 : n;
+ lastfont = lastsubfont = -1;
+
+} /* End of t_charht */
+
+
+/*****************************************************************************/
+
+
+void
+t_slant (
+ int n /* slant characters this many degrees */
+)
+
+
+{
+
+
+/*
+ *
+ * Remembers the requested slant, from 'x X n'. Forces a call to t_sf(), which
+ * is where the real work is done, by setting lastfont to -1.
+ *
+ */
+
+ fontname[font].fontslant = n;
+ lastfont = lastsubfont = -1;
+
+} /* End of t_slant */
+
+/*****************************************************************************/
+
+
+void
+t_reset (
+ int c /* pause or restart */
+)
+
+
+{
+
+
+/*
+ *
+ * Found an "x stop" or "x pause" command. Although nothing's done here we could
+ * add code to reset everything so dpost could handle multiple files formatted for
+ * different devices.
+ *
+ */
+
+
+} /* End of t_reset */
+
+
+/*****************************************************************************/
+
+
+void
+t_trailer(void)
+
+
+{
+
+
+/*
+ *
+ * Called after we find an "x trailer" in the input file. Forcing out the last
+ * page is done at the end of conv(), but probably belongs here.
+ *
+ */
+
+
+ endtext();
+
+} /* End of t_trailer */
+
+
+/*****************************************************************************/
+
+
+void
+hgoto (
+ int n /* new horizontal position */
+)
+
+
+{
+
+
+/*
+ *
+ * Want to be at this absolute horizontal position next. Actual motion commands
+ * are generated in oput(), charlib(), and the drawing routines.
+ *
+ */
+
+
+ hpos = n;
+
+} /* End of hgoto */
+
+
+/*****************************************************************************/
+
+
+void
+hmot (
+ int n /* move this far horizontally */
+)
+
+
+{
+
+
+/*
+ *
+ * Handles relative horizontal motion. troff's current positon, as recorded in
+ * in hpos, is changed by n units. Usually called right before we're supposed to
+ * print a character.
+ *
+ */
+
+
+ hpos += n;
+
+} /* End of hmot */
+
+
+/*****************************************************************************/
+
+
+void
+vgoto (
+ int n /* new vertical position */
+)
+
+
+{
+
+
+/*
+ *
+ * Moves vertically in troff's coordinate system to absolute position n.
+ *
+ */
+
+
+ vpos = n;
+
+} /* End of vgoto */
+
+
+/*****************************************************************************/
+
+
+void
+vmot (
+ int n /* move this far vertically */
+)
+
+
+{
+
+
+/*
+ *
+ * Handles relative vertical motion of n units in troff's coordinate system.
+ *
+ */
+
+
+ vpos += n;
+
+} /* End of vmot */
+
+
+/*****************************************************************************/
+
+
+void
+xymove (
+ int x,
+ int y /* this is where we want to be */
+)
+
+
+{
+
+
+/*
+ *
+ * Makes sure the post-processor and printer agree about the current position.
+ *
+ */
+
+
+ hgoto(x);
+ vgoto(y);
+
+ fprintf(tf, "%d %d m\n", hpos, vpos);
+
+ lastx = hpos;
+ savey = lasty = vpos;
+
+} /* End of xymove */
+
+
+/*****************************************************************************/
+
+
+void
+put1s (
+ register char *s /* find and print this character */
+)
+
+
+{
+
+
+ static int i = 0; /* last one we found - usually */
+
+
+/*
+ *
+ * *s points to the start of a two character string that represents one of troff's
+ * special characters. To print it we first look for *s in the chname[] array using
+ * chtab[i] to find the string representing character i in chname[]. If the lookup
+ * is successful we add 128 to i and ask put1() to finish printing the character.
+ * We remember the index where the last character was found because requests to
+ * print a special character often come in bunches (eg. drawing lines with \(ru).
+ *
+ */
+
+
+ if (s[0] == 'P' && s[1] == 'S' && s[2] != 0) { /* PostScript name */
+ int m;
+ struct namecache *np;
+ struct afmtab *a;
+ if ((a = fontname[font].afm) != NULL &&
+ (np = afmnamelook(a, &s[2])) != NULL &&
+ ((m = np->fival[0]) != NOCODE ||
+ (m = np->fival[1]) != NOCODE)) {
+ put1(m+32);
+ return;
+ }
+ }
+ if ( strcmp(s, &chname[chtab[i]]) != 0 )
+ for ( i = 0; i < nchtab; i++ )
+ if ( strcmp(&chname[chtab[i]], s) == 0 )
+ break;
+
+ if ( i < nchtab )
+ put1(i + 128);
+ else i = 0;
+
+} /* End of put1s */
+
+
+/*****************************************************************************/
+
+
+void
+put1 (
+ register int c /* want to print this character */
+)
+
+
+{
+
+
+ register int i = 0; /* character code from fitab */
+ register int j; /* number of fonts we've checked so far */
+ register int k; /* font we're currently looking at */
+ int *pw = NULL; /* font widthtab and */
+ unsigned short *p = NULL; /* and codetab where c was found */
+ int code; /* code used to get c printed */
+ int ofont; /* font when we started */
+
+
+/*
+ *
+ * Arranges to have character c printed. If c < 128 it's a simple ASCII character,
+ * otherwise it's a special character. Things done here have to agree with the way
+ * the font tables were built by makedev, and work as follows. First we subtract
+ * 32 from c because the tables don't record the non-graphic ASCII characters.
+ * If fitab[k][c] isn't zero the character is on font k and the value is an index
+ * that can be used to recover width and character code data from the other two
+ * tables. If fitab[k][c] is zero the character isn't defined on font k and we
+ * check the next font, which is found as follows. The current font is the first
+ * one we check, and it's followed by a circular search of all the remaining fonts
+ * that starts with the first special font and skips font position 0. If character
+ * c is found somewhere besides the current font we change to that font and use
+ * fitab[k][c] to locate missing data in the other two tables. The width of the
+ * character can be found at fontab[k][c] while codetab[k][c] is whatever we
+ * need to tell the printer to have character c printed. lastc records the real
+ * name of the character because it's lost by the time oput() gets called but
+ * charlib() may need it.
+ *
+ * Took all the debugging stuff out because at least this part of the program is
+ * reasonably solid.
+ *
+ */
+
+
+ lastc = c; /* charlib() needs the name not the code */
+ if ( (c -= 32) <= 0 ) /* probably never happens */
+ return;
+
+ k = ofont = font;
+
+ if ( fitab[k] && (i = fitab[k][c]) != 0 ) { /* it's on this font */
+ p = codetab[font];
+ pw = fontab[font];
+ } else if ( smnt > 0 ) { /* on special (we hope) */
+ for ( k=smnt, j=0; j <= nfonts; j++, k = (k+1) % (nfonts+1) ) {
+ if ( k == 0 ) continue;
+ if ( fitab[k] && (i = fitab[k][c]) != 0 ) {
+ p = codetab[k];
+ pw = fontab[k];
+ setfont(k);
+ break;
+ } /* End if */
+ } /* End for */
+ } /* End else */
+
+ lastw = 0;
+ if ( i != 0 && (code = p[i]) != 0 ) {
+ if (size != FRACTSIZE)
+ lastw = horscale * widthfac * ((pw[i] * pstab[size-1] + unitwidth/2) / unitwidth);
+ else
+ lastw = horscale * widthfac * (int)((pw[i] * fractsize + unitwidth/2) / unitwidth);
+ if (widthfac == 1) /* ignore fractional parts since troff */
+ lastw = (int)lastw; /* does the same */
+ if (track && encoding != MAXENCODING+2)
+ lastw += track;
+ if (code == NOCODE && fontname[k].afm)
+ code = c + 32;
+ oput(code);
+ } /* End if */
+
+ if ( font != ofont )
+ setfont(ofont);
+
+} /* End of put1 */
+
+
+/*****************************************************************************/
+
+
+static void
+oprep(int stext)
+{
+ if ( textcount > MAXSTACK ) /* don't put too much on the stack? */
+ endtext();
+
+ if ( font != lastfont || size != lastsize || subfont != lastsubfont ||
+ (size == FRACTSIZE && fractsize != lastfractsize) ||
+ horscale != lasthorscale) {
+ t_sf(0);
+ }
+ if (tracked < 0)
+ t_strack();
+
+ if ( vpos != lasty )
+ endline();
+
+ if (stext) {
+ starttext();
+
+ if ( ABS(hpos - lastx) > slop )
+ endstring();
+ }
+ wordspace = 0;
+}
+
+
+void
+oput (
+ int c /* want to print this character */
+)
+
+
+{
+
+
+/*
+ *
+ * Arranges to print the character whose code is c in the current font. All the
+ * actual positioning is done here, in charlib(), or in the drawing routines.
+ *
+ */
+
+ if ( asciichar(c) && printchar(c) )
+ switch ( c ) {
+ case '(':
+ case ')':
+ case '\\':
+ if (encoding != 5)
+ addchar('\\');
+
+ default:
+ addchar(c);
+ } /* End switch */
+ else if ( c > 040 )
+ addoctal(c);
+ else charlib(c);
+
+ lastx += lastw;
+
+} /* End of oput */
+
+
+/*****************************************************************************/
+
+
+void
+starttext(void)
+
+
+{
+
+
+/*
+ * Called whenever we want to be sure we're ready to start collecting characters
+ * for the next call to PostScript procedure t (ie. the one that prints them). If
+ * textcount is positive we've already started, so there's nothing to do. The more
+ * complicated encoding schemes save text strings in the strings[] array and need
+ * detailed information about the strings when they're written to the output file
+ * in endtext().
+ *
+ */
+
+
+ if ( textcount < 1 ) {
+ switch ( encoding ) {
+ case 0:
+ case 1:
+ case 4:
+ putc('(', tf);
+ charcount = 1;
+ break;
+
+ case 5:
+ strptr = strings;
+ break;
+
+ case 2:
+ case 3:
+ strptr = strings;
+ spacecount = 0;
+ line[1].str = strptr;
+ line[1].dx = 0;
+ line[1].spaces = 0;
+ line[1].start = hpos;
+ line[1].width = 0;
+ charcount = 0;
+ break;
+
+ case MAXENCODING+1: /* reverse video */
+ if ( lastend == -1 )
+ lastend = hpos;
+ putc('(', tf);
+ charcount = 1;
+ break;
+
+ case MAXENCODING+2: /* follow a funny baseline */
+ putc('(', tf);
+ charcount = 1;
+ break;
+ } /* End switch */
+ textcount = 1;
+ lastx = stringstart = hpos;
+ laststrstart = INT_MIN;
+ } /* End if */
+
+} /* End of starttext */
+
+
+/*****************************************************************************/
+
+
+void
+endtext(void)
+
+
+{
+
+ char buf[STRINGSPACE+100];
+ int i; /* loop index */
+ int n, m;
+
+
+/*
+ *
+ * Generates a call to the PostScript procedure that processes all the text we've
+ * accumulated - provided textcount is positive.
+ *
+ */
+
+ if ( textcount > 0 ) { /* started working on some text */
+ switch ( encoding ) {
+ case 0:
+ fprintf(tf, ")%d t\n", stringstart);
+ break;
+
+ case 4:
+ if (laststrstart != INT_MIN)
+ fprintf(tf, ")%d %d t\n",
+ stringstart - laststrstart, stringstart);
+ else
+ fprintf(tf, ")%d t\n", stringstart);
+ break;
+
+ case 5:
+ putstring(strings, strptr - strings, tf);
+ strptr = strings;
+ if (laststrstart != INT_MIN)
+ putint(stringstart - laststrstart, tf);
+ putint(stringstart, tf);
+ putc('t', tf);
+ putc('\n', tf);
+ break;
+
+
+ case 1:
+ fprintf(tf, ")%d %d t\n", stringstart, lasty);
+ break;
+
+ case 2:
+ *strptr = '\0';
+ line[textcount].width = lastx - line[textcount].start;
+ if ( spacecount != 0 || textcount != 1 ) {
+ n = 0;
+ for ( i = textcount; i > 0; i-- ) {
+ m = snprintf(buf, sizeof buf, "(%s)%d %d",
+ line[i].str, line[i].spaces, line[i].width);
+ if (i < textcount && n + m >= 80) {
+ putc('\n', tf);
+ n = 0;
+ }
+ fputs(buf, tf);
+ n += m;
+ }
+ if (lasty != savey)
+ fprintf(tf, " %d %d %d t\n", textcount, stringstart, lasty);
+ else
+ fprintf(tf, " %d %d u\n", textcount, stringstart);
+ } else {
+ if (lasty != savey)
+ fprintf(tf, "(%s)%d %d w\n", line[1].str, stringstart, lasty);
+ else
+ fprintf(tf, "(%s)%d v\n", line[1].str, stringstart);
+ }
+ savey = lasty;
+ break;
+
+ case 3:
+ *strptr = '\0';
+ if ( spacecount != 0 || textcount != 1 ) {
+ n = 0;
+ for ( i = textcount; i > 0; i-- ) {
+ m = snprintf(buf, sizeof buf, "(%s)%d",
+ line[i].str, line[i].dx);
+ if (i < textcount && n + m >= 80) {
+ putc('\n', tf);
+ n = 0;
+ }
+ fputs(buf, tf);
+ n += m;
+ }
+ if (lasty != savey)
+ fprintf(tf, " %d %d %d t\n", textcount, stringstart, lasty);
+ else
+ fprintf(tf, " %d %d u\n", textcount, stringstart);
+ } else {
+ if (lasty != savey)
+ fprintf(tf, "(%s)%d %d w\n", line[1].str, stringstart, lasty);
+ else
+ fprintf(tf, "(%s)%d v\n", line[1].str, stringstart);
+ }
+ savey = lasty;
+ break;
+
+ case MAXENCODING+1:
+ fprintf(tf, ")%d ", stringstart);
+ fprintf(tf, "%d %d drawrvbox ", lastend - rvslop, (int)(lastx + .5) + rvslop);
+ fprintf(tf, "t\n"/*, stringstart*/);
+ lastend = (lastx + .5) + 2 * rvslop;
+ break;
+
+ case MAXENCODING+2:
+ fprintf(tf, ")%d %d t\n", stringstart, lasty);
+ break;
+ } /* End switch */
+ charcount = 0;
+ } /* End if */
+
+ textcount = 0;
+
+} /* End of endtext */
+
+
+/*****************************************************************************/
+
+
+void
+endstring(void)
+
+
+{
+
+
+ int dx;
+
+
+/*
+ *
+ * Horizontal positions are out of sync. End the last open string, adjust the
+ * printer's position, and start a new string. Assumes we've already started
+ * accumulating text.
+ *
+ */
+
+
+ switch ( encoding ) {
+ case 4:
+ if (laststrstart != INT_MIN)
+ charcount += fprintf(tf, ")%d", stringstart - laststrstart);
+ else {
+ putc(')', tf);
+ charcount++;
+ }
+ laststrstart = stringstart;
+ goto nx;
+
+ case 5:
+ putstring(strings, strptr - strings, tf);
+ strptr = strings;
+ charcount++;
+ if (laststrstart != INT_MIN)
+ charcount += putint(stringstart - laststrstart, tf);
+ laststrstart = stringstart;
+ textcount++;
+ lastx = stringstart = hpos;
+ break;
+
+ case 0:
+ case 1:
+ charcount += fprintf(tf, ")%d", stringstart);
+ nx:
+ if (charcount >= 60) {
+ putc('\n', tf);
+ charcount = 0;
+ }
+ putc('(', tf);
+ charcount++;
+ textcount++;
+ lastx = stringstart = hpos;
+ break;
+
+ case 2:
+ case 3:
+ if (!wordspace) {
+ endtext();
+ starttext();
+ break;
+ }
+ dx = hpos - lastx;
+ if ( spacecount++ == 0 )
+ line[textcount].dx = dx;
+ if ( line[textcount].dx != dx ) {
+ *strptr++ = '\0';
+ line[textcount].width = lastx - line[textcount].start;
+ line[++textcount].str = strptr;
+ *strptr++ = ' ';
+ line[textcount].dx = dx;
+ line[textcount].start = lastx;
+ line[textcount].width = 0;
+ line[textcount].spaces = 1;
+ charcount = 1;
+ } else {
+ *strptr++ = ' ';
+ line[textcount].spaces++;
+ charcount++;
+ } /* End else */
+ lastx += dx;
+ break;
+
+ case MAXENCODING+1:
+ charcount += fprintf(tf, ")%d", stringstart);
+ if (charcount >= 60) {
+ putc('\n', tf);
+ charcount = 0;
+ }
+ putc('(', tf);
+ charcount++;
+ textcount++;
+ lastx = stringstart = hpos;
+ break;
+
+ case MAXENCODING+2:
+ endtext();
+ starttext();
+ break;
+
+ } /* End switch */
+
+} /* End of endstring */
+
+
+/*****************************************************************************/
+
+
+void
+endline(void)
+
+
+{
+
+
+/*
+ *
+ * The vertical position has changed. Dump any accumulated text, then adjust
+ * the printer's vertical position.
+ *
+ */
+
+
+ endtext();
+
+ if ( encoding == 0 || encoding == 4 || encoding == MAXENCODING+1 ) {
+ fprintf(tf, "%d %d m\n", hpos, vpos);
+ savey = vpos;
+ } else if (encoding == 5) {
+ putint(hpos, tf);
+ putint(vpos, tf);
+ putc('m', tf);
+ putc('\n', tf);
+ }
+
+ lastx = stringstart = lastend = hpos;
+ lasty = vpos;
+
+} /* End of endline */
+
+
+/*****************************************************************************/
+
+
+void
+addchar (
+ int c /* next character in current string */
+)
+
+
+{
+
+
+/*
+ *
+ * Does whatever is needed to add character c to the current string.
+ *
+ */
+
+ static int lastc;
+
+ subfont = 0;
+ if (lastc != '\\')
+ oprep(1);
+ lastc = c;
+ switch ( encoding ) {
+ case 0:
+ case 1:
+ case 4:
+ putc(c, tf);
+ if (charcount++ >= 72 && c != '\\') {
+ putc('\\', tf);
+ putc('\n', tf);
+ charcount = 0;
+ }
+ break;
+
+ case 5:
+ *strptr++ = c;
+ break;
+
+ case 2:
+ case 3:
+ *strptr++ = c;
+ if (charcount++ >= 72 && c != '\\') {
+ *strptr++ = '\\';
+ *strptr++ = '\n';
+ charcount = 0;
+ }
+ break;
+
+ case MAXENCODING+1:
+ case MAXENCODING+2:
+ putc(c, tf);
+ if (charcount++ >= 72 && c != '\\') {
+ putc('\\', tf);
+ putc('\n', tf);
+ charcount = 0;
+ }
+ break;
+ } /* End switch */
+
+} /* End of addchar */
+
+
+/*****************************************************************************/
+
+
+void
+addoctal (
+ int c /* add it as an octal escape */
+)
+
+
+{
+
+ int n;
+
+
+/*
+ *
+ * Adds c to the current string as an octal escape \ddd.
+ *
+ *
+ * If c is not a byte, try to squeeze it into the control area.
+ */
+
+
+ oprep(0);
+ if (c >= 128 && fontname[font].afm && fontname[font].afm->encmap) {
+ c = fontname[font].afm->encmap[c - 128];
+ subfont = c >> 8;
+ c &= 0377;
+ } else
+ subfont = 0;
+ oprep(1);
+ switch ( encoding ) {
+ case 0:
+ case 1:
+ case 4:
+ charcount += fprintf(tf, "\\%03o", c);
+ if (charcount >= 72) {
+ putc('\\', tf);
+ putc('\n', tf);
+ charcount = 0;
+ }
+ break;
+
+ case 5:
+ *strptr++ = c;
+ break;
+
+ case 2:
+ case 3:
+ snprintf(strptr, sizeof strings - (strptr - strings), "\\%03o", c);
+ n = strlen(strptr);
+ strptr += n;
+ charcount += n;
+ if (charcount >= 72) {
+ *strptr++ = '\\';
+ *strptr++ = '\n';
+ charcount = 0;
+ }
+ break;
+
+ case MAXENCODING+1:
+ case MAXENCODING+2:
+ charcount += fprintf(tf, "\\%03o", c);
+ if (charcount >= 72) {
+ putc('\\', tf);
+ putc('\n', tf);
+ charcount = 0;
+ }
+ break;
+ } /* End switch */
+
+} /* End of addoctal */
+
+
+/*****************************************************************************/
+
+
+void
+charlib (
+ int code /* either 1 or 2 */
+)
+
+
+{
+
+
+ char *name; /* name of the character */
+ char tname[10]; /* in case it's a single ASCII character */
+ char *filename; /* real file name */
+
+
+/*
+ *
+ * Called from oput() for characters having codes less than 040. Special files
+ * that define PostScript procedures for certain characters can be found in
+ * directory *fontdir/devpost/charlib. If there's a file that has the same name as
+ * the character we're trying to print it's copied to the output file, otherwise
+ * nothing, except some positioning, is done.
+ *
+ * All character definitions are only made once. Subsequent requests to print the
+ * character generate a call to a procedure that begins with the prefix build_ and
+ * ends with the character's name. Special characters that are assigned codes
+ * other than 1 are assumed to have additional data files that should be copied
+ * to the output file immediately after the build_ call. Those data files should
+ * end in the suffix .map, and usually will be a hex representation of a bitmap.
+ *
+ */
+
+
+ subfont = 0;
+ oprep(1);
+ endtext();
+
+ if ( lastc < 128 ) { /* just a simple ASCII character */
+ snprintf(tname, sizeof tname, "%.3o", lastc);
+ name = tname;
+ } else name = &chname[chtab[lastc - 128]];
+
+ /*
+ * This is just a kludge of course. But since only one file exists which
+ * needs a name mapping, no more general method had been implemented.
+ */
+
+ if (*name == 'L' && name[1] == 'H' && !name[2])
+ filename = "LH_uc";
+ else
+ filename = name;
+
+ if ( downloaded[lastc] == 0 ) {
+ snprintf(temp, sizeof temp, "%s/dev%s/charlib/%s",
+ fontdir, realdev, filename);
+ if ( access(temp, 04) == 0 && doglobal(temp) == TRUE ) {
+ downloaded[lastc] = 1;
+ t_sf(0);
+ } /* End if */
+ } /* End if */
+
+ if ( downloaded[lastc] == 1 ) {
+ xymove(hpos, vpos);
+ fprintf(tf, "%d build_%s\n", (int) lastw, name);
+ if ( code != 1 ) { /* get the bitmap or whatever */
+ snprintf(temp, sizeof temp, "%s/dev%s/charlib/%s.map",
+ fontdir, realdev, name);
+ if ( access(temp, 04) == 0 && tf == stdout )
+ cat(temp, tf);
+ } /* End if */
+ fprintf(tf, "%d %d m\n", stringstart = hpos + lastw, vpos);
+ savey = vpos;
+ } /* End if */
+
+} /* End of charlib */
+
+
+/*****************************************************************************/
+
+
+int
+doglobal (
+ char *name /* copy this to the output - globally */
+)
+
+
+{
+
+
+ int val = FALSE; /* returned to the caller */
+
+
+/*
+ *
+ * Copies file *name to the output file and brackets it with whatever commands are
+ * needed to have it exported to the global environment. TRUE is returned if we
+ * successfully add file *name to the output file.
+ *
+ * Actually, all files included this way are procsets, so they go into
+ * the resource section of the PostScript output and not in the global
+ * setup file.
+ *
+ */
+
+
+ if ( tf == stdout ) {
+ val = cat(name, rf);
+ reset();
+ } /* End if */
+
+ return(val);
+
+} /* End of doglobal */
+
+
+/*****************************************************************************/
+
+void
+documentfont(const char *name)
+{
+ static FILE *fp_out; /* PostScript name added to this file */
+ static int pos;
+ static struct fn {
+ struct fn *next;
+ const char *name;
+ } *fn;
+ struct fn *ft;
+ int n;
+
+ if ( temp_file == NULL ) /* generate a temp file name */
+ if ( (temp_file = tempname("dpost")) == NULL )
+ return;
+
+ if ( fp_out == NULL && (fp_out = fopen(temp_file, "w")) == NULL )
+ return;
+ for (ft = fn; ft; ft = ft->next)
+ if (strcmp(name, ft->name) == 0)
+ return;
+ ft = calloc(1, sizeof *ft);
+ ft->name = strdup(name);
+ ft->next = fn;
+ fn = ft;
+ if ( docfonts++ == 0 )
+ pos += fprintf(fp_out, "%s", DOCUMENTFONTS);
+ else {
+ n = strlen(name);
+ if (pos + n >= 80) {
+ fprintf(fp_out, "\n%s", CONTINUECOMMENT);
+ pos = 0;
+ }
+ }
+ pos += fprintf(fp_out, " %s", name);
+ fflush(fp_out);
+ t_dosupply(name);
+}
+
+
+void
+documentfonts(void)
+
+
+{
+
+
+ FILE *fp_in = NULL; /* PostScript font name read from here */
+
+
+/*
+ *
+ * Whenever a new font is used we try to record the appropriate PostScript font
+ * name in *temp_file for the DOCUMENTFONTS comment that's put out in done().
+ * By default PostScript font names are found in /usr/lib/font/devpost. Fonts
+ * that have a .name file are recorded in *temp_file. The first string in that
+ * file is expected to be that font's (long) PostScript name.
+ *
+ */
+
+
+ snprintf(temp, sizeof temp, "%s/dev%s/%s.name",
+ fontdir, realdev, fontname[font].name);
+
+ if (fontname[font].afm == NULL && (fp_in = fopen(temp, "r")) != NULL ) {
+ if ( sget(temp, sizeof temp, fp_in) == 1 ) {
+ documentfont(temp);
+ } /* End if */
+ if (fp_in != NULL)
+ fclose(fp_in);
+ } else if (fontname[font].afm != NULL){
+ documentfont(fontname[font].afm->fontname);
+ } /* End if */
+
+} /* End of documentfonts */
+
+
+/*****************************************************************************/
+
+
+void
+redirect (
+ int pg /* next page we're printing */
+)
+
+
+{
+
+
+ static FILE *fp_null = NULL; /* if output is turned off */
+
+
+/*
+ *
+ * If we're not supposed to print page pg, tf will be directed to /dev/null,
+ * otherwise output goes to stdout.
+ *
+ */
+
+
+ if ( pg >= 0 && in_olist(pg) == ON )
+ tf = stdout;
+ else if ( (tf = fp_null) == NULL )
+ tf = fp_null = fopen("/dev/null", "w");
+
+} /* End of redirect */
+
+
+/*****************************************************************************/
+
+static char *
+mbs2pdf(char *mp)
+{
+ char *ustr, *tp;
+ int c, i, sz;
+#ifdef EUC
+ int n = 0, w;
+ wchar_t wc;
+#endif
+
+ for (tp = mp; *tp && (*tp&~0177) == 0 && *tp&~037; tp++);
+ if (*tp == 0) {
+ ustr = malloc(sz = 16);
+ *ustr = '(';
+ c = i = 1;
+ while (*mp) {
+ switch (*mp) {
+ case '(':
+ case ')':
+ case '\\':
+ ustr[i++] = '\\';
+ c++;
+ /*FALLTHRU*/
+ default:
+ ustr[i++] = *mp++;
+ c++;
+ }
+ if (i + 4 >= sz)
+ ustr = realloc(ustr, sz += 16);
+ if (c >= 60) {
+ ustr[i++] = '\\';
+ ustr[i++] = '\n';
+ c = 0;
+ }
+ }
+ ustr[i++] = ')';
+ ustr[i++] = 0;
+ return ustr;
+ }
+#ifdef EUC
+ ustr = malloc(sz = 16);
+ c = i = snprintf(ustr, sz, "<FEFF");
+ while (mp += n, *mp) {
+ if ((n = mbtowc(&wc, mp, mb_cur_max)) <= 0) {
+ error(NON_FATAL,
+ "illegal byte sequence %d in PDFMark operand",
+ *mp&0377);
+ n = 1;
+ continue;
+ }
+ if (wc < 0 || wc > 0xFFFF) {
+ error(NON_FATAL, "only BMP values allowed for PDFMark");
+ continue;
+ }
+ if (i + 8 >= sz)
+ ustr = realloc(ustr, sz += 16);
+ w = snprintf(&ustr[i], sz - i * sizeof(*ustr), "%04X", (int)wc);
+ i += w;
+ c += w;
+ if (c >= 60) {
+ ustr[i++] = '\n';
+ c = 0;
+ }
+ }
+ ustr[i++] = '>';
+ ustr[i] = 0;
+ return ustr;
+#else /* !EUC */
+ error(NON_FATAL,
+ "this instance of dpost only supports ASCII with PDFMark");
+ return NULL;
+#endif /* !EUC */
+}
+
+static void
+t_pdfmark(char *buf)
+{
+ char *bp, *tp;
+ int n;
+
+ while (spacechar(*buf&0377))
+ buf++;
+ for (bp = buf; *bp && !spacechar(*bp&0377); bp++);
+ *bp++ = '\0';
+ while (spacechar(*bp&0377))
+ bp++;
+ for (tp = bp; *tp; tp++)
+ if (*tp == '\n') {
+ *tp = '\0';
+ break;
+ }
+ if (strcmp(buf, "Author") == 0)
+ Author = mbs2pdf(bp);
+ else if (strcmp(buf, "Title") == 0)
+ Title = mbs2pdf(bp);
+ else if (strcmp(buf, "Subject") == 0)
+ Subject = mbs2pdf(bp);
+ else if (strcmp(buf, "Keywords") == 0)
+ Keywords = mbs2pdf(bp);
+ else if (strcmp(buf, "Bookmark") == 0 ||
+ strcmp(buf, "BookmarkClosed") == 0) {
+ n = strtol(bp, &bp, 10);
+ while (spacechar(*bp&0377))
+ bp++;
+ if (n < 0 || n > MAXBOOKMARKLEVEL) {
+ error(NON_FATAL, "invalid PDFMark Bookmark level %d,"
+ "maximum is %d\n",
+ n, MAXBOOKMARKLEVEL);
+ return;
+ }
+ Bookmarks = realloc(Bookmarks, ++nBookmarks*sizeof *Bookmarks);
+ Bookmarks[nBookmarks-1].level = n;
+ Bookmarks[nBookmarks-1].Title = mbs2pdf(bp);
+ Bookmarks[nBookmarks-1].title = strdup(bp);
+ Bookmarks[nBookmarks-1].Count = 0;
+ Bookmarks[nBookmarks-1].closed =
+ strcmp(buf, "BookmarkClosed") == 0;
+ endtext();
+ fprintf(tf, "[ /Dest /Bookmark$%ld\n"
+ " /View [/XYZ -4 %g 0]\n"
+ "/DEST pdfmark\n",
+ (long)nBookmarks - 1,
+ pagelength - (lasty >= 0 ? vpos * 72.0 / res : -4));
+ } else
+ error(NON_FATAL, "unknown PDFMark attribute %s", buf);
+}
+
+static void
+orderbookmarks(void)
+{
+
+ int counts[MAXBOOKMARKLEVEL+1];
+ int refs[MAXBOOKMARKLEVEL+1];
+ int i, j, k, t;
+ int lvl = 0;
+
+/*
+ * Generate the Count parameter from the given levels.
+ */
+
+ memset(&counts, 0, sizeof counts);
+ for (i = 0; i <= MAXBOOKMARKLEVEL; i++)
+ refs[i] = -1;
+ for (i = 0; i <= nBookmarks; i++) {
+ k = i < nBookmarks ? Bookmarks[i].level : 0;
+ if (i == nBookmarks || k <= lvl) {
+ for (j = k+1; j <= MAXBOOKMARKLEVEL; j++) {
+ t = j - 1;
+ if (refs[t] >= 0) {
+ Bookmarks[refs[t]].Count += counts[j];
+ refs[t] = -1;
+ }
+ counts[j] = 0;
+ }
+ }
+ if (k > 0 && refs[k-1] < 0) {
+ while (k > 0 && refs[k-1] < 0)
+ k--;
+ error(NON_FATAL, "PDFMark Bookmark \"%s\" at level %d "
+ "has no direct parent, "
+ "using level %d\n",
+ Bookmarks[i].title, Bookmarks[i].level, k);
+ }
+ counts[k]++;
+ refs[k] = i;
+ lvl = k;
+ }
+}
+
+static void
+t_locale(char *lp)
+{
+ static char *savlp;
+
+ if (savlp && strcmp(lp, savlp) == 0)
+ return;
+ free(savlp);
+ savlp = malloc(strlen(lp) + 1);
+ sscanf(lp, "%s", savlp);
+ setlocale(LC_CTYPE, savlp);
+ mb_cur_max = MB_CUR_MAX;
+}
+
+static void
+pref(const char *lp, FILE *fp)
+{
+ int c;
+
+ while ((c = *lp++ & 0377) != 0 && c != '\n') {
+ if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z'))
+ putc(c, fp);
+ else
+ fprintf(fp, "$%2x", c);
+ }
+}
+
+static void
+pref_uri(const char *lp, FILE *fp)
+{
+ int c;
+
+ /* Don't do any escaping here to avoid double-escaping. */
+ while ((c = *lp++ & 0377) != 0 && c != '\n') {
+ putc(c, fp);
+ }
+}
+
+static void
+t_anchor(char *lp)
+{
+ int v;
+
+ v = strtol(lp, &lp, 10);
+ if ((lp = strchr(lp, ' ')) != NULL) {
+ lp++;
+ endtext();
+ fprintf(tf, "[ /Dest /Anchor$");
+ pref(lp, tf);
+ fprintf(tf, "\n"
+ " /View [/XYZ -4 %g 0]\n"
+ "/DEST pdfmark\n",
+ pagelength - (v >= 0 ? v * 72.0 / res : -4));
+ }
+}
+
+static char linkcolor[60] = "0 0 1";
+static char linkborder[60] = "0 0 1";
+
+static char *
+t_linkborderstyle(char *arg) {
+ char c, *s;
+ s = arg;
+ for (s = arg; (c = *s) && c != '\n'; s++);
+ *s = 0;
+ return strdup(arg);
+}
+
+static void
+t_link(char *lp)
+{
+ int llx, lly, urx, ury;
+
+ llx = strtol(lp, &lp, 10);
+ if (*lp) {
+ while (*lp == ',')
+ lp++;
+ lly = strtol(lp, &lp, 10);
+ if (*lp) {
+ while (*lp == ',')
+ lp++;
+ urx = strtol(lp, &lp, 10);
+ if (*lp) {
+ while (*lp == ',')
+ lp++;
+ ury = strtol(lp, &lp, 10);
+ if ((lp = strchr(lp, ' ')) != NULL) {
+ lp++;
+ endtext();
+ fprintf(tf, "[ /Dest /Anchor$");
+ pref(lp, tf);
+ fprintf(tf, "\n"
+ "/Rect [%d %d %d %d]\n"
+ "/Color [%s]\n",
+ llx, -lly, urx, -ury, linkcolor);
+ if (linkborderstyle)
+ fprintf(tf, "/BS << %s >>\n", linkborderstyle);
+ else
+ fprintf(tf, "/Border [%s]\n", linkborder);
+ fprintf(tf,
+ "/Subtype /Link\n"
+ "/ANN pdfmark\n");
+ }
+ }
+ }
+ }
+}
+
+static void
+t_linkcolor(char *lp)
+{
+ float r, g, b;
+
+ r = strtod(lp, &lp);
+ g = strtod(lp, &lp);
+ b = strtod(lp, &lp);
+ snprintf(linkcolor, sizeof linkcolor, "%g %g %g", r, g, b);
+}
+
+static void
+t_linkborder(char *lp)
+{
+ float bx, by, c;
+
+ bx = strtod(lp, &lp);
+ by = strtod(lp, &lp);
+ c = strtod(lp, &lp);
+ snprintf(linkborder, sizeof linkborder, "%g %g %g", bx, by, c);
+ free(linkborderstyle);
+ linkborderstyle = NULL;
+}
+
+static char ulinkcolor[60] = "0 0 1";
+static char ulinkborder[60] = "0 0 1";
+
+static void
+t_ulink(char *lp)
+{
+ int llx, lly, urx, ury;
+
+ llx = strtol(lp, &lp, 10);
+ if (*lp) {
+ while (*lp == ',')
+ lp++;
+ lly = strtol(lp, &lp, 10);
+ if (*lp) {
+ while (*lp == ',')
+ lp++;
+ urx = strtol(lp, &lp, 10);
+ if (*lp) {
+ while (*lp == ',')
+ lp++;
+ ury = strtol(lp, &lp, 10);
+ if ((lp = strchr(lp, ' ')) != NULL) {
+ lp++;
+ endtext();
+ fprintf(tf, "[ /Rect [%d %d %d %d]\n"
+ "/Color [%s]\n",
+ llx, -lly, urx, -ury, ulinkcolor);
+ if (ulinkborderstyle)
+ fprintf(tf, "/BS << %s >>\n", ulinkborderstyle);
+ else
+ fprintf(tf, "/Border [%s]\n", ulinkborder);
+ fprintf(tf, "/Action << /Subtype /URI\n"
+ "/URI (");
+ pref_uri(lp, tf);
+ fprintf(tf, ") >>\n"
+ "/Subtype /Link\n"
+ "/ANN pdfmark\n");
+ }
+ }
+ }
+ }
+}
+
+static void
+t_ulinkcolor(char *lp)
+{
+ float r, g, b;
+
+ r = strtod(lp, &lp);
+ g = strtod(lp, &lp);
+ b = strtod(lp, &lp);
+ snprintf(ulinkcolor, sizeof ulinkcolor, "%g %g %g", r, g, b);
+}
+
+static void
+t_ulinkborder(char *lp)
+{
+ float bx, by, c;
+
+ bx = strtod(lp, &lp);
+ by = strtod(lp, &lp);
+ c = strtod(lp, &lp);
+ snprintf(ulinkborder, sizeof ulinkborder, "%g %g %g", bx, by, c);
+ free(ulinkborderstyle);
+ ulinkborderstyle = NULL;
+}
diff --git a/troff/troff.d/dpost.d/dpost.h b/troff/troff.d/dpost.d/dpost.h
new file mode 100644
index 000000000000..ca96c570f1e7
--- /dev/null
+++ b/troff/troff.d/dpost.d/dpost.h
@@ -0,0 +1,192 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/* from OpenSolaris "dpost.h 1.7 05/06/08 SMI" SVr4.0 1.1 */
+
+/*
+ * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
+ *
+ * Sccsid @(#)dpost.h 1.11 (gritter) 9/22/06
+ */
+
+/*
+ *
+ * Definitions used by the troff post-processor for PostScript printers.
+ *
+ * DEVNAME should be the name of a device whose font files accurately describe
+ * what's available on the target printer. It's a string that's combined with
+ * "/usr/lib/font/dev" to locate the final font directory. It can be changed
+ * using the -T option, but you may end up getting garbage - the character code
+ * field must agree with PostScript's character encoding scheme for each font and
+ * troff's one or two character font names must be mapped into the appropriate
+ * PostScript font names (typically in the prologue)
+ *
+ *
+ */
+
+#define DEVNAME "post" /* name of the target printer */
+
+/*
+ *
+ * NFONT is the most font positions we'll allow. It's set ridiculously high for no
+ * good reason.
+ *
+ */
+
+#define NFONT 300 /* max number of font positions */
+
+/*
+ *
+ * SLOP controls how much horizontal positioning error we'll accept and primarily
+ * helps when we're emulating another device. It's used when we output characters
+ * in oput() to check if troff and the printer have gotten too far out of sync.
+ * Given in units of points and can be changed using the -S option. Converted to
+ * machine units in t_init() after the resolution is known.
+ *
+ */
+
+#define SLOP .2 /* horizontal error - in points */
+
+/*
+ *
+ * Fonts are assigned unique internal numbers (positive integers) in their ASCII
+ * font files. MAXINTERNAL is the largest internal font number that lets the host
+ * resident and DOCUMENTFONTS stuff work. Used to allocate space for an array that
+ * keeps track of what fonts we've seen and perhaps downloaded - could be better!
+ *
+ */
+
+#define MAXINTERNAL 1536
+
+/*
+ *
+ * Several different text line encoding schemes are supported. Print time should
+ * decrease as the value assigned to encoding (in dpost.c) increases, although the
+ * only encoding that's well tested is the lowest level one, which produces output
+ * essentially identical to the original version of dpost. Setting DFLTENCODING to
+ * 0 will give you the most stable (but slowest) encoding. The encoding scheme can
+ * also be set on the command line using the -e option. Faster methods are based
+ * on widthshow and may not place words exactly where troff wanted, but errors will
+ * usually not be noticeable.
+ *
+ */
+
+#define MAXENCODING 5
+
+#ifndef DFLTENCODING
+#define DFLTENCODING 0
+#endif
+
+/*
+ *
+ * The encoding scheme controls how lines of text are output. In the lower level
+ * schemes words and horizontal positions are put on the stack as they're read and
+ * when they're printed it's done in reverse order - the first string printed is
+ * the one on top of the stack and it's the last one on the line. Faster methods
+ * may be forced to reverse the order of strings on the stack, making the top one
+ * the first string on the line. STRINGSPACE sets the size of a character array
+ * that's used to save the strings that make up a line of text so they can be
+ * output in reverse order or perhaps combined in groups for widthshow.
+ *
+ * MAXSTACK controls how far we let PostScript's operand stack grow and determines
+ * the number of strings we'll save before printing all or part of a line of text.
+ * The internal limit in PostScript printers built by Adobe is 500, so MAXSTACK
+ * should never be bigger than about 240!
+ *
+ * Line is a structure used to keep track of the words (or rather strings) on the
+ * current line that have been read but not printed. dx is the width troff wants
+ * to use for a space in the current string. start is where the string began, width
+ * is the total width of the string, and spaces is the number of space characters
+ * in the current string. *str points to the start of the string in the strings[]
+ * array. The Line structure is only used in the higher level encoding schemes.
+ *
+ */
+
+#define MAXSTACK 50 /* most strings we'll save at once */
+#define STRINGSPACE 2000 /* bytes available for string storage */
+
+typedef struct {
+
+ char *str; /* where the string is stored */
+ int dx; /* width of a space */
+ int spaces; /* number of space characters */
+ int start; /* horizontal starting position */
+ int width; /* and its total width */
+
+} Line;
+
+/*
+ *
+ * Simple stuff used to map unrecognized font names into something reasonable. The
+ * mapping array is initialized using FONTMAP and used in loadfont() whenever the
+ * job tries to use a font that we don't recognize. Normally only needed when we're
+ * emulating another device.
+ *
+ */
+
+typedef struct {
+
+ char *name; /* font name we're looking for */
+ char *use; /* and this is what we should use */
+
+} Fontmap;
+
+#define FONTMAP \
+ \
+ { \
+ { "G" , "H" }, \
+ { "LO", "S" }, \
+ { "S2", "S" }, \
+ { "GI", "HI" }, \
+ { "HM", "H" }, \
+ { "HK", "H" }, \
+ { "HL", "H" }, \
+ { "PA", "R" }, \
+ { "PI", "I" }, \
+ { "PB", "B" }, \
+ { "PX", "BI" }, \
+ { NULL, NULL } \
+ }
+
+/*
+ *
+ * The Fontmap stuff isn't quite enough if we expect to do a good job emulating
+ * other devices. A recognized font in *realdev's tables may be have a different
+ * name in *devname's tables, and using the *realdev font may not be the best
+ * choice. The fix is to use an optional lookup table for *devname that's used to
+ * map font names into something else before anything else is done. The table we
+ * use is /usr/lib/font/dev*realdev/fontmaps/devname and if it exists getdevmap()
+ * uses the file to fill in a Devfontmap array. Then whenever an "x font pos name"
+ * command is read mapdevfont() uses the lookup table to map name into something
+ * else before loadfont() is called.
+ *
+ */
+
+typedef struct {
+
+ char name[3]; /* map this font name */
+ char use[3]; /* into this one */
+
+} Devfontmap;
diff --git a/troff/troff.d/dpost.d/draw.c b/troff/troff.d/dpost.d/draw.c
new file mode 100644
index 000000000000..68d3215b4418
--- /dev/null
+++ b/troff/troff.d/dpost.d/draw.c
@@ -0,0 +1,844 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * University Copyright- Copyright (c) 1982, 1986, 1988
+ * The Regents of the University of California
+ * All Rights Reserved
+ *
+ * University Acknowledgment- Portions of this document are derived from
+ * software developed by the University of California, Berkeley, and its
+ * contributors.
+ */
+
+/* from OpenSolaris "draw.c 1.6 05/06/08 SMI" SVr4.0 1.1 */
+
+/*
+ * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
+ *
+ * Sccsid @(#)draw.c 1.7 (gritter) 3/27/07
+ */
+
+/*
+ *
+ * Drawing routines used by dpost. Almost no real work is done here. Instead
+ * the required calculations are done in special Postscript procedures that
+ * include:
+ *
+ *
+ * Dl
+ *
+ * x1 y1 x y Dl -
+ *
+ * Starts a new path and then draws a line from the current point
+ * (x, y) to (x1, y1).
+ *
+ * De
+ *
+ * x y a b De -
+ *
+ * Starts a new path and then draws an ellipse that has its left side
+ * at the current point (x, y) and horizontal and vertical axes lengths
+ * given by a and b respectively.
+ *
+ * Da
+ *
+ * x y dx1 dy1 dx2 dy2 Da -
+ *
+ * Starts a new segment and then draws a circular arc from the current
+ * point (x, y) to (x + dx1 + dx2, y + dy1 + dy2). The center of the
+ * circle is at (x + dx1, y + dy1). Arcs always go counter-clockwise
+ * from the starting point to the end point.
+ *
+ * DA
+ *
+ * x y dx1 dy1 dx2 dy2 DA -
+ *
+ * Draws a clockwise arc from (x, y) to (x + dx1 + dx2, y + dy1 + dy2)
+ * with center at (x + dx1, y + dy1). Only needed when we're building
+ * large paths that use arcs and want to control the current point. The
+ * arguments passed to drawarc() will be whatever they would have been
+ * for a counter-clockwise arc, so we need to map them into appropriate
+ * arguments for PostScript's arcn operator. The mapping is,
+ *
+ * x = hpos + dx1' + dx2'
+ * y = vpos + dy1' + dy2'
+ * dx1 = -dx2'
+ * dy1 = -dy2'
+ * dx2 = -dx1'
+ * dy2 = -dy1'
+ *
+ * where primed values represent the drawarc() arguments and (hpos, vpos)
+ * is our current position.
+ *
+ * Ds
+ *
+ * x0 y0 x1 y1 x2 y2 Ds -
+ *
+ * Starts a new segment and then draws a quadratic spline connecting
+ * point ((x0 + x1)/2, (y0 + y1)/2) to ((x1 + x2)/2, (y1 + y2)/2).
+ * The points used in Postscript's curveto procedure are given by,
+ *
+ * x0' = (x0 + 5 * x1) / 6
+ * x1' = (x2 + 5 * x1) / 6
+ * x2' = (x1 + x2) / 2
+ *
+ * with similar equations for the y coordinates.
+ *
+ * By default all the PostScript drawing procedures begin with a newpath (just to
+ * be safe) and end with a stroke, which essentially isolates the path elements
+ * built by the drawing procedures. In order to accommodate big paths built from
+ * smaller pieces each of the PostScript drawing procedures can forced to retain
+ * the path that's being built. That's what happens in beginpath() when an "x X
+ * BeginPath" command is read. beginpath() sets the PostScript variable inpath to
+ * true, and that essentially eliminates the newpath/stroke pair that bracket the
+ * individual pieces. In that case the path is terminated and drawn when dpost
+ * reads an "x X DrawPath" command.
+ *
+ * Early versions of dpost included the PostScript drawing procedures as part of
+ * the prologue, and as a result they were included with every job, even if they
+ * were never used. This version has separated the drawing procedures from the
+ * default prologue (they're now in *drawfile) and only includes them if they're
+ * really needed, which is yet another convenient violation of page independence.
+ * Routine getdraw() is responsible for adding *drawfile to the output file, and
+ * if it can't read *drawfile it continues on as if nothing happened. That means
+ * everything should still work if you append *drawfile to *prologue and then
+ * delete *drawfile.
+ *
+ */
+
+
+#include <stdio.h>
+#include <math.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "gen.h" /* general purpose definitions */
+#include "ext.h" /* external variable definitions */
+
+
+int gotdraw = FALSE; /* TRUE when *drawfile has been added */
+int gotbaseline = FALSE; /* TRUE after *baselinefile is added */
+int inpath = FALSE; /* TRUE if we're putting pieces together */
+
+
+/*
+ *
+ * All these should be defined in file dpost.c.
+ *
+ */
+
+
+extern int hpos;
+extern int vpos;
+extern int encoding;
+extern int maxencoding;
+extern int realencoding;
+
+extern char *drawfile;
+extern char *baselinefile;
+extern FILE *tf;
+
+
+/*****************************************************************************/
+
+
+void
+getdraw(void)
+
+
+{
+
+
+/*
+ *
+ * Responsible for making sure the PostScript drawing procedures are downloaded
+ * from *drawfile. Stuff is done at most once per job, and only if the job needs
+ * them. For now I've decided not to quit if we can't read the drawing file. That
+ * pretty much assumes an old version of prologue is being used that includes all
+ * the drawing procedures.
+ *
+ */
+
+
+ if ( gotdraw == FALSE && access(drawfile, 04) == 0 )
+ doglobal(drawfile);
+
+ if ( tf == stdout )
+ gotdraw = TRUE;
+
+} /* End of getdraw */
+
+
+/*****************************************************************************/
+
+
+void
+drawline (
+ int dx,
+ int dy /* endpoint is (hpos+dx, vpos+dy) */
+)
+
+
+{
+
+
+/*
+ *
+ * Draws a line from (hpos, vpos) to (hpos+dx, vpos+dy), and leaves the current
+ * position at the endpoint.
+ *
+ */
+
+
+ if ( dx == 0 && dy == 0 )
+ drawcirc(1, 'c');
+ else fprintf(tf, "%d %d %d %d Dl\n", hpos + dx, vpos + dy, hpos, vpos);
+
+ hgoto(hpos+dx); /* where troff expects to be */
+ vgoto(vpos+dy);
+
+ resetpos(); /* not sure where the printer is */
+
+} /* End of drawline */
+
+
+/*****************************************************************************/
+
+
+void
+drawcirc (
+ int d, /* diameter of the circle */
+ int c
+)
+
+
+{
+
+
+/*
+ *
+ * Draws a circle of diameter d with the left 'side' of the circle at the
+ * current point. After we're finished drawing we move the current position
+ * to the right side.
+ *
+ */
+
+ drawellip(d, d, c == 'C' ? 'E' : 'e');
+
+} /* End of drawcirc */
+
+
+/*****************************************************************************/
+
+
+void
+drawellip (
+ int a,
+ int b, /* axes lengths for the ellipse */
+ int c
+)
+
+
+{
+
+
+/*
+ *
+ * Draws an ellipse having axes lengths horizontally and vertically of a and
+ * b. The left side of the ellipse is at the current point. After we're done
+ * drawing the path we move the current position to the right side.
+ *
+ */
+
+
+ if ( a == 0 && b == 0 )
+ return;
+
+ fprintf(tf, "%d %d %d %d D%c\n", hpos, vpos, a, b, c);
+
+ hgoto(hpos + a); /* where troff expects to be */
+ vgoto(vpos);
+
+ resetpos(); /* not sure where the printer is */
+
+} /* End of drawellip */
+
+
+/*****************************************************************************/
+
+
+void
+drawarc (
+ int dx1,
+ int dy1, /* vector from current pos to center */
+ int dx2,
+ int dy2, /* from center to end of the arc */
+ int c /* clockwise if c is A */
+)
+
+
+{
+
+
+/*
+ *
+ * If c isn't set to 'A' a counter-clockwise arc is drawn from the current point
+ * (hpos, vpos) to (hpos+dx1+dx2, vpos+dy1+dy2). The center of the circle is the
+ * point (hpos+dx1, vpos+dy1). If c is 'A' the arc goes clockwise from the point
+ * (hpos+dx1+dx2, vpos+dy1+dy2) to (hpos, vpos). Clockwise arcs are only needed
+ * if we're building a larger path out of pieces that include arcs, and want to
+ * have PostScript manage the path for us. Arguments (for a clockwise arc) are
+ * what would have been supplied if the arc was drawn in a counter-clockwise
+ * direction, and are converted to values suitable for use with PostScript's arcn
+ * operator.
+ *
+ */
+
+
+ if ( (dx1 != 0 || dy1 != 0) && (dx2 != 0 || dy2 != 0) )
+ {
+ if ( c != 'A' )
+ fprintf(tf, "%d %d %d %d %d %d Da\n", hpos, vpos, dx1, dy1, dx2, dy2);
+ else fprintf(tf, "%d %d %d %d %d %d DA\n", hpos+dx1+dx2, vpos+dy1+dy2,
+ -dx2, -dy2, -dx1, -dy1);
+ }
+
+ hgoto(hpos + dx1 + dx2); /* where troff expects to be */
+ vgoto(vpos + dy1 + dy2);
+
+ resetpos(); /* not sure where the printer is */
+
+} /* End of drawarc */
+
+
+/*****************************************************************************/
+
+void
+drawspline(
+
+
+ FILE *fp, /* input for point list */
+ int flag /* flag!=1 connect end points */
+)
+
+
+{
+
+
+ int x[100], y[100];
+ int i, N;
+
+
+/*
+ *
+ * Spline drawing routine for Postscript printers. The complicated stuff is
+ * handled by procedure Ds, which should be defined in the library file. I've
+ * seen wrong implementations of troff's spline drawing, so fo the record I'll
+ * write down the parametric equations and the necessary conversions to Bezier
+ * cubic splines (as used in Postscript).
+ *
+ *
+ * Parametric equation (x coordinate only):
+ *
+ *
+ * (x2 - 2 * x1 + x0) 2 (x0 + x1)
+ * x = ------------------ * t + (x1 - x0) * t + ---------
+ * 2 2
+ *
+ *
+ * The coefficients in the Bezier cubic are,
+ *
+ *
+ * A = 0
+ * B = (x2 - 2 * x1 + x0) / 2
+ * C = x1 - x0
+ *
+ *
+ * while the current point is,
+ *
+ * current-point = (x0 + x1) / 2
+ *
+ * Using the relationships given in the Postscript manual (page 121) it's easy to
+ * see that the control points are given by,
+ *
+ *
+ * x0' = (x0 + 5 * x1) / 6
+ * x1' = (x2 + 5 * x1) / 6
+ * x2' = (x1 + x2) / 2
+ *
+ *
+ * where the primed variables are the ones used by curveto. The calculations
+ * shown above are done in procedure Ds using the coordinates set up in both
+ * the x[] and y[] arrays.
+ *
+ * A simple test of whether your spline drawing is correct would be to use cip
+ * to draw a spline and some tangent lines at appropriate points and then print
+ * the file.
+ *
+ */
+
+
+ for ( N = 2; N < sizeof(x)/sizeof(x[0]); N++ )
+ if (fscanf(fp, "%d %d", &x[N], &y[N]) != 2)
+ break;
+
+ x[0] = x[1] = hpos;
+ y[0] = y[1] = vpos;
+
+ for (i = 1; i < N; i++) {
+ x[i+1] += x[i];
+ y[i+1] += y[i];
+ } /* End for */
+
+ x[N] = x[N-1];
+ y[N] = y[N-1];
+
+ for (i = ((flag!=1)?0:1); i < ((flag!=1)?N-1:N-2); i++)
+ fprintf(tf, "%d %d %d %d %d %d Ds\n", x[i], y[i], x[i+1], y[i+1], x[i+2], y[i+2]);
+
+ hgoto(x[N]); /* where troff expects to be */
+ vgoto(y[N]);
+
+ resetpos(); /* not sure where the printer is */
+
+} /* End of drawspline */
+
+
+/*****************************************************************************/
+
+
+void
+beginpath (
+ char *buf, /* whatever followed "x X BeginPath" */
+ int copy /* ignore *buf if FALSE */
+)
+
+
+{
+
+
+/*
+ *
+ * Called from devcntrl() whenever an "x X BeginPath" command is read. It's used
+ * to mark the start of a sequence of drawing commands that should be grouped
+ * together and treated as a single path. By default the drawing procedures in
+ * *drawfile treat each drawing command as a separate object, and usually start
+ * with a newpath (just as a precaution) and end with a stroke. The newpath and
+ * stroke isolate individual drawing commands and make it impossible to deal with
+ * composite objects. "x X BeginPath" can be used to mark the start of drawing
+ * commands that should be grouped together and treated as a single object, and
+ * part of what's done here ensures that the PostScript drawing commands defined
+ * in *drawfile skip the newpath and stroke, until after the next "x X DrawPath"
+ * command. At that point the path that's been built up can be manipulated in
+ * various ways (eg. filled and/or stroked with a different line width).
+ *
+ * String *buf is unnecessary and is only included for compatibility with an early
+ * verion of that's still in use. In that version "x X BeginObject" marked the
+ * start of a graphical object, and whatever followed it was passed along in *buf
+ * and copied to the output file. Color selection is one of the options that's
+ * available in parsebuf(), so if we get here we add *colorfile to the output
+ * file before doing anything important.
+ *
+ */
+
+
+
+ if ( inpath == FALSE ) {
+ endtext();
+ getdraw();
+ getcolor();
+ fprintf(tf, "gsave\n");
+ fprintf(tf, "newpath\n");
+ fprintf(tf, "%d %d m\n", hpos, vpos);
+ fprintf(tf, "/inpath true def\n");
+ if ( copy == TRUE )
+ fprintf(tf, "%s", buf);
+ inpath = TRUE;
+ } /* End if */
+
+} /* End of beginpath */
+
+
+/*****************************************************************************/
+
+
+void
+drawpath(char *buf, int copy)
+
+
+{
+
+
+/*
+ *
+ * Called from devcntrl() whenever an "x X DrawPath" command is read. It marks the
+ * end of the path started by the last "x X BeginPath" command and uses whatever
+ * has been passed along in *buf to manipulate the path (eg. fill and/or stroke
+ * the path). Once that's been done the drawing procedures are restored to their
+ * default behavior in which each drawing command is treated as an isolated path.
+ * The new version (called after "x X DrawPath") has copy set to FALSE, and calls
+ * parsebuf() to figure out what goes in the output file. It's a feeble attempt
+ * to free users and preprocessors (like pic) from having to know PostScript. The
+ * comments in parsebuf() describe what's handled.
+ *
+ * In the early version a path was started with "x X BeginObject" and ended with
+ * "x X EndObject". In both cases *buf was just copied to the output file, and
+ * was expected to be legitimate PostScript that manipulated the current path.
+ * The old escape sequence will be supported for a while (for Ravi), and always
+ * call this routine with copy set to TRUE.
+ *
+ *
+ */
+
+
+ if ( inpath == TRUE ) {
+ if ( copy == TRUE )
+ fprintf(tf, "%s", buf);
+ else parsebuf(buf);
+ fprintf(tf, "grestore\n");
+ fprintf(tf, "/inpath false def\n");
+ reset();
+ inpath = FALSE;
+ } /* End if */
+
+} /* End of drawpath */
+
+
+/*****************************************************************************/
+
+
+void
+parsebuf (
+ char *buf /* whatever followed "x X DrawPath" */
+)
+
+
+{
+
+
+ char *p; /* usually the next token */
+ char *p1; /* for grabbing arguments */
+ char *pend; /* end of the original string (ie. *buf) */
+ int gsavelevel = 0; /* non-zero if we've done a gsave */
+
+/*
+ *
+ * Simple minded attempt at parsing the string that followed an "x X DrawPath"
+ * command. Everything not recognized here is simply ignored - there's absolutely
+ * no error checking and what was originally in buf is clobbered by strtok().
+ * A typical *buf might look like,
+ *
+ * gray .9 fill stroke
+ *
+ * to fill the current path with a gray level of .9 and follow that by stroking the
+ * outline of the path. Since unrecognized tokens are ignored the last example
+ * could also be written as,
+ *
+ * with gray .9 fill then stroke
+ *
+ * The "with" and "then" strings aren't recognized tokens and are simply discarded.
+ * The "stroke", "fill", and "wfill" force out appropriate PostScript code and are
+ * followed by a grestore. In otherwords changes to the grahics state (eg. a gray
+ * level or color) are reset to default values immediately after the stroke, fill,
+ * or wfill tokens. For now "fill" gets invokes PostScript's eofill operator and
+ * "wfill" calls fill (ie. the operator that uses the non-zero winding rule).
+ *
+ * The tokens that cause temporary changes to the graphics state are "gray" (for
+ * setting the gray level), "color" (for selecting a known color from the colordict
+ * dictionary defined in *colorfile), and "line" (for setting the line width). All
+ * three tokens can be extended since strncmp() makes the comparison. For example
+ * the strings "line" and "linewidth" accomplish the same thing. Colors are named
+ * (eg. "red"), but must be appropriately defined in *colorfile. For now all three
+ * tokens must be followed immediately by their single argument. The gray level
+ * (ie. the argument that follows "gray") should be a number between 0 and 1, with
+ * 0 for black and 1 for white.
+ *
+ * To pass straight PostScript through enclose the appropriate commands in double
+ * quotes. Straight PostScript is only bracketed by the outermost gsave/grestore
+ * pair (ie. the one from the initial "x X BeginPath") although that's probably
+ * a mistake. Suspect I may have to change the double quote delimiters.
+ *
+ */
+
+
+ pend = buf + strlen(buf);
+ p = strtok(buf, " \n");
+
+ while ( p != NULL ) {
+ if ( gsavelevel == 0 ) {
+ fprintf(tf, "gsave\n");
+ gsavelevel++;
+ } /* End if */
+ if ( strcmp(p, "stroke") == 0 ) {
+ fprintf(tf, "closepath stroke\ngrestore\n");
+ gsavelevel--;
+ } else if ( strcmp(p, "openstroke") == 0 ) {
+ fprintf(tf, "stroke\ngrestore\n");
+ gsavelevel--;
+ } else if ( strcmp(p, "fill") == 0 ) {
+ fprintf(tf, "eofill\ngrestore\n");
+ gsavelevel--;
+ } else if ( strcmp(p, "wfill") == 0 ) {
+ fprintf(tf, "fill\ngrestore\n");
+ gsavelevel--;
+ } else if ( strcmp(p, "sfill") == 0 ) {
+ fprintf(tf, "eofill\ngrestore\ngsave\nstroke\ngrestore\n");
+ gsavelevel--;
+ } else if ( strncmp(p, "gray", strlen("gray")) == 0 ) {
+ p1 = strtok(NULL, " \n");
+ fprintf(tf, "%s setgray\n", p1);
+ } else if ( strncmp(p, "color", strlen("color")) == 0 ) {
+ p1 = strtok(NULL, " \n");
+ fprintf(tf, "/%s _setcolor\n", p1);
+ } else if ( strncmp(p, "line", strlen("line")) == 0 ) {
+ p1 = strtok(NULL, " \n");
+ fprintf(tf, "%s resolution mul 2 div setlinewidth\n", p1);
+ } else if ( strncmp(p, "reverse", strlen("reverse")) == 0 )
+ fprintf(tf, "reversepath\n");
+ else if ( *p == '"' ) {
+ for ( ; gsavelevel > 0; gsavelevel-- )
+ fprintf(tf, "grestore\n");
+ if ( (p1 = p + strlen(p)) < pend )
+ *p1 = ' ';
+ p = strtok(p, "\"\n");
+ fprintf(tf, "%s\n", p);
+ } /* End else */
+ p = strtok(NULL, " \n");
+ } /* End while */
+
+ for ( ; gsavelevel > 0; gsavelevel-- )
+ fprintf(tf, "grestore\n");
+
+} /* End of parsebuf */
+
+
+/*****************************************************************************/
+
+
+void
+getbaseline(void)
+
+
+{
+
+
+/*
+ *
+ * Responsible for making sure the PostScript procedures needed for printing text
+ * along an arbitrary baseline are downloaded from *baselinefile. Done at most
+ * once per job, and only if the the stuff is really used.
+ *
+ */
+
+
+ if ( gotbaseline == FALSE && access(baselinefile, 04) == 0 )
+ doglobal(baselinefile);
+
+ if ( tf == stdout )
+ gotbaseline = TRUE;
+
+} /* End of getbaseline */
+
+
+/*****************************************************************************/
+
+
+void
+newbaseline (
+ char *buf /* whatever followed "x X NewBaseline" */
+)
+
+
+{
+
+
+ char *p; /* for eliminating white space etc. */
+
+
+/*
+ *
+ * Called from devcntrl() whenever an "x X NewBaseline" command is recognized. We
+ * assume whatever is in *buf is a set of parametric equations that describe the
+ * new baseline. Equations for x(t), y(t), dx/dt, and dy/dt must be written in
+ * PostScript, bracketed by { and } characters, and supplied in exactly that order.
+ * In particular the equation for x must come first in *buf and it ends up as the
+ * last one on the stack, while the equation for dy/dt comes last (in *buf) and
+ * ends up on the top of the PostScript stack. For example if *buf is given by,
+ *
+ * {} {180 mul 3.1416 div cos} {pop 1} {180 mul 3.1416 div sin neg}
+ *
+ * text will be printed along the curve y = cos(x).
+ *
+ * Angles given in radians must be converted to degrees for the PostScript trig
+ * functions, and things are scaled so that 1 unit maps into 1 inch. In the last
+ * example the cosine curve that describes the baseline has an amplitude of 1 inch.
+ * As another example of this rather confusing syntax if *buf is,
+ *
+ * {} {} {pop 1} {pop 1}
+ *
+ * the baseline will be the 45 degree line y = x.
+ *
+ * When any of the four functions is used they're called with a single number on
+ * the stack that's equal to the current value of the parameter t. The coordinate
+ * system axes run parallel to the PostScript coordinate system that's currently
+ * being used.
+ *
+ */
+
+
+ for ( p = buf; *p; p++ ) /* eliminate trailing '\n' */
+ if ( *p == '\n' ) {
+ *p = '\0';
+ break;
+ } /* End if */
+
+ for ( p = buf; *p && (*p == ' ' || *p == ':'); p++ ) ;
+
+ if ( *p != '\0' ) { /* something's there */
+ endtext();
+ getbaseline();
+ fprintf(tf, "mark resolution %s newbaseline\n", p);
+ t_sf(1);
+ resetpos();
+ } /* End if */
+
+} /* End of newbaseline */
+
+
+/*****************************************************************************/
+
+
+void
+drawtext (
+ char *buf /* whatever followed "x X DrawText */
+)
+
+
+{
+
+
+ char *p; /* for eliminating white space etc. */
+
+
+/*
+ *
+ * Called from devcntrl() whenever an "x X DrawText command is recognized. *buf
+ * should contain three arguments in the following order. First comes the text we
+ * want to print along the current baseline. Right now the string should be given
+ * as a PostScript string using characters '(' and ')' as the delimiters. Next in
+ * *buf comes a justification mode that can be the words left, right, or center.
+ * Last comes a number that represents the starting value of the parameter t that's
+ * given as the argument to the parametric equations that describe the current
+ * baseline. For example if *buf is given by,
+ *
+ * (hello world) left .5
+ *
+ * hello world will be printed along the path described by the current baseline
+ * and left justified at whatever (x(.5), y(.5)) happens to be. Usually will be
+ * preceeded by an "x X NewBaseline" call that defines the current baseline. The
+ * origin of the coordinate system used by the parametric equations will be the
+ * current point.
+ *
+ */
+
+
+ for ( p = buf; *p; p++ ) /* eliminate trailing '\n' */
+ if ( *p == '\n' ) {
+ *p = '\0';
+ break;
+ } /* End if */
+
+ for ( p = buf; *p && (*p == ' ' || *p == ':'); p++ ) ;
+
+ if ( *p != '\0' ) { /* something's there */
+ endtext();
+ getbaseline();
+ xymove(hpos, vpos);
+ fprintf(tf, "mark %s drawfunnytext\n", p);
+ resetpos();
+ } /* End if */
+
+} /* End of drawtext */
+
+
+/*****************************************************************************/
+
+
+void
+settext(char *buf)
+
+
+{
+
+
+ char *p;
+
+
+/*
+ *
+ * Does whatever is needed to ensure any text that follows will be set along the
+ * curve described by the PostScript procedures listed in *buf. If *buf doesn't
+ * contain anything useful (eg. just a newline) things are restored to whatever
+ * they originally were. Doesn't work well if we try to start in the middle of a
+ * line of text.
+ *
+ * The parametric equations needed are,
+ *
+ * x = f(t)
+ * y = g(t)
+ * dx/dt = f'(t)
+ * dy/dt = g'(t)
+ *
+ * and must be given as proper PostScript procedures. The equation for x must come
+ * first (ie. it ends up on the bottom of the stack) and the equation for dy/dt
+ * must be given last (ie. it ends up on top of the stack). For example if *buf
+ * is given by,
+ *
+ * {} {180 mul 3.1416 div cos} {pop 1} {180 mul 3.1416 div sin neg}
+ *
+ * text will be set along the curve y=cos(x).
+ *
+ */
+
+
+ endtext();
+ getbaseline();
+
+ for ( p = buf; *p && *p == ' '; p++ ) ;
+
+ if ( *p && *p != '\n' ) {
+ encoding = maxencoding + 2;
+ fprintf(tf, "mark resolution %s newbaseline\n", buf);
+ } else encoding = realencoding;
+
+ fprintf(tf, "%d setdecoding\n", encoding);
+ resetpos();
+
+} /* End of settext */
+
+
+/*****************************************************************************/
+
diff --git a/troff/troff.d/dpost.d/ext.h b/troff/troff.d/dpost.d/ext.h
new file mode 100644
index 000000000000..d1e76dbfb64d
--- /dev/null
+++ b/troff/troff.d/dpost.d/ext.h
@@ -0,0 +1,54 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/* from OpenSolaris "ext.h 1.5 05/06/08 SMI" SVr4.0 1.1 */
+
+/*
+ * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
+ *
+ * Sccsid @(#)ext.h 1.7 (gritter) 3/27/07
+ */
+
+/*
+ *
+ * External varible declarations - many are defined in glob.c.
+ *
+ */
+
+
+extern char **argv; /* global so everyone can use them */
+extern int argc;
+
+extern int x_stat; /* program exit status */
+extern int debug; /* debug flag */
+extern int ignore; /* what we do with FATAL errors */
+
+extern long lineno; /* line number */
+extern long position; /* byte position */
+extern int printed; /* pages printed so far */
+extern char *prog_name; /* and program name - for errors */
+extern char *temp_file; /* temporary file - for some programs */
+
+extern int LanguageLevel; /* language level of generated PS */
diff --git a/troff/troff.d/dpost.d/gen.h b/troff/troff.d/dpost.d/gen.h
new file mode 100644
index 000000000000..6e0a2bb1ef86
--- /dev/null
+++ b/troff/troff.d/dpost.d/gen.h
@@ -0,0 +1,174 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/* from OpenSolaris "gen.h 1.5 05/06/08 SMI" SVr4.0 1.1 */
+
+/*
+ * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
+ *
+ * Sccsid @(#)gen.h 1.16 (gritter) 10/15/06
+ */
+
+/*
+ *
+ * A few definitions that shouldn't have to change. They're used by most of the
+ * programs in this package.
+ *
+ */
+
+
+extern const char creator[];
+
+
+#define NON_FATAL 0
+#define FATAL 1
+#define USER_FATAL 2
+
+#define OFF 0
+#define ON 1
+
+#define FALSE 0
+#define TRUE 1
+
+#define BYTE 8
+#define BMASK 0377
+
+#define POINTS 72.3
+
+#ifndef PI
+#define PI 3.141592654
+#endif
+
+
+/*
+ *
+ * A few simple macros.
+ *
+ */
+
+
+#define ABS(A) ((A) >= 0 ? (A) : -(A))
+#undef MIN
+#define MIN(A, B) ((A) < (B) ? (A) : (B))
+#undef MAX
+#define MAX(A, B) ((A) > (B) ? (A) : (B))
+
+/* color.c */
+void getcolor(void);
+void newcolor(char *);
+void setcolor(void);
+/* dpost.c */
+void init_signals(void);
+void header(FILE *);
+void options(void);
+void setpaths(char *);
+void setup(void);
+void arguments(void);
+void done(void);
+void account(void);
+void conv(register FILE *);
+void devcntrl(FILE *);
+void fontinit(void);
+void loadfont(int, char *, char *, int, int);
+void loadspecial(void);
+void loaddefault(void);
+void fontprint(int);
+char *mapfont(char *);
+void getdevmap(void);
+char *mapdevfont(char *);
+void reset(void);
+void resetpos(void);
+void t_init(void);
+void t_page(int);
+void t_newline(void);
+int t_size(int);
+void setsize(int, float);
+void t_fp(int, char *, char *, void *);
+int t_font(char *);
+void setfont(int);
+void t_sf(int);
+void t_charht(int, float);
+void t_slant(int);
+void needresource(const char *, ...);
+void t_supply(char *);
+void t_reset(int);
+void t_trailer(void);
+void hgoto(int);
+void hmot(int);
+void vgoto(int);
+void vmot(int);
+void xymove(int, int);
+void put1s(register char *);
+void put1(register int);
+void oput(int);
+void starttext(void);
+void endtext(void);
+void endstring(void);
+void endline(void);
+void addchar(int);
+void addoctal(int);
+void charlib(int);
+int doglobal(char *);
+void documentfont(const char *);
+void documentfonts(void);
+void redirect(int);
+/* draw.c */
+void getdraw(void);
+void drawline(int, int);
+void drawcirc(int, int);
+void drawellip(int, int, int);
+void drawarc(int, int, int, int, int);
+void drawspline(FILE *, int);
+void beginpath(char *, int);
+void drawpath(char *, int);
+void parsebuf(char *);
+void getbaseline(void);
+void newbaseline(char *);
+void drawtext(char *);
+void settext(char *);
+/* glob.c */
+/* misc.c */
+void error(int, char *, ...);
+void out_list(char *);
+int in_olist(int);
+int cat(char *, FILE *);
+int str_convert(char **, int);
+char *tempname(const char *);
+int psskip(size_t, FILE *);
+char *psgetline(char **, size_t *, size_t *, FILE *);
+int sget(char *, size_t, FILE *);
+/* pictures.c */
+void picture(char *);
+FILE *picopen(char *);
+void inlinepic(FILE *, char *);
+void piccopy(FILE *, FILE *, long);
+/* ps_include.c */
+void ps_include(const char *, FILE *, FILE *, int, int, int, int,
+ double, double, double, double, double, double, double);
+/* request.c */
+void saverequest(char *);
+void writerequest(int, FILE *);
+void dumprequest(char *, char *, FILE *);
+/* tempnam.c */
diff --git a/troff/troff.d/dpost.d/getopt.c b/troff/troff.d/dpost.d/getopt.c
new file mode 100644
index 000000000000..bb8c53d072cb
--- /dev/null
+++ b/troff/troff.d/dpost.d/getopt.c
@@ -0,0 +1,222 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
+ *
+ * Sccsid @(#)getopt.c 1.10 (gritter) 12/16/07
+ */
+/* from OpenSolaris "getopt.c 1.23 05/06/08 SMI" */
+
+/* Copyright (c) 1988 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * See getopt(3C) and SUS/XPG getopt() for function definition and
+ * requirements.
+ *
+ * This actual implementation is a bit looser than the specification
+ * as it allows any character other than ':' to be used as an option
+ * character - The specification only guarantees the alnum characters
+ * ([a-z][A-Z][0-9]).
+ */
+
+#include <sys/types.h>
+#include <string.h>
+#include <stdio.h>
+
+extern ssize_t write(int, const void *, size_t);
+
+char *optarg = NULL;
+int optind = 1;
+int opterr = 1;
+int optopt = 0;
+
+#define ERR(s, c) err(s, c, optstring, argv[0])
+static void
+err(const char *s, int c, const char *optstring, const char *argv0)
+{
+ char errbuf[256], *ep = errbuf;
+ const char *cp;
+
+ if (opterr && optstring[0] != ':') {
+ for (cp = argv0; *cp && ep<&errbuf[sizeof errbuf]; cp++, ep++)
+ *ep = *cp;
+ for (cp = ": "; *cp && ep<&errbuf[sizeof errbuf]; cp++, ep++)
+ *ep = *cp;
+ for (cp = s; *cp && ep<&errbuf[sizeof errbuf]; cp++, ep++)
+ *ep = *cp;
+ for (cp = " -- "; *cp && ep<&errbuf[sizeof errbuf]; cp++, ep++)
+ *ep = *cp;
+ if (ep<&errbuf[sizeof errbuf])
+ *ep++ = c;
+ if (ep<&errbuf[sizeof errbuf])
+ *ep++ = '\n';
+ write(2, errbuf, ep - errbuf);
+ }
+}
+
+/*
+ * getopt_sp is required to keep state between successive calls to getopt()
+ * while extracting aggregated options (ie: -abcd). Hence, getopt() is not
+ * thread safe or reentrant, but it really doesn't matter.
+ *
+ * So, why isn't this "static" you ask? Because the historical Bourne
+ * shell has actually latched on to this little piece of private data.
+ */
+int getopt_sp = 1;
+
+/*
+ * Determine if the specified character (c) is present in the string
+ * (optstring) as a regular, single character option. If the option is found,
+ * return a pointer into optstring pointing at the option character,
+ * otherwise return null. The character ':' is not allowed.
+ */
+static char *
+parse(const char *optstring, const char c)
+{
+ char *cp = (char *)optstring;
+
+ if (c == ':')
+ return (NULL);
+ do {
+ if (*cp == c)
+ return (cp);
+ } while (*cp++ != '\0');
+ return (NULL);
+}
+
+/*
+ * External function entry point.
+ */
+int
+getopt(int argc, char *const *argv, const char *optstring)
+{
+ char c;
+ char *cp;
+
+ /*
+ * Has the end of the options been encountered? The following
+ * implements the SUS requirements:
+ *
+ * If, when getopt() is called:
+ * argv[optind] is a null pointer
+ * *argv[optind] is not the character '-'
+ * argv[optind] points to the string "-"
+ * getopt() returns -1 without changing optind. If
+ * argv[optind] points to the string "--"
+ * getopt() returns -1 after incrementing optind.
+ */
+ if (getopt_sp == 1) {
+ if (optind >= argc || argv[optind][0] != '-' ||
+ argv[optind] == NULL || argv[optind][1] == '\0')
+ return (EOF);
+ else if (strcmp(argv[optind], "--") == 0) {
+ optind++;
+ return (EOF);
+ }
+ }
+
+ /*
+ * Getting this far indicates that an option has been encountered.
+ * Note that the syntax of optstring applies special meanings to
+ * the characters ':' and '(', so they are not permissible as
+ * option letters. A special meaning is also applied to the ')'
+ * character, but its meaning can be determined from context.
+ * Note that the specification only requires that the alnum
+ * characters be accepted.
+ */
+ optopt = c = (unsigned char)argv[optind][getopt_sp];
+ optarg = NULL;
+ if ((cp = parse(optstring, c)) == NULL) {
+ /* LINTED: variable format specifier */
+ ERR("illegal option", c);
+ if (argv[optind][++getopt_sp] == '\0') {
+ optind++;
+ getopt_sp = 1;
+ }
+ return ('?');
+ }
+ optopt = c = *cp;
+
+ /*
+ * A valid option has been identified. If it should have an
+ * option-argument, process that now. SUS defines the setting
+ * of optarg as follows:
+ *
+ * 1. If the option was the last character in the string pointed to
+ * by an element of argv, then optarg contains the next element
+ * of argv, and optind is incremented by 2. If the resulting
+ * value of optind is not less than argc, this indicates a
+ * missing option-argument, and getopt() returns an error
+ * indication.
+ *
+ * 2. Otherwise, optarg points to the string following the option
+ * character in that element of argv, and optind is incremented
+ * by 1.
+ *
+ * The second clause allows -abcd (where b requires an option-argument)
+ * to be interpreted as "-a -b cd".
+ */
+ if (*(cp + 1) == ':') {
+ /* The option takes an argument */
+ if (argv[optind][getopt_sp+1] != '\0') {
+ optarg = &argv[optind++][getopt_sp+1];
+ } else if (++optind >= argc) {
+ /* LINTED: variable format specifier */
+ ERR("option requires an argument", c);
+ getopt_sp = 1;
+ optarg = NULL;
+ return (optstring[0] == ':' ? ':' : '?');
+ } else
+ optarg = argv[optind++];
+ getopt_sp = 1;
+ } else {
+ /* The option does NOT take an argument */
+ if (argv[optind][++getopt_sp] == '\0') {
+ getopt_sp = 1;
+ optind++;
+ }
+ optarg = NULL;
+ }
+ return (c);
+} /* getopt() */
+
+#ifdef __APPLE__
+/*
+ * Starting with Mac OS 10.5 Leopard, <unistd.h> turns getopt()
+ * into getopt$UNIX2003() by default. Consequently, this function
+ * is called instead of the one defined above. However, optind is
+ * still taken from this file, so in effect, options are not
+ * properly handled. Defining an own getopt$UNIX2003() function
+ * works around this issue.
+ */
+int
+getopt$UNIX2003(int argc, char *const argv[], const char *optstring)
+{
+ return getopt(argc, argv, optstring);
+}
+#endif /* __APPLE__ */
diff --git a/troff/troff.d/dpost.d/glob.c b/troff/troff.d/dpost.d/glob.c
new file mode 100644
index 000000000000..3738ce688750
--- /dev/null
+++ b/troff/troff.d/dpost.d/glob.c
@@ -0,0 +1,56 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/* from OpenSolaris "glob.c 1.5 05/06/08 SMI" SVr4.0 1.1 */
+
+/*
+ * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
+ *
+ * Sccsid @(#)glob.c 1.3 (gritter) 8/9/05
+ */
+
+/*
+ *
+ * Definition and initialization of some global variables.
+ *
+ */
+
+
+#include <stdio.h>
+#include "gen.h" /* general purpose definitions */
+
+
+char **argv; /* global so everyone can use them */
+int argc;
+
+int x_stat = 0; /* program exit status */
+int debug = OFF; /* debug flag */
+int ignore = OFF; /* what we do with FATAL errors */
+
+long lineno = 0; /* line number */
+long position = 0; /* byte position */
+char *prog_name = ""; /* and program name - for errors */
+char *temp_file = NULL; /* temporary file - for some programs */
+
diff --git a/troff/troff.d/dpost.d/makedev.c b/troff/troff.d/dpost.d/makedev.c
new file mode 100644
index 000000000000..bbe7172b9b81
--- /dev/null
+++ b/troff/troff.d/dpost.d/makedev.c
@@ -0,0 +1,29 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
+ *
+ * Sccsid @(#)makedev.c 1.1 (gritter) 9/4/05
+ */
+
+#include "../makedev.c"
diff --git a/troff/troff.d/dpost.d/misc.c b/troff/troff.d/dpost.d/misc.c
new file mode 100644
index 000000000000..3d6692b72021
--- /dev/null
+++ b/troff/troff.d/dpost.d/misc.c
@@ -0,0 +1,395 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/*
+ * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* from OpenSolaris "misc.c 1.6 05/06/08 SMI" */
+
+/*
+ * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
+ *
+ * Sccsid @(#)misc.c 1.14 (gritter) 12/25/06
+ */
+
+/*
+ *
+ * A few general purpose routines.
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include "gen.h" /* a few general purpose definitions */
+#include "ext.h" /* external variable declarations */
+#include "path.h"
+#include "asciitype.h"
+
+
+static int nolist = 0; /* number of specified ranges */
+static int olist[512]; /* processing range pairs */
+
+
+void
+error(int kind, char *mesg, ...)
+{
+
+
+/*
+ *
+ * Called when we've run into some kind of program error. *mesg is printed using
+ * the control string arguments a?. We'll quit if we're not ignoring errors and
+ * kind is FATAL.
+ *
+ */
+
+
+ if ( mesg != NULL && *mesg != '\0' ) {
+ va_list ap;
+
+ fprintf(stderr, "%s: ", prog_name);
+ va_start(ap, mesg);
+ vfprintf(stderr, mesg, ap);
+ va_end(ap);
+ if ( lineno > 0 )
+ fprintf(stderr, " (line %ld)", lineno);
+ if ( position > 0 )
+ fprintf(stderr, " (near byte %ld)", position);
+ if ( printed > 0 )
+ fprintf(stderr, " (page %d)", printed);
+ putc('\n', stderr);
+ } /* End if */
+
+ if ( kind == FATAL && ignore == OFF ) {
+ if ( temp_file != NULL )
+ unlink(temp_file);
+ exit(x_stat | 01);
+ } /* End if */
+
+} /* End of error */
+
+
+/*****************************************************************************/
+/* for the AFM handling functions from troff */
+void
+verrprint(char *fmt, va_list ap)
+{
+ fprintf(stderr, "%s: ", prog_name);
+ vfprintf(stderr, fmt, ap);
+ putc('\n', stderr);
+}
+
+void
+errprint(char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ verrprint(fmt, ap);
+ va_end(ap);
+}
+
+/*****************************************************************************/
+
+
+void
+out_list (
+ char *str /* process ranges in this string */
+)
+
+
+{
+
+
+ int start, stop; /* end points */
+
+
+/*
+ *
+ * Called to get the processing ranges that were specified by using the -o option.
+ * The range syntax should be identical to the one used in nroff and troff.
+ *
+ */
+
+
+ while ( *str && nolist < sizeof(olist) - 2 ) {
+ start = stop = str_convert(&str, 0);
+
+ if ( *str == '-' && *str++ )
+ stop = str_convert(&str, 9999);
+
+ if ( start > stop )
+ error(FATAL, "illegal range %d-%d", start, stop);
+
+ olist[nolist++] = start;
+ olist[nolist++] = stop;
+
+ if ( *str != '\0' ) str++;
+
+ } /* End while */
+
+ olist[nolist] = 0;
+
+} /* End of out_list */
+
+
+/*****************************************************************************/
+
+
+int
+in_olist (
+ int num /* should we print this page? */
+)
+
+
+{
+
+
+ int i; /* just a loop index */
+
+
+/*
+ *
+ * Returns ON if num represents a page that we're supposed to print. If no ranges
+ * were selected nolist will be 0 and we'll print everything.
+ *
+ */
+
+
+ if ( nolist == 0 ) /* everything's included */
+ return(ON);
+
+ for ( i = 0; i < nolist; i += 2 )
+ if ( num >= olist[i] && num <= olist[i+1] )
+ return(ON);
+
+ return(OFF);
+
+} /* End of in_olist */
+
+
+/*****************************************************************************/
+
+
+int
+cat (
+ char *file, /* copy this file to out */
+ FILE *out
+)
+
+
+{
+
+
+ int fd_in; /* for the input */
+ int fd_out; /* and output files */
+ char buf[512]; /* buffer for reads and writes */
+ int count; /* number of bytes we just read */
+
+
+/*
+ *
+ * Copies *file to stdout - mostly for the prologue. Returns FALSE if there was a
+ * problem and TRUE otherwise.
+ *
+ */
+
+
+ fflush(out);
+
+ if ( (fd_in = open(file, O_RDONLY)) == -1 )
+ return(FALSE);
+
+ fd_out = fileno(out);
+ while ( (count = read(fd_in, buf, sizeof(buf))) > 0 )
+ write(fd_out, buf, count);
+
+ close(fd_in);
+
+ return(TRUE);
+
+} /* End of cat */
+
+
+/*****************************************************************************/
+
+
+int
+str_convert (
+ char **str, /* get next number from this string */
+ int err /* value returned on error */
+)
+
+
+{
+
+
+ int i; /* just a loop index */
+ int c;
+
+
+/*
+ *
+ * Gets the next integer from **str and returns its value to the caller. If **str
+ * isn't an integer err is returned. *str is updated after each digit is processed.
+ *
+ */
+
+
+ if ( ! isdigit(c = **str) ) /* something's wrong */
+ return(err);
+
+ for ( i = 0; isdigit(c = **str); *str += 1 )
+ i = 10 * i + c - '0';
+
+ return(i);
+
+} /* End of str_convert */
+
+
+/*****************************************************************************/
+
+
+
+
+void interrupt(
+
+
+ int sig) /* signal that we caught */
+
+
+{
+
+
+/*
+ *
+ * Called when we get a signal that we're supposed to catch.
+ *
+ */
+
+
+ if ( temp_file != NULL )
+ unlink(temp_file);
+
+ exit(1);
+
+} /* End of interrupt */
+
+
+/*****************************************************************************/
+
+
+char *
+tempname(const char *sfx)
+{
+ size_t l = strlen(TEMPDIR) + strlen(sfx) + 10;
+ char *pat = malloc(l);
+ snprintf(pat, l, "%s/%sXXXXXX", TEMPDIR, sfx);
+ if (close(mkstemp(pat)) < 0)
+ return NULL;
+ return pat;
+}
+
+
+/*****************************************************************************/
+
+
+#if defined (__GLIBC__) && defined (_IO_getc_unlocked)
+#undef getc
+#define getc(f) _IO_getc_unlocked(f)
+#endif
+
+#define LSIZE 512
+
+int psskip(size_t n, FILE *fp)
+{
+ return fseek(fp, n, SEEK_CUR);
+}
+
+char *psgetline(char **line, size_t *linesize, size_t *llen, FILE *fp)
+{
+ int c;
+ size_t n = 0;
+ int nl = 0;
+
+ if (*line == NULL || *linesize < LSIZE + n + 1)
+ *line = realloc(*line, *linesize = LSIZE + n + 1);
+ for (;;) {
+ if (n >= *linesize - LSIZE / 2)
+ *line = realloc(*line, *linesize += LSIZE);
+ c = getc(fp);
+ if (c != EOF) {
+ if (nl && c != '\n') {
+ ungetc(c, fp);
+ break;
+ }
+ (*line)[n++] = c;
+ (*line)[n] = '\0';
+ if (c == '\n')
+ break;
+ if (c == '\r')
+ nl = 1;
+ } else {
+ if (n > 0)
+ break;
+ else
+ return NULL;
+ }
+ }
+ if (llen)
+ *llen = n;
+ return *line;
+}
+
+
+/*****************************************************************************/
+
+
+int
+sget(char *buf, size_t size, FILE *fp)
+{
+ int c, n = 0;
+
+ do
+ c = getc(fp);
+ while (spacechar(c));
+ if (c != EOF) do {
+ if (n+1 < size)
+ buf[n++] = c;
+ c = getc(fp);
+ } while (c != EOF && !spacechar(c));
+ ungetc(c, fp);
+ buf[n] = 0;
+ return n > 1 ? 1 : c == EOF ? EOF : 0;
+}
diff --git a/troff/troff.d/dpost.d/otf.c b/troff/troff.d/dpost.d/otf.c
new file mode 100644
index 000000000000..9e193247cf34
--- /dev/null
+++ b/troff/troff.d/dpost.d/otf.c
@@ -0,0 +1,36 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
+ *
+ * Sccsid @(#)otf.c 1.3 (gritter) 10/13/05
+ */
+
+#include <stdio.h>
+#if defined (__GLIBC__) && defined (_IO_putc_unlocked)
+#undef putc
+#define putc(c, f) _IO_putc_unlocked(c, f)
+#endif
+
+#define DPOST
+#include "../otf.c"
diff --git a/troff/troff.d/dpost.d/path.h b/troff/troff.d/dpost.d/path.h
new file mode 100644
index 000000000000..2723e74f81f6
--- /dev/null
+++ b/troff/troff.d/dpost.d/path.h
@@ -0,0 +1,61 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/* from OpenSolaris "path.h 1.5 05/06/08 SMI" SVr4.0 1.6 */
+
+/*
+ * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
+ *
+ * Sccsid @(#)path.h 1.5 (gritter) 12/18/05
+ */
+/*
+ *
+ * pathname definitions for important files and directories.
+ *
+ */
+
+
+#define DPOST PSTDIR "/dpost.ps"
+#define POSTBGI PSTDIR "/postbgi.ps"
+#define POSTDAISY PSTDIR "/postdaisy.ps"
+#define POSTDMD PSTDIR "/postdmd.ps"
+#define POSTMD PSTDIR "/postmd.ps"
+#define POSTPLOT PSTDIR "/postplot.ps"
+#define POSTPRINT PSTDIR "/postprint.ps"
+#define POSTTEK PSTDIR "/posttek.ps"
+
+#define BASELINE PSTDIR "/baseline.ps"
+#define COLOR PSTDIR "/color.ps"
+#define CUTMARKS PSTDIR "/cutmarks.ps"
+#define DRAW PSTDIR "/draw.ps"
+#define FORMFILE PSTDIR "/forms.ps"
+#define KERNING PSTDIR "/kerning.ps"
+#define REQUESTFILE PSTDIR "/ps.requests"
+#define PSINCLUDEFILE PSTDIR "/ps_include.ps"
+
+#define HOSTFONTDIR "/usr/share/lib/hostfontdir"
+#define FONTDIR FNTDIR
+#define TEMPDIR "/tmp"
+
diff --git a/troff/troff.d/dpost.d/pictures.c b/troff/troff.d/dpost.d/pictures.c
new file mode 100644
index 000000000000..e6c135dd2947
--- /dev/null
+++ b/troff/troff.d/dpost.d/pictures.c
@@ -0,0 +1,364 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 1993 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/* from OpenSolaris "pictures.c 1.7 05/06/08 SMI" SVr4.0 1.1 */
+
+/*
+ * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
+ *
+ * Sccsid @(#)pictures.c 1.7 (gritter) 3/27/07
+ */
+
+/*
+ *
+ * PostScript picture inclusion routines. Support for managing in-line pictures
+ * has been added, and works in combination with the simple picpack pre-processor
+ * that's supplied with this package. An in-line picture begins with a special
+ * device control command that looks like,
+ *
+ * x X InlinPicture name size
+ *
+ * where name is the pathname of the original picture file and size is the number
+ * of bytes in the picture, which begins immediately on the next line. When dpost
+ * encounters the InlinePicture device control command inlinepic() is called and
+ * that routine appends the string name and the integer size to a temporary file
+ * (fp_pic) and then adds the next size bytes read from the current input file to
+ * file fp_pic. All in-line pictures are saved in fp_pic and located later using
+ * the name string and picture file size that separate pictures saved in fp_pic.
+ *
+ * When a picture request (ie. an "x X PI" command) is encountered picopen() is
+ * called and it first looks for the picture file in fp_pic. If it's found there
+ * the entire picture (ie. size bytes) is copied from fp_pic to a new temp file
+ * and that temp file is used as the picture file. If there's nothing in fp_pic
+ * or if the lookup failed the original route is taken.
+ *
+ * Support for in-line pictures is an attempt to address requirements, expressed
+ * by several orginazations, of being able to store a document as a single file
+ * (usually troff input) that can then be sent through dpost and ultimately to
+ * a PostScript printer. The mechanism may help some users, but the are obvious
+ * disadvantages to this approach, and the original mechanism is the recommended
+ * approach! Perhaps the most important problem is that troff output, with in-line
+ * pictures included, doesn't fit the device independent language accepted by
+ * important post-processors (like proff) and that means you won't be able to
+ * reliably preview a packed file on your 5620 (or whatever).
+ *
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "comments.h" /* PostScript file structuring comments */
+#include "gen.h" /* general purpose definitions */
+#include "path.h" /* just for TEMPDIR definition */
+
+
+static FILE *fp_pic = NULL; /* in-line pictures go here */
+
+extern int res, hpos, vpos;
+extern int picflag;
+extern FILE *tf;
+
+
+/*****************************************************************************/
+
+
+void
+picture (
+ char *buf /* stuff following 'x X PI' command */
+)
+
+
+{
+
+
+ int poffset; /* page offset */
+ int indent; /* indent */
+ int length; /* line length */
+ int totrap; /* distance to next trap */
+ char name[4096]; /* picture file and page string */
+ char hwo[4096], *p; /* height, width and offset strings */
+ char flags[4096]; /* miscellaneous stuff */
+ int page = 1; /* page number pulled from name[] */
+ double frame[4]; /* height, width, y, and x offsets from hwo[] */
+ char units; /* scale indicator for frame dimensions */
+ int whiteout = 0; /* white out the box? */
+ int outline = 0; /* draw a box around the picture? */
+ int scaleboth = 0; /* scale both dimensions? */
+ double adjx = 0.5; /* left-right adjustment */
+ double adjy = 0.5; /* top-bottom adjustment */
+ double rot = 0; /* rotation in clockwise degrees */
+ FILE *fp_in; /* for *name */
+ int i; /* loop index */
+
+
+/*
+ *
+ * Called from devcntrl() after an 'x X PI' command is found. The syntax of that
+ * command is:
+ *
+ * x X PI:args
+ *
+ * with args separated by colons and given by:
+ *
+ * poffset
+ * indent
+ * length
+ * totrap
+ * file[(page)]
+ * height[,width[,yoffset[,xoffset]]]
+ * [flags]
+ *
+ * poffset, indent, length, and totrap are given in machine units. height, width,
+ * and offset refer to the picture frame in inches, unless they're followed by
+ * the u scale indicator. flags is a string that provides a little bit of control
+ * over the placement of the picture in the frame. Rotation of the picture, in
+ * clockwise degrees, is set by the a flag. If it's not followed by an angle
+ * the current rotation angle is incremented by 90 degrees, otherwise the angle
+ * is set by the number that immediately follows the a.
+ *
+ */
+
+
+ if ( picflag == OFF ) /* skip it */
+ return;
+
+ endtext();
+
+ flags[0] = '\0'; /* just to be safe */
+ if ( sscanf(buf, "%d:%d:%d:%d:%[^:]:%[^:]:%[^:]", &poffset, &indent,
+ &length, &totrap, name, hwo, flags) < 6 ) {
+ error(NON_FATAL, "too few arguments to specify picture");
+ return;
+ } /* End if */
+
+ if ( sscanf(name, "%*[^(](%d", &page) == 1 ) /* grab the page number */
+ strtok(name, "("); /* and separate it from the name */
+
+ if ( (fp_in = picopen(name)) == NULL ) {
+ error(NON_FATAL, "can't open picture file %s", name);
+ return;
+ } /* End if */
+
+ frame[0] = frame[1] = -1; /* default frame height, width */
+ frame[2] = frame[3] = 0; /* and y and x offsets */
+
+ for ( i = 0, p = hwo; i < 4 && p != NULL; i++, p = strchr(p, ',') ) {
+ if (i)
+ p++;
+ if ( sscanf(p, "%lf%c", &frame[i], &units) == 2 )
+ if ( units == 'i' || units == ',' || units == '\0' )
+ frame[i] *= res;
+ }
+
+ if ( frame[0] <= 0 ) /* check what we got for height */
+ frame[0] = totrap;
+
+ if ( frame[1] <= 0 ) /* and width - check too big?? */
+ frame[1] = length - indent;
+
+ frame[3] += poffset + indent; /* real x offset */
+
+ for ( i = 0; flags[i]; i++ )
+ switch ( flags[i] ) {
+ case 'c': adjx = adjy = 0.5; break; /* move to the center */
+ case 'l': adjx = 0; break; /* left */
+ case 'r': adjx = 1; break; /* right */
+ case 't': adjy = 1; break; /* top */
+ case 'b': adjy = 0; break; /* or bottom justify */
+ case 'o': outline = 1; break; /* outline the picture */
+ case 'w': whiteout = 1; break; /* white out the box */
+ case 's': scaleboth = 1; break; /* scale both dimensions */
+ case 'a': if ( sscanf(&flags[i+1], "%lf", &rot) != 1 )
+ rot += 90;
+ } /* End switch */
+
+ fprintf(tf, "save mark\n");
+ fprintf(tf, "[ /NamespacePush pdfmark\n");
+
+ ps_include(name, fp_in, tf, page, whiteout, outline, scaleboth,
+ frame[3]+frame[1]/2, -vpos-frame[2]-frame[0]/2, frame[1], frame[0], adjx, adjy, -rot);
+
+ fprintf(tf, "[ /NamespacePop pdfmark\n");
+ fprintf(tf, "cleartomark restore\n");
+ xymove(hpos, vpos);
+ t_sf(1);
+
+ fclose(fp_in);
+
+} /* End of picture */
+
+
+/*****************************************************************************/
+
+
+FILE *picopen(
+
+
+ char *path /* picture file pathname */
+)
+
+
+{
+
+
+ char name[4096]; /* pathnames */
+ long total; /* and sizes - from *fp_pic */
+ char *tname; /* pathname */
+ FILE *fp; /* and pointer for the new temp file */
+
+
+/*
+ *
+ * Responsible for finding and opening the next picture file. If we've accumulated
+ * any in-line pictures fp_pic won't be NULL and we'll look there first. If *path
+ * is found in *fp_pic we create another temp file, open it for update, unlink it,
+ * copy in the picture, seek back to the start of the new temp file, and return
+ * the file pointer to the caller. If fp_pic is NULL or the lookup fails we just
+ * open file *path and return the resulting file pointer to the caller.
+ *
+ */
+
+
+ if ( fp_pic != NULL ) {
+ fseek(fp_pic, 0L, SEEK_SET);
+ while ( fscanf(fp_pic, "%s %ld\n", name, &total) != EOF ) {
+ if ( strcmp(path, name) == 0 ) {
+ if ( (tname = tempname("dpost")) == NULL )
+ error(FATAL, "can't generate temp file name");
+ if ( (fp = fopen(tname, "w+")) == NULL )
+ error(FATAL, "can't open %s", tname);
+ unlink(tname);
+ free(tname);
+ piccopy(fp_pic, fp, total);
+ fseek(fp, 0L, SEEK_SET);
+ return(fp);
+ } /* End if */
+ fseek(fp_pic, total, SEEK_CUR);
+ } /* End while */
+ } /* End if */
+
+ return(fopen(path, "r"));
+
+} /* End of picopen */
+
+
+/*****************************************************************************/
+
+
+void
+inlinepic(
+
+
+ FILE *fp, /* current input file */
+ char *buf /* whatever followed "x X InlinePicture" */
+)
+
+
+{
+
+
+ char *tname; /* temp file pathname - for *fp_pic */
+ char name[4096]; /* picture file pathname */
+ long total; /* and size - both from *buf */
+
+
+/*
+ *
+ * Adds an in-line picture file to the end of temporary file *fp_pic. All pictures
+ * grabbed from the input file are saved in the same temp file. Each is preceeded
+ * by a one line header that includes the original picture file pathname and the
+ * size of the picture in bytes. The in-line picture file is opened for update,
+ * left open, and unlinked so it disappears when we do.
+ *
+ */
+
+
+ if ( fp_pic == NULL ) {
+ if ( (tname = tempname("dpost")) == NULL )
+ error(FATAL, "can't generate in-line picture file name");
+ if ( (fp_pic = fopen(tname, "w+")) == NULL )
+ error(FATAL, "can't open in-line picture file %s", tname);
+ unlink(tname);
+ } /* End if */
+
+ if ( sscanf(buf, "%s %ld", name, &total) != 2 )
+ error(FATAL, "in-line picture error");
+
+ fseek(fp_pic, 0L, SEEK_END);
+ fprintf(fp_pic, "%s %ld\n", name, total);
+ getc(fp);
+ fflush(fp_pic);
+ piccopy(fp, fp_pic, total);
+ ungetc('\n', fp);
+
+} /* End of inlinepic */
+
+
+/*****************************************************************************/
+
+
+void
+piccopy(
+
+
+ FILE *fp_in, /* input */
+ FILE *fp_out, /* and output file pointers */
+ long total /* number of bytes to be copied */
+)
+
+
+{
+
+
+ long i; /* loop index */
+
+
+/*
+ *
+ * Copies total bytes from file fp_in to fp_out. Used to append picture files to
+ * *fp_pic and then copy them to yet another temporary file immediately before
+ * they're used (in picture()).
+ *
+ */
+
+
+ for ( i = 0; i < total; i++ )
+ if ( putc(getc(fp_in), fp_out) == EOF )
+ error(FATAL, "error copying in-line picture file");
+ fflush(fp_out);
+
+} /* End of piccopy */
+
+
+/*****************************************************************************/
+
diff --git a/troff/troff.d/dpost.d/ps_include.c b/troff/troff.d/dpost.d/ps_include.c
new file mode 100644
index 000000000000..758bde956243
--- /dev/null
+++ b/troff/troff.d/dpost.d/ps_include.c
@@ -0,0 +1,361 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/* from OpenSolaris "ps_include.c 1.5 05/06/08 SMI" SVr4.0 1.3 */
+
+/*
+ * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
+ *
+ * Sccsid @(#)ps_include.c 1.10 (gritter) 10/15/06
+ */
+
+/*
+ *
+ * Picture inclusion code for PostScript printers.
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "gen.h"
+#include "ext.h"
+#include "path.h"
+#include "asciitype.h"
+
+
+#define var(x) fprintf(fout, "/%s %g def\n", #x, x)
+#define has(word) _has(buf, word)
+#define grab(n) ((Section *)(nglobal \
+ ? realloc((char *)global, n*sizeof(Section)) \
+ : calloc(n, sizeof(Section))))
+
+
+static char *buf;
+static size_t bufsize;
+typedef struct {long start, end;} Section;
+
+static void copy(FILE *, FILE *, Section *);
+static char *_has(const char *, const char *);
+static void addfonts(char *);
+
+/*****************************************************************************/
+
+
+void
+ps_include(
+
+
+ const char *name, /* file name */
+ FILE *fin, FILE *fout, /* input and output files */
+ int page_no, /* physical page number from *fin */
+ int whiteout, /* erase picture area */
+ int outline, /* draw a box around it and */
+ int scaleboth, /* scale both dimensions - if not zero */
+ double cx, double cy, /* center of the picture and */
+ double sx, double sy, /* its size - in current coordinates */
+ double ax, double ay, /* left-right, up-down adjustment */
+ double rot /* rotation - in clockwise degrees */
+)
+
+
+{
+
+ static int gotinclude;
+
+ int foundpage = 0; /* found the page when non zero */
+ int nglobal = 0; /* number of global defs so far */
+ int maxglobal = 0; /* and the number we've got room for */
+ Section prolog, page, trailer; /* prologue, page, and trailer offsets */
+ Section *global = 0; /* offsets for all global definitions */
+ double llx, lly; /* lower left and */
+ double urx, ury; /* upper right corners - default coords */
+ double w = whiteout != 0; /* mostly for the var() macro */
+ double o = outline != 0;
+ double s = scaleboth != 0;
+ int i; /* loop index */
+ int lineno = 0;
+ int epsf = 0;
+ int hires = 0;
+ int state = 0;
+ int indoc = 0;
+ char *bp, *cp;
+ enum {
+ NORMAL,
+ DOCUMENTFONTS,
+ DOCUMENTNEEDEDRESOURCES,
+ } cont = NORMAL;
+
+
+/*
+ *
+ * Reads a PostScript file (*fin), and uses structuring comments to locate the
+ * prologue, trailer, global definitions, and the requested page. After the whole
+ * file is scanned, the special ps_include PostScript definitions are copied to
+ * *fout, followed by the prologue, global definitions, the requested page, and
+ * the trailer. Before returning the initial environment (saved in PS_head) is
+ * restored.
+ *
+ * By default we assume the picture is 8.5 by 11 inches, but the BoundingBox
+ * comment, if found, takes precedence.
+ *
+ */
+
+ if (gotinclude == 0 && access(PSINCLUDEFILE, 04) == 0) {
+ doglobal(PSINCLUDEFILE);
+ gotinclude++;
+ }
+
+ llx = lly = 0; /* default BoundingBox - 8.5x11 inches */
+ urx = 72 * 8.5;
+ ury = 72 * 11.0;
+
+ /* section boundaries and bounding box */
+
+ prolog.start = prolog.end = 0;
+ page.start = page.end = 0;
+ trailer.start = 0;
+ fseek(fin, 0L, SEEK_SET);
+
+ while ( psgetline(&buf, &bufsize, NULL, fin) != NULL ) {
+ if (++lineno == 1 && strncmp(buf, "%!PS-", 5) == 0) {
+ for (bp = buf; !spacechar(*bp&0377); bp++);
+ while (*bp && *bp != '\n' && *bp != '\r' &&
+ spacechar(*bp&0377))
+ bp++;
+ if (strncmp(bp, "EPSF-", 5) == 0)
+ epsf++;
+ }
+ if (state == 0 && (*buf == '\n' || has("%%EndComments") ||
+ buf[0] != '%' || buf[1] == ' ' ||
+ buf[1] == '\t' || buf[1] == '\r' ||
+ buf[1] == '\n')) {
+ state = 1;
+ continue;
+ }
+ if (buf[0] != '%' || buf[1] != '%')
+ continue;
+ if (state != 1 && (bp = has("%%+")) != NULL) {
+ switch (cont) {
+ case DOCUMENTFONTS:
+ addfonts(bp);
+ break;
+ case DOCUMENTNEEDEDRESOURCES:
+ goto needres;
+ }
+ continue;
+ } else
+ cont = NORMAL;
+ if (has("%%Page: ")) {
+ if (!foundpage)
+ page.start = ftell(fin);
+ sscanf(buf, "%*s %*s %d", &i);
+ if (i == page_no)
+ foundpage = 1;
+ else if (foundpage && page.end <= page.start)
+ page.end = ftell(fin);
+ } else if (has("%%EndPage: ")) {
+ sscanf(buf, "%*s %*s %d", &i);
+ if (i == page_no) {
+ foundpage = 1;
+ page.end = ftell(fin);
+ }
+ if (!foundpage)
+ page.start = ftell(fin);
+ } else if (state != 1 && !indoc &&
+ has("%%BoundingBox:") && !hires) {
+ sscanf(buf, "%%%%BoundingBox: %lf %lf %lf %lf", &llx, &lly, &urx, &ury);
+ if (epsf)
+ epsf++;
+ } else if (state != 1 && !indoc && has("%%HiResBoundingBox:")) {
+ sscanf(buf, "%%%%HiResBoundingBox: %lf %lf %lf %lf", &llx, &lly, &urx, &ury);
+ hires++;
+ if (epsf)
+ epsf++;
+ } else if (has("%%LanguageLevel:")) {
+ int n;
+ sscanf(buf, "%%%%LanguageLevel: %d", &n);
+ LanguageLevel = MAX(LanguageLevel, n);
+ } else if ((bp = has("%%DocumentNeededFonts:")) != NULL ||
+ (bp = has("%%DocumentFonts:")) != NULL) {
+ cont = DOCUMENTFONTS;
+ addfonts(bp);
+ } else if ((bp = has("%%DocumentNeededResources:")) != NULL) {
+ needres:
+ if ((cp = _has(bp, "font")))
+ addfonts(cp);
+ else {
+ for (cp = bp; *cp && *cp != '\n' &&
+ *cp != '\r'; cp++);
+ *cp = '\0';
+ needresource("%s", bp);
+ }
+ cont = DOCUMENTNEEDEDRESOURCES;
+ } else if (indoc == 0 && (has("%%EndProlog") ||
+ has("%%EndSetup") || has("%%EndDocumentSetup")))
+ prolog.end = page.start = ftell(fin);
+ else if (indoc == 0 && has("%%EOF"))
+ break;
+ else if (state == 1 && indoc == 0 && has("%%Trailer")) {
+ trailer.start = ftell(fin);
+ state = 2;
+ } else if (state == 1 && has("%%BeginDocument:"))
+ indoc++;
+ else if (state == 1 && indoc > 0 && has("%%EndDocument"))
+ indoc--;
+ else if (state == 1 && (cp = has("%%BeginBinary:")) != NULL) {
+ if ((i = strtol(cp, &cp, 10)) > 0)
+ psskip(i, fin);
+ } else if (state == 1 && (cp = has("%%BeginData:")) != NULL) {
+ if ((i = strtol(cp, &cp, 10)) > 0) {
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ while (*cp && *cp != ' ' && *cp != '\t')
+ cp++;
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if (strncmp(cp, "Bytes", 5) == 0)
+ psskip(i, fin);
+ else if (strncmp(cp, "Lines", 5) == 0) {
+ while (i-- && psgetline(&buf,
+ &bufsize, NULL, fin) != NULL);
+ }
+ }
+ } else if (has("%%BeginGlobal")) {
+ if (page.end <= page.start) {
+ if (nglobal >= maxglobal) {
+ maxglobal += 20;
+ global = grab(maxglobal);
+ }
+ global[nglobal].start = ftell(fin);
+ }
+ } else if (has("%%EndGlobal"))
+ if (page.end <= page.start)
+ global[nglobal++].end = ftell(fin);
+ }
+
+ fseek(fin, 0L, SEEK_END);
+ if (trailer.start == 0)
+ trailer.start = ftell(fin);
+ trailer.end = ftell(fin);
+
+ if (page.end <= page.start)
+ page.end = trailer.start;
+
+/*
+fprintf(stderr, "prolog=(%d,%d)\n", prolog.start, prolog.end);
+fprintf(stderr, "page=(%d,%d)\n", page.start, page.end);
+for(i = 0; i < nglobal; i++)
+ fprintf(stderr, "global[%d]=(%d,%d)\n", i, global[i].start, global[i].end);
+fprintf(stderr, "trailer=(%d,%d)\n", trailer.start, trailer.end);
+*/
+
+ /* all output here */
+ fprintf(fout, "_ps_include_head\n");
+ var(llx); var(lly); var(urx); var(ury); var(w); var(o); var(s);
+ var(cx); var(cy); var(sx); var(sy); var(ax); var(ay); var(rot);
+ fprintf(fout, "_ps_include_setup\n");
+ if (epsf >= 2) {
+ size_t len;
+ rewind(fin);
+ fprintf(fout, "%%%%BeginDocument: %s\n", name);
+ while (psgetline(&buf, &bufsize, &len, fin) != NULL) {
+ if (has("%%BeginPreview:")) {
+ while (psgetline(&buf, &bufsize, &len, fin)
+ != NULL &&
+ !has("%%EndPreview"));
+ continue;
+ }
+ fwrite(buf, 1, len, fout);
+ }
+ fprintf(fout, "%%%%EndDocument\n");
+ } else {
+ copy(fin, fout, &prolog);
+ for(i = 0; i < nglobal; i++)
+ copy(fin, fout, &global[i]);
+ copy(fin, fout, &page);
+ copy(fin, fout, &trailer);
+ }
+ fprintf(fout, "_ps_include_tail\n");
+
+ if(nglobal)
+ free(global);
+
+}
+
+static void
+copy(FILE *fin, FILE *fout, Section *s)
+{
+ size_t len;
+
+ if (s->end <= s->start)
+ return;
+ fseek(fin, s->start, SEEK_SET);
+ while (ftell(fin) < s->end &&
+ psgetline(&buf, &bufsize, &len, fin) != NULL) {
+ if (buf[0] == '%')
+ putc(' ', fout);
+ fwrite(buf, 1, len, fout);
+ }
+}
+
+static char *
+_has(const char *buf, const char *word)
+{
+ int n;
+
+ n = strlen(word);
+ if (strncmp(buf, word, n) != 0)
+ return NULL;
+ if (buf[n] == ' ' || buf[n] == '\t' || buf[n] == '\r' ||
+ buf[n] == '\n' || buf[n] == 0) {
+ while (buf[n] == ' ' || buf[n] == '\t')
+ n++;
+ return (char *)&buf[n];
+ }
+ return NULL;
+}
+
+static void
+addfonts(char *line)
+{
+ char *lp = line, c;
+
+ do {
+ while (*lp == ' ' || *lp == '\t')
+ lp++;
+ line = lp;
+ while (*lp && *lp != ' ' && *lp != '\t' && *lp != '\n' &&
+ *lp != '\r')
+ lp++;
+ c = *lp;
+ *lp = '\0';
+ if (*line && strcmp(line, "(atend)"))
+ documentfont(line);
+ *lp = c;
+ } while (c && c != '\n' && c != '\r');
+}
diff --git a/troff/troff.d/dpost.d/request.c b/troff/troff.d/dpost.d/request.c
new file mode 100644
index 000000000000..3cf447b42741
--- /dev/null
+++ b/troff/troff.d/dpost.d/request.c
@@ -0,0 +1,182 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/* from OpenSolaris "request.c 1.5 05/06/08 SMI" SVr4.0 1.1 */
+
+/*
+ * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
+ *
+ * Sccsid @(#)request.c 1.3 (gritter) 8/9/05
+ */
+
+/*
+ *
+ * Things used to handle special requests (eg. manual feed) globally or on a per
+ * page basis. Requests are passed through to the translator using the -R option.
+ * The argument to -R can be "request", "request:page", or "request:page:file".
+ * If page is omitted (as in the first form) or set to 0 request will be applied
+ * to the global environment. In all other cases it applies only to the selected
+ * page. If a file is given, page must be supplied, and the lookup is in that file
+ * rather than *requestfile.
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gen.h" /* general purpose definitions */
+#include "request.h" /* a few special definitions */
+#include "path.h" /* for the default request file */
+
+
+Request request[MAXREQUEST]; /* next page or global request */
+int nextreq = 0; /* goes in request[nextreq] */
+char *requestfile = REQUESTFILE; /* default lookup file */
+
+
+/*****************************************************************************/
+
+
+void
+saverequest (
+ char *want /* grab code for this stuff */
+)
+
+
+{
+
+
+ char *page; /* and save it for this page */
+
+
+/*
+ *
+ * Save the request until we get to appropriate page - don't even bother with
+ * the lookup right now. Format of *want string is "request", "request:page", or
+ * "request:page:file", and we assume we can change the string here as needed.
+ * If page is omitted or given as 0 the request will be done globally. If *want
+ * includes a file, request and page must also be given, and in that case *file
+ * will be used for the lookup.
+ *
+ */
+
+
+ if ( nextreq < MAXREQUEST ) {
+ request[nextreq].want = strtok(want, ": ");
+ if ( (page = strtok(NULL, ": ")) == NULL )
+ request[nextreq].page = 0;
+ else request[nextreq].page = atoi(page);
+ if ( (request[nextreq].file = strtok(NULL, ": ")) == NULL )
+ request[nextreq].file = requestfile;
+ nextreq++;
+ } else error(NON_FATAL, "too many requests - ignoring %s", want);
+
+} /* End of saverequest */
+
+
+/*****************************************************************************/
+
+
+void
+writerequest(
+
+
+ int page, /* write everything for this page */
+ FILE *fp_out /* to this file */
+)
+
+
+{
+
+ int i; /* loop index */
+
+
+/*
+ *
+ * Writes out all the requests that have been saved for page. Page 0 refers to
+ * the global environment and is done during initial setup.
+ *
+ */
+
+
+ for ( i = 0; i < nextreq; i++ )
+ if ( request[i].page == page )
+ dumprequest(request[i].want, request[i].file, fp_out);
+
+} /* End of writerequest */
+
+
+/*****************************************************************************/
+
+
+void
+dumprequest(
+
+
+ char *want, /* look for this string */
+ char *file, /* in this file */
+ FILE *fp_out /* and write the value out here */
+)
+
+
+{
+
+
+ char buf[100]; /* line buffer for reading *file */
+ FILE *fp_in;
+
+
+/*
+ *
+ * Looks for *want in the request file and if it's found the associated value
+ * is copied to the output file. Keywords (ie. the *want strings) begin an @ in
+ * the first column of file, while the values (ie. the stuff that's copied to
+ * the output file) starts on the next line and extends to the next keyword or
+ * to the end of file.
+ *
+ */
+
+
+ if ( (fp_in = fopen(file, "r")) != NULL ) {
+ while ( fgets(buf, sizeof(buf), fp_in) != NULL )
+ if ( buf[0] == '@' && strncmp(want, &buf[1], strlen(want)) == 0 )
+ while ( fgets(buf, sizeof(buf), fp_in) != NULL )
+ {
+ if ( buf[0] == '#' || buf[0] == '%' )
+ continue;
+ else if ( buf[0] != '@' )
+ fprintf(fp_out, "%s", buf);
+ else break;
+ }
+ fclose(fp_in);
+ } /* End if */
+
+} /* End of dumprequest */
+
+
+/*****************************************************************************/
+
diff --git a/troff/troff.d/dpost.d/request.h b/troff/troff.d/dpost.d/request.h
new file mode 100644
index 000000000000..829c7020d636
--- /dev/null
+++ b/troff/troff.d/dpost.d/request.h
@@ -0,0 +1,58 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+/* from OpenSolaris "request.h 1.5 05/06/08 SMI" SVr4.0 1.1 */
+
+/*
+ * Portions Copyright (c) 2005 Gunnar Ritter, Freiburg i. Br., Germany
+ *
+ * Sccsid @(#)request.h 1.3 (gritter) 8/9/05
+ */
+
+/*
+ *
+ * Things used to handle special PostScript requests (like manual feed) globally
+ * or on a per page basis. All the translators I've supplied accept the -R option
+ * that can be used to insert special PostScript code before the global setup is
+ * done, or at the start of named pages. The argument to the -R option is a string
+ * that can be "request", "request:page", or "request:page:file". If page isn't
+ * given (as in the first form) or if it's 0 in the last two, the request applies
+ * to the global environment, otherwise request holds only for the named page.
+ * If a file name is given a page number must be supplied, and in that case the
+ * request will be looked up in that file.
+ *
+ */
+
+#define MAXREQUEST 30
+
+typedef struct {
+
+ char *want;
+ int page;
+ char *file;
+
+} Request;
+
+
diff --git a/troff/troff.d/dpost.d/version.c b/troff/troff.d/dpost.d/version.c
new file mode 100644
index 000000000000..b87752dda8b8
--- /dev/null
+++ b/troff/troff.d/dpost.d/version.c
@@ -0,0 +1,3 @@
+/* Sccsid @(#)dpost_version.c 4.37 (gritter) 10/3/05 */
+#define DPOST
+#include "../../version.c"