home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
QSPRINTF.ZIP
/
QSPRINTF.C
Wrap
C/C++ Source or Header
|
1989-02-04
|
8KB
|
268 lines
/*
** qsprintf()
** Copyright (C) 1988, 1989, William B. McCormick
** Released to public domain on 01 February 1989.
**
** Reentrant sprintf() replacement. Quick-and-dirty but duplicates most
** of the sprintf() functionality.
**
** History:
** 07/28/88 William B. McCormick
** Quick printf() for OS/2 multi-threaded programs.
** 02/01/89 William B. McCormick
** Changed to sprintf(). Added '*' specification. Released
** to public domain.
**
** Properly formats:
** % [flags] [width ] [.precision] [size] type
** flags:
** - left justify the result within field.
** 0 pad with '0' instead of ' '
** width:
** Controls the minimum # of characters printed. If value is
** less than specified width, padding is added. The width
** may be '*', in which case an integer argument from the
** argument list supplies the value.
** precision:
** Specifies the maximum # of characters printed. The precision
** may be '*', in which case an integer argument from the
** argument list supplies the value.
** size:
** F Specifies 's' is FAR
** N Specifies 's' is NEAR
** l Specifies 'd', 'x', 'u' is long
** B Followed by integer (or '*') from 2-36. Specifies
** base of number to be printed with 'd', 'i', or 'u'.
** type:
** s string
** d signed integer
** i signed integer
** u unsigned integer
** x unsigned hexadecimal integer ('abcdef')
** n Number of characters written to destination so far
** is stored in the integer whose address is given as
** the argument
*/
#include <stdlib.h>
#include <stdarg.h>
#include <limits.h>
/* comment out these lines for strict ANSI compatibility */
#define FAR far
#define NEAR near
/* prototype */
int qsprintf( char *dest, const char *fmt, ... );
#define TRUE 1
#define FALSE 0
#ifndef isdigit
# define isdigit(c) ((c)>='0' && (c)<='9')
#endif
#define w_char( dest, ch ) (*(dest)++ = ch)
#define w_str( dest, str, len ) for ( ; (len)>0; (len)--, (str)++ ) \
w_char( (dest), *(str) )
static void
w_string( char **pdest,
register const char FAR *str,
int minlen,
int maxlen,
char fill )
{
unsigned count, c2;
register const char FAR *p;
char *dest;
dest = *pdest;
count = 0;
p = str;
while ( *p++ )
if ( ++count == maxlen )
break;
if ( minlen > 0 ) {
for ( ; minlen>count; --minlen )
w_char( dest, fill );
}
c2 = count;
w_str( dest, str, c2 );
if ( minlen < 0 ) {
for ( minlen=-minlen; minlen>count; --minlen )
w_char( dest, fill );
}
*pdest = dest;
}
static char
get_int( va_list *parg, const char **pp, int *vp )
{
register const char *p;
register int val;
int sign;
char firstc;
p = *pp;
if ( *p=='-' ) {
++p;
sign = -1;
}
else
sign = 1;
firstc = *p;
if ( *p=='0' ) /* skip zero in case '0*' */
++ p;
if ( *p=='*' ) { /* get the value */
++ p;
val = va_arg( *parg, int );
}
else {
val = 0;
for ( ; isdigit(*p); p++ )
val = val * 10 + *p - '0';
}
*vp = val * sign;
*pp = p;
return firstc;
}
int cdecl
qsprintf( char *dest, const char *fmt, ... )
{
va_list arg;
register const char *reg_p;
const char *auto_p;
char buf[ CHAR_BIT * sizeof(long) + 1 ];
int val, val2;
int base;
int islong, isfar, isnear;
char fill;
char *org_dest;
org_dest = dest;
va_start(arg,fmt);
reg_p = fmt;
for ( ;*reg_p; reg_p++ ) {
if ( *reg_p=='%' ) {
isnear = isfar = islong = FALSE;
val = val2 = 0;
base = 10;
fill = ' ';
auto_p = reg_p + 1;
if ( get_int( &arg, &auto_p, &val ) == '0' )
fill = '0';
if ( *auto_p=='.' ) {
++auto_p;
(void) get_int( &arg, &auto_p, &val2 );
}
reg_p = auto_p-1;
next_fmt:
switch ( *++reg_p ) {
case 'l':
islong = TRUE;
goto next_fmt;
case 'F':
isfar = TRUE;
goto next_fmt;
case 'N':
isnear = TRUE;
goto next_fmt;
case 'B':
auto_p = reg_p+1;
(void) get_int( &arg, &auto_p, &base );
reg_p = auto_p-1;
goto next_fmt;
case 'n':
*va_arg( arg, int * ) = dest - org_dest;
break;
case 's':
w_string( &dest,
isfar ?
va_arg(arg,const char FAR *) :
(isnear ?
(const char FAR *)va_arg(arg,
const char NEAR *) :
(const char FAR *)va_arg(arg, const char *)),
val,
val2,
fill );
break;
case 'u':
w_string( &dest,
ltoa( islong ?
va_arg(arg,unsigned long) :
(unsigned long)va_arg(arg,unsigned),
buf,
base ),
val,
INT_MAX,
fill );
break;
case 'd':
case 'i':
w_string( &dest,
ltoa( islong ?
va_arg(arg,long) :
(long) va_arg(arg,int),
buf,
base ),
val,
INT_MAX,
fill );
break;
case 'x':
w_string( &dest,
ltoa( islong ?
va_arg(arg,long) :
(long) va_arg(arg,int),
buf,
16 ),
val,
INT_MAX,
fill );
break;
default:
w_char( dest, *reg_p );
}
}
else {
w_char( dest, *reg_p );
}
}
w_char( dest, '\0' );
return dest - org_dest - 1; /* length of string */
}