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