_sprintf.c
来自「深圳市微逻辑电子有限公司 巨果• Kingmos® 系统核心」· C语言 代码 · 共 476 行
C
476 行
#include <edef.h>
#include <estring.h>
#include <estdarg.h>
#define GET_DIGIT( c ) ( (c) - '0' )
#define IS_DIGIT( c ) ( ( (unsigned)GET_DIGIT(c) ) <= 9 )
#define TO_CHAR( n ) ( (n) + '0' )
// flags
#define LONGINT 0x01 // long int
#define SHORTINT 0x02 // short int
#define ALT 0x04 // alternate form
#define LEFTJUST 0x10 // left adjustment
#define ZEROFILL 0x20 // zero fill
#define HEXPREFIX 0x40 // add 0x or 0X prefix
#define OCT 0
#define DEC 1
#define HEX 2
#define BUF 32
#define SARG() \
( flags & LONGINT ? va_arg(ap, long) : \
flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
(long)va_arg(ap, int) )
#define UARG() \
( flags&LONGINT ? va_arg(ap, unsigned long) : \
flags&SHORTINT ? (unsigned long)(unsigned short)va_arg(ap, int) : \
(unsigned long)va_arg(ap, unsigned int) )
#ifdef QUICK_OUTPUT
#define out_byte( pbuf, c ) ( *(pbuf) = (char)(c), 1 )
#else
static int out_byte( char * pbuf, char c )
{
*pbuf = c;
return 1;
}
#endif // QUICK_OUTPUT
static int out_string( char * pbuf, const char * s )
{
int i = 0;
if( s )
while( *s ) { *pbuf++ = *s++; i++; };
return i;
}
static int out_mem( char * pbuf, const char * s, int num )
{
int i = 0;
if( s )
{
i = num;
while( num && *s ) { *pbuf++ = *s++; num--; };
}
return i;
}
static int out_pad( char * pbuf, int c, unsigned int num )
{
int i = num;
while( num ) { *pbuf++ = c; num--; };
return i;
}
//int sprintf( fp, fmt0, ap )
//_IO_FILE *fp;
//char const *fmt0;
//_IO_va_list ap;
//unsigned int std_sprintf( unsigned char *pbuf, const unsigned char *format, ... )
unsigned int _out_stream(
char *outbuf,
const char *format,
va_list ap )
{
register const char *fmt; /* format string */
register int ch; /* character from fmt */
register int n; /* handy integer (short term usage) */
register char *cp; /* handy char pointer (short term usage) */
const char *fmark; /* for remembering a place in fmt */
register int flags; /* flags as above */
int ret; /* return value accumulator */
int width; /* width from format (%8d), or 0 */
int prec; /* precision from format (%.3d), or -1 */
char sign; /* sign prefix (' ', '+', '-', or \0) */
int base;
unsigned long _ulong; /* integer arguments %[diouxX] */
int dprec; /* a copy of prec if [diouxX], 0 otherwise */
int dpad; /* extra 0 padding needed for integers */
int fieldsz; /* field size expanded by sign, dpad etc */
/* The initialization of 'size' is to suppress a warning that
'size' might be used unitialized. It seems gcc can't
quite grok this spaghetti code ... */
int size = 0; /* size of converted field or string */
char buf[33]; /* space for %c, %[diouxX], %[eEfgG] */
//char ox[2]; /* space for 0x hex-prefix */
fmt = format;//fmt0;
ret = 0;
// Scan the format for conversions (`%' character).
while( 1 )
{
for( fmark = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++ )
;
if( ( n = fmt - fmark ) != 0 )
{
//PRINT( fmark, n ); // out_string
outbuf += out_mem( outbuf, fmark, n );
ret += n;
}
if( ch == '\0' )
goto done;
fmt++; // skip over '%'
flags = 0;
dprec = 0;
width = 0;
prec = -1;
sign = '\0';
rflag:
ch = *fmt++;
reswitch:
switch( ch )
{
case ' ':
//**************************************************
// ``If the space and + flags both appear, the space
// flag will be ignored.''
// -- ANSI X3J11
//*************************************************
if ( !sign )
sign = ' ';
goto rflag;
case '#':
flags |= ALT;
goto rflag;
case '*':
//***********************************************
// ``A negative field width argument is taken as a
// - flag followed by a positive field width.''
// -- ANSI X3J11
// They don't exclude field widths read from args.
//************************************************
if( (width = va_arg(ap, int) ) >= 0 )
goto rflag;
width = -width;
/* FALLTHROUGH */
case '-':
flags |= LEFTJUST;
flags &= ~ZEROFILL; /* '-' disables '0' */
goto rflag;
case '+':
sign = '+';
goto rflag;
case '.':
if( (ch = *fmt++) == '*')
{
n = va_arg(ap, int);
prec = n < 0 ? -1 : n;
goto rflag;
}
n = 0;
while( IS_DIGIT(ch) )
{
n = 10 * n + GET_DIGIT(ch);
ch = *fmt++;
}
prec = n < 0 ? -1 : n;
goto reswitch;
case '0':
//*********************************************
// ``Note that 0 is taken as a flag, not as the
// beginning of a field width.''
// -- ANSI X3J11
//*********************************************
if( !(flags & LEFTJUST) )
flags |= ZEROFILL; // '-' disables '0'
goto rflag;
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
n = 0;
do
{
n = 10 * n + GET_DIGIT(ch);
ch = *fmt++;
}while ( IS_DIGIT(ch) );
width = n;
goto reswitch;
case 'h':
flags |= SHORTINT;
goto rflag;
case 'l':
flags |= LONGINT;
goto rflag;
case 'c':
*( cp = buf ) = va_arg(ap, int);
size = 1;
sign = '\0';
break;
case 'D':
flags |= LONGINT;
//FALLTHROUGH
case 'd':
case 'i':
// signed
_ulong = SARG();
if( (long)_ulong < 0 )
{
_ulong = -(long)_ulong;
sign = '-';
}
base = DEC;
goto number;
case 'n':
if( flags & LONGINT )
*va_arg( ap, long * ) = ret;
else if( flags & SHORTINT )
*va_arg( ap, short * ) = ret;
else
*va_arg( ap, int * ) = ret;
continue; // no output
case 'O':
flags |= LONGINT;
//FALLTHROUGH
case 'o':
// unsigned
_ulong = UARG();
base = OCT;
goto nosign;
case 'p':
//************************************************
// The argument shall be a pointer to void. The
// value of the pointer is converted to a sequence
// of printable characters, in an implementation-
// defined manner.
// -- ANSI X3J11
//************************************************
/* NOSTRICT */
_ulong = (unsigned long)va_arg( ap, void * );
base = HEX;
flags |= HEXPREFIX;
ch = 'x';
goto nosign;
case 's':
if ( ( cp = va_arg( ap, char * ) ) == 0 )
cp = "0";//"(null)";
if( prec >= 0 )
{
char *p = (char*)memchr( cp, 0, prec );
if( p != 0 )
{
size = p - cp;
if( size > prec )
size = prec;
} else
size = prec;
}
else
size = strlen(cp);
sign = '\0';
break;
case 'U':
flags |= LONGINT;
//FALLTHROUGH
case 'u':
// unsigned
_ulong = UARG();
base = DEC;
goto nosign;
case 'X':
case 'x':
_ulong = UARG();
base = HEX;
// leading 0x/X only if non-zero
if( (flags & ALT) && _ulong != 0 )
flags |= HEXPREFIX;
// unsigned conversions
nosign:
sign = '\0';
//************************************************
// ``... diouXx conversions ... if a precision is
// specified, the 0 flag will be ignored.''
// -- ANSI X3J11
//************************************************
number:
if( (dprec = prec) >= 0 )
flags &= ~ZEROFILL;
//************************************************
// ``The result of converting a zero value with an
// explicit precision of zero is no characters.''
// -- ANSI X3J11
//************************************************
cp = buf + BUF;
if (_ulong != 0 || prec != 0)
{
char *xdigs; // digits for [xX] conversion
//
// unsigned mod is hard, and unsigned mod
// by a constant is easier than that by
// a variable; hence this switch.
//
switch (base)
{
case OCT:
do {
*--cp = TO_CHAR( (char)(_ulong & 7) );
_ulong >>= 3;
}while (_ulong);
// handle octal leading 0
if( (flags & ALT) && *cp != '0' )
*--cp = '0';
break;
case DEC:
// many numbers are 1 digit
while( _ulong >= 10 )
{
*--cp = TO_CHAR( (char)(_ulong % 10) );
_ulong /= 10;
}
*--cp = TO_CHAR( (char)_ulong);
break;
case HEX:
if( ch == 'X' )
xdigs = "0123456789ABCDEF";
else // ch == 'x' || ch == 'p'
xdigs = "0123456789abcdef";
do
{
*--cp = xdigs[_ulong & 15];
_ulong >>= 4;
} while( _ulong );
break;
default:
cp = "";//"bug in vform: bad base";
goto skipsize;
}
}
size = buf + BUF - cp;
skipsize:
break;
default: // "%?" prints ?, unless ? is NUL
if( ch == '\0' )
goto done;
// pretend it was %c with argument ch
cp = buf;
*cp = ch;
size = 1;
sign = '\0';
break;
}
/*
* All reasonable formats wind up here. At this point,
* `cp' points to a string which (if not flags&LEFTJUST)
* should be padded out to `width' places. If
* flags&ZEROFILL, it should first be prefixed by any
* sign or other prefix; otherwise, it should be blank
* padded before the prefix is emitted. After any
* left-hand padding and prefixing, emit zeroes
* required by a decimal [diouxX] precision, then print
* the string proper, then emit zeroes required by any
* leftover floating precision; finally, if LEFTJUST,
* pad with blanks.
*/
/*
* compute actual size, so we know how much to pad.
*/
fieldsz = size;
dpad = dprec - size;
if (dpad < 0)
dpad = 0;
if (sign)
fieldsz++;
else if (flags & HEXPREFIX)
fieldsz += 2;
fieldsz += dpad;
// right-adjusting blank padding
if( (flags & (LEFTJUST|ZEROFILL) ) == 0 && width > fieldsz )
//PAD_SP(width - fieldsz);
outbuf += out_pad( outbuf, ' ', width - fieldsz );
// prefix
if( sign )
{
//PRINT(&sign, 1);
outbuf += out_byte( outbuf, sign );
}
else if (flags & HEXPREFIX)
{
//ox[0] = '0';
//ox[1] = ch;
//PRINT(ox, 2);
outbuf += out_byte( outbuf, '0' );
outbuf += out_byte( outbuf, (char)ch );
}
// right-adjusting zero padding
if ( (flags & (LEFTJUST|ZEROFILL)) == ZEROFILL && width > fieldsz )
//PAD_0(width - fieldsz);
outbuf += out_pad( outbuf, '0', width - fieldsz );
// leading zeroes from decimal precision
//PAD_0(dpad);
// 2004-03-15 lilin -begin
//out_pad( outbuf, '0', dpad );
outbuf += out_pad( outbuf, '0', dpad );
// -end
// the string or number proper
//PRINT(cp, size);
outbuf += out_mem( outbuf, cp, size );
// left-adjusting padding (always blank)
if( (flags & LEFTJUST) && width > fieldsz )
//PAD_SP(width - fieldsz);
outbuf += out_pad( outbuf, ' ', width - fieldsz );
// finally, adjust ret
ret += width > fieldsz ? width : fieldsz;
}
done:
return ret;
//error:
// return 0;
}
unsigned int std_sprintf( char *pbuf, const char *format, ... )
{
int i;
va_list vl;
va_start(vl, format);
i = _out_stream( pbuf, format, vl );
pbuf[i] = 0;
return i;
}
unsigned int std_vsprintf( char *pbuf, const char *format, va_list argptr )
{
int i;
i = _out_stream( pbuf, format, argptr );
pbuf[i] = 0;
return i;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?