Import of canonical tnftp 20030825 sources,

to make it easier to track new versions.
This commit is contained in:
lukem 2003-07-26 20:39:04 +00:00
parent b01a63d324
commit 264a9b906d
4 changed files with 1177 additions and 0 deletions

257
net/tnftp/files/aclocal.m4 vendored Normal file
View file

@ -0,0 +1,257 @@
dnl $Id: aclocal.m4,v 1.1.1.1 2003/07/26 20:39:04 lukem Exp $
dnl
dnl
dnl AC_MSG_TRY_COMPILE
dnl
dnl Written by Luke Mewburn <lukem@NetBSD.org>
dnl
dnl Usage:
dnl AC_MSG_TRY_COMPILE(Message, CacheVar, Includes, Code,
dnl ActionPass [,ActionFail] )
dnl
dnl effectively does:
dnl AC_CACHE_CHECK(Message, CacheVar,
dnl AC_TRY_COMPILE(Includes, Code, CacheVar = yes, CacheVar = no)
dnl if CacheVar == yes
dnl AC_MESSAGE_RESULT(yes)
dnl ActionPass
dnl else
dnl AC_MESSAGE_RESULT(no)
dnl ActionFail
dnl )
dnl
AC_DEFUN(AC_MSG_TRY_COMPILE, [
AC_CACHE_CHECK($1, $2, [
AC_TRY_COMPILE([ $3 ], [ $4; ], [ $2=yes ], [ $2=no ])
])
if test "x[$]$2" = "xyes"; then
$5
else
$6
:
fi
])
dnl
dnl AC_MSG_TRY_LINK
dnl
dnl Usage:
dnl AC_MSG_TRY_LINK(Message, CacheVar, Includes, Code,
dnl ActionPass [,ActionFail] )
dnl
dnl as AC_MSG_TRY_COMPILE, but uses AC_TRY_LINK instead of AC_TRY_COMPILE
dnl
AC_DEFUN(AC_MSG_TRY_LINK, [
AC_CACHE_CHECK($1, $2, [
AC_TRY_LINK([ $3 ], [ $4; ], [ $2=yes ], [ $2=no ])
])
if test "x[$]$2" = "xyes"; then
$5
else
$6
:
fi
])
dnl
dnl AC_LIBRARY_NET: #Id: net.m4,v 1.5 1997/11/09 21:36:54 jhawk Exp #
dnl
dnl Written by John Hawkinson <jhawk@mit.edu>. This code is in the Public
dnl Domain.
dnl
dnl This test is for network applications that need socket() and
dnl gethostbyname() -ish functions. Under Solaris, those applications need to
dnl link with "-lsocket -lnsl". Under IRIX, they should *not* link with
dnl "-lsocket" because libsocket.a breaks a number of things (for instance:
dnl gethostbyname() under IRIX 5.2, and snoop sockets under most versions of
dnl IRIX).
dnl
dnl Unfortunately, many application developers are not aware of this, and
dnl mistakenly write tests that cause -lsocket to be used under IRIX. It is
dnl also easy to write tests that cause -lnsl to be used under operating
dnl systems where neither are necessary (or useful), such as SunOS 4.1.4, which
dnl uses -lnsl for TLI.
dnl
dnl This test exists so that every application developer does not test this in
dnl a different, and subtly broken fashion.
dnl
dnl It has been argued that this test should be broken up into two seperate
dnl tests, one for the resolver libraries, and one for the libraries necessary
dnl for using Sockets API. Unfortunately, the two are carefully intertwined and
dnl allowing the autoconf user to use them independantly potentially results in
dnl unfortunate ordering dependancies -- as such, such component macros would
dnl have to carefully use indirection and be aware if the other components were
dnl executed. Since other autoconf macros do not go to this trouble, and almost
dnl no applications use sockets without the resolver, this complexity has not
dnl been implemented.
dnl
dnl The check for libresolv is in case you are attempting to link statically
dnl and happen to have a libresolv.a lying around (and no libnsl.a).
dnl
AC_DEFUN(AC_LIBRARY_NET, [
# Most operating systems have gethostbyname() in the default searched
# libraries (i.e. libc):
AC_CHECK_FUNC(gethostbyname, ,
# Some OSes (eg. Solaris) place it in libnsl:
AC_CHECK_LIB(nsl, gethostbyname, ,
# Some strange OSes (SINIX) have it in libsocket:
AC_CHECK_LIB(socket, gethostbyname, ,
# Unfortunately libsocket sometimes depends on libnsl.
# AC_CHECK_LIB's API is essentially broken so the following
# ugliness is necessary:
AC_CHECK_LIB(socket, gethostbyname,
LIBS="-lsocket -lnsl $LIBS",
AC_CHECK_LIB(resolv, gethostbyname),
-lnsl)
)
)
)
AC_CHECK_FUNC(socket, , AC_CHECK_LIB(socket, socket, ,
AC_CHECK_LIB(socket, socket, LIBS="-lsocket -lnsl $LIBS", , -lnsl)))
])
dnl Checks for SOCKS firewall support.
dnl
dnl Written by Matthew R. Green <mrg@eterna.com.au>
dnl
AC_DEFUN(AC_LIBRARY_SOCKS, [
AC_MSG_CHECKING(whether to support SOCKS)
AC_ARG_WITH(socks,
[ --with-socks Compile with SOCKS firewall traversal support.],
[
case "$withval" in
no)
AC_MSG_RESULT(no)
;;
yes)
AC_MSG_RESULT(yes)
AC_CHECK_LIB(socks5, SOCKSconnect, [
socks=5
LIBS="-lsocks5 $LIBS"], [
AC_CHECK_LIB(socks, Rconnect, [
socks=4
LIBS="-lsocks $LIBS"], [
AC_MSG_ERROR(Could not find socks library. You must first install socks.) ] ) ] )
;;
esac
],
AC_MSG_RESULT(no)
)
if test "x$socks" = "x"; then
AC_MSG_CHECKING(whether to support SOCKS5)
AC_ARG_WITH(socks5,
[ --with-socks5[=PATH] Compile with SOCKS5 firewall traversal support.],
[
case "$withval" in
no)
AC_MSG_RESULT(no)
;;
*)
AC_MSG_RESULT(yes)
socks=5
if test "x$withval" = "xyes"; then
withval="-lsocks5"
else
if test -d "$withval"; then
if test -d "$withval/include"; then
CFLAGS="$CFLAGS -I$withval/include"
else
CFLAGS="$CFLAGS -I$withval"
fi
if test -d "$withval/lib"; then
withval="-L$withval/lib -lsocks5"
else
withval="-L$withval -lsocks5"
fi
fi
fi
LIBS="$withval $LIBS"
# If Socks was compiled with Kerberos support, we will need
# to link against kerberos libraries. Temporarily append
# to LIBS. This is harmless if there is no kerberos support.
TMPLIBS="$LIBS"
LIBS="$LIBS $KERBEROS_LIBS"
AC_TRY_LINK([],
[ SOCKSconnect(); ],
[],
[ AC_MSG_ERROR(Could not find the $withval library. You must first install socks5.) ])
LIBS="$TMPLIBS"
;;
esac
],
AC_MSG_RESULT(no)
)
fi
if test "x$socks" = "x"; then
AC_MSG_CHECKING(whether to support SOCKS4)
AC_ARG_WITH(socks4,
[ --with-socks4[=PATH] Compile with SOCKS4 firewall traversal support.],
[
case "$withval" in
no)
AC_MSG_RESULT(no)
;;
*)
AC_MSG_RESULT(yes)
socks=4
if test "x$withval" = "xyes"; then
withval="-lsocks"
else
if test -d "$withval"; then
withval="-L$withval -lsocks"
fi
fi
LIBS="$withval $LIBS"
AC_TRY_LINK([],
[ Rconnect(); ],
[],
[ AC_MSG_ERROR(Could not find the $withval library. You must first install socks.) ])
;;
esac
],
AC_MSG_RESULT(no)
)
fi
if test "x$socks" = "x4"; then
AC_DEFINE(SOCKS)
AC_DEFINE(SOCKS4)
AC_DEFINE(connect, Rconnect)
AC_DEFINE(getsockname, Rgetsockname)
AC_DEFINE(bind, Rbind)
AC_DEFINE(accept, Raccept)
AC_DEFINE(listen, Rlisten)
AC_DEFINE(select, Rselect)
fi
if test "x$socks" = "x5"; then
AC_DEFINE(SOCKS)
AC_DEFINE(SOCKS5)
AC_DEFINE(connect,SOCKSconnect)
AC_DEFINE(getsockname,SOCKSgetsockname)
AC_DEFINE(getpeername,SOCKSgetpeername)
AC_DEFINE(bind,SOCKSbind)
AC_DEFINE(accept,SOCKSaccept)
AC_DEFINE(listen,SOCKSlisten)
AC_DEFINE(select,SOCKSselect)
AC_DEFINE(recvfrom,SOCKSrecvfrom)
AC_DEFINE(sendto,SOCKSsendto)
AC_DEFINE(recv,SOCKSrecv)
AC_DEFINE(send,SOCKSsend)
AC_DEFINE(read,SOCKSread)
AC_DEFINE(write,SOCKSwrite)
AC_DEFINE(rresvport,SOCKSrresvport)
AC_DEFINE(shutdown,SOCKSshutdown)
AC_DEFINE(listen,SOCKSlisten)
AC_DEFINE(close,SOCKSclose)
AC_DEFINE(dup,SOCKSdup)
AC_DEFINE(dup2,SOCKSdup2)
AC_DEFINE(fclose,SOCKSfclose)
AC_DEFINE(gethostbyname,SOCKSgethostbyname)
fi
])

