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