eh, make ’em volatile, this is not time-critical code anyway
[alioth/magicpoint.git] / print.c
1 /*
2  * Copyright (C) 1997 and 1998 WIDE Project.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  * 3. Neither the name of the project nor the names of its contributors
13  *    may be used to endorse or promote products derived from this software
14  *    without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLER
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include "mgp.h"
30 #if HAVE_LOCALE_H
31 #include <locale.h>
32 #endif
33
34 static u_int align = AL_LEFT;
35 static char *curprefix = NULL;
36 static char *tabprefix = NULL;
37 static u_int lineheight;
38 static u_int linewidth;
39 static u_int gaplevel = 0;
40 static int char_off = 0;        /* y-offset of the chars (relative to the
41                                    current line, used for super/subscript */
42
43 #define DEFAULT_PAPER_SIZE      "a4"
44 #define PRINT_ASCIIFONT         "Times-Roman"
45 #define PRINT_ASCIITHICKFONT    "Helvetica"
46 #define PRINT_KANJIFONT         "Ryumin-Light-H"
47 #define PRINT_KANJITHICKFONT    "GothicBBB-Medium-H"
48
49 static FILE *fp;
50 static u_int reverse;
51 static char outputfile[MAXVALLEN];
52 static int colorps = 0;
53 static int painticon = 0;
54 static u_int curlinenum;
55 static u_int curpagenum=0;
56 static u_int xprefix = 0;
57 static u_int tabxprefix = 0;
58 static u_int valign = VL_BOTTOM;
59
60 /* by Arnd Schmitter 23.07.2004 */
61 static int lg; /* Counts the Recursionlevel in print_page() for new Pause-Mode */
62 static int PauseMode=0; /* Should Pause-Statements splitet into multiple Pages ? */
63
64 static struct imagepool {
65         struct ctrl *image;
66         int xoffset;
67         int xsiz;
68         int ysiz;
69         int eps;
70         int target_text;    /* by A. Ito */
71 } imagepool[256];               /*enough?*/
72 static int nimagepool = 0;
73 static struct textpool {
74         int pfx;
75         int xoffset;
76         int yoffset;     /* offset for super/subscript */
77         int xsiz;
78         struct fontmap *font;
79         int size;
80         char *text;
81         u_long fore;
82         u_long back;
83         char *charset;
84 } textpool[1024];               /*enough?*/
85 static int ntextpool = 0;
86
87 u_long fore;
88 u_long back;
89
90 /* lang code */
91 #define ASCII   0
92 #define KANJI   1
93 #define NOPE    -1
94
95 static int maxfontid = 0;
96 static struct fontmap {
97         int ctrl;
98         int lang;
99         const char *font;
100         const char *psfont;
101         int fontid;     /* flag bit for generating font map */
102         int loaded;
103 } fontmap[] = {
104         { CTL_XFONT2, ASCII, "century schoolbook l-medium-r", "NewCenturySchlbk-Roman", 0, 0 },
105         { CTL_XFONT2, ASCII, "century schoolbook l-medium-i", "NewCenturySchlbk-Italic", 0, 0 },
106         { CTL_XFONT2, ASCII, "century schoolbook l-bold-r", "NewCenturySchlbk-Bold", 0, 0 },
107         { CTL_XFONT2, ASCII, "century schoolbook l-bold-i", "NewCenturySchlbk-BoldItalic", 0, 0 },
108         { CTL_XFONT2, ASCII, "times-medium-r",  "Times-Roman", 0, 0 },
109         { CTL_XFONT2, ASCII, "times-medium-i",  "Times-Italic", 0, 0 },
110         { CTL_XFONT2, ASCII, "times-bold-r",    "Times-Bold", 0, 0 },
111         { CTL_XFONT2, ASCII, "times-bold-i",    "Times-BoldItalic", 0, 0 },
112         { CTL_XFONT2, ASCII, "helvetica-medium-r",      "Helvetica", 0, 0 },
113         { CTL_XFONT2, ASCII, "helvetica-medium-o",      "Helvetica-Oblique", 0, 0 },
114         { CTL_XFONT2, ASCII, "helvetica-bold-r",        "Helvetica-Bold", 0, 0 },
115         { CTL_XFONT2, ASCII, "helvetica-bold-o",        "Helvetica-BoldOblique", 0, 0 },
116         { CTL_XFONT2, ASCII, "courier-medium-r",        "Courier", 0, 0 },
117         { CTL_XFONT2, ASCII, "courier-medium-o",        "Courier-Oblique", 0, 0 },
118         { CTL_XFONT2, ASCII, "courier-bold-r",  "Courier-Bold", 0, 0 },
119         { CTL_XFONT2, ASCII, "courier-bold-i",  "Courier-BoldOblique", 0, 0 },
120         { CTL_XFONT2, ASCII, "times*",          "Times", 0, 0 },
121         { CTL_XFONT2, ASCII, "helvetica*",      "Helvetica", 0, 0 },
122         { CTL_XFONT2, ASCII, "courier*",                "Courier", 0, 0 },
123         { CTL_XFONT2, ASCII, "symbol*",         "Symbol", 0, 0 },
124         { CTL_XFONT2, ASCII, "*",               "Helvetica", 0, 0 },    /*last resort*/
125         { CTL_XFONT2, KANJI, "*",               "Ryumin-Light-H", 0, 0 }, /*last resort*/
126         /*PSFONT*/
127         { CTL_PSFONT, ASCII, "Times-Roman", "Times-Roman", 0, 0 },
128         { CTL_PSFONT, ASCII, "Times-Italic", "Times-Italic", 0, 0 },
129         { CTL_PSFONT, ASCII, "Times-Bold", "Times-Bold", 0, 0 },
130         { CTL_PSFONT, ASCII, "Times-BoldItalic", "Times-BoldItalic", 0, 0 },
131         { CTL_PSFONT, ASCII, "Helvetica", "Helvetica", 0, 0 },
132         { CTL_PSFONT, ASCII, "Helvetica-BoldOblique", "Helvetica-BoldOblique", 0, 0 },
133         { CTL_PSFONT, ASCII, "Helvetica-Bold", "Helvetica-Bold", 0, 0 },
134         { CTL_PSFONT, ASCII, "Courier", "Courier", 0, 0 },
135         { CTL_PSFONT, ASCII, "Courier-Oblique", "Courier-Oblique", 0, 0 },
136         { CTL_PSFONT, ASCII, "Courier-Bold", "Courier-Bold", 0, 0 },
137         { CTL_PSFONT, ASCII, "Courier-BoldOblique", "Courier-BoldOblique", 0, 0 },
138         { CTL_PSFONT, ASCII, "AvantGarde-Book", "AvantGarde-Book", 0, 0 },
139         { CTL_PSFONT, ASCII, "AvantGarde-BookOblique", "AvantGarde-BookOblique", 0, 0 },
140         { CTL_PSFONT, ASCII, "AvantGarde-Demi", "AvantGarde-Demi", 0, 0 },
141         { CTL_PSFONT, ASCII, "AvantGarde-DemiQblique", "AvantGarde-DemiQblique", 0, 0 },
142         { CTL_PSFONT, ASCII, "Bookman-Demi", "Bookman-Demi", 0, 0 },
143         { CTL_PSFONT, ASCII, "Bookman-DemiItalic", "Bookman-DemiItalic", 0, 0 },
144         { CTL_PSFONT, ASCII, "Bookman-Light", "Bookman-Light", 0, 0 },
145         { CTL_PSFONT, ASCII, "Bookman-LightItalic", "Bookman-LightItalic", 0, 0 },
146         { CTL_PSFONT, ASCII, "Helvetica-Narrow", "Helvetica-Narrow", 0, 0 },
147         { CTL_PSFONT, ASCII, "Helvetic-NarrowOblique","Helvetic-NarrowOblique", 0, 0 },
148         { CTL_PSFONT, ASCII, "Helvetica-NarrowBold", "Helvetica-NarrowBold", 0, 0 },
149         { CTL_PSFONT, ASCII, "Helvetica-NarrowBoldOblique", "Helvetica-NarrowBoldOblique", 0, 0 },
150         { CTL_PSFONT, ASCII, "Helvetica-Oblique", "Helvetica-Oblique", 0, 0 },
151         { CTL_PSFONT, ASCII, "NewCenturySchlbk-Roman", "NewCenturySchlbk-Roman", 0, 0 },
152         { CTL_PSFONT, ASCII, "NewCenturySchlbk-Bold", "NewCenturySchlbk-Bold", 0, 0 },
153         { CTL_PSFONT, ASCII, "NewCenturySchlbk-Italic", "NewCenturySchlbk-Italic", 0, 0 },
154         { CTL_PSFONT, ASCII, "NewCenturySchlbk-BoldItalic", "NewCenturySchlbk-BoldItalic", 0, 0 },
155         { CTL_PSFONT, ASCII, "Palatino-Roman", "Palatino-Roman", 0, 0 },
156         { CTL_PSFONT, ASCII, "Palatino-Bold", "Palatino-Bold", 0, 0 },
157         { CTL_PSFONT, ASCII, "Palatino-Italic", "Palatino-Italic", 0, 0 },
158         { CTL_PSFONT, ASCII, "Palatino-BoldItalic", "Palatino-BoldItalic", 0, 0 },
159         { CTL_PSFONT, ASCII, "ZapfChancery-MediumItalic", "ZapfChancery-MediumItalic", 0, 0 },
160         { CTL_PSFONT, ASCII, "Symbol", "Symbol", 0, 0 },
161         { CTL_PSFONT, ASCII, "ZapfDingbats", "ZapfDingbats", 0, 0 },
162         { CTL_PSFONT, ASCII, "*", "Helvetica", 0, 0 }, /*Last Resort*/
163         { -1, 0, NULL, NULL, 0, 0 }
164 };
165 static struct fontmap *curfont[10];     /*indexed by lang*/
166
167 typedef struct papersize {
168         const char *name;       /* name of paper size */
169         int height, width;      /* height, width in points for LANDSCAPE */
170 } Paper;
171
172 static const Paper papersizes[] = {
173         { "a3",         842, 1191 },    /* 29.7cm * 42cm */
174         { "a4",         595, 842 },     /* 21cm * 29.7cm */
175         { "a5",         421, 595 },     /* 14.85cm * 21cm */
176         { "b5",         516, 729 },     /* 18.2cm * 25.72cm */
177         { "A3",         842, 1191 },    /* 29.7cm * 42cm */
178         { "A4",         595, 842 },     /* 21cm * 29.7cm */
179         { "A5",         421, 595 },     /* 14.85cm * 21cm */
180         { "B5",         516, 729 },     /* 18.2cm * 25.72cm */
181         { "letter",     612, 792 },     /* 8.5in * 11in */
182         { "legal",      612, 1008 },    /* 8.5in * 14in */
183         { "ledger",     1224, 792 },    /* 17in * 11in */
184         { "tabloid",    792, 1224 },    /* 11in * 17in */
185         { "statement",  396, 612 },     /* 5.5in * 8.5in */
186         { "executive",  540, 720 },     /* 7.6in * 10in */
187         { "folio",      612, 936 },     /* 8.5in * 13in */
188         { "quarto",     610, 780 },     /* 8.5in * 10.83in */
189         { "10x14",      720, 1008 },    /* 10in * 14in */
190         { NULL, 0, 0 }
191 };
192
193 static const char *latin1def =
194 "[ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
195 " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
196 " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
197 " /.notdef /.notdef /space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quoteright\n"
198 " /parenleft /parenright /asterisk /plus /comma /hyphen /period /slash /zero /one\n"
199 " /two /three /four /five /six /seven /eight /nine /colon /semicolon\n"
200 " /less /equal /greater /question /at /A /B /C /D /E\n"
201 " /F /G /H /I /J /K /L /M /N /O\n"
202 " /P /Q /R /S /T /U /V /W /X /Y\n"
203 " /Z /bracketleft /backslash /bracketright /asciicircum /underscore /quoteleft /a /b /c\n"
204 " /d /e /f /g /h /i /j /k /l /m\n"
205 " /n /o /p /q /r /s /t /u /v /w\n"
206 " /x /y /z /braceleft /bar /braceright /asciitilde /.notdef /.notdef /.notdef\n"
207 " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
208 " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
209 " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
210 " /space /exclamdown /cent /sterling /currency /yen /brokenbar /section /dieresis /copyright\n"
211 " /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron /degree /plusminus /twosuperior /threesuperior\n"
212 " /acute /mu /paragraph /periodcentered /cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf\n"
213 " /threequarters /questiondown /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla\n"
214 " /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis /Eth /Ntilde\n"
215 " /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply /Oslash /Ugrave /Uacute /Ucircumflex\n"
216 " /Udieresis /Yacute /Thorn /germandbls /agrave /aacute /acircumflex /atilde /adieresis /aring\n"
217 " /ae /ccedilla /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis\n"
218 " /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide /oslash /ugrave\n"
219 " /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis] /isolatin1encoding exch def\n";
220
221 static const char *latin2def =
222 "[ /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
223 " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
224 " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
225 " /.notdef /.notdef /space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quoteright\n"
226 " /parenleft /parenright /asterisk /plus /comma /minus /period /slash /zero /one\n"
227 " /two /three /four /five /six /seven /eight /nine /colon /semicolon\n"
228 " /less /equal /greater /question /at /A /B /C /D /E\n"
229 " /F /G /H /I /J /K /L /M /N /O\n"
230 " /P /Q /R /S /T /U /V /W /X /Y\n"
231 " /Z /bracketleft /backslash /bracketright /asciicircum /underscore /quoteleft /a /b /c\n"
232 " /d /e /f /g /h /i /j /k /l /m\n"
233 " /n /o /p /q /r /s /t /u /v /w\n"
234 " /x /y /z /braceleft /bar /braceright /asciitilde /.notdef /.notdef /.notdef\n"
235 " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
236 " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
237 " /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
238 " /space /Aogonek /breve /Lslash /currency /Lcaron /Sacute /section /dieresis /Scaron\n"
239 " /Scedilla /Tcaron /Zacute /hyphen /Zcaron /Zdotaccent /degree /aogonek /ogonek /lslash\n"
240 " /acute /lcaron /sacute /caron /cedilla /scaron /scedilla /tcaron /zacute /hungarumlaut\n"
241 " /zcaron /zdotaccent /Racute /Aacute /Acircumflex /Abreve /Adieresis /Lacute /Cacute /Ccedilla\n"
242 " /Ccaron /Eacute /Eogonek /Edieresis /Ecaron /Iacute /Icircumflex /Dcaron /Dbar /Nacute\n"
243 " /Ncaron /Oacute /Ocircumflex /Ohungarumlaut /Odieresis /multiply /Rcaron /Uring /Uacute /Uhungarumlaut\n"
244 " /Udieresis /Yacute /Tcedilla /germandbls /racute /aacute /acircumflex /abreve /adieresis /lacute\n"
245 " /cacute /ccedilla /ccaron /eacute /eogonek /edieresis /ecaron /iacute /icircumflex /dcaron\n"
246 " /dbar /nacute /ncaron /oacute /ocircumflex /ohungarumlaut /odieresis /divide /rcaron /uring\n"
247 " /uacute /uhungarumlaut /udieresis /yacute /tcedilla /dotaccent] /isolatin2encoding exch def\n";
248
249 static const struct encoding {
250         const char *name;
251         const char *defstr;
252 } encodings[] = {
253         { "iso-8859-1", "isolatin1encoding", },
254         { "latin1",     "isolatin1encoding", },
255         { "iso-8859-2", "isolatin2encoding", },
256         { "latin2",     "isolatin2encoding", },
257         { NULL, NULL, },
258 };
259 const struct encoding *encoding = NULL;
260
261 static const Paper *paper;
262 static int w_width, w_height;
263 static int paper_xmargin = 10;
264 static int paper_ymargin = 5;
265
266 static const Paper *findpaper(const char *);
267 static void print_out(void);
268 static void scan_font(u_int);
269 static void print_page(u_int);
270 static void print_init(void);
271 static void print_pageinit(u_int);
272 static void process_direc_print(struct ctrl *cp);
273 static void scan_backcolor(u_int);
274 static void line_start(void);
275 static void line_end(void);
276 static void icon_output(struct textpool *);
277 static void line_skip(int, int);
278 static void print_bar(struct ctrl *);
279 static void print_icon(struct ctrl *);
280 static void print_line(char *, int);
281 static void print_string(char *, int);
282 static void print_fragment(u_char *, u_int, int, int);
283 static void text_remember(char *, int, int, int, int);
284 static void icon_remember(int, int, int, u_long);
285 static void image_remember(struct ctrl *, struct imagepool *);
286 static void image_load_print(const char *, int, int, int, int, int);
287 static void print_usage(char *) __dead;
288 static void setpencolor(u_long);
289 static void print_full_image(XImage *, Visual *);
290 static void print_8_image(XImage *);
291 static void print_32_image(XImage *, Visual *);
292 static void print_eps(FILE *, char *, int, int, int);
293 static struct fontmap *findfont(int, int, char *);
294 static char *fontstring(struct fontmap *);
295 static void loadfont(struct fontmap *, const char *);
296 static int  count_pause(u_int page);   /* Added 23.07.2004 by Arnd Schmitter */
297
298 /*
299  * Paper size selection code is based on psutil.c by Angus J. C. Duggan
300  * but trivial
301  */
302 static const Paper *
303 findpaper(const char *name)
304 {
305         const Paper *pp;
306         for (pp = papersizes; pp->name; pp++) {
307                 if (strcmp(pp->name, name) == 0)
308                         return pp;
309         }
310         return (const Paper *)NULL;
311 }
312
313 static void
314 print_out(void)
315 {
316         u_int   i;
317         u_int   width, height;
318
319         width  = window_width;
320         height = window_height;
321         window_width  = w_width;
322         window_height = w_height;
323
324         char_size[0] = window_height * DEFAULT_CHARSIZE / 100;
325         sup_off = DEFAULT_SUPOFF;
326         sub_off = DEFAULT_SUBOFF;
327         sup_scale = DEFAULT_SUPSCALE;
328
329         if (outputfile[0]) {
330                 if ((fp = fopen(outputfile, "w")) == NULL) {
331                         perror("fopen");
332                         exit(-1);
333                 }
334         } else
335                 fp = stdout;
336
337         print_init();
338         for (i = 1; i <= maxpage; i ++) {
339                 scan_font(i);
340         }
341         for (i = 1; i <= maxpage; i ++)
342           {
343             lg=0; /* Set the recursionlevel to 0 for each new page (Arnd Schmitter 23.07.2004) */
344             print_page(i);
345           }
346
347         fclose(fp);
348
349         window_width  = width;
350         window_height = height;
351 }
352
353 static void
354 scan_font(u_int page)
355 {
356         u_int line;
357         struct ctrl *cp;
358         struct fontmap *font;
359         int code;
360
361         if (mgp_flag & FL_VERBOSE)
362                 fprintf(fp, "%% scan_font page %d\n", page);
363         for (line = 0;
364              line <= page_attribute[page].pg_linenum;
365              line++) {
366                 /* process normal control */
367                 for (cp = page_control[page][line]; cp; cp = cp->ct_next) {
368                         switch(cp->ct_op) {
369                         case CTL_PSFONT:
370                                 font = findfont(cp->ct_op,ASCII,cp->ctc_value);
371                                 if(font)
372                                         curfont[ASCII] = font;
373                                 break;
374
375                         case CTL_XFONT2:
376                                 if (strcmp(cp->ctc2_value2, "iso8859-1") == 0)
377                                         code = ASCII;
378                                 else if (strncmp(cp->ctc2_value2,
379                                                 "jisx0208", 8) == 0) {
380                                         code = KANJI;
381                                 } else {
382                                         fprintf(stderr,
383                                                 "unsupported XFONT registry %s\n",
384                                                 cp->ctc2_value2);
385                                         exit(1);
386                                 }
387                                 font = findfont(cp->ct_op, code,
388                                         cp->ctc2_value1);
389                                 if (font)
390                                         curfont[code] = font;
391                                 break;
392
393                         case CTL_XFONT:
394                                 fprintf(stderr, "obsolete directive XFONT\n");
395                                 exit(1);
396                         case CTL_TEXT:
397                                 if (strstr(cp->ctc_value, "\033$B")
398                                  || strstr(cp->ctc_value, "\033$@")) {
399                                         if (curfont[KANJI]) {
400                                                 loadfont(curfont[KANJI],
401                                                         curfont[KANJI]->font);
402                                         } else {
403                                                 fprintf(stderr,
404 "unable to find proper font for %s\n", "kanji");
405                                                 exit(1);
406                                         }
407                                 }
408                                 if (curfont[ASCII]) {
409                                         loadfont(curfont[ASCII],
410                                                 curfont[ASCII]->font);
411                                 } else {
412                                         fprintf(stderr,
413 "unable to find proper font for %s\n", "ascii");
414                                         exit(1);
415                                 }
416
417                         default:
418                                 break;
419                         }
420                 }
421         }
422
423         memset(curfont, 0, sizeof(curfont));
424 }
425
426 /*
427  * This Function counts the Number of Pause-Statements.
428  */
429 static int
430 count_pause(u_int page)
431 {
432   int count=0;
433   u_int line;
434   struct ctrl*cp;
435   for (line = 0;
436        line <= page_attribute[page].pg_linenum;
437        line++) {
438     curlinenum = line;
439     /* process normal control */
440     for (cp = page_control[page][line]; cp; cp = cp->ct_next)
441       {
442         if(cp->ct_op == CTL_PAUSE)
443           {
444             count++;
445           }
446       }
447   }
448   return count;
449 }
450
451 static void
452 print_page(u_int page)
453 {
454         u_int line;
455         struct ctrl *cp;
456
457         int ret=0;  /* A Pause Command was found */
458         int lc = 0; /* Counter to prevent infinite recursion loops at Pause-Statements */
459         int pcount; /* Stores the Number of Pause Statements for a Page */
460
461         /* Modified by Arnd Schmitter 23.07.2004:
462      * when in PauseMode for emulationg %pause in PS file (option "-m")
463      * this function is called recursively to print the beginning of
464      * the page again up to current %pause statement
465      */
466         /*curpagenum = page;*/
467         curpagenum++;
468         scan_backcolor(page);
469         print_pageinit(curpagenum);
470         /* End of Modification */
471
472         for (line = 0;
473              line <= page_attribute[page].pg_linenum;
474              line++) {
475                 curlinenum = line;
476                 /* process normal control */
477                 for (cp = page_control[page][line]; cp; cp = cp->ct_next)
478                   {
479                     if ((PauseMode) && (cp->ct_op == CTL_PAUSE))
480                       if (lc >= lg)
481                         ret=1;
482                       else
483                         (lc)++;
484                     else
485                       process_direc_print(cp);
486
487                     if (ret) goto pause; /* If a Pause has been found exit Loop immedeatly */
488                   }
489         }
490  pause:
491         fprintf(fp, "grestore\n\n");
492         fprintf(fp, "showpage\n\n");
493         /* If a Pause has been found -> Restart this Page */
494         if (ret)
495           {
496             lg++;
497             /* If we are in Pause-Mode check if we are called because of the last CTL_PAUSE at End of Page */
498             /*   At the Endo of the Last Page is no PAUSE Statemtent. So we have to use all Statements in the
499              Page */
500             pcount=count_pause(page);
501             if ((pcount != lg)||(page == (maxpage)))
502               print_page(page);
503           }
504 }
505
506 static void
507 print_init(void)
508 {
509         const char **p;
510         const char *aligns[] = { "center", "left", "right", NULL };
511
512         /* Added by Arnd Schmitter 23.07.2004 */
513         /*   If we split Pages with Pause Statements the number of absolute Pages gets greater then maxpage */
514         u_int i;
515         int absolute_pages = maxpage+1;
516         if (PauseMode)
517           {
518             for (i = 0; i < maxpage; i++)
519               {
520                 absolute_pages+=count_pause(i)-1;
521               }
522           }
523
524         /*fprintf(stderr,"Pages %d\n",absolute_pages);*/
525
526         fprintf(fp, "%%!PS-Adobe-2.0\n");
527         fprintf(fp, "%%%%Creator: mgp2ps\n");
528         fprintf(fp, "%%%%Title: %s\n", mgp_fname);
529         fprintf(fp, "%%%%Pages: %d\n", absolute_pages);
530         fprintf(fp, "%%%%BoundingBox: 0 0 %d %d\n", paper->height, paper->width);
531         fprintf(fp, "%%%%DocumentPaperSizes: %s\n", paper->name);
532         fprintf(fp, "%%%%Orientation: Landscape\n");
533         fprintf(fp, "%%%%EndComments\n");
534
535         /* define constants */
536         fprintf(fp, "/XMARGIN %d def /YMARGIN %d def "
537                 "/WIDTH %d def /HEIGHT %d def\n",
538                 paper_xmargin, paper_ymargin, window_width, window_height);
539         fprintf(fp, "/XBODY WIDTH XMARGIN 2 mul sub def\n");
540         fprintf(fp, "/vertgap %d def /horizgap %d def\n", vert_gap[0], horiz_gap[0]);
541
542         fprintf(fp, "/resety {/ymin 0 def /ymax 0 def} def\n");
543         fprintf(fp, "/setymax {dup ymax gt {dup /ymax exch def} if pop} def\n");
544         fprintf(fp, "/setymin {dup ymin lt {dup /ymin exch def} if pop} def\n");
545         fprintf(fp, "/calcy {dup ( ) eq\n"
546                 "  {0 setymax 0 setymin pop}\n"
547                 "  {pop charsize 0.7 mul setymax charsize -0.15 mul setymin}\n"
548                 "  ifelse\n"
549                 "} def\n");
550
551         fprintf(fp, "resety\n");
552
553         /* define writebox */
554         fprintf(fp, "/writebox {\n");
555         fprintf(fp, "  XMARGIN YMARGIN -1 mul moveto "
556                         "0 HEIGHT -1 mul rlineto\n");
557         fprintf(fp, "  WIDTH 0 rlineto 0 HEIGHT rlineto\n");
558         fprintf(fp, "  WIDTH -1 mul 0 rlineto stroke\n");
559         fprintf(fp, "} def\n");
560
561         /* define writeboxfill */
562         fprintf(fp, "/writeboxfill {\n");
563         fprintf(fp, "  newpath XMARGIN YMARGIN -1 mul moveto "
564                         "0 HEIGHT -1 mul rlineto\n");
565         fprintf(fp, "  WIDTH 0 rlineto 0 HEIGHT rlineto\n");
566         fprintf(fp, "  WIDTH -1 mul 0 rlineto closepath eofill stroke\n");
567         fprintf(fp, "} def\n");
568
569         /* ypos = ypos - (charsize * (1 + vert_gap / 100)) + little margin */
570         fprintf(fp, "/NL {\n");
571         fprintf(fp, "  charsize imgsize gt\n");
572         fprintf(fp, "   ymax ymin sub /csize exch def\n");
573         fprintf(fp, "   csize 0 eq {/csize charsize def} if\n");
574         fprintf(fp, "    { vertgap 100 div 1 add csize mul }\n");
575         fprintf(fp, "    { vertgap 100 div csize mul imgsize add }\n");
576         fprintf(fp, "  ifelse\n");
577         fprintf(fp, "  ypos exch sub /ypos exch def\n");
578         /* we can get similar results to xft2 by doing this */
579         if (!gaplevel)
580                 fprintf(fp, "  HEIGHT 90 div ypos exch sub /ypos exch def\n");
581         fprintf(fp, "} bind def\n");
582
583         /* show with line wrapping */
584         fprintf(fp, "/initcharsize { /charsize 0 def /imgsize 0 def resety} def\n");
585         fprintf(fp, "initcharsize\n");
586         fprintf(fp, "/setcharsize {\n");
587         fprintf(fp, "  dup charsize gt { dup /charsize exch def } if pop\n");
588         fprintf(fp, "} def\n");
589         fprintf(fp, "/setimgsize {\n");
590         fprintf(fp, "  dup imgsize gt { dup /imgsize exch def } if pop\n");
591         fprintf(fp, "} def\n");
592
593         fprintf(fp, "/updatetotlen {\n");
594         fprintf(fp, "  dup totlen exch sub /totlen exch def\n");
595         fprintf(fp, "} bind def\n");
596
597         fprintf(fp, "/updatefillzero {\n");
598         fprintf(fp, "  inmargin {\n");
599         fprintf(fp, "    currentpoint pop /fillzero exch def\n");
600         fprintf(fp, "    /inmargin false def\n");
601         fprintf(fp, "  } if\n");
602         fprintf(fp, "} bind def\n");
603
604         /* centering */
605         fprintf(fp, "/centerdefxpos {\n");
606         fprintf(fp, "  totlen XBODY gt\n");
607         fprintf(fp, "    { XMARGIN }\n");
608         fprintf(fp, "    { XBODY totlen sub 2 div XMARGIN add }\n");
609         fprintf(fp, "  ifelse /xpos exch def\n");
610         fprintf(fp, "} bind def\n");
611
612         /* leftfill */
613         fprintf(fp, "/leftdefxpos {\n");
614         fprintf(fp, "  /xpos fillzero def\n");
615         fprintf(fp, "} bind def\n");
616
617         /* rightfill */
618         fprintf(fp, "/rightdefxpos {\n");
619         fprintf(fp, "  totlen XBODY gt\n");
620         fprintf(fp, "    { XMARGIN }\n");
621         fprintf(fp, "    { XBODY totlen sub XMARGIN add }\n");
622         fprintf(fp, "  ifelse /xpos exch def\n");
623         fprintf(fp, "} bind def\n");
624
625         /* check newline */
626         for (p = aligns; *p; p++) {
627                 fprintf(fp, "/%snewlinecheck {\n", *p);
628                 fprintf(fp, "  currentpoint pop add XMARGIN XBODY add gt {\n");
629                 fprintf(fp, "    NL %sdefxpos xpos ypos charsize 2 div sub moveto\n",
630                         *p);
631                 fprintf(fp, "  } if\n");
632                 fprintf(fp, "} bind def\n");
633         }
634
635         /* a spell for EPS */
636         fprintf(fp, "%%\n");
637         fprintf(fp, "/BeginEPSF {%%def\n");
638         fprintf(fp, "  /b4_Inc_state save def\n");
639         fprintf(fp, "  /dict_count countdictstack def\n");
640         fprintf(fp, "  /op_count count 1 sub def\n");
641         fprintf(fp, "  userdict begin\n");
642         fprintf(fp, "  /showpage {}def\n");
643         fprintf(fp, "  0 setgray 0 setlinecap\n");
644         fprintf(fp, "  1 setlinewidth 0 setlinejoin\n");
645         fprintf(fp, "  10 setmiterlimit [] 0 setdash\n");
646         fprintf(fp, "  newpath\n");
647         fprintf(fp, "  /languagelevel where\n");
648         fprintf(fp, "  {pop languagelevel\n");
649         fprintf(fp, "  1 ne\n");
650         fprintf(fp, "    {false setstrokeadjust\n");
651         fprintf(fp, "     false setoverprint\n");
652         fprintf(fp, "    }if\n");
653         fprintf(fp, "  }if\n");
654         fprintf(fp, "}bind def\n");
655         fprintf(fp, "%%\n");
656         fprintf(fp, "/EndEPSF {%%def\n");
657         fprintf(fp, "  count op_count sub {pop}repeat\n");
658         fprintf(fp, "  countdictstack\n");
659         fprintf(fp, "  dict_count sub {end}repeat\n");
660         fprintf(fp, "  b4_Inc_state restore\n");
661         fprintf(fp, "}bind def\n");
662         fprintf(fp, "%%\n");
663
664         /* emit character encoding definition, if necessary */
665         if (encoding && strcmp(encoding->defstr, "isolatin1encoding") == 0)
666                 fprintf(fp, "%s", latin1def);
667         if (encoding && strcmp(encoding->defstr, "isolatin2encoding") == 0)
668                 fprintf(fp, "%s", latin2def);
669 }
670
671 static void
672 print_pageinit(u_int page)
673 {
674
675         window_width  = paper->width - paper_xmargin * 2;
676         window_height = paper->height - paper_ymargin * 2;
677         fprintf(fp, "%%%%Page: %d %d\n", page, page);
678         fprintf(fp, "/ypos YMARGIN -1 mul 4 sub def\n");
679         fprintf(fp, "/xpos 0 def\n");
680         fprintf(fp, "initcharsize\n");
681         if (!colorps)
682                 fprintf(fp, "90 rotate newpath writebox\n");
683         else {
684                 setpencolor(back);
685                 fprintf(fp, "90 rotate newpath writeboxfill\n");
686         }
687         fprintf(fp, "gsave\n");
688 }
689
690 static void
691 process_direc_print(struct ctrl *cp)
692 {
693         struct fontmap *font;
694         int code;
695
696         switch(cp->ct_op) {
697         case CTL_SIZE:
698                 char_size[0] = window_height * cp->ctf_value / 100;
699                 fprintf(fp, "%d setcharsize\n", char_size[0]);
700                 break;
701
702         case CTL_PSFONT:
703                 font = findfont(cp->ct_op,ASCII,cp->ctc_value);
704                 if(font)
705                         curfont[ASCII] = font;
706                 break;
707
708         case CTL_XFONT2:
709                 if (strcmp(cp->ctc2_value2, "iso8859-1") == 0)
710                         code = ASCII;
711                 else if (strncmp(cp->ctc2_value2, "jisx0208", 8) == 0)
712                         code = KANJI;
713                 else {
714                         fprintf(stderr, "unsupported XFONT registry %s\n",
715                                 cp->ctc2_value2);
716                         exit(1);
717                 }
718                 font = findfont(cp->ct_op, code, cp->ctc2_value1);
719                 if (font)
720                         curfont[code] = font;
721                 break;
722
723         case CTL_XFONT:
724                 fprintf(stderr, "internal error: "
725                         "obsolete directive CTL_XFONT\n");
726                 exit(1);
727
728         case CTL_VGAP:
729                 vert_gap[0] = cp->cti_value;
730                 fprintf(fp, "/vertgap %d def\n", cp->cti_value);
731                 break;
732
733         case CTL_HGAP:
734                 horiz_gap[0] = cp->cti_value;
735                 fprintf(fp, "/horizgap %d def\n", cp->cti_value);
736                 break;
737
738         case CTL_GAP:
739                 vert_gap[0] = horiz_gap[0] = cp->cti_value;
740                 fprintf(fp, "/vertgap %d def ", cp->cti_value);
741                 fprintf(fp, "/horizgap %d def\n", cp->cti_value);
742                 break;
743
744         case CTL_CENTER:
745                 align = AL_CENTER;
746                 break;
747
748         case CTL_LEFT:
749                 align = AL_LEFT;
750                 break;
751
752         case CTL_LEFTFILL:
753                 align = AL_LEFTFILL0;
754                 break;
755
756         case CTL_RIGHT:
757                 align = AL_RIGHT;
758                 break;
759
760         case CTL_IMAGE:
761                 image_remember(cp, &imagepool[nimagepool]);
762                 line_skip(imagepool[nimagepool].xsiz,
763                         imagepool[nimagepool].ysiz);
764
765                 /* placeholder */
766                 textpool[ntextpool].pfx = 0;
767                 textpool[ntextpool].xoffset = 0;
768                 textpool[ntextpool].xsiz = imagepool[nimagepool].xsiz;
769                 textpool[ntextpool].size = imagepool[nimagepool].ysiz;
770                 textpool[ntextpool].font = 0;           /*image*/
771                 textpool[ntextpool].text = NULL;
772                 textpool[ntextpool].fore = fore;        /*XXX*/
773                 textpool[ntextpool].back = back;        /*XXX*/
774                 ntextpool++;
775
776                 nimagepool++;
777                 break;
778
779         case CTL_BAR:
780                 print_bar(cp);
781                 break;
782
783         case CTL_PREFIX:
784                 curprefix = cp->ctc_value;
785                 break;
786
787         case CTL_PREFIXN:
788                 xprefix = window_width * cp->ctf_value / 100;
789                 break;
790
791         case CTL_TABPREFIX:
792                 tabprefix = cp->ctc_value;
793                 break;
794
795         case CTL_TABPREFIXN:
796                 tabxprefix = window_width * cp->ctf_value / 100;
797                 break;
798
799         case CTL_PREFIXPOS:
800                 if (tabprefix)
801                         print_line(tabprefix, 1);
802                 else if (curprefix)
803                         print_line(curprefix, 1);
804                 break;
805
806         case CTL_TEXT:
807             {
808                 if (!cp->ctc_value)
809                         break;
810                 print_line(cp->ctc_value, 0);
811                 if (align == AL_LEFTFILL0)
812                         align = AL_LEFTFILL1;
813
814                 /* disable super/subscript for next line */
815                 if (char_off != 0)
816                 {
817                         char_size[0]=nonscaled_size[0];
818                         char_off=0;
819                 }
820                 break;
821             }
822
823         case CTL_ICON:
824                 print_icon(cp);
825                 break;
826
827         case CTL_LINESTART:
828                 line_start();
829                 break;
830
831         case CTL_LINEEND:
832                 line_end();
833                 if (align == AL_LEFTFILL1)
834                         align = AL_LEFTFILL0;
835                 break;
836
837         case CTL_FORE:
838                 fore = cp->ctl_value;
839                 break;
840
841 #if 0 /* it's not necessary */
842         case CTL_BACK:
843                 back = cp->ctl_value;
844                 break;
845 #endif
846
847         /*
848      * MARK and AGAIN processing by A.Ito, 14 Jul. 2000
849      */
850         case CTL_MARK:
851                 fprintf(fp,"/markx xpos def /marky ypos def\n");
852                 break;
853
854         case CTL_AGAIN:
855                 fprintf(fp,"markx marky moveto /xpos markx def /ypos marky def\n");
856                 break;
857
858         case CTL_VALIGN:
859                 valign = cp->cti_value;
860                 break;
861
862         case CTL_AREA:
863                 window_width = (paper->width - paper_xmargin * 2) * cp->ctar_width / 100;
864                 window_height = (paper->height - paper_ymargin * 2) * cp->ctar_height / 100;
865                 fprintf(fp, "grestore\ngsave\n");
866                 fprintf(fp, "%f dup scale\n", cp->ctar_height / 100.0);
867                 fprintf(fp, "WIDTH XMARGIN 2 mul sub %f mul 0 translate\n",
868                     (double)cp->ctar_xoff / cp->ctar_height);
869                 fprintf(fp, "/XBODY WIDTH XMARGIN 2 mul sub %f mul def\n",
870                     (double)cp->ctar_width / cp->ctar_height);
871                 fprintf(fp, "/ypos YMARGIN -1 mul 4 sub HEIGHT %f mul sub def\n",
872                     (double)cp->ctar_yoff / cp->ctar_height);
873                 fprintf(fp, "/xpos 0 def\n");
874                 break;
875         case CTL_OPAQUE:
876                 if (cp->cti_value > 100){
877                         fprintf(stderr, "%%opaque: value should be 0-100\n");
878                         cp->cti_value = 100;
879                 }
880                 fprintf(fp, "%f setgray\n", 1.0 - (float)cp->cti_value /100.0);
881                 break;
882
883         /* setup for super/subscript */
884         case CTL_SETSUP:
885                 if (cp->cti3_value1 > 100 || cp->cti3_value1 < 10){
886                         sup_off = DEFAULT_SUPOFF;
887                 } else {
888                         sup_off = cp->cti3_value1 / 100.;
889                 }
890                 if (cp->cti3_value2 > 100 || cp->cti3_value2 < 10){
891                         sub_off = DEFAULT_SUBOFF;
892                 } else {
893                         sub_off = cp->cti3_value2 / 100.;
894                 }
895                 if (cp->cti3_value3 > 100 || cp->cti3_value3 < 10){
896                         sup_scale = DEFAULT_SUPSCALE;
897                 } else {
898                         sup_scale = cp->cti3_value3 / 100.;
899                 }
900                 break;
901
902         /* subscript */
903         case CTL_SUB:
904                 /* save old size and set new one */
905                 nonscaled_size[0] = char_size[0];
906                 char_size[0] = char_size[0] * sup_scale;
907                 char_off = nonscaled_size[0] * (-sub_off);
908                 fprintf(fp, "%d setcharsize\n", char_size[0]);
909                 break;
910
911         /* superscript */
912         case CTL_SUP:
913                 /* save old size and set new one */
914                 nonscaled_size[0] = char_size[0];
915                 char_size[0] = char_size[0] * sup_scale;
916                 char_off = nonscaled_size[0] * sup_off;
917                 fprintf(fp, "%d setcharsize\n", char_size[0]);
918                 break;
919
920         default:
921           break;
922         }
923 }
924
925 static void
926 scan_backcolor(u_int page)
927 {
928   struct ctrl *cp;
929   u_int line;
930
931         for (line = 0; line <= page_attribute[page].pg_linenum; line++) {
932                 for (cp = page_control[page][line]; cp; cp = cp->ct_next)
933                         switch(cp->ct_op) {
934                                 case CTL_BACK:
935                                         back = cp->ctl_value;
936                                 break;
937                                 default:
938                                 break;
939                 }
940         }
941 }
942
943 static void
944 line_start(void)
945 {
946         linewidth = 0;
947         nimagepool = 0;
948         ntextpool = 0;
949 }
950
951 static void
952 line_end(void)
953 {
954         int i;
955         const char *alignstr;
956
957         switch (align) {
958         case AL_CENTER:
959                 alignstr = "center";
960                 break;
961         case AL_LEFT:
962         case AL_LEFTFILL0:
963         case AL_LEFTFILL1:
964                 alignstr = "left";
965                 break;
966         case AL_RIGHT:
967                 alignstr = "right";
968                 break;
969         default:
970                 alignstr = "";
971                 break;
972         }
973
974         /*
975          * line output starts here
976          */
977         if (mgp_flag & FL_VERBOSE)
978                 fprintf(fp, "%% a line starts here\n");
979
980         /*
981          * if we have nothing on the line, skip it
982          */
983         if (!ntextpool && !nimagepool){
984                 fprintf(fp, "initcharsize %d setcharsize\n", char_size[0]);
985                 goto done;
986         }
987
988         /*
989          * push strings in reverse order.
990          */
991         fprintf(fp, "initcharsize\n");
992         fprintf(fp, "0 %% sentinel for text width computation\n");
993         fprintf(fp, "gsave newpath 0 0 moveto\n");
994
995         for (i = ntextpool - 1; 0 <= i; i--) {
996                 if (!textpool[i].text) {
997                         fprintf(fp, "%d add\n", textpool[i].xsiz);
998                         continue;
999                 }
1000                 fprintf(fp, "%d setcharsize %d %s %s calcy\n",
1001                         textpool[i].size, textpool[i].size,
1002                         fontstring(textpool[i].font),
1003                         textpool[i].text);
1004
1005                 fprintf(fp, "%d setcharsize %d %s %s "
1006                         "1 copy stringwidth pop 3 2 roll add\n",
1007                         textpool[i].size, textpool[i].size,
1008                         fontstring(textpool[i].font),
1009                         textpool[i].text);
1010         }
1011         fprintf(fp, "grestore\n");
1012
1013         if (mgp_flag & FL_VERBOSE) {
1014                 fprintf(fp, "%% stack should have: str3 str2 str1 width\n");
1015                 fprintf(fp, "%% alignment: %s\n", alignstr);
1016         }
1017
1018         /*
1019          * now show those chars with line wrapping. brief logic is:
1020          *
1021          *      position adjust;
1022          *      foreach i (item in textpool) {
1023          *              if (item exceeds the right edge) {
1024          *                      carriage return;
1025          *                      position adjust;
1026          *              }
1027          *              show;
1028          *      }
1029          */
1030         fprintf(fp, "/totlen exch def\n");
1031         fprintf(fp, "/totlen totlen %d add def\n", tabxprefix ? tabxprefix:xprefix);
1032         fprintf(fp, "/inmargin true def /fillzero XMARGIN def\n");
1033         fprintf(fp, "%sdefxpos ", alignstr);
1034
1035         /*
1036          * to determine text base line, we need to set imgsize first. pretty ugly..
1037          */
1038     {
1039         struct ctrl *cp1;
1040                 for (i = 0; i < nimagepool; i++) {
1041                         cp1 = imagepool[i].image;
1042                         if (cp1)
1043                                 fprintf(fp, "%d setimgsize\n", imagepool[i].ysiz);      /*XXX*/
1044                 }
1045         }
1046         fprintf(fp, "/yypos ypos charsize imgsize gt \n");
1047
1048         switch(valign){
1049         case VL_TOP:
1050                 fprintf(fp, " { 0 } { 0 } ifelse sub def\n");
1051                 break;
1052         case VL_BOTTOM:
1053                 fprintf(fp, " { 0 } { imgsize charsize sub } ifelse sub def\n");
1054                 break;
1055         case VL_CENTER:
1056                 fprintf(fp, " { 0 } { imgsize charsize sub 2 div } ifelse sub def\n");
1057                 break;
1058         }
1059         fprintf(fp, "/xpos xpos %d add def\n", tabxprefix ? tabxprefix:xprefix);
1060         fprintf(fp, "xpos yypos ymax sub moveto\n");
1061
1062         for (i = 0; i < ntextpool; i++) {
1063                 if (textpool[i].text) {
1064                         fprintf(fp, "%d %s 1 copy stringwidth pop ",
1065                                 textpool[i].size,
1066                                 fontstring(textpool[i].font));
1067                 } else
1068                         fprintf(fp, "%d ", textpool[i].xsiz);
1069                 fprintf(fp, "updatetotlen ");
1070                 if (textpool[i].text)
1071                         fprintf(fp, "%snewlinecheck ", alignstr);
1072                 else
1073                         fprintf(fp, "pop ");
1074
1075                 if (colorps
1076                  && (i == 0
1077                   || (textpool[i - 1].fore != textpool[i].fore)
1078                   || (textpool[i - 1].back != textpool[i].back))) {
1079                         fprintf(fp, "\n");
1080                         setpencolor(textpool[i].fore);
1081                 }
1082
1083                 if (textpool[i].text) {
1084                         if (!textpool[i].pfx)
1085                                 fprintf(fp, "updatefillzero ");
1086
1087                         /* for super/subscript: modify the current y-position */
1088                         if (textpool[i].yoffset != 0)
1089                                 fprintf(fp, "currentpoint %d add moveto ",
1090                                         textpool[i].yoffset);
1091                         fprintf(fp, "show\n");
1092
1093                         /* for super/subscript: reset the old y-position */
1094                         if (textpool[i].yoffset != 0)
1095                                 fprintf(fp, "currentpoint %d sub moveto ",
1096                                         textpool[i].yoffset);
1097                 } else {
1098                         fprintf(fp, "\n");
1099                         if (textpool[i].font) {
1100                                 /* icon */
1101                                 icon_output(&textpool[i]);
1102                         } else {
1103                                 /* image */
1104                                 fprintf(fp, "%d 0 rmoveto\n", textpool[i].xsiz);
1105                         }
1106                 }
1107                 fprintf(fp, "/xpos%d currentpoint pop def\n", i);
1108         }
1109
1110         ntextpool = 0;
1111
1112     {
1113         struct ctrl *cp1;
1114
1115         for (i = 0; i < nimagepool; i++) {
1116                 if (mgp_flag & FL_VERBOSE)
1117                         fprintf(fp, "%% emit the content of imagepool\n");
1118                 cp1 = imagepool[i].image;
1119                 if (cp1) {
1120                         image_load_print(cp1->ctm_fname, cp1->ctm_numcolor,
1121                                 cp1->ctm_ximagesize, cp1->ctm_yimagesize,
1122                                 cp1->ctm_zoomflag, cp1->ctm_rotate);
1123                 }
1124                 fprintf(fp, "/xpos xpos%d def xpos ypos moveto\n",
1125                     imagepool[i].target_text);
1126
1127         }
1128         nimagepool = 0;
1129     }
1130
1131 done:
1132         fprintf(fp, "NL\n");
1133         tabprefix = NULL;
1134         tabxprefix = 0;
1135 }
1136
1137 static void
1138 icon_output(struct textpool *tp)
1139 {
1140         int isize = tp->size;
1141         int csize = tp->xsiz;
1142         int ixoff, iyoff;
1143         int paintit;
1144
1145         iyoff = (csize - isize) / 6;    /*XXX*/
1146         ixoff = tp->xoffset + (csize - isize) / 2;  /* XXX */
1147
1148         paintit = (painticon || colorps);
1149
1150         switch ((size_t)tp->font) {     /*XXX*/
1151         case 0:
1152                 /* XXX: image is not supported yet */
1153                 break;
1154         case 1: /* this is box */
1155                 fprintf(fp, "currentpoint ");
1156                 if (paintit)
1157                         fprintf(fp, "currentpoint newpath moveto ");
1158                 fprintf(fp, "%d %d rmoveto ", ixoff, iyoff);
1159                 fprintf(fp, "0 %d rlineto ", isize);
1160                 fprintf(fp, "%d 0 rlineto ", isize);
1161                 fprintf(fp, "0 %d rlineto ", -isize);
1162                 fprintf(fp, "%d 0 rlineto ", -isize);
1163                 if (paintit)
1164                         fprintf(fp, "closepath eofill ");
1165                 fprintf(fp, "stroke moveto\n");
1166                 fprintf(fp, "%d 0 rmoveto\n", ixoff * 2 + isize);
1167                 break;
1168         case 2: /* this is arc */
1169                 fprintf(fp, "currentpoint ");
1170                 if (paintit)
1171                         fprintf(fp, "currentpoint newpath moveto ");
1172                 fprintf(fp, "%d %d rmoveto ", ixoff + isize, iyoff + isize/2);
1173                 fprintf(fp, "currentpoint exch %d add exch %d 0 360 arc ",
1174                         -isize/2, isize/2);
1175                 if (paintit)
1176                         fprintf(fp, "closepath eofill ");
1177                 fprintf(fp, "stroke moveto\n");
1178                 fprintf(fp, "%d 0 rmoveto\n", ixoff * 2 + isize);
1179                 break;
1180         case 3:
1181                 fprintf(fp, "currentpoint ");
1182                 if (paintit)
1183                         fprintf(fp, "currentpoint newpath moveto ");
1184                 fprintf(fp, "%d %d rmoveto ", ixoff, iyoff);
1185                 fprintf(fp, "%d 0 rlineto ", isize);
1186                 fprintf(fp, "%d %d rlineto ", -isize/2, isize);
1187                 fprintf(fp, "%d %d rlineto ", -isize/2, -isize);
1188                 if (paintit)
1189                         fprintf(fp, "closepath eofill ");
1190                 fprintf(fp, "stroke moveto\n");
1191                 fprintf(fp, "%d 0 rmoveto\n", ixoff * 2 + isize);
1192                 break;
1193         case 4:
1194                 fprintf(fp, "currentpoint ");
1195                 if (paintit)
1196                         fprintf(fp, "currentpoint newpath moveto ");
1197                 fprintf(fp, "%d %d rmoveto ", ixoff, iyoff + isize);
1198                 fprintf(fp, "%d 0 rlineto ", isize);
1199                 fprintf(fp, "%d %d rlineto ", -isize/2, -isize);
1200                 fprintf(fp, "%d %d rlineto ", -isize/2, isize);
1201                 if (paintit)
1202                         fprintf(fp, "closepath eofill ");
1203                 fprintf(fp, "stroke moveto\n");
1204                 fprintf(fp, "%d 0 rmoveto\n", ixoff * 2 + isize);
1205                 break;
1206         case 5:
1207                 fprintf(fp, "currentpoint ");
1208                 if (paintit)
1209                         fprintf(fp, "currentpoint newpath moveto ");
1210                 fprintf(fp, "%d %d rmoveto ", ixoff, iyoff);
1211                 fprintf(fp, "0 %d rlineto ", isize);
1212                 fprintf(fp, "%d %d rlineto ", isize, -isize/2);
1213                 fprintf(fp, "%d %d rlineto ", -isize, -isize/2);
1214                 if (paintit)
1215                         fprintf(fp, "closepath eofill ");
1216                 fprintf(fp, "stroke moveto\n");
1217                 fprintf(fp, "%d 0 rmoveto\n", ixoff * 2 + isize);
1218                 break;
1219         case 6:
1220                 fprintf(fp, "currentpoint ");
1221                 if (paintit)
1222                         fprintf(fp, "currentpoint newpath moveto ");
1223                 fprintf(fp, "%d %d rmoveto ", ixoff + isize, iyoff);
1224                 fprintf(fp, "0 %d rlineto ", isize);
1225                 fprintf(fp, "%d %d rlineto ", -isize, -isize/2);
1226                 fprintf(fp, "%d %d rlineto ", isize, -isize/2);
1227                 if (paintit)
1228                         fprintf(fp, "closepath eofill ");
1229                 fprintf(fp, "stroke moveto\n");
1230                 fprintf(fp, "%d 0 rmoveto\n", ixoff * 2 + isize);
1231                 break;
1232         case 7:
1233                 fprintf(fp, "currentpoint ");
1234                 if (paintit)
1235                         fprintf(fp, "currentpoint newpath moveto ");
1236                 fprintf(fp, "%d %d rmoveto ", ixoff, iyoff + isize/2);
1237                 fprintf(fp, "%d %d rlineto ",  isize/2,  isize/2);
1238                 fprintf(fp, "%d %d rlineto ",  isize/2, -isize/2);
1239                 fprintf(fp, "%d %d rlineto ", -isize/2, -isize/2);
1240                 fprintf(fp, "%d %d rlineto ", -isize/2,  isize/2);
1241                 if (paintit)
1242                         fprintf(fp, "closepath eofill ");
1243                 fprintf(fp, "stroke moveto\n");
1244                 fprintf(fp, "%d 0 rmoveto\n", ixoff * 2 + isize);
1245                 break;
1246         }
1247 }
1248
1249 static void
1250 line_skip(int x, int y)
1251 {
1252         linewidth += x;
1253         lineheight = ((int)lineheight < y) ? (unsigned int)y : lineheight;
1254 }
1255
1256 static void
1257 print_bar(struct ctrl *cp)
1258 {
1259         struct ctrl_bar pbar;
1260
1261         pbar.ct_width = cp->ctb_width * w_height / 1000;
1262         pbar.ct_start = cp->ctb_start * w_width / 100;
1263         pbar.ct_length = cp->ctb_length * w_width / 100;
1264
1265         fprintf(fp, "%%bar color %d %d %d\n",
1266                 cp->ctb_width, cp->ctb_start, cp->ctb_length);
1267         fprintf(fp, "XMARGIN ypos moveto\n");
1268         fprintf(fp, "%d 0 rmoveto\n", pbar.ct_start);
1269         fprintf(fp, "%d %d rlineto\n", 0, pbar.ct_width * -1);
1270         fprintf(fp, "%d %d rlineto\n", pbar.ct_length, 0);
1271         fprintf(fp, "%d %d rlineto\n", 0, pbar.ct_width);
1272         fprintf(fp, "%d %d rlineto stroke\n", pbar.ct_length * -1, 0);
1273         fprintf(fp, "/ypos ypos %d sub def\n",
1274                 cp->ctb_width + VERT_GAP(char_size[0]) / 2);
1275         fprintf(fp, "xpos ypos moveto\n");
1276
1277         linewidth = 0;
1278 }
1279
1280 static void
1281 print_icon(struct ctrl *cp)
1282 {
1283         int i;
1284         int itype, isize;
1285
1286         for (i = 0; icon_words[i].ctl_strlen != 0; i++) {
1287                 if (!strncasecmp(cp->ctic_value, icon_words[i].ctl_string,
1288                         strlen(cp->ctic_value)))
1289                                 break;
1290         }
1291         itype = icon_words[i].ctl_type;
1292         isize = char_size[0] * cp->ctic_size / 100;
1293         icon_remember(itype, isize, linewidth, cp->ctic_color);
1294         linewidth += char_size[0];
1295 }
1296
1297 static void
1298 print_line(char *data, int pfx)
1299 {
1300         if (data && *data)
1301                 print_string(data, pfx);
1302 }
1303
1304 static void
1305 print_string(char *data, int pfx)
1306 {
1307         u_char *p, *q;
1308         int kanji = 0;
1309         u_int code2;
1310
1311         p = (u_char *)data;
1312
1313         while (*p && *p != '\n') {
1314                 if (p[0] == 0x1b && p[1] == '$'
1315                  && (p[2] == 'B' || p[2] == '@')) {
1316                         kanji = 1;
1317                         p += 3;
1318                         continue;
1319                 }
1320                 if (p[0] == 0x1b && p[1] == '('
1321                  && (p[2] == 'B' || p[2] == 'J')) {
1322                         kanji = 0;
1323                         p += 3;
1324                         continue;
1325                 }
1326
1327                 if (kanji) {
1328                         for (q = p + 2; 0x21 <= q[0] && q[0] <= 0x7e; q += 2) {
1329                                 code2 = q[0] * 256 + q[1];
1330                                 if (!iskinsokuchar(code2))
1331                                         break;
1332                         }
1333                 } else {
1334                         q = p;
1335                         while (*q && isprint(*q) && !isspace(*q))
1336                                 q++;
1337                         if (q == p)
1338                                 q++;
1339                         else {
1340                                 /* append spaces to the end of the word. */
1341                                 while (*q && isspace(*q))
1342                                         q++;
1343                         }
1344                 }
1345
1346                 print_fragment(p, q - p, kanji, pfx);
1347
1348                 p = q;
1349         }
1350 }
1351
1352 static void
1353 print_fragment(u_char *data, u_int len, int kanjimode, int pfx)
1354 {
1355         u_char *p;
1356         char *q;
1357         char buf[4096];
1358         u_int code;
1359         int textstartpos = 0;
1360 #define OPENBRACE(kanji)        ((kanji) ? '<' : '(')
1361 #define CLOSEBRACE(kanji)       ((kanji) ? '>' : ')')
1362 #define DANGERLETTER(x) \
1363         ((x) == '(' || (x) == ')' || (x) == '\\')
1364
1365         p = data;
1366         if (kanjimode) {
1367                 q = &buf[1];
1368                 while (len) {
1369                         code = p[0] * 256 + p[1];
1370                         sprintf(q, "%04x ", code);
1371                         p += 2;
1372                         len -= 2;
1373                         q += 5;
1374                 }
1375                 buf[0] = OPENBRACE(kanjimode);
1376                 *q++ = CLOSEBRACE(kanjimode);
1377                 *q = '\0';
1378                 text_remember(buf, KANJI, char_size[0], textstartpos, pfx);
1379         } else {
1380                 /* must take care of escaping those "dangerous" letters */
1381                 q = &buf[0];
1382                 *q++ = OPENBRACE(kanjimode);
1383                 while (len) {
1384                         if (DANGERLETTER(p[0]))
1385                                 *q++ = '\\';
1386                         *q++ = *p++;
1387                         len--;
1388                 }
1389                 *q++ = CLOSEBRACE(kanjimode);
1390                 *q++ = '\0';
1391                 text_remember(buf, ASCII, char_size[0], textstartpos, pfx);
1392         }
1393         /* by A.Ito 14 Jul. 2000 */
1394         /* placeholder */
1395         imagepool[nimagepool].image = NULL;
1396         imagepool[nimagepool].target_text = ntextpool-1;
1397         nimagepool++;
1398 }
1399
1400 static char *
1401 checkeps(const char *fname)
1402 {
1403         static char epsfile[MAXPATHLEN];
1404         static char fullname[MAXPATHLEN];
1405         char *p;
1406
1407         /* rewrite file suffix, if it is not "ps" nor "eps". */
1408         strlcpy(epsfile, fname, sizeof(epsfile));
1409         p = strrchr(epsfile, '.');
1410         if (p) {
1411                 if (strcmp(p, ".ps") != 0 && strcmp(p, ".eps") != 0 &&
1412                         strcmp(p, ".idraw") != 0) {
1413                         /* try "basename.eps" */
1414                         memcpy(p, ".eps", 5);
1415                 }
1416         }
1417
1418         fullname[0] = '\0';
1419         if (findImage(epsfile, fullname) == 0)
1420                 return fullname;
1421         else
1422                 return NULL;
1423 }
1424
1425 static void
1426 text_remember(char *text, int ctype, int fontsize, int offset, int pfx)
1427 {
1428         /*XXX*/
1429         if (strcmp(text, "()") == 0)
1430                 return;
1431         if (!curfont[ctype]) {
1432                 fprintf(stderr, "cannot find proper font, skipping\n");
1433                 return;
1434         }
1435         textpool[ntextpool].pfx = pfx;
1436         textpool[ntextpool].xoffset = offset;
1437         textpool[ntextpool].yoffset = char_off;
1438         textpool[ntextpool].xsiz = linewidth - offset;
1439         textpool[ntextpool].size = fontsize;
1440         textpool[ntextpool].font = curfont[ctype];
1441         textpool[ntextpool].text = strdup(text);
1442         textpool[ntextpool].fore = fore;
1443         textpool[ntextpool].back = back;
1444         ntextpool++;
1445 }
1446
1447 static void
1448 icon_remember(int icon, int fontsize, int offset, u_long color)
1449 {
1450         textpool[ntextpool].pfx = 1;
1451         textpool[ntextpool].xoffset = offset;
1452         textpool[ntextpool].xsiz = char_size[0];
1453         textpool[ntextpool].size = fontsize;
1454         textpool[ntextpool].font = (struct fontmap *)(size_t)icon;      /*XXX*/
1455         textpool[ntextpool].text = NULL;
1456         textpool[ntextpool].fore = color;
1457         textpool[ntextpool].back = back;        /*XXX*/
1458         ntextpool++;
1459 }
1460
1461 /* !TODO: move rotation code into some library */
1462 /* rotate image by 90 degrees (counter clockwise) */
1463 static void
1464 rotate_image_p90(Image *image)
1465 {
1466         unsigned int row, column, pl = image->pixlen;
1467         unsigned int new_height = image->width, new_width = image->height, new_linelen = new_width * pl;
1468         byte *src, *tgt, *col_head;
1469         Pixel d;
1470         /* allocate buffer for new image */
1471         byte *rot_data = lmalloc(new_linelen * new_height);
1472
1473         /* do the rotation */
1474         for (row = 0, src = image->data, col_head = rot_data + (new_height - 1) * new_linelen;
1475                         row < image->height;
1476                         row++, col_head += pl) {
1477                 for (column = 0, tgt = col_head;
1478                                 column < image->width;
1479                                 column++, src += pl, tgt -= new_linelen) {
1480                         d = memToVal(src, pl);
1481                         valToMem(d, tgt, pl);
1482                 }
1483         }
1484
1485         /* swap to rotated image, exchange height and width
1486            and point to rotated data */
1487         image->height = new_height;
1488         image->width = new_width;
1489         lfree(image->data);
1490         image->data = rot_data;
1491 }
1492
1493 /* rotate image by -90 degrees (clockwise) */
1494 static void
1495 rotate_image_m90(Image *image)
1496 {
1497         unsigned int row, column, pl = image->pixlen;
1498         unsigned int new_height = image->width, new_width = image->height, new_linelen = new_width * pl;
1499         byte *src, *tgt;
1500         Pixel d;
1501         /* allocate buffer for new image */
1502         byte *rot_data = lmalloc(new_linelen * new_height);
1503
1504         /* do the rotation */
1505         for (row = 0, src = image->data; row < image->height; row++) {
1506                 for (column = 0, tgt = rot_data + new_linelen - (row + 1) * pl;
1507                                 column < image->width;
1508                                 column++, src += pl, tgt += new_linelen) {
1509                         d = memToVal(src, pl);
1510                         valToMem(d, tgt, pl);
1511                 }
1512         }
1513
1514         /* swap to rotated image, exchange height and width
1515            and point to rotated data */
1516         image->height = new_height;
1517         image->width = new_width;
1518         lfree(image->data);
1519         image->data = rot_data;
1520
1521         return;
1522 }
1523
1524 /* rotate image by 180 degrees */
1525 static void
1526 rotate_image_180(Image *image)
1527 {
1528         unsigned int row, column, pl = image->pixlen;
1529         unsigned int new_height = image->height, new_width = image->width, new_linelen = new_width * pl;
1530         byte *src, *tgt;
1531         Pixel d;
1532         /* allocate buffer for new image */
1533         byte *rot_data = lmalloc(new_linelen * new_height);
1534
1535         /* do the rotation */
1536         for (row = 0, src = image->data; row < image->height; row++) {
1537                 for (column = 0, tgt = rot_data + (new_height - row) * new_linelen - pl;
1538                                 column < image->width;
1539                                 column++, src += pl, tgt -= pl) {
1540                         d = memToVal(src, pl);
1541                         valToMem(d, tgt, pl);
1542                 }
1543         }
1544
1545         /* swap to rotated image, exchange height and width
1546            and point to rotated data */
1547         image->height = new_height;
1548         image->width = new_width;
1549         lfree(image->data);
1550         image->data = rot_data;
1551
1552         return;
1553 }
1554
1555 static void
1556 image_remember(struct ctrl *cp, struct imagepool *pool)
1557 {
1558         char *epsname;
1559         Image *myimage;
1560         float xzoom, yzoom;
1561         int x1, y1v, x2, y2, width, height, swidth, sheight;
1562         struct render_state state;
1563
1564         if ((epsname = checkeps(cp->ctm_fname))){
1565                 if (ps_boundingbox(epsname, &x1, &y1v, &x2, &y2) < 0) goto noneps;
1566
1567                 width = x2 - x1;
1568                 height = y2 - y1v;
1569         } else {
1570                 myimage = loadImage(cp->ctm_fname);
1571                 if (!myimage) {
1572                         fprintf(stderr, "failed to open %s\n", cp->ctm_fname);
1573                         exit(1);
1574                 }
1575                 switch (cp->ctm_rotate) {
1576                         case 0:
1577                                 /* Do nothing */
1578                                 break;
1579
1580                         case -90:
1581                         case 270:
1582                                 rotate_image_m90(myimage);
1583                                 break;
1584
1585                         case 90:
1586                                 rotate_image_p90(myimage);
1587                                 break;
1588
1589                         case -180:
1590                         case 180:
1591                                 rotate_image_180(myimage);
1592                                 break;
1593
1594                         default:
1595                                 fprintf(stderr, "rotation by %d degrees not supported.\n", cp->ctm_rotate);
1596                                 cleanup(-1);
1597                 }
1598                 width = myimage->width;
1599                 height = myimage->height;
1600                 freeImage(myimage);
1601         }
1602                 xzoom = (!cp->ctm_ximagesize ? 100 : cp->ctm_ximagesize);
1603                 yzoom = (!cp->ctm_yimagesize ? 100 : cp->ctm_yimagesize);
1604
1605                 state.width = window_width;
1606                 state.height = window_height;
1607                 image_zoomratio(&state, &xzoom, &yzoom, cp->ctm_zoomflag,
1608                         width, height);
1609                 swidth = (int) width * xzoom / 100;
1610                 sheight = (int) height * yzoom / 100;
1611
1612                 pool->xsiz = swidth;
1613                 pool->ysiz = sheight;
1614                 pool->xoffset = linewidth;
1615                 pool->image = cp;
1616                 return;
1617
1618 noneps:
1619         myimage = loadImage(cp->ctm_fname);
1620         if (!myimage) {
1621                 fprintf(stderr, "failed to open %s\n", cp->ctm_fname);
1622                 exit(1);
1623         }
1624         switch (cp->ctm_rotate) {
1625                 case 0:
1626                         /* Do nothing */
1627                         break;
1628
1629                 case -90:
1630                 case 270:
1631                         rotate_image_m90(myimage);
1632                         break;
1633
1634                 case 90:
1635                         rotate_image_p90(myimage);
1636                         break;
1637
1638                 case -180:
1639                 case 180:
1640                         rotate_image_180(myimage);
1641                         break;
1642
1643                 default:
1644                         fprintf(stderr, "rotation by %d degrees not supported.\n", cp->ctm_rotate);
1645                         cleanup(-1);
1646         }
1647         pool->xsiz = myimage->width;
1648         pool->ysiz = myimage->height;
1649         freeImage(myimage);
1650         pool->xoffset = linewidth;
1651         pool->image = cp;
1652 }
1653
1654 static void
1655 image_load_print(const char *filename, int numcolor,
1656     int ximagesize, int yimagesize, int zoomflag, int rotate)
1657 {
1658         Image *myimage, *image;
1659         Pixmap mypixmap;
1660         XImageInfo *ximageinfo;
1661         XImage  *print_image;
1662         int width, height;
1663         float xzoomrate, yzoomrate;
1664         static Cursor curs;
1665         u_int   print_width, print_height;
1666         struct render_state state;
1667
1668         if (zoomflag == 2)
1669                 ximagesize = yimagesize = 0;
1670
1671         /* hook for eps */
1672     {
1673         char *p;
1674         FILE *epsfp;
1675
1676         p = checkeps(filename);
1677         if (p) {
1678                 epsfp = fopen(p, "r");
1679                 print_eps(epsfp, p, ximagesize, yimagesize, zoomflag);
1680                 fclose(epsfp);
1681                 return;
1682         }
1683     }
1684
1685         if (!curs)
1686                 curs = XCreateFontCursor(display, XC_watch);
1687         XDefineCursor(display, window, curs); XFlush(display);
1688
1689         screen = DefaultScreen(display);
1690
1691         if ((myimage = loadImage(filename)) == NULL)
1692                 exit(-1);       /* fail to load image data */
1693         switch (rotate) {
1694                 case 0:
1695                         /* Do nothing */
1696                         break;
1697
1698                 case -90:
1699                 case 270:
1700                         rotate_image_m90(myimage);
1701                         break;
1702
1703                 case 90:
1704                         rotate_image_p90(myimage);
1705                         break;
1706
1707                 case -180:
1708                 case 180:
1709                         rotate_image_180(myimage);
1710                         break;
1711
1712                 default:
1713                         fprintf(stderr, "rotation by %d degrees not supported.\n", rotate);
1714                         cleanup(-1);
1715         }
1716         width = myimage->width;
1717         height = myimage->height;
1718
1719         if (numcolor)
1720                 myimage = reduce(myimage, numcolor, verbose);
1721
1722         xzoomrate = (float) ximagesize;
1723         yzoomrate = (float) yimagesize;
1724         state.width = window_width;
1725         state.height = window_height;
1726         image_zoomratio(&state, &xzoomrate, &yzoomrate, zoomflag,
1727                 width, height);
1728         image = myimage;
1729         myimage = zoom(image, xzoomrate, yzoomrate, verbose);
1730         freeImage(image);
1731         width = myimage->width;
1732         height = myimage->height;
1733
1734         if (! (ximageinfo= imageToXImage(display, screen, visual, depth,
1735                         myimage, 0, 0, 0, verbose))) {
1736                 fprintf(stderr, "Cannot convert Image to XImage\n");
1737                 exit(1);
1738         }
1739
1740         mypixmap = ximageToPixmap(display, RootWindow(display, 0), ximageinfo);
1741         if (!mypixmap) {
1742                 fprintf(stderr, "Cannot create image in server\n");
1743                 exit(1);
1744         }
1745
1746         switch (align) {
1747         case AL_LEFT:
1748         case AL_LEFTFILL0:
1749         case AL_LEFTFILL1:
1750                 break;
1751         case AL_CENTER:
1752                 break;
1753         case AL_RIGHT:
1754                 break;
1755         }
1756
1757         print_width = myimage->width;
1758         print_height = myimage->height;
1759
1760         print_image =  XGetImage(display, mypixmap, 0, 0,
1761                                         print_width, print_height,
1762                                         AllPlanes, ZPixmap);
1763
1764         fprintf(fp, "gsave\n");
1765
1766         /* fixed by A.Ito */
1767         fprintf(fp, "xpos ypos %d sub translate\n",
1768                 print_height);
1769         fprintf(fp, "%d %d scale\n", print_width, print_height);
1770         fprintf(fp, "%d %d 8\n", print_width, print_height);
1771         fprintf(fp, "[%d 0 0 %d 0 %d]\n", print_width,
1772                         -1 * print_height, print_height);
1773         fprintf(fp, "{currentfile\n");
1774         fprintf(fp, "%d string readhexstring pop}\n", print_width * 3);
1775         fprintf(fp, "false 3\n");
1776         fprintf(fp, "colorimage\n");
1777
1778         /* XXX is there any generic way of doing this? */
1779         switch (print_image->bits_per_pixel) {
1780         case 8:
1781                 print_8_image(print_image);
1782                 break;
1783         case 16:
1784                 print_full_image(print_image, visual);
1785                 break;
1786         case 32:
1787                 print_32_image(print_image, visual);
1788                 break;
1789         default:
1790                 fprintf(stderr, "Sorry unsupported visual %d\n",
1791                         print_image->bits_per_pixel);
1792                 exit(-1);
1793         }
1794
1795         fprintf(fp, "grestore\n");
1796
1797         XFreePixmap(display, mypixmap);
1798         freeXImage(ximageinfo);
1799         freeImage(myimage);
1800         XUndefineCursor(display, window); XFlush(display);
1801 }
1802
1803 static void
1804 print_usage(char *name)
1805 {
1806         fprintf(stderr, "Usage: %s [-cimPrv] [-e encoding] [-f psfile] "
1807             "[-g gap] [-p paper] [-x xmargin] [-y ymargin] mgpfile\n", name);
1808         exit(0);
1809 }
1810
1811 static void
1812 setpencolor(u_long c)
1813 {
1814         /*
1815          * update the color of the pen.
1816          * XXX background is ignored at this moment
1817          */
1818         XColor color;
1819
1820         color.pixel = c;
1821         XQueryColor(display, colormap, &color);
1822         fprintf(fp, "%f %f %f setrgbcolor %% #%08x depth %d\n",
1823                 color.red / 65535.0,
1824                 color.green / 65535.0,
1825                 color.blue / 65535.0,
1826                 (int) color.pixel, depth);
1827 }
1828
1829 static void
1830 print_full_image(XImage *print_image, Visual *visual2)
1831 {
1832         u_int   x, y;
1833         u_int   r, g, b;
1834         u_int   count = 0;
1835         u_int   width, height, byte_width;
1836         u_short *data;
1837
1838         data = (u_short *)print_image->data;
1839         width = print_image->width;
1840         height = print_image->height;
1841         byte_width = print_image->bytes_per_line / sizeof(u_short);
1842
1843         for (y = 0; y < height; y ++) {
1844                 for (x = 0; x < width; x ++) {
1845                         r = ((data[x + y * byte_width] & visual2->red_mask) >> 11) & 0xff;
1846                         g = ((data[x + y * byte_width] & visual2->green_mask) >> 5) & 0xff;
1847                         b = (data[x + y * byte_width] & visual2->blue_mask) & 0xff;
1848
1849                         if (reverse)
1850                                 fprintf(fp, "%02x%02x%02x",
1851                                         ~(r << 3) & 0xff, ~(g << 2) & 0xff, ~(b << 3) & 0xff);
1852                         else
1853                                 fprintf(fp, "%02x%02x%02x", r << 3, g << 2, b << 3);
1854
1855                         count ++;
1856                         if (count == 10) {
1857                                 count = 0;
1858                                 fprintf(fp, "\n");
1859                         }
1860                 }
1861         }
1862 }
1863
1864 static void
1865 print_32_image(XImage *print_image, Visual *visual2)
1866 {
1867         u_int   x, y;
1868         u_int   r, g, b;
1869         u_int   count = 0;
1870         u_int   width, height;
1871
1872         width = print_image->width;
1873         height = print_image->height;
1874
1875         for (y = 0; y < height; y ++) {
1876                 for (x = 0; x < width; x ++) {
1877                         unsigned long pix;
1878                         pix = XGetPixel(print_image, x, y);
1879                         r = ((pix & visual2->red_mask)   >> 16) & 0xff;
1880                         g = ((pix & visual2->green_mask) >>  8) & 0xff;
1881                         b =   pix & visual2->blue_mask          & 0xff;
1882
1883                         if (reverse)
1884                                 fprintf(fp, "%02x%02x%02x",
1885                                         ~r & 0xff, ~g & 0xff, ~b & 0xff);
1886                         else
1887                                 fprintf(fp, "%02x%02x%02x", r, g, b);
1888
1889                         count ++;
1890                         if (count == 10) {
1891                                 count = 0;
1892                                 fprintf(fp, "\n");
1893                         }
1894                 }
1895         }
1896 }
1897
1898 static void
1899 print_8_image(XImage *print_image)
1900 {
1901         u_int   x, y;
1902         u_int   count = 0;
1903         u_char  *data;
1904         u_int   width, height, byte_width;
1905
1906         data = (u_char *)print_image->data;
1907         width = print_image->width;
1908         height = print_image->height;
1909         byte_width = print_image->bytes_per_line / sizeof(u_char);
1910
1911         for (y = 0; y < height; y ++) {
1912                 for (x = 0; x < width; x ++) {
1913                         if (reverse)
1914                                 fprintf(fp, "%02x%02x%02x",
1915                                         ~data[x + y * byte_width] & 0xff,
1916                                         ~data[x + y * byte_width] & 0xff,
1917                                         ~data[x + y * byte_width] & 0xff);
1918                         else
1919                                 fprintf(fp, "%02x%02x%02x",
1920                                         data[x + y * byte_width],
1921                                         data[x + y * byte_width],
1922                                         data[x + y * byte_width]);
1923
1924                         count ++;
1925                         if (count == 10) {
1926                                 count = 0;
1927                                 fprintf(fp, "\n");
1928                         }
1929                 }
1930         }
1931 }
1932
1933 static void
1934 print_eps(FILE *epsfp, char *filename,
1935     int ximagesize, int yimagesize, int zoomflag)
1936 {
1937         char line1[BUFSIZ];
1938         char line2[BUFSIZ];
1939         char line[BUFSIZ];
1940         int x1, y1v, x2, y2, height, width;
1941         float xzoomrate, yzoomrate;
1942         double xscale, yscale;
1943         int noboundingbox;
1944         struct render_state state;
1945
1946         if (fgets(line1, sizeof(line1), epsfp) == NULL) {
1947                 fprintf(stderr, "no first line in %s.\n", filename);
1948                 exit(1);
1949         }
1950         if (strncmp(line1, "%!", 2) != 0) {
1951                 fprintf(stderr, "non eps file %s used as eps.\n", filename);
1952                 exit(1);
1953         }
1954
1955         noboundingbox = 1;
1956         while (1) {
1957                 if (fgets(line2, sizeof(line2), epsfp) == NULL)
1958                         break;
1959                 if (line2[0] != '%')
1960                         break;
1961                 if (strncmp(line2, "%%EndComments", 12) == 0)
1962                         break;
1963                 if (sscanf(line2, "%%%%BoundingBox: %d %d %d %d",
1964                                 &x1, &y1v, &x2, &y2) == 4) {
1965                         noboundingbox = 0;
1966                         break;
1967                 }
1968         }
1969         if (noboundingbox) {
1970                 fprintf(stderr, "no bounding box in %s.\n", filename);
1971                 exit(1);
1972         }
1973
1974         /* width/height of original image */
1975         width = x2 - x1;
1976         height = y2 - y1v;
1977
1978         ximagesize = (!ximagesize ? 100 : ximagesize);
1979         yimagesize = (!yimagesize ? 100 : yimagesize);
1980
1981         xzoomrate = (float) ximagesize;
1982         yzoomrate = (float) yimagesize;
1983         state.width = window_width;
1984         state.height = window_height;
1985         image_zoomratio(&state, &xzoomrate, &yzoomrate, zoomflag,
1986                 width, height);
1987         xscale = xzoomrate / 100.0;
1988         yscale = yzoomrate / 100.0;
1989
1990         switch (align) {
1991         case AL_LEFT:
1992         case AL_LEFTFILL0:
1993         case AL_LEFTFILL1:
1994                 break;
1995         case AL_CENTER:
1996                 break;
1997         case AL_RIGHT:
1998                 break;
1999         }
2000
2001         fprintf(fp, "BeginEPSF\n");
2002 /*
2003         fprintf(fp, "%d XMARGIN add ypos translate\n", xpos);
2004 */
2005         /* by A.Ito */
2006         fprintf(fp, "xpos ypos translate\n");
2007         fprintf(fp, "%f %f scale\n", xscale, yscale);
2008         fprintf(fp, "%d %d translate\n", -1 * x1, -1 * y2);
2009         fprintf(fp, "%%%%BeginDocument: %s\n", filename);
2010         fputs(line1, fp);
2011         fputs(line2, fp);
2012         while (fgets(line, sizeof(line), epsfp)) {
2013                 if (strncmp(line, "%%PageBoundingBox:", 18) == 0
2014                 ||  strncmp(line, "%%Trailer", 9) == 0)
2015                         line[1] = '#';
2016                 fputs(line, fp);
2017         }
2018         fprintf(fp, "%%%%EndDocument\n");
2019         fprintf(fp, "EndEPSF\n");
2020 }
2021
2022 /*------------------------------------------------------------*/
2023
2024 int
2025 main(int argc, char *argv[])
2026 {
2027         int opt;
2028         char *progname;
2029         static char pathbuf[MAXPATHLEN];
2030
2031 #if HAVE_SETLOCALE_CTYPE
2032         setlocale(LC_CTYPE, "");
2033 #endif
2034
2035         progname = argv[0];
2036
2037         /* set default paper size */
2038         paper = findpaper(DEFAULT_PAPER_SIZE);
2039
2040         while ((opt = getopt(argc, argv, "ce:f:g:imPp:rvx:y:")) != -1) {
2041                 switch (opt) {
2042                 case 'c':
2043                         colorps++;
2044                         break;
2045
2046                 case 'e':
2047                         for (encoding = &encodings[0];
2048                              encoding->name;
2049                              encoding++) {
2050                                 if (strcmp(encoding->name, optarg) == 0)
2051                                         break;
2052                         }
2053                         if (!encoding->name) {
2054                                 fprintf(stderr, "unknown encoding %s\n", optarg);
2055                                 exit(1);
2056                         }
2057                         break;
2058
2059                 case 'f':
2060                         strlcpy(outputfile, optarg, sizeof(outputfile));
2061                         break;
2062
2063                 case 'g':
2064                         gaplevel = atoi(optarg);
2065                         break;
2066
2067                 case 'i':
2068                         painticon++;
2069                         break;
2070
2071                 case 'm':       /* Added by Arnd Schmitter 23.07.2004 */
2072                         PauseMode=1;
2073                         break;
2074
2075                 case 'P':
2076                         parse_debug++;
2077                         break;
2078
2079                 case 'p':
2080                         paper = findpaper(optarg);
2081                         if (!paper) {
2082                                 fprintf(stderr,"Paper size '%s' not recognised. Using %s instead.\n",
2083                                     optarg, DEFAULT_PAPER_SIZE);
2084                                 paper = findpaper(DEFAULT_PAPER_SIZE);
2085                         }
2086                         break;
2087
2088                 case 'r':
2089                         reverse = 1;
2090                         break;
2091
2092                 case 'v':
2093                         mgp_flag |= FL_VERBOSE;
2094                         break;
2095
2096                 case 'x':
2097                         paper_xmargin = atoi(optarg);
2098                         break;
2099
2100                 case 'y':
2101                         paper_ymargin = atoi(optarg);
2102                         break;
2103
2104                 default:
2105                         print_usage(progname);
2106                         /*NOTREACHED*/
2107                 }
2108         }
2109
2110         w_width  = paper->width - paper_xmargin * 2;
2111         w_height = paper->height - paper_ymargin * 2;
2112
2113         argc -= optind;
2114         argv += optind;
2115
2116         if (argc != 1) {
2117                 print_usage(progname);
2118                 /*NOTREACHED*/
2119         }
2120
2121         mgp_fname = argv[0];
2122
2123         /* setting up the search path. */
2124     {
2125         char *p;
2126         loadPathsAndExts();
2127         strlcpy(pathbuf, mgp_fname, sizeof(pathbuf));
2128         if ((p = strrchr(pathbuf, '/'))) {
2129                 *p = '\0';
2130                 Paths[NumPaths++]= expandPath(pathbuf);
2131         }
2132     }
2133
2134         init_win1(NULL);
2135         load_file(mgp_fname);
2136         init_win2();
2137         fore = 0UL;
2138         back = (1UL << depth) - 1;
2139         print_out();
2140
2141         exit(0);
2142 }
2143
2144 static struct fontmap *
2145 findfont(int ctrl, int lang, char *font)
2146 {
2147         struct fontmap *p, *q;
2148         char *star;
2149
2150         if (!font[0])
2151                 return NULL;
2152
2153         for (p = fontmap; 0 <= p->ctrl; p++) {
2154                 if (p->ctrl != ctrl || p->lang != lang)
2155                         continue;
2156                 star = strchr(p->font, '*');
2157                 if (!star && strcmp(p->font, font) == 0)
2158                         goto found;
2159                 if (star && strncmp(p->font, font, star - p->font) == 0)
2160                 {
2161                         if(strcmp(font,"k14")==0)
2162                                 goto found;
2163                         if(ctrl ==CTL_PSFONT)
2164                                 fprintf(stderr,"PSFONT: %s  not found\n",font);
2165                         goto found;
2166                 }
2167         }
2168         return NULL;
2169
2170 found:
2171         if (p->fontid)
2172                 return p;
2173
2174         p->fontid = ++maxfontid;
2175
2176         if (mgp_flag & FL_VERBOSE) {
2177                 char fonttype;
2178
2179                 switch (ctrl) {
2180                 case CTL_XFONT2: fonttype = 'x'; break;
2181
2182                 case CTL_PSFONT: fonttype = 'p'; break;
2183                 default:        fonttype = '?'; break;
2184                 }
2185                 fprintf(fp, "%% %cfont \"%s\" seen, mapped to ps font \"%s\"\n",
2186                         fonttype, font, p->psfont);
2187                 if (strcmp(font, p->font) != 0) {
2188                         fprintf(fp, "%%\t(wildcard match against \"%s\")\n",
2189                                 p->font);
2190                 }
2191         }
2192         /* use the same font index for same PS font names */
2193         for (q = fontmap; 0 <= q->ctrl; q++) {
2194                 if (strcmp(p->psfont, q->psfont) == 0)
2195                         q->fontid = maxfontid;
2196         }
2197
2198         return p;
2199 }
2200
2201 static char *
2202 fontstring(struct fontmap *font)
2203 {
2204         static char fontname[10];
2205
2206         sprintf(fontname, "F%03d", font->fontid);
2207         return fontname;
2208 }
2209
2210 static void
2211 loadfont(struct fontmap *font, const char *name)
2212 {
2213         if (!font) {
2214                 fprintf(stderr, "unable to find proper font for %s\n", name);
2215                 exit(1);
2216         }
2217
2218         if (font->loaded)
2219                 return;
2220
2221         /* define font calling sequence */
2222         if (mgp_flag & FL_VERBOSE) {
2223                 fprintf(fp, "%% loading font \"%s\" for %s\n",
2224                         font->psfont, font->font);
2225         }
2226         if (font->lang == ASCII && encoding) {
2227                 /*
2228                  * Symbol font does not need latin1-encoding
2229                  */
2230                 if (strcmp(font->psfont, "Symbol") == 0) {
2231                         fprintf(fp,
2232                                 "/%s%s\n"
2233                                 "       /%s findfont\n"
2234                                 "               dup length dict begin\n"
2235                                 "               {1 index /FID ne {def} {pop "
2236                                 "pop} ifelse} forall\n"
2237                                 "       currentdict end\n"
2238                                 "definefont pop\n",
2239                                 fontstring(font), "t", font->psfont);
2240                 } else {
2241                         fprintf(fp,
2242 "/%s%s\n"
2243 "       /%s findfont\n"
2244 "               dup length dict begin\n"
2245 "               {1 index /FID ne {def} {pop pop} ifelse} forall\n"
2246 "               /Encoding %s def\n"
2247 "       currentdict end\n"
2248 "definefont pop\n",
2249                         fontstring(font), "t", font->psfont, encoding->defstr);
2250                 }
2251
2252                 fprintf(fp, "/%s {/%s%s findfont exch scalefont setfont} def\n",
2253                         fontstring(font), fontstring(font), "t");
2254         } else {
2255                 fprintf(fp, "/%s {/%s findfont exch scalefont setfont} def\n",
2256                         fontstring(font), font->psfont);
2257         }
2258         font->loaded = 1;
2259 }
2260
2261 void
2262 cleanup(int sig)
2263 {
2264         /* dummy */
2265         exit(-sig);
2266 }