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 | |
7 | static __isl_give isl_printer *file_start_line(__isl_take isl_printer *p) |
8 | { |
9 | fprintf(stream: p->file, format: "%s%*s%s" , p->indent_prefix ? p->indent_prefix : "" , |
10 | p->indent, "" , p->prefix ? p->prefix : "" ); |
11 | return p; |
12 | } |
13 | |
14 | static __isl_give isl_printer *file_end_line(__isl_take isl_printer *p) |
15 | { |
16 | fprintf(stream: p->file, format: "%s\n" , p->suffix ? p->suffix : "" ); |
17 | return p; |
18 | } |
19 | |
20 | static __isl_give isl_printer *file_flush(__isl_take isl_printer *p) |
21 | { |
22 | fflush(stream: p->file); |
23 | return p; |
24 | } |
25 | |
26 | static __isl_give isl_printer *file_print_str(__isl_take isl_printer *p, |
27 | const char *s) |
28 | { |
29 | fprintf(stream: p->file, format: "%s" , s); |
30 | return p; |
31 | } |
32 | |
33 | static __isl_give isl_printer *file_print_double(__isl_take isl_printer *p, |
34 | double d) |
35 | { |
36 | fprintf(stream: p->file, format: "%g" , d); |
37 | return p; |
38 | } |
39 | |
40 | static __isl_give isl_printer *file_print_int(__isl_take isl_printer *p, int i) |
41 | { |
42 | fprintf(stream: p->file, format: "%d" , i); |
43 | return p; |
44 | } |
45 | |
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 | |
52 | static int grow_buf(__isl_keep isl_printer *p, int ) |
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 | |
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, extra: len)) |
76 | goto error; |
77 | memcpy(dest: p->buf + p->buf_n, src: s, n: len); |
78 | p->buf_n += len; |
79 | |
80 | p->buf[p->buf_n] = '\0'; |
81 | return p; |
82 | error: |
83 | isl_printer_free(printer: p); |
84 | return NULL; |
85 | } |
86 | |
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, extra: 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(printer: p); |
100 | return NULL; |
101 | } |
102 | |
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, s: p->indent_prefix, len: strlen(s: p->indent_prefix)); |
107 | p = str_print_indent(p, indent: p->indent); |
108 | if (p->prefix) |
109 | p = str_print(p, s: p->prefix, len: strlen(s: p->prefix)); |
110 | return p; |
111 | } |
112 | |
113 | static __isl_give isl_printer *str_end_line(__isl_take isl_printer *p) |
114 | { |
115 | if (p->suffix) |
116 | p = str_print(p, s: p->suffix, len: strlen(s: p->suffix)); |
117 | p = str_print(p, s: "\n" , len: strlen(s: "\n" )); |
118 | return p; |
119 | } |
120 | |
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 | |
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, len: strlen(s: s)); |
132 | } |
133 | |
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(s: p->buf + p->buf_n, maxlen: left, format: "%g" , d); |
139 | if (need >= left) { |
140 | if (grow_buf(p, extra: need)) |
141 | goto error; |
142 | left = p->buf_size - p->buf_n; |
143 | need = snprintf(s: p->buf + p->buf_n, maxlen: left, format: "%g" , d); |
144 | } |
145 | p->buf_n += need; |
146 | return p; |
147 | error: |
148 | isl_printer_free(printer: p); |
149 | return NULL; |
150 | } |
151 | |
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(s: p->buf + p->buf_n, maxlen: left, format: "%d" , i); |
156 | if (need >= left) { |
157 | if (grow_buf(p, extra: need)) |
158 | goto error; |
159 | left = p->buf_size - p->buf_n; |
160 | need = snprintf(s: p->buf + p->buf_n, maxlen: left, format: "%d" , i); |
161 | } |
162 | p->buf_n += need; |
163 | return p; |
164 | error: |
165 | isl_printer_free(printer: p); |
166 | return NULL; |
167 | } |
168 | |
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: s); |
177 | if (len < p->width) |
178 | p = str_print_indent(p, indent: 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 | |
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(ctx: 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 | |
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(ctx: 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(printer: p); |
266 | return NULL; |
267 | } |
268 | |
269 | __isl_null isl_printer *isl_printer_free(__isl_take isl_printer *p) |
270 | { |
271 | if (!p) |
272 | return NULL; |
273 | free(ptr: p->buf); |
274 | free(ptr: p->indent_prefix); |
275 | free(ptr: p->prefix); |
276 | free(ptr: p->suffix); |
277 | free(ptr: p->yaml_state); |
278 | isl_id_to_id_free(hmap: p->notes); |
279 | isl_ctx_deref(ctx: p->ctx); |
280 | free(ptr: p); |
281 | |
282 | return NULL; |
283 | } |
284 | |
285 | isl_ctx *isl_printer_get_ctx(__isl_keep isl_printer *printer) |
286 | { |
287 | return printer ? printer->ctx : NULL; |
288 | } |
289 | |
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 | |
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 | |
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 | |
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 | */ |
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(ptr: p->indent_prefix); |
344 | p->indent_prefix = prefix ? strdup(s: prefix) : NULL; |
345 | |
346 | return p; |
347 | } |
348 | |
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(ptr: p->prefix); |
356 | p->prefix = prefix ? strdup(s: prefix) : NULL; |
357 | |
358 | return p; |
359 | } |
360 | |
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(ptr: p->suffix); |
368 | p->suffix = suffix ? strdup(s: suffix) : NULL; |
369 | |
370 | return p; |
371 | } |
372 | |
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 | |
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 | */ |
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(hmap: p->notes, key: id); |
401 | } |
402 | |
403 | /* Retrieve the note identified by "id" from "p". |
404 | * The note is assumed to exist. |
405 | */ |
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(hmap: p->notes, key: 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 | */ |
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(ctx: isl_printer_get_ctx(printer: p), min_size: 1); |
434 | if (!p->notes) |
435 | goto error; |
436 | } |
437 | p->notes = isl_id_to_id_set(hmap: p->notes, key: id, val: 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(id: 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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
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 | */ |
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, state: isl_yaml_mapping_val); |
583 | } else if (state == isl_yaml_mapping_first_key_start) { |
584 | p = update_state(p, state: 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, state: 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, indent: 2); |
599 | } |
600 | p = update_state(p, state: 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, indent: -2); |
607 | p = p->ops->start_line(p); |
608 | p = p->ops->print_str(p, "- " ); |
609 | p = isl_printer_indent(p, indent: 2); |
610 | } |
611 | p = update_state(p, state: isl_yaml_sequence); |
612 | } |
613 | |
614 | return p; |
615 | } |
616 | |
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, eol: 0); |
625 | if (!p) |
626 | return NULL; |
627 | return p->ops->print_str(p, s); |
628 | } |
629 | |
630 | __isl_give isl_printer *isl_printer_print_double(__isl_take isl_printer *p, |
631 | double d) |
632 | { |
633 | p = enter_state(p, eol: 0); |
634 | if (!p) |
635 | return NULL; |
636 | |
637 | return p->ops->print_double(p, d); |
638 | } |
639 | |
640 | __isl_give isl_printer *isl_printer_print_int(__isl_take isl_printer *p, int i) |
641 | { |
642 | p = enter_state(p, eol: 0); |
643 | if (!p) |
644 | return NULL; |
645 | |
646 | return p->ops->print_int(p, i); |
647 | } |
648 | |
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, eol: 0); |
653 | if (!p) |
654 | return NULL; |
655 | |
656 | return p->ops->print_isl_int(p, i); |
657 | } |
658 | |
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 | |
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 | */ |
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(s: printer->buf); |
688 | } |
689 | |
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 | */ |
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, eol: 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, indent: 2); |
723 | p = p->ops->start_line(p); |
724 | } |
725 | p = push_state(p, state: 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 | */ |
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, indent: -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 | */ |
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, eol: p->yaml_style == ISL_YAML_STYLE_BLOCK); |
774 | p = push_state(p, state: 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 | */ |
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, indent: -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 | */ |
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 | |