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