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