irprintf.c 9.38 KB
Newer Older
Michael Beck's avatar
Michael Beck committed
1
2
3
4
5
6
7
8
9
10
11
/*
 * Project:     libFIRM
 * File name:   ir/ir/irprintf.c
 * Purpose:     A little printf helper unterstanding firm types
 * Author:      Sebastian Hack
 * Created:     29.11.2004
 * CVS-ID:      $Id$
 * Copyright:   (c) 1998-2004 Universitt Karlsruhe
 * Licence:     This file protected by GPL -  GNU GENERAL PUBLIC LICENSE.
 */

12
/**
Michael Beck's avatar
Michael Beck committed
13
14
15
 * @file irprinf.c
 *
 * A little printf helper unterstanding firm types.
16
17
18
19
 * @author Sebastian Hack
 * @date 29.11.2004
 */

Michael Beck's avatar
Michael Beck committed
20
#ifdef HAVE_CONFIG_H
Michael Beck's avatar
Michael Beck committed
21
#include "config.h"
Michael Beck's avatar
Michael Beck committed
22
23
#endif

Michael Beck's avatar
Michael Beck committed
24
#ifdef HAVE_STRING_H
Sebastian Hack's avatar
Sebastian Hack committed
25
#include <string.h>
Michael Beck's avatar
Michael Beck committed
26
#endif
27

28
29
30
31
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>

Sebastian Hack's avatar
Sebastian Hack committed
32
33
#include <ctype.h>

Michael Beck's avatar
Michael Beck committed
34
35
36
37
#include "ident.h"
#include "irmode_t.h"
#include "irnode_t.h"
#include "entity_t.h"
38
39
#include "tv.h"
#include "irprintf.h"
40
41
#include "pset.h"
#include "iterator.h"
42
#include "bitset.h"
43

44

Michael Beck's avatar
Michael Beck committed
45
46
47
/**
 * append a char to a string buffer
 */
48
static void str_append_char(void *object, size_t n, char ch)
49
50
51
52
53
54
{
	char buf[2];

	buf[0] = ch;
	buf[1] = 0;

55
	strncat(object, buf, n);
56
57
}

Michael Beck's avatar
Michael Beck committed
58
59
60
/**
 * append a string to a string buffer
 */
61
static void str_append_str(void *object, size_t n, const char *str)
62
{
63
	strncat(object, str, n);
64
65
}

Michael Beck's avatar
Michael Beck committed
66
67
68
/**
 * append a char to a file
 */
69
static void file_append_char(void *object, size_t n, char ch)
70
{
71
	fputc(ch, object);
72
73
}

Michael Beck's avatar
Michael Beck committed
74
75
76
/**
 * append a string to a file
 */
77
static void file_append_str(void *object, size_t n, const char *str)
78
{
79
	fputs(str, object);
80
81
}

Michael Beck's avatar
Michael Beck committed
82
83
84
/**
 * the file appender
 */
85
86
87
88
89
static const appender_t file_appender = {
	file_append_char,
	file_append_str
};

Michael Beck's avatar
Michael Beck committed
90
91
92
/**
 * the string buffer appender
 */
93
94
95
96
97
static const appender_t str_appender = {
	str_append_char,
	str_append_str
};

98
99
100
101
102
103
104
105
106
107
108
109
static void ir_common_vprintf(const appender_t *app, void *object,
		size_t limit, const char *fmt, va_list args);

static INLINE void ir_common_printf(const appender_t *app, void *object,
		size_t limit, const char *fmt, ...)
{
	va_list args;

	va_start(args, fmt);
	ir_common_vprintf(app, object, limit, fmt, args);
	va_end(args);
}
110

Sebastian Hack's avatar
Sebastian Hack committed
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#if 0
static int is_std_fmt(const char *fmt)
{
	static const char *fmt_re_str =
		"^[0 -+#']?[1-9]*(\\.[1-9]*)?[hlLqjzt]?[diouxXeEfFgGaAc]";

	static regex_t fmt_re;
	static int preapred_re = 0;

	regmatch_t match[1];
	int res;

	if(!preapred_re) {
		int res = regcomp(&fmt_re, fmt_re_str, REG_EXTENDED);
		assert(res == 0 && "Could not prepare regex");
		preapred_re = 1;
	}

	res = regexec(&fmt_re, fmt, 1, &match[0], 0);

#if 0
	if(res != 0) {
		char buf[256];
		regerror(res, &fmt_re, buf, sizeof(buf));
		printf("%s ", buf);
	}

	printf("res: %d, start: %d, end: %d\n",
			res, match[0].rm_so, match[0].rm_eo);
#endif

	return res == 0 ? match[0].rm_eo : -1;
}
#endif

struct settings {
	char pad;
	int width;
	int left_just;
	int put_plus;
	int alternate;
};

