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_id_to_id_free(p
->notes
);
276 isl_ctx_deref(p
->ctx
);
282 isl_ctx
*isl_printer_get_ctx(__isl_keep isl_printer
*printer
)
284 return printer
? printer
->ctx
: NULL
;
287 FILE *isl_printer_get_file(__isl_keep isl_printer
*printer
)
292 isl_die(isl_printer_get_ctx(printer
), isl_error_invalid
,
293 "not a file printer", return NULL
);
294 return printer
->file
;
297 __isl_give isl_printer
*isl_printer_set_isl_int_width(__isl_take isl_printer
*p
,
308 __isl_give isl_printer
*isl_printer_set_indent(__isl_take isl_printer
*p
,
319 __isl_give isl_printer
*isl_printer_indent(__isl_take isl_printer
*p
,
332 /* Replace the indent prefix of "p" by "prefix".
334 __isl_give isl_printer
*isl_printer_set_indent_prefix(__isl_take isl_printer
*p
,
340 free(p
->indent_prefix
);
341 p
->indent_prefix
= prefix
? strdup(prefix
) : NULL
;
346 __isl_give isl_printer
*isl_printer_set_prefix(__isl_take isl_printer
*p
,
353 p
->prefix
= prefix
? strdup(prefix
) : NULL
;
358 __isl_give isl_printer
*isl_printer_set_suffix(__isl_take isl_printer
*p
,
365 p
->suffix
= suffix
? strdup(suffix
) : NULL
;
370 __isl_give isl_printer
*isl_printer_set_output_format(__isl_take isl_printer
*p
,
376 p
->output_format
= output_format
;
381 int isl_printer_get_output_format(__isl_keep isl_printer
*p
)
385 return p
->output_format
;
388 /* Does "p" have a note with identifier "id"?
390 isl_bool
isl_printer_has_note(__isl_keep isl_printer
*p
,
391 __isl_keep isl_id
*id
)
394 return isl_bool_error
;
396 return isl_bool_false
;
397 return isl_id_to_id_has(p
->notes
, id
);
400 /* Retrieve the note identified by "id" from "p".
401 * The note is assumed to exist.
403 __isl_give isl_id
*isl_printer_get_note(__isl_keep isl_printer
*p
,
404 __isl_take isl_id
*id
)
408 has_note
= isl_printer_has_note(p
, id
);
412 isl_die(isl_printer_get_ctx(p
), isl_error_invalid
,
413 "no such note", goto error
);
415 return isl_id_to_id_get(p
->notes
, id
);
421 /* Associate "note" to the identifier "id" in "p",
422 * replacing the previous note associated to the identifier, if any.
424 __isl_give isl_printer
*isl_printer_set_note(__isl_take isl_printer
*p
,
425 __isl_take isl_id
*id
, __isl_take isl_id
*note
)
427 if (!p
|| !id
|| !note
)
430 p
->notes
= isl_id_to_id_alloc(isl_printer_get_ctx(p
), 1);
434 p
->notes
= isl_id_to_id_set(p
->notes
, id
, note
);
436 return isl_printer_free(p
);
445 /* Keep track of whether the printing to "p" is being performed from
446 * an isl_*_dump function as specified by "dump".
448 __isl_give isl_printer
*isl_printer_set_dump(__isl_take isl_printer
*p
,
459 /* Set the YAML style of "p" to "yaml_style" and return the updated printer.
461 __isl_give isl_printer
*isl_printer_set_yaml_style(__isl_take isl_printer
*p
,
467 p
->yaml_style
= yaml_style
;
472 /* Return the YAML style of "p" or -1 on error.
474 int isl_printer_get_yaml_style(__isl_keep isl_printer
*p
)
478 return p
->yaml_style
;
481 /* Push "state" onto the stack of currently active YAML elements and
482 * return the updated printer.
484 static __isl_give isl_printer
*push_state(__isl_take isl_printer
*p
,
485 enum isl_yaml_state state
)
490 if (p
->yaml_size
< p
->yaml_depth
+ 1) {
491 enum isl_yaml_state
*state
;
492 state
= isl_realloc_array(p
->ctx
, p
->yaml_state
,
493 enum isl_yaml_state
, p
->yaml_depth
+ 1);
495 return isl_printer_free(p
);
496 p
->yaml_state
= state
;
497 p
->yaml_size
= p
->yaml_depth
+ 1;
500 p
->yaml_state
[p
->yaml_depth
] = state
;
506 /* Remove the innermost active YAML element from the stack and
507 * return the updated printer.
509 static __isl_give isl_printer
*pop_state(__isl_take isl_printer
*p
)
517 /* Set the state of the innermost active YAML element to "state" and
518 * return the updated printer.
520 static __isl_give isl_printer
*update_state(__isl_take isl_printer
*p
,
521 enum isl_yaml_state state
)
525 if (p
->yaml_depth
< 1)
526 isl_die(isl_printer_get_ctx(p
), isl_error_invalid
,
527 "not in YAML construct", return isl_printer_free(p
));
529 p
->yaml_state
[p
->yaml_depth
- 1] = state
;
534 /* Return the state of the innermost active YAML element.
535 * Return isl_yaml_none if we are not inside any YAML element.
537 static enum isl_yaml_state
current_state(__isl_keep isl_printer
*p
)
540 return isl_yaml_none
;
541 if (p
->yaml_depth
< 1)
542 return isl_yaml_none
;
543 return p
->yaml_state
[p
->yaml_depth
- 1];
546 /* If we are printing a YAML document and we are at the start of an element,
547 * print whatever is needed before we can print the actual element and
548 * keep track of the fact that we are now printing the element.
549 * If "eol" is set, then whatever we print is going to be the last
550 * thing that gets printed on this line.
552 * If we are about the print the first key of a mapping, then nothing
553 * extra needs to be printed. For any other key, however, we need
554 * to either move to the next line (in block format) or print a comma
556 * Before printing a value in a mapping, we need to print a colon.
558 * For sequences, in flow format, we only need to print a comma
559 * for each element except the first.
560 * In block format, before the first element in the sequence,
561 * we move to a new line, print a dash and increase the indentation.
562 * Before any other element, we print a dash on a new line,
563 * temporarily moving the indentation back.
565 static __isl_give isl_printer
*enter_state(__isl_take isl_printer
*p
,
568 enum isl_yaml_state state
;
573 state
= current_state(p
);
574 if (state
== isl_yaml_mapping_val_start
) {
576 p
= p
->ops
->print_str(p
, ":");
578 p
= p
->ops
->print_str(p
, ": ");
579 p
= update_state(p
, isl_yaml_mapping_val
);
580 } else if (state
== isl_yaml_mapping_first_key_start
) {
581 p
= update_state(p
, isl_yaml_mapping_key
);
582 } else if (state
== isl_yaml_mapping_key_start
) {
583 if (p
->yaml_style
== ISL_YAML_STYLE_FLOW
)
584 p
= p
->ops
->print_str(p
, ", ");
586 p
= p
->ops
->end_line(p
);
587 p
= p
->ops
->start_line(p
);
589 p
= update_state(p
, isl_yaml_mapping_key
);
590 } else if (state
== isl_yaml_sequence_first_start
) {
591 if (p
->yaml_style
!= ISL_YAML_STYLE_FLOW
) {
592 p
= p
->ops
->end_line(p
);
593 p
= p
->ops
->start_line(p
);
594 p
= p
->ops
->print_str(p
, "- ");
595 p
= isl_printer_indent(p
, 2);
597 p
= update_state(p
, isl_yaml_sequence
);
598 } else if (state
== isl_yaml_sequence_start
) {
599 if (p
->yaml_style
== ISL_YAML_STYLE_FLOW
)
600 p
= p
->ops
->print_str(p
, ", ");
602 p
= p
->ops
->end_line(p
);
603 p
= isl_printer_indent(p
, -2);
604 p
= p
->ops
->start_line(p
);
605 p
= p
->ops
->print_str(p
, "- ");
606 p
= isl_printer_indent(p
, 2);
608 p
= update_state(p
, isl_yaml_sequence
);
614 __isl_give isl_printer
*isl_printer_print_str(__isl_take isl_printer
*p
,
620 return isl_printer_free(p
);
621 p
= enter_state(p
, 0);
624 return p
->ops
->print_str(p
, s
);
627 __isl_give isl_printer
*isl_printer_print_double(__isl_take isl_printer
*p
,
630 p
= enter_state(p
, 0);
634 return p
->ops
->print_double(p
, d
);
637 __isl_give isl_printer
*isl_printer_print_int(__isl_take isl_printer
*p
, int i
)
639 p
= enter_state(p
, 0);
643 return p
->ops
->print_int(p
, i
);
646 __isl_give isl_printer
*isl_printer_print_isl_int(__isl_take isl_printer
*p
,
649 p
= enter_state(p
, 0);
653 return p
->ops
->print_isl_int(p
, i
);
656 __isl_give isl_printer
*isl_printer_start_line(__isl_take isl_printer
*p
)
661 return p
->ops
->start_line(p
);
664 __isl_give isl_printer
*isl_printer_end_line(__isl_take isl_printer
*p
)
669 return p
->ops
->end_line(p
);
672 char *isl_printer_get_str(__isl_keep isl_printer
*printer
)
674 if (!printer
|| !printer
->buf
)
676 return strdup(printer
->buf
);
679 __isl_give isl_printer
*isl_printer_flush(__isl_take isl_printer
*p
)
684 return p
->ops
->flush(p
);
687 /* Start a YAML mapping and push a new state to reflect that we
688 * are about to print the first key in a mapping.
690 * In flow style, print the opening brace.
691 * In block style, move to the next line with an increased indentation,
692 * except if this is the outer mapping or if we are inside a sequence
693 * (in which case we have already increased the indentation and we want
694 * to print the first key on the same line as the dash).
696 __isl_give isl_printer
*isl_printer_yaml_start_mapping(
697 __isl_take isl_printer
*p
)
699 enum isl_yaml_state state
;
701 p
= enter_state(p
, p
->yaml_style
== ISL_YAML_STYLE_BLOCK
);
704 state
= current_state(p
);
705 if (p
->yaml_style
== ISL_YAML_STYLE_FLOW
)
706 p
= p
->ops
->print_str(p
, "{ ");
707 else if (state
!= isl_yaml_none
&& state
!= isl_yaml_sequence
) {
708 p
= p
->ops
->end_line(p
);
709 p
= isl_printer_indent(p
, 2);
710 p
= p
->ops
->start_line(p
);
712 p
= push_state(p
, isl_yaml_mapping_first_key_start
);
716 /* Finish a YAML mapping and pop it from the state stack.
718 * In flow style, print the closing brace.
720 * In block style, first check if we are still in the
721 * isl_yaml_mapping_first_key_start state. If so, we have not printed
722 * anything yet, so print "{}" to indicate an empty mapping.
723 * If we increased the indentation in isl_printer_yaml_start_mapping,
724 * then decrease it again.
725 * If this is the outer mapping then print a newline.
727 __isl_give isl_printer
*isl_printer_yaml_end_mapping(
728 __isl_take isl_printer
*p
)
730 enum isl_yaml_state state
;
732 state
= current_state(p
);
736 if (p
->yaml_style
== ISL_YAML_STYLE_FLOW
)
737 return p
->ops
->print_str(p
, " }");
738 if (state
== isl_yaml_mapping_first_key_start
)
739 p
= p
->ops
->print_str(p
, "{}");
742 state
= current_state(p
);
743 if (state
!= isl_yaml_none
&& state
!= isl_yaml_sequence
)
744 p
= isl_printer_indent(p
, -2);
745 if (state
== isl_yaml_none
)
746 p
= p
->ops
->end_line(p
);
750 /* Start a YAML sequence and push a new state to reflect that we
751 * are about to print the first element in a sequence.
753 * In flow style, print the opening bracket.
755 __isl_give isl_printer
*isl_printer_yaml_start_sequence(
756 __isl_take isl_printer
*p
)
760 p
= enter_state(p
, p
->yaml_style
== ISL_YAML_STYLE_BLOCK
);
761 p
= push_state(p
, isl_yaml_sequence_first_start
);
764 if (p
->yaml_style
== ISL_YAML_STYLE_FLOW
)
765 p
= p
->ops
->print_str(p
, "[ ");
769 /* Finish a YAML sequence and pop it from the state stack.
771 * In flow style, print the closing bracket.
773 * In block style, check if we are still in the
774 * isl_yaml_sequence_first_start state. If so, we have not printed
775 * anything yet, so print "[]" or " []" to indicate an empty sequence.
776 * We print the extra space when we instructed enter_state not
777 * to print a space at the end of the line.
778 * Otherwise, undo the increase in indentation performed by
779 * enter_state when moving away from the isl_yaml_sequence_first_start
781 * If this is the outer sequence then print a newline.
783 __isl_give isl_printer
*isl_printer_yaml_end_sequence(
784 __isl_take isl_printer
*p
)
786 enum isl_yaml_state state
, up
;
788 state
= current_state(p
);
792 if (p
->yaml_style
== ISL_YAML_STYLE_FLOW
)
793 return p
->ops
->print_str(p
, " ]");
794 up
= current_state(p
);
795 if (state
== isl_yaml_sequence_first_start
) {
796 if (up
== isl_yaml_mapping_val
)
797 p
= p
->ops
->print_str(p
, " []");
799 p
= p
->ops
->print_str(p
, "[]");
801 p
= isl_printer_indent(p
, -2);
805 state
= current_state(p
);
806 if (state
== isl_yaml_none
)
807 p
= p
->ops
->end_line(p
);
811 /* Mark the fact that the current element is finished and that
812 * the next output belongs to the next element.
813 * In particular, if we are printing a key, then prepare for
814 * printing the subsequent value. If we are printing a value,
815 * prepare for printing the next key. If we are printing an
816 * element in a sequence, prepare for printing the next element.
818 __isl_give isl_printer
*isl_printer_yaml_next(__isl_take isl_printer
*p
)
820 enum isl_yaml_state state
;
824 if (p
->yaml_depth
< 1)
825 isl_die(isl_printer_get_ctx(p
), isl_error_invalid
,
826 "not in YAML construct", return isl_printer_free(p
));
828 state
= current_state(p
);
829 if (state
== isl_yaml_mapping_key
)
830 state
= isl_yaml_mapping_val_start
;
831 else if (state
== isl_yaml_mapping_val
)
832 state
= isl_yaml_mapping_key_start
;
833 else if (state
== isl_yaml_sequence
)
834 state
= isl_yaml_sequence_start
;
835 p
= update_state(p
, state
);