1 /*
2  *  gretl -- Gnu Regression, Econometrics and Time-series Library
3  *  Copyright (C) 2001 Allin Cottrell and Riccardo "Jack" Lucchetti
4  *
5  *  This program is free software: you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation, either version 3 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19 
20 #include "gretl.h"
21 #include "graph_page.h"
22 #include "session.h"
23 #include "gpt_control.h"
24 #include "texprint.h"
25 #include "guiprint.h"
26 
27 #ifdef G_OS_WIN32
28 # include <io.h>
29 # include "gretlwin32.h"
30 #else
31 # include <unistd.h>
32 # include <sys/stat.h>
33 #endif
34 
35 #define GRAPHS_MAX 8
36 
37 typedef struct _graphpage graphpage;
38 
39 struct _graphpage {
40     int term;
41     int mono;
42     int ngraphs;
43     char **fnames;
44 };
45 
46 static graphpage gpage;
47 static char gpage_base[FILENAME_MAX];
48 static char gpage_tex_base[FILENAME_MAX];
49 
gpage_filenames_init(const char * base)50 static void gpage_filenames_init (const char *base)
51 {
52     if (base == NULL) {
53 	strcpy(gpage_base, gretl_dotdir());
54 	strcat(gpage_base, "gretl_graphpage");
55 	strcpy(gpage_tex_base, "gretl_graphpage");
56     } else {
57 	const char *p;
58 
59 	strcpy(gpage_base, base);
60 	if (has_suffix(gpage_base, ".tex") ||
61 	    has_suffix(gpage_base, ".pdf") ||
62 	    has_suffix(gpage_base, ".eps")) {
63 	    gpage_base[strlen(gpage_base) - 4] = '\0';
64 	} else if (has_suffix(gpage_base, ".ps")) {
65 	    gpage_base[strlen(gpage_base) - 3] = '\0';
66 	}
67 	p = path_last_slash_const(gpage_base);
68 	if (p != NULL) {
69 	    strcpy(gpage_tex_base, p + 1);
70 	} else {
71 	    strcpy(gpage_tex_base, gpage_base);
72 	}
73     }
74 }
75 
gpage_fname(const char * ext,int i)76 static char *gpage_fname (const char *ext, int i)
77 {
78     static char fname[MAXLEN];
79     char num[12];
80     int n = strlen(gpage_base);
81 
82     fname[0] = num[0] = '\0';
83 
84     if (i > 0) {
85 	sprintf(num, "_%d", i);
86 	n += strlen(num);
87     }
88 
89     if (ext != NULL) {
90 	n += strlen(ext);
91     }
92 
93     if (n < MAXLEN) {
94 	strcpy(fname, gpage_base);
95 	if (num[0] != '\0') {
96 	    strcat(fname, num);
97 	}
98 	if (ext != NULL) {
99 	    strcat(fname, ext);
100 	}
101     }
102 
103     return fname;
104 }
105 
gpage_errmsg(char * msg,int gui)106 static void gpage_errmsg (char *msg, int gui)
107 {
108     if (gui) {
109 	errbox(msg);
110     } else {
111 	gretl_errmsg_set(msg);
112     }
113 }
114 
graph_page_init(void)115 static void graph_page_init (void)
116 {
117     gpage.mono = 0;
118     gpage.ngraphs = 0;
119     gpage.fnames = NULL;
120 }
121 
doctop(FILE * fp)122 static void doctop (FILE *fp)
123 {
124     const char *paper = in_usa()? "letterpaper" : "a4paper";
125     const char *driver = "pdftex";
126 
127     if (gpage.term == GP_TERM_EPS) {
128 	driver = "dvips";
129     }
130 
131     fprintf(fp, "\\documentclass[%s]{article}\n", paper);
132     fprintf(fp, "\\usepackage[%s]{graphicx}\n", driver);
133 }
134 
135 /* A4 is 210mm * 297mm */
136 
geomline(int ng,FILE * fp)137 static int geomline (int ng, FILE *fp)
138 {
139     double width = 7.0, height = 10.0;
140     double tmarg = 0.5, lmarg = 0.75;
141     char unit[3];
142 
143     if (in_usa()) {
144 	strcpy(unit, "in");
145     } else {
146 	strcpy(unit, "mm");
147 	width = 190;
148 	height = 277.0;
149 	tmarg = lmarg = 10.0;
150     }
151 
152     gretl_push_c_numeric_locale();
153 
154     fprintf(fp, "\\usepackage[body={%g%s,%g%s},"
155 	    "top=%g%s,left=%g%s,nohead]{geometry}\n\n",
156 	    width, unit, height, unit,
157 	    tmarg, unit, lmarg, unit);
158 
159     gretl_pop_c_numeric_locale();
160 
161     return 0;
162 }
163 
common_setup(FILE * fp)164 static void common_setup (FILE *fp)
165 {
166     fputs("\\begin{document}\n\n"
167 	  "\\thispagestyle{empty}\n\n"
168 	  "\\vspace*{\\stretch{1}}\n\n"
169 	  "\\begin{center}\n", fp);
170 }
171 
oddgraph(int ng,int i)172 static int oddgraph (int ng, int i)
173 {
174     return (ng % 2) && (i == ng - 1);
175 }
176 
177 enum {
178     SCALE_LARGE,
179     SCALE_REGULAR,
180     SCALE_MEDIUM,
181     SCALE_SMALL
182 };
183 
tex_graph_setup(int ng,FILE * fp)184 static int tex_graph_setup (int ng, FILE *fp)
185 {
186     double scale[] = { 1.2, 1.0, 0.9, 0.85 };
187     double s, vspace = 1.0;
188     int i;
189 
190     if (ng > GRAPHS_MAX) {
191 	fprintf(stderr, "ng (%d) out of range\n", ng);
192 	return 1;
193     }
194 
195     gretl_push_c_numeric_locale();
196 
197     if (ng == 1) {
198 	s = scale[SCALE_LARGE];
199 	fprintf(fp, "\\includegraphics[scale=%g]{%s_1}\n", s, gpage_tex_base);
200     } else if (ng == 2) {
201 	s = scale[SCALE_REGULAR];
202 	fprintf(fp, "\\includegraphics[scale=%g]{%s_1}\n\n", s, gpage_tex_base);
203 	fprintf(fp, "\\vspace{%gin}\n\n", vspace);
204 	fprintf(fp, "\\includegraphics{%s_2}\n\n", gpage_tex_base);
205     } else if (ng == 3) {
206 	s = scale[SCALE_MEDIUM];
207 	vspace = 0.25;
208 	for (i=0; i<3; i++) {
209 	    fprintf(fp, "\\includegraphics[scale=%g]{%s_%d}\n\n", s,
210 		    gpage_tex_base, i + 1);
211 	    fprintf(fp, "\\vspace{%gin}\n", vspace);
212 	}
213     } else {
214 	if (ng > 6) {
215 	    s = scale[SCALE_SMALL];
216 	    vspace = 0.20;
217 	} else {
218 	    s = scale[SCALE_MEDIUM];
219 	    vspace = 0.25;
220 	}
221 	fputs("\\begin{tabular}{cc}\n", fp);
222 	for (i=0; i<ng; i++) {
223 	    if (oddgraph(ng, i)) {
224 		fprintf(fp, "\\multicolumn{2}{c}{\\includegraphics[scale=%g]{%s_%d}}",
225 			s, gpage_tex_base, i + 1);
226 	    } else {
227 		fprintf(fp, "\\includegraphics[scale=%g]{%s_%d}", s,
228 			gpage_tex_base, i + 1);
229 		if (i % 2 == 0) {
230 		    fputs(" &\n  ", fp);
231 		} else if (i < ng - 1) {
232 		    fprintf(fp, " \\\\ [%gin]\n", vspace);
233 		}
234 	    }
235 	}
236 	fputs("\\end{tabular}\n", fp);
237     }
238 
239     gretl_pop_c_numeric_locale();
240 
241     return 0;
242 }
243 
common_end(FILE * fp)244 static void common_end (FILE *fp)
245 {
246     fputs("\\end{center}\n\n"
247 	  "\\vspace*{\\stretch{2}}\n\n"
248 	  "\\end{document}\n", fp);
249 }
250 
make_graphpage_tex(void)251 static int make_graphpage_tex (void)
252 {
253     char *fname;
254     FILE *fp;
255     int err = 0;
256 
257     fname = gpage_fname(".tex", 0);
258 
259     fp = gretl_fopen(fname, "w");
260     if (fp == NULL) {
261 	return 1;
262     }
263 
264     doctop(fp);
265 
266     err = geomline(gpage.ngraphs, fp);
267 
268     if (!err) {
269 	common_setup(fp);
270 	err = tex_graph_setup(gpage.ngraphs, fp);
271     }
272 
273     if (!err) {
274 	common_end(fp);
275     }
276 
277     fclose(fp);
278 
279     return err;
280 }
281 
graph_page_add_file(const char * fname)282 int graph_page_add_file (const char *fname)
283 {
284     char **fnames;
285     int ng = gpage.ngraphs + 1;
286 
287     if (ng > GRAPHS_MAX) {
288 	gpage_errmsg(_("The graph page is full"), 1);
289 	return 1;
290     }
291 
292     fnames = myrealloc(gpage.fnames, ng * sizeof *fnames);
293     if (fnames == NULL) {
294 	return E_ALLOC;
295     }
296 
297     fnames[ng - 1] = g_strdup(fname);
298     gpage.fnames = fnames;
299     gpage.ngraphs = ng;
300 
301     mark_session_changed();
302 
303     return 0;
304 }
305 
in_graph_page(const char * fname)306 int in_graph_page (const char *fname)
307 {
308     int i;
309 
310     for (i=0; i<gpage.ngraphs; i++) {
311 	if (!strcmp(fname, gpage.fnames[i])) {
312 	    return 1;
313 	}
314     }
315 
316     return 0;
317 }
318 
graph_page_add_last_graph(void)319 static int graph_page_add_last_graph (void)
320 {
321     const char *fname = last_session_graph_name();
322     int err = 0;
323 
324     if (fname != NULL && *fname != '\0') {
325 	if (!in_graph_page(fname)) {
326 	    err = graph_page_add_file(fname);
327 	}
328     }
329 
330     return err;
331 }
332 
gnuplot_compile(const char * fname)333 static int gnuplot_compile (const char *fname)
334 {
335     const char *gnuplot = gretl_gnuplot_path();
336     gchar *plotcmd;
337     int err = 0;
338 
339 #ifdef G_OS_WIN32
340     plotcmd = g_strdup_printf("\"%s\" \"%s\"", gnuplot, fname);
341 #else
342     plotcmd = g_strdup_printf("%s \"%s\"", gnuplot, fname);
343 #endif
344 
345     err = gretl_spawn(plotcmd);
346     g_free(plotcmd);
347 
348     return err;
349 }
350 
351 static double gp_fontscale = 1.0;
352 
graph_page_set_font_scale(const char * s)353 static int graph_page_set_font_scale (const char *s)
354 {
355     double x;
356 
357     s += strspn(s, " ");
358     x = dot_atof(s);
359 
360     if (x > 0.0 && x < 4.0) {
361 	gp_fontscale = x;
362 	return 0;
363     } else {
364 	gretl_errmsg_sprintf("'%s': invalid fontscale", s);
365 	return E_DATA;
366     }
367 }
368 
gp_cairo_fontsize(void)369 static int gp_cairo_fontsize (void)
370 {
371     int basesize = 10; /* or 12? */
372     int fontsize;
373 
374     if (gp_fontscale != 1.0) {
375 	fontsize = basesize * gp_fontscale;
376 	if (fontsize < 4) {
377 	    fontsize = 4;
378 	}
379     } else {
380 	fontsize = basesize;
381     }
382 
383     return fontsize;
384 }
385 
gp_make_outfile(const char * gfname,int i,double scale)386 static int gp_make_outfile (const char *gfname, int i, double scale)
387 {
388     char *fname;
389     FILE *fp, *fq;
390     int err = 0;
391 
392     fp = gretl_fopen(gfname, "rb");
393     if (fp == NULL) {
394 	file_read_errbox(gfname);
395 	return E_FOPEN;
396     }
397 
398     fname = gpage_fname(".plt", 0);
399 
400     fq = gretl_fopen(fname, "wb");
401     if (fq == NULL) {
402 	file_write_errbox(fname);
403 	fclose(fp);
404 	return E_FOPEN;
405     }
406 
407     gretl_push_c_numeric_locale();
408 
409     /* FIXME: is "dashed" wanted when "mono" is given below? */
410 
411     if (gpage.term == GP_TERM_PDF) {
412 	/* PDF output */
413 	int fontsize = gp_cairo_fontsize();
414 
415 	fprintf(fq, "set term pdfcairo font \"sans,%d\"%s", fontsize,
416 		(gpage.mono)? " mono dashed" : " ");
417 	fname = gpage_fname(".pdf", i);
418     } else {
419 	/* EPS output variants */
420 	int fontsize = gp_cairo_fontsize();
421 
422 	fprintf(fq, "set term epscairo font \"sans,%d\"%s", fontsize,
423 		(gpage.mono)? " mono dashed" : " ");
424 	fname = gpage_fname(".ps", i);
425     }
426 
427     if (scale != 1.0) {
428 	fprintf(fq, " size %g,%g\n", scale * 5.0, scale * 3.5);
429     } else {
430 	fputc('\n', fq);
431     }
432 
433     gretl_pop_c_numeric_locale();
434 
435     fputs("set encoding utf8\n", fq);
436     fprintf(fq, "set output '%s'\n", fname);
437 
438     if (!err) {
439 	filter_gnuplot_file(gpage.mono, gfname, fp, fq);
440     }
441 
442     fclose(fp);
443     fclose(fq);
444 
445     if (!err) {
446 	fname = gpage_fname(".plt", 0);
447 	err = gnuplot_compile(fname);
448     }
449 
450     return err;
451 }
452 
453 #if defined(G_OS_WIN32)
454 
get_dvips_path(char * path)455 static int get_dvips_path (char *path)
456 {
457     int ret;
458     char *p;
459 
460     ret = SearchPath(NULL, "dvips.exe", NULL, MAXLEN, path, &p);
461 
462     return (ret == 0);
463 }
464 
465 #else
466 
spawn_dvips(char * texsrc)467 static int spawn_dvips (char *texsrc)
468 {
469     GError *error = NULL;
470     gchar *sout = NULL;
471     gchar *argv[5];
472     char outfile[MAXLEN];
473     int ok, status;
474     int ret = 0;
475 
476     sprintf(outfile, "%s.ps", texsrc);
477 
478     argv[0] = "dvips";
479     argv[1] = "-o";
480     argv[2] = outfile;
481     argv[3] = texsrc;
482     argv[4] = NULL;
483 
484     ok = g_spawn_sync(gretl_dotdir(),
485 		      argv,
486 		      NULL,    /* envp */
487 		      G_SPAWN_SEARCH_PATH |
488 		      G_SPAWN_STDERR_TO_DEV_NULL,
489 		      NULL,    /* child_setup */
490 		      NULL,    /* user_data */
491 		      &sout,   /* standard output */
492 		      NULL,    /* standard error */
493 		      &status, /* exit status */
494 		      &error);
495 
496     if (!ok) {
497 	errbox(error->message);
498 	g_error_free(error);
499 	ret = LATEX_EXEC_FAILED;
500     } else if (status != 0) {
501 	gchar *errmsg;
502 
503 	errmsg = g_strdup_printf("%s\n%s",
504 				 _("Failed to process TeX file"),
505 				 sout);
506 	errbox(errmsg);
507 	g_free(errmsg);
508 	ret = 1;
509     }
510 
511     if (sout != NULL) g_free(sout);
512 
513     return ret;
514 }
515 
516 #endif /* Windows or not */
517 
dvips_compile(char * texshort)518 int dvips_compile (char *texshort)
519 {
520 #ifdef G_OS_WIN32
521     static char dvips_path[MAXLEN];
522     char tmp[MAXLEN];
523 #endif
524     int err = 0;
525 
526 #if defined(G_OS_WIN32)
527     if (*dvips_path == 0 && get_dvips_path(dvips_path)) {
528 	win_show_last_error();
529 	return 1;
530     }
531 
532     sprintf(tmp, "\"%s\" -o %s.ps %s", dvips_path, texshort, texshort);
533     if (win_run_sync(tmp, gretl_dotdir())) {
534 	return 1;
535     }
536 #else
537     err = spawn_dvips(texshort);
538 #endif
539 
540     return err;
541 }
542 
latex_compile_graph_page(void)543 static int latex_compile_graph_page (void)
544 {
545     char *fname;
546     int err;
547 
548     /* ensure we don't get stale output */
549     if (gpage.term == GP_TERM_EPS) {
550 	fname = gpage_fname(".ps", 0);
551     } else {
552 	fname = gpage_fname(".pdf", 0);
553     }
554 
555     gretl_remove(fname);
556 
557     err = latex_compile(gpage_tex_base);
558 
559     if (err == LATEX_ERROR) {
560 	char *fname = gpage_fname(".log", 0);
561 
562 	view_file(fname, 0, 1, 78, 350, VIEW_FILE);
563     }
564 
565     if (gpage.term == GP_TERM_EPS && !err) {
566 	err = dvips_compile(gpage_base);
567     }
568 
569     return err;
570 }
571 
make_gp_output(void)572 static int make_gp_output (void)
573 {
574     char *fname;
575     double scale = 1.0;
576     int i, err = 0;
577 
578     if (gpage.ngraphs == 3) {
579 	scale = 0.8;
580     } else if (gpage.ngraphs > 3) {
581 	scale = 0.75;
582     }
583 
584     for (i=0; i<gpage.ngraphs && !err; i++) {
585 	fprintf(stderr, "make_outfile %d: '%s'\n", i, gpage.fnames[i]);
586 	err = gp_make_outfile(gpage.fnames[i], i + 1, scale);
587     }
588 
589     if (!err) {
590 	fname = gpage_fname(".plt", 0);
591 	gretl_remove(fname);
592     }
593 
594     return err;
595 }
596 
real_display_gpage(void)597 static int real_display_gpage (void)
598 {
599     char *fname;
600     int err = 0;
601 
602     if (gpage.term == GP_TERM_PDF) {
603 	fname = gpage_fname(".pdf", 0);
604     } else {
605 	fname = gpage_fname(".ps", 0);
606     }
607 
608 #if defined(G_OS_WIN32)
609     err = win32_open_file(fname);
610 #elif defined(OS_OSX)
611     err = osx_open_file(fname);
612 #else
613     if (gpage.term == GP_TERM_PDF) {
614 	err = gretl_fork("viewpdf", fname, NULL);
615     } else {
616 	err = gretl_fork("viewps", fname, NULL);
617     }
618 #endif
619 
620     return err;
621 }
622 
gpage_cleanup(void)623 static void gpage_cleanup (void)
624 {
625     char *fname;
626     int i;
627 
628     for (i=0; i<gpage.ngraphs; i++) {
629 	if (gpage.term == GP_TERM_PDF) {
630 	    fname = gpage_fname(".pdf", i + 1);
631 	} else {
632 	    fname = gpage_fname(".ps", i + 1);
633 	}
634 	gretl_remove(fname);
635     }
636 
637     fname = gpage_fname(".tex", 0);
638     gretl_remove(fname);
639     fname = gpage_fname(".dvi", 0);
640     gretl_remove(fname);
641     fname = gpage_fname(".log", 0);
642     gretl_remove(fname);
643     fname = gpage_fname(".aux", 0);
644     gretl_remove(fname);
645 }
646 
gpage_switch_compiler(int term)647 static gchar *gpage_switch_compiler (int term)
648 {
649     gchar *orig = g_strdup(latex);
650     char *p, tmp[MAXSTR];
651     char test[4];
652     int len0, have_pdf;
653 
654     strcpy(tmp, latex);
655     p = strrslash(tmp);
656     if (p == NULL) {
657 	len0 = 0;
658 	p = tmp;
659     } else {
660 	len0 = p - tmp + 1;
661 	p++;
662     }
663 
664     *test = '\0';
665     strncat(test, p, 3);
666     gretl_lower(test);
667 
668     have_pdf = (strcmp(test, "pdf") == 0);
669 
670     if (term == GP_TERM_PDF && !have_pdf) {
671 	/* switch to pdflatex */
672 	*latex = '\0';
673 	strncat(latex, tmp, len0);
674 	strcat(latex, "pdf");
675 	strcat(latex, p);
676     } else if (term != GP_TERM_PDF && have_pdf) {
677 	/* switch to plain latex */
678 	*latex = '\0';
679 	strncat(latex, tmp, len0);
680 	strcat(latex, p + 3);
681     }
682 
683     return orig;
684 }
685 
gpage_revert_compiler(gchar * orig)686 static void gpage_revert_compiler (gchar *orig)
687 {
688     if (orig != NULL) {
689 	strcpy(latex, orig);
690 	g_free(orig);
691     }
692 }
693 
display_graph_page(GtkWidget * parent)694 int display_graph_page (GtkWidget *parent)
695 {
696     const char *opts[] = {
697 	N_("color"),
698 	N_("monochrome")
699     };
700     const char *sdir = get_session_dirname();
701     gchar *latex_orig = NULL;
702     int resp, err = 0;
703 
704     if (gpage.ngraphs == 0) {
705 	gpage_errmsg(_("The graph page is empty"), 1);
706 	return 1;
707     }
708 
709     resp = radio_dialog(_("graph page options"), NULL, opts,
710 			2, 0, 0, parent);
711     if (resp < 0) {
712 	return 0;
713     }
714 
715     gpage.mono = (resp == 1);
716 
717     err = gretl_chdir(sdir);
718     if (err) {
719 	/* maybe we're not in @dotdir? */
720 	gchar *full_session_dir = gretl_make_dotpath(sdir);
721 
722 	err = gretl_chdir(full_session_dir);
723 	g_free(full_session_dir);
724     }
725     if (err) {
726 	err = E_FOPEN;
727 	goto bailout;
728     }
729 
730     gpage_filenames_init(NULL);
731 
732     if (get_tex_use_pdf()) {
733 	gpage.term = GP_TERM_PDF;
734     } else {
735 	gpage.term = GP_TERM_EPS;
736     }
737 
738     /* write the LaTeX driver file */
739     err = make_graphpage_tex();
740 
741     if (!err) {
742 	/* transform individual plot files and compile
743 	   using gnuplot */
744 	err = make_gp_output();
745     }
746 
747     if (!err) {
748 	/* compile LaTeX */
749 	err = latex_compile_graph_page();
750     }
751 
752     if (!err) {
753 	/* display output file */
754 	err = real_display_gpage();
755     }
756 
757     gpage_revert_compiler(latex_orig);
758     gpage_cleanup();
759 
760  bailout:
761 
762     if (err) {
763 	gui_errmsg(err);
764     }
765 
766     return err;
767 }
768 
clear_graph_page(int on_exit)769 void clear_graph_page (int on_exit)
770 {
771     int i;
772 
773     if (!on_exit && gpage.ngraphs > 0) {
774 	mark_session_changed();
775     }
776 
777     for (i=0; i<gpage.ngraphs; i++) {
778 	free(gpage.fnames[i]);
779     }
780     free(gpage.fnames);
781 
782     graph_page_init();
783 }
784 
graph_page_get_n_graphs(void)785 int graph_page_get_n_graphs (void)
786 {
787     return gpage.ngraphs;
788 }
789 
save_graph_page(const char * fname)790 int save_graph_page (const char *fname)
791 {
792     const char *sdir = get_session_dirname();
793     char *latex_orig = NULL;
794     int err = 0;
795 
796     gretl_chdir(sdir);
797 
798     gpage_filenames_init(fname);
799 
800     if (get_tex_use_pdf()) {
801 	gpage.term = GP_TERM_PDF;
802     } else {
803 	gpage.term = GP_TERM_EPS;
804     }
805 
806     /* write the LaTeX driver file */
807     err = make_graphpage_tex();
808 
809     if (!err) {
810 	/* transform individual plot files and compile
811 	   using gnuplot */
812 	err = make_gp_output();
813     }
814 
815     gpage_revert_compiler(latex_orig);
816 
817     return err;
818 }
819 
print_graph_page_direct(const char * fname,gretlopt opt)820 static int print_graph_page_direct (const char *fname,
821 				    gretlopt opt)
822 {
823     gchar *thisdir = NULL;
824     char *latex_orig = NULL;
825     int cd_done = 0;
826     int err = 0;
827 
828     if (gpage.ngraphs == 0) {
829 	gpage_errmsg(_("The graph page is empty"), 1);
830 	return 1;
831     }
832 
833     thisdir = g_get_current_dir();
834 
835     if (gretl_chdir(get_session_dirname()) != 0) {
836 	g_free(thisdir);
837 	return 1;
838     }
839 
840     gpage.mono = (opt & OPT_M) ? 1 : 0;
841     gpage_filenames_init(NULL);
842 
843     if (has_suffix(fname, ".pdf")) {
844 	gpage.term = GP_TERM_PDF;
845 	if (!get_tex_use_pdf()) {
846 	    latex_orig = gpage_switch_compiler(gpage.term);
847 	}
848     } else {
849 	gpage.term = GP_TERM_EPS;
850 	if (get_tex_use_pdf()) {
851 	    latex_orig = gpage_switch_compiler(gpage.term);
852 	}
853     }
854 
855     /* write the LaTeX driver file */
856     err = make_graphpage_tex();
857 
858     if (!err) {
859 	/* transform individual plot files and compile
860 	   using gnuplot */
861 	err = make_gp_output();
862     }
863 
864     if (!err) {
865 	err = latex_compile_graph_page();
866     }
867 
868     if (!err) {
869 	char *output;
870 
871 	if (gpage.term == GP_TERM_PDF) {
872 	    output = gpage_fname(".pdf", 0);
873 	} else {
874 	    output = gpage_fname(".ps", 0);
875 	}
876 	if (thisdir != NULL) {
877 	    /* come back out of dotdir */
878 	    if (gretl_chdir(thisdir) != 0) {
879 		err = 1;
880 	    } else {
881 		cd_done = 1;
882 	    }
883 	}
884 	fname = gretl_maybe_switch_dir(fname);
885 	err = gretl_copy_file(output, fname);
886 	if (!err) {
887 	    fprintf(stderr, "graphpg: wrote %s\n", fname);
888 	}
889 	remove(output);
890     }
891 
892     if (thisdir != NULL && !cd_done) {
893 	gretl_chdir(thisdir);
894     }
895 
896     g_free(thisdir);
897     gpage_revert_compiler(latex_orig);
898     gpage_cleanup();
899 
900     return err;
901 }
902 
graph_page_exec(const char * parm,const char * parm2,gretlopt opt)903 int graph_page_exec (const char *parm,
904 		     const char *parm2,
905 		     gretlopt opt)
906 {
907     const char *outfile = NULL;
908     int gotparm = 0;
909     int err = 0;
910 
911     if (parm != NULL) {
912 	gotparm = 1;
913     }
914 
915     if (gotparm && (opt & OPT_O)) {
916 	/* the --output option rules out the various
917 	   command words */
918 	err = E_PARSE;
919     } else if (opt & OPT_O) {
920 	/* --output="filename" */
921 	outfile = get_optval_string(GRAPHPG, OPT_O);
922 	if (outfile == NULL) {
923 	    err = E_PARSE;
924 	} else {
925 	    err = print_graph_page_direct(outfile, opt);
926 	}
927     } else if (!gotparm) {
928 	err = E_PARSE;
929     }
930 
931     if (gotparm && !err) {
932 	/* handle the parameter we got */
933 	if (!strcmp(parm, "add")) {
934 	    err = graph_page_add_last_graph();
935 	} else if (!strcmp(parm, "show")) {
936 	    err = display_graph_page(NULL);
937 	} else if (!strcmp(parm, "free")) {
938 	    if (gpage.ngraphs > 0) {
939 		clear_graph_page(0);
940 	    }
941 	} else if (!strcmp(parm, "fontscale")) {
942 	    if (parm2 == NULL) {
943 		gretl_errmsg_set("fontscale: parameter is missing");
944 		err = E_PARSE;
945 	    } else {
946 		err = graph_page_set_font_scale(parm2);
947 	    }
948 	} else {
949 	    err = E_PARSE;
950 	}
951     }
952 
953     return err;
954 }
955