[2186] in bugtraq
snprintf
daemon@ATHENA.MIT.EDU (Patrick Powell)
Thu Aug 31 22:49:40 1995
Date: Wed, 30 Aug 1995 09:40:29 -0700
Reply-To: Bugtraq List <BUGTRAQ@CRIMELAB.COM>
From: Patrick Powell <papowell@sdsu.edu>
X-To: BUGTRAQ@CRIMELAB.COM
To: Multiple recipients of list BUGTRAQ <BUGTRAQ@CRIMELAB.COM>
Here is a highly portable snprintf that we use on a bunch of embedded controller
software; it has been 'configure'd to work with GNU autoconf.
Your milage may vary. Enjoy.
Prof. Patrick Powell
Dept. Electrical and Computer Engineering,
San Diego State University,
San Diego, CA 92182-1309
Office (619) 594-7796; Lab (619) 594-7578 FAX (619) 594-7577
email: papowell@sdsu.edu
---- Cut Here and feed the following to sh ----
#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.1).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
# Made on 1995-08-30 09:38 PDT by <papowell@dickory>.
# Source directory was `/tmp'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 522 -rw-r--r-- README.snprintf
# 6630 -rw-r--r-- snprintf.c
# 1100 -rw-r--r-- snprintf.h
#
touch -am 1231235999 $$.touch >/dev/null 2>&1
if test ! -f 1231235999 && test -f $$.touch; then
shar_touch=touch
else
shar_touch=:
echo
echo 'WARNING: not restoring timestamps. Consider getting and'
echo "installing GNU \`touch', distributed in GNU File Utilities..."
echo
fi
rm -f 1231235999 $$.touch
#
# ============= README.snprintf ==============
if test -f 'README.snprintf' && test X"$1" != X"-c"; then
echo 'x - skipping README.snprintf (file already exists)'
else
echo 'x - extracting README.snprintf (text)'
sed 's/^X//' << 'SHAR_EOF' > 'README.snprintf' &&
Tue Aug 29 17:30:22 PDT 1995 Patrick Powell
This is a very idiot level version of SNPRINTF that can be ported
to several different systems. Note that the lobotomized dopr_outch()
routine at the end of the snprintf.c file makes sure that no funny control
characters get printed out.
X
If you have CONFIGURE, add the following lines to the configure.in
script- these detect the prescence of the varargs.h or stdarg.h files:
X
AC_CHECK_HEADERS(varargs.h stdarg.h)
X
The snprintf code in the attached files is fairly portable.
X
SHAR_EOF
$shar_touch -am 0829174195 'README.snprintf' &&
chmod 0644 'README.snprintf' ||
echo 'restore of README.snprintf failed'
shar_count="`wc -c < 'README.snprintf'`"
test 522 -eq "$shar_count" ||
echo "README.snprintf: original size 522, current size $shar_count"
fi
# ============= snprintf.c ==============
if test -f 'snprintf.c' && test X"$1" != X"-c"; then
echo 'x - skipping snprintf.c (file already exists)'
else
echo 'x - extracting snprintf.c (text)'
sed 's/^X//' << 'SHAR_EOF' > 'snprintf.c' &&
/**************************************************************
X * Original:
X * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
X * A bombproof version of doprnt (dopr) included.
X * Sigh. This sort of thing is always nasty do deal with. Note that
X * the version here does not include floating point...
X *
X * plp_snprintf() is used instead of sprintf() as it does limit checks
X * for string length. This covers a nasty loophole.
X *
X * The other functions are there to prevent NULL pointers from
X * causing nast effects.
X **************************************************************/
X
static char _id[] = "$Id: snprintf.c,v 1.1 1995/08/19 20:36:09 papowell Exp $";
static void dopr();
static char *end;
X
#if defined(HAVE_CONFIG_H)
# include config.h
#endif
X
/* varargs declarations: */
X
#if defined(HAVE_STDARG_H)
# include <stdarg.h>
# define HAVE_STDARGS /* let's hope that works everywhere (mj) */
# define VA_LOCAL_DECL va_list ap;
# define VA_START(f) va_start(ap, f)
# define VA_SHIFT(v,t) ; /* no-op for ANSI */
# define VA_END va_end(ap)
#else
# if defined(HAVE_VARARGS_H)
# include <varargs.h>
# undef HAVE_STDARGS
# define VA_LOCAL_DECL va_list ap;
# define VA_START(f) va_start(ap) /* f is ignored! */
# define VA_SHIFT(v,t) v = va_arg(ap,t)
# define VA_END va_end(ap)
# else
XXX ** NO VARARGS ** XX
# endif
#endif
X
#ifdef HAVE_STDARGS
int plp_snprintf (char *str, size_t count, const char *fmt, ...);
int vplp_snprintf (char *str, size_t count, const char *fmt, va_list arg);
void setproctitle( char *fmt, ... );
#else
int plp_snprintf ();
int vplp_snprintf ();
void setproctitle();
#endif
X
int vplp_snprintf(str, count, fmt, args)
X char *str;
X size_t count;
X const char *fmt;
X va_list args;
{
X str[0] = 0;
X end = str+count-1;
X dopr( str, fmt, args );
X if( count>0 ){
X end[0] = 0;
X }
X return(strlen(str));
}
X
/* VARARGS3 */
#ifdef HAVE_STDARGS
int plp_snprintf (char *str,size_t count,const char *fmt,...)
#else
int plp_snprintf (va_alist) va_dcl
#endif
{
#ifndef HAVE_STDARGS
X char *str;
X size_t count;
X char *fmt;
#endif
X VA_LOCAL_DECL
X
X VA_START (fmt);
X VA_SHIFT (str, char *);
X VA_SHIFT (count, size_t );
X VA_SHIFT (fmt, char *);
X (void) vplp_snprintf ( str, count, fmt, ap);
X VA_END;
X return( strlen( str ) );
}
X
/*
X * dopr(): poor man's version of doprintf
X */
X
static void fmtstr( char *value, int ljust, int len, int zpad );
static void fmtnum( long value, int base, int dosign,
X int ljust, int len, int zpad );
static void dostr( char * );
static char *output;
static void dopr_outch( int c );
X
static void dopr( buffer, format, args )
X char *buffer;
X char *format;
X va_list args;
{
X int ch;
X long value;
X int longflag = 0;
X char *strvalue;
X int ljust;
X int len;
X int zpad;
X
X output = buffer;
X while( (ch = *format++) ){
X switch( ch ){
X case '%':
X ljust = len = zpad = 0;
X nextch:
X ch = *format++;
X switch( ch ){
X case 0:
X dostr( "**end of format**" );
X return;
X case '-': ljust = 1; goto nextch;
X case '0': /* set zero padding if len not set */
X if(len==0) zpad = '0';
X case '1': case '2': case '3':
X case '4': case '5': case '6':
X case '7': case '8': case '9':
X len = len*10 + ch - '0';
X goto nextch;
X case 'l': longflag = 1; goto nextch;
X case 'u': case 'U':
X /*fmtnum(value,base,dosign,ljust,len,zpad) */
X if( longflag ){
X value = va_arg( args, long );
X } else {
X value = va_arg( args, int );
X }
X fmtnum( value, 10,0, ljust, len, zpad ); break;
X case 'o': case 'O':
X /*fmtnum(value,base,dosign,ljust,len,zpad) */
X if( longflag ){
X value = va_arg( args, long );
X } else {
X value = va_arg( args, int );
X }
X fmtnum( value, 8,0, ljust, len, zpad ); break;
X case 'd': case 'D':
X if( longflag ){
X value = va_arg( args, long );
X } else {
X value = va_arg( args, int );
X }
X fmtnum( value, 10,1, ljust, len, zpad ); break;
X case 'x':
X if( longflag ){
X value = va_arg( args, long );
X } else {
X value = va_arg( args, int );
X }
X fmtnum( value, 16,0, ljust, len, zpad ); break;
X case 'X':
X if( longflag ){
X value = va_arg( args, long );
X } else {
X value = va_arg( args, int );
X }
X fmtnum( value,-16,0, ljust, len, zpad ); break;
X case 's':
X strvalue = va_arg( args, char *);
X fmtstr( strvalue,ljust,len,zpad ); break;
X case 'c':
X ch = va_arg( args, int );
X dopr_outch( ch ); break;
X case '%': dopr_outch( ch ); continue;
X default:
X dostr( "???????" );
X }
X longflag = 0;
X break;
X default:
X dopr_outch( ch );
X break;
X }
X }
X *output = 0;
}
X
static void
fmtstr( value, ljust, len, zpad )
X char *value;
X int ljust, len, zpad;
{
X int padlen, strlen; /* amount to pad */
X
X if( value == 0 ){
X value = "<NULL>";
X }
X for( strlen = 0; value[strlen]; ++ strlen ); /* strlen */
X padlen = len - strlen;
X if( padlen < 0 ) padlen = 0;
X if( ljust ) padlen = -padlen;
X while( padlen > 0 ) {
X dopr_outch( ' ' );
X --padlen;
X }
X dostr( value );
X while( padlen < 0 ) {
X dopr_outch( ' ' );
X ++padlen;
X }
}
X
static void
fmtnum( value, base, dosign, ljust, len, zpad )
X long value;
X int base, dosign, ljust, len, zpad;
{
X int signvalue = 0;
X unsigned long uvalue;
X char convert[20];
X int place = 0;
X int padlen = 0; /* amount to pad */
X int caps = 0;
X
X /* DEBUGP(("value 0x%x, base %d, dosign %d, ljust %d, len %d, zpad %d\n",
X value, base, dosign, ljust, len, zpad )); */
X uvalue = value;
X if( dosign ){
X if( value < 0 ) {
X signvalue = '-';
X uvalue = -value;
X }
X }
X if( base < 0 ){
X caps = 1;
X base = -base;
X }
X do{
X convert[place++] =
X (caps? "0123456789ABCDEF":"0123456789abcdef")
X [uvalue % (unsigned)base ];
X uvalue = (uvalue / (unsigned)base );
X }while(uvalue);
X convert[place] = 0;
X padlen = len - place;
X if( padlen < 0 ) padlen = 0;
X if( ljust ) padlen = -padlen;
X /* DEBUGP(( "str '%s', place %d, sign %c, padlen %d\n",
X convert,place,signvalue,padlen)); */
X if( zpad && padlen > 0 ){
X if( signvalue ){
X dopr_outch( signvalue );
X --padlen;
X signvalue = 0;
X }
X while( padlen > 0 ){
X dopr_outch( zpad );
X --padlen;
X }
X }
X while( padlen > 0 ) {
X dopr_outch( ' ' );
X --padlen;
X }
X if( signvalue ) dopr_outch( signvalue );
X while( place > 0 ) dopr_outch( convert[--place] );
X while( padlen < 0 ){
X dopr_outch( ' ' );
X ++padlen;
X }
}
X
static void dostr( str )
X char *str;
{
X while(*str) dopr_outch(*str++);
}
X
static void dopr_outch( c )
X int c;
{
X if( iscntrl(c) && c != '\n' && c != '\t' ){
X c = '@' + (c & 0x1F);
X if( end == 0 || output < end ){
X *output++ = '^';
X }
X }
X if( end == 0 || output < end ){
X *output++ = c;
X }
}
SHAR_EOF
$shar_touch -am 0829173595 'snprintf.c' &&
chmod 0644 'snprintf.c' ||
echo 'restore of snprintf.c failed'
shar_count="`wc -c < 'snprintf.c'`"
test 6630 -eq "$shar_count" ||
echo "snprintf.c: original size 6630, current size $shar_count"
fi
# ============= snprintf.h ==============
if test -f 'snprintf.h' && test X"$1" != X"-c"; then
echo 'x - skipping snprintf.h (file already exists)'
else
echo 'x - extracting snprintf.h (text)'
sed 's/^X//' << 'SHAR_EOF' > 'snprintf.h' &&
/* if you have configure you can use this */
#if defined(HAVE_CONFIG_H)
# include config.h
#endif
X
/* varargs declarations: */
/* you might have to hand force this by doing #define HAVE_STDARG_H */
X
#if defined(HAVE_STDARG_H)
# include <stdarg.h>
# define HAVE_STDARGS /* let's hope that works everywhere (mj) */
# define VA_LOCAL_DECL va_list ap;
# define VA_START(f) va_start(ap, f)
# define VA_SHIFT(v,t) ; /* no-op for ANSI */
# define VA_END va_end(ap)
#else
# if defined(HAVE_VARARGS_H)
# include <varargs.h>
# undef HAVE_STDARGS
# define VA_LOCAL_DECL va_list ap;
# define VA_START(f) va_start(ap) /* f is ignored! */
# define VA_SHIFT(v,t) v = va_arg(ap,t)
# define VA_END va_end(ap)
# else
XXX ** NO VARARGS ** XX
# endif
#endif
X
/* you can have ANSI C definitions */
#ifdef HAVE_STDARGS
int plp_snprintf (char *str, size_t count, const char *fmt, ...);
int vplp_snprintf (char *str, size_t count, const char *fmt, va_list arg);
void setproctitle( char *fmt, ... );
#else
int plp_snprintf ();
int vplp_snprintf ();
void setproctitle();
#endif
X
X
SHAR_EOF
$shar_touch -am 0829174095 'snprintf.h' &&
chmod 0644 'snprintf.h' ||
echo 'restore of snprintf.h failed'
shar_count="`wc -c < 'snprintf.h'`"
test 1100 -eq "$shar_count" ||
echo "snprintf.h: original size 1100, current size $shar_count"
fi
exit 0