1#include <string.h>
2#include <isl_printer_private.h>
3
4static __isl_give isl_printer *file_start_line(__isl_take isl_printer *p)
5{
6	fprintf(p->file, "%*s%s", p->indent, "", p->prefix ? p->prefix : "");
7	return p;
8}
9
10static __isl_give isl_printer *file_end_line(__isl_take isl_printer *p)
11{
12	fprintf(p->file, "%s\n", p->suffix ? p->suffix : "");
13	return p;
14}
15
16static __isl_give isl_printer *file_flush(__isl_take isl_printer *p)
17{
18	fflush(p->file);
19	return p;
20}
21
22static __isl_give isl_printer *file_print_str(__isl_take isl_printer *p,
23	const char *s)
24{
25	fprintf(p->file, "%s", s);
26	return p;
27}
28
29static __isl_give isl_printer *file_print_double(__isl_take isl_printer *p,
30	double d)
31{
32	fprintf(p->file, "%g", d);
33	return p;
34}
35
36static __isl_give isl_printer *file_print_int(__isl_take isl_printer *p, int i)
37{
38	fprintf(p->file, "%d", i);
39	return p;
40}
41
42static __isl_give isl_printer *file_print_isl_int(__isl_take isl_printer *p, isl_int i)
43{
44	isl_int_print(p->file, i, p->width);
45	return p;
46}
47
48static int grow_buf(__isl_keep isl_printer *p, int extra)
49{
50	int new_size;
51	char *new_buf;
52
53	if (p->buf_size == 0)
54		return -1;
55
56	new_size = ((p->buf_n + extra + 1) * 3) / 2;
57	new_buf = isl_realloc_array(p->ctx, p->buf, char, new_size);
58	if (!new_buf) {
59		p->buf_size = 0;
60		return -1;
61	}
62	p->buf = new_buf;
63	p->buf_size = new_size;
64
65	return 0;
66}
67
68static __isl_give isl_printer *str_print(__isl_take isl_printer *p,
69	const char *s, int len)
70{
71	if (p->buf_n + len + 1 >= p->buf_size && grow_buf(p, len))
72		goto error;
73	memcpy(p->buf + p->buf_n, s, len);
74	p->buf_n += len;
75
76	p->buf[p->buf_n] = '\0';
77	return p;
78error:
79	isl_printer_free(p);
80	return NULL;
81}
82
83static __isl_give isl_printer *str_print_indent(__isl_take isl_printer *p,
84	int indent)
85{
86	int i;
87
88	if (p->buf_n + indent + 1 >= p->buf_size && grow_buf(p, indent))
89		goto error;
90	for (i = 0; i < indent; ++i)
91		p->buf[p->buf_n++] = ' ';
92	return p;
93error:
94	isl_printer_free(p);
95	return NULL;
96}
97
98static __isl_give isl_printer *str_start_line(__isl_take isl_printer *p)
99{
100	p = str_print_indent(p, p->indent);
101	if (p->prefix)
102		p = str_print(p, p->prefix, strlen(p->prefix));
103	return p;
104}
105
106static __isl_give isl_printer *str_end_line(__isl_take isl_printer *p)
107{
108	if (p->suffix)
109		p = str_print(p, p->suffix, strlen(p->suffix));
110	p = str_print(p, "\n", strlen("\n"));
111	return p;
112}
113
114static __isl_give isl_printer *str_flush(__isl_take isl_printer *p)
115{
116	p->buf_n = 0;
117	return p;
118}
119
120static __isl_give isl_printer *str_print_str(__isl_take isl_printer *p,
121	const char *s)
122{
123	return str_print(p, s, strlen(s));
124}
125
126static __isl_give isl_printer *str_print_double(__isl_take isl_printer *p,
127	double d)
128{
129	int left = p->buf_size - p->buf_n;
130	int need = snprintf(p->buf + p->buf_n, left, "%g", d);
131	if (need >= left) {
132		if (grow_buf(p, need))
133			goto error;
134		left = p->buf_size - p->buf_n;
135		need = snprintf(p->buf + p->buf_n, left, "%g", d);
136	}
137	p->buf_n += need;
138	return p;
139error:
140	isl_printer_free(p);
141	return NULL;
142}
143
144static __isl_give isl_printer *str_print_int(__isl_take isl_printer *p, int i)
145{
146	int left = p->buf_size - p->buf_n;
147	int need = snprintf(p->buf + p->buf_n, left, "%d", i);
148	if (need >= left) {
149		if (grow_buf(p, need))
150			goto error;
151		left = p->buf_size - p->buf_n;
152		need = snprintf(p->buf + p->buf_n, left, "%d", i);
153	}
154	p->buf_n += need;
155	return p;
156error:
157	isl_printer_free(p);
158	return NULL;
159}
160
161static __isl_give isl_printer *str_print_isl_int(__isl_take isl_printer *p,
162	isl_int i)
163{
164	char *s;
165	int len;
166
167	s = isl_int_get_str(i);
168	len = strlen(s);
169	if (len < p->width)
170		p = str_print_indent(p, p->width - len);
171	p = str_print(p, s, len);
172	isl_int_free_str(s);
173	return p;
174}
175
176struct isl_printer_ops {
177	__isl_give isl_printer *(*start_line)(__isl_take isl_printer *p);
178	__isl_give isl_printer *(*end_line)(__isl_take isl_printer *p);
179	__isl_give isl_printer *(*print_double)(__isl_take isl_printer *p,
180		double d);
181	__isl_give isl_printer *(*print_int)(__isl_take isl_printer *p, int i);
182	__isl_give isl_printer *(*print_isl_int)(__isl_take isl_printer *p,
183						isl_int i);
184	__isl_give isl_printer *(*print_str)(__isl_take isl_printer *p,
185						const char *s);
186	__isl_give isl_printer *(*flush)(__isl_take isl_printer *p);
187};
188
189static struct isl_printer_ops file_ops = {
190	file_start_line,
191	file_end_line,
192	file_print_double,
193	file_print_int,
194	file_print_isl_int,
195	file_print_str,
196	file_flush
197};
198
199static struct isl_printer_ops str_ops = {
200	str_start_line,
201	str_end_line,
202	str_print_double,
203	str_print_int,
204	str_print_isl_int,
205	str_print_str,
206	str_flush
207};
208
209__isl_give isl_printer *isl_printer_to_file(isl_ctx *ctx, FILE *file)
210{
211	struct isl_printer *p = isl_alloc_type(ctx, struct isl_printer);
212	if (!p)
213		return NULL;
214	p->ctx = ctx;
215	isl_ctx_ref(p->ctx);
216	p->ops = &file_ops;
217	p->file = file;
218	p->buf = NULL;
219	p->buf_n = 0;
220	p->buf_size = 0;
221	p->indent = 0;
222	p->output_format = ISL_FORMAT_ISL;
223	p->prefix = NULL;
224	p->suffix = NULL;
225	p->width = 0;
226
227	return p;
228}
229
230__isl_give isl_printer *isl_printer_to_str(isl_ctx *ctx)
231{
232	struct isl_printer *p = isl_alloc_type(ctx, struct isl_printer);
233	if (!p)
234		return NULL;
235	p->ctx = ctx;
236	isl_ctx_ref(p->ctx);
237	p->ops = &str_ops;
238	p->file = NULL;
239	p->buf = isl_alloc_array(ctx, char, 256);
240	if (!p->buf)
241		goto error;
242	p->buf_n = 0;
243	p->buf[0] = '\0';
244	p->buf_size = 256;
245	p->indent = 0;
246	p->output_format = ISL_FORMAT_ISL;
247	p->prefix = NULL;
248	p->suffix = NULL;
249	p->width = 0;
250
251	return p;
252error:
253	isl_printer_free(p);
254	return NULL;
255}
256
257void *isl_printer_free(__isl_take isl_printer *p)
258{
259	if (!p)
260		return NULL;
261	free(p->buf);
262	isl_ctx_deref(p->ctx);
263	free(p);
264
265	return NULL;
266}
267
268isl_ctx *isl_printer_get_ctx(__isl_keep isl_printer *printer)
269{
270	return printer ? printer->ctx : NULL;
271}
272
273FILE *isl_printer_get_file(__isl_keep isl_printer *printer)
274{
275	if (!printer)
276		return NULL;
277	if (!printer->file)
278		isl_die(isl_printer_get_ctx(printer), isl_error_invalid,
279			"not a file printer", return NULL);
280	return printer->file;
281}
282
283__isl_give isl_printer *isl_printer_set_isl_int_width(__isl_take isl_printer *p,
284	int width)
285{
286	if (!p)
287		return NULL;
288
289	p->width = width;
290
291	return p;
292}
293
294__isl_give isl_printer *isl_printer_set_indent(__isl_take isl_printer *p,
295	int indent)
296{
297	if (!p)
298		return NULL;
299
300	p->indent = indent;
301
302	return p;
303}
304
305__isl_give isl_printer *isl_printer_indent(__isl_take isl_printer *p,
306	int indent)
307{
308	if (!p)
309		return NULL;
310
311	p->indent += indent;
312	if (p->indent < 0)
313		p->indent = 0;
314
315	return p;
316}
317
318__isl_give isl_printer *isl_printer_set_prefix(__isl_take isl_printer *p,
319	const char *prefix)
320{
321	if (!p)
322		return NULL;
323
324	p->prefix = prefix;
325
326	return p;
327}
328
329__isl_give isl_printer *isl_printer_set_suffix(__isl_take isl_printer *p,
330	const char *suffix)
331{
332	if (!p)
333		return NULL;
334
335	p->suffix = suffix;
336
337	return p;
338}
339
340__isl_give isl_printer *isl_printer_set_output_format(__isl_take isl_printer *p,
341	int output_format)
342{
343	if (!p)
344		return NULL;
345
346	p->output_format = output_format;
347
348	return p;
349}
350
351int isl_printer_get_output_format(__isl_keep isl_printer *p)
352{
353	if (!p)
354		return -1;
355	return p->output_format;
356}
357
358__isl_give isl_printer *isl_printer_print_str(__isl_take isl_printer *p,
359	const char *s)
360{
361	if (!p)
362		return NULL;
363	if (!s)
364		return isl_printer_free(p);
365
366	return p->ops->print_str(p, s);
367}
368
369__isl_give isl_printer *isl_printer_print_double(__isl_take isl_printer *p,
370	double d)
371{
372	if (!p)
373		return NULL;
374
375	return p->ops->print_double(p, d);
376}
377
378__isl_give isl_printer *isl_printer_print_int(__isl_take isl_printer *p, int i)
379{
380	if (!p)
381		return NULL;
382
383	return p->ops->print_int(p, i);
384}
385
386__isl_give isl_printer *isl_printer_print_isl_int(__isl_take isl_printer *p,
387	isl_int i)
388{
389	if (!p)
390		return NULL;
391
392	return p->ops->print_isl_int(p, i);
393}
394
395__isl_give isl_printer *isl_printer_start_line(__isl_take isl_printer *p)
396{
397	if (!p)
398		return NULL;
399
400	return p->ops->start_line(p);
401}
402
403__isl_give isl_printer *isl_printer_end_line(__isl_take isl_printer *p)
404{
405	if (!p)
406		return NULL;
407
408	return p->ops->end_line(p);
409}
410
411char *isl_printer_get_str(__isl_keep isl_printer *printer)
412{
413	if (!printer || !printer->buf)
414		return NULL;
415	return strdup(printer->buf);
416}
417
418__isl_give isl_printer *isl_printer_flush(__isl_take isl_printer *p)
419{
420	if (!p)
421		return NULL;
422
423	return p->ops->flush(p);
424}
425