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