Added %> for indenting
[libfirm] / ir / ir / irprintf.c
1 /*
2  * Project:     libFIRM
3  * File name:   ir/ir/irprintf.c
4  * Purpose:     A little printf helper unterstanding firm types
5  * Author:      Sebastian Hack
6  * Created:     29.11.2004
7  * CVS-ID:      $Id$
8  * Copyright:   (c) 1998-2004 Universität Karlsruhe
9  * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
10  */
11
12 /**
13  * @file irprinf.c
14  *
15  * A little printf helper unterstanding firm types.
16  * @author Sebastian Hack
17  * @date 29.11.2004
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #ifdef HAVE_STRING_H
25 #include <string.h>
26 #endif
27 #ifdef HAVE_INTTYPES_H
28 #include <inttypes.h>
29 #endif
30
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <stdarg.h>
34
35 #include <ctype.h>
36
37 #include "ident.h"
38 #include "irmode_t.h"
39 #include "irnode_t.h"
40 #include "entity_t.h"
41 #include "type_t.h"
42 #include "tv.h"
43 #include "irprintf.h"
44 #include "obst.h"
45 #include "pset.h"
46 #include "iterator.h"
47 #include "bitset.h"
48
49 #define STRNIL "(nil)"
50
51 /**
52  * Init the string.
53  */
54 static void str_init(void *object, size_t n)
55 {
56         strcpy(object, "");
57 }
58
59 /**
60  * append a char to a string buffer.
61  */
62 static void str_append_char(void *object, size_t n, char ch)
63 {
64         char buf[2];
65
66         buf[0] = ch;
67         buf[1] = 0;
68
69         strncat(object, buf, n);
70 }
71
72 /**
73  * append a string to a string buffer.
74  */
75 static void str_append_str(void *object, size_t n, const char *str)
76 {
77         strncat(object, str, n);
78 }
79
80
81 /**
82  * Init the file. i.e. do nothing.
83  */
84 static void file_init(void *object, size_t n)
85 {
86 }
87
88 /**
89  * append a char to a file.
90  */
91 static void file_append_char(void *object, size_t n, char ch)
92 {
93         fputc(ch, object);
94 }
95
96 /**
97  * append a string to a file.
98  */
99 static void file_append_str(void *object, size_t n, const char *str)
100 {
101         fputs(str, object);
102 }
103
104 /**
105  * Init the obstack. i.e. do nothing.
106  */
107 static void obst_init(void *object, size_t n)
108 {
109 }
110
111 /**
112  * append a char to a obstack.
113  */
114 static void obst_append_char(void *object, size_t n, char ch)
115 {
116         struct obstack *obst = object;
117         obstack_1grow(obst, ch);
118 }
119
120 /**
121  * append a string to a obstack.
122  */
123 static void obst_append_str(void *object, size_t n, const char *str)
124 {
125         struct obstack *obst = object;
126         obstack_grow(obst, str, strlen(str));
127 }
128
129
130 /**
131  * the file appender
132  */
133 static const appender_t file_appender = {
134         file_init,
135         file_append_char,
136         file_append_str
137 };
138
139 /**
140  * the string buffer appender
141  */
142 static const appender_t str_appender = {
143         str_init,
144         str_append_char,
145         str_append_str
146 };
147
148 /**
149  * the obstack appender.
150  */
151 static const appender_t obst_appender = {
152         obst_init,
153         obst_append_char,
154         obst_append_str
155 };
156
157 static void ir_common_vprintf(const appender_t *app, void *object,
158                 size_t limit, const char *fmt, va_list args);
159
160 static INLINE void ir_common_printf(const appender_t *app, void *object,
161                 size_t limit, const char *fmt, ...)
162 {
163         va_list args;
164
165         va_start(args, fmt);
166         ir_common_vprintf(app, object, limit, fmt, args);
167         va_end(args);
168 }
169
170 #if 0
171 static int is_std_fmt(const char *fmt)
172 {
173         static const char *fmt_re_str =
174                 "^[0 -+#']?[1-9]*(\\.[1-9]*)?[hlLqjzt]?[diouxXeEfFgGaAc]";
175
176         static regex_t fmt_re;
177         static int preapred_re = 0;
178
179         regmatch_t match[1];
180         int res;
181
182         if(!preapred_re) {
183                 int res = regcomp(&fmt_re, fmt_re_str, REG_EXTENDED);
184                 assert(res == 0 && "Could not prepare regex");
185                 preapred_re = 1;
186         }
187
188         res = regexec(&fmt_re, fmt, 1, &match[0], 0);
189
190 #if 0
191         if(res != 0) {
192                 char buf[256];
193                 regerror(res, &fmt_re, buf, sizeof(buf));
194                 printf("%s ", buf);
195         }
196
197         printf("res: %d, start: %d, end: %d\n",
198                         res, match[0].rm_so, match[0].rm_eo);
199 #endif
200
201         return res == 0 ? match[0].rm_eo : -1;
202 }
203 #endif
204
205 struct settings {
206         char pad;
207         int width;
208         int left_just;
209         int put_plus;
210         int alternate;
211 };
212
213 /* Length specifiers. */
214 enum {
215         len_char,
216         len_short,
217         len_int,
218         len_long,
219         len_long_long
220 };
221
222
223 #define MIN(x,y) ((x) < (y) ? (x) : (y))
224 #define MAX(x,y) ((x) > (y) ? (x) : (y))
225
226 static void dump_with_settings(const appender_t *app, void *object, size_t limit,
227                 const struct settings *settings, const char *str)
228 {
229         if(settings->width >= 0) {
230                 int i;
231                 size_t n = strlen(str);
232                 int lim = MIN(settings->width, (int)limit);
233                 int to_print = MIN(lim, (int)n);
234                 int to_pad = to_print - lim;
235
236                 if(!settings->left_just)
237                         for(i = 0; i < to_pad; ++i)
238                                 app->append_char(object, lim, settings->pad);
239
240                 app->append_str(object, to_print, str);
241
242                 if(!settings->left_just)
243                         for(i = 0; i < to_pad; ++i)
244                                 app->append_char(object, lim, settings->pad);
245         }
246
247         else
248                 app->append_str(object, limit, str);
249 }
250
251
252 /**
253  * A small printf helper routine for ir nodes.
254  * @param app An appender (this determines where the stuff is dumped
255  * to).
256  * @param object A target passed to the appender.
257  * @param limit The maximum number of characters to dump.
258  * @param fmt The format string.
259  * @param args A va_list.
260  */
261 static void ir_common_vprintf(const appender_t *app, void *object,
262                 size_t limit, const char *fmt, va_list args)
263 {
264         const char *str;
265         char buf[4096];
266         int i, n;
267
268 #define DUMP_STR(s) app->append_str(object, limit, s)
269 #define DUMP_CH(ch) app->append_char(object, limit, ch)
270
271         app->init(object, limit);
272
273         for(i = 0, n = strlen(fmt); i < n; ++i) {
274                 char ch = fmt[i];
275
276                 if(ch == '%') {
277                         int len;
278                         const char *len_str = "";
279
280                         struct settings settings;
281
282                         settings.alternate = 0;
283                         settings.pad = ' ';
284                         settings.width = -1;
285                         settings.left_just = 0;
286                         settings.put_plus = 0;
287
288                         ch = fmt[++i];
289
290                         /* Clear the temporary buffer */
291                         buf[0] = '\0';
292
293                         /* Set the string to print to the buffer by default. */
294                         str = buf;
295
296                         while(strchr("#0-+", ch)) {
297                                 switch(ch) {
298                                         case '#':
299                                                 settings.alternate = 1;
300                                                 break;
301                                         case '0':
302                                                 settings.pad = '0';
303                                                 break;
304                                         case '-':
305                                                 settings.left_just = 1;
306                                                 break;
307                                         case '+':
308                                                 settings.put_plus = 1;
309                                                 break;
310                                 }
311
312                                 ch = fmt[++i];
313                         }
314
315
316                         /* Read the field width */
317                         {
318                                 char *endptr;
319                                 int increase;
320
321                                 settings.width = (int) strtol(&fmt[i], &endptr, 10);
322                                 increase = (char *) endptr - &fmt[i];
323                                 ch = fmt[i += increase];
324                                 if(increase == 0)
325                                         settings.width = -1;
326                         }
327
328                         /* Ignore the precision */
329                         if(ch == '.')
330                                 while(isdigit(ch = fmt[++i]));
331
332                         /* read the length modifier. */
333                         switch(ch) {
334                                 case 'h':
335                                         len_str = "h";
336                                         len = len_short;
337                                         if((ch = fmt[++i]) == 'h') {
338                                                 len_str = "hh";
339                                                 len = len_char;
340                                         }
341                                         break;
342
343                                 case 'l':
344                                         len_str = "l";
345                                         len = len_long;
346                                         if((ch = fmt[++i]) == 'l') {
347                                                 len_str = "ll";
348                                                 len = len_long_long;
349                                         }
350                                         break;
351
352                                 default:
353                                         len = len_int;
354                         }
355
356                         /* Do the conversion specifier. */
357                         switch(ch) {
358
359                                 /* The percent itself */
360                                 case '%':
361                                         buf[0] = '%';
362                                         buf[1] = '\0';
363                                         break;
364
365                                 /* Indent */
366                                 case '>':
367                                         {
368                                                 int i, n = va_arg(args, int);
369                                                 for(i = 0; i < n && i < sizeof(buf) - 1; ++i)
370                                                         buf[i] = ' ';
371
372                                                 buf[i] = '\0';
373                                         }
374                                         break;
375
376                                 case 'c':
377                                         buf[0] = va_arg(args, int);
378                                         buf[1] = '\0';
379                                         break;
380
381                                 case 's':
382                                         str = va_arg(args, const char *);
383                                         break;
384
385                                 case 'p':
386                                         snprintf(buf, sizeof(buf), "%p", va_arg(args, void *));
387                                         break;
388
389                                 case 'd':
390                                 case 'x':
391                                 case 'X':
392                                 case 'o':
393                                         {
394                                                 char fmt_str[16];
395                                                 snprintf(fmt_str, sizeof(fmt_str), "%%%s%c", len_str, ch);
396
397                                                 switch(len) {
398                                                         case len_char:
399                                                         case len_short:
400                                                         case len_int:
401                                                                 {
402                                                                         int arg = va_arg(args, int);
403                                                                         snprintf(buf, sizeof(buf), fmt_str, arg);
404                                                                 }
405                                                                 break;
406
407                                                         case len_long:
408                                                                 {
409                                                                         long arg = va_arg(args, long);
410                                                                         snprintf(buf, sizeof(buf), fmt_str, arg);
411                                                                 }
412                                                                 break;
413
414                                                         case len_long_long:
415                                                                 {
416                                                                         int64_t arg = va_arg(args, int64_t);
417                                                                         snprintf(buf, sizeof(buf), fmt_str, arg);
418                                                                 }
419                                                                 break;
420                                                 }
421                                         }
422                                         break;
423
424                                 case 'I':
425                                         str = get_id_str(va_arg(args, ident *));
426                                         break;
427
428                                 case 't':
429                                         str = get_type_name(va_arg(args, type *));
430                                         break;
431
432                                 case 'e':
433                                         str = get_entity_name(va_arg(args, entity *));
434                                         break;
435
436                                 case 'E':
437                                         str = get_entity_ld_name(va_arg(args, entity *));
438                                         break;
439
440                                 case 'T':
441                                         tarval_snprintf(buf, sizeof(buf), va_arg(args, tarval *));
442                                         break;
443
444                                 case 'n':
445                                         {
446                                                 ir_node *irn = va_arg(args, ir_node *);
447                                                 if(irn)
448                                                         snprintf(buf, sizeof(buf), "%s%s:%ld",
449                                                                         get_irn_opname(irn), get_mode_name(get_irn_mode(irn)), get_irn_node_nr(irn));
450                                                 else
451                                                         strncpy(buf, STRNIL, sizeof(buf));
452                                         }
453                                         break;
454
455                                 case 'O':
456                                         str = get_irn_opname(va_arg(args, ir_node *));
457                                         break;
458
459                                 case 'N':
460                                         snprintf(buf, sizeof(buf), "%ld", get_irn_node_nr(va_arg(args, ir_node *)));
461                                         break;
462
463                                 case 'm':
464                                         str = get_mode_name(va_arg(args, ir_mode *));
465                                         break;
466
467                                 case 'B':
468                                         snprintf(buf, sizeof(buf), "%ld",
469                                                         get_irn_node_nr(get_nodes_block(va_arg(args, ir_node *))));
470                                         break;
471
472                                 case 'b':
473                                         {
474                                                 const bitset_t *bs = va_arg(args, const bitset_t *);
475                                                 const char *prefix = "";
476                                                 unsigned long i;
477
478                                                 DUMP_CH('[');
479                                                 for(i = bitset_next_set(bs, 0); i != -1; i = bitset_next_set(bs, i + 1)) {
480                                                         snprintf(buf, sizeof(buf), "%ld", i);
481                                                         DUMP_STR(prefix);
482                                                         DUMP_STR(buf);
483                                                         prefix = ", ";
484                                                 }
485                                                 DUMP_CH(']');
486                                                 buf[0] = '\0';
487                                         }
488                                         break;
489
490                                 case '*':
491                                         {
492                                                 iterator_t *it = va_arg(args, iterator_t *);
493                                                 void *collection = va_arg(args, void *);
494                                                 void *curr;
495                                                 const char *prefix = "";
496                                                 char format = fmt[++i];
497                                                 ir_printf_cb_t *cb = format == 'C' ? va_arg(args, ir_printf_cb_t *) : NULL;
498
499                                                 assert(is_iterator(it) && "Pass an iterator interface and the collection");
500
501                                                 snprintf(buf, sizeof(buf), "%%%c", format);
502
503                                                 DUMP_CH('[');
504                                                 for(curr = it->start(collection); curr; curr = it->next(collection, curr)) {
505                                                         DUMP_STR(prefix);
506
507                                                         if(cb)
508                                                                 cb(app, object, limit, curr);
509                                                         else
510                                                                 ir_common_printf(app, object, limit, buf, curr);
511
512                                                         prefix = ", ";
513                                                 }
514                                                 it->finish(collection, curr);
515
516                                                 DUMP_CH(']');
517                                         }
518
519                                         /* clean the buffer again */
520                                         buf[0] = '\0';
521                                         break;
522                         }
523
524                         dump_with_settings(app, object, limit, &settings, str);
525                 }
526
527                 else
528                         DUMP_CH(ch);
529         }
530
531 #undef DUMP_STR
532 #undef DUMP_CH
533 }
534
535 /**
536  * Convencience for stdout dumping.
537  */
538 void ir_printf(const char *fmt, ...)
539 {
540         va_list args;
541         va_start(args, fmt);
542         ir_common_vprintf(&file_appender, stdout, 0, fmt, args);
543         va_end(args);
544 }
545
546 /**
547  * Convencience for file dumping.
548  */
549 void ir_fprintf(FILE *f, const char *fmt, ...)
550 {
551         va_list args;
552         va_start(args, fmt);
553         ir_common_vprintf(&file_appender, f, 0, fmt, args);
554         va_end(args);
555 }
556
557 /**
558  * Convencience for string dumping.
559  */
560 void ir_snprintf(char *buf, size_t len, const char *fmt, ...)
561 {
562         va_list args;
563         va_start(args, fmt);
564         ir_common_vprintf(&str_appender, buf, len, fmt, args);
565         va_end(args);
566 }
567
568 /**
569  * Convencience for string dumping.
570  */
571 void ir_obst_printf(struct obstack *obst, const char *fmt, ...)
572 {
573         va_list args;
574         va_start(args, fmt);
575         ir_common_vprintf(&obst_appender, obst, 0, fmt, args);
576         va_end(args);
577 }
578
579 void ir_vprintf(const char *fmt, va_list args)
580 {
581         ir_common_vprintf(&file_appender, stdout, 0, fmt, args);
582 }
583
584 void ir_vfprintf(FILE *f, const char *fmt, va_list args)
585 {
586         ir_common_vprintf(&file_appender, f, 0, fmt, args);
587 }
588
589 void ir_vsnprintf(char *buf, size_t len, const char *fmt, va_list args)
590 {
591         ir_common_vprintf(&str_appender, buf, len, fmt, args);
592 }
593
594 void ir_obst_vprintf(struct obstack *obst, const char *fmt, va_list args)
595 {
596         ir_common_vprintf(&obst_appender, obst, 0, fmt, args);
597 }