2 * This file is part of libFirm.
3 * Copyright (C) 2012 IPD Goos, Universit"at Karlsruhe, Germany
8 * A customizable printf clone.
9 * @author Sebastian Hack
23 #include "lc_printf.h"
28 /* printf implementation */
30 typedef struct lc_arg_t {
31 struct lc_arg_t *next;
35 const lc_arg_handler_t *handler;
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. */
44 /** The default argument environment. */
45 static lc_arg_env_t *default_env = NULL;
47 static inline lc_arg_env_t *_lc_arg_get_default_env(void)
50 default_env = lc_arg_add_std(lc_arg_new_env());
55 lc_arg_env_t *lc_arg_get_default_env(void)
57 return _lc_arg_get_default_env();
60 static int lc_arg_cmp(const void *p1, const void *p2, size_t size)
62 const lc_arg_t *a1 = (const lc_arg_t*)p1;
63 const lc_arg_t *a2 = (const lc_arg_t*)p2;
65 return strcmp(a1->name, a2->name);
69 lc_arg_env_t *lc_arg_new_env(void)
71 lc_arg_env_t *env = XMALLOCZ(lc_arg_env_t);
72 env->args = new_set(lc_arg_cmp, 16);
76 void lc_arg_free_env(lc_arg_env_t *env)
82 int lc_arg_register(lc_arg_env_t *env, const char *name, char letter, const lc_arg_handler_t *handler)
87 lc_arg_t **map = NULL;
91 arg.handler = handler;
93 if (isupper((unsigned char)letter)) {
97 else if (islower((unsigned char)letter)) {
102 ent = set_insert(lc_arg_t, env->args, &arg, sizeof(arg), hash_str(name));
104 if (ent && base != 0)
105 map[letter - base] = ent;
110 void lc_arg_unregister(lc_arg_env_t *env, const char *name)
116 int lc_arg_append(lc_appendable_t *app, const lc_arg_occ_t *occ, const char *str, size_t len)
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)
125 return lc_appendable_snwadd(app, str, len, MAX(0, occ->width), occ->flag_minus, pad);
129 static int dispatch_snprintf(char *buf, size_t len, const char *fmt,
130 int lc_arg_type, const lc_arg_value_t *val)
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"
144 static char *make_fmt(char *buf, size_t len, const lc_arg_occ_t *occ)
153 if (occ->precision > 0)
154 snprintf(prec, sizeof(prec), ".%d", occ->precision);
157 snprintf(width, sizeof(width), "%d", occ->width);
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';
164 /* work-around for buggy mscrt not supporting z, j, and t modifier */
165 if (occ->modifier_length == 1) {
167 if (sizeof(size_t) == sizeof(int))
169 if (sizeof(size_t) == sizeof(__int64)) {
175 } else if (mod[0] == 't') {
176 if (sizeof(ptrdiff_t) == sizeof(int))
178 if (sizeof(ptrdiff_t) == sizeof(__int64)) {
184 } else if (mod[0] == 'j') {
185 if (sizeof(intmax_t) == sizeof(int))
187 if (sizeof(intmax_t) == sizeof(__int64)) {
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 */
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" : "",
209 mod, occ->conversion);
215 * Standard argument handler.
217 static int std_get_lc_arg_type(const lc_arg_occ_t *occ)
219 size_t modlen = occ->modifier_length;
221 /* check, if the type can be derived from the modifier */
223 const char *mod = occ->modifier;
226 return modlen > 1 && mod[1] == 'h' ? lc_arg_type_char : lc_arg_type_short;
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);
238 /* The type is given by the conversion specifier and cannot be
239 * determined from the modifier. */
240 switch (occ->conversion) {
247 return lc_arg_type_double;
251 return lc_arg_type_ptr;
253 return lc_arg_type_int;
257 static int std_emit(lc_appendable_t *app, const lc_arg_occ_t *occ, const lc_arg_value_t *val)
262 make_fmt(fmt, sizeof(fmt), occ);
264 switch (occ->conversion) {
266 /* Store the number of written characters in the given
267 * int pointer location */
270 int *num = (int*)val->v_ptr;
271 *num = (int)app->written;
275 /* strings are dumped directly, since they can get really big. A
276 * buffer of 128 letters for all other types should be enough. */
279 const char *str = (const char*)val->v_ptr;
280 res = lc_arg_append(app, occ, str, strlen(str));
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);
297 static const lc_arg_handler_t std_handler = {
302 lc_arg_env_t *lc_arg_add_std(lc_arg_env_t *env)
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);
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);
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);
326 static char *read_int(const char *s, int *value)
329 int res = (int) strtol(s, &endptr, 10);
330 *value = endptr == s ? -1 : res;
334 /* Generic printf() function. */
336 int lc_evpprintf(const lc_arg_env_t *env, lc_appendable_t *app, const char *fmt, va_list args)
340 const char *last = fmt + strlen(fmt);
342 /* Find the first % */
343 s = strchr(fmt, '%');
345 /* Emit the text before the first % was found */
346 lc_appendable_snadd(app, fmt, (s ? s : last) - fmt);
351 const lc_arg_t *arg = NULL;
355 /* We must be at a '%' */
358 /* Reset the occurrence structure */
359 memset(&occ, 0, sizeof(occ));
361 /* Eat all flags and set the corresponding flags in the occ struct */
362 for (++s; strchr("#0-+", *s); ++s) {
382 /* Read the width if given */
383 s = read_int(s, &occ.width);
387 /* read the precision if given */
390 s = read_int(s + 1, &precision);
392 /* Negative or lacking precision after a '.' is treated as
394 occ.precision = MAX(0, precision);
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
407 res += lc_appendable_chadd(app, '%');
411 const char *named = ++s;
413 /* Read until the closing brace or end of the string. */
414 for (ch = *s; ch != '}' && ch != '\0'; ch = *++s) {
418 size_t n = s - named;
422 name = (char*) malloc(sizeof(char) * (n + 1));
423 memcpy(name, named, sizeof(char) * n);
427 arg = set_find(lc_arg_t, env->args, &tmp, sizeof(tmp), hash_str(named));
429 occ.modifier_length = 0;
431 /* Set the conversion specifier of the occurrence to the
432 * letter specified in the argument description. */
434 occ.conversion = arg->letter;
438 /* If we ended with a closing brace, move the current
439 * pointer after it, since it is not to be dumped. */
450 /* Read, as long there are letters */
451 while (isalpha((unsigned char)ch) && !arg) {
453 lc_arg_t * const *map = env->lower;
455 /* If uppercase, select the uppercase map from the environment */
456 if (isupper((unsigned char)ch)) {
461 if (map[ch - base] != NULL) {
463 occ.modifier_length = s - mod;
465 arg = map[ch - base];
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;
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);
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"
489 /* Finally, call the handler. */
490 res += handler->emit(app, &occ, &val);
495 res += lc_appendable_snadd(app, old, (s ? s : last) - old);
501 /* Convenience implementations */
503 int lc_epprintf(const lc_arg_env_t *env, lc_appendable_t *app, const char *fmt, ...)
508 res = lc_evpprintf(env, app, fmt, args);
513 int lc_pprintf(lc_appendable_t *app, const char *fmt, ...)
518 res = lc_vpprintf(app, fmt, args);
523 int lc_vpprintf(lc_appendable_t *app, const char *fmt, va_list args)
525 return lc_evpprintf(_lc_arg_get_default_env(), app, fmt, args);
528 int lc_eprintf(const lc_arg_env_t *env, const char *fmt, ...)
533 res = lc_efprintf(env, stdout, fmt, args);
538 int lc_esnprintf(const lc_arg_env_t *env, char *buf, size_t len, const char *fmt, ...)
543 res = lc_evsnprintf(env, buf, len, fmt, args);
548 int lc_efprintf(const lc_arg_env_t *env, FILE *file, const char *fmt, ...)
553 res = lc_evfprintf(env, file, fmt, args);
558 int lc_eoprintf(const lc_arg_env_t *env, struct obstack *obst, const char *fmt, ...)
563 res = lc_evoprintf(env, obst, fmt, args);
568 int lc_evprintf(const lc_arg_env_t *env, const char *fmt, va_list args)
570 return lc_evfprintf(env, stdout, fmt, args);
573 int lc_evsnprintf(const lc_arg_env_t *env, char *buf, size_t len, const char *fmt, va_list args)
578 lc_appendable_init(&app, lc_appendable_string, buf, len);
579 res = lc_evpprintf(env, &app, fmt, args);
580 lc_appendable_finish(&app);
584 int lc_evfprintf(const lc_arg_env_t *env, FILE *f, const char *fmt, va_list args)
589 lc_appendable_init(&app, lc_appendable_file, f, 0);
590 res = lc_evpprintf(env, &app, fmt, args);
591 lc_appendable_finish(&app);
595 int lc_evoprintf(const lc_arg_env_t *env, struct obstack *obst, const char *fmt, va_list args)
600 lc_appendable_init(&app, lc_appendable_obstack, obst, 0);
601 res = lc_evpprintf(env, &app, fmt, args);
602 lc_appendable_finish(&app);
607 int lc_printf(const char *fmt, ...)
612 res = lc_vprintf(fmt, args);
617 int lc_snprintf(char *buf, size_t len, const char *fmt, ...)
622 res = lc_vsnprintf(buf, len, fmt, args);
627 int lc_fprintf(FILE *f, const char *fmt, ...)
632 res = lc_vfprintf(f, fmt, args);
637 int lc_oprintf(struct obstack *obst, const char *fmt, ...)
642 res = lc_voprintf(obst, fmt, args);
648 int lc_vprintf(const char *fmt, va_list args)
650 return lc_evprintf(_lc_arg_get_default_env(), fmt, args);
653 int lc_vsnprintf(char *buf, size_t len, const char *fmt, va_list args)
655 return lc_evsnprintf(_lc_arg_get_default_env(), buf, len, fmt, args);
658 int lc_vfprintf(FILE *f, const char *fmt, va_list args)
660 return lc_evfprintf(_lc_arg_get_default_env(), f, fmt, args);
663 int lc_voprintf(struct obstack *obst, const char *fmt, va_list args)
665 return lc_evoprintf(_lc_arg_get_default_env(), obst, fmt, args);