1 #include <string.h>
2 #include <isl_int.h>
3 #include <isl/id.h>
4 #include <isl/id_to_id.h>
5 #include <isl_printer_private.h>
6 
file_start_line(__isl_take isl_printer * p)7 static __isl_give isl_printer *file_start_line(__isl_take isl_printer *p)
8 {
9 	fprintf(p->file, "%s%*s%s", p->indent_prefix ? p->indent_prefix : "",
10 				    p->indent, "", p->prefix ? p->prefix : "");
11 	return p;
12 }
13 
file_end_line(__isl_take isl_printer * p)14 static __isl_give isl_printer *file_end_line(__isl_take isl_printer *p)
15 {
16 	fprintf(p->file, "%s\n", p->suffix ? p->suffix : "");
17 	return p;
18 }
19 
file_flush(__isl_take isl_printer * p)20 static __isl_give isl_printer *file_flush(__isl_take isl_printer *p)
21 {
22 	fflush(p->file);
23 	return p;
24 }
25 
file_print_str(__isl_take isl_printer * p,const char * s)26 static __isl_give isl_printer *file_print_str(__isl_take isl_printer *p,
27 	const char *s)
28 {
29 	fprintf(p->file, "%s", s);
30 	return p;
31 }
32 
file_print_double(__isl_take isl_printer * p,double d)33 static __isl_give isl_printer *file_print_double(__isl_take isl_printer *p,
34 	double d)
35 {
36 	fprintf(p->file, "%g", d);
37 	return p;
38 }
39 
file_print_int(__isl_take isl_printer * p,int i)40 static __isl_give isl_printer *file_print_int(__isl_take isl_printer *p, int i)
41 {
42 	fprintf(p->file, "%d", i);
43 	return p;
44 }
45 
file_print_isl_int(__isl_take isl_printer * p,isl_int i)46 static __isl_give isl_printer *file_print_isl_int(__isl_take isl_printer *p, isl_int i)
47 {
48 	isl_int_print(p->file, i, p->width);
49 	return p;
50 }
51 
grow_buf(__isl_keep isl_printer * p,int extra)52 static int grow_buf(__isl_keep isl_printer *p, int extra)
53 {
54 	int new_size;
55 	char *new_buf;
56 
57 	if (p->buf_size == 0)
58 		return -1;
59 
60 	new_size = ((p->buf_n + extra + 1) * 3) / 2;
61 	new_buf = isl_realloc_array(p->ctx, p->buf, char, new_size);
62 	if (!new_buf) {
63 		p->buf_size = 0;
64 		return -1;
65 	}
66 	p->buf = new_buf;
67 	p->buf_size = new_size;
68 
69 	return 0;
70 }
71 
str_print(__isl_take isl_printer * p,const char * s,int len)72 static __isl_give isl_printer *str_print(__isl_take isl_printer *p,
73 	const char *s, int len)
74 {
75 	if (p->buf_n + len + 1 >= p->buf_size && grow_buf(p, len))
76 		goto error;
77 	memcpy(p->buf + p->buf_n, s, len);
78 	p->buf_n += len;
79 
80 	p->buf[p->buf_n] = '\0';
81 	return p;
82 error:
83 	isl_printer_free(p);
84 	return NULL;
85 }
86 
str_print_indent(__isl_take isl_printer * p,int indent)87 static __isl_give isl_printer *str_print_indent(__isl_take isl_printer *p,
88 	int indent)
89 {
90 	int i;
91 
92 	if (p->buf_n + indent + 1 >= p->buf_size && grow_buf(p, indent))
93 		goto error;
94 	for (i = 0; i < indent; ++i)
95 		p->buf[p->buf_n++] = ' ';
96 	p->buf[p->buf_n] = '\0';
97 	return p;
98 error:
99 	isl_printer_free(p);
100 	return NULL;
101 }
102 
str_start_line(__isl_take isl_printer * p)103 static __isl_give isl_printer *str_start_line(__isl_take isl_printer *p)
104 {
105 	if (p->indent_prefix)
106 		p = str_print(p, p->indent_prefix, strlen(p->indent_prefix));
107 	p = str_print_indent(p, p->indent);
108 	if (p->prefix)
109 		p = str_print(p, p->prefix, strlen(p->prefix));
110 	return p;
111 }
112 
str_end_line(__isl_take isl_printer * p)113 static __isl_give isl_printer *str_end_line(__isl_take isl_printer *p)
114 {
115 	if (p->suffix)
116 		p = str_print(p, p->suffix, strlen(p->suffix));
117 	p = str_print(p, "\n", strlen("\n"));
118 	return p;
119 }
120 
str_flush(__isl_take isl_printer * p)121 static __isl_give isl_printer *str_flush(__isl_take isl_printer *p)
122 {
123 	p->buf_n = 0;
124 	p->buf[p->buf_n] = '\0';
125 	return p;
126 }
127 
str_print_str(__isl_take isl_printer * p,const char * s)128 static __isl_give isl_printer *str_print_str(__isl_take isl_printer *p,
129 	const char *s)
130 {
131 	return str_print(p, s, strlen(s));
132 }
133 
str_print_double(__isl_take isl_printer * p,double d)134 static __isl_give isl_printer *str_print_double(__isl_take isl_printer *p,
135 	double d)
136 {
137 	int left = p->buf_size - p->buf_n;
138 	int need = snprintf(p->buf + p->buf_n, left, "%g", d);
139 	if (need >= left) {
140 		if (grow_buf(p, need))
141 			goto error;
142 		left = p->buf_size - p->buf_n;
143 		need = snprintf(p->buf + p->buf_n, left, "%g", d);
144 	}
145 	p->buf_n += need;
146 	return p;
147 error:
148 	isl_printer_free(p);
149 	return NULL;
150 }
151 
str_print_int(__isl_take isl_printer * p,int i)152 static __isl_give isl_printer *str_print_int(__isl_take isl_printer *p, int i)
153 {
154 	int left = p->buf_size - p->buf_n;
155 	int need = snprintf(p->buf + p->buf_n, left, "%d", i);
156 	if (need >= left) {
157 		if (grow_buf(p, need))
158 			goto error;
159 		left = p->buf_size - p->buf_n;
160 		need = snprintf(p->buf + p->buf_n, left, "%d", i);
161 	}
162 	p->buf_n += need;
163 	return p;
164 error:
165 	isl_printer_free(p);
166 	return NULL;
167 }
168 
str_print_isl_int(__isl_take isl_printer * p,isl_int i)169 static __isl_give isl_printer *str_print_isl_int(__isl_take isl_printer *p,
170 	isl_int i)
171 {
172 	char *s;
173 	int len;
174 
175 	s = isl_int_get_str(i);
176 	len = strlen(s);
177 	if (len < p->width)
178 		p = str_print_indent(p, p->width - len);
179 	p = str_print(p, s, len);
180 	isl_int_free_str(s);
181 	return p;
182 }
183 
184 struct isl_printer_ops {
185 	__isl_give isl_printer *(*start_line)(__isl_take isl_printer *p);
186 	__isl_give isl_printer *(*end_line)(__isl_take isl_printer *p);
187 	__isl_give isl_printer *(*print_double)(__isl_take isl_printer *p,
188 		double d);
189 	__isl_give isl_printer *(*print_int)(__isl_take isl_printer *p, int i);
190 	__isl_give isl_printer *(*print_isl_int)(__isl_take isl_printer *p,
191 						isl_int i);
192 	__isl_give isl_printer *(*print_str)(__isl_take isl_printer *p,
193 						const char *s);
194 	__isl_give isl_printer *(*flush)(__isl_take isl_printer *p);
195 };
196 
197 static struct isl_printer_ops file_ops = {
198 	file_start_line,
199 	file_end_line,
200 	file_print_double,
201 	file_print_int,
202 	file_print_isl_int,
203 	file_print_str,
204 	file_flush
205 };
206 
207 static struct isl_printer_ops str_ops = {
208 	str_start_line,
209 	str_end_line,
210 	str_print_double,
211 	str_print_int,
212 	str_print_isl_int,
213 	str_print_str,
214 	str_flush
215 };
216 
isl_printer_to_file(isl_ctx * ctx,FILE * file)217 __isl_give isl_printer *isl_printer_to_file(isl_ctx *ctx, FILE *file)
218 {
219 	struct isl_printer *p = isl_calloc_type(ctx, struct isl_printer);
220 	if (!p)
221 		return NULL;
222 	p->ctx = ctx;
223 	isl_ctx_ref(p->ctx);
224 	p->ops = &file_ops;
225 	p->file = file;
226 	p->buf = NULL;
227 	p->buf_n = 0;
228 	p->buf_size = 0;
229 	p->indent = 0;
230 	p->output_format = ISL_FORMAT_ISL;
231 	p->indent_prefix = NULL;
232 	p->prefix = NULL;
233 	p->suffix = NULL;
234 	p->width = 0;
235 	p->yaml_style = ISL_YAML_STYLE_FLOW;
236 
237 	return p;
238 }
239 
isl_printer_to_str(isl_ctx * ctx)240 __isl_give isl_printer *isl_printer_to_str(isl_ctx *ctx)
241 {
242 	struct isl_printer *p = isl_calloc_type(ctx, struct isl_printer);
243 	if (!p)
244 		return NULL;
245 	p->ctx = ctx;
246 	isl_ctx_ref(p->ctx);
247 	p->ops = &str_ops;
248 	p->file = NULL;
249 	p->buf = isl_alloc_array(ctx, char, 256);
250 	if (!p->buf)
251 		goto error;
252 	p->buf_n = 0;
253 	p->buf[0] = '\0';
254 	p->buf_size = 256;
255 	p->indent = 0;
256 	p->output_format = ISL_FORMAT_ISL;
257 	p->indent_prefix = NULL;
258 	p->prefix = NULL;
259 	p->suffix = NULL;
260 	p->width = 0;
261 	p->yaml_style = ISL_YAML_STYLE_FLOW;
262 
263 	return p;
264 error:
265 	isl_printer_free(p);
266 	return NULL;
267 }
268 
isl_printer_free(__isl_take isl_printer * p)269 __isl_null isl_printer *isl_printer_free(__isl_take isl_printer *p)
270 {
271 	if (!p)
272 		return NULL;
273 	free(p->buf);
274 	free(p->indent_prefix);
275 	free(p->prefix);
276 	free(p->suffix);
277 	free(p->yaml_state);
278 	isl_id_to_id_free(p->notes);
279 	isl_ctx_deref(p->ctx);
280 	free(p);
281 
282 	return NULL;
283 }
284 
isl_printer_get_ctx(__isl_keep isl_printer * printer)285 isl_ctx *isl_printer_get_ctx(__isl_keep isl_printer *printer)
286 {
287 	return printer ? printer->ctx : NULL;
288 }
289 
isl_printer_get_file(__isl_keep isl_printer * printer)290 FILE *isl_printer_get_file(__isl_keep isl_printer *printer)
291 {
292 	if (!printer)
293 		return NULL;
294 	if (!printer->file)
295 		isl_die(isl_printer_get_ctx(printer), isl_error_invalid,
296 			"not a file printer", return NULL);
297 	return printer->file;
298 }
299 
isl_printer_set_isl_int_width(__isl_take isl_printer * p,int width)300 __isl_give isl_printer *isl_printer_set_isl_int_width(__isl_take isl_printer *p,
301 	int width)
302 {
303 	if (!p)
304 		return NULL;
305 
306 	p->width = width;
307 
308 	return p;
309 }
310 
isl_printer_set_indent(__isl_take isl_printer * p,int indent)311 __isl_give isl_printer *isl_printer_set_indent(__isl_take isl_printer *p,
312 	int indent)
313 {
314 	if (!p)
315 		return NULL;
316 
317 	p->indent = indent;
318 
319 	return p;
320 }
321 
isl_printer_indent(__isl_take isl_printer * p,int indent)322 __isl_give isl_printer *isl_printer_indent(__isl_take isl_printer *p,
323 	int indent)
324 {
325 	if (!p)
326 		return NULL;
327 
328 	p->indent += indent;
329 	if (p->indent < 0)
330 		p->indent = 0;
331 
332 	return p;
333 }
334 
335 /* Replace the indent prefix of "p" by "prefix".
336  */
isl_printer_set_indent_prefix(__isl_take isl_printer * p,const char * prefix)337 __isl_give isl_printer *isl_printer_set_indent_prefix(__isl_take isl_printer *p,
338 	const char *prefix)
339 {
340 	if (!p)
341 		return NULL;
342 
343 	free(p->indent_prefix);
344 	p->indent_prefix = prefix ? strdup(prefix) : NULL;
345 
346 	return p;
347 }
348 
isl_printer_set_prefix(__isl_take isl_printer * p,const char * prefix)349 __isl_give isl_printer *isl_printer_set_prefix(__isl_take isl_printer *p,
350 	const char *prefix)
351 {
352 	if (!p)
353 		return NULL;
354 
355 	free(p->prefix);
356 	p->prefix = prefix ? strdup(prefix) : NULL;
357 
358 	return p;
359 }
360 
isl_printer_set_suffix(__isl_take isl_printer * p,const char * suffix)361 __isl_give isl_printer *isl_printer_set_suffix(__isl_take isl_printer *p,
362 	const char *suffix)
363 {
364 	if (!p)
365 		return NULL;
366 
367 	free(p->suffix);
368 	p->suffix = suffix ? strdup(suffix) : NULL;
369 
370 	return p;
371 }
372 
isl_printer_set_output_format(__isl_take isl_printer * p,int output_format)373 __isl_give isl_printer *isl_printer_set_output_format(__isl_take isl_printer *p,
374 	int output_format)
375 {
376 	if (!p)
377 		return NULL;
378 
379 	p->output_format = output_format;
380 
381 	return p;
382 }
383 
isl_printer_get_output_format(__isl_keep isl_printer * p)384 int isl_printer_get_output_format(__isl_keep isl_printer *p)
385 {
386 	if (!p)
387 		return -1;
388 	return p->output_format;
389 }
390 
391 /* Does "p" have a note with identifier "id"?
392  */
isl_printer_has_note(__isl_keep isl_printer * p,__isl_keep isl_id * id)393 isl_bool isl_printer_has_note(__isl_keep isl_printer *p,
394 	__isl_keep isl_id *id)
395 {
396 	if (!p || !id)
397 		return isl_bool_error;
398 	if (!p->notes)
399 		return isl_bool_false;
400 	return isl_id_to_id_has(p->notes, id);
401 }
402 
403 /* Retrieve the note identified by "id" from "p".
404  * The note is assumed to exist.
405  */
isl_printer_get_note(__isl_keep isl_printer * p,__isl_take isl_id * id)406 __isl_give isl_id *isl_printer_get_note(__isl_keep isl_printer *p,
407 	__isl_take isl_id *id)
408 {
409 	isl_bool has_note;
410 
411 	has_note = isl_printer_has_note(p, id);
412 	if (has_note < 0)
413 		goto error;
414 	if (!has_note)
415 		isl_die(isl_printer_get_ctx(p), isl_error_invalid,
416 			"no such note", goto error);
417 
418 	return isl_id_to_id_get(p->notes, id);
419 error:
420 	isl_id_free(id);
421 	return NULL;
422 }
423 
424 /* Associate "note" to the identifier "id" in "p",
425  * replacing the previous note associated to the identifier, if any.
426  */
isl_printer_set_note(__isl_take isl_printer * p,__isl_take isl_id * id,__isl_take isl_id * note)427 __isl_give isl_printer *isl_printer_set_note(__isl_take isl_printer *p,
428 	__isl_take isl_id *id, __isl_take isl_id *note)
429 {
430 	if (!p || !id || !note)
431 		goto error;
432 	if (!p->notes) {
433 		p->notes = isl_id_to_id_alloc(isl_printer_get_ctx(p), 1);
434 		if (!p->notes)
435 			goto error;
436 	}
437 	p->notes = isl_id_to_id_set(p->notes, id, note);
438 	if (!p->notes)
439 		return isl_printer_free(p);
440 	return p;
441 error:
442 	isl_printer_free(p);
443 	isl_id_free(id);
444 	isl_id_free(note);
445 	return NULL;
446 }
447 
448 /* Keep track of whether the printing to "p" is being performed from
449  * an isl_*_dump function as specified by "dump".
450  */
isl_printer_set_dump(__isl_take isl_printer * p,int dump)451 __isl_give isl_printer *isl_printer_set_dump(__isl_take isl_printer *p,
452 	int dump)
453 {
454 	if (!p)
455 		return NULL;
456 
457 	p->dump = dump;
458 
459 	return p;
460 }
461 
462 /* Set the YAML style of "p" to "yaml_style" and return the updated printer.
463  */
isl_printer_set_yaml_style(__isl_take isl_printer * p,int yaml_style)464 __isl_give isl_printer *isl_printer_set_yaml_style(__isl_take isl_printer *p,
465 	int yaml_style)
466 {
467 	if (!p)
468 		return NULL;
469 
470 	p->yaml_style = yaml_style;
471 
472 	return p;
473 }
474 
475 /* Return the YAML style of "p" or -1 on error.
476  */
isl_printer_get_yaml_style(__isl_keep isl_printer * p)477 int isl_printer_get_yaml_style(__isl_keep isl_printer *p)
478 {
479 	if (!p)
480 		return -1;
481 	return p->yaml_style;
482 }
483 
484 /* Push "state" onto the stack of currently active YAML elements and
485  * return the updated printer.
486  */
push_state(__isl_take isl_printer * p,enum isl_yaml_state state)487 static __isl_give isl_printer *push_state(__isl_take isl_printer *p,
488 	enum isl_yaml_state state)
489 {
490 	if (!p)
491 		return NULL;
492 
493 	if (p->yaml_size < p->yaml_depth + 1) {
494 		enum isl_yaml_state *state;
495 		state = isl_realloc_array(p->ctx, p->yaml_state,
496 					enum isl_yaml_state, p->yaml_depth + 1);
497 		if (!state)
498 			return isl_printer_free(p);
499 		p->yaml_state = state;
500 		p->yaml_size = p->yaml_depth + 1;
501 	}
502 
503 	p->yaml_state[p->yaml_depth] = state;
504 	p->yaml_depth++;
505 
506 	return p;
507 }
508 
509 /* Remove the innermost active YAML element from the stack and
510  * return the updated printer.
511  */
pop_state(__isl_take isl_printer * p)512 static __isl_give isl_printer *pop_state(__isl_take isl_printer *p)
513 {
514 	if (!p)
515 		return NULL;
516 	p->yaml_depth--;
517 	return p;
518 }
519 
520 /* Set the state of the innermost active YAML element to "state" and
521  * return the updated printer.
522  */
update_state(__isl_take isl_printer * p,enum isl_yaml_state state)523 static __isl_give isl_printer *update_state(__isl_take isl_printer *p,
524 	enum isl_yaml_state state)
525 {
526 	if (!p)
527 		return NULL;
528 	if (p->yaml_depth < 1)
529 		isl_die(isl_printer_get_ctx(p), isl_error_invalid,
530 			"not in YAML construct", return isl_printer_free(p));
531 
532 	p->yaml_state[p->yaml_depth - 1] = state;
533 
534 	return p;
535 }
536 
537 /* Return the state of the innermost active YAML element.
538  * Return isl_yaml_none if we are not inside any YAML element.
539  */
current_state(__isl_keep isl_printer * p)540 static enum isl_yaml_state current_state(__isl_keep isl_printer *p)
541 {
542 	if (!p)
543 		return isl_yaml_none;
544 	if (p->yaml_depth < 1)
545 		return isl_yaml_none;
546 	return p->yaml_state[p->yaml_depth - 1];
547 }
548 
549 /* If we are printing a YAML document and we are at the start of an element,
550  * print whatever is needed before we can print the actual element and
551  * keep track of the fact that we are now printing the element.
552  * If "eol" is set, then whatever we print is going to be the last
553  * thing that gets printed on this line.
554  *
555  * If we are about the print the first key of a mapping, then nothing
556  * extra needs to be printed.  For any other key, however, we need
557  * to either move to the next line (in block format) or print a comma
558  * (in flow format).
559  * Before printing a value in a mapping, we need to print a colon.
560  *
561  * For sequences, in flow format, we only need to print a comma
562  * for each element except the first.
563  * In block format, before the first element in the sequence,
564  * we move to a new line, print a dash and increase the indentation.
565  * Before any other element, we print a dash on a new line,
566  * temporarily moving the indentation back.
567  */
enter_state(__isl_take isl_printer * p,int eol)568 static __isl_give isl_printer *enter_state(__isl_take isl_printer *p,
569 	int eol)
570 {
571 	enum isl_yaml_state state;
572 
573 	if (!p)
574 		return NULL;
575 
576 	state = current_state(p);
577 	if (state == isl_yaml_mapping_val_start) {
578 		if (eol)
579 			p = p->ops->print_str(p, ":");
580 		else
581 			p = p->ops->print_str(p, ": ");
582 		p = update_state(p, isl_yaml_mapping_val);
583 	} else if (state == isl_yaml_mapping_first_key_start) {
584 		p = update_state(p, isl_yaml_mapping_key);
585 	} else if (state == isl_yaml_mapping_key_start) {
586 		if (p->yaml_style == ISL_YAML_STYLE_FLOW)
587 			p = p->ops->print_str(p, ", ");
588 		else {
589 			p = p->ops->end_line(p);
590 			p = p->ops->start_line(p);
591 		}
592 		p = update_state(p, isl_yaml_mapping_key);
593 	} else if (state == isl_yaml_sequence_first_start) {
594 		if (p->yaml_style != ISL_YAML_STYLE_FLOW) {
595 			p = p->ops->end_line(p);
596 			p = p->ops->start_line(p);
597 			p = p->ops->print_str(p, "- ");
598 			p = isl_printer_indent(p, 2);
599 		}
600 		p = update_state(p, isl_yaml_sequence);
601 	} else if (state == isl_yaml_sequence_start) {
602 		if (p->yaml_style == ISL_YAML_STYLE_FLOW)
603 			p = p->ops->print_str(p, ", ");
604 		else {
605 			p = p->ops->end_line(p);
606 			p = isl_printer_indent(p, -2);
607 			p = p->ops->start_line(p);
608 			p = p->ops->print_str(p, "- ");
609 			p = isl_printer_indent(p, 2);
610 		}
611 		p = update_state(p, isl_yaml_sequence);
612 	}
613 
614 	return p;
615 }
616 
isl_printer_print_str(__isl_take isl_printer * p,const char * s)617 __isl_give isl_printer *isl_printer_print_str(__isl_take isl_printer *p,
618 	const char *s)
619 {
620 	if (!p)
621 		return NULL;
622 	if (!s)
623 		return isl_printer_free(p);
624 	p = enter_state(p, 0);
625 	if (!p)
626 		return NULL;
627 	return p->ops->print_str(p, s);
628 }
629 
isl_printer_print_double(__isl_take isl_printer * p,double d)630 __isl_give isl_printer *isl_printer_print_double(__isl_take isl_printer *p,
631 	double d)
632 {
633 	p = enter_state(p, 0);
634 	if (!p)
635 		return NULL;
636 
637 	return p->ops->print_double(p, d);
638 }
639 
isl_printer_print_int(__isl_take isl_printer * p,int i)640 __isl_give isl_printer *isl_printer_print_int(__isl_take isl_printer *p, int i)
641 {
642 	p = enter_state(p, 0);
643 	if (!p)
644 		return NULL;
645 
646 	return p->ops->print_int(p, i);
647 }
648 
isl_printer_print_isl_int(__isl_take isl_printer * p,isl_int i)649 __isl_give isl_printer *isl_printer_print_isl_int(__isl_take isl_printer *p,
650 	isl_int i)
651 {
652 	p = enter_state(p, 0);
653 	if (!p)
654 		return NULL;
655 
656 	return p->ops->print_isl_int(p, i);
657 }
658 
isl_printer_start_line(__isl_take isl_printer * p)659 __isl_give isl_printer *isl_printer_start_line(__isl_take isl_printer *p)
660 {
661 	if (!p)
662 		return NULL;
663 
664 	return p->ops->start_line(p);
665 }
666 
isl_printer_end_line(__isl_take isl_printer * p)667 __isl_give isl_printer *isl_printer_end_line(__isl_take isl_printer *p)
668 {
669 	if (!p)
670 		return NULL;
671 
672 	return p->ops->end_line(p);
673 }
674 
675 /* Return a copy of the string constructed by the string printer "printer".
676  */
isl_printer_get_str(__isl_keep isl_printer * printer)677 __isl_give char *isl_printer_get_str(__isl_keep isl_printer *printer)
678 {
679 	if (!printer)
680 		return NULL;
681 	if (printer->ops != &str_ops)
682 		isl_die(isl_printer_get_ctx(printer), isl_error_invalid,
683 			"isl_printer_get_str can only be called on a string "
684 			"printer", return NULL);
685 	if (!printer->buf)
686 		return NULL;
687 	return strdup(printer->buf);
688 }
689 
isl_printer_flush(__isl_take isl_printer * p)690 __isl_give isl_printer *isl_printer_flush(__isl_take isl_printer *p)
691 {
692 	if (!p)
693 		return NULL;
694 
695 	return p->ops->flush(p);
696 }
697 
698 /* Start a YAML mapping and push a new state to reflect that we
699  * are about to print the first key in a mapping.
700  *
701  * In flow style, print the opening brace.
702  * In block style, move to the next line with an increased indentation,
703  * except if this is the outer mapping or if we are inside a sequence
704  * (in which case we have already increased the indentation and we want
705  * to print the first key on the same line as the dash).
706  */
isl_printer_yaml_start_mapping(__isl_take isl_printer * p)707 __isl_give isl_printer *isl_printer_yaml_start_mapping(
708 	__isl_take isl_printer *p)
709 {
710 	enum isl_yaml_state state;
711 
712 	if (!p)
713 		return NULL;
714 	p = enter_state(p, p->yaml_style == ISL_YAML_STYLE_BLOCK);
715 	if (!p)
716 		return NULL;
717 	state = current_state(p);
718 	if (p->yaml_style == ISL_YAML_STYLE_FLOW)
719 		p = p->ops->print_str(p, "{ ");
720 	else if (state != isl_yaml_none && state != isl_yaml_sequence) {
721 		p = p->ops->end_line(p);
722 		p = isl_printer_indent(p, 2);
723 		p = p->ops->start_line(p);
724 	}
725 	p = push_state(p, isl_yaml_mapping_first_key_start);
726 	return p;
727 }
728 
729 /* Finish a YAML mapping and pop it from the state stack.
730  *
731  * In flow style, print the closing brace.
732  *
733  * In block style, first check if we are still in the
734  * isl_yaml_mapping_first_key_start state.  If so, we have not printed
735  * anything yet, so print "{}" to indicate an empty mapping.
736  * If we increased the indentation in isl_printer_yaml_start_mapping,
737  * then decrease it again.
738  * If this is the outer mapping then print a newline.
739  */
isl_printer_yaml_end_mapping(__isl_take isl_printer * p)740 __isl_give isl_printer *isl_printer_yaml_end_mapping(
741 	__isl_take isl_printer *p)
742 {
743 	enum isl_yaml_state state;
744 
745 	state = current_state(p);
746 	p = pop_state(p);
747 	if (!p)
748 		return NULL;
749 	if (p->yaml_style == ISL_YAML_STYLE_FLOW)
750 		return p->ops->print_str(p, " }");
751 	if (state == isl_yaml_mapping_first_key_start)
752 		p = p->ops->print_str(p, "{}");
753 	if (!p)
754 		return NULL;
755 	state = current_state(p);
756 	if (state != isl_yaml_none && state != isl_yaml_sequence)
757 		p = isl_printer_indent(p, -2);
758 	if (state == isl_yaml_none)
759 		p = p->ops->end_line(p);
760 	return p;
761 }
762 
763 /* Start a YAML sequence and push a new state to reflect that we
764  * are about to print the first element in a sequence.
765  *
766  * In flow style, print the opening bracket.
767  */
isl_printer_yaml_start_sequence(__isl_take isl_printer * p)768 __isl_give isl_printer *isl_printer_yaml_start_sequence(
769 	__isl_take isl_printer *p)
770 {
771 	if (!p)
772 		return NULL;
773 	p = enter_state(p, p->yaml_style == ISL_YAML_STYLE_BLOCK);
774 	p = push_state(p, isl_yaml_sequence_first_start);
775 	if (!p)
776 		return NULL;
777 	if (p->yaml_style == ISL_YAML_STYLE_FLOW)
778 		p = p->ops->print_str(p, "[ ");
779 	return p;
780 }
781 
782 /* Finish a YAML sequence and pop it from the state stack.
783  *
784  * In flow style, print the closing bracket.
785  *
786  * In block style, check if we are still in the
787  * isl_yaml_sequence_first_start state.  If so, we have not printed
788  * anything yet, so print "[]" or " []" to indicate an empty sequence.
789  * We print the extra space when we instructed enter_state not
790  * to print a space at the end of the line.
791  * Otherwise, undo the increase in indentation performed by
792  * enter_state when moving away from the isl_yaml_sequence_first_start
793  * state.
794  * If this is the outer sequence then print a newline.
795  */
isl_printer_yaml_end_sequence(__isl_take isl_printer * p)796 __isl_give isl_printer *isl_printer_yaml_end_sequence(
797 	__isl_take isl_printer *p)
798 {
799 	enum isl_yaml_state state, up;
800 
801 	state = current_state(p);
802 	p = pop_state(p);
803 	if (!p)
804 		return NULL;
805 	if (p->yaml_style == ISL_YAML_STYLE_FLOW)
806 		return p->ops->print_str(p, " ]");
807 	up = current_state(p);
808 	if (state == isl_yaml_sequence_first_start) {
809 		if (up == isl_yaml_mapping_val)
810 			p = p->ops->print_str(p, " []");
811 		else
812 			p = p->ops->print_str(p, "[]");
813 	} else {
814 		p = isl_printer_indent(p, -2);
815 	}
816 	if (!p)
817 		return NULL;
818 	state = current_state(p);
819 	if (state == isl_yaml_none)
820 		p = p->ops->end_line(p);
821 	return p;
822 }
823 
824 /* Mark the fact that the current element is finished and that
825  * the next output belongs to the next element.
826  * In particular, if we are printing a key, then prepare for
827  * printing the subsequent value.  If we are printing a value,
828  * prepare for printing the next key.  If we are printing an
829  * element in a sequence, prepare for printing the next element.
830  */
isl_printer_yaml_next(__isl_take isl_printer * p)831 __isl_give isl_printer *isl_printer_yaml_next(__isl_take isl_printer *p)
832 {
833 	enum isl_yaml_state state;
834 
835 	if (!p)
836 		return NULL;
837 	if (p->yaml_depth < 1)
838 		isl_die(isl_printer_get_ctx(p), isl_error_invalid,
839 			"not in YAML construct", return isl_printer_free(p));
840 
841 	state = current_state(p);
842 	if (state == isl_yaml_mapping_key)
843 		state = isl_yaml_mapping_val_start;
844 	else if (state == isl_yaml_mapping_val)
845 		state = isl_yaml_mapping_key_start;
846 	else if (state == isl_yaml_sequence)
847 		state = isl_yaml_sequence_start;
848 	p = update_state(p, state);
849 
850 	return p;
851 }
852