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