4 Copyright (C) 2004 Kustaa Nyholm
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with this library; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <lib/tinyprintf.h>
29 /* Enable long int support */
30 #define PRINTF_LONG_SUPPORT
32 /* Enable long long int support (implies long int support) */
33 //#define PRINTF_LONG_LONG_SUPPORT
35 /* Enable %z (size_t) support */
36 #define PRINTF_SIZE_T_SUPPORT
39 * Configuration adjustments
41 #ifdef PRINTF_SIZE_T_SUPPORT
42 #include <sys/types.h>
45 #ifdef PRINTF_LONG_LONG_SUPPORT
46 # define PRINTF_LONG_SUPPORT
49 /* __SIZEOF_<type>__ defined at least by gcc */
50 #ifdef __SIZEOF_POINTER__
51 # define SIZEOF_POINTER __SIZEOF_POINTER__
53 #ifdef __SIZEOF_LONG_LONG__
54 # define SIZEOF_LONG_LONG __SIZEOF_LONG_LONG__
56 #ifdef __SIZEOF_LONG__
57 # define SIZEOF_LONG __SIZEOF_LONG__
60 # define SIZEOF_INT __SIZEOF_INT__
64 # define _TFP_GCC_NO_INLINE_ __attribute__ ((noinline))
66 # define _TFP_GCC_NO_INLINE_
73 char lz:1; /**< Leading zeros */
74 char alt:1; /**< alternate form */
75 char uc:1; /**< Upper case (for base16 only) */
76 char align_left:1; /**< 0 == align right (default), 1 == align left */
77 unsigned int width; /**< field width */
78 char sign; /**< The sign to display (if any) */
79 unsigned int base; /**< number base (e.g.: 8, 10, 16) */
80 char *bf; /**< Buffer to output */
84 #ifdef PRINTF_LONG_LONG_SUPPORT
85 static void _TFP_GCC_NO_INLINE_ ulli2a(
86 unsigned long long int num, struct param *p)
89 unsigned long long int d = 1;
91 while (num / d >= p->base)
97 if (n || dgt > 0 || d == 0) {
98 *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10);
105 static void lli2a(long long int num, struct param *p)
115 #ifdef PRINTF_LONG_SUPPORT
116 static void uli2a(unsigned long int num, struct param *p)
119 unsigned long int d = 1;
121 while (num / d >= p->base)
127 if (n || dgt > 0 || d == 0) {
128 *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10);
135 static void li2a(long num, struct param *p)
145 static void ui2a(unsigned int num, struct param *p)
150 while (num / d >= p->base)
156 if (n || dgt > 0 || d == 0) {
157 *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10);
164 static void i2a(int num, struct param *p)
173 static int a2d(char ch)
175 if (ch >= '0' && ch <= '9')
177 else if (ch >= 'a' && ch <= 'f')
178 return ch - 'a' + 10;
179 else if (ch >= 'A' && ch <= 'F')
180 return ch - 'A' + 10;
185 static char a2u(char ch, const char **src, int base, unsigned int *nump)
187 const char *p = *src;
188 unsigned int num = 0;
190 while ((digit = a2d(ch)) >= 0) {
193 num = num * base + digit;
201 static void putchw(void *putp, putcf putf, struct param *p)
207 /* Number of filling characters */
208 while (*bf++ && n > 0)
212 if (p->alt && p->base == 16)
214 else if (p->alt && p->base == 8)
217 /* Fill with space to align to the right, before alternate or sign */
218 if (!p->lz && !p->align_left) {
228 if (p->alt && p->base == 16) {
230 putf(putp, (p->uc ? 'X' : 'x'));
231 } else if (p->alt && p->base == 8) {
235 /* Fill with zeros, after alternate or sign */
241 /* Put actual buffer */
246 /* Fill with space to align to the left, after string */
247 if (!p->lz && p->align_left) {
253 void tfp_format(void *putp, putcf putf, const char *fmt, va_list va)
256 #ifdef PRINTF_LONG_SUPPORT
257 char bf[23]; /* long = 64b on some architectures */
259 char bf[12]; /* int = 32b on some architectures */
264 while ((ch = *(fmt++))) {
268 #ifdef PRINTF_LONG_SUPPORT
269 char lng = 0; /* 1 for long, 2 for long long */
271 /* Init parameter struct */
279 while ((ch = *(fmt++))) {
297 if (ch >= '0' && ch <= '9') {
298 ch = a2u(ch, &fmt, 10, &(p.width));
301 /* We accept 'x.y' format but don't support it completely:
302 * we ignore the 'y' digit => this ignores 0-fill
303 * size and makes it == width (ie. 'x') */
305 p.lz = 1; /* zero-padding */
306 /* ignore actual 0-fill size: */
309 } while ((ch >= '0') && (ch <= '9'));
312 #ifdef PRINTF_SIZE_T_SUPPORT
313 # ifdef PRINTF_LONG_SUPPORT
316 if (sizeof(size_t) == sizeof(unsigned long int))
318 # ifdef PRINTF_LONG_LONG_SUPPORT
319 else if (sizeof(size_t) == sizeof(unsigned long long int))
326 #ifdef PRINTF_LONG_SUPPORT
330 #ifdef PRINTF_LONG_LONG_SUPPORT
343 #ifdef PRINTF_LONG_SUPPORT
344 #ifdef PRINTF_LONG_LONG_SUPPORT
346 ulli2a(va_arg(va, unsigned long long int), &p);
350 uli2a(va_arg(va, unsigned long int), &p);
353 ui2a(va_arg(va, unsigned int), &p);
354 putchw(putp, putf, &p);
359 #ifdef PRINTF_LONG_SUPPORT
360 #ifdef PRINTF_LONG_LONG_SUPPORT
362 lli2a(va_arg(va, long long int), &p);
366 li2a(va_arg(va, long int), &p);
369 i2a(va_arg(va, int), &p);
370 putchw(putp, putf, &p);
372 #ifdef SIZEOF_POINTER
375 # if defined(SIZEOF_INT) && SIZEOF_POINTER <= SIZEOF_INT
377 # elif defined(SIZEOF_LONG) && SIZEOF_POINTER <= SIZEOF_LONG
379 # elif defined(SIZEOF_LONG_LONG) && SIZEOF_POINTER <= SIZEOF_LONG_LONG
386 p.uc = (ch == 'X')?1:0;
387 #ifdef PRINTF_LONG_SUPPORT
388 #ifdef PRINTF_LONG_LONG_SUPPORT
390 ulli2a(va_arg(va, unsigned long long int), &p);
394 uli2a(va_arg(va, unsigned long int), &p);
397 ui2a(va_arg(va, unsigned int), &p);
398 putchw(putp, putf, &p);
402 ui2a(va_arg(va, unsigned int), &p);
403 putchw(putp, putf, &p);
406 putf(putp, (char)(va_arg(va, int)));
409 p.bf = va_arg(va, char *);
410 putchw(putp, putf, &p);
423 #if TINYPRINTF_DEFINE_TFP_PRINTF
424 static putcf stdout_putf;
425 static void *stdout_putp;
427 void init_printf(void *putp, putcf putf)
433 void tfp_printf(char *fmt, ...)
437 tfp_format(stdout_putp, stdout_putf, fmt, va);
442 #if TINYPRINTF_DEFINE_TFP_SPRINTF
443 struct _vsnprintf_putcf_data
445 size_t dest_capacity;
450 static void _vsnprintf_putcf(void *p, char c)
452 struct _vsnprintf_putcf_data *data = (struct _vsnprintf_putcf_data*)p;
453 if (data->num_chars < data->dest_capacity)
454 data->dest[data->num_chars] = c;
458 int tfp_vsnprintf(char *str, size_t size, const char *format, va_list ap)
460 struct _vsnprintf_putcf_data data;
466 data.dest_capacity = size-1;
468 tfp_format(&data, _vsnprintf_putcf, format, ap);
470 if (data.num_chars < data.dest_capacity)
471 data.dest[data.num_chars] = '\0';
473 data.dest[data.dest_capacity] = '\0';
475 return data.num_chars;
478 int tfp_snprintf(char *str, size_t size, const char *format, ...)
483 va_start(ap, format);
484 retval = tfp_vsnprintf(str, size, format, ap);
489 struct _vsprintf_putcf_data
495 static void _vsprintf_putcf(void *p, char c)
497 struct _vsprintf_putcf_data *data = (struct _vsprintf_putcf_data*)p;
498 data->dest[data->num_chars++] = c;
501 int tfp_vsprintf(char *str, const char *format, va_list ap)
503 struct _vsprintf_putcf_data data;
506 tfp_format(&data, _vsprintf_putcf, format, ap);
507 data.dest[data.num_chars] = '\0';
508 return data.num_chars;
511 int tfp_sprintf(char *str, const char *format, ...)
516 va_start(ap, format);
517 retval = tfp_vsprintf(str, format, ap);