123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920 |
- /*
- File: tinyprintf.c
- Copyright (C) 2004 Kustaa Nyholm
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
- #include "tinystdio.h"
- #include <string.h>
- #include <stdlib.h>
- #include <math.h>
- /*
- * Configuration
- */
- /* Enable long int support */
- #define PRINTF_LONG_SUPPORT
- /* Enable long long int support (implies long int support) */
- #define PRINTF_LONG_LONG_SUPPORT
- /* Enable %z (size_t) support */
- #define PRINTF_SIZE_T_SUPPORT
- /*
- * Configuration adjustments
- */
- #ifdef PRINTF_LONG_LONG_SUPPORT
- # define PRINTF_LONG_SUPPORT
- #endif
- /* __SIZEOF_<type>__ defined at least by gcc */
- #ifdef __SIZEOF_POINTER__
- # define SIZEOF_POINTER __SIZEOF_POINTER__
- #endif
- #ifdef __SIZEOF_LONG_LONG__
- # define SIZEOF_LONG_LONG __SIZEOF_LONG_LONG__
- #endif
- #ifdef __SIZEOF_LONG__
- # define SIZEOF_LONG __SIZEOF_LONG__
- #endif
- #ifdef __SIZEOF_INT__
- # define SIZEOF_INT __SIZEOF_INT__
- #endif
- #ifdef __GNUC__
- # define _TFP_GCC_NO_INLINE_ __attribute__ ((noinline))
- #else
- # define _TFP_GCC_NO_INLINE_
- #endif
- /*
- * Implementation
- */
- struct param {
- char lz:1; /**< Leading zeros */
- char alt:1; /**< alternate form */
- char uc:1; /**< Upper case (for base16 only) */
- char align_left:1; /**< 0 == align right (default), 1 == align left */
- int width; /**< field width */
- char sign; /**< The sign to display (if any) */
- unsigned int base; /**< number base (e.g.: 8, 10, 16) */
- char *bf; /**< Buffer to output */
- char prec;
- };
- #ifdef PRINTF_LONG_LONG_SUPPORT
- static void _TFP_GCC_NO_INLINE_ ulli2a(
- unsigned long long int num, struct param *p)
- {
- int n = 0;
- unsigned long long int d = 1;
- char *bf = p->bf;
- while (num / d >= p->base)
- d *= p->base;
- while (d != 0) {
- int dgt = num / d;
- num %= d;
- d /= p->base;
- if (n || dgt > 0 || d == 0) {
- *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10);
- ++n;
- }
- }
- *bf = 0;
- }
- static void lli2a(long long int num, struct param *p)
- {
- if (num < 0) {
- num = -num;
- p->sign = '-';
- }
- ulli2a(num, p);
- }
- #endif
- #ifdef PRINTF_LONG_SUPPORT
- static void uli2a(unsigned long int num, struct param *p)
- {
- int n = 0;
- unsigned long int d = 1;
- char *bf = p->bf;
- while (num / d >= p->base)
- d *= p->base;
- while (d != 0) {
- int dgt = num / d;
- num %= d;
- d /= p->base;
- if (n || dgt > 0 || d == 0) {
- *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10);
- ++n;
- }
- }
- *bf = 0;
- }
- static void li2a(long num, struct param *p)
- {
- if (num < 0) {
- num = -num;
- p->sign = '-';
- }
- uli2a(num, p);
- }
- #endif
- static void ui2a(unsigned int num, struct param *p)
- {
- int n = 0;
- unsigned int d = 1;
- char *bf = p->bf;
- while (num / d >= p->base)
- d *= p->base;
- while (d != 0) {
- int dgt = num / d;
- num %= d;
- d /= p->base;
- if (n || dgt > 0 || d == 0) {
- *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10);
- ++n;
- }
- }
- *bf = 0;
- }
- static void i2a(int num, struct param *p)
- {
- if (num < 0) {
- num = -num;
- p->sign = '-';
- }
- ui2a(num, p);
- }
- static int a2d(char ch)
- {
- if (ch >= '0' && ch <= '9')
- return ch - '0';
- else if (ch >= 'a' && ch <= 'f')
- return ch - 'a' + 10;
- else if (ch >= 'A' && ch <= 'F')
- return ch - 'A' + 10;
- else
- return -1;
- }
- static char a2u(char ch, const char **src, int base, unsigned int *nump)
- {
- const char *p = *src;
- unsigned int num = 0;
- int digit;
- while ((digit = a2d(ch)) >= 0) {
- if (digit > base)
- break;
- num = num * base + digit;
- ch = *p++;
- }
- *src = p;
- *nump = num;
- return ch;
- }
- void float_to_s(double a, char buffer[])
- {
- if (a < 0)
- {
- a = -a;
- tfp_sprintf(buffer, "-%d.%d", (int)a, (int)((a - (int)a)*1000));
- }
- else
- tfp_sprintf(buffer, "%d.%d", (int)a, (int)((a - (int)a)*1000));
- }
- double s_to_float(char* str)
- {
- int neg;
- double fvalue = 0;
- int pos;
- if (*str == '-')
- {
- neg = 1;
- str++;
- }
- else
- neg = 0;
- int point_flag = 0;
- int exp = 0;
- for (fvalue = 0, pos = 0; *str != 0 ; str++, pos++)
- {
- if (*str == '.')
- {
- point_flag = 1;
- str++;
- }
- if ('0' <= *str && *str <= '9')
- fvalue = fvalue*10 + (int)(*str - '0');
- else
- break;
- if (point_flag == 1)
- exp++;
- }
- if (pos == 0)
- return 0;
- for (pos = 0; pos < exp; pos++)
- fvalue = fvalue/10.0;
- return neg ? -fvalue : fvalue;
- }
- static void putchw(void *putp, putcf putf, struct param *p)
- {
- char ch;
- int n = p->width;
- char *bf = p->bf;
- /* Number of filling characters */
- while (*bf++ && n > 0)
- n--;
- if (p->sign)
- n--;
- if (p->alt && p->base == 16)
- n -= 2;
- else if (p->alt && p->base == 8)
- n--;
- /* Fill with space to align to the right, before alternate or sign */
- if (!p->lz && !p->align_left) {
- while (n-- > 0)
- putf(putp, ' ');
- }
- /* print sign */
- if (p->sign)
- putf(putp, p->sign);
- /* Alternate */
- if (p->alt && p->base == 16) {
- putf(putp, '0');
- putf(putp, (p->uc ? 'X' : 'x'));
- } else if (p->alt && p->base == 8) {
- putf(putp, '0');
- }
- /* Fill with zeros, after alternate or sign */
- if (p->lz) {
- while (n-- > 0)
- putf(putp, '0');
- }
- /* Put actual buffer */
- bf = p->bf;
- while ((ch = *bf++))
- putf(putp, ch);
- /* Fill with space to align to the left, after string */
- if (!p->lz && p->align_left) {
- while (n-- > 0)
- putf(putp, ' ');
- }
- }
- void tfp_format(void *putp, putcf putf, const char *fmt, va_list va)
- {
- struct param p;
- double fval;
- int temp_buffer[10];
- int fpart;
- int fiter;
- int ffactor;
- int sign;
- #ifdef PRINTF_LONG_SUPPORT
- char bf[23]; /* long = 64b on some architectures */
- #else
- char bf[12]; /* int = 32b on some architectures */
- #endif
- char ch;
- p.bf = bf;
- while ((ch = *(fmt++))) {
- if (ch != '%') {
- putf(putp, ch);
- } else {
- #ifdef PRINTF_LONG_SUPPORT
- char lng = 0; /* 1 for long, 2 for long long */
- #endif
- /* Init parameter struct */
- p.lz = 0;
- p.alt = 0;
- p.width = 0;
- p.align_left = 0;
- p.sign = 0;
- p.prec = 2;
- /* Flags */
- while ((ch = *(fmt++))) {
- switch (ch) {
- case '-':
- p.align_left = 1;
- continue;
- case '0':
- p.lz = 1;
- continue;
- case '#':
- p.alt = 1;
- continue;
- case '+':
- p.sign = 1;
- continue;
- default:
- break;
- }
- break;
- }
- /* Width */
- if (ch >= '0' && ch <= '9') {
- ch = a2u(ch, &fmt, 10, &(p.width));
- }
- /* We accept 'x.y' format but don't support it completely:
- * we ignore the 'y' digit => this ignores 0-fill
- * size and makes it == width (ie. 'x') */
- if (ch == '.') {
- //p.lz = 1; /* zero-padding */
- /* ignore actual 0-fill size: */
- ch = *(fmt++);
- if (ch >= '0' && ch <= '9')
- p.prec = ch - '0';
- do
- {
- ch = *(fmt++);
- } while (ch >= '0' && ch <= '9');
- }
- #ifdef PRINTF_SIZE_T_SUPPORT
- # ifdef PRINTF_LONG_SUPPORT
- if (ch == 'z') {
- ch = *(fmt++);
- if (sizeof(size_t) == sizeof(unsigned long int))
- lng = 1;
- # ifdef PRINTF_LONG_LONG_SUPPORT
- else if (sizeof(size_t) == sizeof(unsigned long long int))
- lng = 2;
- # endif
- } else
- # endif
- #endif
- #ifdef PRINTF_LONG_SUPPORT
- if (ch == 'l') {
- ch = *(fmt++);
- lng = 1;
- #ifdef PRINTF_LONG_LONG_SUPPORT
- if (ch == 'l') {
- ch = *(fmt++);
- lng = 2;
- }
- #endif
- }
- #endif
- switch (ch) {
- case 0:
- goto abort;
- case 'u':
- p.base = 10;
- #ifdef PRINTF_LONG_SUPPORT
- #ifdef PRINTF_LONG_LONG_SUPPORT
- if (2 == lng)
- ulli2a(va_arg(va, unsigned long long int), &p);
- else
- #endif
- if (1 == lng)
- uli2a(va_arg(va, unsigned long int), &p);
- else
- #endif
- ui2a(va_arg(va, unsigned int), &p);
- putchw(putp, putf, &p);
- break;
- case 'd':
- case 'i':
- p.base = 10;
- #ifdef PRINTF_LONG_SUPPORT
- #ifdef PRINTF_LONG_LONG_SUPPORT
- if (2 == lng)
- lli2a(va_arg(va, long long int), &p);
- else
- #endif
- if (1 == lng)
- li2a(va_arg(va, long int), &p);
- else
- #endif
- i2a(va_arg(va, int), &p);
- putchw(putp, putf, &p);
- break;
- #ifdef SIZEOF_POINTER
- case 'p':
- p.alt = 1;
- # if defined(SIZEOF_INT) && SIZEOF_POINTER <= SIZEOF_INT
- lng = 0;
- # elif defined(SIZEOF_LONG) && SIZEOF_POINTER <= SIZEOF_LONG
- lng = 1;
- # elif defined(SIZEOF_LONG_LONG) && SIZEOF_POINTER <= SIZEOF_LONG_LONG
- lng = 2;
- # endif
- #endif
- case 'x':
- case 'X':
- p.base = 16;
- p.uc = (ch == 'X')?1:0;
- #ifdef PRINTF_LONG_SUPPORT
- #ifdef PRINTF_LONG_LONG_SUPPORT
- if (2 == lng)
- ulli2a(va_arg(va, unsigned long long int), &p);
- else
- #endif
- if (1 == lng)
- uli2a(va_arg(va, unsigned long int), &p);
- else
- #endif
- ui2a(va_arg(va, unsigned int), &p);
- putchw(putp, putf, &p);
- break;
- case 'o':
- p.base = 8;
- ui2a(va_arg(va, unsigned int), &p);
- putchw(putp, putf, &p);
- break;
- case 'c':
- putf(putp, (char)(va_arg(va, int)));
- break;
- case 's':
- p.bf = va_arg(va, char *);
- putchw(putp, putf, &p);
- p.bf = bf;
- break;
- case '%':
- putf(putp, ch);
- break;
- case 'f':
- case 'F':
- fval = va_arg(va, double);
- sign = 0;
- if (fval < 0)
- {
- sign = 1;
- p.width--;
- fval = - fval;
- }
- else if (p.sign) {
- sign = 2;
- p.width--;
- }
- fpart = (int)fval;
- fiter = 0;
- while (fpart != 0)
- {
- temp_buffer[fiter++] = fpart % 10;
- fpart = fpart / 10;
- }
- fiter--;
- if (fiter == -1)
- p.width--;
- /* Leading zeros */
- if (p.lz) {
- if (sign == 1)
- putf(putp, '-');
- else if (sign == 2)
- putf(putp, '+');
- while (p.width-- > p.prec + fiter + 2)
- {
- putf(putp, '0');
- }
- }
- else
- {
- while (p.width-- > p.prec + fiter + 2)
- {
- putf(putp, ' ');
- }
- if (sign == 1)
- putf(putp, '-');
- else if (sign == 2)
- putf(putp, '+');
- }
- if (fiter == -1)
- putf(putp, '0');
- while (fiter > -1)
- {
- putf(putp, '0' + (temp_buffer[fiter--]));
- }
- putf(putp, '.');
- ffactor = 1;
- while (p.prec-- > 0)
- {
- ffactor *= 10;
- fpart = (int)((fval - (int)fval)*ffactor);
- if (fpart == 0)
- putf(putp, '0');
- }
- fiter = 0;
- while (fpart != 0)
- {
- temp_buffer[fiter++] = fpart % 10;
- fpart = fpart / 10;
- }
- fiter--;
- while (fiter > -1)
- {
- putf(putp, '0' + (temp_buffer[fiter--]));
- }
- break;
- default:
- break;
- }
- }
- }
- abort:;
- }
- #if TINYPRINTF_DEFINE_TFP_PRINTF
- static putcf stdout_putf;
- static void *stdout_putp;
- void init_printf(void *putp, putcf putf)
- {
- stdout_putf = putf;
- stdout_putp = putp;
- }
- void tfp_printf(char *fmt, ...)
- {
- va_list va;
- va_start(va, fmt);
- tfp_format(stdout_putp, stdout_putf, fmt, va);
- va_end(va);
- }
- #endif
- #if TINYPRINTF_DEFINE_TFP_SPRINTF
- struct _vsnprintf_putcf_data
- {
- size_t dest_capacity;
- char *dest;
- size_t num_chars;
- };
- static void _vsnprintf_putcf(void *p, char c)
- {
- struct _vsnprintf_putcf_data *data = (struct _vsnprintf_putcf_data*)p;
- if (data->num_chars < data->dest_capacity)
- data->dest[data->num_chars] = c;
- data->num_chars ++;
- }
- int tfp_vsnprintf(char *str, size_t size, const char *format, va_list ap)
- {
- struct _vsnprintf_putcf_data data;
- if (size < 1)
- return 0;
- data.dest = str;
- data.dest_capacity = size-1;
- data.num_chars = 0;
- tfp_format(&data, _vsnprintf_putcf, format, ap);
- if (data.num_chars < data.dest_capacity)
- data.dest[data.num_chars] = '\0';
- else
- data.dest[data.dest_capacity] = '\0';
- return data.num_chars;
- }
- int tfp_snprintf(char *str, size_t size, const char *format, ...)
- {
- va_list ap;
- int retval;
- va_start(ap, format);
- retval = tfp_vsnprintf(str, size, format, ap);
- va_end(ap);
- return retval;
- }
- struct _vsprintf_putcf_data
- {
- char *dest;
- size_t num_chars;
- };
- static void _vsprintf_putcf(void *p, char c)
- {
- struct _vsprintf_putcf_data *data = (struct _vsprintf_putcf_data*)p;
- data->dest[data->num_chars++] = c;
- }
- int tfp_vsprintf(char *str, const char *format, va_list ap)
- {
- struct _vsprintf_putcf_data data;
- data.dest = str;
- data.num_chars = 0;
- tfp_format(&data, _vsprintf_putcf, format, ap);
- data.dest[data.num_chars] = '\0';
- return data.num_chars;
- }
- int tfp_sprintf(char *str, const char *format, ...)
- {
- va_list ap;
- int retval;
- va_start(ap, format);
- retval = tfp_vsprintf(str, format, ap);
- va_end(ap);
- return retval;
- }
- int isdigit (char c) {
- if ((c>='0') && (c<='9')) return 1;
- return 0;
- }
- int tfp_vsscanf(const char* str, const char* format, ...)
- {
- va_list ap;
- int value, tmp, width;
- float fvalue;
- double Fvalue;
- int count = 0;
- int pos;
- char neg, fmt_code;
- const char* pf;
- const char *tc;
- char tmp_str[20];
- va_start(ap, format);
- for (pf = format, count = 0; *format != 0 && *str != 0; format++, str++)
- {
- while (*format == ' ' && *format != 0)
- format++;
- if (*format == 0)
- break;
- while (*str == ' ' && *str != 0)
- str++;
- if (*str == 0)
- break;
- if (*format == '%')
- {
- format++;
- if (*format == 'n')
- {
- if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
- {
- fmt_code = 'x';
- str += 2;
- }
- else
- if (str[0] == 'b')
- {
- fmt_code = 'b';
- str++;
- }
- else
- fmt_code = 'd';
- }
- else if (*format >= '1' && *format <= '9') {
- for (tc = format; isdigit (*format); format++);
- strncpy(tmp_str, tc, format - tc);
- tmp_str[format - tc] = '\0';
- width = atoi(tmp_str);
- fmt_code = *format;
- }
- else
- fmt_code = *format;
- switch (fmt_code)
- {
- case 'x':
- case 'X':
- for (value = 0, pos = 0; *str != 0; str++, pos++)
- {
- if ('0' <= *str && *str <= '9')
- tmp = *str - '0';
- else
- if ('a' <= *str && *str <= 'f')
- tmp = *str - 'a' + 10;
- else
- if ('A' <= *str && *str <= 'F')
- tmp = *str - 'A' + 10;
- else
- break;
- value *= 16;
- value += tmp;
- }
- if (pos == 0)
- return count;
- *(va_arg(ap, int*)) = value;
- count++;
- break;
- case 'b':
- for (value = 0, pos = 0; *str != 0; str++, pos++)
- {
- if (*str != '0' && *str != '1')
- break;
- value *= 2;
- value += *str - '0';
- }
- if (pos == 0)
- return count;
- *(va_arg(ap, int*)) = value;
- count++;
- break;
- case 'd':
- if (*str == '-')
- {
- neg = 1;
- str++;
- }
- else
- neg = 0;
- if (!width) {
- for (value = 0, pos = 0; *str != 0; str++, pos++)
- {
- if ('0' <= *str && *str <= '9')
- value = value*10 + (int)(*str - '0');
- else{
- break;
- }
- }
- }
- else{
- for (value = 0, pos = 0; pos != width; str++, pos++)
- {
- if ('0' <= *str && *str <= '9')
- value = value*10 + (int)(*str - '0');
- else{
- break;
- }
- }
- str--;
- }
- if (pos == 0)
- return count;
- *(va_arg(ap, int*)) = neg ? -value : value;
- count++;
- break;
- case 'f':
- if (*str == '-')
- {
- neg = 1;
- str++;
- }
- else
- neg = 0;
- int point_flag = 0;
- int exp = 0;
- for (fvalue = 0, pos = 0; *str != 0 ; str++, pos++)
- {
- if (*str == '.')
- {
- point_flag = 1;
- str++;
- }
- if ('0' <= *str && *str <= '9')
- fvalue = fvalue*10 + (int)(*str - '0');
- else
- break;
- if (point_flag == 1)
- exp++;
- }
- if (pos == 0)
- return count;
- for (pos = 0; pos < exp; pos++)
- fvalue = fvalue/10.0;
- *(va_arg(ap, float*)) = neg ? -fvalue : fvalue;
- count++;
- break;
- case 'F':
- if (*str == '-')
- {
- neg = 1;
- str++;
- }
- else
- neg = 0;
- int Fpoint_flag = 0;
- int Fexp = 0;
- for (Fvalue = 0, pos = 0; *str != 0 ; str++, pos++)
- {
- if (*str == '.')
- {
- Fpoint_flag = 1;
- str++;
- }
- if ('0' <= *str && *str <= '9')
- Fvalue = Fvalue*10 + (int)(*str - '0');
- else
- break;
- if (Fpoint_flag == 1)
- Fexp++;
- }
- if (pos == 0)
- return count;
- for (pos = 0; pos < Fexp; pos++)
- Fvalue = Fvalue/10.0;
- *(va_arg(ap, double*)) = neg ? -Fvalue : Fvalue;
- count++;
- break;
- case 'c':
- *(va_arg(ap, char*)) = *str;
- count++;
- break;
- case 's':
- pos = 0;
- char* tab = va_arg(ap, char**);
- while (*str != ' ' && *str != 0)
- *(tab++) = *str++;
- *tab = 0;
- count++;
- break;
- default:
- return count;
- }
- }
- else
- {
- if (*format != *str)
- break;
- }
- }
- va_end(ap);
- return count;
- }
- #endif
|