| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924 | /*File: tinyprintf.cCopyright (C) 2004  Kustaa NyholmThis library is free software; you can redistribute it and/ormodify it under the terms of the GNU Lesser General PublicLicense as published by the Free Software Foundation; eitherversion 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNULesser General Public License for more details.You should have received a copy of the GNU Lesser General PublicLicense along with this library; if not, write to the Free SoftwareFoundation, 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_SIZE_T_SUPPORT#include <sys/types.h>#endif#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_SUPPORTstatic 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_SUPPORTstatic 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);}#endifstatic 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_PRINTFstatic 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_SPRINTFstruct _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
 |