Changed russian description a little bit
[gnuplot] / term / post.trm
1 /* Hello, Emacs: this is -*-C-*- !
2  * $Id: post.trm,v 1.203.2.17 2009/03/02 17:40:06 mikulik Exp $
3  */
4
5 /* GNUPLOT - post.trm */
6
7 /*[
8  * Copyright 1990 - 1993, 1998, 1999, 2000, 2001, 2004
9  *
10  * Permission to use, copy, and distribute this software and its
11  * documentation for any purpose with or without fee is hereby granted,
12  * provided that the above copyright notice appear in all copies and
13  * that both that copyright notice and this permission notice appear
14  * in supporting documentation.
15  *
16  * Permission to modify the software is granted, but not the right to
17  * distribute the complete modified source code.  Modifications are to
18  * be distributed as patches to the released version.  Permission to
19  * distribute binaries produced by compiling modified sources is granted,
20  * provided you
21  *   1. distribute the corresponding source modifications from the
22  *    released version in the form of a patch file along with the binaries,
23  *   2. add special version identification to distinguish your version
24  *    in addition to the base release version number,
25  *   3. provide your name and address as the primary contact for the
26  *    support of your modified version, and
27  *   4. retain our contact information in regard to use of the base
28  *    software.
29  * Permission to distribute the released version of the source code along
30  * with corresponding source modifications in the form of a patch file is
31  * granted with same provisions 2 through 4 for binary distributions.
32  *
33  * This software is provided "as is" without express or implied warranty
34  * to the extent permitted by applicable law.
35 ]*/
36
37 /*
38  * This terminal driver supports:
39  *     postscript
40  *
41  * AUTHORS
42  *  Russell Lang  <rjl@monu1.cc.monash.edu.au>
43  *
44  * modified 10/5/95 by drd - put in support for other postscript drivers
45  * (enhpost, pslatex, ...) so they dont have to work quite so hard
46  *
47  * send your comments or suggestions to (gnuplot-info@lists.sourceforge.net).
48  *
49  * The 'postscript' driver produces landscape output 10" wide and 7" high.
50  * To change font to Times-Roman and font size to 20pts use
51  * 'set term postscript "Times-Roman" 20'.
52  * To get a smaller (5" x 3.5") eps output use 'set term post eps'
53  * and make only one plot per file.  Font size for eps will be half
54  * the specified size.
55  *
56  * Erik Luijten 30/5/97: added %%CreationDate, made %%DocumentFonts conform
57  *                       to DSC, added version no. and patchl. to %%Creator
58  * Petr Mikulik, Jan 1999: terminal entries for PM3D functionality
59  *
60  * Dick Crawford 24/5/00: added 'a{}{}' syntax to allow for overprinting
61  *
62  * Dan Sebald, 7 March 2003: terminal entry for image functionality
63  *
64  *  Harald Harders (h.harders@tu-bs.de), 2004-12-02:
65  *  Moved all terminal settings into a single structure.
66  *
67  *  Harald Harders (h.harders@tu-bs.de), 2005-02-08:
68  *  Merged functionality of postscript, pslatex, pstex, and epslatex terminals.
69  *
70  *  Ethan Merritt Mar 2006:   Break out prolog and character encodings into
71  *  separate files loaded at runtime
72  */
73
74 #include "driver.h"
75
76 #ifdef TERM_PROTO
77 #include "variable.h"   /* For loadpath_handler used in PS_dump_prologue_file */
78 #endif
79
80 #ifdef TERM_REGISTER
81 register_term(post)
82 #endif
83
84 #ifdef TERM_PROTO
85 TERM_PUBLIC void PS_options __PROTO((void));
86 TERM_PUBLIC void PS_common_init __PROTO((TBOOLEAN uses_fonts, unsigned int xoff, unsigned int yoff, unsigned int bb_xmin, unsigned int bb_ymin, unsigned int bb_xmax, unsigned int bb_ymax, const char **dict));
87 TERM_PUBLIC void PS_init __PROTO((void));
88 TERM_PUBLIC void PS_graphics __PROTO((void));
89 TERM_PUBLIC void PS_text __PROTO((void));
90 TERM_PUBLIC void PS_reset __PROTO((void));
91 TERM_PUBLIC void PS_linetype __PROTO((int linetype));
92 TERM_PUBLIC void PS_move __PROTO((unsigned int x, unsigned int y));
93 TERM_PUBLIC void PS_vector __PROTO((unsigned int x, unsigned int y));
94 TERM_PUBLIC void PS_put_text __PROTO((unsigned int x, unsigned int y, const char *str));
95 TERM_PUBLIC int PS_text_angle __PROTO((int ang));
96 TERM_PUBLIC int PS_justify_text __PROTO((enum JUSTIFY mode));
97 TERM_PUBLIC void PS_point __PROTO((unsigned int x, unsigned int y, int number));
98 TERM_PUBLIC void PS_arrow __PROTO(( unsigned int sx, unsigned int sy,
99     unsigned int ex, unsigned int ey, int head));
100 TERM_PUBLIC int PS_set_font __PROTO((const char * font));
101 TERM_PUBLIC void PS_fillbox __PROTO((int style, unsigned int x1, unsigned int y1, unsigned int width, unsigned int height));
102 TERM_PUBLIC void PS_linewidth __PROTO((double linewidth)); /* JFi [linewidth] */
103 TERM_PUBLIC void PS_pointsize __PROTO((double ptsize)); /* JFi [pointsize] */
104 TERM_PUBLIC int PS_make_palette (t_sm_palette *);
105 TERM_PUBLIC void PS_previous_palette (void);
106 TERM_PUBLIC void PS_set_color (t_colorspec *);
107 TERM_PUBLIC void PS_filled_polygon (int, gpiPoint *);
108 #ifdef WITH_IMAGE
109 TERM_PUBLIC void PS_image __PROTO((unsigned, unsigned, coordval *, gpiPoint *, t_imagecolor));
110 #endif
111
112 /* To support "set term post enhanced" */
113 TERM_PUBLIC void ENHPS_put_text __PROTO((unsigned int x, unsigned int y, const char *str));
114 TERM_PUBLIC int  ENHPS_set_font __PROTO((const char * font));
115 TERM_PUBLIC void ENHPS_OPEN __PROTO((char * fontname, double fontsize,
116                         double base, TBOOLEAN widthflag, TBOOLEAN showflag,
117                         int overprint));
118 TERM_PUBLIC void ENHPS_FLUSH __PROTO((void));
119 TERM_PUBLIC void ENHPS_WRITEC __PROTO((int c));
120 TERM_PUBLIC char *PS_RememberFont __PROTO((char *fname, int reencode));
121
122 TERM_PUBLIC char *PS_escape_string __PROTO((char *origstr, char *escapelist));
123
124 TERM_PUBLIC void PS_path __PROTO((int p));
125 static TBOOLEAN PS_newpath = FALSE;
126
127 #endif /* TERM_PROTO */
128
129 #ifndef TERM_PROTO_ONLY
130
131 #ifdef TERM_BODY
132
133 #include "post.h"
134
135 #define PS_FLUSH_PATH do {                      \
136     if (ps_path_count) {                        \
137         fputs("stroke\n", gppsfile);            \
138         ps_path_count = 0;                      \
139         PS_relative_ok = FALSE;                 \
140     }                                           \
141 } while (0)
142
143 /* Datastructure implementing inclusion of font files */
144 struct ps_fontfile_def {
145     struct ps_fontfile_def *next;/* pointer to next fontfile in linked list */
146     char *fontfile_name;
147     char *fontfile_fullname;
148 };
149
150 /* Terminal type of postscript dialect */
151 enum PS_TERMINALTYPE {
152     PSTERM_PSTEX, PSTERM_PSLATEX, PSTERM_EPSLATEX, PSTERM_POSTSCRIPT
153 };
154
155 enum PS_PSFORMAT {
156     PSTERM_EPS, PSTERM_PORTRAIT, PSTERM_LANDSCAPE
157 };
158
159 /* One struct that takes all terminal parameters
160  * by Harald Harders <h.harders@tu-bs.de> */
161 typedef struct ps_params_t {
162     enum PS_TERMINALTYPE terminal;
163     int xoff;
164     int yoff;
165     enum PS_PSFORMAT psformat;
166     TBOOLEAN level1;
167     TBOOLEAN color;
168     TBOOLEAN blacktext;
169     TBOOLEAN solid;
170     float dash_length;
171     float linewidth_factor;
172     TBOOLEAN duplex_option;           /* one of duplex or simplex specified? */
173     TBOOLEAN duplex_state;
174     TBOOLEAN rounded;                 /* rounded linecaps and linejoins */
175     struct ps_fontfile_def *first_fontfile;
176     char font[MAX_ID_LEN+1];          /* name of font */
177     float fontsize;                     /* size of font in pts */
178     TBOOLEAN useauxfile;              /* only necessary for ps(la)tex */
179     TBOOLEAN rotate;                  /* only necessary for ps(la)tex */
180     int palfunc_samples;              /* setable via "palf$uncparam" */
181     double palfunc_deviation;         /* terminal option */
182     TBOOLEAN oldstyle;
183     TBOOLEAN epslatex_standalone;
184 } ps_params_t;
185
186 #define POST_PARAMS_DEFAULT { \
187     PSTERM_POSTSCRIPT, 50, 50, \
188     PSTERM_LANDSCAPE, FALSE, FALSE, FALSE, FALSE, 1.0, 1.0, FALSE, \
189     FALSE, FALSE, NULL, "Helvetica", 14, FALSE, FALSE, 2000, 0.003, \
190     FALSE, FALSE \
191 }
192
193 static ps_params_t post_params = POST_PARAMS_DEFAULT;
194 static const ps_params_t post_params_default = POST_PARAMS_DEFAULT;
195
196 #define EPSLATEX_PARAMS_DEFAULT { \
197     PSTERM_EPSLATEX, 50, 50, \
198     PSTERM_EPS, FALSE, FALSE, TRUE, FALSE, 1.0, 1.0, FALSE, \
199     FALSE, FALSE, NULL, "", 11, TRUE, FALSE, 2000, 0.003, \
200     FALSE, FALSE \
201 }
202 static ps_params_t epslatex_params = EPSLATEX_PARAMS_DEFAULT;
203 static const ps_params_t epslatex_params_default = EPSLATEX_PARAMS_DEFAULT;
204
205 #define PSLATEX_PARAMS_DEFAULT { \
206     PSTERM_PSLATEX, 0, 0, \
207     PSTERM_EPS, FALSE, FALSE, TRUE, FALSE, 1.0, 1.0, FALSE, \
208     FALSE, FALSE, NULL, "", 0, FALSE, TRUE, 2000, 0.003, \
209     FALSE, FALSE \
210 }
211 static ps_params_t pslatex_params = PSLATEX_PARAMS_DEFAULT;
212 static const ps_params_t pslatex_params_default = PSLATEX_PARAMS_DEFAULT;
213
214 #define PSTEX_PARAMS_DEFAULT { \
215     PSTERM_PSTEX, 0, 0, \
216     PSTERM_EPS, FALSE, FALSE, TRUE, FALSE, 1.0, 1.0, FALSE, \
217     FALSE, FALSE, NULL, "", 0, FALSE, TRUE, 2000, 0.003, \
218     FALSE, FALSE \
219 }
220 static ps_params_t pstex_params = PSTEX_PARAMS_DEFAULT;
221 static const ps_params_t pstex_params_default = PSTEX_PARAMS_DEFAULT;
222
223 static ps_params_t *ps_params = &post_params;
224
225 static void make_interpolation_code __PROTO((void));
226 static void make_color_model_code __PROTO((void));
227 static char * save_space __PROTO((double gray));
228 static void write_component_array __PROTO((const char *text, gradient_struct *grad, int cnt, int offset));
229 static void write_gradient_definition __PROTO((gradient_struct *gradient, int cnt));
230 static void write_color_space __PROTO((t_sm_palette *palette));
231 static void make_palette_formulae __PROTO((void));
232 static void PS_make_header __PROTO((t_sm_palette *palette));
233
234 static float ps_fontsize;
235
236 /* for enhanced mode, we keep a separate font name and size, which
237  * is restored to the default value on font of ""
238  */
239 static char ps_enh_font[MAX_ID_LEN+1];
240 static float ps_enh_fontsize;
241 static int  ENHPS_initialized;
242
243 static int ps_page = 0;         /* page count */
244 static int ps_path_count = 0;   /* count of lines in path */
245 static int ps_ang = 0;                  /* text angle */
246 static enum JUSTIFY ps_justify = LEFT;  /* text is flush left */
247
248 static void delete_ps_fontfile __PROTO((struct ps_fontfile_def *, struct ps_fontfile_def *));
249
250 TERM_PUBLIC void PS_load_fontfile __PROTO((struct ps_fontfile_def *,TBOOLEAN));
251 TERM_PUBLIC void PS_load_fontfiles __PROTO((TBOOLEAN));
252
253 static TBOOLEAN ps_explicit_size = FALSE;
254 static size_units ps_explicit_units = INCHES;
255 static int eps_explicit_x = 0;
256 static int eps_explicit_y = 0;
257
258 #define DOTS_PER_INCH (300)    /* resolution of printer we expect to use */
259
260 /* name of auxiliary file */
261 static char *pslatex_auxname = NULL;
262
263 /* Routine to copy pre-existing prolog files into output stream */
264 static void PS_dump_prologue_file __PROTO((char *));
265
266 static const char GPFAR * GPFAR OldEPSL_linetypes[] = {
267 /* Line Types */
268 "% Redefine line types to match old epslatex driver\n",
269 "/LTw { PL [] 1 setgray } def\n", /* background (assumed white) */
270 "/LTb { BL [] 0 0 0 DL } def\n", /* border */
271 "/LTa { AL [1 udl mul 2 udl mul] 0 setdash 0 0 0 setrgbcolor } def\n", /* axes */
272 "/LT0 { PL [] 1 0 0 DL } def\n",
273 "/LT1 { PL [8 dl1 5 dl1] 0 0 1 DL } def\n",
274 "/LT2 { PL [4 dl1 4 dl1] 0 1 1 DL } def\n",
275 "/LT3 { PL [8 dl1 5 dl1 0.5 dl1 5 dl1] 1 0 1 DL } def\n",
276 NULL
277 };
278
279 static const char GPFAR * GPFAR ENHPS_header[] = {
280 /* For MFshow and MFwidth the tos is an array with the string and font info:  */
281 /*      [<fontname (a string)> <fontsize> <vertical offset> <width significant?> <printed?> <overprint> <text string>]  */
282 /* EAM Mar 2004 - Add in a special case overprint 3 = save, overprint 4 = restore */
283
284 "/MFshow {\n",
285 "   { dup 5 get 3 ge\n",        /* EAM test for overprint 3 or 4 */
286 "     { 5 get 3 eq {gsave} {grestore} ifelse }\n", /* EAM */
287 "     {dup dup 0 get findfont exch 1 get scalefont setfont\n",
288 "     [ currentpoint ] exch dup 2 get 0 exch R dup 5 get 2 ne {dup dup 6\n",
289 "     get exch 4 get {show} {stringwidth pop 0 R} ifelse }if dup 5 get 0 eq\n",
290 "     {dup 3 get {2 get neg 0 exch R pop} {pop aload pop M} ifelse} {dup 5\n",
291 "     get 1 eq {dup 2 get exch dup 3 get exch 6 get stringwidth pop -2 div\n",
292 "     dup 0 R} {dup 6 get stringwidth pop -2 div 0 R 6 get\n",
293 "     show 2 index {aload pop M neg 3 -1 roll neg R pop pop} {pop pop pop\n",
294 "     pop aload pop M} ifelse }ifelse }ifelse }\n",
295 "     ifelse }\n", /* EAM */
296 "   forall} bind def\n",
297
298 /* get the width of the text */
299 /* HH 2005-07-24 - Add in a special case overprint 3 = save, 4 = restore
300  * also for estimation of string width. This is done by interposing an 
301  * additional value on the stack. between XYsave and XYrestore,
302  * this number is increased by the strings. By pop'ing this number, all
303  * strings between XYsave and XYrestore are ignored. */
304 "/MFwidth {0 exch { dup 5 get 3 ge { 5 get 3 eq { 0 } { pop } ifelse }\n",
305 " {dup 3 get{dup dup 0 get findfont exch 1 get scalefont setfont\n",
306 "     6 get stringwidth pop add} {pop} ifelse} ifelse} forall} bind def\n",
307
308 /* flush left show */
309 "/MLshow { currentpoint stroke M\n",
310 "  0 exch R\n  Blacktext {gsave 0 setgray MFshow grestore} {MFshow} ifelse } bind def\n",
311
312 /* flush right show */
313 "/MRshow { currentpoint stroke M\n",
314 "  exch dup MFwidth neg 3 -1 roll R\n  Blacktext {gsave 0 setgray MFshow grestore} {MFshow} ifelse } bind def\n",
315
316 /* centred show */
317 "/MCshow { currentpoint stroke M\n",
318 "  exch dup MFwidth -2 div 3 -1 roll R\n  Blacktext {gsave 0 setgray MFshow grestore} {MFshow} ifelse } bind def\n",
319
320 /* Save and restore for @-text (phantom box) */
321 "/XYsave    { [( ) 1 2 true false 3 ()] } bind def\n",
322 "/XYrestore { [( ) 1 2 true false 4 ()] } bind def\n",
323
324 NULL
325 };
326
327 /* external/internal prologue files machinery */
328 #if defined(GNUPLOT_PS_DIR)
329 # if defined(_Windows)
330 #  include "win/winmain.h"
331 # elif defined(OS2)
332 #  define INCL_DOSPROCESS
333 #  define INCL_DOSMODULEMGR
334 #  include <os2.h>
335 # endif /* _Windows || OS2 */
336 #else /* GNUPLOT_PS_DIR */
337 # include "PostScript/prologues.h"
338 #endif /* GNUPLOT_PS_DIR */
339
340 /* added to enhpost by Matt Heffron <heffron@falstaff.css.beckman.com> */
341 /* moved to post.trm by drd */
342
343 static struct PS_FontName {
344         char *name;
345         struct PS_FontName *next;
346 } *PS_DocFonts = NULL;
347
348 static char PS_default_font[MAX_ID_LEN+1] = {'H','e','l','v','e','t','i','c','a',',','1','4','\0'};
349
350 /* given a font, look in store to see if it is there already
351  * if so, return NULL. If not, reencode it if allowed to, otherwise
352  * return an appropriate re-encode string
353  */
354
355 TERM_PUBLIC char *
356 PS_RememberFont(char *fname, int can_reencode)
357 {
358     struct PS_FontName *fnp;
359     char *recode = NULL;
360     char *myfname = "Symbol";
361
362     if (strcmp(fname, "Symbol-Oblique") != 0)
363         myfname = fname;
364
365     for (fnp = PS_DocFonts; fnp ; fnp = fnp->next)
366         if (strcmp(fnp->name, myfname) == 0)
367             return NULL;
368
369     /* we did not find the name */
370
371     fnp = (struct PS_FontName *)gp_alloc(sizeof(struct PS_FontName),
372                                          "PostScript Font record");
373     fnp->name = gp_strdup(myfname);
374     fnp->next = PS_DocFonts;
375     PS_DocFonts = fnp;
376
377     switch(encoding) {
378     case S_ENC_ISO8859_1:
379         recode = "reencodeISO def\n";
380         break;
381     case S_ENC_ISO8859_2:
382         recode = "reencodeISO2 def\n";
383         break;
384     case S_ENC_ISO8859_15:
385         recode = "reencodeISO15 def\n";
386         break;
387     case S_ENC_CP437:
388         recode = "reencodeCP437 def\n";
389         break;
390     case S_ENC_CP850 :
391         recode = "reencodeCP850 def\n";
392         break;
393     case S_ENC_CP852 :
394         recode = "reencodeCP852 def\n";
395         break;
396     case S_ENC_KOI8_R :
397         recode = "reencodeKOI8R def\n";
398         break;
399     case S_ENC_CP1250 :
400         recode = "reencodeCP1250 def\n";
401         break;
402     case S_ENC_KOI8_U :
403         recode = "reencodeKOI8U def\n";
404         break;
405     default:
406         /* do nothing */
407         break;
408     }
409
410     if (can_reencode && recode) {
411         fprintf(gppsfile,"/%s %s", myfname, recode);
412         return NULL;
413     } else
414         return recode;
415 }
416
417 char *
418 PS_escape_string(char *origstr, char *escapelist)
419 {
420     char *newstr;
421     char *n;
422
423     if (!origstr || !*origstr)
424         return NULL;
425
426     newstr = gp_alloc(2*strlen(origstr)+1,"PS_escape_string");
427     for (n=newstr; *origstr; *n++ = *origstr++) {
428         if (strchr(escapelist,*origstr))
429             *n++ = '\\';
430     }
431     *n = '\0';
432
433     return newstr;
434 }
435
436 static int PS_pen_x, PS_pen_y;
437 static int PS_taken;
438 static int PS_linetype_last;
439 static double PS_linewidth_last; /* HBB NEW 20031219 */
440 static TBOOLEAN PS_relative_ok;
441
442 /* HBB 990914: PS_SOLID is already used by the WIN32 API headers.
443  * Renamed to PS_SOLIDE, therefore... */
444 enum PS_id {
445     PS_PORTRAIT, PS_LANDSCAPE,
446     PS_EPSF, PS_DEFAULT, PS_ENHANCED, PS_NOENHANCED,
447     PS_LATEX, EPSLATEX_STANDALONE, EPSLATEX_INPUT,
448     PS_MONOCHROME, PS_COLOR, PS_BLACKTEXT, PS_COLORTEXT,
449     PS_SOLIDE, PS_DASHED, PS_DASHLENGTH, PS_LINEWIDTH,
450     PS_SIMPLEX, PS_DUPLEX, PS_DEFAULTPLEX,
451     PS_ROUNDED, PS_NOROUNDED, PS_FONTFILE, PS_NOFONTFILES,
452     PS_PALFUNCPARAM,
453     PS_LEVEL1, PS_LEVELDEFAULT, PS_FONT,
454     PSLATEX_ROTATE, PSLATEX_NOROTATE, PSLATEX_AUXFILE, PSLATEX_NOAUXFILE,
455     PSLATEX_OLDSTYLE, PSLATEX_NEWSTYLE, EPSLATEX_HEADER, EPSLATEX_NOHEADER,
456     PS_SIZE,
457     PS_OTHER
458 };
459
460 static struct gen_table PS_opts[] =
461 {
462     { "d$efault", PS_DEFAULT },
463     { "p$ortrait", PS_PORTRAIT },
464     { "l$andscape", PS_LANDSCAPE },
465     { "ep$sf", PS_EPSF },
466     { "enh$anced", PS_ENHANCED },
467     { "noenh$anced", PS_NOENHANCED },
468     { "m$onochrome", PS_MONOCHROME },
469     { "c$olor", PS_COLOR },
470     { "c$olour", PS_COLOR },
471     { "b$lacktext", PS_BLACKTEXT },
472     { "colort$ext", PS_COLORTEXT },
473     { "colourt$ext", PS_COLORTEXT },
474     { "so$lid", PS_SOLIDE },
475     { "da$shed", PS_DASHED },
476     { "dashl$ength", PS_DASHLENGTH },
477     { "dl", PS_DASHLENGTH },
478     { "linew$idth", PS_LINEWIDTH },
479     { "lw", PS_LINEWIDTH },
480     { "size", PS_SIZE },
481     { "si$mplex", PS_SIMPLEX },
482     { "du$plex", PS_DUPLEX },
483     { "defaultp$lex", PS_DEFAULTPLEX },
484     { "butt", PS_NOROUNDED },
485     { "rou$nded", PS_ROUNDED },
486     { "fontf$ile", PS_FONTFILE },
487     { "nofontf$iles", PS_NOFONTFILES },
488     { "palf$uncparam", PS_PALFUNCPARAM },
489     { "level1", PS_LEVEL1 },
490     { "leveldefault", PS_LEVELDEFAULT },
491     { "font", PS_FONT },
492     { "stand$alone", EPSLATEX_STANDALONE },
493     { "inp$ut", EPSLATEX_INPUT },
494     { "header", EPSLATEX_HEADER },
495     { "noheader", EPSLATEX_NOHEADER },
496     { "r$otate", PSLATEX_ROTATE },
497     { "n$orotate", PSLATEX_NOROTATE },
498     { "a$uxfile", PSLATEX_AUXFILE },
499     { "noa$uxfile", PSLATEX_NOAUXFILE },
500     { "old$style", PSLATEX_OLDSTYLE },
501     { "new$style", PSLATEX_NEWSTYLE },
502     { NULL, PS_OTHER }
503 };
504
505
506 TERM_PUBLIC void
507 PS_options()
508 {
509     struct value a;
510     char *s;
511     char *ps_fontfile_char = NULL;
512     char tmp_term_options[MAX_LINE_LEN+1] = "";
513
514     TBOOLEAN set_orientation = FALSE, set_enhanced = FALSE, set_plex = FALSE;
515     TBOOLEAN set_level = FALSE, set_color = FALSE, set_dashed = FALSE;
516     TBOOLEAN set_dashlen = FALSE, set_linewidth = FALSE, set_round = FALSE;
517     TBOOLEAN set_palfunc = FALSE, set_colortext = FALSE;
518     TBOOLEAN set_standalone = FALSE, set_epslheader = FALSE;
519     TBOOLEAN set_pslrotate = FALSE, set_pslauxfile = FALSE;
520     TBOOLEAN set_psloldstyle = FALSE, set_font = FALSE, set_fontsize = FALSE;
521
522     /* Annoying hack to handle the case of 'set termoption' after */
523     /* we have already initialized the terminal.                  */
524     if (c_token != 2)
525         ps_explicit_size = FALSE;
526
527     if (strcmp(term->name, "pstex") == 0)
528         ps_params = &pstex_params;
529     else if (strcmp(term->name, "pslatex") == 0)
530         ps_params = &pslatex_params;
531     else if (strcmp(term->name, "epslatex") == 0) {
532         ps_params = &epslatex_params;
533     } else
534         ps_params = &post_params;
535
536     if (ps_params->terminal == PSTERM_POSTSCRIPT) {
537         if (pslatex_auxname)
538             free(pslatex_auxname);
539         pslatex_auxname = NULL;
540     } else {
541         term->set_font = PS_set_font;
542     }
543
544     if (!END_OF_COMMAND) {
545         if (lookup_table(&PS_opts[0],c_token) == PS_DEFAULT) {
546             switch (ps_params->terminal) {
547             case PSTERM_POSTSCRIPT:
548                 while (ps_params->first_fontfile != NULL)
549                     delete_ps_fontfile((struct ps_fontfile_def *) NULL,
550                                        ps_params->first_fontfile);
551                 *ps_params = post_params_default;
552                 break;
553             case PSTERM_EPSLATEX:
554                 *ps_params = epslatex_params_default;
555                 break;
556             case PSTERM_PSLATEX:
557                 *ps_params = pslatex_params_default;
558                 break;
559             case PSTERM_PSTEX:
560                 *ps_params = pstex_params_default;
561                 break;
562             }
563             term->flags &= ~TERM_ENHANCED_TEXT;
564             c_token++;
565             if (!END_OF_COMMAND) 
566                 int_error(c_token,
567                           "extraneous argument in set terminal %s",term->name);
568         }
569     }
570
571     while (!END_OF_COMMAND) {
572         switch(lookup_table(&PS_opts[0],c_token)) {
573         case PS_PORTRAIT:
574             if (set_orientation || ps_params->terminal != PSTERM_POSTSCRIPT)
575                 int_error(c_token,
576                           "extraneous argument in set terminal %s",term->name);
577             set_orientation = TRUE;
578             ps_params->psformat = PSTERM_PORTRAIT;
579             c_token++;
580             break;
581         case PS_LANDSCAPE:
582             if (set_orientation || ps_params->terminal != PSTERM_POSTSCRIPT)
583                 int_error(c_token,
584                           "extraneous argument in set terminal %s",term->name);
585             set_orientation = TRUE;
586             ps_params->psformat = PSTERM_LANDSCAPE;
587             c_token++;
588             break;
589         case PS_EPSF:
590             if (set_orientation || ps_params->terminal != PSTERM_POSTSCRIPT)
591                 int_error(c_token,
592                           "extraneous argument in set terminal %s",term->name);
593             set_orientation = TRUE;
594             ps_params->psformat = PSTERM_EPS;
595             c_token++;
596             break;
597         case PS_LEVEL1:
598             if (set_level)
599                 int_error(c_token,
600                           "extraneous argument in set terminal %s",term->name);
601             set_level = TRUE;
602             ps_params->level1 = TRUE;
603             c_token++;
604             break;
605         case PS_LEVELDEFAULT:
606             if (set_level)
607                 int_error(c_token,
608                           "extraneous argument in set terminal %s",term->name);
609             set_level = TRUE;
610             ps_params->level1 = FALSE;
611             c_token++;
612             break;
613         case PS_DEFAULT:
614             int_error(c_token,
615                       "extraneous argument in set terminal %s",term->name);
616             c_token++;
617             break;
618         case PS_ENHANCED:
619             if (set_enhanced || ps_params->terminal != PSTERM_POSTSCRIPT)
620                 int_error(c_token,
621                           "extraneous argument in set terminal %s",term->name);
622             set_enhanced = TRUE;
623             term->put_text = ENHPS_put_text;
624             term->set_font = ENHPS_set_font;
625             term->flags |= TERM_ENHANCED_TEXT;
626             ++c_token;
627             break;
628         case PS_NOENHANCED:
629             if (set_enhanced || ps_params->terminal != PSTERM_POSTSCRIPT)
630                 int_error(c_token,
631                           "extraneous argument in set terminal %s",term->name);
632             set_enhanced = TRUE;
633             term->put_text = PS_put_text;
634             term->set_font = PS_set_font;
635             term->flags &= ~TERM_ENHANCED_TEXT;
636             ++c_token;
637             break;
638 #ifdef PSLATEX_DRIVER
639         case EPSLATEX_STANDALONE:
640             if (set_standalone || ps_params->terminal != PSTERM_EPSLATEX)
641                 int_error(c_token,
642                           "extraneous argument in set terminal %s",term->name);
643             set_standalone = TRUE;
644             ps_params->epslatex_standalone = TRUE;
645             ++c_token;
646             break;
647         case EPSLATEX_INPUT:
648             if (set_standalone || ps_params->terminal != PSTERM_EPSLATEX)
649                 int_error(c_token,
650                           "extraneous argument in set terminal %s",term->name);
651             set_standalone = TRUE;
652             ps_params->epslatex_standalone = FALSE;
653             ++c_token;
654             break;
655
656         case EPSLATEX_HEADER:
657             if (set_epslheader || ps_params->terminal != PSTERM_EPSLATEX)
658                 int_error(c_token,
659                           "extraneous argument in set terminal %s",term->name);
660             set_epslheader = TRUE;
661             ++c_token;
662             free(epslatex_header);
663             /* Protect against int_error() bail from try_to_get_string() */
664                 epslatex_header = NULL;
665             epslatex_header = try_to_get_string();
666             if (!epslatex_header)
667                 int_error(c_token,"String containing header information expected");
668             break;
669
670         case EPSLATEX_NOHEADER:
671             if (set_epslheader || ps_params->terminal != PSTERM_EPSLATEX)
672                 int_error(c_token,
673                           "extraneous argument in set terminal %s",term->name);
674             set_epslheader = TRUE;
675             free(epslatex_header);
676             epslatex_header = NULL;
677             ++c_token;
678             break;
679
680         case PSLATEX_ROTATE:
681             if (set_pslrotate || ((ps_params->terminal != PSTERM_PSLATEX) &&
682                                   (ps_params->terminal != PSTERM_PSTEX)))
683                 int_error(c_token,
684                           "extraneous argument in set terminal %s",term->name);
685             set_pslrotate = TRUE;
686             ps_params->rotate = TRUE;
687             ++c_token;
688             break;
689         case PSLATEX_NOROTATE:
690             if (set_pslrotate || ((ps_params->terminal != PSTERM_PSLATEX) &&
691                                   (ps_params->terminal != PSTERM_PSTEX)))
692                 int_error(c_token,
693                           "extraneous argument in set terminal %s",term->name);
694             set_pslrotate = TRUE;
695             ps_params->rotate = FALSE;
696             ++c_token;
697             break;
698         case PSLATEX_AUXFILE:
699             if (set_pslauxfile ||
700                 ((ps_params->terminal == PSTERM_POSTSCRIPT) ||
701                  (ps_params->terminal == PSTERM_EPSLATEX)))
702                 int_error(c_token,
703                           "extraneous argument in set terminal %s",term->name);
704             set_pslauxfile = TRUE;
705             ps_params->useauxfile = TRUE;
706             c_token++;
707             break;
708         case PSLATEX_NOAUXFILE:
709             if (set_pslauxfile ||
710                 ((ps_params->terminal == PSTERM_POSTSCRIPT) ||
711                  (ps_params->terminal == PSTERM_EPSLATEX)))
712                 int_error(c_token,
713                           "extraneous argument in set terminal %s",term->name);
714             set_pslauxfile = TRUE;
715             ps_params->useauxfile = FALSE;
716             c_token++;
717             break;
718         case PSLATEX_OLDSTYLE:
719             if (set_psloldstyle || ps_params->terminal == PSTERM_POSTSCRIPT)
720                 int_error(c_token,
721                           "extraneous argument in set terminal %s",term->name);
722             set_psloldstyle = TRUE;
723             ps_params->oldstyle = TRUE;
724             if (ps_params->terminal == PSTERM_EPSLATEX)
725                 ps_params->rounded = TRUE;
726             c_token++;
727             break;
728         case PSLATEX_NEWSTYLE:
729             if (set_psloldstyle || ps_params->terminal == PSTERM_POSTSCRIPT)
730                 int_error(c_token,
731                           "extraneous argument in set terminal %s",term->name);
732             set_psloldstyle = TRUE;
733             ps_params->oldstyle = FALSE;
734             c_token++;
735             break;
736 #endif
737         case PS_MONOCHROME:
738             if (set_color)
739                 int_error(c_token,
740                           "extraneous argument in set terminal %s",term->name);
741             set_color = TRUE;
742             ps_params->color = FALSE;
743             c_token++;
744             break;
745         case PS_COLOR:
746             if (set_color)
747                 int_error(c_token,
748                           "extraneous argument in set terminal %s",term->name);
749             set_color = TRUE;
750             ps_params->color = TRUE;
751             c_token++;
752             break;
753         case PS_BLACKTEXT:
754             if (set_colortext || ((ps_params->terminal != PSTERM_POSTSCRIPT) &&
755                                   (ps_params->terminal != PSTERM_EPSLATEX)))
756                 int_error(c_token,
757                           "extraneous argument in set terminal %s",term->name);
758             set_colortext = TRUE;
759             ps_params->blacktext = TRUE;
760             c_token++;
761             break;
762         case PS_COLORTEXT:
763             if (set_colortext || ((ps_params->terminal != PSTERM_POSTSCRIPT) &&
764                                   (ps_params->terminal != PSTERM_EPSLATEX)))
765                 int_error(c_token,
766                           "extraneous argument in set terminal %s",term->name);
767             set_colortext = TRUE;
768             ps_params->blacktext = FALSE;
769             c_token++;
770             break;
771         case PS_SOLIDE:
772             if (set_dashed)
773                 int_error(c_token,
774                           "extraneous argument in set terminal %s",term->name);
775             set_dashed = TRUE;
776             ps_params->solid = TRUE;
777             c_token++;
778             break;
779         case PS_DASHED:
780             if (set_dashed)
781                 int_error(c_token,
782                           "extraneous argument in set terminal %s",term->name);
783             set_dashed = TRUE;
784             ps_params->solid = FALSE;
785             c_token++;
786             break;
787         case PS_DASHLENGTH:
788             if (set_dashlen)
789                 int_error(c_token,
790                           "extraneous argument in set terminal %s",term->name);
791             set_dashlen = TRUE;
792             c_token++;
793             ps_params->dash_length = real(const_express(&a));
794             if (ps_params->dash_length <= 0.0)
795                 ps_params->dash_length = 1.0;
796             break;
797         case PS_LINEWIDTH:
798             if (set_linewidth)
799                 int_error(c_token,
800                           "extraneous argument in set terminal %s",term->name);
801             set_linewidth = TRUE;
802             c_token++;
803             ps_params->linewidth_factor = real(const_express(&a));
804             if (ps_params->linewidth_factor <= 0.0)
805                 ps_params->linewidth_factor = 1.0;
806             break;
807         case PS_SIMPLEX:
808             if (set_plex || ps_params->terminal != PSTERM_POSTSCRIPT)
809                 int_error(c_token,
810                           "extraneous argument in set terminal %s",term->name);
811             set_plex = TRUE;
812             ps_params->duplex_state  = FALSE;
813             ps_params->duplex_option = TRUE;
814             c_token++;
815             break;
816         case PS_DUPLEX:
817             if (set_plex || ps_params->terminal != PSTERM_POSTSCRIPT)
818                 int_error(c_token,
819                           "extraneous argument in set terminal %s",term->name);
820             set_plex = TRUE;
821             ps_params->duplex_state  = TRUE;
822             ps_params->duplex_option = TRUE;
823             c_token++;
824             break;
825         case PS_DEFAULTPLEX:
826             if (set_plex || ps_params->terminal != PSTERM_POSTSCRIPT)
827                 int_error(c_token,
828                           "extraneous argument in set terminal %s",term->name);
829             set_plex = TRUE;
830             ps_params->duplex_option = FALSE;
831             c_token++;
832             break;
833         case PS_ROUNDED:
834             if (set_round)
835                 int_error(c_token,
836                           "extraneous argument in set terminal %s",term->name);
837             set_round = TRUE;
838             ps_params->rounded = TRUE;
839             c_token++;
840             break;
841         case PS_NOROUNDED:
842             if (set_round)
843                 int_error(c_token,
844                           "extraneous argument in set terminal %s",term->name);
845             set_round = TRUE;
846             ps_params->rounded = FALSE;
847             c_token++;
848             break;
849         case PS_FONTFILE: {
850             TBOOLEAN deleteentry = FALSE;
851             c_token++;
852             if (ps_params->terminal != PSTERM_POSTSCRIPT)
853                 int_error(c_token,
854                           "extraneous argument in set terminal %s",term->name);
855
856             if (!isstring(c_token)) {
857                 if (equals(c_token, "add"))
858                     c_token++;
859                 else if (almost_equals(c_token, "del$ete")) {
860                     deleteentry = TRUE;
861                     c_token++;
862                 } else
863                     int_error(c_token, "Font filename expected");
864             }
865             if (isstring(c_token)) {
866                 TBOOLEAN filename_doubled = FALSE;
867                 struct ps_fontfile_def *curr_ps_fontfile = 
868                     ps_params->first_fontfile;
869                 struct ps_fontfile_def *prev_ps_fontfile = NULL;
870                 struct ps_fontfile_def *new_ps_fontfile =
871                      gp_alloc(sizeof(struct ps_fontfile_def),
872                              "new_ps_fontfile");
873
874                 new_ps_fontfile->fontfile_name =
875                     gp_alloc (token_len(c_token),
876                               "new_ps_fontfile->fontfile_name");
877                 quote_str(new_ps_fontfile->fontfile_name,
878                           c_token, token_len(c_token));
879                 gp_expand_tilde(&(new_ps_fontfile->fontfile_name));
880                 if (!deleteentry) {
881 #if defined(PIPES)
882                     if (*(new_ps_fontfile->fontfile_name) != '<') {
883 #endif
884                         new_ps_fontfile->fontfile_fullname =
885                             fontpath_fullname(new_ps_fontfile->fontfile_name);
886                         if (!new_ps_fontfile->fontfile_fullname)
887                             int_error(c_token, "Font file '%s' not found",
888                                       new_ps_fontfile->fontfile_name);
889 #if defined(PIPES)
890                     } else
891                         new_ps_fontfile->fontfile_fullname = NULL;
892 #endif
893
894                 }
895                 new_ps_fontfile->next = NULL;
896
897                 if (!deleteentry) {
898                     LFS *lf=lf_head;
899                     if (lf) {
900                         while (lf->prev)
901                             lf=lf->prev;
902                     }
903                     if ((lf && lf->interactive) || interactive)
904                         /* if (interactive) { */
905                         PS_load_fontfile(new_ps_fontfile,FALSE);
906                 }
907
908                 if (ps_params->first_fontfile) {
909                     while (curr_ps_fontfile) {
910                         if (strcmp(curr_ps_fontfile->fontfile_name,
911                                    new_ps_fontfile->fontfile_name) == 0) {
912                             filename_doubled = TRUE;
913                             if (deleteentry) {
914                                 delete_ps_fontfile(prev_ps_fontfile,
915                                                    curr_ps_fontfile);
916                                 curr_ps_fontfile = NULL;
917                                 break;
918                             }
919                         }
920                         prev_ps_fontfile = curr_ps_fontfile;
921                         curr_ps_fontfile = curr_ps_fontfile->next;
922                     }
923                     if (!filename_doubled) {
924                         if (!deleteentry)
925                             prev_ps_fontfile->next = new_ps_fontfile;
926                         else
927                             int_warn(c_token,"Can't delete Font filename '%s'",
928                                      new_ps_fontfile->fontfile_name);
929                     }
930                 } else {
931                     if (!deleteentry)
932                         ps_params->first_fontfile = new_ps_fontfile;
933                     else
934                         int_warn(c_token, "Can't delete Font filename '%s'",
935                                  new_ps_fontfile->fontfile_name);
936                 }
937                 c_token++;
938             } else
939                 int_error(c_token, "Font filename expected");
940             break;
941         }
942         case PS_NOFONTFILES:
943             if (ps_params->terminal != PSTERM_POSTSCRIPT)
944                 int_error(c_token,
945                           "extraneous argument in set terminal %s",term->name);
946             while (ps_params->first_fontfile != NULL)
947                 delete_ps_fontfile((struct ps_fontfile_def *) NULL,
948                                    ps_params->first_fontfile);
949             ++c_token;
950             break;
951         case PS_PALFUNCPARAM:
952             if (set_palfunc)
953                 int_error(c_token,
954                           "extraneous argument in set terminal %s",term->name);
955             set_palfunc = TRUE;
956             ++c_token;
957             ps_params->palfunc_samples = (int)real(const_express(&a));
958             if (ps_params->palfunc_samples < 2)
959                 ps_params->palfunc_samples = 2;
960             if (!END_OF_COMMAND && equals(c_token, ",")) {
961                 ++c_token;
962                 ps_params->palfunc_deviation = fabs(real(const_express(&a)));
963                 if (ps_params->palfunc_deviation >= 1)
964                     int_error(c_token-1,"allowed deviation must be < 1");
965             }
966             break;
967         
968         case PS_SIZE:
969             {
970             float xmax_t, ymax_t;
971
972             c_token++;
973             ps_explicit_size = TRUE;
974             ps_explicit_units = parse_term_size(&xmax_t, &ymax_t, INCHES);
975
976             /* PostScript *always* works in pts, not locally defined dpi */
977             term->xmax = xmax_t * PS_SC * 72./gp_resolution;
978             term->ymax = ymax_t * PS_SC * 72./gp_resolution;
979             eps_explicit_x = 2 * term->xmax;
980             eps_explicit_y = 2 * term->ymax;
981             break;
982             }
983         
984         case PS_FONT:
985             c_token++;
986             /* Fall through to attempt to read font name */
987         case PS_OTHER:
988         default:
989             if ((s = try_to_get_string())) {
990                 if (set_font)
991                     int_error(c_token,
992                               "extraneous argument in set terminal %s",
993                               term->name);
994                 set_font = TRUE;
995                 if ((ps_params->terminal == PSTERM_POSTSCRIPT) ||
996                     (ps_params->terminal == PSTERM_EPSLATEX)) {
997                     char *comma = strrchr(s,',');
998                     if (comma && (1 == sscanf(comma+1,"%f",&ps_params->fontsize))) {
999                         set_fontsize = TRUE;
1000                         *comma = '\0';
1001                     }
1002                     if (*s)
1003                         strncpy(ps_params->font, s, sizeof(ps_params->font));
1004                     free(s);
1005                 } else
1006                     int_error(c_token-1,
1007                               "terminal %s does not allow specification %s",
1008                               term->name, "of font name");
1009             } else {
1010                 if (set_fontsize)
1011                     int_error(c_token,
1012                               "extraneous argument in set terminal %s",
1013                               term->name);
1014                 set_fontsize = TRUE;
1015                 /* We have font size specified */
1016                 ps_params->fontsize = real(const_express(&a));
1017             }
1018             break;
1019         }
1020     }
1021
1022     switch (ps_params->terminal) {
1023     case PSTERM_POSTSCRIPT:
1024         ps_fontsize = ps_params->fontsize;
1025         break;
1026     case PSTERM_EPSLATEX:
1027         ps_fontsize = 2 * ps_params->fontsize;
1028         break;
1029     case PSTERM_PSLATEX:
1030     case PSTERM_PSTEX:
1031         if (ps_params->fontsize > 0)
1032             ps_fontsize = 2 * ps_params->fontsize;
1033         else
1034             ps_fontsize = 20; /* default: 10pt */
1035         break;
1036     }
1037     term->v_char = (unsigned int)(ps_fontsize*PS_SC);
1038     if (ps_params->oldstyle)
1039         term->h_char = (unsigned int)(ps_fontsize*PS_SC*5/10);
1040     else
1041         term->h_char = (unsigned int)(ps_fontsize*PS_SC*6/10);
1042     sprintf(PS_default_font,"%s,%g",ps_params->font,ps_fontsize);
1043
1044     if (ps_params->terminal == PSTERM_POSTSCRIPT) {
1045         if (ps_params->first_fontfile) {
1046             struct ps_fontfile_def *curr_ps_fontfile =
1047                 ps_params->first_fontfile;
1048             unsigned int totlength = 0;
1049             char *running;
1050
1051             while (curr_ps_fontfile) {
1052                 totlength += strlen(curr_ps_fontfile->fontfile_name) +
1053                     strlen(" fontfile \"\"");
1054                 curr_ps_fontfile = curr_ps_fontfile->next;
1055             }
1056             curr_ps_fontfile = ps_params->first_fontfile;
1057             ps_fontfile_char = gp_alloc (totlength+1,"ps_fontfile_char");
1058             running = ps_fontfile_char;
1059             while (curr_ps_fontfile) {
1060                 sprintf(running," fontfile \"%s\"",
1061                         curr_ps_fontfile->fontfile_name);
1062                 running += strlen(running);
1063                 curr_ps_fontfile = curr_ps_fontfile->next;
1064             }
1065         }
1066     }
1067
1068     /* HBB 19990823: fixed the options string. It violated the 'save
1069      * loadable output' rule */
1070     if (ps_params->terminal == PSTERM_POSTSCRIPT)
1071         sprintf(term_options,"%s %s %s \\\n",
1072                 ps_params->psformat==PSTERM_EPS ? "eps" :
1073                 (ps_params->psformat==PSTERM_PORTRAIT ?
1074                  "portrait" : "landscape"),
1075                 term->put_text == ENHPS_put_text ? "enhanced" : "noenhanced",
1076                 ps_params->duplex_option ? (ps_params->duplex_state ?
1077                                             "duplex" : "simplex")
1078                 : "defaultplex");
1079     else if (ps_params->terminal != PSTERM_EPSLATEX)
1080         sprintf(term_options, "%s%s",
1081                 ps_params->rotate ? "rotate" : "norotate",
1082                 ps_params->useauxfile ? " auxfile" : "");
1083     else
1084         term_options[0] = '\0';
1085
1086     sprintf(tmp_term_options,"   %s %s %s \\\n\
1087    %s dashlength %.1f linewidth %.1f %s \\\n",
1088             ps_params->level1 ? "level1" : "leveldefault",
1089             ps_params->color ? "color" : "monochrome",
1090             ps_params->blacktext ? "blacktext" : "colortext",
1091             ps_params->solid ? "solid" : "dashed",
1092             ps_params->dash_length,
1093             ps_params->linewidth_factor,
1094             ps_params->rounded ? "rounded" : "butt");
1095     strcat(term_options,tmp_term_options);
1096
1097     sprintf(tmp_term_options,"   palfuncparam %d,%g \\\n   ",
1098             ps_params->palfunc_samples, ps_params->palfunc_deviation);
1099     strcat(term_options,tmp_term_options);
1100
1101 #ifdef PSLATEX_DRIVER
1102     if ((ps_params->terminal == PSTERM_PSTEX) ||
1103         (ps_params->terminal == PSTERM_PSLATEX)) {
1104         sprintf(tmp_term_options, "%s %s ",
1105                 ps_params->rotate ? "rotate" : "norotate",
1106                 ps_params->useauxfile ? "auxfile" : "noauxfile");
1107         strcat(term_options,tmp_term_options);
1108     }
1109
1110     if (ps_params->terminal == PSTERM_EPSLATEX) {
1111         sprintf(tmp_term_options, "%s ",
1112                 ps_params->epslatex_standalone ? "standalone" : "input");
1113         if (epslatex_header)
1114             sprintf(tmp_term_options, "header \"%s\" ", epslatex_header);
1115         else
1116             sprintf(tmp_term_options, "noheader ");
1117         strcat(term_options,tmp_term_options);
1118     }
1119 #endif
1120
1121     if (ps_explicit_size) {
1122         if (ps_explicit_units == CM)
1123             sprintf(tmp_term_options,"size %.2fcm, %.2fcm ",
1124                 2.54*(float)term->xmax/(72.*PS_SC), 2.54*(float)term->ymax/(72.*PS_SC));
1125         else
1126             sprintf(tmp_term_options,"size %.2fin, %.2fin ",
1127                 (float)term->xmax/(72.*PS_SC), (float)term->ymax/(72.*PS_SC));
1128         strcat(term_options,tmp_term_options);
1129     }
1130
1131     if (ps_params->terminal == PSTERM_POSTSCRIPT)
1132         sprintf(tmp_term_options,"\"%s\" %g%s ",
1133                 ps_params->font,ps_params->fontsize,
1134                 ps_fontfile_char ? ps_fontfile_char : "");
1135     else if (ps_params->terminal == PSTERM_EPSLATEX)
1136         sprintf(tmp_term_options,"\"%s\" %g ",
1137                 ps_params->font,ps_params->fontsize);
1138     else if (ps_params->fontsize)
1139         sprintf(tmp_term_options,"%g ",ps_params->fontsize);
1140     else
1141         tmp_term_options[0]='\0';
1142     if (ps_fontfile_char)
1143         free(ps_fontfile_char);
1144
1145     strcat(term_options,tmp_term_options);
1146
1147 }
1148
1149 /* store settings passed to common_init() for use in PS_graphics()
1150  * ps_params->psformat, etc are reserved for storing the term options
1151  */
1152 static TBOOLEAN ps_common_uses_fonts;
1153 static unsigned int ps_common_xoff, ps_common_yoff;
1154
1155
1156 TERM_PUBLIC void
1157 PS_load_fontfile(struct ps_fontfile_def *current_ps_fontfile, TBOOLEAN doload)
1158 {
1159     if (current_ps_fontfile) {
1160         unsigned int linesread = 0;
1161         FILE *ffont = NULL;
1162         char line[256];
1163         char ext[4];
1164         char cmd[256];
1165         char *fontname = NULL;
1166 #if defined(PIPES)
1167         char *envcmd = NULL;
1168         TBOOLEAN ispipe = FALSE;
1169 #endif
1170
1171         ext[0] = '\0';
1172         cmd[0] = '\0';
1173
1174         if (doload)
1175             fprintf(gppsfile,"%%%%BeginProcSet: %s\n",
1176                     current_ps_fontfile->fontfile_name);
1177
1178         /* get filename extension if no pipe (if pipe *ext=='\0') */
1179 #if defined(PIPES)
1180         if (*(current_ps_fontfile->fontfile_name) != '<') {
1181             /* Filename is given */
1182 #endif
1183             if (strlen(current_ps_fontfile->fontfile_name) > 3)
1184                 strcpy(ext, current_ps_fontfile->fontfile_name +
1185                        strlen(current_ps_fontfile->fontfile_name) - 3);
1186             else
1187                 strcpy(ext, current_ps_fontfile->fontfile_name);
1188
1189             /* make extension lowercase for comparison */
1190             lower_case(ext);
1191
1192             if (!current_ps_fontfile->fontfile_fullname)
1193                 int_error(NO_CARET, "Font file '%s' not found",
1194                           current_ps_fontfile->fontfile_name);
1195 #if defined(PIPES)
1196         }
1197 #endif
1198         if (strlen(ext) == 0) {
1199 #if defined(PIPES)
1200             /* Pipe is given */
1201             ispipe = TRUE;
1202             strcpy(cmd,current_ps_fontfile->fontfile_name + 1);
1203             ffont = popen(cmd, "r");
1204             if (!ffont)
1205                 int_error(NO_CARET, "Could not execute pipe '%s'",
1206                           current_ps_fontfile->fontfile_name + 1);
1207 #endif
1208         }
1209         else if (strcmp(ext,"ttf") == 0) {
1210             /* TrueType */
1211 #if defined(PIPES)
1212             ispipe = TRUE;
1213             envcmd = getenv("GNUPLOT_TTFTOPFA");
1214             if (envcmd != NULL)
1215                 sprintf(cmd,envcmd,current_ps_fontfile->fontfile_fullname);
1216             else
1217                 sprintf(cmd,"ttf2pt1 -a -e -W 0 %s -",
1218                         current_ps_fontfile->fontfile_fullname);
1219             if (strlen(cmd) == 0)
1220                 int_error(NO_CARET,
1221                           "No command for automatic font conversion ttf->pfa defined");
1222             else {
1223                 ffont = popen(cmd,"r");
1224                 if (!ffont)
1225                     int_error(NO_CARET,"Could not execute command '%s'", cmd);
1226             }
1227 #else
1228             os_error(NO_CARET,
1229                      "Automatic font conversion ttf->pfa not supported");
1230 #endif
1231         } else if (strcmp(ext,"pfb") == 0) {
1232             /* PFB */
1233 #if defined(PIPES)
1234             ispipe = TRUE;
1235             envcmd = getenv("GNUPLOT_PFBTOPFA");
1236             if (envcmd != NULL)
1237                 sprintf(cmd,envcmd,current_ps_fontfile->fontfile_fullname);
1238             else
1239                 sprintf(cmd,"pfbtops %s",
1240                         current_ps_fontfile->fontfile_fullname);
1241             if (strlen(cmd) == 0)
1242                 int_error(NO_CARET,
1243                           "No command for automatic font conversion pfb->pfa defined");
1244             else {
1245                 ffont = popen(cmd,"r");
1246                 if (!ffont)
1247                     int_error(NO_CARET,"Could not execute command '%s'", cmd);
1248             }
1249 #else
1250             os_error(NO_CARET,
1251                      "Automatic font conversion pfb->pfa not supported");
1252 #endif
1253         } else {
1254             /* PFA */
1255             if (strcmp(ext,"pfa") != 0)
1256                 int_warn(NO_CARET,
1257                          "Font file '%s' has unknown extension. Assume it is a pfa file",
1258                          current_ps_fontfile->fontfile_name);
1259             ffont = fopen(current_ps_fontfile->fontfile_fullname, "r");
1260             if (!ffont)
1261                 int_error(NO_CARET, "Font file '%s' not found",
1262                           current_ps_fontfile->fontfile_name);
1263         }
1264         /* read the file */
1265         while (fgets(line,255,ffont)) {
1266             /* test file format */
1267             if ((linesread == 0) &&
1268                  (strstr(line,"%!PS-AdobeFont") != line) &&
1269                  (strstr(line,"%!FontType1") != line)) {
1270 #if defined(PIPES)
1271                 if (ispipe)
1272                     int_warn(NO_CARET,
1273                              "Command '%s' seems not to generate PFA data",
1274                              cmd);
1275                 else
1276 #endif
1277                     int_warn(NO_CARET,
1278                              "Font file '%s' seems not to be a PFA file",
1279                              current_ps_fontfile->fontfile_name);
1280             }
1281             /* get fontname */
1282             if (strstr(line,"/FontName") == line) {
1283                 char *fnende = NULL;
1284                 fontname = gp_alloc(strlen(line)-9,"load_fontfiles");
1285                 strcpy(fontname,strstr(line+1,"/")+1);
1286                 fnende = strstr(fontname," ");
1287                 *fnende = '\0';
1288                 /* Print font name */
1289                 if (!doload) {
1290                     if (current_ps_fontfile->fontfile_fullname)
1291                         fprintf(stderr,
1292                                 "Font file '%s' contains the font '%s'. Location:\n   %s\n",
1293                                 current_ps_fontfile->fontfile_name,
1294                                 fontname,
1295                                 current_ps_fontfile->fontfile_fullname);
1296                     else
1297                         fprintf(stderr,
1298                                 "Pipe '%s' contains the font '%s'.\n",
1299                                 current_ps_fontfile->fontfile_name,
1300                                 fontname);
1301 #if defined(PIPES)
1302                     /* Stop reading font file in order to save time */
1303                     /* This does not work for pipes because they give the */
1304                     /* error message 'broken pipe' */
1305                     if (!ispipe)
1306 #endif
1307                         break;
1308                 }
1309             }
1310
1311             if (doload)
1312                 fputs(line, gppsfile);
1313
1314             ++linesread;
1315         }
1316 #if defined(PIPES)
1317         if (ispipe) {
1318             int exitcode;
1319             if ((exitcode = pclose(ffont)) != 0)
1320                 int_error(NO_CARET,
1321                           "Command '%s' generated error, exitcode is %d",
1322                           cmd, exitcode);
1323         }
1324         else
1325 #endif
1326             fclose(ffont);
1327
1328         if (linesread == 0) {
1329 #if defined(PIPES)
1330             if (ispipe)
1331                 int_error(NO_CARET,
1332                           "Command '%s' generates empty output",
1333                           cmd);
1334             else
1335 #endif
1336                 int_error(NO_CARET, "Font file '%s' is empty",
1337                           current_ps_fontfile->fontfile_name);
1338         }
1339         if (doload)
1340             fputs("%%EndProcSet\n", gppsfile);
1341
1342         /* Computer Modern Symbol font with corrected baseline if the
1343          * font CMEX10 is embedded */
1344         if (doload && fontname && (strcmp(fontname,"CMEX10") == 0)) {
1345             fputs("%%BeginProcSet: CMEX10-Baseline\n", gppsfile);
1346             fputs("/CMEX10-Baseline /CMEX10 findfont [1 0 0 1 0 1] makefont\n",
1347                   gppsfile);
1348             fputs("dup length dict begin {1 index /FID eq {pop pop} {def} ifelse} forall\n", gppsfile);
1349             fputs("currentdict end definefont pop\n", gppsfile);
1350             fputs("%%EndProcSet\n",gppsfile);
1351         }
1352
1353         if (fontname) {
1354             free(fontname);
1355             fontname = NULL;
1356         }
1357     }
1358 }
1359
1360
1361 TERM_PUBLIC void
1362 PS_load_fontfiles(TBOOLEAN doload)
1363 {
1364     struct ps_fontfile_def *current_ps_fontfile=ps_params->first_fontfile;
1365
1366     while (current_ps_fontfile) {
1367         PS_load_fontfile(current_ps_fontfile,doload);
1368         current_ps_fontfile = current_ps_fontfile->next;
1369     }
1370 }
1371
1372
1373 TERM_PUBLIC void
1374 PS_common_init(
1375     TBOOLEAN uses_fonts,                /* FALSE for (e)ps(la)tex */
1376     unsigned int xoff, unsigned int yoff, /* how much to translate by */
1377     unsigned int bb_xmin, unsigned int bb_ymin,
1378     unsigned int bb_xmax, unsigned int bb_ymax, /* bounding box */
1379     const char **dict) /* extra entries for the dictionary */
1380 {
1381     static const char GPFAR psi1[] = "\
1382 %%%%Creator: gnuplot %s patchlevel %s\n\
1383 %%%%CreationDate: %s\n\
1384 %%%%DocumentFonts: %s\n";
1385
1386     static const char GPFAR psi2[] = "\
1387 %%%%EndComments\n\
1388 %%%%BeginProlog\n\
1389 /gnudict 256 dict def\ngnudict begin\n\
1390 %%\n\
1391 %% The following 6 true/false flags may be edited by hand if required\n\
1392 %% The unit line width may also be changed\n\
1393 %%\n\
1394 /Color %s def\n\
1395 /Blacktext %s def\n\
1396 /Solid %s def\n\
1397 /Dashlength %g def\n\
1398 /Landscape %s def\n\
1399 /Level1 %s def\n\
1400 /Rounded %s def\n\
1401 /TransparentPatterns false def\n\
1402 /gnulinewidth %.3f def\n\
1403 /userlinewidth gnulinewidth def\n\
1404 %%\n\
1405 /vshift %d def\n\
1406 /dl1 {\n\
1407   %.1f Dashlength mul mul\n\
1408   Rounded { currentlinewidth 0.75 mul sub dup 0 le { pop 0.01 } if } if\n\
1409 } def\n\
1410 /dl2 {\n\
1411   %.1f Dashlength mul mul\n\
1412   Rounded { currentlinewidth 0.75 mul add } if\n\
1413 } def\n\
1414 /hpt_ %.1f def\n\
1415 /vpt_ %.1f def\n\
1416 /hpt hpt_ def\n\
1417 /vpt vpt_ def\n";
1418
1419     static const char GPFAR psi3[] = "\
1420 Level1 {} {\n\
1421 /SDict 10 dict def\n\
1422 systemdict /pdfmark known not {\n\
1423   userdict /pdfmark systemdict /cleartomark get put\n\
1424 } if\n\
1425 SDict begin [\n\
1426   /Title (%s)\n\
1427   /Subject (gnuplot plot)\n\
1428   /Creator (gnuplot %s patchlevel %s)\n\
1429   /Author (%s)\n\
1430 %%  /Producer (gnuplot)\n\
1431 %%  /Keywords ()\n\
1432   /CreationDate (%s)\n\
1433   /DOCINFO pdfmark\n\
1434 end\n\
1435 } ifelse\n";
1436
1437
1438     struct termentry *t = term;
1439     int i;
1440     time_t now;
1441     char *timedate;
1442
1443     ps_common_uses_fonts = uses_fonts;
1444     ps_common_xoff = xoff;
1445     ps_common_yoff = yoff;
1446
1447     ps_page = 0;
1448
1449     time(&now);
1450     timedate=asctime(localtime(&now));
1451     timedate[strlen(timedate)-1]='\0';
1452
1453 #ifdef PSLATEX_DRIVER
1454     /* Set files for (e)ps(la)tex terminals */
1455     switch (ps_params->terminal) {
1456     case PSTERM_EPSLATEX:
1457         EPSLATEX_common_init();
1458         break;
1459     case PSTERM_PSLATEX:
1460     case PSTERM_PSTEX:
1461         PSTEX_common_init();
1462         break;
1463     default:; /* do nothing, just avoid a compiler warning */
1464     }
1465 #endif
1466
1467     if (ps_params->psformat == PSTERM_EPS)
1468         fputs("%!PS-Adobe-2.0 EPSF-2.0\n", gppsfile);
1469     else
1470         fputs("%!PS-Adobe-2.0\n", gppsfile);
1471
1472     if (outstr)
1473         fprintf(gppsfile, "%%%%Title: %s\n", outstr);   /*  JFi  */
1474     fprintf(gppsfile, psi1, gnuplot_version, gnuplot_patchlevel,
1475             timedate, uses_fonts ? "(atend)" : "");
1476
1477     fprintf(gppsfile,"%%%%BoundingBox: %d %d %d %d\n",
1478             xoff + bb_xmin, yoff + bb_ymin, xoff + bb_xmax, yoff + bb_ymax);
1479
1480     if ((ps_params->terminal == PSTERM_POSTSCRIPT) &&
1481         (ps_params->psformat != PSTERM_EPS))
1482         fprintf(gppsfile,"%%%%Orientation: %s\n",
1483                 ps_params->psformat == PSTERM_LANDSCAPE ?
1484                 "Landscape" : "Portrait");
1485
1486     if (ps_params->psformat != PSTERM_EPS)
1487         fputs("%%Pages: (atend)\n", gppsfile);
1488     fprintf(gppsfile, psi2,
1489             ps_params->color ? "true" : "false",
1490             ps_params->blacktext ? "true" : "false",
1491             ps_params->solid ? "true" : "false",
1492             ps_params->dash_length,     /* dash length */
1493             ps_params->psformat == PSTERM_LANDSCAPE ? "true" : "false",
1494             ps_params->level1 ? "true" : "false",
1495             ps_params->rounded ? "true" : "false",
1496             PS_LW*ps_params->linewidth_factor,  /* line width */
1497             (int)(t->v_char)/(-3),      /* shift for vertical centring */
1498             PS_SC*1.0,  /* dash length */
1499             PS_SC*1.0,  /* dash length */
1500             PS_HTIC/2.0,                /* half point width */
1501             PS_VTIC/2.0);               /* half point height */
1502
1503     /* HH: print pdf information interpreted by ghostscript/acrobat */
1504     {
1505         char *username=getusername();
1506         char *username2=PS_escape_string(username,"()\\");
1507         char *outstr2=PS_escape_string(outstr,"()\\");
1508         fprintf(gppsfile, psi3,
1509                 outstr2?outstr2:"",
1510                 gnuplot_version, gnuplot_patchlevel,
1511                 username2?username2:"", 
1512                 timedate);
1513         if (username)
1514             free(username);
1515         if (username2)
1516             free(username2);
1517         if (outstr2)
1518             free(outstr2);
1519     }
1520
1521     /* insert font encoding vector */
1522     if (uses_fonts) {
1523         switch (encoding) {
1524             case S_ENC_ISO8859_1:   PS_dump_prologue_file("8859-1.ps"); break;
1525             case S_ENC_ISO8859_2:   PS_dump_prologue_file("8859-2.ps"); break;
1526             case S_ENC_ISO8859_15:  PS_dump_prologue_file("8859-15.ps"); break;
1527             case S_ENC_CP437:       PS_dump_prologue_file("cp437.ps"); break;
1528             case S_ENC_CP850:       PS_dump_prologue_file("cp850.ps"); break;
1529             case S_ENC_CP852:       PS_dump_prologue_file("cp852.ps"); break;
1530             case S_ENC_CP1250:      PS_dump_prologue_file("cp1250.ps"); break;
1531             case S_ENC_KOI8_R:      PS_dump_prologue_file("koi8r.ps"); break;
1532             case S_ENC_KOI8_U:      PS_dump_prologue_file("koi8u.ps"); break;
1533             case S_ENC_DEFAULT:
1534             default:                break;
1535         }
1536     }
1537
1538     /* Dump the body of the prologue */
1539     PS_dump_prologue_file("prologue.ps");
1540
1541     /* Redefine old epslatex linetypes if requested */
1542     if ((ps_params->terminal == PSTERM_EPSLATEX) && ps_params->oldstyle) {
1543         for (i = 0; OldEPSL_linetypes[i] != NULL; i++)
1544             fprintf(gppsfile,"%s",OldEPSL_linetypes[i]);
1545     }
1546
1547     if (ps_params->duplex_option)
1548         fprintf(gppsfile, "statusdict begin %s setduplexmode end\n",
1549                 ps_params->duplex_state ? "true" : "false");
1550
1551     if (dict)
1552         while (*dict)
1553             fputs(*(dict++), gppsfile);
1554
1555     if (uses_fonts) {
1556         PS_load_fontfiles(TRUE);
1557         PS_RememberFont(ps_params->font, 1);
1558     }
1559
1560     fputs("end\n%%EndProlog\n", gppsfile);
1561 }
1562
1563 /* the init fn for the postscript driver */
1564 TERM_PUBLIC void
1565 PS_init()
1566 {
1567     unsigned int xmin_t = 0, ymin_t = 0, xmax_t = 0, ymax_t = 0;
1568
1569     switch (ps_params->psformat) {
1570     case PSTERM_EPS:
1571         if (ps_explicit_size) {
1572             term->xmax = eps_explicit_x;
1573             term->ymax = eps_explicit_y;
1574         } else {
1575             term->xmax = PS_XMAX;
1576             if (ps_params->oldstyle)
1577                 term->ymax = PS_YMAX_OLDSTYLE;
1578             else
1579                 term->ymax = PS_YMAX;
1580         }
1581         xmin_t = term->xmax * xoffset / (2*PS_SC);
1582         xmax_t = term->xmax * (xsize + xoffset) / (2*PS_SC);
1583         ymin_t = term->ymax * yoffset / (2*PS_SC);
1584         ymax_t = term->ymax * (ysize + yoffset) / (2*PS_SC);
1585         break;
1586     case PSTERM_PORTRAIT:
1587         if (!ps_explicit_size) {
1588             term->xmax = PS_YMAX;
1589             term->ymax = PS_XMAX;
1590         }
1591         xmin_t = term->xmax * xoffset / PS_SC;
1592         xmax_t = term->xmax * (xsize + xoffset) / PS_SC;
1593         ymin_t = term->ymax * yoffset / PS_SC;
1594         ymax_t = term->ymax * (ysize + yoffset) / PS_SC;
1595         break;
1596     case PSTERM_LANDSCAPE:
1597         if (!ps_explicit_size) {
1598             term->xmax = PS_XMAX;
1599             term->ymax = PS_YMAX;
1600         }
1601         ymin_t = term->xmax * xoffset / PS_SC;
1602         ymax_t = term->xmax * (xsize+xoffset) / PS_SC;
1603         xmin_t = term->ymax * (1-ysize-yoffset) / PS_SC;
1604         xmax_t = term->ymax * (1-yoffset) / PS_SC;
1605         break;
1606     default:
1607         int_error(NO_CARET, "invalid postscript format used");
1608     }
1609
1610     /* for enhanced postscript, copy ps_params->font to ps_enh_font
1611      * does no harm for non-enhanced
1612      */
1613     strcpy(ps_enh_font, ps_params->font);
1614     ps_enh_fontsize = ps_fontsize;
1615
1616     switch (ps_params->terminal) {
1617     case PSTERM_POSTSCRIPT:
1618         gppsfile = gpoutfile;
1619         break;
1620     default:
1621 #ifdef PSLATEX_DRIVER
1622         PSTEX_reopen_output();
1623         break;
1624     case PSTERM_EPSLATEX:
1625         EPSLATEX_reopen_output();
1626 #endif
1627         break;
1628     }
1629
1630     PS_common_init(ps_params->terminal == PSTERM_POSTSCRIPT,
1631                    ps_params->xoff, ps_params->yoff,
1632                    xmin_t, ymin_t, xmax_t, ymax_t,
1633                    (term->put_text == ENHPS_put_text) ? ENHPS_header : NULL);
1634     
1635     /* Keep track of whether we have written the enhanced text dictionary yet */
1636     ENHPS_initialized = (term->put_text == ENHPS_put_text) ? 2 : 1;
1637 }
1638
1639
1640 TERM_PUBLIC void
1641 PS_graphics()
1642 {
1643     static char GPFAR psg1[] = "0 setgray\nnewpath\n";
1644     struct termentry *t = term;
1645     ps_page++;
1646     if (ps_params->psformat != PSTERM_EPS)
1647         fprintf(gppsfile,"%%%%Page: %d %d\n",ps_page,ps_page);
1648
1649     /* If we are about to use enhanced text mode for the first time in a plot that */
1650     /* was initialized previously without it, we need to write out the macros now */
1651     if (term->put_text == ENHPS_put_text && ENHPS_initialized == 1) {
1652         const char **dict = ENHPS_header;
1653         while (*dict)
1654             fputs(*(dict++), gppsfile);
1655         fprintf(stderr,"Writing out PostScript macros for enhanced text mode\n");
1656         ENHPS_initialized = 2;
1657     }
1658
1659     fprintf(gppsfile,"\
1660 gnudict begin\ngsave\n\
1661 %d %d translate\n\
1662 %.3f %.3f scale\n",
1663             ps_common_xoff, ps_common_yoff,
1664             (ps_params->psformat == PSTERM_EPS ? 0.5 : 1.0)/PS_SC,
1665             (ps_params->psformat == PSTERM_EPS ? 0.5 : 1.0)/PS_SC);
1666     if (ps_params->psformat == PSTERM_LANDSCAPE)
1667         fprintf(gppsfile,"90 rotate\n0 %d translate\n", -(int)(term->ymax));
1668     fprintf(gppsfile, psg1);
1669     if (ps_common_uses_fonts)
1670         fprintf(gppsfile, "(%s) findfont %d scalefont setfont\n",
1671                 ps_params->font, (t->v_char));
1672     ps_path_count = 0;
1673     PS_relative_ok = FALSE;
1674     PS_pen_x = PS_pen_y = -4000;
1675     PS_taken = 0;
1676     PS_linewidth_last = PS_linetype_last =  LT_UNDEFINED;
1677 }
1678
1679
1680 TERM_PUBLIC void
1681 PS_text()
1682 {
1683     ps_path_count = 0;
1684     fputs("stroke\ngrestore\nend\nshowpage\n", gppsfile);
1685     /* fprintf(stderr,"taken %d times\n",PS_taken); */
1686     /* informational:  tells how many times it was "cheaper"
1687      * to do a relative moveto or lineto rather than an
1688      * absolute one */
1689 }
1690
1691
1692 TERM_PUBLIC void
1693 PS_reset()
1694 {
1695     fputs("%%Trailer\n", gppsfile);
1696
1697     /* I think the following commands should be executed
1698        `if (ps_common_uses_fonts)`. So I changed the next line.
1699        Please see "PS_RememberFont", too.                       */  /* JFi */
1700
1701     /*  if (!ps_common_uses_fonts) {  */                             /* JFi */
1702     if (ps_common_uses_fonts) {
1703         fputs("%%DocumentFonts: ", gppsfile);
1704         while (PS_DocFonts) {
1705             struct PS_FontName *fnp;
1706             fnp = PS_DocFonts->next;
1707             fprintf(gppsfile, "%s%s", PS_DocFonts->name, fnp ? " " : "\n");
1708             free(PS_DocFonts->name);
1709             free(PS_DocFonts);
1710             PS_DocFonts = fnp;
1711         }
1712     }
1713     if (ps_params->psformat != PSTERM_EPS)
1714         fprintf(gppsfile,"%%%%Pages: %d\n",ps_page);
1715 }
1716
1717 TERM_PUBLIC void
1718 PS_linetype(int linetype)
1719 {
1720     if ((ps_params->terminal == PSTERM_EPSLATEX) && ps_params->oldstyle)
1721         linetype = (linetype % 4) + 3;
1722     else
1723         linetype = (linetype % 9) + 3;
1724     if (linetype < 0)   /* LT_NODRAW, LT_BACKGROUND, LT_UNDEFINED */
1725         linetype = 0;
1726
1727     if (PS_linetype_last == linetype) return;
1728
1729     PS_relative_ok = FALSE;
1730     PS_FLUSH_PATH;
1731
1732     PS_linetype_last = linetype;
1733     fprintf(gppsfile, "LT%c\n", "wba012345678"[linetype]);
1734     ps_path_count = 0;
1735 }
1736
1737
1738 TERM_PUBLIC void
1739 PS_linewidth (double linewidth)
1740 {
1741     /* HBB NEW 20031219: don't do anything if nothing changed */
1742     if (ps_path_count != 0 && PS_linewidth_last == linewidth)
1743         return;
1744     PS_linewidth_last = linewidth;
1745     PS_linetype_last = -1;      /* disable cache for next linetype change */
1746
1747     PS_FLUSH_PATH;
1748     fprintf(gppsfile, "%.3f UL\n", linewidth);
1749
1750     /*
1751         Documentation of the 'change linewidth' strategy of the postscript terminal:
1752
1753         1. define a new postscript variable with a default value:
1754         /userlinewidth gnulinewidth def
1755
1756         2. define a new postscript command to change the contents of that variable:
1757         /UL { gnulinewidth mul /userlinewidth exch def } def
1758         usage:  multiplication_factor UL
1759
1760         3. modify the already known postscript command /PL for the plot lines:
1761         /PL { stroke userlinewidth setlinewidth } def
1762
1763         4. issue the new command before every change of the plot linestyle:
1764         example:
1765         4.0 UL
1766         LT0
1767         result:
1768         Linetype 0 is drawn four times as thick as defined by the contents
1769         of the postscript variable 'gnulinewidth'.
1770     */
1771 }
1772
1773
1774 TERM_PUBLIC void
1775 PS_pointsize (double ptsize)
1776 {
1777     fprintf(gppsfile, "%.3f UP\n", ptsize);
1778
1779 /*
1780  *  Documentation of the 'change pointsize' strategy of the postscript
1781  * terminal:
1782  *
1783  * 1. define two new postscript variables to hold the overall pointsize:
1784  *    /hpt_  and  /vpt_
1785  *
1786  * 2. define a new postscript command to use the contents of these variables:
1787  *    /UP { cf. definition above } def
1788  *    usage:  multiplication_factor UP
1789  *
1790  * [3.] [doesn't exist, skip to next number]
1791  *
1792  * 4. issue the new command whereever you change the symbols (and linetype):
1793  *    example:
1794  *        2.5 UP
1795  *        4.0 UL  % optionally change linewidth, too
1796  *        LT0
1797  *    result:
1798  *        Next symbols will be drawn 2.5 times as big as defined by the
1799  *        GNUPLOT `set pointsize` command (= overall pointsize).
1800  */
1801 }
1802
1803
1804 TERM_PUBLIC void
1805 PS_move(unsigned int x, unsigned int y)
1806 {
1807     /* Make this semi-dynamic and independent of architecture */
1808     char abso[5+2*INT_STR_LEN], rel[5+2*INT_STR_LEN];
1809     int dx = x - PS_pen_x;
1810     int dy = y - PS_pen_y;
1811
1812     /* can't cancel all null moves--need a move after stroke'ing */
1813     if (dx==0 && dy==0 && PS_relative_ok)
1814         return;
1815
1816     sprintf(abso, "%d %d M\n", x, y);
1817     sprintf(rel, "%d %d R\n", dx, dy);
1818
1819     if (PS_newpath) {
1820         fprintf(gppsfile, "%d %d N\n", x, y);
1821         PS_newpath = FALSE;
1822     } else
1823     if (strlen(rel) < strlen(abso) && PS_relative_ok) {
1824         fputs(rel, gppsfile);
1825         PS_taken++;
1826     } else
1827         fputs(abso, gppsfile);
1828     PS_relative_ok = TRUE;
1829     ps_path_count += 1;
1830
1831     PS_pen_x = x;
1832     PS_pen_y = y;
1833 }
1834
1835 TERM_PUBLIC void
1836 PS_vector(unsigned int x, unsigned int y)
1837 {
1838     char abso[5+2*INT_STR_LEN], rel[5+2*INT_STR_LEN];
1839     int dx = x - PS_pen_x;
1840     int dy = y - PS_pen_y;
1841
1842     if (dx==0 && dy==0)
1843         return;
1844
1845     sprintf(abso, "%d %d L\n", x, y);
1846     sprintf(rel, "%d %d V\n", dx, dy);
1847
1848     /* The following PS_move() is executed only when the limit of ps_path_count
1849      * has been reached below: then PS_FLUSH_PATH has been called which has not
1850      * moved to currentpoint after the stroke. */
1851     if (!PS_relative_ok)
1852         PS_move(PS_pen_x, PS_pen_y);
1853
1854     if (strlen(rel) < strlen(abso)) {
1855         fputs(rel, gppsfile);
1856         PS_taken++;             /* only used for debug info */
1857         ps_path_count += 1;
1858     } else {
1859         fputs(abso, gppsfile);
1860         ps_path_count = 1;  /* If we set it to zero, it may never get flushed */
1861     }
1862     /* Ghostscript has a "pile-up of rounding errors" bug: a sequence of many
1863      * rmove's or rlineto's does not yield the same line as move's or lineto's.
1864      * Therefore, we periodically force an update of the absolute position.
1865      * There was a case when 400 rlineto's were too much, so let's go a little
1866      * bit higher than the default function sampling rate in gnuplot.
1867      * This runs into a second ghostscript bug, that mixing relative and absolute
1868      * lineto with no intervening 'stroke' is ridiculously slow to render.
1869      * So we stroke the partial line, update the position in absolute terms,
1870      * then continue.  This whole section can go away if ghostscript/gv is fixed.
1871      */
1872 #define MAX_REL_PATHLEN 105
1873     if (ps_path_count >= MAX_REL_PATHLEN) {
1874         fprintf(gppsfile, "stroke %d %d M\n", x, y);
1875         ps_path_count = 1;
1876     }
1877
1878     PS_relative_ok = TRUE;
1879     PS_pen_x = x;
1880     PS_pen_y = y;
1881 }
1882
1883
1884 TERM_PUBLIC void
1885 PS_put_text(unsigned int x, unsigned int y, const char *str)
1886 {
1887     char ch;
1888
1889     if (!str && !strlen(str))
1890         return;
1891     PS_move(x,y);
1892     if (ps_ang != 0)
1893         fprintf(gppsfile,"currentpoint gsave translate %d rotate 0 0 M\n",
1894                 ps_ang);
1895     putc('(',gppsfile);
1896     ch = *str++;
1897     while(ch!='\0') {
1898         if ((ch=='(') || (ch==')') || (ch=='\\'))
1899             putc('\\', gppsfile);
1900         putc(ch, gppsfile);
1901         ch = *str++;
1902     }
1903
1904     switch(ps_justify) {
1905     case LEFT :
1906         fputs(") Lshow\n", gppsfile);
1907         break;
1908     case CENTRE :
1909         fputs(") Cshow\n", gppsfile);
1910         break;
1911     case RIGHT :
1912         fputs(") Rshow\n", gppsfile);
1913         break;
1914     }
1915     if (ps_ang != 0)
1916         fputs("grestore\n", gppsfile);
1917     ps_path_count = 0;
1918     PS_relative_ok = FALSE;
1919 }
1920
1921
1922 TERM_PUBLIC int
1923 PS_text_angle(int ang)
1924 {
1925     ps_ang = ang;
1926     return TRUE;
1927 }
1928
1929
1930 TERM_PUBLIC int
1931 PS_justify_text(enum JUSTIFY mode)
1932 {
1933     ps_justify = mode;
1934     return TRUE;
1935 }
1936
1937
1938 TERM_PUBLIC int
1939 PS_set_font(const char *font)
1940 {
1941     char *name;
1942     unsigned int  i;
1943     float size;
1944     size_t sep;
1945
1946     if (!font || !(*font))
1947         font = PS_default_font;
1948     sep = strcspn(font,",");
1949     name = gp_strdup(font);
1950     name[sep] = NUL;
1951     for (i=0; i<sep; i++)
1952         if (name[i] == ' ') name[i] = '-';
1953     size = ps_fontsize;
1954     if (font[sep] == ',')
1955         sscanf (&(font[sep+1]),"%f",&size);
1956
1957     /* If TeX is doing the font handling, we don't need to */
1958     /* write anything into the postscript stream */
1959     if (ps_params->terminal == PSTERM_POSTSCRIPT) {
1960         PS_RememberFont(name,1);
1961         fprintf(gppsfile, "/%s findfont %g scalefont setfont\n",
1962                 name, size*PS_SC);
1963     }
1964     free(name);
1965
1966     term->v_char = (unsigned int)(size*PS_SC);
1967     term->h_char = (unsigned int)(size*PS_SC*6/10);
1968     return TRUE;
1969 }
1970
1971
1972 /* postscript point routines */
1973
1974
1975 TERM_PUBLIC void
1976 PS_point(unsigned int x, unsigned int y, int number)
1977 {
1978     static const char GPFAR * GPFAR pointFNS[] = {
1979         "Pnt",  "Pls",   "Crs",    "Star",
1980         "Box",  "BoxF",  "Circle", "CircleF",
1981         "TriU", "TriUF", "TriD",   "TriDF",
1982         "Dia",  "DiaF",  "Pent",   "PentF",
1983         "C0",   "C1",    "C2",     "C3",
1984         "C4",   "C5",    "C6",     "C7",
1985         "C8",   "C9",    "C10",    "C11",
1986         "C12",  "C13",   "C14",    "C15",
1987         "S0",   "S1",    "S2",     "S3",
1988         "S4",   "S5",    "S6",     "S7",
1989         "S8",   "S9",    "S10",    "S11",
1990         "S12",  "S13",   "S14",    "S15",
1991         "D0",   "D1",    "D2",     "D3",
1992         "D4",   "D5",    "D6",     "D7",
1993         "D8",   "D9",    "D10",    "D11",
1994         "D12",  "D13",   "D14",    "D15",
1995         "BoxE", "CircE", "TriUE",  "TriDE",
1996         "DiaE", "PentE", "BoxW",   "CircW",
1997         "TriUW","TriDW", "DiaW",   "PentW"
1998     };
1999     static const char GPFAR * GPFAR pointFNS_OldEPSL[] = {
2000         "Pnt",  "Dia",   "Circle", "Pls",
2001         "Crs",  "Box",   "DiaF",   "CircleF",
2002         "BoxF"
2003     };
2004     if ((ps_params->terminal == PSTERM_EPSLATEX) && ps_params->oldstyle) {
2005         if (number < 0)
2006             number = -1;                /* negative types are all 'dot' */
2007         else
2008             number %= sizeof(pointFNS_OldEPSL)/sizeof(pointFNS_OldEPSL[0]) -1;
2009         fprintf(gppsfile, "%d %d %s\n", x, y, pointFNS_OldEPSL[number+1]);
2010     } else {
2011         if (number < 0)
2012             number = -1;                /* negative types are all 'dot' */
2013         else
2014             number %= sizeof(pointFNS)/sizeof(pointFNS[0]) -1;
2015         fprintf(gppsfile, "%d %d %s\n", x, y, pointFNS[number+1]);
2016     }
2017
2018     PS_relative_ok = FALSE;
2019     ps_path_count = 0;
2020     PS_linewidth_last = PS_linetype_last =  -1; /* force next linetype change */
2021 }
2022
2023 TERM_PUBLIC void
2024 PS_fillbox(
2025     int style,
2026     unsigned int x1, unsigned int y1,
2027     unsigned int width, unsigned int height)
2028 {
2029     double filldens;
2030     int pattern;
2031
2032     PS_FLUSH_PATH;
2033
2034     switch(style & 0xf) {
2035
2036     case FS_SOLID:
2037         /* style == 1 --> fill with intensity according to filldensity */
2038         filldens = (style >> 4) / 100.0;
2039         if(filldens < 0.0)
2040             filldens = 0.0;
2041         if(filldens > 1.0)
2042             filldens = 1.0;
2043         fprintf(gppsfile, "%.3f %d %d %d %d BoxColFill\n",
2044                 filldens, x1,y1, width,height);
2045         break;
2046
2047     case FS_PATTERN:
2048         /* style == 2 --> fill with pattern according to fillpattern */
2049         /* the upper 3 nibbles of 'style' contain pattern number */
2050         pattern = (style >> 4) % 8;
2051         switch (pattern) {
2052
2053         default:
2054         case 0:
2055                 fprintf(gppsfile, "%d %d %d %d BoxFill\n",
2056                         x1, y1, width, height);
2057                 break;
2058         case 1:
2059                 fprintf(gppsfile, "%d %d %d %d %d %d 1 PatternFill\n",
2060                         x1, y1, width, height, 80, -45);
2061                 break;
2062         case 2:
2063                 fprintf(gppsfile, "%d %d %d %d %d %d 2 PatternFill\n",
2064                         x1, y1, width, height, 40,  45);
2065                 break;
2066         case 3:
2067                 fprintf(gppsfile, "1 %d %d %d %d BoxColFill\n",
2068                         x1, y1, width, height);
2069                 break;
2070         case 4:
2071                 fprintf(gppsfile, "%d %d %d %d %d %d 0 PatternFill\n",
2072                         x1, y1, width, height, 80,  45);
2073                 break;
2074         case 5:
2075                 fprintf(gppsfile, "%d %d %d %d %d %d 0 PatternFill\n",
2076                         x1, y1, width, height, 80, -45);
2077                 break;
2078         case 6:
2079                 fprintf(gppsfile, "%d %d %d %d %d %d 0 PatternFill\n",
2080                         x1, y1, width, height, 40,  30);
2081                 break;
2082         case 7:
2083                 fprintf(gppsfile, "%d %d %d %d %d %d 0 PatternFill\n",
2084                         x1, y1, width, height, 40, -30);
2085                 break;
2086         }
2087         break; /* end of pattern filling part */
2088
2089     default: /* style == 0 or unknown --> fill with background color */
2090         fprintf(gppsfile, "%d %d %d %d BoxFill\n", x1, y1, width, height);
2091     }
2092
2093     PS_relative_ok = FALSE;
2094     PS_linewidth_last = PS_linetype_last =  -1;
2095 }
2096
2097
2098 /* ENHPOST */
2099
2100 static TBOOLEAN ENHps_opened_string;  /* try to cut out empty ()'s */
2101
2102 /*
2103  * close a postscript string if it has been opened
2104  */
2105 TERM_PUBLIC void
2106 ENHPS_FLUSH()
2107 {
2108     if (ENHps_opened_string) {
2109         fputs(")]\n", gppsfile);
2110         ENHps_opened_string = FALSE;
2111     }
2112 }
2113
2114 /*
2115  * open a postscript string
2116  */
2117 TERM_PUBLIC void
2118 ENHPS_OPEN(
2119     char *fontname,
2120     double fontsize, double base,
2121     TBOOLEAN widthflag, TBOOLEAN showflag,
2122     int overprint)
2123 {
2124     /* overprint 3 means save current position; 4 means restore saved position */
2125     /* EAM FIXME - I couldn't figure out how to use less than the 7 parameters */
2126     /* that the normal case macro wants. Somebody more familiar with PostScript*/
2127     /* than I am please clean it up!                                           */
2128     if (overprint == 3) {
2129         fputs("XYsave\n", gppsfile);
2130         return;
2131     } else if (overprint == 4) {
2132         fputs("XYrestore\n", gppsfile);
2133         return;
2134     }
2135
2136         if (!ENHps_opened_string) {
2137             fprintf(gppsfile, "[(%s) %.1f %.1f %s %s %d (",
2138                     fontname, fontsize, base,
2139                     widthflag ? "true" : "false",
2140                     showflag ? "true" : "false",
2141                     overprint);
2142             ENHps_opened_string = TRUE;
2143         }
2144 }
2145
2146 /*
2147  * write one or more characters from inside enhanced text processing
2148  */
2149 TERM_PUBLIC void
2150 ENHPS_WRITEC(int c)
2151 {
2152     fputc(c, gppsfile);
2153 }
2154
2155 /* a set-font routine for enhanced post : simply copies
2156  * the font into a global, or restores the globals
2157  * to the ps_params->font default
2158  */
2159
2160 TERM_PUBLIC int
2161 ENHPS_set_font(const char *font)
2162 {
2163     if (ignore_enhanced_text)
2164         return PS_set_font(font);
2165
2166     if (*font) {
2167         size_t sep = strcspn(font,",");
2168         if (sep > 0) {
2169             strncpy(ps_enh_font,font,sep);
2170             ps_enh_font[sep] = NUL;
2171             PS_RememberFont(ps_enh_font, 1);
2172         }
2173         ps_enh_fontsize = ps_fontsize;
2174         sscanf (font+sep+1,"%f",&ps_enh_fontsize);
2175     } else {
2176         /* return to defaults */
2177         strcpy(ps_enh_font, ps_params->font);
2178         ps_enh_fontsize = ps_fontsize;
2179     }
2180     term->v_char = (unsigned int)(ps_enh_fontsize*PS_SC);
2181     term->h_char = (unsigned int)(ps_enh_fontsize*PS_SC*6/10);
2182
2183     return TRUE;
2184 }
2185
2186 TERM_PUBLIC void
2187 ENHPS_put_text(unsigned int x, unsigned int y, const char *str)
2188 {
2189     if (ignore_enhanced_text) {
2190         PS_put_text(x,y,str);
2191         return;
2192     }
2193
2194     /* flush any pending graphics (all the XShow routines do this...) */
2195
2196     if (!strlen(str))
2197         return;
2198
2199     PS_FLUSH_PATH;
2200
2201     /* if there are no magic characters, we should just be able
2202      * punt the string to PS_put_text(), which will give shorter
2203      * ps output [eg tics and stuff rarely need extra processing],
2204      * but we need to make sure that the current font is the
2205      * default one before we can do that. {ie I tried it and it
2206      * used the wrong font !}
2207      * if (!strpbrk(str, "{}^_@&~"))
2208      * {
2209      *   - do something to ensure default font is selected
2210      *   PS_put_text(x,y,str);
2211      *   return;
2212      * }
2213      */
2214
2215     PS_move(x,y);
2216
2217     if (ps_ang != 0)
2218         fprintf(gppsfile,"currentpoint gsave translate %d rotate 0 0 moveto\n",
2219                 ps_ang);
2220
2221     fputs("[ ", gppsfile);
2222
2223     /* set up the global variables needed by enhanced_recursion() */
2224     enhanced_max_height = -1000;
2225     enhanced_min_height = 1000;
2226     enhanced_fontscale = PS_SC;
2227     strncpy(enhanced_escape_format,"\\%o",sizeof(enhanced_escape_format));
2228
2229     ENHps_opened_string = FALSE;
2230
2231     /* Set the recursion going. We say to keep going until a
2232      * closing brace, but we don't really expect to find one.
2233      * If the return value is not the nul-terminator of the
2234      * string, that can only mean that we did find an unmatched
2235      * closing brace in the string. We increment past it (else
2236      * we get stuck in an infinite loop) and try again.
2237      *
2238      * ps_enh_font and ps_enh_fontsize are either set to the
2239      * the defaults set on option line, or have been set to
2240      * "font,size". That is to say, ps_params->font is used only
2241      * at startup and by ENHPS_set_font
2242      */
2243     while (*(str = enhanced_recursion((char *)str, TRUE, ps_enh_font,
2244                  (double)(ps_enh_fontsize*PS_SC), 0.0, TRUE, TRUE, 0))) {
2245         ENHPS_FLUSH();
2246
2247         /* I think we can only get here if *str == '}' */
2248         enh_err_check(str);
2249
2250         if (!*++str)
2251             break; /* end of string */
2252
2253         /* else carry on and process the rest of the string */
2254     }
2255
2256     enhanced_max_height += enhanced_min_height;
2257
2258     fprintf(gppsfile, "] %.1f ", -enhanced_max_height/3);
2259
2260     switch(ps_justify) {
2261     case LEFT :
2262         fputs("MLshow\n", gppsfile);
2263         break;
2264     case CENTRE :
2265         fputs("MCshow\n", gppsfile);
2266         break;
2267     case RIGHT :
2268         fputs("MRshow\n", gppsfile);
2269         break;
2270     }
2271
2272     if (ps_ang != 0)
2273         fputs("grestore\n", gppsfile);
2274     ps_path_count = 0;
2275     PS_relative_ok = FALSE;
2276 }
2277
2278 static void
2279 make_palette_formulae()
2280 {
2281 #define R sm_palette.formulaR
2282 #define G sm_palette.formulaG
2283 #define B sm_palette.formulaB
2284 /* print the definition of R,G,B formulae */
2285   fputs("/InterpolatedColor false def\n", gppsfile);
2286 if (sm_palette.ps_allcF == 0) { /* print only those 3 used formulae */
2287     fprintf(gppsfile, "/cF%i {%s} bind def\t%% %s\n",
2288              abs(R), ps_math_color_formulae[ 2*abs(R) ],
2289              ps_math_color_formulae[ 2*abs(R)+1 ]);
2290     if (abs(G) != abs(R))
2291       fprintf(gppsfile, "/cF%i {%s} bind def\t%% %s\n",
2292                abs(G), ps_math_color_formulae[ 2*abs(G) ],
2293                ps_math_color_formulae[ 2*abs(G)+1 ]);
2294     if ((abs(B) != abs(R)) && (abs(B) != abs(G)))
2295       fprintf(gppsfile, "/cF%i {%s} bind def\t%% %s\n",
2296                abs(B), ps_math_color_formulae[ 2*abs(B) ],
2297                ps_math_color_formulae[ 2*abs(B)+1 ]);
2298     }
2299   else { /* all color formulae are written into the output PostScript file */
2300     int i = 0;
2301     while (*(ps_math_color_formulae[2*i])) {
2302       fprintf(gppsfile, "/cF%i {%s} bind def\t%% %s\n",
2303                i, ps_math_color_formulae[ 2*i ],
2304                ps_math_color_formulae[ 2*i+1 ]);
2305       i++;
2306       }
2307     }
2308 #undef R
2309 #undef G
2310 #undef B
2311 }
2312
2313
2314
2315 static void
2316 make_interpolation_code()
2317 {
2318     static const char *header[] = {
2319         "/grayindex {/gidx 0 def\n",
2320         "  {GrayA gidx get grayv ge {exit} if /gidx gidx 1 add def} loop} def\n",
2321         "/dgdx {grayv GrayA gidx get sub GrayA gidx 1 sub get\n",
2322         "  GrayA gidx get sub div} def \n",
2323         "/redvalue {RedA gidx get RedA gidx 1 sub get\n",
2324         "  RedA gidx get sub dgdxval mul add} def\n",
2325         "/greenvalue {GreenA gidx get GreenA gidx 1 sub get\n",
2326         "  GreenA gidx get sub dgdxval mul add} def\n",
2327         "/bluevalue {BlueA gidx get BlueA gidx 1 sub get\n",
2328         "  BlueA gidx get sub dgdxval mul add} def\n",
2329         "/interpolate {\n",
2330         "  grayindex grayv GrayA gidx get sub abs 1e-5 le\n",
2331         "    {RedA gidx get GreenA gidx get BlueA gidx get}\n",
2332         "    {/dgdxval dgdx def redvalue greenvalue bluevalue} ifelse} def\n",
2333         NULL,
2334     };
2335     int i;
2336
2337     for(i=0; header[i]!=NULL; ++i) {
2338         fputs(header[i], gppsfile);
2339     }
2340 }
2341
2342
2343 static void
2344 make_color_model_code()
2345 {
2346     /* Postscript version of the color space transformations in getcolor.c */
2347     static const char *header[] = {
2348         "/HSV2RGB {",
2349         "  exch dup 0.0 eq {pop exch pop dup dup} % achromatic gray\n",
2350         "  { /HSVs exch def /HSVv exch def 6.0 mul dup floor dup 3 1 roll sub\n ",
2351         "    /HSVf exch def /HSVi exch cvi def /HSVp HSVv 1.0 HSVs sub mul def\n",
2352         "        /HSVq HSVv 1.0 HSVs HSVf mul sub mul def \n",
2353         "        /HSVt HSVv 1.0 HSVs 1.0 HSVf sub mul sub mul def\n",
2354         "        /HSVi HSVi 6 mod def 0 HSVi eq {HSVv HSVt HSVp}\n",
2355         "        {1 HSVi eq {HSVq HSVv HSVp}{2 HSVi eq {HSVp HSVv HSVt}\n",
2356         "        {3 HSVi eq {HSVp HSVq HSVv}{4 HSVi eq {HSVt HSVp HSVv}\n",
2357         "        {HSVv HSVp HSVq} ifelse} ifelse} ifelse} ifelse} ifelse\n",
2358         "  } ifelse} def\n",
2359         "/Constrain {\n",
2360         "  dup 0 lt {0 exch pop}{dup 1 gt {1 exch pop} if} ifelse} def\n",
2361         "/YIQ2RGB {\n",
2362         "  3 copy -1.702 mul exch -1.105 mul add add Constrain 4 1 roll\n",
2363         "  3 copy -0.647 mul exch -0.272 mul add add Constrain 5 1 roll\n",
2364         "  0.621 mul exch -0.956 mul add add Constrain 3 1 roll } def\n",
2365         "/CMY2RGB {",
2366         "  1 exch sub exch 1 exch sub 3 2 roll 1 exch sub 3 1 roll exch } def\n",
2367         "/XYZ2RGB {",
2368         "  3 copy -0.9017 mul exch -0.1187 mul add exch 0.0585 mul exch add\n",
2369         "  Constrain 4 1 roll 3 copy -0.0279 mul exch 1.999 mul add exch\n",
2370         "  -0.9844 mul add Constrain 5 1 roll -0.2891 mul exch -0.5338 mul add\n",
2371         "  exch 1.91 mul exch add Constrain 3 1 roll} def\n",
2372         "/SelectSpace {ColorSpace (HSV) eq {HSV2RGB}{ColorSpace (XYZ) eq {\n",
2373         "  XYZ2RGB}{ColorSpace (CMY) eq {CMY2RGB}{ColorSpace (YIQ) eq {YIQ2RGB}\n",
2374         "  if} ifelse} ifelse} ifelse} def\n",
2375         NULL,
2376     };
2377     int i;
2378
2379     for(i=0; header[i]!=NULL; ++i) {
2380         fputs(header[i], gppsfile);
2381     }
2382 }
2383
2384
2385 static char
2386 *save_space(double gray)
2387 {
2388     /* printing the gray with 4 digits and without the leading 0
2389      * ... saving space */
2390     static char s[40];
2391
2392     gray = 0.0001*(int)(gray*10000+0.5); /* round it to 4 digits */
2393     sprintf(s, "%.4g", gray);
2394     if (s[0] == '0' && s[1] == '.')
2395         return &(s[1]);  /* strip leading 0 */
2396     else
2397         return s;
2398 }
2399
2400
2401 static void
2402 write_color_space(t_sm_palette *palette)
2403 {
2404     /* write something like
2405      *   /ColorSpace (HSV) def
2406      * depending on the selected cmodel in palette */
2407     fputs("/ColorSpace ", gppsfile);
2408     switch(palette->cmodel) {
2409     case C_MODEL_RGB:
2410         fputs("(RGB)", gppsfile);
2411         break;
2412     case C_MODEL_HSV:
2413         fputs("(HSV)", gppsfile);
2414         break;
2415     case C_MODEL_CMY:
2416         fputs("(CMY)", gppsfile);
2417         break;
2418     case C_MODEL_YIQ:
2419         fputs("(YIQ)", gppsfile);
2420         break;
2421     case C_MODEL_XYZ:
2422         fputs("(XYZ)", gppsfile);
2423         break;
2424     default:
2425         fprintf(stderr,"%s:%d ooops: Unkown color model '%c'. Will be RGB\n",
2426                 __FILE__, __LINE__, (char)(palette->cmodel));
2427         fputs("(RGB)", gppsfile);
2428         break;
2429     }
2430     fputs(" def\n", gppsfile);
2431 }
2432
2433
2434 static void
2435 write_component_array(const char *text, gradient_struct *grad,
2436                       int cnt, int offset)
2437 {
2438     /*  write someting like
2439      *     /RedA [ 0 .1 .2 .3 .35 .3 .2 .1 0 0 0 ] def
2440      *  nicely formated to gppsfile
2441      */
2442     int i=0, len=0;
2443     char *val;
2444
2445     fprintf(gppsfile, "/%s [", text);
2446     len = strlen(text) + 4;
2447     for(i=0; i<cnt; ++i) {
2448         char *ref = (char*)(&(grad[i]));
2449
2450         ref += offset;
2451         val = save_space(*((double*) (ref)));
2452         len += strlen(val) + 1;
2453         if(len > 77) {
2454             fputs("\n  ",gppsfile);
2455             len = strlen(val) + 3;
2456         }
2457         fprintf(gppsfile, "%s ", val);
2458     }
2459     fputs("] def\n", gppsfile);
2460 }
2461
2462
2463 static void
2464 write_gradient_definition(gradient_struct *gradient, int cnt)
2465 {
2466     /* some strange pointer acrobatic here, but it seems to work... */
2467     char *ref = (char*) (gradient);
2468     int p = (char*) (&(gradient[0].pos)) - ref;
2469     int r = (char*) (&(gradient[0].col.r)) - ref;
2470     int g = (char*) (&(gradient[0].col.g)) - ref;
2471     int b = (char*) (&(gradient[0].col.b)) - ref;
2472
2473     write_component_array("GrayA", gradient, cnt, p);
2474     write_component_array("RedA", gradient, cnt, r);
2475     write_component_array("GreenA", gradient, cnt, g);
2476     write_component_array("BlueA", gradient, cnt, b);
2477 }
2478
2479
2480 static void
2481 PS_make_header(t_sm_palette *palette)
2482 {
2483     /* write header for smooth colors */
2484     fputs("gsave % colour palette begin\n", gppsfile);
2485     fprintf(gppsfile, "/maxcolors %i def\n", sm_palette.use_maxcolors);
2486     make_color_model_code();
2487
2488     switch(sm_palette.colorMode) {
2489     case SMPAL_COLOR_MODE_GRAY:
2490         fputs("/InterpolatedColor false def\n", gppsfile);
2491         break;  /* nothing to do for gray */
2492     case SMPAL_COLOR_MODE_RGB:
2493         make_palette_formulae();
2494         break;
2495     case SMPAL_COLOR_MODE_FUNCTIONS: {
2496         int cnt=0;
2497         gradient_struct *gradient;
2498
2499         fputs("/InterpolatedColor true def\n", gppsfile);
2500         make_interpolation_code();
2501         gradient = approximate_palette(palette, ps_params->palfunc_samples,
2502                                        ps_params->palfunc_deviation, &cnt);
2503         write_gradient_definition(gradient, cnt);
2504         free(gradient);
2505         break;
2506     }
2507     case SMPAL_COLOR_MODE_GRADIENT:
2508         fputs("/InterpolatedColor true def\n", gppsfile);
2509         make_interpolation_code();
2510         write_gradient_definition(palette->gradient, palette->gradient_num);
2511         break;
2512     default:
2513         fprintf(stderr, "%s:%d ooops: Unknown color mode '%c'\n",
2514                  __FILE__, __LINE__, (char)(sm_palette.colorMode));
2515     }
2516     fputs("/pm3dround {maxcolors 0 gt {dup 1 ge\n", gppsfile);
2517     fputs("\t{pop 1} {maxcolors mul floor maxcolors 1 sub div} ifelse} if} def\n",
2518           gppsfile);
2519     fprintf(gppsfile, "/pm3dGamma 1.0 %g div def\n", sm_palette.gamma);
2520     write_color_space(palette);
2521
2522 /* Now print something like
2523    /g {dup cF7 exch dup cF5 exch cF15 setrgbcolor} bind def
2524 */
2525 #define R sm_palette.formulaR
2526 #define G sm_palette.formulaG
2527 #define B sm_palette.formulaB
2528
2529 /* 18.1.2009 Since the beginning of pm3d, the Color definition switched
2530    between gray and colour map. This led to ambiguities for custom colour
2531    palettes if they contain grays only. Thus let postscript choose always
2532    always colour palette for interpolated colours ('set palette defined',
2533    'set palette file') and colour/gray according to Color otherwise
2534    ('set palette gray', 'set palette rgb').
2535 */
2536 #if 0
2537     fprintf(gppsfile, "Color %s and { %% COLOUR vs. GRAY map\n",
2538             (sm_palette.colorMode!=SMPAL_COLOR_MODE_GRAY) ? "true":"false");
2539 #else
2540     if (sm_palette.colorMode == SMPAL_COLOR_MODE_GRAY)
2541         fputs("false { % COLOUR vs. GRAY map\n", gppsfile);
2542     else
2543         fputs("Color InterpolatedColor or { % COLOUR vs. GRAY map\n", gppsfile);
2544 #endif
2545
2546     fputs("  InterpolatedColor { %% Interpolation vs. RGB-Formula\n",
2547           gppsfile);
2548     fputs("    /g {stroke pm3dround /grayv exch def interpolate\n", gppsfile);
2549     fputs("        SelectSpace setrgbcolor} bind def\n", gppsfile);
2550     fputs("  }{\n", gppsfile);
2551     fputs("  /g {stroke pm3dround dup ", gppsfile);
2552     if (R < 0)
2553         fputs("1 exch sub ", gppsfile); /* negate */
2554     fprintf(gppsfile,"cF%i Constrain exch dup ", abs(R));
2555     if (G < 0)
2556         fputs("1 exch sub ", gppsfile); /* negate */
2557     fprintf(gppsfile,"cF%i Constrain exch ", abs(G));
2558     if (R<0 || G<0 || B<0)
2559         fputs("\n\t", gppsfile);
2560     if (B < 0)
2561         fputs("1 exch sub ", gppsfile); /* negate */
2562     fprintf(gppsfile,"cF%i Constrain ", abs(B));
2563     fputs("\n       SelectSpace setrgbcolor} bind def\n", gppsfile);
2564     fputs("  } ifelse\n", gppsfile);
2565     fputs("}{\n", gppsfile);
2566     fputs("  /g {stroke pm3dround pm3dGamma exp setgray} bind def\n", gppsfile);
2567     fputs("} ifelse\n", gppsfile);
2568 #undef R
2569 #undef G
2570 #undef B
2571 }
2572
2573
2574 TERM_PUBLIC int PS_make_palette (t_sm_palette *palette)
2575 {
2576     if (palette == NULL) {
2577         return 0;  /* postscript can do continuous colors */
2578     }
2579
2580     PS_make_header(palette);
2581     return 0;
2582 }
2583
2584
2585 TERM_PUBLIC void PS_set_color (t_colorspec *colorspec)
2586 {
2587     double gray;
2588
2589     PS_linetype_last = -1;  /* Force next call to linetype to be honored */
2590
2591     if (colorspec->type == TC_LT) {
2592         int linetype = colorspec->lt;
2593         PS_FLUSH_PATH;
2594         if ((ps_params->terminal == PSTERM_EPSLATEX) && ps_params->oldstyle)
2595             linetype = (linetype % 4) + 3;
2596         else
2597             linetype = (linetype % 9) + 3;
2598         if (linetype < 0)       /* LT_NODRAW, LT_BACKGROUND, LT_UNDEFINED */
2599             linetype = 0;
2600         fprintf(gppsfile, "LC%1c setrgbcolor\n","wba012345678"[linetype]);
2601     } else if (colorspec->type == TC_RGB) {
2602         double r = (double)((colorspec->lt >> 16 ) & 255) / 255.;
2603         double g = (double)((colorspec->lt >> 8 ) & 255) / 255.;
2604         double b = (double)(colorspec->lt & 255) / 255.;
2605         PS_FLUSH_PATH;
2606         fprintf(gppsfile, "%3.2f %3.2f %3.2f C ",r,g,b);
2607     }
2608
2609     if (colorspec->type != TC_FRAC)
2610         return;
2611
2612 /* map [0;1] to gray/colors */
2613     gray = colorspec->value;
2614     if (gray <= 0)
2615         fputs("0 g ", gppsfile);
2616     else {
2617         if (gray >= 1)
2618             fputs("1 g ", gppsfile);
2619         else
2620             fprintf(gppsfile, "%s g ", save_space(gray));
2621     }
2622     PS_relative_ok = FALSE; /* "M" required because "g" forces stroke (??) */
2623 }
2624
2625
2626 TERM_PUBLIC void PS_filled_polygon (int points, gpiPoint *corners)
2627 {
2628     int i;
2629     float filldens = 1.0;
2630     int pattern = 0;
2631     int style = corners->style;
2632
2633     /* Stroke the previous graphic element if required. */
2634     if (PS_relative_ok)
2635         PS_FLUSH_PATH;
2636
2637     if (points == 4 && style == FS_OPAQUE) {
2638         /* Special case for pm3d surface quadrangles
2639          *  <x0> <y0> ... <x4> <y4> h
2640          */
2641             fprintf(gppsfile, "%i %i N", corners[0].x, corners[0].y);
2642             fprintf(gppsfile, " %i %i %i %i %i %i h\n",
2643             corners[3].x-corners[2].x, corners[3].y-corners[2].y,
2644             corners[2].x-corners[1].x, corners[2].y-corners[1].y,
2645             corners[1].x-corners[0].x, corners[1].y-corners[0].y);
2646     } else {
2647         /* General case for solid or pattern-filled polygons
2648          * gsave <x0> <y0> N <x1> <y1> ... <xn> <yn> density PolyFill
2649          */
2650         fprintf(gppsfile, "gsave ");
2651         fprintf(gppsfile, "%i %i N", corners[0].x, corners[0].y);
2652         for (i = 1; i < points; i++) {
2653             /* The rationale for mixing V and L is given in PS_vector */
2654             if (i % MAX_REL_PATHLEN)
2655                 fprintf(gppsfile, " %i %i V", corners[i].x-corners[i-1].x,
2656                     corners[i].y-corners[i-1].y);
2657             else
2658                 fprintf(gppsfile, " %i %i L", corners[i].x, corners[i].y);
2659         }
2660
2661         switch(style & 0xf) {
2662         
2663         case FS_SOLID:
2664             filldens = (style >> 4) / 100.0;
2665             if(filldens < 0.0)
2666                 filldens = 0.0;
2667             if(filldens >= 1.0)
2668                 fprintf(gppsfile, " 1 PolyFill\n");
2669             else
2670                 fprintf(gppsfile, " %.2f PolyFill\n", filldens);
2671             break;
2672             
2673         case FS_PATTERN:
2674             pattern = (style >> 4) % 8;
2675             if (pattern == 0)  {
2676                 filldens = 0.5;
2677                 fprintf(gppsfile, " %.1f PolyFill\n", filldens);
2678             } else {
2679                 fprintf(gppsfile," Pattern%d fill grestore\n", pattern);
2680             }
2681             break;
2682
2683         default:
2684             fputs(" 1 PolyFill\n", gppsfile);
2685             break;
2686
2687         }
2688     }
2689
2690     PS_relative_ok = FALSE;
2691 }
2692
2693 #undef MAX_REL_PATHLEN
2694
2695 TERM_PUBLIC void PS_previous_palette()
2696 {
2697     /* Needed to stroke the previous graphic element. */
2698     PS_FLUSH_PATH;
2699     fputs("grestore % colour palette end\n", gppsfile);
2700 }
2701
2702
2703 /*
2704  * The reason for having a PostScript-specific wrapper for do_arrow
2705  * is that post.trm draws dotted lines for monochrome output, and
2706  * dotted arrowheads are ugly.  So in that case we call do_arrow twice,
2707  * the second time to retrace the head with the line style forced to solid.
2708  */
2709 TERM_PUBLIC void PS_arrow (
2710     unsigned int sx, unsigned int sy,
2711     unsigned int ex, unsigned int ey,
2712     int head)
2713 {
2714     do_arrow( sx, sy, ex, ey, head );
2715     if (!ps_params->solid && head != 0) {
2716         PS_FLUSH_PATH;
2717         fputs("gsave [] 0 setdash\n", gppsfile);
2718         do_arrow( sx, sy, ex, ey, -head );
2719         PS_FLUSH_PATH;
2720         fputs("grestore\n", gppsfile);
2721     }
2722 }
2723
2724 static void
2725 delete_ps_fontfile(struct ps_fontfile_def *prev, struct ps_fontfile_def *this)
2726 {
2727     if (this != NULL) {         /* there really is something to delete */
2728         FPRINTF((stderr, "Remove font/kerning file `%s'\n",
2729                  this->fontfile_name));
2730         if (prev != NULL)       /* there is a previous ps_fontfile */
2731             prev->next = this->next;
2732         else                    /* this = ps_params->first_fontfile */
2733                                 /* so change ps_params->first_fontfile */
2734             ps_params->first_fontfile = this->next;
2735         free(this->fontfile_name);
2736         free(this->fontfile_fullname);
2737         free(this);
2738         this = NULL;
2739     }
2740 }
2741
2742
2743 #ifdef WITH_IMAGE
2744
2745 static void
2746 PS_encode85(unsigned long tuple4, unsigned char *tuple5)
2747 {
2748     /* The compiler should know to carry out the powers of
2749      * 85 computation at compilation time.
2750      */
2751     tuple5[0] = tuple4/(85*85*85*85);
2752     tuple4 -= ((unsigned long)tuple5[0])*(85*85*85*85);
2753     tuple5[1] = tuple4/(85*85*85);
2754     tuple4 -= ((unsigned long)tuple5[1])*(85*85*85);
2755     tuple5[2] = tuple4/(85*85);
2756     tuple4 -= ((unsigned long)tuple5[2])*(85*85);
2757     tuple5[3] = tuple4/(85);
2758     tuple4 -= ((unsigned long)tuple5[3])*(85);
2759     tuple5[4] = tuple4;
2760 }
2761
2762 enum PS_ENCODING {
2763     PS_ASCII_HEX,
2764     PS_ASCII85
2765 } PS_ENCODING;
2766
2767 /* Returns pointer to encoded image, allocated on heap that the
2768  * caller must free.  Can error to command line so make sure all
2769  * heap memory is recorded in static pointers when calling this
2770  * routine.
2771  */
2772 static char *
2773 PS_encode_image(unsigned M, unsigned N, coordval *image, t_imagecolor color_mode, 
2774                 int bits_per_component, int max_colors, double cscale,
2775                 enum PS_ENCODING encoding, int *return_num_bytes)
2776 {
2777     unsigned coord_remaining;
2778     coordval *coord_ptr;
2779     unsigned short i_line;
2780     unsigned i_element;
2781     unsigned end_of_line;
2782     unsigned short bits_remaining, bits_start;
2783
2784     unsigned long tuple4;
2785     unsigned char tuple5[5];
2786     int max_encoded_bytes;
2787     char *encoded_image, *encoded_image_ptr;
2788     unsigned long total_bits;
2789
2790 #define ASCII_PER_LINE 78
2791
2792     /* 18.1.2009 RGB images ("plot ... with rgbimage") are drawn always in color,
2793      * i.e. for both "set term post color" and "set term post mono".
2794      */
2795     total_bits = bits_per_component*M*N*((color_mode == IC_RGB /* && ps_params->color */) ? 3 : 1);
2796
2797     /* At the end of each image line, data is aligned to the nearest 8 bits,
2798      * which means potentially adding 7 bits per line.
2799      */
2800     end_of_line = M;
2801     total_bits += N*7;
2802
2803     /* Compute max number of ascii characters encoding will require.
2804      */
2805     if (encoding == PS_ASCII_HEX) {
2806         /* Straight hex encoding */
2807         max_encoded_bytes = (total_bits/4 + 1);
2808         max_encoded_bytes += max_encoded_bytes / ASCII_PER_LINE; /* newline characters */
2809     } else {
2810         /* ASCII85 encoding */
2811         max_encoded_bytes = (total_bits/32 + 1)*5 + 2; /* 5 tuples and additional ~> */
2812         max_encoded_bytes += max_encoded_bytes / ASCII_PER_LINE; /* newline characters */
2813     }
2814
2815     /* Reserve enough memory. */
2816     if (!(encoded_image = gp_alloc(max_encoded_bytes, "encoded image")))
2817         int_error(NO_CARET, "GNUPLOT (post.trm):  Error allocating memory.\n");
2818     encoded_image_ptr = encoded_image;
2819
2820     coord_ptr = image;
2821     i_line = ASCII_PER_LINE;
2822     i_element = 0;
2823     coord_remaining = M*N;
2824     if (color_mode == IC_RGB /* && ps_params->color */) {
2825         end_of_line *= 3;
2826         coord_remaining *= 3;
2827     }
2828     bits_remaining = 32;
2829     bits_start = 0;
2830     tuple4 = 0;
2831
2832     while (coord_remaining) {
2833         unsigned short us_tmp;
2834         if (0 /* color_mode == IC_RGB && !ps_params->color */) {
2835             coordval c_tmp;
2836             c_tmp = *coord_ptr++;
2837             c_tmp += *coord_ptr++;
2838             c_tmp += *coord_ptr++;
2839             us_tmp = (unsigned short) (c_tmp*(max_colors-1)/3.0 + 0.5);
2840         } else
2841             us_tmp = (unsigned short) ((*coord_ptr++) * max_colors);
2842
2843         if (us_tmp > (max_colors-1)) us_tmp = max_colors-1;
2844
2845         /* Rescale to accommodate a mismatch between max_colors and # of bits */
2846         us_tmp *= cscale;
2847
2848         if (bits_remaining < bits_per_component) {
2849             tuple4 <<= bits_remaining;
2850             bits_start = bits_per_component - bits_remaining;
2851             bits_remaining = 0;
2852             tuple4 |= (us_tmp >> bits_start);
2853         } else {
2854             tuple4 <<= bits_per_component;
2855             tuple4 |= us_tmp;
2856             bits_remaining -= bits_per_component;
2857         }
2858
2859         /* If this is last pixel in line, pad to nearest 8 bits. */
2860         i_element++;
2861         if (i_element == end_of_line) {
2862             register unsigned short bit_align = (bits_remaining & 0x7);
2863             tuple4 <<= bit_align;
2864             bits_remaining -= bit_align;
2865             i_element = 0;
2866         }
2867
2868         /* Check if another 4-tuple is complete. */
2869         if (!bits_remaining) {
2870             if (ps_params->level1) {
2871                 /* A straight hex encoding for every 4 bits. */
2872                 unsigned char tuple8[8];
2873                 int i;
2874                 for (i=7; i >= 0; i--) {
2875                     tuple8[i] = tuple4 & 0xf;
2876                     tuple4 >>= 4;
2877                 }
2878                 for (i=0; i < 8; i++) {
2879                     sprintf(encoded_image_ptr++, "%1x", tuple8[i]);
2880                     i_line--;
2881                     if (!i_line) {i_line = ASCII_PER_LINE; *encoded_image_ptr++ = '\n';}
2882                 }
2883             } else {
2884                 /* Convert to ASCII85 representation. */
2885                 if (tuple4) {
2886                     int i;
2887                     PS_encode85(tuple4, tuple5);
2888                     tuple4 = 0;
2889                     for (i=0; i < 5; i++) {
2890                         sprintf(encoded_image_ptr++, "%c", tuple5[i]+'!');
2891                         i_line--;
2892                         if (!i_line) {i_line = ASCII_PER_LINE; *encoded_image_ptr++ = '\n';}
2893                     }
2894                 } else {
2895                     *encoded_image_ptr++ = 'z';
2896                     i_line--;
2897                     if (!i_line) {i_line = ASCII_PER_LINE; *encoded_image_ptr++ = '\n';}
2898                 }
2899             }
2900
2901             /* Now pick up any bits that may have not made it into the 4-tuple. */
2902             if (bits_start) {tuple4 = us_tmp - ((us_tmp>>bits_start)<<bits_start);}
2903             bits_remaining = 32 - bits_start;
2904             bits_start = 0;
2905
2906         }
2907
2908         coord_remaining--;
2909
2910     }
2911
2912     if (bits_remaining < 32) {
2913         int i;
2914         int n = 4 - bits_remaining/8;
2915         if (ps_params->level1) {
2916             /* A straight hex encoding for every 4 bits. */
2917             unsigned char tuple8[8];
2918             for (i=2*n-1; i >= 0; i--) {
2919                 tuple8[i] = tuple4 & 0xf;
2920                 tuple4 >>= 4;
2921             }
2922             for (i=0; i < 2*n; i++) {
2923                 sprintf(encoded_image_ptr++, "%1x", tuple8[i]);
2924                 i_line--;
2925                 if (!i_line) {i_line = ASCII_PER_LINE; *encoded_image_ptr++ = '\n';}
2926             }
2927         } else {
2928             /* Convert to ASCII85 representation.
2929              *
2930              * The case where not all bytes in a tuple are used is slightly different.
2931              * There is no use of 'z' as a special character and the remaining bytes
2932              * need to be filled.  Then use only a portion of the final 5-tuple.
2933              */
2934             tuple4 <<= bits_remaining;
2935             PS_encode85(tuple4, tuple5);
2936             /* Write first n+1 bytes. */
2937             for (i=0; i <= n; i++) {
2938                 sprintf(encoded_image_ptr++, "%c", tuple5[i]+'!');
2939                 i_line--;
2940                 if (!i_line) {i_line = ASCII_PER_LINE; *encoded_image_ptr++ = '\n';}
2941             }
2942         }
2943     }
2944
2945     if (!ps_params->level1) {
2946         sprintf(encoded_image_ptr, "~>");
2947         encoded_image_ptr += 2;
2948     }
2949
2950     *return_num_bytes = (encoded_image_ptr - encoded_image);
2951     assert(*return_num_bytes <= max_encoded_bytes); 
2952     return encoded_image;
2953 }
2954
2955
2956 static void
2957 print_five_operand_image(unsigned M, unsigned N, gpiPoint *corner, t_imagecolor color_mode, unsigned short bits_per_component)
2958 {
2959     char *space = ps_params->level1 ? "" : "  ";
2960
2961     fprintf(gppsfile, "%sgsave\n", space);
2962     if (sm_palette.colorMode == SMPAL_COLOR_MODE_GRAY)
2963         fprintf(gppsfile, "%s{pm3dGamma exp} settransfer\n", space);
2964     fprintf(gppsfile, "%s%d %d translate\n", space, corner[0].x, corner[0].y);
2965     fprintf(gppsfile, "%s%d %d scale\n", space, (corner[1].x - corner[0].x), (corner[1].y - corner[0].y));
2966     fprintf(gppsfile, "%s%d %d %d\n", space, M, N, bits_per_component);
2967     fprintf(gppsfile, "%s[ %d 0 0 %d 0 0 ]\n", space, M, N);
2968     if (ps_params->level1) {
2969         fprintf(gppsfile, "/imagebuf %d string def\n", 
2970                 (M*N*bits_per_component*((color_mode == IC_RGB /* && ps_params->color */) ? 3 : 1) + 7)/8);
2971         fputs("{currentfile imagebuf readhexstring pop}\n", gppsfile);
2972     } else
2973         fprintf(gppsfile, "  currentfile /ASCII85Decode filter\n");
2974     if (color_mode == IC_RGB /* && ps_params->color */) {
2975         fprintf(gppsfile, "%sfalse 3\n"
2976                           "%scolorimage\n", space, space);
2977     } else
2978         fprintf(gppsfile, "%simage\n", space);
2979 }
2980
2981
2982 TERM_PUBLIC void
2983 PS_image (unsigned M, unsigned N, coordval *image, gpiPoint *corner, t_imagecolor color_mode)
2984 {
2985     char *encoded_image;
2986     int num_encoded_bytes;
2987     unsigned short bits_per_component = 0;
2988     int max_colors, i_tmp;
2989     TBOOLEAN five_operand_image;
2990     double cscale;
2991
2992 #define DEFAULT_BITS_PER_COMPONENT 8
2993 #define DEFAULT_COMPONENT_MAX (1<<DEFAULT_BITS_PER_COMPONENT)
2994
2995     if (sm_palette.use_maxcolors > 0)
2996         max_colors = sm_palette.use_maxcolors;
2997     else
2998         max_colors = DEFAULT_COMPONENT_MAX;
2999
3000     i_tmp = 1;
3001     while (i_tmp < max_colors) {
3002         bits_per_component++;
3003         i_tmp <<= 1;
3004     }
3005
3006     if (bits_per_component < 1 || bits_per_component > 12) {
3007         fprintf(stderr, "GNUPLOT (post.trm):  Component bits (%d) out of range.\n", bits_per_component);
3008         return;
3009     }
3010
3011     if (bits_per_component > 8)
3012         bits_per_component = 12;
3013     else if (bits_per_component > 4)
3014         bits_per_component = 8;
3015     else if (bits_per_component > 2)
3016         bits_per_component = 4;
3017
3018     /* Color and gray scale images do not need a palette and can use
3019      * the 5 operand form of the image routine.
3020      */
3021 #if 0
3022     /* 18.1.2009 It was decided to use the custom palette (i.e. colours) also
3023        for the monochrome postscript output.
3024     */
3025     if ((color_mode == IC_RGB) || (sm_palette.colorMode == SMPAL_COLOR_MODE_GRAY) || !ps_params->color)
3026 #else
3027     if ((color_mode == IC_RGB) || (sm_palette.colorMode == SMPAL_COLOR_MODE_RGB && !ps_params->color) || (sm_palette.colorMode == SMPAL_COLOR_MODE_GRAY))
3028 #endif
3029         five_operand_image = TRUE;
3030     else
3031         five_operand_image = FALSE;
3032
3033     /* The five operand image doesn't have a palette and the values are
3034      * such that 0 maps to 0.0 and 2^bits_per_component - 1 maps to 1.0
3035      * in the PostScript driver.  Without any other knowledge, we scale
3036      * things so that our max colors corresponds to 1.0.
3037      */
3038     if (five_operand_image)
3039         cscale =  (float)((1 << bits_per_component)-1) / (float)(max_colors-1);
3040     else
3041         cscale = 1.0;
3042
3043     encoded_image = PS_encode_image(M, N, image, color_mode, 
3044                                 bits_per_component, max_colors, cscale,
3045                                 (ps_params->level1 ? PS_ASCII_HEX : PS_ASCII85), &num_encoded_bytes);
3046
3047     fputs("%%%%BeginImage\n", gppsfile);
3048
3049     /* Clip image to requested bounding box */
3050     fprintf(gppsfile,"gsave %d %d N %d %d L %d %d L %d %d L Z clip\n",
3051         corner[2].x, corner[2].y, corner[2].x, corner[3].y, corner[3].x, corner[3].y, corner[3].x, corner[2].y);
3052
3053     /* Color and gray scale images do not need a palette and can use
3054      * the 5 operand form of the image routine.  For other types of
3055      * palettes, the 1 operand form of the image routine must be used
3056      * and an indexed palette needs to be constructed.
3057      */
3058     if (five_operand_image) {
3059
3060         if (ps_params->level1) {
3061             print_five_operand_image(M, N, corner, color_mode, bits_per_component);
3062         } else {
3063             fputs("InterpretLevel1 {\n"
3064                   "  %% Construct a box instead of image\n"
3065                   "  LTb\n", gppsfile);
3066             fprintf(gppsfile, "  %d %d M\n", corner[0].x, corner[0].y);
3067             fprintf(gppsfile, "  %d 0 V\n", (corner[1].x - corner[0].x));
3068             fprintf(gppsfile, "  0 %d V\n", (corner[1].y - corner[0].y));
3069             fprintf(gppsfile, "  %d 0 V\n", -(corner[1].x - corner[0].x));
3070             fprintf(gppsfile, "  %d %d L\n", corner[0].x, corner[0].y);
3071             fputs("  40 -110 R\n"
3072                   "  (PS level 2 image) Lshow\n"
3073                   "  % Read data but ignore it\n", gppsfile);
3074             fprintf(gppsfile, "  /imagebuf %d string def\n", num_encoded_bytes);
3075             fputs("  currentfile imagebuf readstring\n"
3076                   "} {\n", gppsfile);
3077             print_five_operand_image(M, N, corner, color_mode, bits_per_component);
3078             fputs("} ifelse\n", gppsfile);
3079         }
3080
3081     }
3082     else {
3083
3084         int allocated;
3085         unsigned short i_tuple;
3086         double fact = 1.0 / (double)(max_colors-1);
3087         if (!ps_params->level1) {
3088             fputs("InterpretLevel1 {\n"
3089                   "  %% Construct a box instead of image\n"
3090                   "  LTb\n", gppsfile);
3091             fprintf(gppsfile, "  %d %d M\n", corner[0].x, corner[0].y);
3092             fprintf(gppsfile, "  %d 0 V\n", (corner[1].x - corner[0].x));
3093             fprintf(gppsfile, "  0 %d V\n", (corner[1].y - corner[0].y));
3094             fprintf(gppsfile, "  %d 0 V\n", -(corner[1].x - corner[0].x));
3095             fprintf(gppsfile, "  %d %d L\n", corner[0].x, corner[0].y);
3096             fprintf(gppsfile, "  40 -110 R\n"
3097                     "  (PS level 2 image) Lshow\n"
3098                     "  %% Read data but ignore it\n"
3099                     "  /imagebuf %d string def\n"
3100                     "  currentfile imagebuf readstring\n", num_encoded_bytes);
3101             fputs("} {\n", gppsfile);
3102         }
3103         fputs("gsave\n", gppsfile);
3104         fprintf(gppsfile, "%d %d translate\n", corner[0].x, corner[0].y);
3105         fprintf(gppsfile, "%d %d scale\n", (corner[1].x - corner[0].x), (corner[1].y - corner[0].y));
3106         fputs("%%%%BeginPalette\n", gppsfile);
3107         fprintf(gppsfile, "[ /Indexed\n  /DeviceRGB %d\n  <", (max_colors-1));
3108
3109 #define TUPLES_PER_LINE 8
3110
3111         for (allocated = 0, i_tuple = 0; allocated < max_colors; allocated++, i_tuple--) {
3112             double gray = (double) allocated * fact;
3113             rgb255_color color;
3114             rgb255maxcolors_from_gray( gray, &color );
3115             if (!i_tuple) { fprintf(gppsfile,"\n  "); i_tuple = TUPLES_PER_LINE; }
3116             fprintf(gppsfile," %2.2x%2.2x%2.2x", (int)color.r, (int)color.g, (int)color.b);
3117         }
3118
3119         fputs("\n  >\n] setcolorspace\n", gppsfile);
3120         fputs("%%%%EndPalette\n", gppsfile);
3121         fprintf(gppsfile, "<<\n  /ImageType 1\n  /Width %d\n  /Height %d\n", M, N);
3122         fprintf(gppsfile, "  /BitsPerComponent %d\n  /ImageMatrix [ %d 0 0 %d 0 0 ]\n", bits_per_component, M, N);
3123         fprintf(gppsfile, "  /Decode [ 0 %d ]\n", ((1<<bits_per_component)-1));
3124         if (ps_params->level1) {
3125             fprintf(gppsfile, "  /imagebuf %d string def\n", (M*N*bits_per_component + 7)/8);
3126             fputs("  /DataSource {currentfile imagebuf readhexstring pop}\n", gppsfile);
3127         } else {
3128             fputs("  /DataSource currentfile /ASCII85Decode filter\n", gppsfile);
3129         }
3130         fputs("  /MultipleDataSources false\n", gppsfile);
3131         fputs("  /Interpolate false\n"
3132               ">>\n"
3133               "image\n", gppsfile);
3134         if (!ps_params->level1)
3135             fputs("} ifelse\n", gppsfile);
3136
3137     }
3138
3139     /* Send encoded image to file. */
3140     {
3141     char *encoded_image_ptr;
3142     for (i_tmp=0, encoded_image_ptr = encoded_image; i_tmp < num_encoded_bytes; i_tmp++)
3143         fputc(*encoded_image_ptr++, gppsfile);
3144     }
3145
3146     if (ps_params->level1)
3147         fputs("\ngrestore\n", gppsfile);
3148     else
3149         fputs("\nInterpretLevel1 not {\n"
3150               "  grestore\n"
3151               "} if\n", gppsfile);
3152     fputs("grestore\n", gppsfile);
3153     fputs("%%%%EndImage\n", gppsfile);
3154
3155     free(encoded_image);
3156
3157     return;
3158 }
3159
3160 #endif /* WITH_IMAGE */
3161
3162 /* First look for the GNUPLOT_PS_DIR environment variable
3163  * If unsuccessful, look for hardcoded absolute path on UNIX,
3164  * or hardcoded relative path on Windows and OS2,
3165  * or files included at compile time. */
3166 static void
3167 PS_dump_prologue_file(char *name)
3168 {
3169     char *fullname;
3170     char *ps_prologue_dir;
3171     FILE *prologue_fd;
3172     char buf[256];
3173
3174     if ((ps_prologue_dir = getenv("GNUPLOT_PS_DIR")) == NULL) {
3175 #ifdef GNUPLOT_PS_DIR
3176 # if defined(_Windows)
3177         /* retrieve prologues path relatively to gnuplot executable,
3178          * whose path is in szModuleName (winmain.c) */
3179         ps_prologue_dir = gp_alloc(strlen((char*) szModuleName)
3180                         + strlen(GNUPLOT_PS_DIR) + 2, "Prolog path");
3181         strcpy(ps_prologue_dir, (char*) szModuleName);
3182         strcat(ps_prologue_dir, "\\");
3183         /* GNUPLOT_PS_DIR is _relative_ path */
3184         strcat(ps_prologue_dir, GNUPLOT_PS_DIR);
3185 # elif defined(OS2)
3186         const ULONG bufsiz = 1024;
3187         CHAR exepath[bufsiz];
3188         PPIB ppib;
3189         ULONG rc;
3190         
3191         rc = DosGetInfoBlocks(NULL, &ppib);
3192         if (!rc)
3193                 rc = DosQueryModuleName(ppib->pib_hmte, bufsiz, (PCHAR) &exepath);
3194         if (!rc) {
3195             char *p = strrchr(exepath, '\\');
3196             *(++p) = '\0';
3197             ps_prologue_dir = gp_alloc(strlen(exepath) + strlen(GNUPLOT_PS_DIR) + 2,
3198                         "Prolog path");
3199             strcpy(ps_prologue_dir, exepath);
3200             strcat(ps_prologue_dir, "\\");
3201             /* GNUPLOT_PS_DIR is _relative_ path */
3202             strcat(ps_prologue_dir, GNUPLOT_PS_DIR);
3203         }
3204         else {
3205             ps_prologue_dir = gp_alloc(1, "Prolog path");
3206             /* unsucessful to retrieve executable path */
3207             strcpy(ps_prologue_dir,"");
3208         }
3209 # else /* !_Windows && !OS2 */
3210         /* use hardcoded _absolute_ path */
3211         ps_prologue_dir = GNUPLOT_PS_DIR;
3212 # endif
3213 #else /* using headers included at compile time */
3214         const char **dump = NULL;
3215         int i;
3216
3217         /* load from included header */
3218         if (!strcmp(name,"8859-15.ps"))
3219                 dump = prologue_8859_15_ps;
3220         else if (!strcmp(name,"8859-1.ps"))
3221                 dump = prologue_8859_1_ps;
3222         else if (!strcmp(name,"8859-2.ps"))
3223                 dump = prologue_8859_2_ps;
3224         else if (!strcmp(name,"cp1250.ps"))
3225                 dump = prologue_cp1250_ps;
3226         else if (!strcmp(name,"cp437.ps"))
3227                 dump = prologue_cp437_ps;
3228         else if (!strcmp(name,"cp850.ps"))
3229                 dump = prologue_cp850_ps;
3230         else if (!strcmp(name,"cp852.ps"))
3231                 dump = prologue_cp852_ps;
3232         else if (!strcmp(name,"koi8r.ps"))
3233                 dump = prologue_koi8r_ps;
3234         else if (!strcmp(name,"koi8u.ps"))
3235                 dump = prologue_koi8u_ps;
3236         else if (!strcmp(name,"prologue.ps"))
3237                 dump = prologue_prologue_ps;
3238         else
3239                 int_error(NO_CARET,"Requested Postscript prologue is not included");
3240
3241         if (dump) {
3242                 for (i = 0; dump[i] != NULL; ++i)
3243                 fprintf(gppsfile, "%s", dump[i]);
3244         }
3245         return;
3246 #endif /* GNUPLOT_PS_DIR */
3247     }
3248
3249     fullname = gp_alloc(strlen(ps_prologue_dir) + strlen(name) + 4,"Prolog name");
3250     strcpy(fullname,ps_prologue_dir);
3251 #if defined(_Windows) || defined(OS2)
3252     if (fullname[strlen(fullname)-1] != '\\')
3253         strcat(fullname,"\\");
3254 #elif !defined(VMS)
3255     if (fullname[strlen(fullname)-1] != '/')
3256         strcat(fullname,"/");
3257 #endif
3258     strcat(fullname,name);
3259     prologue_fd = fopen(fullname,"r");
3260 #if defined(_Windows) || defined(OS2)
3261     if (getenv("GNUPLOT_PS_DIR") == NULL)
3262         free(ps_prologue_dir);
3263 #endif
3264     if (!prologue_fd)
3265         prologue_fd = loadpath_fopen(name,"r");
3266     if (!prologue_fd) {
3267         fprintf(stderr,"Can't find PostScript prologue file %s\n", fullname);
3268         loadpath_handler(ACTION_SHOW,NULL);
3269         free(fullname);
3270         fprintf(stderr,"Please copy %s to one of the above directories\n",name);
3271         fprintf(stderr,"or set the loadpath appropriately\n");
3272         fprintf(stderr,"or set the environmental variable GNUPLOT_PS_DIR\n");
3273         int_error(NO_CARET,"Plot failed!");
3274     }
3275     free(fullname);
3276     while (fgets(buf, sizeof(buf), prologue_fd))
3277         fputs(buf, gppsfile);
3278     fclose(prologue_fd);
3279 }
3280
3281 TERM_PUBLIC void
3282 PS_path(int p)
3283 {
3284     switch (p) {
3285         case 0: /* Start new path */
3286                 PS_FLUSH_PATH;
3287                 PS_newpath = TRUE;
3288                 break;
3289
3290         case 1: /* Close path */
3291                 fprintf(gppsfile, "Z ");
3292                 PS_FLUSH_PATH;
3293                 break;
3294     }
3295
3296 }
3297
3298 #endif /* TERM_BODY */
3299
3300 #ifdef TERM_TABLE
3301
3302 TERM_TABLE_START(post_driver)
3303     "postscript",
3304     "PostScript graphics, including EPSF embedded files (*.eps)",
3305     PS_XMAX, PS_YMAX, PS_VCHAR, PS_HCHAR, 
3306     PS_VTIC, PS_HTIC, PS_options, PS_init, PS_reset, 
3307     PS_text, null_scale, PS_graphics, PS_move, PS_vector, 
3308     PS_linetype, PS_put_text, PS_text_angle, 
3309     PS_justify_text, PS_point, PS_arrow, PS_set_font, PS_pointsize,
3310     TERM_BINARY|TERM_IS_POSTSCRIPT|TERM_CAN_CLIP /*flags*/, 
3311     0 /*suspend*/, 0 /*resume*/, PS_fillbox, PS_linewidth
3312 #ifdef USE_MOUSE
3313     , 0, 0, 0, 0, 0 /* no mouse support for postscript */
3314 #endif
3315     , PS_make_palette,
3316     PS_previous_palette, /* write grestore */
3317     PS_set_color,
3318     PS_filled_polygon
3319 #ifdef WITH_IMAGE
3320     , PS_image
3321 #endif
3322     , ENHPS_OPEN, ENHPS_FLUSH, ENHPS_WRITEC
3323     , 0         /* layer control */
3324     , PS_path
3325 TERM_TABLE_END(post_driver)
3326
3327 #undef LAST_TERM
3328 #define LAST_TERM post_driver
3329
3330 #endif /* TERM_TABLE */
3331
3332 #endif /* TERM_PROTO_ONLY */
3333
3334 #ifdef TERM_HELP
3335 /* This is a pseudo help section that is labeled with 00psglobal to be
3336  * sure that it is sorted in before `post', `epslatex', and `pslatex'.
3337  * This section just defines commonly used text snippets for all three
3338  * help sections defined in this file. Defining PS_COMMON_OPTS1,
3339  * PS_COMMON_OPTS2, and PS_COMMON_DOC1 outside START_HELP()...END_HELP()
3340  * does not work.
3341  * The last line before the END_HELP(00psglobal) contains one single line
3342  * of "text" that is necessary to avoid errors.
3343  */
3344 START_HELP(00psglobal)
3345 #define PS_COMMON_OPTS1 \
3346 "                               {level1 | leveldefault}",\
3347 "                               {color | colour | monochrome}",\
3348 "                               {solid | dashed}",\
3349 "                               {dashlength | dl <DL>}",\
3350 "                               {linewidth | lw <LW>}",\
3351 "                               {rounded | butt}",\
3352 "                               {palfuncparam <samples>{,<maxdeviation>}}",\
3353 "                               {size <XX>{unit},<YY>{unit}}",
3354 #define PS_COMMON_OPTS2 \
3355 "                               {blacktext | colortext | colourtext}",\
3356 "                               {{font} \"fontname{,fontsize}\" {<fontsize>}}",
3357 #define PS_COMMON_PROLOG_INFO \
3358 " If you see the error message",\
3359 "       \"Can't find PostScript prologue file ... \"",\
3360 " Please see and follow the instructions in `postscript prologue`.",\
3361 "",
3362 #define PS_COMMON_DOC1 \
3363 " The option `color` enables color, while `monochrome` prefers black and white",\
3364 " drawing elements. Further, `monochrome` uses gray `palette` but it does not",\
3365 " change color of objects specified with an explicit `colorspec`."\
3366 "",\
3367 " `solid` draws all plots with solid lines, overriding any dashed patterns.",\
3368 " `dashlength` or `dl` scales the length of the dashed-line segments by <DL>,",\
3369 " which is a floating-point number greater than zero.",\
3370 " `linewidth` or `lw` scales all linewidths by <LW>.",\
3371 "",\
3372 " By default the generated PostScript code uses language features that were",\
3373 " introduced in PostScript Level 2, notably filters and pattern-fill of",\
3374 " irregular objects such as filledcurves.  PostScript Level 2 features are",\
3375 " conditionally protected so that PostScript Level 1 interpreters do not issue",\
3376 " errors but, rather, display a message or a PostScript Level 1 approximation.",\
3377 " The `level1` option substitutes PostScript Level 1 approximations of these",\
3378 " features and uses no PostScript Level 2 code.  This may be required by some",\
3379 " old printers and old versions of Adobe Illustrator.  The flag `level1` can be", \
3380 " toggled later by editing a single line in the PostScript output file to force",\
3381 " PostScript Level 1 interpretation.  In the case of files containing level 2",\
3382 " code, the above features will not appear or will be replaced by a note when",\
3383 " this flag is set or when the interpreting program does not indicate that it",\
3384 " understands level 2 PostScript or higher.",\
3385 "",\
3386 " `rounded` sets line caps and line joins to be rounded; `butt` is the",\
3387 " default, butt caps and mitered joins;",\
3388 "",\
3389 " `palfuncparam` controls how `set palette functions` are encoded as gradients",\
3390 " in the output. Analytic color component functions (set via",\
3391 " `set palette functions`) are encoded as linear interpolated gradients in the",\
3392 " postscript output:  The color component functions are sampled at <samples>",\
3393 " points and all points are removed from this gradient which can be removed",\
3394 " without changing the resulting colors by more than <maxdeviation>. For",\
3395 " almost every useful palette you may savely leave the defaults of",\
3396 " <samples>=2000 and <maxdeviation>=0.003 untouched.",\
3397 "",\
3398 " The default size for postscript output is 10 inches x 7 inches. The default",\
3399 " for eps output is 5 x 3.5 inches.  The `size` option changes this to",\
3400 " whatever the user requests. By default the X and Y sizes are taken to be in",\
3401 " inches, but other units are possibly (currently only cm). The BoundingBox",\
3402 " of the plot is correctly adjusted to contain the resized image.",\
3403 " Screen coordinates always run from 0.0 to 1.0 along the full length of the",\
3404 " plot edges as specified by the `size` option.",\
3405 " NB: `this is a change from the previously recommended method of using the",\
3406 " set size command prior to setting the terminal type`.  The old method left",\
3407 " the BoundingBox unchanged and screen coordinates did not correspond to the",\
3408 " actual limits of the plot.",\
3409 "",
3410 ""
3411 END_HELP(00psglobal)
3412
3413 START_HELP(epslatex)
3414 "1 epslatex",
3415 "?commands set terminal epslatex",
3416 "?set terminal epslatex",
3417 "?set term epslatex",
3418 "?terminal epslatex",
3419 "?term epslatex",
3420 "?epslatex",
3421 " The `epslatex` driver generates output for further processing by LaTeX.",
3422 "",
3423 " Syntax:",
3424 "       set terminal epslatex   {default}",
3425 "       set terminal epslatex   {standalone | input}",
3426 "                               {oldstyle | newstyle}",
3427 PS_COMMON_OPTS1
3428 "                               {header <header> | noheader}",
3429 PS_COMMON_OPTS2
3430 "",
3431 " The epslatex terminal prints a plot as `terminal postscript eps`",
3432 " but transfers the texts to LaTeX instead of including in the PostScript",
3433 " code. Thus, many options are the same as in the `postscript terminal`.",
3434 "",
3435 " From version 4.0 to 4.2, some changes have been invoked into the default ",
3436 " appearance of the epslatex terminal to reach better consistency with the",
3437 " postscript terminal:  The plot size has been changed from 5 x 3 inches to",
3438 " 5 x 3.5 inches;  the character width is now estimated to be 60% of the font",
3439 " size while the old epslatex terminal used 50%;  now, the larger number of",
3440 " postscript linetypes and symbols are used.  To reach an appearance that is",
3441 " nearly identical to the old one specify the option `oldstyle`. (In fact",
3442 " some small differences remain: the symbol sizes are slightly different, the",
3443 " tics are half as large as in the old terminal which can be changed using",
3444 " `set tics scale`, and the arrows have all features as in the postscript",
3445 " terminal.)",
3446 "",
3447 PS_COMMON_PROLOG_INFO
3448 PS_COMMON_DOC1
3449 " `blacktext` forces all text to be written in black even in color mode;",
3450 "",
3451 " The epslatex driver offers a special way of controlling text positioning:",
3452 " (a) If any text string begins with '{', you also need to include a '}' at the",
3453 " end of the text, and the whole text will be centered both horizontally",
3454 " and vertically by LaTeX.  (b) If the text string begins with '[', you need",
3455 " to continue it with: a position specification (up to two out of t,b,l,r,c),",
3456 " ']{', the text itself, and finally, '}'. The text itself may be anything",
3457 " LaTeX can typeset as an LR-box. \\rule{}{}'s may help for best positioning.",
3458 " See also the documentation for the `pslatex` terminal driver.",
3459 " To create multiline labels, use \\shortstack, for example",
3460 "    set ylabel '[r]{\\shortstack{first line \\\\ second line}}' ",
3461 "",
3462 " The `back` option of `set label` commands is handled slightly different",
3463 " than in other terminals. Labels using 'back' are printed behind all other",
3464 " elements of the plot while labels using 'front' are printed above ",
3465 " everything else.",
3466 "",
3467 " The driver produces two different files, one for the eps part of the figure",
3468 " and one for the LaTeX part. The name of the LaTeX file is taken from the",
3469 " `set output` command. The name of the eps file is derived by replacing",
3470 " the file extension (normally `.tex`) with `.eps` instead.  There is no",
3471 " LaTeX output if no output file is given!  Remember to close the",
3472 " `output file` before next plot unless in `multiplot` mode.",
3473 "",
3474 " In your LaTeX documents use '\\input{filename}' to include the figure.",
3475 " The `.eps` file is included by the command \\includegraphics{...}, so you",
3476 " must also include \\usepackage{graphicx} in the LaTeX preamble.  If you",
3477 " want to use coloured text (option `textcolour`) you also have to include",
3478 " \\usepackage{color} in the LaTeX preamble.",
3479 "",
3480 " Pdf files can be made from the eps file using 'epstopdf'. If the graphics",
3481 " package is properly configured, the LaTeX files can also be processed by",
3482 " pdflatex without changes, using the pdf files instead of the eps files."
3483 "",
3484 " The behaviour concerning font selection depends on the header mode.",
3485 " In all cases, the given font size is used for the calculation of proper",
3486 " spacing. When not using the `standalone` mode the actual LaTeX font and",
3487 " font size at the point of inclusion is taken, so use LaTeX commands for",
3488 " changing fonts. If you use e.g. 12pt as font size for your LaTeX",
3489 " document, use '\"\" 12' as options. The font name is ignored. If using",
3490 " `standalone` the given font and font size are used, see below for a",
3491 " detailed description.",
3492 "",
3493 " If text is printed coloured is controlled by the TeX booleans \\ifGPcolor",
3494 " and \\ifGPblacktext. Only if \\ifGPcolor is true and \\ifGPblacktext is",
3495 " false, text is printed coloured. You may either change them in the",
3496 " generated TeX file or provide them globally in your TeX file, for example",
3497 " by using",
3498 "    \\newif\\ifGPblacktext",
3499 "    \\GPblacktexttrue",
3500 " in the preamble of your document. The local assignment is only done if no",
3501 " global value is given.",
3502 "",
3503 " When using the epslatex terminal give the name of the TeX file in the",
3504 " `set output` command including the file extension (normally \".tex\").",
3505 " The eps filename is generated by replacing the extension by \".eps\".",
3506 "",
3507 " If using the `standalone` mode a complete LaTeX header is added to the",
3508 " LaTeX file; and \"-inc\" is added to the filename of the eps file.",
3509 " The `standalone` mode generates a TeX file that produces",
3510 " output with the correct size when using dvips, pdfTeX, or VTeX.",
3511 " The default, `input`, generates a file that has to be included into a",
3512 " LaTeX document using the \\input command.",
3513 "",
3514 " If a font other than \"\" or \"default\" is given it is interpreted as",
3515 " LaTeX font name.  It contains up to three parts, separated by a comma:",
3516 " 'fontname,fontseries,fontshape'.  If the default fontshape or fontseries",
3517 " are requested, they can be omitted.  Thus, the real syntax for the fontname",
3518 " is '[fontname][,fontseries][,fontshape]'.  The naming convention for all",
3519 " parts is given by the LaTeX font scheme.  The fontname is 3 to 4 characters",
3520 " long and is built as follows: One character for the font vendor, two",
3521 " characters for the name of the font, and optionally one additional",
3522 " character for special fonts, e.g., 'j' for fonts with old-style numerals",
3523 " or 'x' for expert fonts. The names of many fonts is described in",
3524 "^ <a href=\"http://www.tug.org/fontname/fontname.pdf\">",
3525 "           http://www.tug.org/fontname/fontname.pdf",
3526 "^ </a>",
3527 " For example, 'cmr' stands for Computer Modern Roman, 'ptm' for Times-Roman,",
3528 " and 'phv' for Helvetica.  The font series denotes the thickness of the",
3529 " glyphs, in most cases 'm' for normal (\"medium\") and 'bx' or 'b' for bold",
3530 " fonts.  The font shape is 'n' for upright, 'it' for italics, 'sl' for",
3531 " slanted, or 'sc' for small caps, in general.  Some fonts may provide",
3532 " different font series or shapes.",
3533 "",
3534 " Examples:",
3535 "",
3536 " Use Times-Roman boldface (with the same shape as in the surrounding text):",
3537 "       set terminal epslatex 'ptm,bx'",
3538 " Use Helvetica, boldface, italics:",
3539 "       set terminal epslatex 'phv,bx,it'",
3540 " Continue to use the surrounding font in slanted shape:",
3541 "       set terminal epslatex ',,sl'",
3542 " Use small capitals:",
3543 "       set terminal epslatex ',,sc'",
3544 "",
3545 " By this method, only text fonts are changed. If you also want to change",
3546 " the math fonts you have to use the \"gnuplot.cfg\" file or the `header`",
3547 " option, described below.",
3548 "",
3549 " In standalone mode, the font size is taken from the given font size in the",
3550 " `set terminal` command. To be able to use a specified font size, a file",
3551 " \"size<size>.clo\" has to reside in the LaTeX search path.  By default,",
3552 " 10pt, 11pt, and 12pt are supported.  If the package \"extsizes\" is",
3553 " installed, 8pt, 9pt, 14pt, 17pt, and 20pt are added.",
3554 "",
3555 " The `header` option takes a string as argument.  This string is written",
3556 " into the generated LaTeX file.  If using the `standalone` mode, it is ",
3557 " written into the preamble, directly before the \\begin{document} command.",
3558 " In the `input` mode, it is placed directly after the \\begingroup command",
3559 " to ensure that all settings are local to the plot.",
3560 "",
3561 " Examples:",
3562 "",
3563 " Use T1 fontencoding, change the text and math font to Times-Roman as well",
3564 " as the sans-serif font to Helvetica:",
3565 "     set terminal epslatex standalone header \\",
3566 "     \"\\\\usepackage[T1]{fontenc}\\n\\\\usepackage{mathptmx}\\n\\\\usepackage{helvet}\"",
3567 " Use a boldface font in the plot, not influencing the text outside the plot:",
3568 "     set terminal epslatex input header \"\\\\bfseries\"",
3569 "",
3570 " If the file \"gnuplot.cfg\" is found by LaTeX it is input in the preamble",
3571 " the LaTeX document, when using `standalone` mode.  It can be used for",
3572 " further settings, e.g., changing the document font to Times-Roman,",
3573 " Helvetica, and Courier, including math fonts (handled by \"mathptmx.sty\"):",
3574 "       \\usepackage{mathptmx}",
3575 "       \\usepackage[scaled=0.92]{helvet}",
3576 "       \\usepackage{courier}",
3577 " The file \"gnuplot.cfg\" is loaded before the header information given",
3578 " by the `header` command.  Thus, you can use `header` to overwrite some of",
3579 " settings performed using \"gnuplot.cfg\"",
3580 ""
3581 END_HELP(epslatex)
3582
3583 START_HELP(pslatex)
3584 "1 pslatex and pstex",
3585 "?commands set terminal pslatex",
3586 "?set terminal pslatex",
3587 "?set term pslatex",
3588 "?terminal pslatex",
3589 "?term pslatex",
3590 "?pslatex",
3591 "?commands set terminal pstex",
3592 "?set terminal pstex",
3593 "?set term pstex",
3594 "?terminal pstex",
3595 "?term pstex",
3596 "?pstex",
3597 " The `pslatex` driver generates output for further processing by LaTeX,",
3598 " while the `pstex` driver generates output for further processing by",
3599 " TeX. `pslatex` uses \\specials understandable by dvips and xdvi. Figures",
3600 " generated by `pstex` can be included in any plain-based format (including",
3601 " LaTeX).",
3602 "",
3603 " Syntax:",
3604 "       set terminal [pslatex | pstex] {default}",
3605 "       set terminal [pslatex | pstex]",
3606 "                               {rotate | norotate}",
3607 "                               {oldstyle | newstyle}",
3608 "                               {auxfile | noauxfile}",
3609 PS_COMMON_OPTS1
3610 "                               {<font_size>}",
3611 "",
3612 PS_COMMON_PROLOG_INFO
3613 PS_COMMON_DOC1
3614 " if `rotate` is specified, the y-axis label is rotated.",
3615 " <font_size> is the size (in pts) of the desired font.",
3616 "",
3617 " If `auxfile` is specified, it directs the driver to put the PostScript",
3618 " commands into an auxiliary file instead of directly into the LaTeX file.",
3619 " This is useful if your pictures are large enough that dvips cannot handle",
3620 " them.  The name of the auxiliary PostScript file is derived from the name of",
3621 " the TeX file given on the `set output` command; it is determined by replacing",
3622 " the trailing `.tex` (actually just the final extent in the file name) with",
3623 " `.ps` in the output file name, or, if the TeX file has no extension, `.ps`",
3624 " is appended.  The `.ps` is included into the `.tex` file by a",
3625 " \\special{psfile=...} command.  Remember to close the `output file` before",
3626 " next plot unless in `multiplot` mode.",
3627 "",
3628 " Gnuplot versions prior version 4.2 have generated plots of the size",
3629 " 5 x 3 inches using the ps(la)tex terminal while the current version generates",
3630 " 5 x 3.5 inches to be consistent with the postscript eps terminal.  In",
3631 " addition, the character width is now estimated to be 60% of the font size",
3632 " while the old epslatex terminal used 50%. To reach the old format specify",
3633 " the option `oldstyle`.",
3634 "",
3635 " The pslatex driver offers a special way of controlling text positioning: ",
3636 " (a) If any text string begins with '{', you also need to include a '}' at the",
3637 " end of the text, and the whole text will be centered both horizontally",
3638 " and vertically by LaTeX.  (b) If the text string begins with '[', you need",
3639 " to continue it with: a position specification (up to two out of t,b,l,r),",
3640 " ']{', the text itself, and finally, '}'. The text itself may be anything",
3641 " LaTeX can typeset as an LR-box. \\rule{}{}'s may help for best positioning.",
3642 "",
3643 " The options not described here are identical to the `Postscript terminal`.",
3644 " Look there if you want to know what they do.",
3645 "",
3646 " Examples:",
3647 "       set term pslatex monochrome dashed rotate       # set to defaults",
3648 " To write the PostScript commands into the file \"foo.ps\":",
3649 "       set term pslatex auxfile",
3650 "       set output \"foo.tex\"; plot ...; set output",
3651 " About label positioning:",
3652 " Use gnuplot defaults (mostly sensible, but sometimes not really best):",
3653 "        set title '\\LaTeX\\ -- $ \\gamma $'",
3654 " Force centering both horizontally and vertically:",
3655 "        set label '{\\LaTeX\\ -- $ \\gamma $}' at 0,0",
3656 " Specify own positioning (top here):",
3657 "        set xlabel '[t]{\\LaTeX\\ -- $ \\gamma $}'",
3658 " The other label -- account for long ticlabels:",
3659 "        set ylabel '[r]{\\LaTeX\\ -- $ \\gamma $\\rule{7mm}{0pt}}'",
3660 "",
3661 " Linewidths and pointsizes may be changed with `set style line`."
3662 ""
3663 END_HELP(pslatex)
3664
3665 START_HELP(post)
3666 "1 postscript",
3667 "?commands set terminal postscript",
3668 "?set terminal postscript",
3669 "?set term postscript",
3670 "?terminal postscript",
3671 "?term postscript",
3672 "?postscript",
3673 " Several options may be set in the `postscript` driver.",
3674 "",
3675 " Syntax:",
3676 "       set terminal postscript {default}",
3677 "       set terminal postscript {landscape | portrait | eps}",
3678 "                               {enhanced | noenhanced}",
3679 "                               {defaultplex | simplex | duplex}",
3680 "                               {fontfile [add | delete] \"<filename>\"",
3681 "                                | nofontfiles}",
3682 PS_COMMON_OPTS1
3683 PS_COMMON_OPTS2
3684 PS_COMMON_PROLOG_INFO
3685 "",
3686 " `landscape` and `portrait` choose the plot orientation.",
3687 " `eps` mode generates EPS (Encapsulated PostScript) output, which is just",
3688 " regular PostScript with some additional lines that allow the file to be",
3689 " imported into a variety of other applications.  (The added lines are",
3690 " PostScript comment lines, so the file may still be printed by itself.)  To",
3691 " get EPS output, use the `eps` mode and make only one plot per file.  In `eps`",
3692 " mode the whole plot, including the fonts, is reduced to half of the default",
3693 " size.",
3694 "",
3695 " `enhanced` enables enhanced text mode features (subscripts,",
3696 " superscripts and mixed fonts). See `enhanced` for more information.",
3697 " `blacktext` forces all text to be written in black even in color mode;",
3698 "",
3699 " Duplexing in PostScript is the ability of the printer to print on both",
3700 " sides of the same sheet of paper.  With `defaultplex`, the default setting",
3701 " of the printer is used; with `simplex` only one side is printed; `duplex`",
3702 " prints on both sides (ignored if your printer can't do it).",
3703 "",
3704 " `\"<fontname>\"` is the name of a valid PostScript font; and `<fontsize>` is",
3705 " the size of the font in PostScript points.",
3706 " In addition to the standard postscript fonts, an oblique version of the",
3707 " Symbol font, useful for mathematics, is defined. It is called",
3708 " \"Symbol-Oblique\".",
3709 "",
3710 " `default` sets all options to their defaults: `landscape`, `monochrome`,",
3711 " `dashed`, `dl 1.0`, `lw 1.0`, `defaultplex`, `noenhanced`, \"Helvetica\" and",
3712 " 14pt.  Default size of a PostScript plot is 10 inches wide and 7 inches high.",
3713 PS_COMMON_DOC1
3714 " Fonts listed by `fontfile` or `fontfile add` encapsulate the font",
3715 " definitions of the listed font from a postscript Type 1 or TrueType font",
3716 " file directly into the gnuplot output postscript file.  Thus, the enclosed",
3717 " font can be used in labels, titles, etc.  See the section",
3718 " `postscript fontfile` for more details.  With `fontfile delete`, a fontfile",
3719 " is deleted from the list of embedded files.  `nofontfiles` cleans the list",
3720 " of embedded fonts.",
3721 "",
3722 " Examples:",
3723 "       set terminal postscript default       # old postscript",
3724 "       set terminal postscript enhanced      # old enhpost",
3725 "       set terminal postscript landscape 22  # old psbig",
3726 "       set terminal postscript eps 14        # old epsf1",
3727 "       set terminal postscript eps 22        # old epsf2",
3728 "       set size 0.7,1.4; set term post portrait color \"Times-Roman\" 14",
3729 "       set term post \"VAGRoundedBT_Regular\" 14 fontfile \"bvrr8a.pfa\"",
3730 "",
3731 " Linewidths and pointsizes may be changed with `set style line`.",
3732 "",
3733 " The `postscript` driver supports about 70 distinct pointtypes, selectable",
3734 " through the `pointtype` option on `plot` and `set style line`.",
3735 "",
3736 " Several possibly useful files about `gnuplot`'s PostScript are included",
3737 " in the /docs/psdoc subdirectory of the `gnuplot` distribution and at the",
3738 " distribution sites.  These are \"ps_symbols.gpi\" (a `gnuplot` command file",
3739 " that, when executed, creates the file \"ps_symbols.ps\" which shows all the",
3740 " symbols available through the `postscript` terminal), \"ps_guide.ps\" (a",
3741 " PostScript file that contains a summary of the enhanced syntax and a page",
3742 " showing what the octal codes produce with text and symbol fonts),",
3743 " \"ps_file.doc\" (a text file that contains a discussion of the organization",
3744 " of a PostScript file written by `gnuplot`), and \"ps_fontfile_doc.tex\"",
3745 " (a LaTeX file which contains a short documentation concerning the",
3746 " encapsulation of LaTeX fonts with a glyph table of the math fonts).",
3747 "",
3748 " A PostScript file is editable, so once `gnuplot` has created one, you are",
3749 " free to modify it to your heart's desire.  See the `editing postscript`",
3750 " section for some hints.",
3751 "2 enhanced postscript",
3752 "?commands set terminal postscript enhanced",
3753 "?set terminal postscript enhanced",
3754 "?set term postscript enhanced",
3755 "?terminal postscript enhanced",
3756 "?term postscript enhanced",
3757 "?enhanced_postscript",
3758 "?enhanced postscript",
3759 "?Enhanced postscript",
3760 "?enhanced text",
3761 "?Enhanced text",
3762 "?enhanced",
3763 " Several terminal types support an enhanced text mode in which ",
3764 " additional formatting information is embedded in the text string.",
3765 "",
3766 "@start table - first is interactive cleartext form",
3767 "  Control      Examples        Explanation",
3768 "   ^           a^x             superscript",
3769 "   _           a_x             subscript",
3770 "   @           @x or a@^b_c    phantom box (occupies no width)",
3771 "   &           &{space}        inserts space of specified length",
3772 "   ~           ~a{.8-}         overprints '-' on 'a', raised by .8",
3773 "                               times the current fontsize",
3774 "#\\begin{tabular}{|ccl|} \\hline",
3775 "#\\multicolumn{3}{|c|}{Enhanced Text Control Codes} \\\\ \\hline",
3776 "#Control & Examples & Explanation \\\\ \\hline",
3777 "#\\verb~^~ & \\verb~a^x~ & superscript\\\\",
3778 "#\\verb~_~ & \\verb~a_x~ & subscript\\\\",
3779 "#\\verb~@~ & \\verb~@x or a@^b_c~ & phantom box (occupies no width)\\\\",
3780 "#\\verb~&~ & \\verb~&{space}~ & inserts space of specified length\\\\",
3781 "#\\verb|~| & \\verb|~a{.8-}| & overprints '-' on 'a', raised by .8\\\\",
3782 "#\\verb~ ~ & \\verb~ ~ & times the current fontsize\\\\",
3783 "%c c l .",
3784 "%.TE", /* ugly - doc2ms uses @ for column separator, but here we */
3785 "%.TS", /* need @ in table, so end and restart the table ! */
3786 "%center box tab ($) ;",
3787 "%c c l .",
3788 "%Control$Examples$Explanation",
3789 "%_",
3790 "%^$a^x$superscript",
3791 "%\\&_$a\\&_x$subscript",
3792 "% @ $ @x or a\\&@^b\\&_c$phantom box (occupies no width)",
3793 "% & $ &{space}$inserts space of specified length",
3794 "% ~ $ ~a{.8-}$overprints '-' on 'a', raised by .8",
3795 "%   $   $times the current fontsize",
3796 "@end table",
3797 "",
3798 " Braces can be used to place multiple-character text where a single character",
3799 " is expected (e.g., 2^{10}).  To change the font and/or size, use the full",
3800 " form:  {/[fontname][=fontsize | *fontscale] text}.  Thus {/Symbol=20 G} is a",
3801 " 20-point GAMMA and {/*0.75 K} is a K at three-quarters of whatever fontsize",
3802 " is currently in effect.  (The '/' character MUST be the first character after",
3803 " the '{'.)",
3804 "",
3805 " If the encoding vector has been changed by `set encoding`, the default",
3806 " encoding vector can be used instead by following the slash with a dash.  This",
3807 " is unnecessary if you use the Symbol font, however---since /Symbol uses its",
3808 " own encoding vector, `gnuplot` will not apply any other encoding vector to",
3809 " it.",
3810 "",
3811 " The phantom box is useful for a@^b_c to align superscripts and subscripts",
3812 " but does not work well for overwriting an accent on a letter.  (To do the",
3813 " latter, it is much better to use 'set encoding iso_8859_1' to change to the",
3814 " ISO Latin-1 encoding vector, which contains a large variety of letters with",
3815 " accents or other diacritical marks.)  Since the box is non-spacing, it is",
3816 " sensible to put the shorter of the subscript or superscript in the box (that",
3817 " is, after the @).",
3818 "",
3819 " Space equal in length to a string can be inserted using the '&' character.",
3820 " Thus",
3821 "         'abc&{def}ghi'",
3822 " would produce",
3823 "         'abc   ghi'.",
3824 "",
3825 " The '~' character causes the next character or bracketed text to be",
3826 " overprinted by the following character or bracketed text.  The second text",
3827 " will be horizontally centered on the first.  Thus '~a/' will result in an 'a'",
3828 " with a slash through it.  You can also shift the second text vertically by",
3829 " preceding the second text with a number, which will define the fraction of the",
3830 " current fontsize by which the text will be raised or lowered.  In this case",
3831 " the number and text must be enclosed in brackets because more than one",
3832 " character is necessary.  If the overprinted text begins with a number, put a",
3833 " space between the vertical offset and the text ('~{abc}{.5 000}'); otherwise",
3834 " no space is needed ('~{abc}{.5---}').  You can change the font for one or",
3835 " both strings ('~a{.5 /*.2 o}'---an 'a' with a one-fifth-size 'o' on top---and",
3836 " the space between the number and the slash is necessary), but you can't",
3837 " change it after the beginning of the string.  Neither can you use any other",
3838 " special syntax within either string.  You can, of course, use control",
3839 " characters by escaping them (see below), such as '~a{\\^}'",
3840 "",
3841 " You can access special symbols numerically by specifying \\character-code (in",
3842 " octal), e.g., {/Symbol \\245} is the symbol for infinity.",
3843 "",
3844 " You can escape control characters using \\, e.g.,  \\\\, \\{, and so on.",
3845 "",
3846 " But be aware that strings in double-quotes are parsed differently than those",
3847 " enclosed in single-quotes.  The major difference is that backslashes may need",
3848 " to be doubled when in double-quoted strings.",
3849 "",
3850 " Examples (these are hard to describe in words---try them!):",
3851 "       set xlabel 'Time (10^6 {/Symbol m}s)'",
3852 "       set title '{/Symbol=18 \\362@_{/=9.6 0}^{/=12 x}} \\",
3853 "                  {/Helvetica e^{-{/Symbol m}^2/2} d}{/Symbol m}'",
3854 "",
3855 " The file \"ps_guide.ps\" in the /docs/psdoc subdirectory of the `gnuplot` source",
3856 " distribution contains more examples of the enhanced syntax.",
3857 "2 editing postscript",
3858 "?commands set terminal postscript editing",
3859 "?set terminal postscript editing",
3860 "?set term postscript editing",
3861 "?terminal postscript editing",
3862 "?term postscript editing",
3863 "?editing_postscript",
3864 "?editing postscript",
3865 " The PostScript language is a very complex language---far too complex to",
3866 " describe in any detail in this document.  Nevertheless there are some things",
3867 " in a PostScript file written by `gnuplot` that can be changed without risk of",
3868 " introducing fatal errors into the file.",
3869 "",
3870 " For example, the PostScript statement \"/Color true def\" (written into the",
3871 " file in response to the command `set terminal postscript color`), may be",
3872 " altered in an obvious way to generate a black-and-white version of a plot.",
3873 " Similarly line colors, text colors, line weights and symbol sizes can also be",
3874 " altered in straight-forward ways.  Text (titles and labels) can be edited to",
3875 " correct misspellings or to change fonts.  Anything can be repositioned, and",
3876 " of course anything can be added or deleted, but modifications such as these",
3877 " may require deeper knowledge of the PostScript language.",
3878 "",
3879 " The organization of a PostScript file written by `gnuplot` is discussed in",
3880 " the text file \"ps_file.doc\" in the docs/ps subdirectory of the gnuplot",
3881 " source distribution.",
3882 "2 postscript fontfile",
3883 "?commands set terminal postscript fontfile",
3884 "?set terminal postscript fontfile",
3885 "?set term postscript fontfile",
3886 "?terminal postscript fontfile",
3887 "?term postscript fontfile",
3888 "?postscript fontfile",
3889 "?fontfile",
3890 " The `fontfile` or `fontfile add` option takes one file name as argument",
3891 " and encapsulates this file into the postscript output in order to make",
3892 " this font available for text elements (labels, tic marks, titles, etc.).",
3893 " The `fontfile delete` option also takes one file name as argument. It",
3894 " deletes this file name from the list of encapsulated files.",
3895 "",
3896 " The postscript terminal understands some",
3897 " font file formats: Type 1 fonts in ASCII file format (extension \".pfa\"),",
3898 " Type 1 fonts in binary file format (extension \".pfb\"), and TrueType",
3899 " fonts (extension \".ttf\"). Pfa files are understood directly, pfb and ttf",
3900 " files are converted on the fly if appropriate conversion tools are",
3901 " installed (see below). You have to specify the full filename including the",
3902 " extension. Each `fontfile` option takes exact one font file name. This",
3903 " option can be used multiple times in order to include more than one font",
3904 " file.",
3905 "",
3906 " The font file is searched in the working directory and in all directories",
3907 " listed in the fontpath which is determined by `set fontpath`.",
3908 " In addition, the fontpath can be set using the environment variable",
3909 " GNUPLOT_FONTPATH. If this is not set a system dependent default search",
3910 " list is used. See `set fontpath` for more details.",
3911 "",
3912 " For using the encapsulated font file you have to specify the font name",
3913 " (which normally is not the same as the file name). When embedding a",
3914 " font file by using the `fontfile` option in interactive mode, the ",
3915 " font name is printed on the screen. E.g.",
3916 "    Font file 'p052004l.pfb' contains the font 'URWPalladioL-Bold'. Location:",
3917 "    /usr/lib/X11/fonts/URW/p052004l.pfb",
3918 "",
3919 " When using pfa or pfb fonts, you can also find it out by looking into the",
3920 " font file. There is a line similar to \"/FontName /URWPalladioL-Bold def\".",
3921 " The middle string without the slash is the fontname, here",
3922 " \"URWPalladioL-Bold\".",
3923 " For TrueType fonts, this is not so easy since the font name is stored in a",
3924 " binary format. In addition, they often have spaces in the font names which",
3925 " is not supported by Type 1 fonts (in which a TrueType is converted on the",
3926 " fly). The font names are changed in order to eliminate the spaces in the",
3927 " fontnames. The easiest way to find out which font name is generated for",
3928 " use with gnuplot, start gnuplot in interactive mode and type in",
3929 " \"set terminal postscript fontfile '<filename.ttf>'\".",
3930 "",
3931 " For converting font files (either ttf or pfb) to pfa format, the conversion",
3932 " tool has to read the font from a file and write it to standard output. If",
3933 " the output cannot be written to standard output, on-the-fly conversion is",
3934 " not possible.",
3935 "",
3936 " For pfb files \"pfbtops\" is a tool which can do this. If this program",
3937 " is installed on your system the on the fly conversion should work.",
3938 " Just try to encapsulate a pfb file. If the compiled in program call does",
3939 " not work correctly you can specify how this program is called by",
3940 " defining the environment variable GNUPLOT_PFBTOPFA e.g. to",
3941 " \"pfbtops %s\". The `%s` will be replaced by the font file name and thus",
3942 " has to exist in the string.",
3943 "",
3944 " If you don't want to do the conversion on the fly but get a pfa file of",
3945 " the font you can use the tool \"pfb2pfa\" which is written in simple c",
3946 " and should compile with any c compiler.",
3947 " It is available from many ftp servers, e.g.",
3948 "^ <a href=\"ftp://ftp.dante.de/tex-archive/fonts/utilities/ps2mf/\">",
3949 "           ftp://ftp.dante.de/tex-archive/fonts/utilities/ps2mf/",
3950 "^ </a>",
3951 " In fact, \"pfbtopfa\" and \"pfb2ps\" do the same job. \"pfbtopfa\" puts",
3952 " the resulting pfa code into a file, whereas \"pfbtops\" writes it to",
3953 " standard output.",
3954 "",
3955 " TrueType fonts are converted into Type 1 pfa format, e.g.",
3956 " by using the tool \"ttf2pt1\" which is available from",
3957 "^ <a href=\"http://ttf2pt1.sourceforge.net/\">",
3958 "           http://ttf2pt1.sourceforge.net/",
3959 "^ </a>",
3960 " If the builtin conversion does not",
3961 " work, the conversion command can be changed by the environment variable",
3962 " GNUPLOT_TTFTOPFA. For usage with ttf2pt1 it may be set to",
3963 " \"ttf2pt1 -a -e -W 0 %s - \". Here again, `%s` stands for the",
3964 " file name.",
3965 "",
3966 " For special purposes you also can use a pipe (if available for your",
3967 " operating system). Therefore you start the file name definition with ",
3968 " the character \"<\" and append a program call. This program has ",
3969 " to write pfa data to standard output. Thus, a pfa file may be accessed",
3970 " by `set fontfile \"< cat garamond.pfa\"`.",
3971 "",
3972 " For example, including Type 1 font files can be used for including the",
3973 " postscript output in LaTeX documents. The \"european computer modern\"",
3974 " font (which is a variant of the \"computer modern\" font) is available",
3975 " in pfb format from any CTAN server, e.g.",
3976 "^ <a href=\"ftp://ftp.dante.de/tex-archive/fonts/ps-type1/cm-super/\">",
3977 "           ftp://ftp.dante.de/tex-archive/fonts/ps-type1/cm-super/",
3978 "^ </a>",
3979 " For example, the file \"sfrm1000.pfb\" contains the normal upright fonts",
3980 " with serifs in the design size 10pt (font name \"SFRM1000\").",
3981 " The computer modern fonts, which are still necessary for mathematics,",
3982 " are available from",
3983 "^ <a href=\"ftp://ftp.dante.de/tex-archive/fonts/cm/ps-type1/bluesky\">",
3984 "           ftp://ftp.dante.de/tex-archive/fonts/cm/ps-type1/bluesky",
3985 "^ </a>",
3986 " With these you can use any character available in TeX. However, the",
3987 " computer modern fonts have a strange encoding. (This is why you should not",
3988 " use cmr10.pfb for text, but sfrm1000.pfb instead.)",
3989 " The usage of TeX fonts is shown in one of the demos.",
3990 " The file \"ps_fontfile_doc.tex\" in the /docs/psdoc subdirectory of the",
3991 " `gnuplot` source distribution contains a table with glyphs of the TeX",
3992 " mathfonts.",
3993 "",
3994 " If the font \"CMEX10\" is embedded (file \"cmex10.pfb\") gnuplot defines",
3995 " the additional font \"CMEX10-Baseline\". It is shifted vertically in order",
3996 " to fit better to the other glyphs (CMEX10 has its baseline at the top of",
3997 " the symbols).",
3998 "2 postscript prologue",
3999 "?commands set terminal postscript prologue",
4000 "?set terminal postscript prologue",
4001 "?terminal postscript prologue",
4002 "?postscript prologue",
4003 "?prologue",
4004 " Each PostScript output file includes a %%Prolog section and possibly some",
4005 " additional user-defined sections containing, for example, character",
4006 " encodings. These sections are copied from a set of PostScript prologue files",
4007 " which are either compiled in the gnuplot executable or stored elsewhere on your",
4008 " computer. This behaviour and the default directory where these files live are",
4009 " controlled at the time gnuplot is built. However, you can control this",
4010 " either by defining an environment variable GNUPLOT_PS_DIR or by using the",
4011 " gnuplot command `set loadpath`. See `set loadpath`.",
4012 "",
4013 ""
4014 END_HELP(post)
4015 #endif /* TERM_HELP */