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