3 #include <isl_printer_private.h>
5 static __isl_give isl_printer
*file_start_line(__isl_take isl_printer
*p
)
7 fprintf(p
->file
, "%s%*s%s", p
->indent_prefix
? p
->indent_prefix
: "",
8 p
->indent
, "", p
->prefix
? p
->prefix
: "");
12 static __isl_give isl_printer
*file_end_line(__isl_take isl_printer
*p
)
14 fprintf(p
->file
, "%s\n", p
->suffix
? p
->suffix
: "");
18 static __isl_give isl_printer
*file_flush(__isl_take isl_printer
*p
)
24 static __isl_give isl_printer
*file_print_str(__isl_take isl_printer
*p
,
27 fprintf(p
->file
, "%s", s
);
31 static __isl_give isl_printer
*file_print_double(__isl_take isl_printer
*p
,
34 fprintf(p
->file
, "%g", d
);
38 static __isl_give isl_printer
*file_print_int(__isl_take isl_printer
*p
, int i
)
40 fprintf(p
->file
, "%d", i
);
44 static __isl_give isl_printer
*file_print_isl_int(__isl_take isl_printer
*p
, isl_int i
)
46 isl_int_print(p
->file
, i
, p
->width
);
50 static int grow_buf(__isl_keep isl_printer
*p
, int extra
)
58 new_size
= ((p
->buf_n
+ extra
+ 1) * 3) / 2;
59 new_buf
= isl_realloc_array(p
->ctx
, p
->buf
, char, new_size
);
65 p
->buf_size
= new_size
;
70 static __isl_give isl_printer
*str_print(__isl_take isl_printer
*p
,
71 const char *s
, int len
)
73 if (p
->buf_n
+ len
+ 1 >= p
->buf_size
&& grow_buf(p
, len
))
75 memcpy(p
->buf
+ p
->buf_n
, s
, len
);
78 p
->buf
[p
->buf_n
] = '\0';
85 static __isl_give isl_printer
*str_print_indent(__isl_take isl_printer
*p
,
90 if (p
->buf_n
+ indent
+ 1 >= p
->buf_size
&& grow_buf(p
, indent
))
92 for (i
= 0; i
< indent
; ++i
)
93 p
->buf
[p
->buf_n
++] = ' ';
100 static __isl_give isl_printer
*str_start_line(__isl_take isl_printer
*p
)
102 if (p
->indent_prefix
)
103 p
= str_print(p
, p
->indent_prefix
, strlen(p
->indent_prefix
));
104 p
= str_print_indent(p
, p
->indent
);
106 p
= str_print(p
, p
->prefix
, strlen(p
->prefix
));
110 static __isl_give isl_printer
*str_end_line(__isl_take isl_printer
*p
)
113 p
= str_print(p
, p
->suffix
, strlen(p
->suffix
));
114 p
= str_print(p
, "\n", strlen("\n"));
118 static __isl_give isl_printer
*str_flush(__isl_take isl_printer
*p
)
121 p
->buf
[p
->buf_n
] = '\0';
125 static __isl_give isl_printer
*str_print_str(__isl_take isl_printer
*p
,
128 return str_print(p
, s
, strlen(s
));
131 static __isl_give isl_printer
*str_print_double(__isl_take isl_printer
*p
,
134 int left
= p
->buf_size
- p
->buf_n
;
135 int need
= snprintf(p
->buf
+ p
->buf_n
, left
, "%g", d
);
137 if (grow_buf(p
, need
))
139 left
= p
->buf_size
- p
->buf_n
;
140 need
= snprintf(p
->buf
+ p
->buf_n
, left
, "%g", d
);
149 static __isl_give isl_printer
*str_print_int(__isl_take isl_printer
*p
, int i
)
151 int left
= p
->buf_size
- p
->buf_n
;
152 int need
= snprintf(p
->buf
+ p
->buf_n
, left
, "%d", i
);
154 if (grow_buf(p
, need
))
156 left
= p
->buf_size
- p
->buf_n
;
157 need
= snprintf(p
->buf
+ p
->buf_n
, left
, "%d", i
);
166 static __isl_give isl_printer
*str_print_isl_int(__isl_take isl_printer
*p
,
172 s
= isl_int_get_str(i
);
175 p
= str_print_indent(p
, p
->width
- len
);
176 p
= str_print(p
, s
, len
);
181 struct isl_printer_ops
{
182 __isl_give isl_printer
*(*start_line
)(__isl_take isl_printer
*p
);
183 __isl_give isl_printer
*(*end_line
)(__isl_take isl_printer
*p
);
184 __isl_give isl_printer
*(*print_double
)(__isl_take isl_printer
*p
,
186 __isl_give isl_printer
*(*print_int
)(__isl_take isl_printer
*p
, int i
);
187 __isl_give isl_printer
*(*print_isl_int
)(__isl_take isl_printer
*p
,
189 __isl_give isl_printer
*(*print_str
)(__isl_take isl_printer
*p
,
191 __isl_give isl_printer
*(*flush
)(__isl_take isl_printer
*p
);
194 static struct isl_printer_ops file_ops
= {
204 static struct isl_printer_ops str_ops
= {
214 __isl_give isl_printer
*isl_printer_to_file(isl_ctx
*ctx
, FILE *file
)
216 struct isl_printer
*p
= isl_calloc_type(ctx
, struct isl_printer
);
227 p
->output_format
= ISL_FORMAT_ISL
;
228 p
->indent_prefix
= NULL
;
232 p
->yaml_style
= ISL_YAML_STYLE_FLOW
;
237 __isl_give isl_printer
*isl_printer_to_str(isl_ctx
*ctx
)
239 struct isl_printer
*p
= isl_calloc_type(ctx
, struct isl_printer
);
246 p
->buf
= isl_alloc_array(ctx
, char, 256);
253 p
->output_format
= ISL_FORMAT_ISL
;
254 p
->indent_prefix
= NULL
;
258 p
->yaml_style
= ISL_YAML_STYLE_FLOW
;
266 __isl_null isl_printer
*isl_printer_free(__isl_take isl_printer
*p
)
271 free(p
->indent_prefix
);
275 isl_ctx_deref(p
->ctx
);
281 isl_ctx
*isl_printer_get_ctx(__isl_keep isl_printer
*printer
)
283 return printer
? printer
->ctx
: NULL
;
286 FILE *isl_printer_get_file(__isl_keep isl_printer
*printer
)
291 isl_die(isl_printer_get_ctx(printer
), isl_error_invalid
,
292 "not a file printer", return NULL
);
293 return printer
->file
;
296 __isl_give isl_printer
*isl_printer_set_isl_int_width(__isl_take isl_printer
*p
,
307 __isl_give isl_printer
*isl_printer_set_indent(__isl_take isl_printer
*p
,
318 __isl_give isl_printer
*isl_printer_indent(__isl_take isl_printer
*p
,
331 /* Replace the indent prefix of "p" by "prefix".
333 __isl_give isl_printer
*isl_printer_set_indent_prefix(__isl_take isl_printer
*p
,
339 free(p
->indent_prefix
);
340 p
->indent_prefix
= prefix
? strdup(prefix
) : NULL
;
345 __isl_give isl_printer
*isl_printer_set_prefix(__isl_take isl_printer
*p
,
352 p
->prefix
= prefix
? strdup(prefix
) : NULL
;
357 __isl_give isl_printer
*isl_printer_set_suffix(__isl_take isl_printer
*p
,
364 p
->suffix
= suffix
? strdup(suffix
) : NULL
;
369 __isl_give isl_printer
*isl_printer_set_output_format(__isl_take isl_printer
*p
,
375 p
->output_format
= output_format
;
380 int isl_printer_get_output_format(__isl_keep isl_printer
*p
)
384 return p
->output_format
;
387 /* Set the YAML style of "p" to "yaml_style" and return the updated printer.
389 __isl_give isl_printer
*isl_printer_set_yaml_style(__isl_take isl_printer
*p
,
395 p
->yaml_style
= yaml_style
;
400 /* Return the YAML style of "p" or -1 on error.
402 int isl_printer_get_yaml_style(__isl_keep isl_printer
*p
)
406 return p
->yaml_style
;
409 /* Push "state" onto the stack of currently active YAML elements and
410 * return the updated printer.
412 static __isl_give isl_printer
*push_state(__isl_take isl_printer
*p
,
413 enum isl_yaml_state state
)
418 if (p
->yaml_size
< p
->yaml_depth
+ 1) {
419 enum isl_yaml_state
*state
;
420 state
= isl_realloc_array(p
->ctx
, p
->yaml_state
,
421 enum isl_yaml_state
, p
->yaml_depth
+ 1);
423 return isl_printer_free(p
);
424 p
->yaml_state
= state
;
425 p
->yaml_size
= p
->yaml_depth
+ 1;
428 p
->yaml_state
[p
->yaml_depth
] = state
;
434 /* Remove the innermost active YAML element from the stack and
435 * return the updated printer.
437 static __isl_give isl_printer
*pop_state(__isl_take isl_printer
*p
)
445 /* Set the state of the innermost active YAML element to "state" and
446 * return the updated printer.
448 static __isl_give isl_printer
*update_state(__isl_take isl_printer
*p
,
449 enum isl_yaml_state state
)
453 if (p
->yaml_depth
< 1)
454 isl_die(isl_printer_get_ctx(p
), isl_error_invalid
,
455 "not in YAML construct", return isl_printer_free(p
));
457 p
->yaml_state
[p
->yaml_depth
- 1] = state
;
462 /* Return the state of the innermost active YAML element.
463 * Return isl_yaml_none if we are not inside any YAML element.
465 static enum isl_yaml_state
current_state(__isl_keep isl_printer
*p
)
468 return isl_yaml_none
;
469 if (p
->yaml_depth
< 1)
470 return isl_yaml_none
;
471 return p
->yaml_state
[p
->yaml_depth
- 1];
474 /* If we are printing a YAML document and we are at the start of an element,
475 * print whatever is needed before we can print the actual element and
476 * keep track of the fact that we are now printing the element.
477 * If "eol" is set, then whatever we print is going to be the last
478 * thing that gets printed on this line.
480 * If we are about the print the first key of a mapping, then nothing
481 * extra needs to be printed. For any other key, however, we need
482 * to either move to the next line (in block format) or print a comma
484 * Before printing a value in a mapping, we need to print a colon.
486 * For sequences, in flow format, we only need to print a comma
487 * for each element except the first.
488 * In block format, before the first element in the sequence,
489 * we move to a new line, print a dash and increase the indentation.
490 * Before any other element, we print a dash on a new line,
491 * temporarily moving the indentation back.
493 static __isl_give isl_printer
*enter_state(__isl_take isl_printer
*p
,
496 enum isl_yaml_state state
;
501 state
= current_state(p
);
502 if (state
== isl_yaml_mapping_val_start
) {
504 p
= p
->ops
->print_str(p
, ":");
506 p
= p
->ops
->print_str(p
, ": ");
507 p
= update_state(p
, isl_yaml_mapping_val
);
508 } else if (state
== isl_yaml_mapping_first_key_start
) {
509 p
= update_state(p
, isl_yaml_mapping_key
);
510 } else if (state
== isl_yaml_mapping_key_start
) {
511 if (p
->yaml_style
== ISL_YAML_STYLE_FLOW
)
512 p
= p
->ops
->print_str(p
, ", ");
514 p
= p
->ops
->end_line(p
);
515 p
= p
->ops
->start_line(p
);
517 p
= update_state(p
, isl_yaml_mapping_key
);
518 } else if (state
== isl_yaml_sequence_first_start
) {
519 if (p
->yaml_style
!= ISL_YAML_STYLE_FLOW
) {
520 p
= p
->ops
->end_line(p
);
521 p
= p
->ops
->start_line(p
);
522 p
= p
->ops
->print_str(p
, "- ");
523 p
= isl_printer_indent(p
, 2);
525 p
= update_state(p
, isl_yaml_sequence
);
526 } else if (state
== isl_yaml_sequence_start
) {
527 if (p
->yaml_style
== ISL_YAML_STYLE_FLOW
)
528 p
= p
->ops
->print_str(p
, ", ");
530 p
= p
->ops
->end_line(p
);
531 p
= isl_printer_indent(p
, -2);
532 p
= p
->ops
->start_line(p
);
533 p
= p
->ops
->print_str(p
, "- ");
534 p
= isl_printer_indent(p
, 2);
536 p
= update_state(p
, isl_yaml_sequence
);
542 __isl_give isl_printer
*isl_printer_print_str(__isl_take isl_printer
*p
,
548 return isl_printer_free(p
);
549 p
= enter_state(p
, 0);
552 return p
->ops
->print_str(p
, s
);
555 __isl_give isl_printer
*isl_printer_print_double(__isl_take isl_printer
*p
,
558 p
= enter_state(p
, 0);
562 return p
->ops
->print_double(p
, d
);
565 __isl_give isl_printer
*isl_printer_print_int(__isl_take isl_printer
*p
, int i
)
567 p
= enter_state(p
, 0);
571 return p
->ops
->print_int(p
, i
);
574 __isl_give isl_printer
*isl_printer_print_isl_int(__isl_take isl_printer
*p
,
577 p
= enter_state(p
, 0);
581 return p
->ops
->print_isl_int(p
, i
);
584 __isl_give isl_printer
*isl_printer_start_line(__isl_take isl_printer
*p
)
589 return p
->ops
->start_line(p
);
592 __isl_give isl_printer
*isl_printer_end_line(__isl_take isl_printer
*p
)
597 return p
->ops
->end_line(p
);
600 char *isl_printer_get_str(__isl_keep isl_printer
*printer
)
602 if (!printer
|| !printer
->buf
)
604 return strdup(printer
->buf
);
607 __isl_give isl_printer
*isl_printer_flush(__isl_take isl_printer
*p
)
612 return p
->ops
->flush(p
);
615 /* Start a YAML mapping and push a new state to reflect that we
616 * are about to print the first key in a mapping.
618 * In flow style, print the opening brace.
619 * In block style, move to the next line with an increased indentation,
620 * except if this is the outer mapping or if we are inside a sequence
621 * (in which case we have already increased the indentation and we want
622 * to print the first key on the same line as the dash).
624 __isl_give isl_printer
*isl_printer_yaml_start_mapping(
625 __isl_take isl_printer
*p
)
627 enum isl_yaml_state state
;
629 p
= enter_state(p
, p
->yaml_style
== ISL_YAML_STYLE_BLOCK
);
632 state
= current_state(p
);
633 if (p
->yaml_style
== ISL_YAML_STYLE_FLOW
)
634 p
= p
->ops
->print_str(p
, "{ ");
635 else if (state
!= isl_yaml_none
&& state
!= isl_yaml_sequence
) {
636 p
= p
->ops
->end_line(p
);
637 p
= isl_printer_indent(p
, 2);
638 p
= p
->ops
->start_line(p
);
640 p
= push_state(p
, isl_yaml_mapping_first_key_start
);
644 /* Finish a YAML mapping and pop it from the state stack.
646 * In flow style, print the closing brace.
648 * In block style, first check if we are still in the
649 * isl_yaml_mapping_first_key_start state. If so, we have not printed
650 * anything yet, so print "{}" to indicate an empty mapping.
651 * If we increased the indentation in isl_printer_yaml_start_mapping,
652 * then decrease it again.
653 * If this is the outer mapping then print a newline.
655 __isl_give isl_printer
*isl_printer_yaml_end_mapping(
656 __isl_take isl_printer
*p
)
658 enum isl_yaml_state state
;
660 state
= current_state(p
);
664 if (p
->yaml_style
== ISL_YAML_STYLE_FLOW
)
665 return p
->ops
->print_str(p
, " }");
666 if (state
== isl_yaml_mapping_first_key_start
)
667 p
= p
->ops
->print_str(p
, "{}");
670 state
= current_state(p
);
671 if (state
!= isl_yaml_none
&& state
!= isl_yaml_sequence
)
672 p
= isl_printer_indent(p
, -2);
673 if (state
== isl_yaml_none
)
674 p
= p
->ops
->end_line(p
);
678 /* Start a YAML sequence and push a new state to reflect that we
679 * are about to print the first element in a sequence.
681 * In flow style, print the opening bracket.
683 __isl_give isl_printer
*isl_printer_yaml_start_sequence(
684 __isl_take isl_printer
*p
)
686 p
= enter_state(p
, p
->yaml_style
== ISL_YAML_STYLE_BLOCK
);
687 p
= push_state(p
, isl_yaml_sequence_first_start
);
690 if (p
->yaml_style
== ISL_YAML_STYLE_FLOW
)
691 p
= p
->ops
->print_str(p
, "[ ");
695 /* Finish a YAML sequence and pop it from the state stack.
697 * In flow style, print the closing bracket.
699 * In block style, check if we are still in the
700 * isl_yaml_sequence_first_start state. If so, we have not printed
701 * anything yet, so print "[]" or " []" to indicate an empty sequence.
702 * We print the extra space when we instructed enter_state not
703 * to print a space at the end of the line.
704 * Otherwise, undo the increase in indentation performed by
705 * enter_state when moving away from the isl_yaml_sequence_first_start
707 * If this is the outer sequence then print a newline.
709 __isl_give isl_printer
*isl_printer_yaml_end_sequence(
710 __isl_take isl_printer
*p
)
712 enum isl_yaml_state state
, up
;
714 state
= current_state(p
);
718 if (p
->yaml_style
== ISL_YAML_STYLE_FLOW
)
719 return p
->ops
->print_str(p
, " ]");
720 up
= current_state(p
);
721 if (state
== isl_yaml_sequence_first_start
) {
722 if (up
== isl_yaml_mapping_val
)
723 p
= p
->ops
->print_str(p
, " []");
725 p
= p
->ops
->print_str(p
, "[]");
727 p
= isl_printer_indent(p
, -2);
731 state
= current_state(p
);
732 if (state
== isl_yaml_none
)
733 p
= p
->ops
->end_line(p
);
737 /* Mark the fact that the current element is finished and that
738 * the next output belongs to the next element.
739 * In particular, if we are printing a key, then prepare for
740 * printing the subsequent value. If we are printing a value,
741 * prepare for printing the next key. If we are printing an
742 * element in a sequence, prepare for printing the next element.
744 __isl_give isl_printer
*isl_printer_yaml_next(__isl_take isl_printer
*p
)
746 enum isl_yaml_state state
;
750 if (p
->yaml_depth
< 1)
751 isl_die(isl_printer_get_ctx(p
), isl_error_invalid
,
752 "not in YAML construct", return isl_printer_free(p
));
754 state
= current_state(p
);
755 if (state
== isl_yaml_mapping_key
)
756 state
= isl_yaml_mapping_val_start
;
757 else if (state
== isl_yaml_mapping_val
)
758 state
= isl_yaml_mapping_key_start
;
759 else if (state
== isl_yaml_sequence
)
760 state
= isl_yaml_sequence_start
;
761 p
= update_state(p
, state
);