diff options
Diffstat (limited to 'mdk-stage1/dietlibc/lib/__v_printf.c')
-rw-r--r-- | mdk-stage1/dietlibc/lib/__v_printf.c | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/mdk-stage1/dietlibc/lib/__v_printf.c b/mdk-stage1/dietlibc/lib/__v_printf.c new file mode 100644 index 000000000..15011cdd8 --- /dev/null +++ b/mdk-stage1/dietlibc/lib/__v_printf.c @@ -0,0 +1,300 @@ +#include "dietfeatures.h" +#include <stdarg.h> +#include <sys/types.h> +#include <stdlib.h> +#include <string.h> +#include "dietstdio.h" +#include "dietwarning.h" + +static inline unsigned int skip_to(const unsigned char *format) { + unsigned int nr; + for (nr=0; format[nr] && (format[nr]!='%'); ++nr); + return nr; +} + +#define A_WRITE(fn,buf,sz) ((fn)->put((void*)(buf),(sz),(fn)->data)) + +static const char pad_line[2][16]= { " ", "0000000000000000", }; +static inline int write_pad(struct arg_printf* fn, int len, int padwith) { + int nr=0; + for (;len>15;len-=16,nr+=16) { + A_WRITE(fn,pad_line[(padwith=='0')?1:0],16); + } + if (len>0) { + A_WRITE(fn,pad_line[(padwith=='0')?1:0],(unsigned int)len); nr+=len; + } + return nr; +} + +int __v_printf(struct arg_printf* fn, const unsigned char *format, va_list arg_ptr) +{ + int len=0; + + while (*format) { + unsigned int sz = skip_to(format); + if (sz) { + A_WRITE(fn,format,sz); len+=sz; + format+=sz; + } + if (*format=='%') { + char buf[128]; + + unsigned char ch, *s, padwith=' '; + + char flag_in_sign=0; + char flag_upcase=0; + char flag_hash=0; + char flag_left=0; + char flag_space=0; + char flag_sign=0; + char flag_dot=0; + signed char flag_long=0; + + unsigned int base; + unsigned int width=0, preci=0; + + long number=0; +#ifdef WANT_LONGLONG_PRINTF + long long llnumber=0; +#endif + + ++format; +inn_printf: + switch(ch=*format++) { + case 0: + return -1; + break; + + /* FLAGS */ + case '#': + flag_hash=-1; + case 'z': + goto inn_printf; + + case 'h': + --flag_long; + goto inn_printf; + case 'L': + ++flag_long; /* fall through */ + case 'l': + ++flag_long; + goto inn_printf; + + case '0': + padwith='0'; + goto inn_printf; + + case '-': + flag_left=1; + goto inn_printf; + + case ' ': + flag_space=1; + goto inn_printf; + + case '+': + flag_sign=1; + goto inn_printf; + + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if(flag_dot) return -1; + width=strtoul(format-1,(char**)&s,10); + format=s; + goto inn_printf; + + case '*': + width=va_arg(arg_ptr,int); + goto inn_printf; + + case '.': + flag_dot=1; + if (*format=='*') { + preci=va_arg(arg_ptr,int); + ++format; + } else { + long int tmp=strtol(format,(char**)&s,10); + preci=tmp<0?0:tmp; + format=s; + } + goto inn_printf; + + /* print a char or % */ + case 'c': + ch=(char)va_arg(arg_ptr,int); + case '%': + A_WRITE(fn,&ch,1); ++len; + break; + + /* print a string */ + case 's': + s=va_arg(arg_ptr,char *); +#ifdef WANT_NULL_PRINTF + if (!s) s="(null)"; +#endif + sz = strlen(s); + if (flag_dot && sz>preci) sz=preci; + flag_dot^=flag_dot; + +print_out: + if (width && (!flag_left)) { + if (flag_in_sign) { + A_WRITE(fn,s,1); ++len; + ++s; --sz; + --width; + } + if (flag_hash>0) { + A_WRITE(fn,s,flag_hash); len+=flag_hash; + s+=flag_hash; sz-=flag_hash; + width-=flag_hash; + } +// len+=write_pad(fn,(signed int)width-(signed int)sz,padwith); + if (flag_dot) { + len+=write_pad(fn,(signed int)width-(signed int)preci,padwith); + len+=write_pad(fn,(signed int)preci-(signed int)sz,'0'); + } else + len+=write_pad(fn,(signed int)width-(signed int)sz,padwith); + } + A_WRITE(fn,s,sz); len+=sz; + if (width && (flag_left)) { + len+=write_pad(fn,(signed int)width-(signed int)sz,' '); + } + break; + + /* print an integer value */ + case 'b': + base=2; + sz=0; + goto num_printf; + case 'p': + flag_hash=2; + flag_long=1; + ch='x'; + case 'X': + flag_upcase=(ch=='X'); + case 'x': + base=16; + sz=0; + if (flag_dot) width=preci; + if (flag_hash) { + buf[1]='0'; + buf[2]=ch; + flag_hash=2; + sz=2; + } + goto num_printf; + case 'd': + case 'i': + flag_in_sign=1; + case 'u': + base=10; + sz=0; + goto num_printf; + case 'o': + base=8; + sz=0; + if (flag_hash) { + buf[1]='0'; + flag_hash=1; + ++sz; + } + +num_printf: + s=buf+1; + + if (flag_long>0) { +#ifdef WANT_LONGLONG_PRINTF + if (flag_long>1) + llnumber=va_arg(arg_ptr,long long); + else +#endif + number=va_arg(arg_ptr,long); + } + else + number=va_arg(arg_ptr,int); + + if (flag_in_sign) { +#ifdef WANT_LONGLONG_PRINTF + if ((flag_long>1)&&(llnumber<0)) { + llnumber=-llnumber; + flag_in_sign=2; + } else +#endif + if (number<0) { + number=-number; + flag_in_sign=2; + } + } + if (flag_long<0) number&=0xffff; + if (flag_long<-1) number&=0xff; +#ifdef WANT_LONGLONG_PRINTF + if (flag_long>1) + sz += __lltostr(s+sz,sizeof(buf)-5,(unsigned long long) llnumber,base,flag_upcase); + else +#endif + sz += __ltostr(s+sz,sizeof(buf)-5,(unsigned long) number,base,flag_upcase); + + if (flag_in_sign==2) { + *(--s)='-'; + ++sz; + } else if ((flag_in_sign)&&(flag_sign || flag_space)) { + *(--s)=(flag_sign)?'+':' '; + ++sz; + } else flag_in_sign=0; + + goto print_out; + +#ifdef WANT_FLOATING_POINT_IN_PRINTF + /* print a floating point value */ + case 'f': + case 'g': + { + int g=(ch=='g'); + double d=va_arg(arg_ptr,double); + if (width==0) width=1; + if (!flag_dot) preci=6; + sz=__dtostr(d,buf,sizeof(buf),width,preci); + if (flag_dot) { + char *tmp; + if ((tmp=strchr(buf,'.'))) { + ++tmp; + while (preci>0 && *++tmp) --preci; + *tmp=0; + } + } + if (g) { + char *tmp,*tmp1; /* boy, is _this_ ugly! */ + if ((tmp=strchr(buf,'.'))) { + tmp1=strchr(tmp,'e'); + while (*tmp) ++tmp; + if (tmp1) tmp=tmp1; + while (*--tmp=='0') ; + if (*tmp!='.') ++tmp; + *tmp=0; + if (tmp1) strcpy(tmp,tmp1); + } + } + preci=strlen(buf); + s=buf; + + goto print_out; + } +#endif + + default: + break; + } + } + } + return len; +} + +link_warning("__v_printf","warning: the printf functions add several kilobytes of bloat.") + |