#define MIN(x,y) ((x) < (y) ? (x) : (y))
#define MAX(x,y) ((x) > (y) ? (x) : (y))


static void dump_with_settings(const appender_t *app, void *object, size_t limit,
		const struct settings *settings, const char *str)
{
	if(settings->width >= 0) {
		int i;
		size_t n = strlen(str);
		int lim = MIN(settings->width, limit);
		int to_print = MIN(lim, n);
		int to_pad = to_print - lim;

		if(!settings->left_just)
			for(i = 0; i < to_pad; ++i)
				app->append_char(object, lim, settings->pad);

		app->append_str(object, to_print, str);

		if(!settings->left_just)
			for(i = 0; i < to_pad; ++i)
				app->append_char(object, lim, settings->pad);
	}

	else
		app->append_str(object, limit, str);
}



/* Length specifiers. */
enum {
	len_char,
	len_short,
	len_int,
	len_long,
	len_long_long
};


195
196
197
198
/**
 * A small printf helper routine for ir nodes.
 * @param app An appender (this determines where the stuff is dumped
 * to).
199
 * @param object A target passed to the appender.
200
201
202
203
 * @param limit The maximum number of characters to dump.
 * @param fmt The format string.
 * @param args A va_list.
 */
204
static void ir_common_vprintf(const appender_t *app, void *object,
205
206
		size_t limit, const char *fmt, va_list args)
{
Sebastian Hack's avatar
Sebastian Hack committed
207
208
	const char *str;
	char buf[4096];
209
210
	int i, n;

211
212
#define DUMP_STR(s) app->append_str(object, limit, s)
#define DUMP_CH(ch) app->append_char(object, limit, ch)
213
214
215
216
217

	for(i = 0, n = strlen(fmt); i < n; ++i) {
		char ch = fmt[i];

		if(ch == '%') {
Sebastian Hack's avatar
Sebastian Hack committed
218
219
220
221
222
223
224
225
226
227
228
229
			int len;
			const char *len_str = "";

			struct settings settings;

			settings.alternate = 0;
			settings.pad = ' ';
			settings.width = -1;
			settings.left_just = 0;
			settings.put_plus = 0;

			ch = fmt[++i];
230
231
232
233

			/* Clear the temporary buffer */
			buf[0] = '\0';

Sebastian Hack's avatar
Sebastian Hack committed
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
			/* Set the string to print to the buffer by default. */
			str = buf;

			while(strchr("#0-+", ch)) {
				switch(ch) {
					case '#':
						settings.alternate = 1;
						break;
					case '0':
						settings.pad = '0';
						break;
					case '-':
						settings.left_just = 1;
						break;
					case '+':
						settings.put_plus = 1;
						break;
				}

				ch = fmt[++i];
			}


			/* Read the field width */
			{
				char *endptr;
				int increase;

				settings.width = (int) strtol(&fmt[i], &endptr, 10);
				increase = (char *) endptr - &fmt[i];
				ch = fmt[i += increase];
				if(increase == 0)
					settings.width = -1;
			}

			/* Ignore the precision */
			if(ch == '.')
				while(isdigit(ch = fmt[++i]));

			/* read the length modifier. */
			switch(ch) {
				case 'h':
					len_str = "h";
					len = len_short;
					if((ch = fmt[++i]) == 'h') {
						len_str = "hh";
						len = len_char;
					}
282
					break;
Sebastian Hack's avatar
Sebastian Hack committed
283
284
285
286
287
288
289
290

				case 'l':
					len_str = "l";
					len = len_long;
					if((ch = fmt[++i]) == 'l') {
						len_str = "ll";
						len = len_long_long;
					}
291
292
					break;

Sebastian Hack's avatar
Sebastian Hack committed
293
294
295
296
297
298
				default:
					len = len_int;
			}

			/* Do the conversion specifier. */
			switch(ch) {
Michael Beck's avatar
Michael Beck committed
299

Sebastian Hack's avatar
Sebastian Hack committed
300
301
302
303
304
				/* The percent itself */
				case '%':
					buf[0] = '%';
					buf[1] = '\0';
					break;
Michael Beck's avatar
Michael Beck committed
305

Sebastian Hack's avatar
Sebastian Hack committed
306
307
308
309
310
311
312
313
				case 'c':
					buf[0] = va_arg(args, int);
					buf[1] = '\0';
					break;

				case 's':
					str = va_arg(args, const char *);
					break;
Michael Beck's avatar
Michael Beck committed
314

315
316
317
318
				case 'p':
					snprintf(buf, sizeof(buf), "%p", va_arg(args, void *));
					break;

Sebastian Hack's avatar
Sebastian Hack committed
319
320
321
322
323
324
325
				case 'd':
				case 'x':
				case 'X':
				case 'o':
					{
						char fmt_str[16];
						snprintf(fmt_str, sizeof(fmt_str), "%%%s%c", len_str, ch);
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350

						switch(len) {
							case len_char:
							case len_short:
							case len_int:
								{
									int arg = va_arg(args, int);
									snprintf(buf, sizeof(buf), fmt_str, arg);
								}
								break;

							case len_long:
								{
									long arg = va_arg(args, long);
									snprintf(buf, sizeof(buf), fmt_str, arg);
								}
								break;

							case len_long_long:
								{
									long long arg = va_arg(args, long long);
									snprintf(buf, sizeof(buf), fmt_str, arg);
								}
								break;
						}
Sebastian Hack's avatar
Sebastian Hack committed
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
					}
					break;

				case 'I':
					str = get_id_str(va_arg(args, ident *));
					break;

				case 'e':
					str = get_entity_name(va_arg(args, entity *));
					break;

				case 'E':
					str = get_entity_ld_name(va_arg(args, entity *));
					break;

366
367
368
369
				case 't':
					tarval_snprintf(buf, sizeof(buf), va_arg(args, tarval *));
					break;

370
				case 'n':
371
372
373
374
375
376
377
					{
						ir_node *irn = va_arg(args, ir_node *);
						snprintf(buf, sizeof(buf), "%s%s:%ld",
								get_irn_opname(irn), get_mode_name(get_irn_mode(irn)), get_irn_node_nr(irn));
					}
					break;

Sebastian Hack's avatar
Sebastian Hack committed
378
379
				case 'O':
					str = get_irn_opname(va_arg(args, ir_node *));
380
381
					break;

382
				case 'N':
383
384
385
386
					snprintf(buf, sizeof(buf), "%ld", get_irn_node_nr(va_arg(args, ir_node *)));
					break;

				case 'm':
Sebastian Hack's avatar
Sebastian Hack committed
387
					str = get_mode_name(va_arg(args, ir_mode *));
388
389
					break;

390
				case 'B':
391
392
393
					snprintf(buf, sizeof(buf), "%ld",
							get_irn_node_nr(get_nodes_block(va_arg(args, ir_node *))));
					break;
394

395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
				case 'b':
					{
						const bitset_t *bs = va_arg(args, const bitset_t *);
						const char *prefix = "";
						unsigned long i;

						DUMP_CH('[');
						for(i = bitset_next_set(bs, 0); i != -1; i = bitset_next_set(bs, i + 1)) {
							snprintf(buf, sizeof(buf), "%ld", i);
							DUMP_STR(prefix);
							DUMP_STR(buf);
							prefix = ", ";
						}
						DUMP_CH(']');
						buf[0] = '\0';
					}
					break;

Sebastian Hack's avatar
Sebastian Hack committed
413
				case '*':
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
					{
						iterator_t *it = va_arg(args, iterator_t *);
						void *collection = va_arg(args, void *);
						void *curr;
						const char *prefix = "";
						char format = fmt[++i];
						ir_printf_cb_t *cb = format == 'C' ? va_arg(args, ir_printf_cb_t *) : NULL;

						assert(is_iterator(it) && "Pass an iterator interface and the collection");

						snprintf(buf, sizeof(buf), "%%%c", format);

						DUMP_CH('[');
						for(curr = it->start(collection); curr; curr = it->next(collection, curr)) {
							DUMP_STR(prefix);

							if(cb)
								cb(app, object, limit, curr);
							else
								ir_common_printf(app, object, limit, buf, curr);

							prefix = ", ";
						}
						it->finish(collection, curr);

						DUMP_CH(']');
					}

					/* clean the buffer again */
					buf[0] = '\0';
					break;
445
446
			}

Sebastian Hack's avatar
Sebastian Hack committed
447
			dump_with_settings(app, object, limit, &settings, str);
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
		}

		else
			DUMP_CH(ch);
	}

#undef DUMP_STR
#undef DUMP_CH
}

/**
 * Convencience for stdout dumping.
 */
void ir_printf(const char *fmt, ...)
{
	va_list args;
	va_start(args, fmt);
	ir_common_vprintf(&file_appender, stdout, 0, fmt, args);
	va_end(args);
}

/**
 * Convencience for file dumping.
 */
void ir_fprintf(FILE *f, const char *fmt, ...)
{
	va_list args;
	va_start(args, fmt);
	ir_common_vprintf(&file_appender, f, 0, fmt, args);
	va_end(args);
}

/**
 * Convencience for string dumping.
 */
void ir_snprintf(char *buf, size_t len, const char *fmt, ...)
{
	va_list args;
	va_start(args, fmt);
	ir_common_vprintf(&str_appender, buf, len, fmt, args);
	va_end(args);
}