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 /* texprint.c for gretl - LaTeX output from modeling */
21 
22 #include "libgretl.h"
23 #include "var.h"
24 #include "johansen.h"
25 #include "texprint.h"
26 
27 #include <glib.h>
28 
29 static char colspec[4][8];
30 static int use_custom;
31 static int use_pdf;
32 
33 #define tex_screen_zero(x)  ((fabs(x) > 1.0e-17)? x : 0.0)
34 
tex_using_custom_tabular(void)35 int tex_using_custom_tabular (void)
36 {
37     return use_custom;
38 }
39 
tex_column_format(int i)40 const char *tex_column_format (int i)
41 {
42     if (i >= 0 && i < 4) {
43 	return colspec[i];
44     } else {
45 	return "";
46     }
47 }
48 
set_tex_use_pdf(const char * prog)49 void set_tex_use_pdf (const char *prog)
50 {
51     const char *p = strrslash(prog);
52     char test[4];
53 
54     /* looking for "pdflatex", possibly preceded by
55        an absolute path */
56 
57     p = (p == NULL)? prog : p + 1;
58 
59     *test = '\0';
60     strncat(test, p, 3);
61     gretl_lower(test);
62     use_pdf = !strcmp(test, "pdf");
63 }
64 
get_tex_use_pdf(void)65 int get_tex_use_pdf (void)
66 {
67     return use_pdf;
68 }
69 
tex_greek_var(const char * s)70 static const char *tex_greek_var (const char *s)
71 {
72     if (!strcmp(s, "alpha")) {
73 	return "\\alpha";
74     } else if (!strcmp(s, "beta")) {
75 	return "\\beta";
76     } else if (!strcmp(s, "gamma")) {
77 	return "\\gamma";
78     } else if (!strcmp(s, "delta")) {
79 	return "\\delta";
80     } else if (!strcmp(s, "epsilon")) {
81 	return "\\epsilon";
82     } else if (!strcmp(s, "chi")) {
83 	return "\\chi";
84     } else if (!strcmp(s, "pi")) {
85 	return "\\pi";
86     } else if (!strcmp(s, "phi")) {
87 	return "\\phi";
88     } else if (!strcmp(s, "psi")) {
89 	return "\\psi";
90     } else if (!strcmp(s, "lambda")) {
91 	return "\\lambda";
92     }
93 
94     return NULL;
95 }
96 
97 /**
98  * tex_escape:
99  * @targ: target string (must be pre-allocated)
100  * @src: source string.
101  *
102  * Copies from @src to @targ, escaping any characters in @src that are
103  * special to TeX (by inserting a leading backslash).
104  *
105  * Returns: the transformed copy of the string
106  */
107 
tex_escape(char * targ,const char * src)108 char *tex_escape (char *targ, const char *src)
109 {
110     char *p = targ;
111 
112     if (src == NULL) {
113 	fprintf(stderr, "tex_escape: src is NULL\n");
114 	*p = '\0';
115 	return p;
116     }
117 
118     while (*src) {
119 	if (*src == '$' || *src == '&' || *src == '_' ||
120 	    *src == '%' || *src == '#')
121 	    *targ++ = '\\';
122 	*targ++ = *src++;
123     }
124 
125     *targ = '\0';
126 
127     return p;
128 }
129 
130 /**
131  * tex_escape_new:
132  * @src: source string.
133  *
134  * Returns: a copy of @src in which any characters that require
135  * escaping are preceded by a backslash.
136  */
137 
tex_escape_new(const char * src)138 char *tex_escape_new (const char *src)
139 {
140     const char *s = src;
141     char *ret = NULL;
142     int i, len = 0;
143 
144     if (src == NULL) {
145 	fprintf(stderr, "tex_escape: src is NULL\n");
146 	return gretl_strdup("");
147     }
148 
149     while (*s) {
150 	if (*s == '$' || *s == '&' || *s == '_' ||
151 	    *s == '%' || *s == '#') {
152 	    len++;
153 	}
154 	len++;
155     }
156 
157     ret = calloc(1, len + 1);
158     s = src;
159     i = 0;
160 
161     while (*s) {
162 	if (*s == '$' || *s == '&' || *s == '_' ||
163 	    *s == '%' || *s == '#') {
164 	    ret[i++] = '\\';
165 	}
166 	ret[i++] = *s;
167     }
168 
169     return ret;
170 }
171 
tex_math_pname(char * targ,const char * s)172 static int tex_math_pname (char *targ, const char *s)
173 {
174     char base[16], op[2], mod[8];
175     int n;
176 
177     n = sscanf(s, "%15[^_^]%1[_^]%7s", base, op, mod);
178 
179     if (n == 3 && (*mod == '{' || isdigit(*mod))) {
180 	const char *tgreek = tex_greek_var(base);
181 	const char *tbase = (tgreek != NULL)? tgreek : base;
182 
183 	if (*mod == '{') {
184 	    sprintf(targ, "$%s%s%s$", tbase, op, mod);
185 	} else {
186 	    sprintf(targ, "$%s%s{%s}$", tbase, op, mod);
187 	}
188 	return 1;
189     }
190 
191     return 0;
192 }
193 
194 /**
195  * tex_escape_special:
196  * @targ: target string (must be pre-allocated)
197  * @src: source string.
198  *
199  * Copies from @src to @targ, escaping characters in @src that are
200  * special to TeX (by inserting a leading backslash).  Unlike
201  * tex_escape(), this function does not mess with '$' in the
202  * source string, and it attempts to handle greek letters
203  * correctly.
204  *
205  * Returns: the transformed copy of the string.
206  */
207 
tex_escape_special(char * targ,const char * src)208 char *tex_escape_special (char *targ, const char *src)
209 {
210     const char *tgreek;
211     char *p = targ;
212 
213     if (strchr(src, '$')) {
214 	/* don't mess with it */
215 	strcpy(targ, src);
216 	return targ;
217     }
218 
219     tgreek = tex_greek_var(src);
220 
221     if (tgreek != NULL) {
222 	sprintf(targ, "$%s$", tgreek);
223     } else if (tex_math_pname(targ, src)) {
224 	; /* handled */
225     } else {
226 	/* regular escape routine */
227 	while (*src) {
228 	    if (*src == '&' || *src == '_' ||
229 		*src == '%' || *src == '#') {
230 		*p++ = '\\';
231 	    }
232 	    *p++ = *src++;
233 	}
234 
235 	*p = '\0';
236     }
237 
238     return targ;
239 }
240 
241 /* Print the floating point number @x into the string @s, using the C
242    format "%*.f", with the digits following the decimal point given by
243    @dig.  This is intended for use with the LaTeX tabular column
244    format "r@{.}l", so the decimal point is replaced by '&'.  In
245    addition, it is presumed that we're _not_ in TeX math mode, so the
246    leading minus sign, if present, is "mathized" as "$-$".
247 
248    NADBL is handled by printing a blank "r@{.}l" value.
249 */
250 
tex_rl_float(double x,char * s,int dig)251 char *tex_rl_float (double x, char *s, int dig)
252 {
253     char *p;
254 
255     if (na(x)) {
256 	return strcpy(s, "\\multicolumn{2}{c}{}");
257     }
258 
259     x = screen_zero(x);
260 
261     if (x < 0) {
262 	sprintf(s, "$-$%.*f", dig, -x);
263     } else {
264 	sprintf(s, "%.*f", dig, x);
265     }
266 
267     p = strchr(s, '.');
268 
269     if (p == NULL) {
270 	p = strchr(s, ',');
271     }
272 
273     if (p != NULL) {
274 	*p = '&';
275     } else {
276 	strcat(s, "&");
277     }
278 
279     return s;
280 }
281 
282 /* When a floating point value is printed as TeX in the C format "%g",
283    process the exponent part.  It is assumed we're not in TeX math
284    mode, so in a negative exponent such as "e-06" the minus will
285    appear as a hyphen, which does not look very good.  Using a true
286    minus sign in the exponent doesn't look very good either (too
287    wide); we compromise by writing the minus as an en dash.
288 */
289 
tex_modify_exponent(char * s)290 char *tex_modify_exponent (char *s)
291 {
292     char *p = strchr(s, 'e');
293 
294     if (p != NULL) {
295 	int minus = (*(p+1) == '-');
296 	char tmp[16];
297 
298 	sprintf(tmp, "\\textrm{e%s%s}", (minus)? "--" : "+", p + 2);
299 	strcpy(p, tmp);
300     }
301 
302     return s;
303 }
304 
tex_rl_double_dig(double x,char * s,int d)305 static char *tex_rl_double_dig (double x, char *s, int d)
306 {
307     char *p;
308 
309     if (na(x)) {
310 	return strcpy(s, "\\multicolumn{2}{c}{}");
311     }
312 
313     x = screen_zero(x);
314 
315     if (x < 0) {
316 	sprintf(s, "$-$%#.*g", d, -x);
317     } else {
318 	sprintf(s, "%#.*g", d, x);
319     }
320 
321     if (strchr(s, 'e') != NULL) {
322 	tex_modify_exponent(s);
323     }
324 
325     p = strchr(s, '.');
326 
327     if (p == NULL) {
328 	p = strchr(s, ',');
329     }
330 
331     if (p != NULL) {
332 	*p = '&';
333     } else {
334 	strcat(s, "&");
335     }
336 
337     return s;
338 }
339 
340 /* Print the floating point number @x into the string @s, using the C
341    format "%#*.g", with GRETL_DIGITS of precision.  This is intended
342    for use with the LaTeX tabular column format "r@{.}l", so the
343    decimal point is replaced by '&'.  In addition, it is presumed that
344    we're _not_ in TeX math mode, so the leading minus sign, if
345    present, is "mathized" as "$-$".
346 
347    NADBL is handled by printing a blank "r@{.}l" value.
348 */
349 
tex_rl_double(double x,char * s)350 char *tex_rl_double (double x, char *s)
351 {
352     return tex_rl_double_dig(x, s, get_gretl_digits());
353 }
354 
355 /* Print the floating point number @x into the string @s, using the C
356    format "%#*.g", with @dig digits of precision.  It is presumed
357    that we're _not_ in TeX math mode, so the leading minus sign, if
358    present, is "mathized" as "$-$".
359 
360    NADBL is handled by printing a space.
361 */
362 
tex_sprint_double_digits(double x,char * s,int dig)363 char *tex_sprint_double_digits (double x, char *s, int dig)
364 {
365     if (na(x)) {
366 	return strcpy(s, " ");
367     }
368 
369     x = screen_zero(x);
370 
371     if (x < 0.0) {
372 	sprintf(s, "$-$%#.*g", dig, -x);
373     } else {
374 	sprintf(s, "%#.*g", dig, x);
375     }
376 
377     if (strchr(s, 'e') != NULL) {
378 	tex_modify_exponent(s);
379     }
380 
381     return s;
382 }
383 
384 /* Basically as above, but for use when in TeX math mode */
385 
tex_sprint_math_double_digits(double x,char * s,int dig)386 static char *tex_sprint_math_double_digits (double x, char *s, int dig)
387 {
388     if (na(x)) {
389 	return strcpy(s, "\\mbox{NA}");
390     }
391 
392     x = screen_zero(x);
393 
394     sprintf(s, "%#.*g", dig, x);
395 
396     if (strchr(s, 'e') != NULL) {
397 	tex_modify_exponent(s);
398     }
399 
400     return s;
401 }
402 
403 /* Print the floating point number @x into the string @s, using the C
404    format "%#*.g", with GRETL_DIGITS of precision.  It is presumed
405    that we're _not_ in TeX math mode, so the leading minus sign, if
406    present, is "mathized" as "$-$".
407 
408    NADBL is handled by printing a space.
409 */
410 
tex_sprint_double(double x,char * s)411 char *tex_sprint_double (double x, char *s)
412 {
413     int d = get_gretl_digits();
414 
415     if (na(x)) {
416 	return strcpy(s, " ");
417     }
418 
419     x = screen_zero(x);
420 
421     if (x < 0.0) {
422 	sprintf(s, "$-$%#.*g", d, -x);
423     } else {
424 	sprintf(s, "%#.*g", d, x);
425     }
426 
427     if (strchr(s, 'e') != NULL) {
428 	tex_modify_exponent(s);
429     }
430 
431     return s;
432 }
433 
434 /* Print the floating point number @x directly to @prn, using the C
435    format "%#*.g", with GRETL_DIGITS of precision.  It is presumed
436    that we're _not_ in TeX math mode, so the leading minus sign, if
437    present, is "mathized" as "$-$".
438 
439    NADBL is handled by printing a space.
440 */
441 
tex_print_double(double x,PRN * prn)442 void tex_print_double (double x, PRN *prn)
443 {
444     char s[32];
445 
446     tex_sprint_double(x, s);
447     pputs(prn, s);
448 }
449 
tex_make_cname(char * cname,const char * src)450 static void tex_make_cname (char *cname, const char *src)
451 {
452     char *p;
453     unsigned char c;
454 
455     if (src == NULL || *src == '\0') return;
456 
457     p = strrchr(src, '_');
458     if (p == NULL) {
459 	tex_escape(cname, src);
460 	return;
461     }
462 
463     c = (unsigned char) *(p + 1);
464 
465     if (isdigit(c)) {
466 	int lag = atoi(++p);
467 
468 	sprintf(cname, "$u_{t-%d}^2$", lag);
469     } else {
470 	tex_escape(cname, src);
471     }
472 }
473 
tex_greek_param(char * targ,const char * src)474 static int tex_greek_param (char *targ, const char *src)
475 {
476     const char *tgreek = tex_greek_var(src);
477 
478     if (tgreek != NULL) {
479 	sprintf(targ, "$%s$", tgreek);
480 	return 1;
481     } else {
482 	*targ = '\0';
483 	return 0;
484     }
485 }
486 
tex_garch_coeff_name(char * targ,const char * src,int inmath)487 static void tex_garch_coeff_name (char *targ, const char *src,
488 				  int inmath)
489 {
490     char fmt[16], vname[VNAMELEN], vnesc[16];
491     int lag;
492 
493     sprintf(fmt, "%%%d[^(](%%d)", VNAMELEN - 1);
494 
495     if (sscanf(src, fmt, vname, &lag) == 2) {
496 	/* e.g. "alpha(0)" */
497 	if (!inmath) {
498 	    sprintf(targ, "$\\%s_{%d}$", vname, lag);
499 	} else {
500 	    sprintf(targ, "\\%s_{%d}", vname, lag);
501 	}
502     } else {
503 	/* regular variable name */
504 	tex_escape(vnesc, src);
505 	if (inmath) {
506 	    sprintf(targ, "\\mbox{%s}", vnesc);
507 	} else {
508 	    strcpy(targ, vnesc);
509 	}
510     }
511 }
512 
tex_mp_coeff_name(char * targ,const char * src,int inmath)513 static void tex_mp_coeff_name (char *targ, const char *src,
514 			       int inmath)
515 {
516     char fmt[12], vname[VNAMELEN], vnesc[24];
517     int power;
518 
519     tex_escape(vnesc, src);
520 
521     sprintf(fmt, "%%%d[^^]^%%d", VNAMELEN - 1);
522 
523     if (sscanf(vnesc, fmt, vname, &power) == 2) {
524 	/* variable raised to some power */
525 	if (!inmath) {
526 	    sprintf(targ, "%s$^{%d}$", vname, power);
527 	} else {
528 	    sprintf(targ, "\\mbox{%s}^%d", vname, power);
529 	}
530     } else {
531 	/* regular variable name */
532 	if (inmath) {
533 	    sprintf(targ, "\\mbox{%s}", vnesc);
534 	} else {
535 	    strcpy(targ, vnesc);
536 	}
537     }
538 }
539 
tex_arma_coeff_name(char * targ,const char * src,int inmath)540 static void tex_arma_coeff_name (char *targ, const char *src,
541 				 int inmath)
542 {
543     char vname[VNAMELEN], vnesc[32], texname[48];
544     int i;
545 
546     if (sscanf(src, "phi_%d", &i)) {
547 	if (!inmath) {
548 	    sprintf(targ, "$\\phi_{%d}$", i);
549 	} else {
550 	    sprintf(targ, "\\phi_{%d}", i);
551 	}
552     } else if (sscanf(src, "Phi_%d", &i)) {
553 	if (!inmath) {
554 	    sprintf(targ, "$\\Phi_{%d}$", i);
555 	} else {
556 	    sprintf(targ, "\\Phi_{%d}", i);
557 	}
558     } else if (sscanf(src, "theta_%d", &i)) {
559 	if (!inmath) {
560 	    sprintf(targ, "$\\theta_{%d}$", i);
561 	} else {
562 	    sprintf(targ, "\\theta_{%d}", i);
563 	}
564     } else if (sscanf(src, "Theta_%d", &i)) {
565 	if (!inmath) {
566 	    sprintf(targ, "$\\Theta_{%d}$", i);
567 	} else {
568 	    sprintf(targ, "\\Theta_{%d}", i);
569 	}
570     } else if (strstr(src, "(-") != NULL) {
571 	char fmt[16];
572 
573 	sprintf(fmt, "%%%d[^(](-%%d)", VNAMELEN - 1);
574 
575 	if (sscanf(src, fmt, vname, &i) == 2) {
576 	    if (!strcmp(vname, "y")) {
577 		strcpy(texname, "y");
578 	    } else {
579 		tex_escape(vnesc, vname);
580 		if (!inmath) {
581 		    strcpy(texname, vnesc);
582 		} else {
583 		    sprintf(texname, "\\mbox{%s}", vnesc);
584 		}
585 	    }
586 	    if (!inmath) {
587 		sprintf(targ, "%s$_{t-%d}$", texname, i);
588 	    } else {
589 		sprintf(targ, "%s_{t-%d}", texname, i);
590 	    }
591 	} else {
592 	    tex_escape(vnesc, src);
593 	    strcpy(targ, vnesc);
594 	}
595     } else {
596 	tex_escape(vnesc, src);
597 	strcpy(targ, vnesc);
598     }
599 }
600 
tex_VAR_varname(char * s,const MODEL * pmod,const DATASET * dset,int v)601 static void tex_VAR_varname (char *s, const MODEL *pmod,
602 			     const DATASET *dset, int v)
603 {
604     char tmp[32], base[12];
605     int lag;
606 
607     gretl_model_get_param_name(pmod, dset, v, tmp);
608 
609     if (sscanf(tmp, "%11[^_]_%d", base, &lag) == 2) {
610 	sprintf(s, "%s$_{t-%d}$", base, lag);
611     } else {
612 	tex_escape(s, tmp);
613     }
614 }
615 
tex_VECM_varname(char * s,const MODEL * pmod,const DATASET * dset,int v)616 static void tex_VECM_varname (char *s, const MODEL *pmod,
617 			      const DATASET *dset, int v)
618 {
619     char tmp[32], base[12];
620     int lag;
621 
622     gretl_model_get_param_name(pmod, dset, v, tmp);
623 
624     if (sscanf(tmp, "d_%11[^_]_%d", base, &lag) == 2) {
625 	sprintf(s, "$\\Delta$%s$_{t-%d}$", base, lag);
626     } else {
627 	tex_escape(s, tmp);
628     }
629 }
630 
tex_print_coeff_custom(const model_coeff * mc,PRN * prn)631 static int tex_print_coeff_custom (const model_coeff *mc, PRN *prn)
632 {
633     char fmt[12];
634 
635     pprintf(prn, "%s & ", mc->name);
636 
637     if (colspec[0][0]) {
638 	/* coefficient */
639 	if (na(mc->b)) {
640 	    pprintf(prn, "\\multicolumn{1}{c}{\\rm %s}", _("undefined"));
641 	} else {
642 	    sprintf(fmt, "$%s$", colspec[0]);
643 	    pprintf(prn, fmt, mc->b);
644 	}
645     }
646 
647     if (!colspec[1][0] && !colspec[2][0] && !colspec[3][0]) {
648 	pputs(prn, " \\\\\n");
649 	return 0;
650     }
651 
652     if (colspec[1][0]) {
653 	if (colspec[0][0]) {
654 	    pputs(prn, " & ");
655 	}
656 	/* standard error */
657 	if (na(mc->se)) {
658 	    pprintf(prn, "\\multicolumn{1}{c}{\\rm %s}", _("undefined"));
659 	} else {
660 	    pprintf(prn, colspec[1], mc->se);
661 	}
662     }
663 
664     if (!colspec[2][0] && !colspec[3][0]) {
665 	pputs(prn, " \\\\\n");
666 	return 0;
667     }
668 
669     if (colspec[2][0]) {
670 	if (colspec[0][0] || colspec[1][0]) {
671 	    pputs(prn, " & ");
672 	}
673 	/* t-ratio */
674 	if (na(mc->tval)) {
675 	    if (mc->show_tval) {
676 		pprintf(prn, "\\multicolumn{1}{c}{\\rm %s}", _("undefined"));
677 	    } else {
678 		pprintf(prn, "\\multicolumn{1}{c}{}");
679 	    }
680 	} else {
681 	    sprintf(fmt, "$%s$", colspec[2]);
682 	    pprintf(prn, fmt, mc->tval);
683 	}
684     }
685 
686     if (colspec[3][0]) {
687 	if (colspec[0][0] || colspec[1][0] || colspec[2][0]) {
688 	    pputs(prn, " & ");
689 	}
690 	/* p-value (or perhaps slope) */
691 	if (mc->show_pval) {
692 	    if (na(mc->pval)) {
693 		pprintf(prn, "\\multicolumn{1}{c}{\\rm %s}", _("undefined"));
694 	    } else {
695 		pprintf(prn, colspec[3], mc->pval);
696 	    }
697 	} else if (!na(mc->slope)) {
698 	    pprintf(prn, colspec[3], mc->slope);
699 	} else {
700 	    pprintf(prn, "\\multicolumn{1}{c}{}");
701 	}
702     }
703 
704     pputs(prn, " \\\\\n");
705 
706     return 0;
707 }
708 
make_tex_coeff_name(const MODEL * pmod,const DATASET * dset,int i,char * name)709 void make_tex_coeff_name (const MODEL *pmod, const DATASET *dset, int i,
710 			  char *name)
711 {
712     char pname[VNAMELEN];
713 
714     gretl_model_get_param_name(pmod, dset, i, pname);
715 
716     if (pmod->aux == AUX_ARCH) {
717 	tex_make_cname(name, pname);
718     } else if (pmod->ci == NLS) {
719 	if (!tex_greek_param(name, pname)) {
720 	    tex_escape(name, pname);
721 	}
722     } else if (pmod->ci == ARMA) {
723 	tex_arma_coeff_name(name, pname, 0);
724     } else if (pmod->ci == GARCH) {
725 	tex_garch_coeff_name(name, pname, 0);
726     } else if (pmod->ci == VAR) {
727 	tex_VAR_varname(name, pmod, dset, i);
728     } else if (pmod->aux == AUX_VECM) {
729 	tex_VECM_varname(name, pmod, dset, i);
730     } else if (pmod->ci == MPOLS) {
731 	tex_mp_coeff_name(name, pname, 0);
732     } else {
733 	tex_escape(name, pname);
734     }
735 }
736 
tex_multi_double(double x,char * numstr)737 static char *tex_multi_double (double x, char *numstr)
738 {
739     char *p;
740 
741     if (na(x)) {
742 	strcpy(numstr, " ");
743     } else if (x < 0) {
744 	sprintf(numstr, "$-$%.15E", -x);
745     } else {
746 	sprintf(numstr, "%.15E", x);
747     }
748 
749     if ((p = strstr(numstr, "E-")) != NULL) {
750 	char tmp[8];
751 
752 	sprintf(tmp, "E--%s", p + 2);
753 	strcpy(p, tmp);
754     }
755 
756     return numstr;
757 }
758 
tex_print_coeff(const model_coeff * mc,PRN * prn)759 void tex_print_coeff (const model_coeff *mc, PRN *prn)
760 {
761     char col1[64], col2[64], col3[64], col4[64];
762     int ncols = 4;
763 
764     if (mc->multi) {
765 	tex_multi_double(mc->b, col1);
766 	tex_multi_double(mc->se, col2);
767 	pprintf(prn, "%s & %s & %s \\\\\n", mc->name, col1, col2);
768 	return;
769     }
770 
771     if (use_custom) {
772 	tex_print_coeff_custom(mc, prn);
773 	return;
774     }
775 
776     if (na(mc->b)) {
777 	sprintf(col1, "\\multicolumn{2}{c}{\\rm %s}", _("undefined"));
778     } else {
779 	tex_rl_double(mc->b, col1);
780     }
781 
782     if (!na(mc->lo) && !na(mc->hi)) {
783 	tex_rl_double(mc->lo, col2);
784 	tex_rl_double(mc->hi, col3);
785 	ncols = 3;
786     } else {
787 	if (na(mc->se)) {
788 	    sprintf(col2, "\\multicolumn{2}{c}{\\rm %s}", _("undefined"));
789 	} else {
790 	    tex_rl_double(mc->se, col2);
791 	}
792 
793 	if (na(mc->tval)) {
794 	    if (mc->show_tval) {
795 		sprintf(col3, "\\multicolumn{2}{c}{\\rm %s}", _("undefined"));
796 	    } else {
797 		strcpy(col3, "\\multicolumn{2}{c}{}");
798 	    }
799 	} else {
800 	    /* note: was tex_rl_float(mc->tval, col3, 4) */
801 	    tex_rl_double_dig(mc->tval, col3, 4);
802 	}
803     }
804 
805     *col4 = '\0';
806 
807     if (!mc->show_pval && na(mc->slope)) {
808 	strcpy(col4, "\\multicolumn{2}{c}{}");
809     } else if (!na(mc->slope)) {
810 	tex_rl_double(mc->slope, col4);
811     } else if (mc->show_pval) {
812 	if (!na(mc->pval)) {
813 	    tex_rl_float(mc->pval, col4, 4);
814 	}
815     }
816 
817     pprintf(prn, "%s &\n"
818 	    "  %s &\n"
819 	    "    %s &\n",
820 	    mc->name,
821 	    col1,
822 	    col2);
823 
824     if (ncols == 4) {
825 	pprintf(prn,
826 		"      %s &\n"
827 		"        %s \\\\\n",
828 		col3,
829 		col4);
830     } else {
831 	pprintf(prn,
832 		"      %s \\\\\n",
833 		col3);
834     }
835 }
836 
837 static int
tex_custom_coeff_table_start(const char ** cols,gretlopt opt,PRN * prn)838 tex_custom_coeff_table_start (const char **cols, gretlopt opt, PRN *prn)
839 {
840     int i, ncols = 0;
841 
842     for (i=0; i<4; i++) {
843 	if (colspec[i][0]) {
844 	    ncols++;
845 	}
846     }
847 
848     if (!(opt & OPT_U)) {
849 	/* not a user-defined model */
850 	pputs(prn, "\\vspace{1em}\n\n");
851     }
852 
853     pputs(prn, "\\begin{tabular}{l");
854 
855     for (i=0; i<ncols; i++) {
856 	pputc(prn, 'r');
857     }
858 
859     pputs(prn, "}\n");
860 
861     pprintf(prn, "\\multicolumn{1}{c}{%s} &\n", _(cols[0]));
862 
863     if (colspec[0][0]) {
864 	pprintf(prn, "\\multicolumn{1}{c}{%s}", _(cols[1]));
865     }
866 
867     if (!colspec[1][0] && !colspec[2][0] && !colspec[3][0]) {
868 	pputs(prn, " \\\\\n");
869 	return ncols;
870     }
871 
872     if (colspec[1][0]) {
873 	if (colspec[0][0]) {
874 	    pputs(prn, " &\n");
875 	}
876 	pprintf(prn, "\\multicolumn{1}{c}{%s}", _(cols[2]));
877     }
878 
879     if (!colspec[2][0] && !colspec[3][0]) {
880 	pputs(prn, " \\\\\n");
881 	return ncols;
882     }
883 
884     if (colspec[2][0]) {
885 	if (colspec[0][0] || colspec[1][0]) {
886 	    pputs(prn, " &\n");
887 	}
888 	pprintf(prn, "\\multicolumn{1}{c}{%s}", _(cols[3]));
889     }
890 
891     if (colspec[3][0]) {
892 	if (colspec[0][0] || colspec[1][0] || colspec[2][0]) {
893 	    pputs(prn, " &\n");
894 	}
895 	pprintf(prn, "\\multicolumn{1}{c}{%s}", _(cols[4]));
896     }
897 
898     pputs(prn, " \\\\\n");
899 
900     return ncols;
901 }
902 
903 /* returns the number of columns in the coeff table */
904 
tex_coeff_table_start(const char ** cols,gretlopt opt,PRN * prn)905 int tex_coeff_table_start (const char **cols, gretlopt opt, PRN *prn)
906 {
907     char pt = get_local_decpoint();
908     int i, mcols, binary = (opt & OPT_B);
909     int ncols = 1;
910 
911     if (use_custom) {
912 	return tex_custom_coeff_table_start(cols, opt, prn);
913     }
914 
915     if (!(opt & OPT_U)) {
916 	/* not a user-defined model */
917 	pputs(prn, "\\vspace{1em}\n\n");
918     }
919 
920     pputs(prn, "\\begin{tabular}{l");
921 
922     for (i=1; cols[i] != NULL; i++) {
923 	if (opt & OPT_M) {
924 	    pputc(prn, 'r');
925 	} else {
926 	    pprintf(prn, "r@{%c}l", pt);
927 	}
928 	ncols += 2;
929     }
930 
931     pprintf(prn, "}\n%s &\n", _(cols[0]));
932 
933     mcols = (opt & OPT_M)? 1 : 2;
934 
935     for (i=1; cols[i] != NULL; i++) {
936 	bufspace(i, prn);
937 	pprintf(prn, "\\multicolumn{%d}{c}{%s%s} %s\n", mcols, _(cols[i]),
938 		(cols[i+1] == NULL && binary)? "$^*$" : "",
939 		(cols[i+1] == NULL)? "\\\\[1ex]" : "&");
940     }
941 
942     return ncols;
943 }
944 
tex_coeff_table_end(PRN * prn)945 void tex_coeff_table_end (PRN *prn)
946 {
947     pputs(prn, "\\end{tabular}\n\n");
948 }
949 
tex_print_VECM_omega(GRETL_VAR * vecm,const DATASET * dset,PRN * prn)950 void tex_print_VECM_omega (GRETL_VAR *vecm, const DATASET *dset, PRN *prn)
951 {
952     char vname[48];
953     const int *list = vecm->ylist;
954     double x;
955     int i, j;
956 
957     pprintf(prn, "%s\n\n", _("Cross-equation covariance matrix"));
958     pputs(prn, "\\vspace{1em}\n");
959 
960     pputs(prn, "\\begin{tabular}{");
961     pputs(prn, "l");
962     for (i=0; i<vecm->neqns; i++) {
963 	pputs(prn, "r");
964     }
965     pputs(prn, "}\n & ");
966 
967     for (i=0; i<vecm->neqns; i++) {
968 	tex_escape(vname, dset->varname[list[i+1]]);
969 	pprintf(prn, "$\\Delta$%s ", vname);
970 	if (i == vecm->neqns - 1) {
971 	    pputs(prn, "\\\\\n");
972 	} else {
973 	    pputs(prn, "& ");
974 	}
975     }
976     pputc(prn, '\n');
977 
978     for (i=0; i<vecm->neqns; i++) {
979 	tex_escape(vname, dset->varname[list[i+1]]);
980 	pprintf(prn, "$\\Delta$%s & ", vname);
981 	for (j=0; j<vecm->neqns; j++) {
982 	    x = gretl_matrix_get(vecm->S, i, j);
983 	    tex_print_double(x, prn);
984 	    if (j == vecm->neqns - 1) {
985 		pputs(prn, "\\\\\n");
986 	    } else {
987 		pputs(prn, " & ");
988 	    }
989 	}
990     }
991 
992     pputs(prn, "\\end{tabular}\n\n");
993     pputs(prn, "\\vspace{1em}\n");
994 
995     pputs(prn, "\\noindent\n");
996     pprintf(prn, "%s = ", _("determinant"));
997     tex_print_double(exp(vecm->ldet), prn);
998     pputs(prn, "\\\\\n");
999 }
1000 
tex_beta_vname(char * s,const GRETL_VAR * v,const DATASET * dset,int i,PRN * prn)1001 static void tex_beta_vname (char *s,
1002 			    const GRETL_VAR *v,
1003 			    const DATASET *dset,
1004 			    int i, PRN *prn)
1005 {
1006     if (i < v->neqns) {
1007 	tex_escape(s, dset->varname[v->ylist[i+1]]);
1008 	pprintf(prn, "%s$_{t-1}$ & ", s);
1009     } else if (auto_restr(v) && i == v->neqns) {
1010 	pprintf(prn, "%s & ", (jcode(v) == J_REST_CONST)? "const" : "trend");
1011     } else if (v->rlist != NULL) {
1012 	int k = i - v->ylist[0] - auto_restr(v) + 1;
1013 
1014 	tex_escape(s, dset->varname[v->rlist[k]]);
1015 	pprintf(prn, "%s$_{t-1}$ & ", s);
1016     }
1017 }
1018 
tex_print_VECM_coint_eqns(GRETL_VAR * vecm,const DATASET * dset,PRN * prn)1019 void tex_print_VECM_coint_eqns (GRETL_VAR *vecm, const DATASET *dset, PRN *prn)
1020 {
1021     char s[32];
1022     JohansenInfo *jv = vecm->jinfo;
1023     int rows = gretl_matrix_rows(jv->Beta);
1024     int i, j;
1025     double x;
1026 
1027     pputs(prn, "\\noindent\n");
1028     pputs(prn, _("Cointegrating vectors"));
1029     if (jv->Bse != NULL) {
1030 	pprintf(prn, " (%s)\n", _("standard errors in parentheses"));
1031     } else {
1032 	pputc(prn, '\n');
1033     }
1034 
1035     pputs(prn, "\n\\vspace{1em}\n");
1036 
1037     pputs(prn, "\\begin{tabular}{");
1038     pputs(prn, "l");
1039     for (i=0; i<jv->rank; i++) {
1040 	pputs(prn, "r");
1041     }
1042     pputs(prn, "}\n");
1043 
1044     for (i=0; i<rows; i++) {
1045 	tex_beta_vname(s, vecm, dset, i, prn);
1046 
1047 	/* coefficients */
1048 	for (j=0; j<jv->rank; j++) {
1049 	    x = gretl_matrix_get(jv->Beta, i, j);
1050 	    if (jv->Bse == NULL) {
1051 		x /= gretl_matrix_get(jv->Beta, j, j);
1052 	    }
1053 	    tex_print_double(x, prn);
1054 	    if (j == jv->rank - 1) {
1055 		pputs(prn, "\\\\\n");
1056 	    } else {
1057 		pputs(prn, "& ");
1058 	    }
1059 	}
1060 
1061 	if (jv->Bse != NULL) {
1062 	    /* standard errors */
1063 	    pputs(prn, " & ");
1064 	    for (j=0; j<jv->rank; j++) {
1065 		x = gretl_matrix_get(jv->Bse, i, j);
1066 		pputc(prn, '(');
1067 		tex_print_double(x, prn);
1068 		pputc(prn, ')');
1069 		if (j == jv->rank - 1) {
1070 		    pputs(prn, "\\\\\n");
1071 		} else {
1072 		    pputs(prn, "& ");
1073 		}
1074 	    }
1075 	}
1076     }
1077 
1078     pputs(prn, "\\end{tabular}\n\n\\vspace{1em}\n");
1079     pputc(prn, '\n');
1080 
1081     rows = gretl_matrix_rows(jv->Alpha);
1082 
1083     pputs(prn, "\\noindent\n");
1084     pprintf(prn, _("Adjustment vectors"));
1085     if (jv->Ase != NULL) {
1086 	pprintf(prn, " (%s)\n", _("standard errors in parentheses"));
1087     } else {
1088 	pputc(prn, '\n');
1089     }
1090 
1091     pputs(prn, "\n\\vspace{1em}\n");
1092 
1093     pputs(prn, "\\begin{tabular}{");
1094     pputs(prn, "l");
1095     for (i=0; i<jv->rank; i++) {
1096 	pputs(prn, "r");
1097     }
1098     pputs(prn, "}\n");
1099 
1100     for (i=0; i<rows; i++) {
1101 	tex_beta_vname(s, vecm, dset, i, prn);
1102 
1103 	/* coefficients */
1104 	for (j=0; j<jv->rank; j++) {
1105 	    x = gretl_matrix_get(jv->Alpha, i, j);
1106 	    if (jv->Ase == NULL) {
1107 		x /= gretl_matrix_get(jv->Alpha, j, j);
1108 	    }
1109 	    tex_print_double(x, prn);
1110 	    if (j == jv->rank - 1) {
1111 		pputs(prn, "\\\\\n");
1112 	    } else {
1113 		pputs(prn, "& ");
1114 	    }
1115 	}
1116 
1117 	if (jv->Ase != NULL) {
1118 	    /* standard errors */
1119 	    pputs(prn, " & ");
1120 	    for (j=0; j<jv->rank; j++) {
1121 		x = gretl_matrix_get(jv->Ase, i, j);
1122 		pputc(prn, '(');
1123 		tex_print_double(x, prn);
1124 		pputc(prn, ')');
1125 		if (j == jv->rank - 1) {
1126 		    pputs(prn, "\\\\\n");
1127 		} else {
1128 		    pputs(prn, "& ");
1129 		}
1130 	    }
1131 	}
1132     }
1133 
1134     pputs(prn, "\\end{tabular}\n\n\\vspace{1em}\n");
1135     pputc(prn, '\n');
1136 
1137 }
1138 
tex_print_VAR_ll_stats(GRETL_VAR * var,PRN * prn)1139 void tex_print_VAR_ll_stats (GRETL_VAR *var, PRN *prn)
1140 {
1141     pprintf(prn, "\\noindent\n%s = ", _("Log-likelihood"));
1142     tex_print_double(var->ll, prn);
1143     pputs(prn, "\\par\n");
1144 
1145     pprintf(prn, "\\noindent\n%s = ", _("Determinant of covariance matrix"));
1146     tex_print_double(exp(var->ldet), prn);
1147     pputs(prn, "\\par\n");
1148 
1149     pprintf(prn, "\\noindent\n%s $= %.4f$ \\par\n", _("AIC"), var->AIC);
1150     pprintf(prn, "\\noindent\n%s $= %.4f$ \\par\n", _("BIC"), var->BIC);
1151     pprintf(prn, "\\noindent\n%s $= %.4f$ \\par\n", _("HQC"), var->HQC);
1152 }
1153 
make_tex_prn(const char * fname,int eqn,int doc,int * err)1154 static PRN *make_tex_prn (const char *fname,
1155 			  int eqn, int doc,
1156 			  int *err)
1157 {
1158     PrnFormat fmt = GRETL_FORMAT_TEX;
1159     PRN *prn;
1160 
1161     gretl_maybe_switch_dir(fname);
1162     prn = gretl_print_new_with_filename(fname, err);
1163 
1164     if (prn != NULL) {
1165 	if (eqn) {
1166 	    fmt |= GRETL_FORMAT_EQN;
1167 	}
1168 	if (doc) {
1169 	    fmt |= GRETL_FORMAT_DOC;
1170 	}
1171 	gretl_print_set_format(prn, fmt);
1172     }
1173 
1174     return prn;
1175 }
1176 
1177 /* mechanism for customizing gretl's tex preamble */
1178 
1179 static char tex_preamble_file[MAXLEN];
1180 
set_tex_locale_filename(char * local)1181 static const char *set_tex_locale_filename (char *local)
1182 {
1183     char *lang = getenv("LANG");
1184 
1185     *local = '\0';
1186 
1187     if (lang != NULL) {
1188 	char lstr[3] = {0};
1189 
1190 	strncat(lstr, lang, 2);
1191 	sprintf(local, "gretlpre_%s.tex", lstr);
1192     }
1193 
1194     return local;
1195 }
1196 
find_gretlpre(const char * path,const char * localname)1197 static int find_gretlpre (const char *path, const char *localname)
1198 {
1199     char test[MAXLEN];
1200     int err, gotit = 0;
1201 
1202     if (*localname != '\0') {
1203 	/* localized preamble file? */
1204 	sprintf(test, "%s%s", path, localname);
1205 	err = gretl_test_fopen(test, "r");
1206 	if (!err) {
1207 	    strcpy(tex_preamble_file, test);
1208 	    gotit = 1;
1209 	}
1210     }
1211 
1212     if (!gotit) {
1213 	/* regular preamble file? */
1214 	sprintf(test, "%sgretlpre.tex", path);
1215 	err = gretl_test_fopen(test, "r");
1216 	if (!err) {
1217 	    strcpy(tex_preamble_file, test);
1218 	    gotit = 1;
1219 	}
1220     }
1221 
1222     return gotit;
1223 }
1224 
set_gretl_tex_preamble(void)1225 void set_gretl_tex_preamble (void)
1226 {
1227     const char *path = gretl_workdir();
1228     char localname[16];
1229     int gotit;
1230 
1231     set_tex_locale_filename(localname);
1232     gotit = find_gretlpre(path, localname);
1233 
1234     if (!gotit) {
1235 	path = maybe_get_default_workdir();
1236 	if (path != NULL) {
1237 	    gotit = find_gretlpre(path, localname);
1238 	}
1239     }
1240 
1241     if (!gotit) {
1242 #ifdef OS_OSX
1243 	path = gretl_app_support_dir();
1244 #else
1245 	path = gretl_dotdir();
1246 #endif
1247 	gotit = find_gretlpre(path, localname);
1248     }
1249 
1250     gretl_error_clear();
1251 }
1252 
landscape_modify_line(char * line)1253 static void landscape_modify_line (char *line)
1254 {
1255     char *p, *rem;
1256 
1257     if (strstr(line, "landscape")) {
1258 	return;
1259     }
1260 
1261     p = strstr(line, "documentclass");
1262 
1263     if (p != NULL) {
1264 	if (*(p + 13) == '[') {
1265 	    p = strchr(p, ']');
1266 	    if (p != NULL) {
1267 		rem = gretl_strdup(p);
1268 		if (rem != NULL) {
1269 		    sprintf(p, ",landscape%s", rem);
1270 		    free(rem);
1271 		}
1272 	    }
1273 	} else {
1274 	    p += 13;
1275 	    rem = gretl_strdup(p);
1276 	    if (rem != NULL) {
1277 		sprintf(p, "[landscape]%s", rem);
1278 		free(rem);
1279 	    }
1280 	}
1281     }
1282 }
1283 
gretl_tex_preamble(PRN * prn,int fmt)1284 void gretl_tex_preamble (PRN *prn, int fmt)
1285 {
1286     char *lang = getenv("LANG");
1287     FILE *fp = NULL;
1288     int userfile = 0;
1289 
1290     if (*tex_preamble_file != '\0') {
1291 	fp = gretl_fopen(tex_preamble_file, "r");
1292 	if (fp != NULL) {
1293 	    char line[256];
1294 
1295 	    /* FIXME model table: longtable and geom packages */
1296 
1297 	    while (fgets(line, sizeof line, fp)) {
1298 		if (strstr(line, "documentclass") &&
1299 		    (fmt & GRETL_FORMAT_LANDSCAPE)) {
1300 		    landscape_modify_line(line);
1301 		}
1302 		pputs(prn, line);
1303 	    }
1304 	    userfile = 1;
1305 	    fclose(fp);
1306 	    fprintf(stderr, "gretltex: using preamble file\n %s\n",
1307 		    tex_preamble_file);
1308 	}
1309     }
1310 
1311     if (!userfile) {
1312 	const char *paper = in_usa()? "letterpaper" : "a4paper";
1313 	const char *driver = use_pdf ? "pdftex" : "dvips";
1314 	const char *margin = "";
1315 
1316 	if (fmt & GRETL_FORMAT_MODELTAB) {
1317 	    margin = "margin=2cm,";
1318 	}
1319 
1320 	pputs(prn, "\\documentclass");
1321 
1322 	if (fmt & GRETL_FORMAT_MODELTAB) {
1323 	    if (fmt & GRETL_FORMAT_LANDSCAPE) {
1324 		pputs(prn, "[landscape]");
1325 	    }
1326 	} else if (fmt & GRETL_FORMAT_LANDSCAPE) {
1327 	    pputs(prn, "[11pt,landscape]");
1328 	} else {
1329 	    pputs(prn, "[11pt]");
1330 	}
1331 
1332 	pputs(prn, "{article}\n");
1333 
1334 #ifdef ENABLE_NLS
1335 	pputs(prn, "\\usepackage[utf8]{inputenc}\n");
1336 #endif
1337 
1338 	if (lang != NULL && !strncmp(lang, "ru", 2)) {
1339 	    pputs(prn, "\\usepackage[russian]{babel}\n");
1340 	}
1341 
1342 	pprintf(prn, "\\usepackage[%s,%s%s]{geometry}\n", paper, margin,
1343 		driver);
1344 
1345 	if (fmt & GRETL_FORMAT_EQN) {
1346 	    pputs(prn, "\\usepackage{amsmath}\n");
1347 	} else {
1348 	    pputs(prn, "\\usepackage{longtable}\n");
1349 	}
1350 
1351 	pputs(prn, "\n\\begin{document}\n\n"
1352 	      "\\thispagestyle{empty}\n\n");
1353     }
1354 }
1355 
1356 /* For use when printing a model in equation style: print the value
1357    unsigned, since the sign will be handled separately.
1358 */
1359 
tex_print_unsigned_double(double x,PRN * prn)1360 static void tex_print_unsigned_double (double x, PRN *prn)
1361 {
1362     tex_print_double(fabs(x), prn);
1363 }
1364 
1365 #define MAXCOEFF 4
1366 
1367 /**
1368  * tex_print_equation:
1369  * @pmod:  pointer to gretl MODEL struct.
1370  * @dset:  information regarding the data set.
1371  * @opt: can include %OPT_S for a standalone document, and
1372  * %OPT_T to print t-ratios rather than standard errors.
1373  * @prn: gretl printing struct.
1374  *
1375  * Prints to @prn a gretl model in the form of a LaTeX equation, either as
1376  * a stand-alone document or as a fragment of LaTeX source for
1377  * insertion into a document.
1378  *
1379  * Returns: 0 on successful completion.
1380  */
1381 
tex_print_equation(const MODEL * pmod,const DATASET * dset,gretlopt opt,PRN * prn)1382 int tex_print_equation (const MODEL *pmod, const DATASET *dset,
1383 			gretlopt opt, PRN *prn)
1384 {
1385     double x;
1386     char tmp[48], vname[32];
1387     int i, nc = pmod->ncoeff;
1388     int split = 0, offvar = 0;
1389     int cchars = 0, ccount = 0;
1390     int se_digits;
1391     int sderr_ok = 1;
1392 
1393     if (pmod->ci == HECKIT) {
1394 	return E_NOTIMP;
1395     }
1396 
1397     if (COUNT_MODEL(pmod->ci)) {
1398 	offvar = gretl_model_get_int(pmod, "offset_var");
1399 	if (offvar > 0) {
1400 	    nc++;
1401 	}
1402     }
1403 
1404     split = (nc > MAXCOEFF);
1405 
1406     if (opt & OPT_S) {
1407 	gretl_tex_preamble(prn, GRETL_FORMAT_EQN);
1408     } else{
1409 	pputs(prn, "%%% the following needs the amsmath LaTeX package\n\n");
1410     }
1411 
1412     /* initial setup */
1413     pputs(prn, "\\begin{gather}\n");
1414     if (split) {
1415 	pputs(prn, "\\begin{split}\n");
1416     }
1417 
1418     /* dependent variable */
1419     *tmp = '\0';
1420     if (pmod->depvar != NULL) {
1421 	tex_escape(tmp, pmod->depvar);
1422     } else {
1423 	i = gretl_model_get_depvar(pmod);
1424 	tex_escape(tmp, dset->varname[i]);
1425     }
1426 
1427     if (0 /* FIXME should this apply for DPANEL? (was ARBOND-specific) */) {
1428 	pprintf(prn, "\\widehat{\\Delta \\rm %s} %s= \n", tmp, (split? "&" : ""));
1429     } else {
1430 	pprintf(prn, "\\widehat{\\rm %s} %s= \n", tmp, (split? "&" : ""));
1431     }
1432 
1433     if (pmod->ci == GARCH) {
1434 	nc -= (1 + pmod->list[1] + pmod->list[2]);
1435     } else if (pmod->ci == PANEL) {
1436 	nc = pmod->list[0] - 1;
1437     }
1438 
1439     se_digits = get_gretl_digits();
1440     se_digits = se_digits > 5 ? 5 : se_digits;
1441 
1442     /* coefficients times indep vars */
1443     for (i=0; i<nc; i++) {
1444 	if (offvar > 0 && i == nc - 1) {
1445 	    pputc(prn, '+');
1446 	    tex_print_double(1.0, prn);
1447 	} else {
1448 	    if (na(pmod->sderr[i])) {
1449 		sderr_ok = 0;
1450 		pprintf(prn, "%s{", (pmod->coeff[i] < 0.0)? "-" :
1451 			(i > 0)? "+" : "");
1452 	    } else if (sderr_ok) {
1453 		if (opt & OPT_T) {
1454 		    /* t-ratios */
1455 		    x = pmod->coeff[i] / pmod->sderr[i];
1456 		    pprintf(prn, "%s\\underset{(%.3f)}{",
1457 			    (pmod->coeff[i] < 0.0)? "-" :
1458 			    (i > 0)? "+" : "", x);
1459 		} else {
1460 		    /* standard errors */
1461 		    tex_sprint_math_double_digits(pmod->sderr[i], tmp, se_digits);
1462 		    pprintf(prn, "%s\\underset{(%s)}{",
1463 			    (pmod->coeff[i] < 0.0)? "-" :
1464 			    (i > 0)? "+" : "", tmp);
1465 		}
1466 	    }
1467 	    tex_print_unsigned_double(pmod->coeff[i], prn);
1468 	    pputc(prn, '}');
1469 	}
1470 
1471 	if (i > 0 || pmod->ifc == 0) {
1472 	    /* regular coefficient, not const */
1473 	    if (offvar > 0 && i == nc - 1) {
1474 		strcpy(vname, dset->varname[offvar]);
1475 	    } else {
1476 		gretl_model_get_param_name(pmod, dset, i, vname);
1477 	    }
1478 	    cchars += strlen(vname);
1479 
1480 	    pputs(prn, "\\,");
1481 
1482 	    if (pmod->ci == ARMA) {
1483 		tex_arma_coeff_name(tmp, vname, 1);
1484 		pputs(prn, tmp);
1485 	    } else if (pmod->ci == GARCH) {
1486 		tex_garch_coeff_name(tmp, vname, 1);
1487 		pputs(prn, tmp);
1488 	    } else if (pmod->ci == MPOLS) {
1489 		tex_mp_coeff_name(tmp, vname, 1);
1490 		pputs(prn, tmp);
1491 	    } else {
1492 		tex_escape(tmp, vname);
1493 		pprintf(prn, "\\mbox{%s}", tmp);
1494 	    }
1495 	}
1496 	ccount++;
1497 	if (split && (cchars > 30 || ccount > 3)) {
1498 	    pputs(prn, "\\\\\n& ");
1499 	    cchars = ccount = 0;
1500 	} else {
1501 	    pputc(prn, '\n');
1502 	}
1503     }
1504 
1505     if (split) {
1506 	pputs(prn, "\\end{split}\n");
1507     }
1508 
1509     pputs(prn, " \\notag \\\\\n");
1510 
1511     if (pmod->ci == GARCH) {
1512 	int q = pmod->list[1];
1513 	int p = pmod->list[2];
1514 	int r = pmod->list[0] - 4;
1515 
1516 	if (opt & OPT_T) {
1517 	    x = pmod->coeff[r] / pmod->sderr[r];
1518 	    pprintf(prn, "\\hat{\\sigma}^2_t = \\underset{(%.3f)}{%g} ",
1519 		    x, pmod->coeff[r]);
1520 	} else {
1521 	    tex_sprint_math_double_digits(pmod->sderr[r], tmp, se_digits);
1522 	    pprintf(prn, "\\hat{\\sigma}^2_t = \\underset{(%s)}{%g} ", /* FIXME? */
1523 		    tmp, pmod->coeff[r]);
1524 	}
1525 
1526 	for (i=1; i<=q; i++) {
1527 	    if (opt & OPT_T) {
1528 		x = pmod->coeff[r+i] / pmod->sderr[r+i];
1529 		pprintf(prn, "%s\\underset{(%.3f)}{",
1530 			(pmod->coeff[r+i] < 0.0)? "-" : "+", x);
1531 	    } else {
1532 		tex_sprint_math_double_digits(pmod->sderr[r+i], tmp, se_digits);
1533 		pprintf(prn, "%s\\underset{(%s)}{",
1534 			(pmod->coeff[r+i] < 0.0)? "-" : "+", tmp);
1535 	    }
1536 	    tex_print_unsigned_double(pmod->coeff[r+i], prn);
1537 	    pputs(prn, "}\\,");
1538 	    pprintf(prn, "\\varepsilon^2_{t-%d}", i);
1539 	}
1540 
1541 	for (i=1; i<=p; i++) {
1542 	    if (opt & OPT_T) {
1543 		x = pmod->coeff[q+r+i] / pmod->sderr[q+r+i];
1544 		pprintf(prn, "%s\\underset{(%.3f)}{",
1545 			(pmod->coeff[q+r+i] < 0.0)? "-" : "+", x);
1546 	    } else {
1547 		tex_sprint_math_double_digits(pmod->sderr[q+r+i], tmp, se_digits);
1548 		pprintf(prn, "%s\\underset{(%s)}{",
1549 			(pmod->coeff[q+r+i] < 0.0)? "-" : "+", tmp);
1550 	    }
1551 	    tex_print_unsigned_double(pmod->coeff[q+r+i], prn);
1552 	    pputs(prn, "}\\,");
1553 	    pprintf(prn, "\\sigma^2_{t-%d}", i);
1554 	}
1555 
1556 	pputs(prn, "\\notag \\\\\n");
1557     }
1558 
1559     pprintf(prn, "T = %d ", pmod->nobs);
1560 
1561     /* additional info (R^2 etc) */
1562     if (pmod->ci == LAD) {
1563 	x = gretl_model_get_double(pmod, "ladsum");
1564 	if (!na(x)) {
1565 	    tex_sprint_math_double_digits(x, tmp, 5);
1566 	    pprintf(prn, "\\quad \\sum |\\hat{u}_t| = %s ", tmp);
1567 	}
1568     } else {
1569 	if (!na(pmod->adjrsq)) {
1570 	    pprintf(prn, "\\quad \\bar{R}^2 = %.4f ", pmod->adjrsq);
1571 	} else if (!na(pmod->lnL)) {
1572 	    pprintf(prn, "\\quad \\mbox{ln}L = %.4f ", pmod->lnL);
1573 	}
1574 
1575 	if (pmod->ci != LOGIT && pmod->ci != PROBIT && !na(pmod->fstt)) {
1576 	    tex_sprint_math_double_digits(pmod->fstt, tmp, 5);
1577 	    pprintf(prn, "\\quad F(%d,%d) = %s ",
1578 		    pmod->dfn, pmod->dfd, tmp);
1579 	}
1580 
1581 	if (!na(pmod->sigma)) {
1582 	    tex_sprint_math_double_digits(pmod->sigma, tmp, 5);
1583 	    pprintf(prn, "\\quad \\hat{\\sigma} = %s ", tmp);
1584 	}
1585 
1586 	if (!na(gretl_model_get_double(pmod, "rho_gls"))) {
1587 	    x = gretl_model_get_double(pmod, "rho_gls");
1588 	    tex_sprint_math_double_digits(x, tmp, 5);
1589 	    pprintf(prn, " \\quad \\rho = %s", tmp);
1590 	}
1591     }
1592 
1593     pputs(prn, "\\notag \\\\\n");
1594 
1595     if (sderr_ok) {
1596 	pprintf(prn, "\\centerline{(%s)} \\notag\n",
1597 		(opt & OPT_T)? _("$t$-statistics in parentheses") :
1598 		_("standard errors in parentheses"));
1599     } else {
1600 	pputs(prn, "\\notag\n");
1601     }
1602 
1603     pputs(prn, "\\end{gather}\n");
1604 
1605     if (opt & OPT_S) {
1606 	pputs(prn, "\n\\end{document}\n");
1607     }
1608 
1609     return 0;
1610 }
1611 
1612 /**
1613  * tex_print_model:
1614  * @pmod:  pointer to gretl MODEL struct.
1615  * @dset: information regarding the data set.
1616  * @opt: may include %OPT_T in case of printing a model
1617  * in equation format, to use t-ratios instead of standard
1618  * errors.
1619  * @prn: gretl printing struct.
1620  *
1621  * Prints to @prn a gretl model in the form of either a LaTeX
1622  * table or an equation, and either as a stand-alone document or
1623  * as a fragment of LaTeX source for insertion into a document.
1624  *
1625  * The options are read from the format field of @prn --
1626  * gretl_print_set_format().
1627  *
1628  * Returns: 0 on successful completion.
1629  */
1630 
tex_print_model(MODEL * pmod,const DATASET * dset,gretlopt opt,PRN * prn)1631 int tex_print_model (MODEL *pmod, const DATASET *dset,
1632 		     gretlopt opt, PRN *prn)
1633 {
1634     int err = 0;
1635 
1636     if (RQ_SPECIAL_MODEL(pmod)) {
1637 	return E_NOTIMP;
1638     }
1639 
1640     if (tex_doc_format(prn)) {
1641 	opt |= OPT_S;
1642     }
1643 
1644     if (tex_eqn_format(prn)) {
1645 	err = tex_print_equation(pmod, dset, opt, prn);
1646     } else {
1647 	if (opt & OPT_T) {
1648 	    /* --format option */
1649 	    const char *s = get_optval_string(TABPRINT, OPT_T);
1650 
1651 	    err = set_tex_param_format(s);
1652 	}
1653 	if (!err) {
1654 	    err = printmodel(pmod, dset, OPT_NONE, prn);
1655 	}
1656     }
1657 
1658     return err;
1659 }
1660 
1661 /**
1662  * texprint:
1663  * @pmod: pointer to model.
1664  * @dset: information regarding the data set.
1665  * @fname: name of file to save.
1666  * @opt: if opt & %OPT_O, complete doc, else fragment;
1667  * if opt & %OPT_E print as equation, otherwise use tabular
1668  * format; if opt & %OPT_T show t-ratios rather than standard
1669  * errors when printing in equation format.
1670  *
1671  * Prints to file a gretl model in the form of a LaTeX table or
1672  * equation, either as a stand-alone document or as a fragment
1673  * of LaTeX source for insertion into a document.
1674  *
1675  * Returns: 0 on successful completion, 1 on error.
1676  */
1677 
texprint(MODEL * pmod,const DATASET * dset,const char * fname,gretlopt opt)1678 int texprint (MODEL *pmod, const DATASET *dset,
1679 	      const char *fname, gretlopt opt)
1680 {
1681     PRN *prn;
1682     int eqn = (opt & OPT_E);
1683     int doc = (opt & OPT_O);
1684     int err = 0;
1685 
1686     if (RQ_SPECIAL_MODEL(pmod)) {
1687 	return E_NOTIMP;
1688     }
1689 
1690     prn = make_tex_prn(fname, eqn, doc, &err);
1691 
1692     if (!err) {
1693 	err = tex_print_model(pmod, dset, opt, prn);
1694 	gretl_print_destroy(prn);
1695     }
1696 
1697     return err;
1698 }
1699 
out_crlf(const char * buf,FILE * fp)1700 static void out_crlf (const char *buf, FILE *fp)
1701 {
1702     const char *p = buf;
1703 
1704 #ifdef G_OS_WIN32
1705     /* fputs on Windows should take care of CR, LF */
1706     fputs(p, fp);
1707 #else
1708     while (*p) {
1709 	if (*p == '\n') {
1710 	    fputs("\r\n", fp);
1711 	} else {
1712 	    fputc(*p, fp);
1713 	}
1714 	p++;
1715     }
1716 #endif
1717 }
1718 
rtfprint(MODEL * pmod,const DATASET * dset,const char * fname,gretlopt opt)1719 int rtfprint (MODEL *pmod, const DATASET *dset,
1720 	      const char *fname, gretlopt opt)
1721 {
1722     const char *buf = NULL;
1723     char *trbuf = NULL;
1724     PRN *prn;
1725     int err = 0;
1726 
1727     if (RQ_SPECIAL_MODEL(pmod)) {
1728 	return E_NOTIMP;
1729     }
1730 
1731     prn = gretl_print_new(GRETL_PRINT_BUFFER, &err);
1732 
1733     if (!err) {
1734 	/* print the model to buffer first */
1735 	gretl_print_set_format(prn, GRETL_FORMAT_RTF);
1736 	err = printmodel(pmod, dset, opt, prn);
1737     }
1738 
1739     if (!err) {
1740 	/* recode if necessary */
1741 	buf = gretl_print_get_buffer(prn);
1742 	if (!gretl_is_ascii(buf)) {
1743 	    trbuf = utf8_to_rtf(buf);
1744 	    if (trbuf == NULL) {
1745 		err = E_ALLOC;
1746 	    }
1747 	}
1748     }
1749 
1750     if (!err) {
1751 	/* now send to file, converting LF to CR + LF
1752 	   as we go, if required
1753 	*/
1754 	FILE *fp;
1755 
1756 	gretl_maybe_switch_dir(fname);
1757 	fp = gretl_fopen(fname, "w");
1758 
1759 	if (fp == NULL) {
1760 	    err = E_FOPEN;
1761 	} else if (trbuf != NULL) {
1762 	    out_crlf(trbuf, fp);
1763 	} else {
1764 	    out_crlf(buf, fp);
1765 	}
1766 
1767 	if (fp != NULL) {
1768 	    fclose(fp);
1769 	}
1770     }
1771 
1772     if (trbuf != NULL) {
1773 	free(trbuf);
1774     }
1775 
1776     if (prn != NULL) {
1777 	gretl_print_destroy(prn);
1778     }
1779 
1780     return err;
1781 }
1782 
out_native(const char * buf,FILE * fp)1783 static void out_native (const char *buf, FILE *fp)
1784 {
1785 #ifdef G_OS_WIN32
1786     if (!gretl_is_ascii(buf)) {
1787 	/* Windows: if the text is UTF-8, prepend
1788 	   the UTF-8 BOM */
1789 	fputc(0xEF, fp);
1790 	fputc(0xBB, fp);
1791 	fputc(0xBF, fp);
1792     }
1793 #endif
1794     fputs(buf, fp);
1795 }
1796 
csvprint(MODEL * pmod,const DATASET * dset,const char * fname,gretlopt opt)1797 int csvprint (MODEL *pmod, const DATASET *dset,
1798 	      const char *fname, gretlopt opt)
1799 {
1800     PRN *prn;
1801     int err = 0;
1802 
1803     if (RQ_SPECIAL_MODEL(pmod)) {
1804 	return E_NOTIMP;
1805     }
1806 
1807     prn = gretl_print_new(GRETL_PRINT_BUFFER, &err);
1808 
1809     if (!err) {
1810 	/* print to buffer first */
1811 	gretl_print_set_format(prn, GRETL_FORMAT_CSV);
1812 	err = printmodel(pmod, dset, opt, prn);
1813     }
1814 
1815     if (!err) {
1816 	/* then send to file */
1817 	const char *buf = gretl_print_get_buffer(prn);
1818 	FILE *fp;
1819 
1820 	gretl_maybe_switch_dir(fname);
1821 	fp = gretl_fopen(fname, "w");
1822 
1823 	if (fp == NULL) {
1824 	    err = E_FOPEN;
1825 	} else {
1826 	    out_native(buf, fp);
1827 	}
1828 
1829 	if (fp != NULL) {
1830 	    fclose(fp);
1831 	}
1832     }
1833 
1834     if (prn != NULL) {
1835 	gretl_print_destroy(prn);
1836     }
1837 
1838     return err;
1839 }
1840 
1841 /**
1842  * tex_print_obs_marker:
1843  * @t: observation number.
1844  * @dset: data information struct.
1845  * @prn: gretl printing struct.
1846  *
1847  * Print a string (label, date or obs number) representing the given @t.
1848  */
1849 
tex_print_obs_marker(int t,const DATASET * dset,PRN * prn)1850 void tex_print_obs_marker (int t, const DATASET *dset, PRN *prn)
1851 {
1852     if (dset->markers) {
1853 	pprintf(prn, "\\texttt{%s} ", dset->S[t]);
1854     } else {
1855 	char tmp[OBSLEN];
1856 
1857 	ntolabel(tmp, t, dset);
1858 	pprintf(prn, "%8s ", tmp);
1859     }
1860 }
1861 
check_colspec(const char * s)1862 static int check_colspec (const char *s)
1863 {
1864     const char *ok = "eEfgG";
1865     int w = 0, p = 0;
1866     char c = 0;
1867     int err = 1;
1868 
1869     /* blank is OK */
1870     if (*s == '\0') {
1871 	return 0;
1872     }
1873 
1874     if (*s != '%') {
1875 	return 1;
1876     }
1877 
1878     s++;
1879 
1880     if (*s == '#') { /* OK */
1881 	s++;
1882     }
1883 
1884     if (sscanf(s, "%d.%d%c", &w, &p, &c) == 3) {
1885 	if (w != 0 && p > 0 && strchr(ok, c)) {
1886 	    err = 0;
1887 	}
1888     } else if (sscanf(s, "%d%c", &w, &c) == 2) {
1889 	if (w != 0 && strchr(ok, c)) {
1890 	    err = 0;
1891 	}
1892     } else if (sscanf(s, ".%d%c", &p, &c) == 2) {
1893 	if (p > 0 && strchr(ok, c)) {
1894 	    err = 0;
1895 	}
1896     } else if (sscanf(s, "%c", &c) == 1) {
1897 	if (strchr(ok, c)) {
1898 	    err = 0;
1899 	}
1900     }
1901 
1902     return err;
1903 }
1904 
1905 /**
1906  * set_tex_param_format:
1907  * @s: stylized format string.
1908  *
1909  * Sets the format with which parameters will be printed, when
1910  * producing TeX tabular output.
1911  *
1912  * Returns: 0 on success, non-zero code on error.
1913  */
1914 
set_tex_param_format(const char * s)1915 int set_tex_param_format (const char *s)
1916 {
1917     const char *p = s;
1918     int i, n = 0;
1919     int err = 0;
1920 
1921     if (s == NULL || !strcmp(s, "default")) {
1922 	use_custom = 0;
1923 	return 0;
1924     }
1925 
1926     for (i=0; i<4; i++) {
1927 	colspec[i][0] = '\0';
1928     }
1929 
1930     i = 0;
1931 
1932     while (i < 4) {
1933 	if (*s == '|' || *s == '\0') {
1934 	    if (n > 7) {
1935 		n = 7;
1936 	    }
1937 	    strncat(colspec[i], p, n);
1938 #if 0
1939 	    fprintf(stderr, "spec %d = '%s'\n", i, colspec[i]);
1940 #endif
1941 	    err = check_colspec(colspec[i]);
1942 	    if (err || *s == '\0') {
1943 		break;
1944 	    }
1945 	    p = s + 1;
1946 	    i++;
1947 	    n = 0;
1948 	} else {
1949 	    n++;
1950 	}
1951 	s++;
1952     }
1953 
1954     if (!err) {
1955 	/* all columns can't be blank */
1956 	n = 0;
1957 	for (i=0; i<4; i++) {
1958 	    if (colspec[i][0] != '\0') n++;
1959 	}
1960 	if (n == 0) {
1961 	    err = E_ARGS;
1962 	}
1963     }
1964 
1965     if (err) {
1966 	for (i=0; i<4; i++) {
1967 	    colspec[i][0] = '\0';
1968 	}
1969 	use_custom = 0;
1970     } else {
1971 	use_custom = 1;
1972     }
1973 
1974     return err;
1975 }
1976