回复 8楼 qjm100
刚刚在网上找到个
程序代码:
int printf(const char *format,...)
{
int n;
va_list arg_ptr;
va_start(arg_ptr, format);
n=vprintf(format, arg_ptr);
va_end(arg_ptr);
return n;
}
int vprintf(const char *format, va_list ap)
{
struct arg_printf _ap = { 0, (int(*)(void*,size_t,void*)) __stdio_outs };
return __v_printf(&_ap,format,ap);
}
int __v_printf(struct arg_printf* fn, const char *format, va_list arg_ptr)
{
unsigned int len=0;
#ifdef WANT_ERROR_PRINTF
int _errno = errno;
#endif
while (*format) {
unsigned long sz = skip_to(format);
if (sz) {
B_WRITE(fn,format,sz); len+=sz;
format+=sz;
}
if (*format=='%') {
char buf[128];
union { char*s; } u_str;
#define s u_str.s
int retval;
unsigned char ch, padwith=' ', precpadwith=' ';
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;
#if __WORDSIZE != 64
case 'j':
#endif
case 'q': /* BSD ... */
case 'L':
++flag_long; /* fall through */
#if __WORDSIZE == 64
case 'j':
#endif
case 'l':
++flag_long;
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 '0':
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);
if (width>MAX_WIDTH) return -1;
if (ch=='0' && !flag_left) padwith='0';
format=s;
goto inn_printf;
case '*':
width=va_arg(arg_ptr,int);
if (width>MAX_WIDTH) return -1; /* width is unsiged, so this catches <0, too */
goto inn_printf;
case '.':
flag_dot=1;
if (*format=='*') {
int tmp=va_arg(arg_ptr,int);
preci=tmp<0?0:tmp;
++format;
} else {
long int tmp=strtol(format,(char**)&s,10);
preci=tmp<0?0:tmp;
format=s;
}
if (preci>MAX_WIDTH) return -1;
goto inn_printf;
/* print a char or % */
case 'c':
ch=(char)va_arg(arg_ptr,int);
case '%':
B_WRITE(fn,&ch,1); ++len;
break;
#ifdef WANT_ERROR_PRINTF
/* print an error message */
case 'm':
s=strerror(_errno);
sz=strlen(s);
B_WRITE(fn,s,sz); len+=sz;
break;
#endif
/* 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;
preci=0;
flag_dot^=flag_dot;
padwith=precpadwith=' ';
print_out:
{
char *sign=s;
int todo=0;
int vs;
if (! (width||preci) ) {
B_WRITE(fn,s,sz); len+=sz;
break;
}
if (flag_in_sign) todo=1;
if (flag_hash>0) todo=flag_hash;
if (todo) {
s+=todo;
sz-=todo;
width-=todo;
}
/* These are the cases for 1234 or "1234" respectively:
%.6u -> "001234"
%6u -> " 1234"
%06u -> "001234"
%-6u -> "1234 "
%.6s -> "1234"
%6s -> " 1234"
%06s -> " 1234"
%-6s -> "1234 "
%6.5u -> " 01234"
%6.5s -> " 1234"
In this code, for %6.5s, 6 is width, 5 is preci.
flag_dot means there was a '.' and preci is set.
flag_left means there was a '-'.
sz is 4 (strlen("1234")).
padwith will be '0' for %06u, ' ' otherwise.
precpadwith is '0' for %u, ' ' for %s.
*/
if (flag_dot && width==0) width=preci;
if (!flag_dot) preci=sz;
if (!flag_left) { /* do left-side padding */
if (write_pad(&len,fn,width-preci,padwith))
return -1;
}
if (todo) {
B_WRITE(fn,sign,todo);
len+=todo;
}
/* do preci padding */
if (write_pad(&len,fn,preci-sz,precpadwith))
return -1;
/* write actual string */
B_WRITE(fn,s,sz); len+=sz;
if (flag_left) {
if (write_pad(&len,fn,width-preci,padwith))
return -1;
}
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_hash) {
buf[1]='0';
buf[2]=ch;
flag_hash=2;
sz=2;
}
if (preci>width) width=preci;
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 (sizeof(int) != sizeof(long) && !flag_in_sign)
number&=((unsigned int)-1);
}
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)
retval = __lltostr(s+sz,sizeof(buf)-5,(unsigned long long) llnumber,base,flag_upcase);
else
#endif
retval = __ltostr(s+sz,sizeof(buf)-5,(unsigned long) number,base,flag_upcase);
/* When 0 is printed with an explicit precision 0, the output is empty. */
if (flag_dot && retval == 1 && s[sz] == '0') {
if (preci == 0||flag_hash > 0) {
sz = 0;
}
flag_hash = 0;
} else sz += retval;
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;
precpadwith='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);
s=buf+1;
if (width==0) width=1;
if (!flag_dot) preci=6;
if (flag_sign || d < +0.0) flag_in_sign=1;
sz=__dtostr(d,s,sizeof(buf)-1,width,preci,g);
if (flag_dot) {
char *tmp;
if ((tmp=strchr(s,'.'))) {
if (preci || flag_hash) ++tmp;
while (preci>0 && *++tmp) --preci;
*tmp=0;
} else if (flag_hash) {
s[sz]='.';
s[++sz]='\0';
}
}
if (g) {
char *tmp,*tmp1; /* boy, is _this_ ugly! */
if ((tmp=strchr(s,'.'))) {
tmp1=strchr(tmp,'e');
while (*tmp) ++tmp;
if (tmp1) tmp=tmp1;
while (*--tmp=='0') ;
if (*tmp!='.') ++tmp;
*tmp=0;
if (tmp1) strcpy(tmp,tmp1);
}
}
if ((flag_sign || flag_space) && d>=0) {
*(--s)=(flag_sign)?'+':' ';
++sz;
}
sz=strlen(s);
if (width<sz) width=sz;
padwith='0';
flag_dot=0;
flag_hash=0;
goto print_out;
}
#endif
default:
break;
}
}
}
return len;
}