1 /*
2  * This file is part of the Yices SMT Solver.
3  * Copyright (C) 2017 SRI International.
4  *
5  * Yices 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  * Yices 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 Yices.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include <assert.h>
20 #include <errno.h>
21 
22 #include "writer.h"
23 
24 /*
25  * Initialize for the given filename
26  * - tries to open the file with mode "w"
27  * - returns -1 if the file can't be opened.
28  *   set print_failed to true and store the errno
29  * - returns 0 otherwise (print_failed is false and errno is 0)
30  */
init_file_writer(writer_t * writer,const char * filename)31 int32_t init_file_writer(writer_t *writer, const char *filename) {
32   FILE *f;
33   int32_t code;
34 
35   f = fopen(filename, "w");
36   writer->output.stream = f;
37   writer->is_stream = true;
38   if (f == NULL) {
39     writer->print_failed = true;
40     writer->print_errno = errno;
41     code = -1;
42   } else {
43     writer->print_failed = false;
44     writer->print_errno = 0;
45     code = 0;
46   }
47 
48   return code;
49 }
50 
51 
52 /*
53  * Initialize with an open stream f
54  * - f must be open and writable
55  */
init_stream_writer(writer_t * writer,FILE * f)56 void init_stream_writer(writer_t *writer, FILE *f) {
57   writer->output.stream = f;
58   writer->is_stream = true;
59   writer->print_failed = false;
60   writer->print_errno = 0;
61 }
62 
63 
64 /*
65  * Initialize for a string buffer
66  */
init_string_writer(writer_t * writer)67 void init_string_writer(writer_t *writer) {
68   init_string_buffer(&writer->output.buffer, 1024);
69   writer->is_stream = false;
70   writer->print_failed = false;
71   writer->print_errno = 0;
72 }
73 
74 
75 
76 /*
77  * Close:
78  * - for a stream writer: close the stream
79  * - for a string writer: add a '\0' at the end of the string buffer
80  * return code = EOF if fclose fails, 0 otherwise
81  */
close_writer(writer_t * writer)82 int close_writer(writer_t *writer) {
83   int code;
84 
85   if (writer->is_stream) {
86     // try to close even if writer->print_failed is true
87     // update the flags if  fclose fails
88     code = fclose(writer->output.stream);
89     if (code == EOF && !writer->print_failed) {
90       writer->print_failed = true;
91       writer->print_errno = errno;
92     }
93   } else {
94     string_buffer_close(&writer->output.buffer);
95     code = 0;
96   }
97 
98   return code;
99 }
100 
101 
102 /*
103  * Extract the string constructed by writer
104  * - this must be a string writer
105  * - function close_writer must be called first
106  * - the returned string is  '\0' terminated
107  * - the length of the string is returned in *len
108  *
109  * The returned string must be freed when no-longer needed (by a call
110  * to safe_free in utils/memalloc.h).
111  */
writer_get_string(writer_t * writer,uint32_t * len)112 char *writer_get_string(writer_t *writer, uint32_t *len) {
113   assert(!writer->is_stream);
114   return string_buffer_export(&writer->output.buffer, len);
115 }
116 
117 
118 
119 /*
120  * Delete: free the buffer if any otherwise do nothing
121  */
delete_writer(writer_t * writer)122 void delete_writer(writer_t *writer) {
123   if (!writer->is_stream) {
124     delete_string_buffer(&writer->output.buffer);
125   }
126 }
127 
128 /*
129  * Print a character, a string, flush
130  * - if writer->print_failed is true, these functions do nothing and exit
131  * - otherwise, they perform the IO operation. If this fails, writer->print_failed
132  *   is set to true and errno is stored in writer->print_errno.
133  */
writer_putc(writer_t * writer,char c)134 void writer_putc(writer_t *writer, char c) {
135   int x;
136 
137   if (writer->is_stream) {
138     if (!writer->print_failed) {
139       x = fputc(c, writer->output.stream);
140       if (x == EOF) {
141 	writer->print_failed = true;
142 	writer->print_errno = errno;
143       }
144     }
145   } else {
146     string_buffer_append_char(&writer->output.buffer, c);
147   }
148 }
149 
writer_puts(writer_t * writer,const char * s)150 void writer_puts(writer_t *writer, const char *s) {
151   int x;
152 
153   if (writer->is_stream) {
154     if (!writer->print_failed) {
155       x = fputs(s, writer->output.stream);
156       if (x == EOF) {
157 	writer->print_failed = true;
158 	writer->print_errno = errno;
159       }
160     }
161   } else {
162     string_buffer_append_string(&writer->output.buffer, s);
163   }
164 }
165 
writer_flush(writer_t * writer)166 void writer_flush(writer_t *writer) {
167   int x;
168 
169   if (writer->is_stream) {
170     if (!writer->print_failed) {
171       x = fflush(writer->output.stream);
172       if (x == EOF) {
173 	writer->print_failed = true;
174 	writer->print_errno = errno;
175       }
176     }
177   }
178 }
179 
180 
181