View file

@ -0,0 +1,92 @@
/* $Id: err.c,v 1.1.1.1 2003/07/26 20:39:05 lukem Exp $ */
/*
* Copyright 1997-2000 Luke Mewburn <lukem@NetBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "tnftp.h"
void
err(int eval, const char *fmt, ...)
{
va_list ap;
int sverrno;
sverrno = errno;
(void)fprintf(stderr, "%s: ", getprogname());
va_start(ap, fmt);
if (fmt != NULL) {
(void)vfprintf(stderr, fmt, ap);
(void)fprintf(stderr, ": ");
}
va_end(ap);
(void)fprintf(stderr, "%s\n", strerror(sverrno));
exit(eval);
}
void
errx(int eval, const char *fmt, ...)
{
va_list ap;
(void)fprintf(stderr, "%s: ", getprogname());
va_start(ap, fmt);
if (fmt != NULL)
(void)vfprintf(stderr, fmt, ap);
va_end(ap);
(void)fprintf(stderr, "\n");
exit(eval);
}
void
warn(const char *fmt, ...)
{
va_list ap;
int sverrno;
sverrno = errno;
(void)fprintf(stderr, "%s: ", getprogname());
va_start(ap, fmt);
if (fmt != NULL) {
(void)vfprintf(stderr, fmt, ap);
(void)fprintf(stderr, ": ");
}
va_end(ap);
(void)fprintf(stderr, "%s\n", strerror(sverrno));
}
void
warnx(const char *fmt, ...)
{
va_list ap;
(void)fprintf(stderr, "%s: ", getprogname());
va_start(ap, fmt);
if (fmt != NULL)
(void)vfprintf(stderr, fmt, ap);
va_end(ap);
(void)fprintf(stderr, "\n");
}

View file

@ -0,0 +1,40 @@
/* $Id: fseeko.c,v 1.1.1.1 2003/07/26 20:39:05 lukem Exp $ */
/*
* Copyright 2002 Luke Mewburn <lukem@NetBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "tnftp.h"
int
fseeko(FILE *stream, off_t offset, int whence)
{
if (offset > (off_t)LONG_MAX) {
errno = EINVAL;
return (-1);
}
return (fseek(stream, (long) offset, whence));
}

View file

@ -0,0 +1,788 @@
/* $Id: snprintf.c,v 1.1.1.1 2003/07/26 20:39:05 lukem Exp $ */
/*
* Copyright Patrick Powell 1995
* This code is based on code written by Patrick Powell (papowell@astart.com)
* It may be used for any purpose as long as this notice remains intact
* on all source code distributions
*/
/**************************************************************
* Original:
* Patrick Powell Tue Apr 11 09:48:21 PDT 1995
* A bombproof version of doprnt (dopr) included.
* Sigh. This sort of thing is always nasty do deal with. Note that
* the version here does not include floating point...
*
* snprintf() is used instead of sprintf() as it does limit checks
* for string length. This covers a nasty loophole.
*
* The other functions are there to prevent NULL pointers from
* causing nast effects.
*
* More Recently:
* Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
* This was ugly. It is still ugly. I opted out of floating point
* numbers, but the formatter understands just about everything
* from the normal C string format, at least as far as I can tell from
* the Solaris 2.5 printf(3S) man page.
*
* Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
* Ok, added some minimal floating point support, which means this
* probably requires libm on most operating systems. Don't yet
* support the exponent (e,E) and sigfig (g,G). Also, fmtint()
* was pretty badly broken, it just wasn't being exercised in ways
* which showed it, so that's been fixed. Also, formated the code
* to mutt conventions, and removed dead code left over from the
* original. Also, there is now a builtin-test, just compile with:
* gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
* and run snprintf for results.
*
* Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
* The PGP code was using unsigned hexadecimal formats.
* Unfortunately, unsigned formats simply didn't work.
*
* Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
* The original code assumed that both snprintf() and vsnprintf() were
* missing. Some systems only have snprintf() but not vsnprintf(), so
* the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
*
* Andrew Tridgell (tridge@samba.org) Oct 1998
* fixed handling of %.0f
* added test for HAVE_LONG_DOUBLE
*
* Luke Mewburn <lukem@NetBSD.org>, Thu Sep 30 23:28:21 EST 1999
* cleaned up formatting, autoconf tests
* added long long support
*
**************************************************************/
#include "tnftp.h"
#if HAVE_LONG_DOUBLE
#define LDOUBLE long double
#else
#define LDOUBLE double
#endif
#if HAVE_LONG_LONG
#define LLONG long long
#else
#define LLONG long
#endif
static void dopr(char *buffer, size_t maxlen, size_t *retlen,
const char *format, va_list args);
static void fmtstr(char *buffer, size_t * currlen, size_t maxlen,
char *value, int min, int max, int flags);
static void fmtint(char *buffer, size_t * currlen, size_t maxlen,
LLONG value, int base, int min, int max, int flags);
static void fmtfp(char *buffer, size_t * currlen, size_t maxlen,
LDOUBLE fvalue, int min, int max, int flags);
static void dopr_outch(char *buffer, size_t * currlen, size_t maxlen, int c);
/*
* dopr(): poor man's version of doprintf
*/
/* format read states */
#define DP_S_DEFAULT 0
#define DP_S_FLAGS 1
#define DP_S_MIN 2
#define DP_S_DOT 3
#define DP_S_MAX 4
#define DP_S_MOD 5
#define DP_S_CONV 6
#define DP_S_DONE 7
/* format flags - Bits */
#define DP_F_MINUS (1 << 0)
#define DP_F_PLUS (1 << 1)
#define DP_F_SPACE (1 << 2)
#define DP_F_NUM (1 << 3)
#define DP_F_ZERO (1 << 4)
#define DP_F_UP (1 << 5)
#define DP_F_UNSIGNED (1 << 6)
/* Conversion Flags */
#define DP_C_SHORT 1
#define DP_C_LONG 2
#define DP_C_LDOUBLE 3
#define DP_C_LLONG 4
#define char_to_int(p) (p - '0')
static void
dopr(char *buffer, size_t maxlen, size_t *retlen, const char *format,
va_list args)
{
char ch;
LLONG value;
LDOUBLE fvalue;
char *strvalue;
int min;
int max;
int state;
int flags;
int cflags;
size_t currlen;
state = DP_S_DEFAULT;
flags = currlen = cflags = min = 0;
max = -1;
ch = *format++;
while (state != DP_S_DONE) {
if ((ch == '\0') || (currlen >= maxlen))
state = DP_S_DONE;
switch (state) {
case DP_S_DEFAULT:
if (ch == '%')
state = DP_S_FLAGS;
else
dopr_outch(buffer, &currlen, maxlen, ch);
ch = *format++;
break;
case DP_S_FLAGS:
switch (ch) {
case '-':
flags |= DP_F_MINUS;
ch = *format++;
break;
case '+':
flags |= DP_F_PLUS;
ch = *format++;
break;
case ' ':
flags |= DP_F_SPACE;
ch = *format++;
break;
case '#':
flags |= DP_F_NUM;
ch = *format++;
break;
case '0':
flags |= DP_F_ZERO;
ch = *format++;
break;
default:
state = DP_S_MIN;
break;
}
break;
case DP_S_MIN:
if (isdigit((unsigned char) ch)) {
min = 10 * min + char_to_int(ch);
ch = *format++;
} else if (ch == '*') {
min = va_arg(args, int);
ch = *format++;
state = DP_S_DOT;
} else
state = DP_S_DOT;
break;
case DP_S_DOT:
if (ch == '.') {
state = DP_S_MAX;
ch = *format++;
} else
state = DP_S_MOD;
break;
case DP_S_MAX:
if (isdigit((unsigned char) ch)) {
if (max < 0)
max = 0;
max = 10 * max + char_to_int(ch);
ch = *format++;
} else if (ch == '*') {
max = va_arg(args, int);
ch = *format++;
state = DP_S_MOD;
} else
state = DP_S_MOD;
break;
case DP_S_MOD:
switch (ch) {
case 'h':
cflags = DP_C_SHORT;
ch = *format++;
break;
case 'l':
if (*format == 'l') {
cflags = DP_C_LLONG;
format++;
} else
cflags = DP_C_LONG;
ch = *format++;
break;
case 'q':
cflags = DP_C_LLONG;
ch = *format++;
break;
case 'L':
cflags = DP_C_LDOUBLE;
ch = *format++;
break;
default:
break;
}
state = DP_S_CONV;
break;
case DP_S_CONV:
switch (ch) {
case 'd':
case 'i':
switch (cflags) {
case DP_C_SHORT:
value = va_arg(args, int);
break;
case DP_C_LONG:
value = va_arg(args, long int);
break;
case DP_C_LLONG:
value = va_arg(args, LLONG);
break;
default:
value = va_arg(args, int);
break;
}
fmtint(buffer, &currlen, maxlen, value, 10,
min, max, flags);
break;
case 'X':
flags |= DP_F_UP;
/* FALLTHROUGH */
case 'x':
case 'o':
case 'u':
flags |= DP_F_UNSIGNED;
switch (cflags) {
case DP_C_SHORT:
value = va_arg(args, unsigned int);
break;
case DP_C_LONG:
value = (LLONG) va_arg(args,
unsigned long int);
break;
case DP_C_LLONG:
value = va_arg(args, unsigned LLONG);
break;
default:
value = (LLONG) va_arg(args,
unsigned int);
break;
}
fmtint(buffer, &currlen, maxlen, value,
ch == 'o' ? 8 : (ch == 'u' ? 10 : 16),
min, max, flags);
break;
case 'f':
if (cflags == DP_C_LDOUBLE)
fvalue = va_arg(args, LDOUBLE);
else
fvalue = va_arg(args, double);
/* um, floating point? */
fmtfp(buffer, &currlen, maxlen, fvalue, min,
max, flags);
break;
case 'E':
flags |= DP_F_UP;
case 'e':
if (cflags == DP_C_LDOUBLE)
fvalue = va_arg(args, LDOUBLE);
else
fvalue = va_arg(args, double);
break;
case 'G':
flags |= DP_F_UP;
case 'g':
if (cflags == DP_C_LDOUBLE)
fvalue = va_arg(args, LDOUBLE);
else
fvalue = va_arg(args, double);
break;
case 'c':
dopr_outch(buffer, &currlen, maxlen,
va_arg(args, int));
break;
case 's':
strvalue = va_arg(args, char *);
if (max < 0)
max = maxlen; /* ie, no max */
fmtstr(buffer, &currlen, maxlen, strvalue,
min, max, flags);
break;
case 'p':
value = (long)va_arg(args, void *);
fmtint(buffer, &currlen, maxlen,
value, 16, min, max, flags);
break;
case 'n':
/* XXX */
if (cflags == DP_C_SHORT) {
short int *num;
num = va_arg(args, short int *);
*num = currlen;
} else if (cflags == DP_C_LONG) { /* XXX */
long int *num;
num = va_arg(args, long int *);
*num = (long int) currlen;
} else if (cflags == DP_C_LLONG) { /* XXX */
LLONG *num;
num = va_arg(args, LLONG *);
*num = (LLONG) currlen;
} else {
int *num;
num = va_arg(args, int *);
*num = currlen;
}
break;
case '%':
dopr_outch(buffer, &currlen, maxlen, ch);
break;
case 'w':
/* not supported yet, treat as next char */
ch = *format++;
break;
default:
/* Unknown, skip */
break;
}
ch = *format++;
state = DP_S_DEFAULT;
flags = cflags = min = 0;
max = -1;
break;
case DP_S_DONE:
break;
default:
/* hmm? */
break; /* some picky compilers need this */
}
}
if (currlen >= maxlen - 1)
currlen = maxlen - 1;
buffer[currlen] = '\0';
*retlen = currlen;
}
static void
fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value,
int min, int max, int flags)
{
int padlen, strln; /* amount to pad */
int cnt = 0;
if (value == 0) {
value = "<NULL>";
}
for (strln = 0; value[strln]; ++strln)
; /* strlen */
padlen = min - strln;
if (padlen < 0)
padlen = 0;
if (flags & DP_F_MINUS)
padlen = -padlen; /* Left Justify */
while ((padlen > 0) && (cnt < max)) {
dopr_outch(buffer, currlen, maxlen, ' ');
--padlen;
++cnt;
}
while (*value && (cnt < max)) {
dopr_outch(buffer, currlen, maxlen, *value++);
++cnt;
}
while ((padlen < 0) && (cnt < max)) {
dopr_outch(buffer, currlen, maxlen, ' ');
++padlen;
++cnt;
}
}
/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */
static void
fmtint(char *buffer, size_t *currlen, size_t maxlen, LLONG value, int base,
int min, int max, int flags)
{
int signvalue = 0;
unsigned LLONG uvalue;
char convert[20];
int place = 0;
int spadlen = 0; /* amount to space pad */
int zpadlen = 0; /* amount to zero pad */
int caps = 0;
if (max < 0)
max = 0;
uvalue = value;
if (!(flags & DP_F_UNSIGNED)) {
if (value < 0) {
signvalue = '-';
uvalue = -value;
} else if (flags & DP_F_PLUS) /* Do a sign (+/i) */
signvalue = '+';
else if (flags & DP_F_SPACE)
signvalue = ' ';
}
if (flags & DP_F_UP)
caps = 1; /* Should characters be upper case? */
do {
convert[place++] =
(caps ? "0123456789ABCDEF" : "0123456789abcdef")
[uvalue % (unsigned) base];
uvalue = (uvalue / (unsigned) base);
} while (uvalue && (place < 20));
if (place == 20)
place--;
convert[place] = 0;
zpadlen = max - place;
spadlen = min - MAX(max, place) - (signvalue ? 1 : 0);
if (zpadlen < 0)
zpadlen = 0;
if (spadlen < 0)
spadlen = 0;
if (flags & DP_F_ZERO) {
zpadlen = MAX(zpadlen, spadlen);
spadlen = 0;
}
if (flags & DP_F_MINUS)
spadlen = -spadlen; /* Left Justifty */
#ifdef DEBUG_SNPRINTF
printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
zpadlen, spadlen, min, max, place);
#endif
/* Spaces */
while (spadlen > 0) {
dopr_outch(buffer, currlen, maxlen, ' ');
--spadlen;
}
/* Sign */
if (signvalue)
dopr_outch(buffer, currlen, maxlen, signvalue);
/* Zeros */
if (zpadlen > 0) {
while (zpadlen > 0) {
dopr_outch(buffer, currlen, maxlen, '0');
--zpadlen;
}
}
/* Digits */
while (place > 0)
dopr_outch(buffer, currlen, maxlen, convert[--place]);
/* Left Justified spaces */
while (spadlen < 0) {
dopr_outch(buffer, currlen, maxlen, ' ');
++spadlen;
}
}
static LDOUBLE
abs_val(LDOUBLE value)
{
LDOUBLE result = value;
if (value < 0)
result = -value;
return result;
}
static LDOUBLE
pow10(int exp)
{
LDOUBLE result = 1;
while (exp) {
result *= 10;
exp--;
}
return result;
}
static long
round(LDOUBLE value)
{
long intpart;
intpart = (long) value;
value = value - intpart;
if (value >= 0.5)
intpart++;
return intpart;
}
static void
fmtfp(char *buffer, size_t *currlen, size_t maxlen, LDOUBLE fvalue,
int min, int max, int flags)
{
int signvalue = 0;
LDOUBLE ufvalue;
char iconvert[20];
char fconvert[20];
int iplace = 0;
int fplace = 0;
int padlen = 0; /* amount to pad */
int zpadlen = 0;
int caps = 0;
long intpart;
long fracpart;
/* AIX manpage says the default is 0, but Solaris says the default is
* 6, and sprintf on AIX defaults to 6 */
if (max < 0)
max = 6;
ufvalue = abs_val(fvalue);
if (fvalue < 0)
signvalue = '-';
else if (flags & DP_F_PLUS) /* Do a sign (+/i) */
signvalue = '+';
else if (flags & DP_F_SPACE)
signvalue = ' ';
#if 0
if (flags & DP_F_UP)
caps = 1; /* Should characters be upper case? */
#endif
intpart = (long) ufvalue;
/* Sorry, we only support 9 digits past the decimal because of our
* conversion method */
if (max > 9)
max = 9;
/* We "cheat" by converting the fractional part to integer by
* multiplying by a factor of 10 */
fracpart = round((pow10(max)) * (ufvalue - intpart));
if (fracpart >= pow10(max)) {
intpart++;
fracpart -= pow10(max);
}
#ifdef DEBUG_SNPRINTF
printf("fmtfp: %g %d.%d min=%d max=%d\n",
(double) fvalue, intpart, fracpart, min, max);
#endif
/* Convert integer part */
do {
iconvert[iplace++] =
(caps ? "0123456789ABCDEF"
: "0123456789abcdef")[intpart % 10];
intpart = (intpart / 10);
} while (intpart && (iplace < 20));
if (iplace == 20)
iplace--;
iconvert[iplace] = 0;
/* Convert fractional part */
do {
fconvert[fplace++] =
(caps ? "0123456789ABCDEF"
: "0123456789abcdef")[fracpart % 10];
fracpart = (fracpart / 10);
} while (fracpart && (fplace < 20));
if (fplace == 20)
fplace--;
fconvert[fplace] = 0;
/* -1 for decimal point, another -1 if we are printing a sign */
padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0);
zpadlen = max - fplace;
if (zpadlen < 0)
zpadlen = 0;
if (padlen < 0)
padlen = 0;
if (flags & DP_F_MINUS)
padlen = -padlen; /* Left Justifty */
if ((flags & DP_F_ZERO) && (padlen > 0)) {
if (signvalue) {
dopr_outch(buffer, currlen, maxlen, signvalue);
--padlen;
signvalue = 0;
}
while (padlen > 0) {
dopr_outch(buffer, currlen, maxlen, '0');
--padlen;
}
}
while (padlen > 0) {
dopr_outch(buffer, currlen, maxlen, ' ');
--padlen;
}
if (signvalue)
dopr_outch(buffer, currlen, maxlen, signvalue);
while (iplace > 0)
dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);
#ifdef DEBUG_SNPRINTF
printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen);
#endif
/*
* Decimal point. This should probably use locale to find the correct
* char to print out.
*/
if (max > 0) {
dopr_outch(buffer, currlen, maxlen, '.');
while (fplace > 0)
dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);
}
while (zpadlen > 0) {
dopr_outch(buffer, currlen, maxlen, '0');
--zpadlen;
}
while (padlen < 0) {
dopr_outch(buffer, currlen, maxlen, ' ');
++padlen;
}
}
static void
dopr_outch(char *buffer, size_t *currlen, size_t maxlen, int c)
{
if (*currlen < maxlen)
buffer[(*currlen)++] = (char)c;
}
int
vsnprintf(char *str, size_t count, const char *fmt, va_list args)
{
size_t retlen;
str[0] = 0;
dopr(str, count, &retlen, fmt, args);
return (retlen);
}
/* VARARGS3 */
int
snprintf(char *str, size_t count, const char *fmt, ...)
{
va_list ap;
int rv;
va_start(ap, fmt);
rv = vsnprintf(str, count, fmt, ap);
va_end(ap);
return (rv);
}
#ifdef TEST_SNPRINTF
#ifndef LONG_STRING
#define LONG_STRING 1024
#endif
int
main(int argc, char *argv[])
{
char buf1[LONG_STRING];
char buf2[LONG_STRING];
char *fp_fmt[] = {
"%-1.5f",
"%1.5f",
"%123.9f",
"%10.5f",
"% 10.5f",
"%+22.9f",
"%+4.9f",
"%01.3f",
"%4f",
"%3.1f",
"%3.2f",
"%.0f",
"%.1f",
NULL
};
double fp_nums[] = {
-1.5, 134.21, 91340.2, 341.1234, 0203.9,
0.96, 0.996, 0.9996, 1.996, 4.136,
0
};
char *int_fmt[] = {
"%-1.5d",
"%1.5d",
"%123.9d",
"%5.5d",
"%10.5d",
"% 10.5d",
"%+22.33d",
"%01.3d",
"%4d",
#if HAVE_LONG_LONG
"%12lld",
#endif
NULL
};
LLONG int_nums[] = {
-1, 134, 91340, 341, 0203,
4294967290,
4294967297,
0
};
int x, y;
int fail = 0;
int num = 0;
int len;
printf("Testing snprintf format codes against system sprintf...\n");
for (x = 0; fp_fmt[x] != NULL; x++) {
printf("testing %s\n", fp_fmt[x]);
for (y = 0; fp_nums[y] != 0; y++) {
snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]);
sprintf(buf2, fp_fmt[x], fp_nums[y]);
if (strcmp(buf1, buf2)) {
printf("snprintf doesn't match Format: %s\n",
fp_fmt[x]);
printf("\tsnprintf = %s\n\tsprintf = %s\n",
buf1, buf2);
fail++;
}
num++;
}
}
for (x = 0; int_fmt[x] != NULL; x++) {
printf("testing %s\n", int_fmt[x]);
for (y = 0; int_nums[y] != 0; y++) {
len = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]);
printf("got %d >%s< (%d)\n", len, buf1, (int)strlen(buf1));
sprintf(buf2, int_fmt[x], int_nums[y]);
if (strcmp(buf1, buf2)) {
printf("snprintf doesn't match Format: %s\n",
int_fmt[x]);
printf("\tsnprintf = %s\n\tsprintf = %s\n",
buf1, buf2);
fail++;
}
num++;
}
}
printf("%d tests failed out of %d.\n", fail, num);
exit(0);
}
#endif /* TEST_SNPRINTF */