
snprintf

Patrick Powell (papowell@sdsu.edu)
Wed, 30 Aug 1995 09:40:29 -0700 
  *	Messages sorted by: [ date ][ thread ][ subject ][ author ] 
  *	Next message: Tim Scanlon: "Re: 
	[8lgm]-Advisory-22.UNIX.syslog.2-Aug-1995" 
  *	Previous message: Martin Hargreaves: "httpd symlinks, was Re: 
	[8lgm]-Advisory-22.UNIX.syslog.2-Aug-1995" 

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


  *	Next message: Tim Scanlon: "Re: 
	[8lgm]-Advisory-22.UNIX.syslog.2-Aug-1995" 
  *	Previous message: Martin Hargreaves: "httpd symlinks, was Re: 
	[8lgm]-Advisory-22.UNIX.syslog.2-Aug-1995" 
