Good day and welcome to the FIRM XMALLOC*() macros. These macros are provided for...
[libfirm] / ir / libcore / lc_printf.c
1 /*
2   libcore: library for basic data structures and algorithms.
3   Copyright (C) 2005  IPD Goos, Universit"at Karlsruhe, Germany
4
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9
10   This library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Lesser General Public License for more details.
14
15   You should have received a copy of the GNU Lesser General Public
16   License along with this library; if not, write to the Free Software
17   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20
21 /**
22  * A customizable printf clone.
23  * @author Sebastian Hack
24  * @date 4.12.2005
25  */
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <stddef.h>
30 #include <stdarg.h>
31 #include <string.h>
32 #include <assert.h>
33 #include <ctype.h>
34
35 #include "lc_common_t.h"
36 #include "xmalloc.h"
37 #include "lc_printf.h"
38 #include "lc_defines.h"
39 #include "hashptr.h"
40 #include "set.h"
41
42 /* printf implementation */
43
44 typedef struct _lc_arg_t {
45         struct _lc_arg_t *next;
46         const char *name;
47         char letter;
48         int lc_arg_type;
49         const lc_arg_handler_t *handler;
50 } lc_arg_t;
51
52 struct _lc_arg_env_t {
53         set *args;                                      /**< Map for named arguments. */
54         lc_arg_t *lower[26];            /**< Map for lower conversion specifiers. */
55         lc_arg_t *upper[26];            /**< Map for upper conversion specifiers. */
56 };
57
58 /** The default argument environment. */
59 static lc_arg_env_t *default_env = NULL;
60
61 static INLINE lc_arg_env_t *_lc_arg_get_default_env(void)
62 {
63         if(!default_env)
64                 default_env = lc_arg_add_std(lc_arg_new_env());
65
66         return default_env;
67 }
68
69 lc_arg_env_t *lc_arg_get_default_env(void)
70 {
71         return _lc_arg_get_default_env();
72 }
73
74 static int lc_arg_cmp(const void *p1, const void *p2, UNUSED(size_t size))
75 {
76         const lc_arg_t *a1 = p1;
77         const lc_arg_t *a2 = p2;
78         return strcmp(a1->name, a2->name);
79 }
80
81
82 lc_arg_env_t *lc_arg_new_env(void)
83 {
84         lc_arg_env_t *env = XMALLOCZ(lc_arg_env_t);
85         env->args = new_set(lc_arg_cmp, 16);
86         return env;
87 }
88
89 void lc_arg_free_env(lc_arg_env_t *env)
90 {
91         del_set(env->args);
92         free(env);
93 }
94
95 int lc_arg_register(lc_arg_env_t *env, const char *name, char letter, const lc_arg_handler_t *handler)
96 {
97         lc_arg_t arg;
98         lc_arg_t *ent;
99         int base = 0;
100         lc_arg_t **map = NULL;
101
102         arg.name = name;
103         arg.letter = letter;
104         arg.handler = handler;
105
106         if(isupper(letter)) {
107                 map = env->upper;
108                 base = 'A';
109         }
110         else if(islower(letter)) {
111                 map = env->lower;
112                 base = 'a';
113         }
114
115         ent = set_insert(env->args, &arg, sizeof(arg), HASH_STR(name, strlen(name)));
116
117         if(ent && base != 0)
118                 map[letter - base] = ent;
119
120         return ent != NULL;
121 }
122
123 void lc_arg_unregister(UNUSED(lc_arg_env_t *env), UNUSED(const char *name))
124 {
125 }
126
127 int lc_arg_append(lc_appendable_t *app, const lc_arg_occ_t *occ, const char *str, size_t len)
128 {
129         char pad = ' ';
130
131         /* Set the padding to zero, if the zero is given and we are not left
132          * justified. (A minus overrides the zero). See printf(3). */
133         if(!occ->flag_minus && occ->flag_zero)
134                 pad = '0';
135
136         return lc_appendable_snwadd(app, str, len, LC_MAX(0, occ->width), occ->flag_minus, pad);
137 }
138
139
140 static int dispatch_snprintf(char *buf, size_t len, const char *fmt,
141                 int lc_arg_type, const lc_arg_value_t *val)
142 {
143         int res = 0;
144
145         switch(lc_arg_type) {
146 #define LC_ARG_TYPE(type,name) \
147                 case lc_arg_type_ ## name: res = snprintf(buf, len, fmt, val->v_ ## name); break;
148 #include "lc_printf_arg_types.def"
149 #undef LC_ARG_TYPE
150         }
151
152         return res;
153 }
154
155 static char *make_fmt(char *buf, size_t len, const lc_arg_occ_t *occ)
156 {
157         char mod[64];
158         char prec[16];
159         char width[16];
160
161         prec[0] = '\0';
162         width[0] = '\0';
163
164         if(occ->precision > 0)
165                 snprintf(prec, sizeof(prec), ".%d", occ->precision);
166
167         if(occ->width > 0)
168                 snprintf(width, sizeof(width), "%d", occ->width);
169
170         assert(occ->modifier && "modifier must not be NULL");
171         strncpy(mod, occ->modifier, sizeof(mod) - 1);
172         mod[LC_MIN(sizeof(mod) - 1, occ->modifier_length)] = '\0';
173
174         snprintf(buf, len, "%%%s%s%s%s%s%s%s%s%c",
175                         occ->flag_space ? "#" : "",
176                         occ->flag_hash ? "#" : "",
177                         occ->flag_plus ? "+" : "",
178                         occ->flag_minus ? "-" : "",
179                         occ->flag_zero ? "0" : "",
180                         width, prec,
181                         mod, occ->conversion);
182
183         return buf;
184 }
185
186 /**
187  * Standard argument handler.
188  */
189 static int std_get_lc_arg_type(const lc_arg_occ_t *occ)
190 {
191         int modlen = occ->modifier_length;
192
193         /* check, if the type can be derived from the modifier */
194         if (modlen > 0) {
195                 const char *mod = occ->modifier;
196                 switch (mod[0]) {
197                         case 'l':
198                                 return modlen > 1 && mod[1] == 'l' ? lc_arg_type_long_long : lc_arg_type_long;
199 #define TYPE_CASE(letter,type) case letter: return lc_arg_type_ ## type;
200 #if 0
201                         TYPE_CASE('j', intmax_t);
202                         TYPE_CASE('z', size_t);
203                         TYPE_CASE('t', ptrdiff_t);
204 #endif
205                         TYPE_CASE('L', long_double);
206 #undef TYPE_CASE
207                 }
208         }
209
210         /* The type is given by the conversion specifier and cannot be
211          * determined from the modifier. */
212         switch (occ->conversion) {
213                 case 'e':
214                 case 'E':
215                 case 'f':
216                 case 'F':
217                 case 'g':
218                 case 'G':
219                         return lc_arg_type_double;
220                 case 's':
221                 case 'n':
222                 case 'p':
223                         return lc_arg_type_ptr;
224                 default:
225                         return lc_arg_type_int;
226         }
227 }
228
229 static int std_emit(lc_appendable_t *app, const lc_arg_occ_t *occ, const lc_arg_value_t *val)
230 {
231         char fmt[32];
232         int res = 0;
233
234         make_fmt(fmt, sizeof(fmt), occ);
235
236         switch(occ->conversion) {
237
238                 /* Store the number of written characters in the given
239                  * int pointer location */
240                 case 'n':
241                         {
242                                 int *num = val->v_ptr;
243                                 *num = app->written;
244                         }
245                         break;
246
247                 /* strings are dumped directly, since they can get really big. A
248                  * buffer of 128 letters for all other types should be enough. */
249                 case 's':
250                         {
251                                 const char *str = val->v_ptr;
252                                 res = lc_arg_append(app, occ, str, strlen(str));
253                         }
254                         break;
255
256                 default:
257                         {
258                                 int len = LC_MAX(128, occ->width + 1);
259                                 char *buf = XMALLOCN(char, len);
260                                 res = dispatch_snprintf(buf, len, fmt, occ->lc_arg_type, val);
261                                 res = lc_appendable_snadd(app, buf, res);
262                                 xfree(buf);
263                         }
264         }
265
266         return res;
267 }
268
269 static const lc_arg_handler_t std_handler = {
270         std_get_lc_arg_type,
271         std_emit
272 };
273
274 lc_arg_env_t *lc_arg_add_std(lc_arg_env_t *env)
275 {
276         lc_arg_register(env, "std:c", 'c', &std_handler);
277         lc_arg_register(env, "std:i", 'i', &std_handler);
278         lc_arg_register(env, "std:d", 'd', &std_handler);
279         lc_arg_register(env, "std:o", 'o', &std_handler);
280         lc_arg_register(env, "std:u", 'u', &std_handler);
281         lc_arg_register(env, "std:x", 'x', &std_handler);
282         lc_arg_register(env, "std:X", 'X', &std_handler);
283
284         lc_arg_register(env, "std:e", 'e', &std_handler);
285         lc_arg_register(env, "std:E", 'E', &std_handler);
286         lc_arg_register(env, "std:f", 'f', &std_handler);
287         lc_arg_register(env, "std:F", 'F', &std_handler);
288         lc_arg_register(env, "std:g", 'g', &std_handler);
289         lc_arg_register(env, "std:G", 'G', &std_handler);
290
291         lc_arg_register(env, "std:s", 's', &std_handler);
292         lc_arg_register(env, "std:p", 'p', &std_handler);
293         lc_arg_register(env, "std:n", 'n', &std_handler);
294
295         return env;
296 }
297
298 static char *read_int(const char *s, int *value)
299 {
300         char *endptr;
301         int res = (int) strtol(s, &endptr, 10);
302         *value = endptr == s ? -1 : res;
303         return endptr;
304 }
305
306 /* Generic printf() function. */
307
308 int lc_evpprintf(const lc_arg_env_t *env, lc_appendable_t *app, const char *fmt, va_list args)
309 {
310         int res = 0;
311         const char *s;
312         const char *last = fmt + strlen(fmt);
313
314         /* Find the first % */
315         s = strchr(fmt, '%');
316
317         /* Emit the text before the first % was found */
318         lc_appendable_snadd(app, fmt, (s ? s : last) - fmt);
319
320         while(s != NULL) {
321                 lc_arg_occ_t occ;
322                 lc_arg_value_t val;
323                 const lc_arg_t *arg = NULL;
324                 const char *old;
325                 char ch;
326
327                 /* We must be at a '%' */
328                 assert(*s == '%');
329
330                 /* Reset the occurrence structure */
331                 memset(&occ, 0, sizeof(occ));
332
333                 /* Eat all flags and set the corresponding flags in the occ struct */
334                 for(++s; strchr("#0-+", *s); ++s) {
335                         switch(*s) {
336                                 case '#':
337                                         occ.flag_hash = 1;
338                                         break;
339                                 case '0':
340                                         occ.flag_zero = 1;
341                                         break;
342                                 case '-':
343                                         occ.flag_minus = 1;
344                                         break;
345                                 case '+':
346                                         occ.flag_plus = 1;
347                                         break;
348                                 case ' ':
349                                         occ.flag_space = 1;
350                                         break;
351                         }
352                 }
353
354                 /* Read the width if given */
355                 s = read_int(s, &occ.width);
356
357                 occ.precision = -1;
358
359                 /* read the precision if given */
360                 if(*s == '.') {
361                         int val;
362                         s = read_int(s + 1, &val);
363
364                         /* Negative or lacking precision after a '.' is treated as
365                          * precision 0. */
366                         occ.precision = LC_MAX(0, val);
367                 }
368
369                 /*
370                  * Now, we can either have:
371                  * - a named argument like {node}
372                  * - some modifiers followed by a conversion specifier
373                  * - or some other character, which ends this format invalidly
374                  */
375                 ch = *s;
376                 switch(ch) {
377                         case '%':
378                                 s++;
379                                 res += lc_appendable_chadd(app, '%');
380                                 break;
381                         case '{':
382                                 {
383                                         const char *named = ++s;
384
385                                         /* Read until the closing brace or end of the string. */
386                                         for(ch = *s; ch != '}' && ch != '\0'; ch = *++s);
387
388                                         if(s - named) {
389                                                 int n = s - named;
390                                                 char *name;
391                                                 lc_arg_t tmp;
392
393                                                 name = malloc(sizeof(char) * (n + 1));
394                                                 memcpy(name, named, sizeof(char) * n);
395                                                 name[n] = '\0';
396                                                 tmp.name = name;
397
398                                                 arg = set_find(env->args, &tmp, sizeof(tmp), HASH_STR(named, n));
399                                                 occ.modifier = "";
400                                                 occ.modifier_length = 0;
401
402                                                 /* Set the conversion specifier of the occurrence to the
403                                                  * letter specified in the argument description. */
404                                                 if(arg)
405                                                         occ.conversion = arg->letter;
406
407                                                 free(name);
408
409                                                 /* If we ended with a closing brace, move the current
410                                                  * pointer after it, since it is not to be dumped. */
411                                                 if(ch == '}')
412                                                         s++;
413                                         }
414                                 }
415                                 break;
416
417                         default:
418                                 {
419                                         const char *mod = s;
420
421                                         /* Read, as long there are letters */
422                                         while(isalpha(ch) && !arg) {
423                                                 int base = 'a';
424                                                 lc_arg_t * const *map = env->lower;
425
426                                                 /* If uppercase, select the uppercase map from the environment */
427                                                 if(isupper(ch)) {
428                                                         base = 'A';
429                                                         map = env->upper;
430                                                 }
431
432                                                 if(map[ch - base] != NULL) {
433                                                         occ.modifier = mod;
434                                                         occ.modifier_length = s - mod;
435                                                         occ.conversion = ch;
436                                                         arg = map[ch - base];
437                                                 }
438
439                                                 ch = *++s;
440                                         }
441                                 }
442                 }
443
444                 /* Call the handler if an argument was determined */
445                 if(arg != NULL && arg->handler != NULL) {
446                         const lc_arg_handler_t *handler = arg->handler;
447
448                         /* Let the handler determine the type of the argument based on the
449                          * information gathered. */
450                         occ.lc_arg_type = handler->get_lc_arg_type(&occ);
451
452                         /* Store the value according to argument information */
453                         switch(occ.lc_arg_type) {
454 #define LC_ARG_TYPE(type,name) case lc_arg_type_ ## name: val.v_ ## name = va_arg(args, type); break;
455 #include "lc_printf_arg_types.def"
456 #undef LC_ARG_TYPE
457                         }
458
459                         /* Finally, call the handler. */
460                         res += handler->emit(app, &occ, &val);
461                 }
462
463                 old = s;
464                 s = strchr(s, '%');
465                 res += lc_appendable_snadd(app, old, (s ? s : last) - old);
466         }
467
468         return res;
469 }
470
471 /* Convenience implementations */
472
473 int lc_epprintf(const lc_arg_env_t *env, lc_appendable_t *app, const char *fmt, ...)
474 {
475         int res;
476         va_list args;
477         va_start(args, fmt);
478         res = lc_evpprintf(env, app, fmt, args);
479         va_end(args);
480         return res;
481 }
482
483 int lc_pprintf(lc_appendable_t *app, const char *fmt, ...)
484 {
485         int res;
486         va_list args;
487         va_start(args, fmt);
488         res = lc_vpprintf(app, fmt, args);
489         va_end(args);
490         return res;
491 }
492
493 int lc_vpprintf(lc_appendable_t *app, const char *fmt, va_list args)
494 {
495         return lc_evpprintf(_lc_arg_get_default_env(), app, fmt, args);
496 }
497
498 int lc_eprintf(const lc_arg_env_t *env, const char *fmt, ...)
499 {
500         int res;
501         va_list args;
502         va_start(args, fmt);
503         res = lc_efprintf(env, stdout, fmt, args);
504         va_end(args);
505         return res;
506 }
507
508 int lc_esnprintf(const lc_arg_env_t *env, char *buf, size_t len, const char *fmt, ...)
509 {
510         int res;
511         va_list args;
512         va_start(args, fmt);
513         res = lc_evsnprintf(env, buf, len, fmt, args);
514         va_end(args);
515         return res;
516 }
517
518 int lc_efprintf(const lc_arg_env_t *env, FILE *file, const char *fmt, ...)
519 {
520         int res;
521         va_list args;
522         va_start(args, fmt);
523         res = lc_evfprintf(env, file, fmt, args);
524         va_end(args);
525         return res;
526 }
527
528 int lc_eoprintf(const lc_arg_env_t *env, struct obstack *obst, const char *fmt, ...)
529 {
530         int res;
531         va_list args;
532         va_start(args, fmt);
533         res = lc_evoprintf(env, obst, fmt, args);
534         va_end(args);
535         return res;
536 }
537
538 int lc_evprintf(const lc_arg_env_t *env, const char *fmt, va_list args)
539 {
540         return lc_evfprintf(env, stdout, fmt, args);
541 }
542
543 int lc_evsnprintf(const lc_arg_env_t *env, char *buf, size_t len, const char *fmt, va_list args)
544 {
545         int res;
546         lc_appendable_t app;
547
548         lc_appendable_init(&app, lc_appendable_string, buf, len);
549         res = lc_evpprintf(env, &app, fmt, args);
550         lc_appendable_finish(&app);
551         return res;
552 }
553
554 int lc_evfprintf(const lc_arg_env_t *env, FILE *f, const char *fmt, va_list args)
555 {
556         int res;
557         lc_appendable_t app;
558
559         lc_appendable_init(&app, lc_appendable_file, f, 0);
560         res = lc_evpprintf(env, &app, fmt, args);
561         lc_appendable_finish(&app);
562         return res;
563 }
564
565 int lc_evoprintf(const lc_arg_env_t *env, struct obstack *obst, const char *fmt, va_list args)
566 {
567         int res;
568         lc_appendable_t app;
569
570         lc_appendable_init(&app, lc_appendable_obstack, obst, 0);
571         res = lc_evpprintf(env, &app, fmt, args);
572         lc_appendable_finish(&app);
573         return res;
574 }
575
576
577 int lc_printf(const char *fmt, ...)
578 {
579         int res;
580         va_list args;
581         va_start(args, fmt);
582         res = lc_vprintf(fmt, args);
583         va_end(args);
584         return res;
585 }
586
587 int lc_snprintf(char *buf, size_t len, const char *fmt, ...)
588 {
589         int res;
590         va_list args;
591         va_start(args, fmt);
592         res = lc_vsnprintf(buf, len, fmt, args);
593         va_end(args);
594         return res;
595 }
596
597 int lc_fprintf(FILE *f, const char *fmt, ...)
598 {
599         int res;
600         va_list args;
601         va_start(args, fmt);
602         res = lc_vfprintf(f, fmt, args);
603         va_end(args);
604         return res;
605 }
606
607 int lc_oprintf(struct obstack *obst, const char *fmt, ...)
608 {
609         int res;
610         va_list args;
611         va_start(args, fmt);
612         res = lc_voprintf(obst, fmt, args);
613         va_end(args);
614         return res;
615 }
616
617
618 int lc_vprintf(const char *fmt, va_list args)
619 {
620         return lc_evprintf(_lc_arg_get_default_env(), fmt, args);
621 }
622
623 int lc_vsnprintf(char *buf, size_t len, const char *fmt, va_list args)
624 {
625         return lc_evsnprintf(_lc_arg_get_default_env(), buf, len, fmt, args);
626 }
627
628 int lc_vfprintf(FILE *f, const char *fmt, va_list args)
629 {
630         return lc_evfprintf(_lc_arg_get_default_env(), f, fmt, args);
631 }
632
633 int lc_voprintf(struct obstack *obst, const char *fmt, va_list args)
634 {
635         return lc_evoprintf(_lc_arg_get_default_env(), obst, fmt, args);
636 }