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 "libgretl.h"
21 #include "libset.h"
22 #include "gretl_func.h"
23 #include "uservar.h"
24 #include <stdarg.h>
25 #include <errno.h>
26 #include <glib/gprintf.h>
27
28 /**
29 * SECTION:gretl_prn
30 * @short_description: gretl printing struct
31 * @title: PRN
32 * @include: libgretl.h
33 *
34 * Most libgretl functions that print output call for a
35 * pointer-to-PRN as one of their arguments. The PRN type is
36 * an opaque structure, constructed and manipulated by the
37 * functions listed here. It is used as a means of generalizing
38 * the printing operation, which may be to a regular file, a
39 * temporary file or a buffer.
40 *
41 * To get hold of a PRN use gretl_print_new() or one of the more
42 * specific constructors, and to free it use gretl_print_destroy().
43 * If you want to use a PRN dirctly for printing in your own code, use
44 * the functions pprintf(), pputs() and pputc(). These are
45 * counterparts to the standard C functions fprintf, fputs and
46 * fputc, but note that with pputs and pputc the PRN argument
47 * must be given first (unlike fputs and fputc in which the
48 * FILE argument goes last).
49 *
50 * Note that whenever a PRN appears as a function parameter
51 * in libgretl it is OK to give a NULL argument: in that case
52 * pprintf(), pputs() and pputc() are no-ops.
53 */
54
55 struct PRN_ {
56 FILE *fp; /* file to which to print, or NULL */
57 gzFile fz; /* gzipped file target, or NULL */
58 char *buf; /* buffer to which to print, or NULL */
59 size_t bufsize; /* allocated size of buffer */
60 size_t blen; /* string length of buffer */
61 int savepos; /* saved position in stream or buffer */
62 GArray *fplist; /* stack for use with output redirection */
63 PrnFormat format; /* plain, TeX, RTF */
64 gint8 fixed; /* non-zero for fixed-size buffer */
65 gint8 gbuf; /* non-zero for buffer obtained via GLib */
66 guint8 nlcount; /* count of trailing newlines */
67 char delim; /* CSV field delimiter */
68 char *fname; /* temp file name, or NULL */
69 };
70
71 struct fpinfo_ {
72 FILE *fp; /* stream to which we're printing */
73 int level; /* level of depth of redicrection */
74 gchar *fname; /* name of file or NULL */
75 gchar *strvar; /* associated string variable or NULL */
76 };
77
78 typedef struct fpinfo_ fpinfo;
79
80 #define PRN_DEBUG 0
81
prn_destroy_fp_list(PRN * prn)82 static void prn_destroy_fp_list (PRN *prn)
83 {
84 int i, n = prn->fplist->len;
85 fpinfo *fi;
86
87 for (i=n-1; i>=0; i--) {
88 fi = &g_array_index(prn->fplist, fpinfo, i);
89 if (fi != NULL) {
90 if (fi->fp != NULL && fi->fp != prn->fp &&
91 fi->fp != stdout && fi->fp != stderr) {
92 fclose(fi->fp);
93 }
94 if (fi->fname != NULL) {
95 g_free(fi->fname);
96 }
97 if (fi->strvar != NULL) {
98 g_free(fi->strvar);
99 }
100 g_array_remove_index(prn->fplist, i);
101 }
102 }
103
104 g_array_free(prn->fplist, TRUE);
105 prn->fplist = NULL;
106 }
107
prn_fp_list_active(PRN * prn)108 static int prn_fp_list_active (PRN *prn)
109 {
110 return prn->fplist != NULL && prn->fplist->len > 0;
111 }
112
113 /**
114 * gretl_print_destroy:
115 * @prn: pointer to gretl printing struct.
116 *
117 * Close a gretl printing struct and free any associated resources.
118 */
119
gretl_print_destroy(PRN * prn)120 void gretl_print_destroy (PRN *prn)
121 {
122 if (prn == NULL) {
123 return;
124 }
125
126 if (prn->fplist != NULL) {
127 prn_destroy_fp_list(prn);
128 }
129
130 if (prn->fp != NULL) {
131 if (prn->fp == stdout) {
132 fflush(stdout);
133 } else if (prn->fp != stderr) {
134 #if PRN_DEBUG
135 fprintf(stderr, "gretl_print_destroy: prn=%p, closing fp at %p\n",
136 (void *) prn, (void *) prn->fp);
137 #endif
138 fclose(prn->fp);
139 }
140 } else if (prn->fz != NULL) {
141 gzclose(prn->fz);
142 }
143
144 if (prn->fname != NULL) {
145 /* prn had a tempfile attached */
146 gretl_remove(prn->fname);
147 free(prn->fname);
148 }
149
150 if (prn->buf != NULL) {
151 #if PRN_DEBUG
152 fprintf(stderr, "gretl_print_destroy: freeing buffer at %p\n",
153 (void *) prn->buf);
154 #endif
155 if (prn->gbuf) {
156 /* the buffer was obtained from GLib */
157 g_free(prn->buf);
158 } else {
159 free(prn->buf);
160 }
161 }
162
163 free(prn);
164 }
165
prn_add_tempfile(PRN * prn)166 static int prn_add_tempfile (PRN *prn)
167 {
168 const char *dotdir = gretl_dotdir();
169 int n = strlen(dotdir) + 16;
170 int err = 0;
171
172 prn->fname = malloc(n);
173 if (prn->fname == NULL) {
174 return E_ALLOC;
175 }
176
177 sprintf(prn->fname, "%sprntmp.XXXXXX", dotdir);
178 prn->fp = gretl_mktemp(prn->fname, "w+");
179
180 #if PRN_DEBUG
181 fprintf(stderr, "prn_add_tempfile: '%s' at %p\n",
182 prn->fname, (void *) prn->fp);
183 #endif
184
185 if (prn->fp == NULL) {
186 free(prn->fname);
187 prn->fname = NULL;
188 err = E_FOPEN;
189 }
190
191 return err;
192 }
193
real_gretl_print_new(PrnType ptype,const char * fname,char * buf,FILE * fp,int zcomp,int * perr)194 static PRN *real_gretl_print_new (PrnType ptype,
195 const char *fname,
196 char *buf,
197 FILE *fp,
198 int zcomp,
199 int *perr)
200 {
201 PRN *prn = malloc(sizeof *prn);
202 int err = 0;
203
204 if (prn == NULL) {
205 if (perr != NULL) {
206 *perr = E_ALLOC;
207 }
208 return NULL;
209 }
210
211 prn->fp = NULL;
212 prn->fz = NULL;
213 prn->fplist = NULL;
214 prn->buf = NULL;
215 prn->bufsize = 0;
216 prn->blen = 0;
217 prn->savepos = -1;
218 prn->format = GRETL_FORMAT_TXT;
219 prn->fixed = 0;
220 prn->gbuf = 0;
221 prn->nlcount = 0;
222 prn->delim = ',';
223 prn->fname = NULL;
224
225 if (ptype == GRETL_PRINT_STREAM) {
226 prn->fp = fp;
227 } else if (ptype == GRETL_PRINT_FILE) {
228 prn->fp = gretl_fopen(fname, "wb");
229 if (prn->fp == NULL) {
230 err = E_FOPEN;
231 free(prn);
232 prn = NULL;
233 }
234 } else if (ptype == GRETL_PRINT_GZFILE) {
235 prn->fz = gretl_gzopen(fname, "wb");
236 if (prn->fz == NULL) {
237 err = E_FOPEN;
238 free(prn);
239 prn = NULL;
240 } else if (zcomp >= 0) {
241 gzsetparams(prn->fz, zcomp, Z_DEFAULT_STRATEGY);
242 }
243 } else if (ptype == GRETL_PRINT_TEMPFILE) {
244 err = prn_add_tempfile(prn);
245 if (err) {
246 free(prn);
247 prn = NULL;
248 } else {
249 prn->savepos = 0;
250 }
251 } else if (ptype == GRETL_PRINT_STDOUT) {
252 prn->fp = stdout;
253 } else if (ptype == GRETL_PRINT_STDERR) {
254 prn->fp = stderr;
255 } else if (ptype == GRETL_PRINT_BUFFER) {
256 if (buf != NULL) {
257 prn->buf = buf;
258 prn->fixed = 1;
259 #if PRN_DEBUG
260 fprintf(stderr, "prn with fixed buffer\n");
261 #endif
262 } else {
263 int p = pprintf(prn, "@init");
264
265 if (p < 0) {
266 err = E_ALLOC;
267 free(prn);
268 prn = NULL;
269 }
270 }
271 }
272
273 #if PRN_DEBUG
274 fprintf(stderr, "real_gretl_print_new at %p: type=%d, fname='%s', "
275 "buf=%p, fp=%p\n", (void *) prn, ptype, fname,
276 (void *) buf, (void *) fp);
277 #endif
278
279 if (perr != NULL) {
280 *perr = err;
281 }
282
283 return prn;
284 }
285
286 /**
287 * gretl_print_new:
288 * @ptype: code indicating the desired printing mode.
289 * @err: location to receive error code, or NULL.
290 *
291 * Create and initialize a gretl printing struct. If @ptype
292 * is %GRETL_PRINT_BUFFER, output will go to an automatically
293 * resized buffer; if @ptype is %GRETL_PRINT_STDOUT or
294 * %GRETL_PRINT_STDERR output goes to %stdout or %stderr
295 * respectively.
296 *
297 * If you want a named file associated with the struct, use
298 * #gretl_print_new_with_filename instead; if you want to
299 * attach a fixed, pre-allocated text buffer, use
300 * #gretl_print_new_with_buffer.
301 *
302 * Returns: pointer to newly created struct, or NULL on failure.
303 */
304
gretl_print_new(PrnType ptype,int * err)305 PRN *gretl_print_new (PrnType ptype, int *err)
306 {
307 if (ptype == GRETL_PRINT_FILE) {
308 fprintf(stderr, "gretl_print_new: needs a filename\n");
309 return NULL;
310 }
311
312 #if PRN_DEBUG
313 fprintf(stderr, "gretl_print_new() called, type = %d\n", ptype);
314 #endif
315
316 return real_gretl_print_new(ptype, NULL, NULL, NULL, -1, err);
317 }
318
319 /**
320 * gretl_print_new_with_filename:
321 * @fname: name of the file to be opened for writing.
322 * @err: location to receive error code.
323 *
324 * Create and initialize a gretl printing struct, with
325 * output directed to the named file.
326 *
327 * Returns: pointer to newly created struct, or NULL on failure.
328 */
329
gretl_print_new_with_filename(const char * fname,int * err)330 PRN *gretl_print_new_with_filename (const char *fname, int *err)
331 {
332 if (fname == NULL) {
333 fprintf(stderr, _("gretl_prn_new: Must supply a filename\n"));
334 return NULL;
335 }
336
337 return real_gretl_print_new(GRETL_PRINT_FILE, fname,
338 NULL, NULL, -1, err);
339 }
340
341 /**
342 * gretl_gzip_print_new:
343 * @fname: name of the compressed file to be opened for writing.
344 * @comp_level: -1 for default, or integer 0 to 9.
345 * @err: location to receive error code.
346 *
347 * Create and initialize a gretl printing struct, with
348 * output directed to the named compressed file.
349 *
350 * Returns: pointer to newly created struct, or NULL on failure.
351 */
352
gretl_gzip_print_new(const char * fname,int comp_level,int * err)353 PRN *gretl_gzip_print_new (const char *fname, int comp_level,
354 int *err)
355 {
356 if (fname == NULL) {
357 fprintf(stderr, "gretl_gzip_print_new: must supply a filename\n");
358 return NULL;
359 } else if (comp_level < -1 || comp_level > 9) {
360 fprintf(stderr, "gretl_gzip_print_new: invalid compression level\n");
361 *err = E_INVARG;
362 return NULL;
363 }
364
365 return real_gretl_print_new(GRETL_PRINT_GZFILE, fname,
366 NULL, NULL, comp_level, err);
367 }
368
369 /**
370 * gretl_print_new_with_tempfile:
371 * @err: location to receive error code.
372 *
373 * Create and initialize a gretl printing struct, with
374 * output directed to a temporary file, which is deleted
375 * when the printing struct is destroyed.
376 *
377 * Returns: pointer to newly created struct, or NULL on failure.
378 */
379
gretl_print_new_with_tempfile(int * err)380 PRN *gretl_print_new_with_tempfile (int *err)
381 {
382 return real_gretl_print_new(GRETL_PRINT_TEMPFILE, NULL,
383 NULL, NULL, -1, err);
384 }
385
386 /**
387 * gretl_print_has_tempfile:
388 * @prn: printing struct to test.
389 *
390 * Returns: 1 if @prn has a tempfile attached, else 0.
391 */
392
gretl_print_has_tempfile(PRN * prn)393 int gretl_print_has_tempfile (PRN *prn)
394 {
395 if (prn != NULL && prn->fname != NULL && prn->fp != NULL) {
396 return strstr(prn->fname, "prntmp.") != NULL;
397 } else {
398 return 0;
399 }
400 }
401
402 /**
403 * gretl_print_get_tempfile_name:
404 * @prn: printing struct to test.
405 *
406 * Returns: if @prn has a tempfile attached, return the name
407 * of that file, otherwise return NULL.
408 */
409
gretl_print_get_tempfile_name(PRN * prn)410 const char *gretl_print_get_tempfile_name (PRN *prn)
411 {
412 if (prn != NULL) {
413 return prn->fname;
414 } else {
415 return NULL;
416 }
417 }
418
419 /**
420 * gretl_print_new_with_buffer:
421 * @buf: pre-allocated text buffer.
422 *
423 * Creates and initializes a gretl printing struct, with
424 * fixed text buffer @buf. Fails if @buf is NULL. This is a
425 * convenience function: you can't use #pprintf, #pputs or
426 * #pputc with a printing struct obtained in this way.
427 *
428 * Note that @buf will be freed if and when #gretl_print_destroy
429 * is called on the #PRN pointer obtained.
430 *
431 * Returns: pointer to newly created struct, or NULL on failure.
432 */
433
gretl_print_new_with_buffer(char * buf)434 PRN *gretl_print_new_with_buffer (char *buf)
435 {
436 if (buf == NULL) {
437 return NULL;
438 } else {
439 return real_gretl_print_new(GRETL_PRINT_BUFFER, NULL,
440 buf, NULL, -1, NULL);
441 }
442 }
443
444 /**
445 * gretl_print_new_with_gchar_buffer:
446 * @buf: pre-allocated text buffer.
447 *
448 * Just as gretl_print_new_with_buffer() except that the buffer is
449 * of pointer-to-gchar type, as obtained from one or other GLib
450 * function. This means that when the #PRN is detroyed the
451 * buffer will be freed using GLib's g_free function rather than
452 * the standard C library's free function.
453 *
454 * Returns: pointer to newly created struct, or NULL on failure.
455 */
456
gretl_print_new_with_gchar_buffer(gchar * buf)457 PRN *gretl_print_new_with_gchar_buffer (gchar *buf)
458 {
459 PRN *prn = NULL;
460
461 if (buf != NULL) {
462 prn = real_gretl_print_new(GRETL_PRINT_BUFFER, NULL,
463 buf, NULL, -1, NULL);
464 if (prn != NULL) {
465 prn->gbuf = 1;
466 }
467 }
468
469 return prn;
470 }
471
472 /**
473 * gretl_print_new_with_stream:
474 * @fp: pre-opened stream.
475 *
476 * Creates and initializes a gretl printing struct, with
477 * printing to @fp.
478 *
479 * Note that @fp will be closed if and when #gretl_print_destroy
480 * is called on the #PRN pointer obtained.
481 *
482 * Returns: pointer to newly created struct, or NULL on failure.
483 */
484
gretl_print_new_with_stream(FILE * fp)485 PRN *gretl_print_new_with_stream (FILE *fp)
486 {
487 if (fp == NULL) {
488 return NULL;
489 } else {
490 return real_gretl_print_new(GRETL_PRINT_STREAM, NULL,
491 NULL, fp, -1, NULL);
492 }
493 }
494
495 /**
496 * gretl_print_detach_stream
497 * @prn: printing struct to operate on.
498 *
499 * Sets the stream member of @prn to NULL so that @prn can
500 * be destroyed without closing the associated stream. May be
501 * used in conjunction with gretl_print_new_with_stream().
502 */
503
gretl_print_detach_stream(PRN * prn)504 void gretl_print_detach_stream (PRN *prn)
505 {
506 prn->fp = NULL;
507 }
508
509 /**
510 * gretl_print_rename_file:
511 * @prn: printing struct to operate on.
512 * @oldpath: name of current file (or NULL if @prn was
513 * set up using #gretl_print_new_with_tempfile).
514 * @newpath: new name for file.
515 *
516 * If @prn is printing to a %FILE pointer, rename the
517 * file to which it is printing and switch the stream
518 * to the new file.
519 *
520 * Returns: 0 on success, 1 on error.
521 */
522
gretl_print_rename_file(PRN * prn,const char * oldpath,const char * newpath)523 int gretl_print_rename_file (PRN *prn, const char *oldpath,
524 const char *newpath)
525 {
526 int err = 0;
527
528 if (prn == NULL) {
529 fprintf(stderr, "gretl_print_rename_file: prn is NULL\n");
530 return E_DATA;
531 }
532
533 if (prn->fp == NULL || prn_fp_list_active(prn)) {
534 return E_DATA;
535 }
536
537 #if PRN_DEBUG
538 fprintf(stderr, "gretl_print_rename_file, prn at %p:\n oldpath='%s'\n"
539 " newpath='%s'\n prn->fp=%p (closing)\n", (void *) prn,
540 oldpath, newpath, (void *) prn->fp);
541 fprintf(stderr, " (old prn->fname = '%s')\n", prn->fname);
542 #endif
543
544 fclose(prn->fp);
545 prn->fp = NULL;
546
547 if (oldpath == NULL && prn->fname != NULL) {
548 /* renaming from tempfile */
549 err = gretl_rename(prn->fname, newpath);
550 } else {
551 err = gretl_rename(oldpath, newpath);
552 }
553
554 if (err) {
555 fprintf(stderr, "%s\n", gretl_errmsg_get());
556 } else {
557 /* re-open the stream under its new name */
558 prn->fp = gretl_fopen(newpath, "a");
559 #if PRN_DEBUG
560 fprintf(stderr, "gretl_print_rename_file: new fp=%p\n", prn->fp);
561 #endif
562 if (prn->fname != NULL) {
563 /* @prn originally used a tempfile: the record of
564 the temporary filename should be deleted
565 */
566 free(prn->fname);
567 prn->fname = NULL;
568 }
569 }
570
571 return err;
572 }
573
574 /**
575 * gretl_print_reset_buffer:
576 * @prn: printing struct to operate on.
577 *
578 * If @prn has an attached buffer, write a NUL byte to
579 * the start of the buffer and reset the count of bytes
580 * printed to zero. The next call to @pprintf or
581 * similar will then overwite rather than cumulating
582 * the printed content.
583 *
584 * Returns: 0 on success, 1 if @prn has no buffer.
585 */
586
gretl_print_reset_buffer(PRN * prn)587 int gretl_print_reset_buffer (PRN *prn)
588 {
589 int err = 0;
590
591 if (prn != NULL && prn->buf != NULL) {
592 *prn->buf = '\0';
593 prn->blen = 0;
594 } else {
595 err = 1;
596 }
597
598 return err;
599 }
600
601 /**
602 * gretl_print_get_buffer:
603 * @prn: printing struct.
604 *
605 * Obtain a pointer to the buffer associated
606 * with @prn, if any. This pointer must not be
607 * modified in any way.
608 *
609 * Returns: the buffer, or NULL on failure.
610 */
611
gretl_print_get_buffer(PRN * prn)612 const char *gretl_print_get_buffer (PRN *prn)
613 {
614 return (prn != NULL)? prn->buf : NULL;
615 }
616
617 /**
618 * gretl_print_get_trimmed_buffer:
619 * @prn: printing struct.
620 *
621 * Obtain a pointer to the buffer associated
622 * with @prn, if any. This pointer must not be
623 * modified in any way. An opening newline
624 * is skipped and any trailing white space is
625 * substituted by NULs.
626 *
627 * Returns: the buffer, or NULL on failure.
628 */
629
gretl_print_get_trimmed_buffer(PRN * prn)630 const char *gretl_print_get_trimmed_buffer (PRN *prn)
631 {
632 char *buf = (prn != NULL)? prn->buf : NULL;
633
634 if (buf != NULL) {
635 int i, n;
636
637 if (*buf == '\n') {
638 buf++;
639 }
640 n = strlen(buf);
641 for (i=n-1; i>0; i--) {
642 if (buf[i] == '\n' && buf[i-1] == '\n') {
643 buf[i] = '\0';
644 } else {
645 break;
646 }
647 }
648 }
649
650 return buf;
651 }
652
653 /**
654 * gretl_print_get_size:
655 * @prn: printing struct.
656 * @width: location to receive width, or NULL.
657 * @height: location to receive height, or NULL.
658 *
659 * If @prn has a non-null buffer attached, provides
660 * the width and/or height of the buffer, the width in
661 * characters and the height in lines. This function is
662 * intended for use with text designed for printing in
663 * a GUI window, and with "reasonable" line lengths for
664 * that context; if the lines are too long (more than
665 * 120 UTF-8 characters) the values written to @width
666 * and/or @height will be zero.
667 */
668
gretl_print_get_size(PRN * prn,int * width,int * height)669 void gretl_print_get_size (PRN *prn, int *width, int *height)
670 {
671 int w = 0, h = 0;
672
673 if (prn != NULL && prn->buf != NULL) {
674 char line[128];
675 int lw;
676
677 bufgets_init(prn->buf);
678 while (bufgets(line, sizeof line, prn->buf)) {
679 lw = g_utf8_strlen(line, -1) - 1;
680 if (lw > 120) {
681 w = h = 0;
682 break;
683 }
684 if (lw > w) {
685 w = lw;
686 }
687 h++;
688 }
689 bufgets_finalize(prn->buf);
690 }
691
692 if (width != NULL) {
693 *width = w;
694 }
695
696 if (height != NULL) {
697 *height = h;
698 }
699 }
700
701 /**
702 * gretl_print_steal_buffer:
703 * @prn: printing struct.
704 *
705 * Obtain a pointer to the buffer associated with @prn,
706 * if any. The pointer on @prn itself is set to NULL
707 * and the caller takes responsibility for freeing the
708 * buffer.
709 *
710 * Returns: the buffer, or NULL on failure.
711 */
712
gretl_print_steal_buffer(PRN * prn)713 char *gretl_print_steal_buffer (PRN *prn)
714 {
715 char *buf = NULL;
716
717 if (prn != NULL) {
718 buf = prn->buf;
719 prn->buf = NULL;
720 }
721
722 return buf;
723 }
724
725 /**
726 * gretl_print_replace_buffer:
727 * @prn: printing struct.
728 * @buf: malloced replacement buffer.
729 *
730 * If @prn currently has a printing buffer in place,
731 * destroy the original and replace it with @buf. Note
732 * @prn "takes ownership" of @buf, which will be freed
733 * when @prn is destroyed.
734 *
735 * Returns: 0 on success, non-zero code on error.
736 */
737
gretl_print_replace_buffer(PRN * prn,char * buf)738 int gretl_print_replace_buffer (PRN *prn, char *buf)
739 {
740 int err = 0;
741
742 if (prn == NULL || prn->buf == NULL || buf == NULL) {
743 err = E_DATA;
744 } else {
745 free(prn->buf);
746 prn->buf = buf;
747 prn->blen = strlen(buf);
748 prn->bufsize = prn->blen + 1;
749 prn->savepos = -1;
750 }
751
752 return err;
753 }
754
755 /**
756 * gretl_print_set_save_position:
757 * @prn: printing struct.
758 *
759 * Sets the current buffer offset as the position from
760 * which a chunk of the current buffer may be saved,
761 * using gretl_print_get_chunk().
762 *
763 * Returns: 0 on success, error code if @prn is not
764 * connected to a buffer.
765 */
766
gretl_print_set_save_position(PRN * prn)767 int gretl_print_set_save_position (PRN *prn)
768 {
769 if (prn == NULL || prn->buf == NULL) {
770 return E_DATA;
771 } else {
772 prn->savepos = prn->blen;
773 return 0;
774 }
775 }
776
777 /**
778 * gretl_print_unset_save_position:
779 * @prn: printing struct.
780 *
781 * Erases the "save position" offset as set by
782 * gretl_print_set_save_position().
783 */
784
gretl_print_unset_save_position(PRN * prn)785 void gretl_print_unset_save_position (PRN *prn)
786 {
787 if (prn != NULL) {
788 prn->savepos = -1;
789 }
790 }
791
792 /**
793 * gretl_print_get_chunk:
794 * @prn: printing struct.
795 *
796 * Retrieves a copy of the buffer associated with @prn,
797 * starting at the offset from the start of the buffer
798 * as set by gretl_print_set_save_position().
799 *
800 * Returns: allocated buffer on success, or NULL on error.
801 */
802
gretl_print_get_chunk(PRN * prn)803 char *gretl_print_get_chunk (PRN *prn)
804 {
805 int maxpos = prn->blen;
806 char *ret;
807
808 if (prn == NULL || prn->buf == NULL ||
809 prn->savepos < 0 || prn->savepos > maxpos) {
810 return NULL;
811 }
812
813 ret = gretl_strdup(prn->buf + prn->savepos);
814 prn->savepos = -1;
815
816 return ret;
817 }
818
819 /**
820 * gretl_print_get_chunk_at:
821 * @prn: printing struct.
822 * @pos: the byte poistion at which to start.
823 *
824 * Retrieves a copy of the buffer associated with @prn,
825 * starting at the offset from the start of the buffer
826 * specified by @pos.
827 *
828 * Returns: allocated buffer on success, or NULL on error.
829 */
830
gretl_print_get_chunk_at(PRN * prn,int pos)831 char *gretl_print_get_chunk_at (PRN *prn, int pos)
832 {
833 int maxpos = prn->blen;
834 char *ret;
835
836 if (prn == NULL || prn->buf == NULL ||
837 pos < 0 || pos > maxpos) {
838 return NULL;
839 }
840
841 ret = gretl_strdup(prn->buf + pos);
842
843 return ret;
844 }
845
846 /**
847 * gretl_print_tell:
848 * @prn: printing struct.
849 *
850 * Returns: the current write position, if @prn
851 * has a buffer attached, otherwise -1.
852 */
853
gretl_print_tell(PRN * prn)854 int gretl_print_tell (PRN *prn)
855 {
856 if (prn == NULL || prn->buf == NULL) {
857 return -1;
858 } else {
859 return prn->blen;
860 }
861 }
862
set_default_csv_delim(PRN * prn)863 static void set_default_csv_delim (PRN *prn)
864 {
865 char test[4];
866
867 sprintf(test, "%.1f", 1.0);
868
869 if (test[1] == ',') {
870 prn->delim = ';';
871 } else {
872 prn->delim = ',';
873 }
874 }
875
876 /**
877 * gretl_print_set_format:
878 * @prn: printing struct.
879 * @format: desired format code.
880 *
881 * Sets the printing format on @prn.
882 */
883
gretl_print_set_format(PRN * prn,PrnFormat format)884 void gretl_print_set_format (PRN *prn, PrnFormat format)
885 {
886 if (prn != NULL) {
887 if (format == GRETL_FORMAT_RTF) {
888 format = GRETL_FORMAT_RTF | GRETL_FORMAT_DOC;
889 }
890 if (format == GRETL_FORMAT_CSV) {
891 set_default_csv_delim(prn);
892 }
893 prn->format = format;
894 }
895 }
896
897 /**
898 * gretl_print_set_delim:
899 * @prn: printing struct.
900 * @delim: desired CSV field-delimiter.
901 *
902 * Sets the CSV delimiter on @prn.
903 */
904
gretl_print_set_delim(PRN * prn,char delim)905 void gretl_print_set_delim (PRN *prn, char delim)
906 {
907 if (prn != NULL) {
908 prn->delim = delim;
909 }
910 }
911
912 /**
913 * gretl_print_toggle_doc_flag:
914 * @prn: printing struct.
915 *
916 * Toggles the %GRETL_FORMAT_DOC flag on @prn.
917 */
918
gretl_print_toggle_doc_flag(PRN * prn)919 void gretl_print_toggle_doc_flag (PRN *prn)
920 {
921 if (prn != NULL) {
922 prn->format ^= GRETL_FORMAT_DOC;
923 }
924 }
925
926 /**
927 * gretl_print_set_has_minus:
928 * @prn: printing struct.
929 *
930 * Sets the %GRETL_FORMAT_HAS_MINUS flag on @prn,
931 * indicating that the Unicode minus sign is
932 * supported.
933 */
934
gretl_print_set_has_minus(PRN * prn)935 void gretl_print_set_has_minus (PRN *prn)
936 {
937 if (prn != NULL) {
938 prn->format |= GRETL_FORMAT_HAS_MINUS;
939 }
940 }
941
942 /**
943 * gretl_print_has_minus:
944 * @prn: printing struct.
945 *
946 * Returns: 1 if @prn supports Unicode minus sign, else 0.
947 */
948
gretl_print_has_minus(PRN * prn)949 int gretl_print_has_minus (PRN *prn)
950 {
951 if (prn != NULL) {
952 return (prn->format & GRETL_FORMAT_HAS_MINUS)? 1 : 0;
953 } else {
954 return 0;
955 }
956 }
957
realloc_prn_buffer(PRN * prn,size_t newlen)958 static int realloc_prn_buffer (PRN *prn, size_t newlen)
959 {
960 char *tmp;
961 int err = 0;
962
963 if (newlen <= 0) {
964 newlen = prn->bufsize * 2;
965 }
966
967 #if PRN_DEBUG
968 fprintf(stderr, "%d bytes left\ndoing realloc(%p, %d)\n",
969 (int) (prn->bufsize - prn->blen), prn->buf,
970 (int) newlen);
971 #endif
972
973 tmp = realloc(prn->buf, newlen);
974
975 if (tmp == NULL) {
976 err = 1;
977 } else {
978 prn->bufsize = newlen;
979 prn->buf = tmp;
980 #if PRN_DEBUG
981 fprintf(stderr, "realloc: prn->buf is %d bytes at %p\n",
982 (int) prn->bufsize, (void *) prn->buf);
983 #endif
984 }
985
986 memset(prn->buf + prn->blen, 0, 1);
987
988 return err;
989 }
990
991 #define INIT_SIZE 2048
992 #define MINREM 1024
993
pprintf_init(PRN * prn)994 static int pprintf_init (PRN *prn)
995 {
996 int ret = 0;
997
998 prn->bufsize = INIT_SIZE;
999 prn->buf = malloc(prn->bufsize);
1000
1001 #if PRN_DEBUG
1002 fprintf(stderr, "pprintf: malloc'd %d bytes at %p\n",
1003 (int) prn->bufsize, (void *) prn->buf);
1004 #endif
1005
1006 if (prn->buf == NULL) {
1007 ret = -1;
1008 } else {
1009 memset(prn->buf, 0, 1);
1010 prn->blen = 0;
1011 }
1012
1013 return ret;
1014 }
1015
get_nl_count(const char * s)1016 static int get_nl_count (const char *s)
1017 {
1018 int i, n = strlen(s) - 1;
1019 int nnl = 0;
1020
1021 for (i=n; i>=0; i--) {
1022 if (s[i] == '\n') nnl++;
1023 else break;
1024 }
1025
1026 return nnl;
1027 }
1028
1029 /**
1030 * pprintf:
1031 * @prn: gretl printing struct.
1032 * @format: as in the C library's printf().
1033 * @Varargs: arguments to be printed.
1034 *
1035 * Multi-purpose printing function: can output to stream, to buffer
1036 * or to nowhere (silently discarding the output), depending on
1037 * how @prn was initialized. Note that it's preferable to use
1038 * pputs() for large chunks of fixed text.
1039 *
1040 * Returns: the number of bytes printed, or -1 on memory allocation
1041 * failure.
1042 */
1043
pprintf(PRN * prn,const char * format,...)1044 int pprintf (PRN *prn, const char *format, ...)
1045 {
1046 va_list args;
1047 int rem, plen = 0;
1048
1049 if (prn == NULL || prn->fixed) {
1050 return 0;
1051 }
1052
1053 if (format != NULL && *format != '\0') {
1054 prn->nlcount = get_nl_count(format);
1055 }
1056
1057 if (prn->fp != NULL) {
1058 /* printing to stream: straightforward */
1059 va_start(args, format);
1060 plen = vfprintf(prn->fp, format, args);
1061 va_end(args);
1062 return plen;
1063 } else if (prn->fz != NULL) {
1064 gchar *tmp = NULL;
1065
1066 va_start(args, format);
1067 plen = g_vasprintf(&tmp, format, args);
1068 va_end(args);
1069 gzputs(prn->fz, tmp);
1070 g_free(tmp);
1071 return plen;
1072 }
1073
1074 if (strncmp(format, "@init", 5) == 0) {
1075 return pprintf_init(prn);
1076 }
1077
1078 if (prn->buf == NULL) {
1079 return 0;
1080 }
1081
1082 rem = prn->bufsize - prn->blen;
1083 if (rem < MINREM) {
1084 if (realloc_prn_buffer(prn, 0)) {
1085 return -1;
1086 }
1087 }
1088
1089 #if PRN_DEBUG > 1
1090 fprintf(stderr, "printing at %p\n", (void *) (prn->buf + prn->blen));
1091 #endif
1092
1093 /* printing to buffer: be careful not to overrun */
1094 rem = prn->bufsize - prn->blen - 1;
1095 va_start(args, format);
1096 plen = vsnprintf(prn->buf + prn->blen, rem, format, args);
1097 va_end(args);
1098
1099 if (plen >= rem) {
1100 /* buffer not big enough: try again */
1101 size_t newsize = prn->bufsize + plen + 1024;
1102
1103 if (realloc_prn_buffer(prn, newsize)) {
1104 return -1;
1105 }
1106 rem = prn->bufsize - prn->blen - 1;
1107 va_start(args, format);
1108 plen = vsnprintf(prn->buf + prn->blen, rem, format, args);
1109 va_end(args);
1110 }
1111
1112 if (plen > 0) {
1113 prn->blen += plen;
1114 }
1115
1116 return plen;
1117 }
1118
1119 /* void variant of pprintf() for use in certain callbacks */
1120
pprintf2(PRN * prn,const char * format,...)1121 void pprintf2 (PRN *prn, const char *format, ...)
1122 {
1123 va_list args;
1124 int rem, plen = 0;
1125
1126 if (prn == NULL || prn->fixed) {
1127 return;
1128 }
1129
1130 if (prn->fp != NULL) {
1131 /* printing to stream: straightforward */
1132 va_start(args, format);
1133 vfprintf(prn->fp, format, args);
1134 va_end(args);
1135 return;
1136 }
1137
1138 if (strncmp(format, "@init", 5) == 0) {
1139 pprintf_init(prn);
1140 return;
1141 }
1142
1143 if (prn->buf == NULL) {
1144 return;
1145 }
1146
1147 rem = prn->bufsize - prn->blen;
1148 if (rem < MINREM) {
1149 if (realloc_prn_buffer(prn, 0)) {
1150 return;
1151 }
1152 }
1153
1154 rem = prn->bufsize - prn->blen - 1;
1155 va_start(args, format);
1156 plen = vsnprintf(prn->buf + prn->blen, rem, format, args);
1157 va_end(args);
1158
1159 if (plen >= rem) {
1160 size_t newsize = prn->bufsize + plen + 1024;
1161
1162 if (realloc_prn_buffer(prn, newsize)) {
1163 return;
1164 }
1165 rem = prn->bufsize - prn->blen - 1;
1166 va_start(args, format);
1167 plen = vsnprintf(prn->buf + prn->blen, rem, format, args);
1168 va_end(args);
1169 }
1170
1171 if (plen > 0) {
1172 prn->blen += plen;
1173 }
1174 }
1175
1176 /**
1177 * pputs:
1178 * @prn: gretl printing struct.
1179 * @s: constant string to print.
1180 *
1181 * Returns: the number of bytes printed, or -1 on memory allocation
1182 * failure.
1183 */
1184
pputs(PRN * prn,const char * s)1185 int pputs (PRN *prn, const char *s)
1186 {
1187 int slen, rem;
1188
1189 if (prn == NULL || prn->fixed) {
1190 return 0;
1191 }
1192
1193 slen = strlen(s);
1194 if (slen > 0) {
1195 prn->nlcount = get_nl_count(s);
1196 }
1197
1198 if (prn->fp != NULL) {
1199 fputs(s, prn->fp);
1200 return slen;
1201 } else if (prn->fz != NULL) {
1202 return gzputs(prn->fz, s);
1203 }
1204
1205 if (prn->buf == NULL) {
1206 return 0;
1207 }
1208
1209 rem = prn->bufsize - prn->blen;
1210
1211 while (rem < MINREM || rem <= slen) {
1212 if (realloc_prn_buffer(prn, 0)) {
1213 return -1;
1214 }
1215 rem = prn->bufsize - prn->blen;
1216 }
1217
1218 #if PRN_DEBUG > 1
1219 fprintf(stderr, "pputs: bufsize=%d, blen=%d, rem=%d, copying %d bytes\n",
1220 (int) prn->bufsize, (int) prn->blen, rem, slen);
1221 #endif
1222
1223 strcpy(prn->buf + prn->blen, s);
1224 prn->blen += slen;
1225
1226 return slen;
1227 }
1228
1229 /**
1230 * pputc:
1231 * @prn: gretl printing struct.
1232 * @c: character to print
1233 *
1234 * Returns: the number of bytes printed, or -1 on memory allocation
1235 * failure.
1236 */
1237
pputc(PRN * prn,int c)1238 int pputc (PRN *prn, int c)
1239 {
1240 if (prn == NULL || prn->fixed) {
1241 return 0;
1242 }
1243
1244 if (c == '\n') prn->nlcount += 1;
1245 else if (c != '\0') prn->nlcount = 0;
1246
1247 if (prn->fp != NULL) {
1248 fputc(c, prn->fp);
1249 return 1;
1250 } else if (prn->fz != NULL) {
1251 char s[2] = {c, '\0'};
1252
1253 return gzputs(prn->fz, s);
1254 }
1255
1256 if (prn->buf == NULL) {
1257 return 0;
1258 }
1259
1260 if (prn->bufsize - prn->blen < MINREM) {
1261 if (realloc_prn_buffer(prn, 0)) {
1262 return -1;
1263 }
1264 }
1265
1266 #if PRN_DEBUG > 1
1267 fprintf(stderr, "pputc: adding char at %p\n", (void *) (prn->buf + prn->blen));
1268 #endif
1269
1270 prn->buf[prn->blen] = c;
1271 prn->buf[prn->blen + 1] = '\0';
1272 prn->blen += 1;
1273
1274 return 1;
1275 }
1276
1277 /**
1278 * gretl_prn_newline:
1279 * @prn: gretl printing struct.
1280 *
1281 * Print a line break, in the mode appropriate to the
1282 * format of @prn (plain text, TeX or RTF).
1283 */
1284
gretl_prn_newline(PRN * prn)1285 void gretl_prn_newline (PRN *prn)
1286 {
1287 if (tex_format(prn)) {
1288 pputs(prn, "\\\\\n");
1289 } else if (rtf_format(prn)) {
1290 pputs(prn, "\\par\n");
1291 } else {
1292 pputc(prn, '\n');
1293 }
1294 }
1295
1296 /**
1297 * gretl_print_ensure_vspace:
1298 * @prn: gretl printing struct.
1299 *
1300 */
1301
gretl_print_ensure_vspace(PRN * prn)1302 void gretl_print_ensure_vspace (PRN *prn)
1303 {
1304 if (prn != NULL && prn->nlcount < 2) {
1305 pputc(prn, '\n');
1306 }
1307 }
1308
1309 /**
1310 * gretl_print_flush_stream:
1311 * @prn: gretl printing struct.
1312 *
1313 * If the output of @prn is directed to a stream, flush
1314 * that stream.
1315 */
1316
gretl_print_flush_stream(PRN * prn)1317 void gretl_print_flush_stream (PRN *prn)
1318 {
1319 if (prn != NULL) {
1320 if (prn->fp != NULL) {
1321 fflush(prn->fp);
1322 } else if (prn->fz != NULL) {
1323 gzflush(prn->fz, Z_SYNC_FLUSH);
1324 }
1325 }
1326 }
1327
1328 /**
1329 * gretl_print_close_file:
1330 * @prn: gretl printing struct.
1331 *
1332 * If the output of @prn is directed to a file, close
1333 * the file. Also frees and sets to NULL the filename
1334 * associated with the stream (but does not remove the
1335 * file).
1336 */
1337
gretl_print_close_stream(PRN * prn)1338 void gretl_print_close_stream (PRN *prn)
1339 {
1340 if (prn == NULL) return;
1341
1342 if (prn->fp != NULL) {
1343 fclose(prn->fp);
1344 prn->fp = NULL;
1345 free(prn->fname);
1346 prn->fname = NULL;
1347 } else if (prn->fz != NULL) {
1348 gzclose(prn->fz);
1349 prn->fz = NULL;
1350 free(prn->fname);
1351 prn->fname = NULL;
1352 }
1353 }
1354
1355 /**
1356 * printing_to_standard_stream:
1357 * @prn: gretl printing struct.
1358 *
1359 * Returns: 1 if the output of @prn is directed to one of the
1360 * standard streams, %stdout or %stderr, else 0.
1361 */
1362
printing_to_standard_stream(PRN * prn)1363 int printing_to_standard_stream (PRN *prn)
1364 {
1365 int ret = 0;
1366
1367 if (prn != NULL && (prn->fp == stdout || prn->fp == stderr)) {
1368 ret = 1;
1369 }
1370
1371 return ret;
1372 }
1373
prn_push_stream(PRN * prn,FILE * fp,const char * fname,const char * strvar)1374 static void prn_push_stream (PRN *prn, FILE *fp, const char *fname,
1375 const char *strvar)
1376 {
1377 fpinfo fi = {prn->fp, 0, NULL, NULL};
1378
1379 if (prn->fplist == NULL) {
1380 prn->fplist = g_array_new(FALSE, FALSE, sizeof(fpinfo));
1381 }
1382 fi.level = gretl_function_depth();
1383 if (fname != NULL) {
1384 fi.fname = g_strdup(fname);
1385 }
1386 if (strvar != NULL) {
1387 fi.strvar = g_strdup(strvar);
1388 }
1389 g_array_append_val(prn->fplist, fi);
1390
1391 prn->fp = fp;
1392 }
1393
handle_outbuf_content(FILE * fp,fpinfo * fi)1394 static int handle_outbuf_content (FILE *fp, fpinfo *fi)
1395 {
1396 user_var *uv;
1397 int err = 0;
1398
1399 uv = get_user_var_of_type_by_name(fi->strvar,
1400 GRETL_TYPE_STRING);
1401 if (uv == NULL) {
1402 err = E_DATA;
1403 } else {
1404 char *buf = NULL;
1405 long pos;
1406 size_t len;
1407
1408 fflush(fp);
1409 fseek(fp, 0, SEEK_END);
1410 pos = ftell(fp);
1411
1412 if (pos > 0) {
1413 buf = calloc(pos + 1, 1);
1414 if (buf == NULL) {
1415 err = E_ALLOC;
1416 } else {
1417 fseek(fp, 0, SEEK_SET);
1418 len = fread(buf, 1, pos, fp);
1419 if (len < pos) {
1420 err = E_DATA;
1421 free(buf);
1422 }
1423 }
1424 } else {
1425 buf = gretl_strdup("");
1426 }
1427
1428 if (!err) {
1429 err = user_var_replace_value(uv, buf, GRETL_TYPE_STRING);
1430 }
1431 }
1432
1433 return err;
1434 }
1435
prn_pop_stream(PRN * prn)1436 static int prn_pop_stream (PRN *prn)
1437 {
1438 FILE *prev = NULL;
1439 char *strvar = NULL;
1440 int err = 0;
1441
1442 if (prn->fplist != NULL) {
1443 int n = prn->fplist->len;
1444 fpinfo *fi;
1445
1446 if (n > 0) {
1447 fi = &g_array_index(prn->fplist, fpinfo, n-1);
1448 prev = fi->fp;
1449 if (fi->strvar != NULL) {
1450 strvar = fi->strvar;
1451 err = handle_outbuf_content(prn->fp, fi);
1452 }
1453 if (fi->fname != NULL) {
1454 g_free(fi->fname);
1455 fi->fname = NULL;
1456 }
1457 g_array_remove_index(prn->fplist, n-1);
1458 }
1459 }
1460
1461 if (prn->fp != NULL && prn->fp != stdout && prn->fp != stderr) {
1462 fclose(prn->fp);
1463 }
1464
1465 if (strvar != NULL) {
1466 gchar *fname = g_strdup_printf("%s%s.prntmp",
1467 gretl_dotdir(),
1468 strvar);
1469 gretl_remove(fname);
1470 g_free(fname);
1471 g_free(strvar);
1472 }
1473
1474 prn->fp = prev;
1475
1476 return err;
1477 }
1478
1479 /**
1480 * print_redirection_level:
1481 * @prn: gretl printing struct.
1482 *
1483 * Returns: 0 if the output of @prn has not been redirected
1484 * relative to its original setting, else the level of
1485 * (possibly nested) redirection.
1486 */
1487
print_redirection_level(PRN * prn)1488 int print_redirection_level (PRN *prn)
1489 {
1490 int ret = 0;
1491
1492 if (prn != NULL) {
1493 if (prn->fp != NULL && prn->buf != NULL) {
1494 ret = 1;
1495 } else if (prn->fixed) {
1496 ret = 1;
1497 }
1498 if (prn_fp_list_active(prn)) {
1499 ret += prn->fplist->len; /* is this right? */
1500 }
1501 }
1502
1503 return ret;
1504 }
1505
1506 /**
1507 * print_redirection_filename:
1508 * @prn: gretl printing struct.
1509 *
1510 * Returns: the name of the file to which output is currently
1511 * redirected, if applicable, otherwise NULL.
1512 */
1513
print_redirection_filename(PRN * prn)1514 const char *print_redirection_filename (PRN *prn)
1515 {
1516 if (prn != NULL && prn_fp_list_active(prn)) {
1517 int i = prn->fplist->len - 1;
1518 fpinfo *fi;
1519
1520 fi = &g_array_index(prn->fplist, fpinfo, i);
1521 if (fi != NULL && fi->fname != NULL) {
1522 return fi->fname;
1523 }
1524 }
1525
1526 return NULL;
1527 }
1528
print_redirected_at_level(PRN * prn,int level)1529 int print_redirected_at_level (PRN *prn, int level)
1530 {
1531 if (prn->fplist != NULL) {
1532 fpinfo *fi;
1533 int i;
1534
1535 for (i=0; i<prn->fplist->len; i++) {
1536 fi = &g_array_index(prn->fplist, fpinfo, i);
1537 if (fi->level == level) {
1538 return 1;
1539 }
1540 }
1541 }
1542
1543 return 0;
1544 }
1545
1546 /**
1547 * print_start_redirection:
1548 * @prn: gretl printing struct.
1549 * @fp: stream to which output should be redirected.
1550 * @fname: name of the file or NULL.
1551 * @strvar: name of associated string variable, or NULL.
1552 *
1553 * Redirects output of @prn to @fp.
1554 *
1555 * Returns: 0 on success, 1 on error.
1556 */
1557
print_start_redirection(PRN * prn,FILE * fp,const char * fname,const char * strvar)1558 int print_start_redirection (PRN *prn, FILE *fp,
1559 const char *fname,
1560 const char *strvar)
1561 {
1562 if (prn == NULL || prn->fixed) {
1563 return 1;
1564 }
1565
1566 if (prn->fp != NULL) {
1567 /* flush the current stream */
1568 fflush(prn->fp);
1569 }
1570 if (fp == NULL) {
1571 /* "redirection" means just disable printing */
1572 prn->fixed = 1;
1573 } else {
1574 /* record current stream in prn->fplist, and
1575 hook output to specified stream
1576 */
1577 prn_push_stream(prn, fp, fname, strvar);
1578 }
1579
1580 return 0;
1581 }
1582
1583 /**
1584 * print_end_redirection:
1585 * @prn: gretl printing struct.
1586 *
1587 * If the output of @prn has been diverted relative to
1588 * its original setting, terminate the redirection.
1589 *
1590 * Returns: 0 on success, 1 on error.
1591 */
1592
print_end_redirection(PRN * prn)1593 int print_end_redirection (PRN *prn)
1594 {
1595 int err = 0;
1596
1597 if (prn != NULL) {
1598 if (prn->fixed) {
1599 prn->fixed = 0;
1600 } else if (prn->fp != NULL) {
1601 err = prn_pop_stream(prn);
1602 }
1603 } else {
1604 err = E_DATA;
1605 }
1606
1607 return err;
1608 }
1609
1610 /**
1611 * plain_format:
1612 * @prn: gretl printing struct.
1613 *
1614 * Returns: 1 if the format of @prn is plain text, else 0.
1615 */
1616
plain_format(PRN * prn)1617 int plain_format (PRN *prn)
1618 {
1619 return (prn != NULL && (prn->format & GRETL_FORMAT_TXT));
1620 }
1621
1622 /**
1623 * rtf_format:
1624 * @prn: gretl printing struct.
1625 *
1626 * Returns: 1 if the format of @prn is RTF, else 0.
1627 */
1628
rtf_format(PRN * prn)1629 int rtf_format (PRN *prn)
1630 {
1631 if (prn != NULL) {
1632 if (prn->format & (GRETL_FORMAT_RTF | GRETL_FORMAT_RTF_TXT)) {
1633 return 1;
1634 }
1635 }
1636
1637 return 0;
1638 }
1639
1640 /**
1641 * rtf_doc_format:
1642 * @prn: gretl printing struct.
1643 *
1644 * Returns: 1 if the format of @prn is RTF, and the
1645 * RTF preamble should be printed, else 0.
1646 */
1647
rtf_doc_format(PRN * prn)1648 int rtf_doc_format (PRN *prn)
1649 {
1650 return (prn != NULL &&
1651 (prn->format & GRETL_FORMAT_RTF) &&
1652 (prn->format & GRETL_FORMAT_DOC));
1653 }
1654
1655 /**
1656 * tex_format:
1657 * @prn: gretl printing struct.
1658 *
1659 * Returns: 1 if the format of @prn is TeX, else 0.
1660 */
1661
tex_format(PRN * prn)1662 int tex_format (PRN *prn)
1663 {
1664 return (prn != NULL && (prn->format & GRETL_FORMAT_TEX));
1665 }
1666
1667 /**
1668 * tex_doc_format:
1669 * @prn: gretl printing struct.
1670 *
1671 * Returns: 1 if the format of @prn is TeX and a complete
1672 * TeX document is being produced, else 0.
1673 */
1674
tex_doc_format(PRN * prn)1675 int tex_doc_format (PRN *prn)
1676 {
1677 return (prn != NULL &&
1678 (prn->format & GRETL_FORMAT_TEX) &&
1679 (prn->format & GRETL_FORMAT_DOC));
1680 }
1681
1682 /**
1683 * tex_eqn_format:
1684 * @prn: gretl printing struct.
1685 *
1686 * Returns: 1 if the format of @prn is TeX and a model
1687 * is being represented as an equation, rather than in
1688 * tabular form, else 0.
1689 */
1690
tex_eqn_format(PRN * prn)1691 int tex_eqn_format (PRN *prn)
1692 {
1693 return (prn != NULL &&
1694 (prn->format & GRETL_FORMAT_TEX) &&
1695 (prn->format & GRETL_FORMAT_EQN));
1696 }
1697
1698 /**
1699 * csv_format:
1700 * @prn: gretl printing struct.
1701 *
1702 * Returns: 1 if the format of @prn is CSV, else 0.
1703 */
1704
csv_format(PRN * prn)1705 int csv_format (PRN *prn)
1706 {
1707 return (prn != NULL && (prn->format & GRETL_FORMAT_CSV));
1708 }
1709
1710 /**
1711 * prn_format:
1712 * @prn: gretl printing struct.
1713 *
1714 * Returns: The formatting flags for @prn.
1715 */
1716
prn_format(PRN * prn)1717 int prn_format (PRN *prn)
1718 {
1719 return (prn != NULL)? prn->format : 0;
1720 }
1721
1722 /**
1723 * prn_delim:
1724 * @prn: gretl printing struct.
1725 *
1726 * Returns: The character to be used as delimiter for CSV.
1727 */
1728
prn_delim(PRN * prn)1729 char prn_delim (PRN *prn)
1730 {
1731 return (prn != NULL)? prn->delim : ',';
1732 }
1733
1734 /**
1735 * gretl_print_has_buffer:
1736 * @prn: gretl printing struct.
1737 *
1738 * Returns: 1 if @prn is using a buffer for printing,
1739 * otherwise 0 (e.g., if a file is being used).
1740 */
1741
gretl_print_has_buffer(PRN * prn)1742 int gretl_print_has_buffer (PRN *prn)
1743 {
1744 return (prn != NULL && prn->buf != NULL);
1745 }
1746
1747 /**
1748 * gretl_print_alloc:
1749 * @prn: gretl printing struct.
1750 * @s: desired size in bytes.
1751 *
1752 * If @prn is using a buffer for printing, try to
1753 * ensure that at least @s bytes are available for
1754 * further printing. May speed things up if we
1755 * know there is a large amount of text to be
1756 * printed.
1757 *
1758 * Returns: 0 on success, non-zero on failure.
1759 */
1760
gretl_print_alloc(PRN * prn,size_t s)1761 int gretl_print_alloc (PRN *prn, size_t s)
1762 {
1763 size_t rem;
1764 int err = 0;
1765
1766 if (prn == NULL || prn->buf == NULL || prn->fixed) {
1767 return E_DATA;
1768 }
1769
1770 rem = prn->bufsize - prn->blen;
1771
1772 if (rem <= s) {
1773 size_t newlen = prn->blen + s + 1;
1774 char *tmp;
1775
1776 tmp = realloc(prn->buf, newlen);
1777 if (tmp == NULL) {
1778 err = E_ALLOC;
1779 } else {
1780 prn->buf = tmp;
1781 prn->bufsize = newlen;
1782 memset(prn->buf + prn->blen, 0, 1);
1783 #if PRN_DEBUG
1784 fprintf(stderr, "gretl_print_alloc: realloc'd prn->buf "
1785 "to %d bytes\n", (int) newlen);
1786 #endif
1787 }
1788 }
1789
1790 return err;
1791 }
1792
1793 /**
1794 * gretl_print_read_tempfile:
1795 * @prn: gretl printing struct.
1796 * @err: location to receive error code.
1797 *
1798 * Retrieves a copy of the content of @prn, if it takes the
1799 * form of a file that has been opened in "w+" or "a+" mode.
1800 *
1801 * Returns: allocated buffer, or NULL on failure.
1802 */
1803
gretl_print_read_tempfile(PRN * prn,int * err)1804 char *gretl_print_read_tempfile (PRN *prn, int *err)
1805 {
1806 size_t chk, bsize;
1807 long pos0;
1808 char *buf = NULL;
1809
1810 if (prn == NULL || prn->fp == NULL) {
1811 fprintf(stderr, "gretl_print_read_tempfile: no temp file to read!\n");
1812 *err = E_DATA;
1813 return NULL;
1814 }
1815
1816 fflush(prn->fp);
1817 pos0 = ftell(prn->fp);
1818 bsize = pos0;
1819 buf = calloc(bsize + 1, 1);
1820
1821 if (buf == NULL) {
1822 *err = E_ALLOC;
1823 } else {
1824 rewind(prn->fp);
1825 chk = fread(buf, 1, bsize, prn->fp);
1826 if (chk != bsize) {
1827 fprintf(stderr, "gretl_print_read_tempfile: bsize=%d but chk=%d\n",
1828 (int) bsize, (int) chk);
1829 *err = E_DATA;
1830 free(buf);
1831 buf = NULL;
1832 }
1833 /* get back to where we were */
1834 fseek(prn->fp, pos0, SEEK_SET);
1835 }
1836
1837 return buf;
1838 }
1839