1 // Copyright 2009 The Archiveopteryx Developers <info@aox.org>
2
3 #include "postscript.h"
4
5 #include "file.h"
6 #include "error.h"
7 #include "class.h"
8 #include "function.h"
9
10
11 static const char * prologue =
12 "%!PS-Adobe-3.0\n"
13 "%%Creator: udoc, http://archiveopteryx.org/udoc/\n"
14 "%%PageOrder: Ascend\n"
15 "%%DocumentMedia:\n"
16 "%%BoundingBox: 0 0 595 841\n"
17 "%%DocumentData: Clean8Bit\n"
18 "%%Orientation: Portrait\n"
19 "%%EndComments\n"
20 "\n"
21 "%%BeginProlog\n"
22 "\n"
23 "/mm { 72 mul 25.4 div } bind def\n"
24 "\n"
25 "/lx 20 mm def\n"
26 "/rx 190 mm def\n"
27 "/dy 12 def\n"
28 "/ty 279 mm def\n"
29 "/by 25 mm def\n"
30 "/page 1 def\n"
31 "\n"
32 "/header\n" // shows page number
33 "{ page 10 string cvs dup stringwidth pop\n"
34 " rx exch sub 285 mm moveto\n"
35 " show\n"
36 "} bind def\n"
37 "/l\n" // shows a single line of text and moves the point down
38 "{\n"
39 " currentpoint 3 -1 roll show dy sub moveto\n"
40 "} bind def\n"
41 "\n"
42 "/s\n" // tos: word. shows a single word and one trailing space.
43 "{ dup stringwidth pop currentpoint pop add rx gt\n"
44 " { currentpoint exch pop dy sub\n"
45 " dup by lt { showpage pop ty /page page 1 add def header } if\n"
46 " lx exch moveto } if\n"
47 " show ( ) show \n"
48 "} bind def\n"
49 "\n"
50 "/p\n" // tos: paragraph. shows the paragraph within x boundaries lx-rx
51 "{ { ( ) search { s pop } { s exit } ifelse } loop\n"
52 " lx currentpoint exch pop dy 2 mul sub moveto\n"
53 "} bind def\n"
54 "\n"
55 "%%EndProlog\n";
56
57 static Postscript * current = 0;
58
59
60 /*! \class Postscript postscript.h
61
62 The Postscript class generates output in postscript form. Plain
63 postscript level 1 is used, and all formatting is done on the
64 printer, even wordwrapping.
65
66 At the moment, all output uses the same font. That's a bug. Have
67 to fix that.
68 */
69
70
71
72 /*! Constructs an Postscript output function, opens \a f for writing
73 and writes the postscript prologue.
74 */
75
Postscript(const char * f)76 Postscript::Postscript( const char * f )
77 : file( 0 )
78 {
79 file = new File( f, File::Write );
80 if ( !file->valid() ) {
81 (void)new Error( file, 0,
82 "Postscript: Unable to open this file for writing" );
83 file = 0;
84 return;
85 }
86 ::current = this;
87 output( prologue );
88 output( "/Times findfont 9.5 scalefont setfont\n"
89 "header\n"
90 "lx ty moveto\n" );
91 }
92
93
94 /*! Destroys the writer and closes the file. */
95
~Postscript()96 Postscript::~Postscript()
97 {
98 endParagraph();
99 output( "showpage\n" );
100 delete file;
101 }
102
103
104 /*! Returns a pointer to the current Postscript singleton. */
105
current()106 Postscript * Postscript::current()
107 {
108 return ::current;
109 }
110
111
112 /*! As Output::startHeadline() */
113
startHeadline(Intro *)114 void Postscript::startHeadline( Intro * )
115 {
116 endParagraph();
117 }
118
119
120 /*! As Output::startHeadline(). */
121
startHeadline(Class *)122 void Postscript::startHeadline( Class * )
123 {
124 endParagraph();
125 }
126
127
128 /*! As Output::startHeadline(). */
129
startHeadline(Function *)130 void Postscript::startHeadline( Function * )
131 {
132 endParagraph();
133 }
134
135
136 /*! Ends a paragraph, if one is being output. */
137
endParagraph()138 void Postscript::endParagraph()
139 {
140 if ( para.isEmpty() )
141 return;
142
143 EString r;
144 uint i = 0;
145 while ( i < para.length() ) {
146 if ( para[i] == '(' || para[i] == ')' || para[i] == '\\' )
147 r.append( "\\" );
148 r.append( para[i] );
149 i++;
150 }
151 output( "(" + r.simplified() + ") p\n" );
152 para = "";
153 }
154
155
156 /*! Outputs \a s to the destination file, taking care to escape
157 characters correctly, and to start a new paragraph if necessary.
158 */
159
addText(const EString & s)160 void Postscript::addText( const EString & s )
161 {
162 para.append( s );
163 }
164
165
166 /*! Outputs \a s to the destination file, theorecically in
167 italics. Right now it's exactly as addText().
168 */
169
addArgument(const EString & s)170 void Postscript::addArgument( const EString & s )
171 {
172 addText( s );
173 }
174
175
176 /*! Adds \a text to the destination file, if possible with the page
177 number where \a f is documented.
178 */
179
addFunction(const EString & text,Function * f)180 void Postscript::addFunction( const EString & text, Function * f )
181 {
182 addText( text );
183 f = f;
184 }
185
186
187 /*! Adds \a text to the destination file, if possible with the page
188 number where \a c is documented.
189
190 */
191
addClass(const EString & text,Class * c)192 void Postscript::addClass( const EString & text, Class * c )
193 {
194 addText( text );
195 c = c;
196 }
197
198
199 /*! Writes \a s to the destination file as-is. */
200
output(const EString & s)201 void Postscript::output( const EString & s )
202 {
203 if ( file )
204 file->write( s );
205 }
206