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