Commit b478e91f authored by Ulf Möller's avatar Ulf Möller
Browse files

different snprintf version.

parent 935a50e8
Loading
Loading
Loading
Loading
+575 −566
Original line number Diff line number Diff line
@@ -62,11 +62,20 @@

#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include "cryptlib.h"
#include <openssl/bio.h>

static void dopr (char *buffer, size_t maxlen, const char *format, 
                  va_list args);
#ifdef BN_LLONG
# ifndef HAVE_LONG_LONG
#  define HAVE_LONG_LONG
# endif
#endif

static void dopr (char *buffer, size_t maxlen, size_t *retlen,
	const char *format, va_list args);

int BIO_printf (BIO *bio, ...)
	{
@@ -79,10 +88,8 @@ int BIO_printf (BIO *bio, ...)
	format=va_arg(args, char *);

	hugebuf[0]='\0';

	dopr(hugebuf, sizeof(hugebuf), format, args);

	ret=BIO_write(bio,hugebuf,strlen(hugebuf));
	dopr(hugebuf, sizeof(hugebuf), &ret, format, args);
	ret=BIO_write(bio, hugebuf, ret);

	va_end(args);
	return(ret);
@@ -90,28 +97,42 @@ int BIO_printf (BIO *bio, ...)

/*
 * Copyright Patrick Powell 1995
 * This code is based on code written by Patrick Powell (papowell@astart.com)
 * 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
 * on all source code distributions.
 */

#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <stdarg.h>

static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
		    char *value, int flags, int min, int max);
static void fmtint (char *buffer, size_t *currlen, size_t maxlen,
		    long value, int base, int min, int max, int flags);
static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
		   long double fvalue, int min, int max, int flags);
static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );

/*
 * dopr(): poor man's version of doprintf
 * This code contains numerious changes and enhancements which were
 * made by lots of contributors over the last years to Patrick Powell's
 * original code:
 *
 * o Patrick Powell <papowell@astart.com>      (1995)
 * o Brandon Long <blong@fiction.net>          (1996, for Mutt)
 * o Thomas Roessler <roessler@guug.de>        (1998, for Mutt)
 * o Michael Elkins <me@cs.hmc.edu>            (1998, for Mutt)
 * o Andrew Tridgell <tridge@samba.org>        (1998, for Samba)
 * o Luke Mewburn <lukem@netbsd.org>           (1999, for LukemFTP)
 * o Ralf S. Engelschall <rse@engelschall.com> (1999, for Pth)
 */

#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 fmtstr     (char *, size_t *, size_t, char *, int, int, int);
static void fmtint     (char *, size_t *, size_t, LLONG, int, int, int, int);
static void fmtfp      (char *, size_t *, size_t, LDOUBLE, int, int, int);
static void dopr_outch (char *, size_t *, size_t, int);

/* format read states */
#define DP_S_DEFAULT    0
#define DP_S_FLAGS      1
@@ -131,19 +152,27 @@ static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c );
#define DP_F_UP         (1 << 5)
#define DP_F_UNSIGNED   (1 << 6)

/* Conversion Flags */
/* conversion flags */
#define DP_C_SHORT      1
#define DP_C_LONG       2
#define DP_C_LDOUBLE    3
#define DP_C_LLONG      4

/* some handy macros */
#define char_to_int(p) (p - '0')
#define MAX(p,q) ((p >= q) ? p : q)

static void dopr (char *buffer, size_t maxlen, const char *format, va_list args)
static void
dopr(
    char *buffer,
    size_t maxlen,
    size_t *retlen,
    const char *format,
    va_list args)
{
    char ch;
  long value;
  long double fvalue;
    LLONG value;
    LDOUBLE fvalue;
    char *strvalue;
    int min;
    int max;
@@ -153,17 +182,15 @@ static void dopr (char *buffer, size_t maxlen, const char *format, va_list args)
    size_t currlen;

    state = DP_S_DEFAULT;
  currlen = flags = cflags = min = 0;
    flags = currlen = cflags = min = 0;
    max = -1;
    ch = *format++;

  while (state != DP_S_DONE)
  {
    while (state != DP_S_DONE) {
        if ((ch == '\0') || (currlen >= maxlen))
            state = DP_S_DONE;

    switch(state) 
    {
        switch (state) {
        case DP_S_DEFAULT:
            if (ch == '%')
                state = DP_S_FLAGS;
@@ -172,8 +199,7 @@ static void dopr (char *buffer, size_t maxlen, const char *format, va_list args)
            ch = *format++;
            break;
        case DP_S_FLAGS:
      switch (ch) 
      {
            switch (ch) {
            case '-':
                flags |= DP_F_MINUS;
                ch = *format++;
@@ -200,58 +226,54 @@ static void dopr (char *buffer, size_t maxlen, const char *format, va_list args)
            }
            break;
        case DP_S_MIN:
      if (isdigit((unsigned char)ch)) 
      {
            if (isdigit((unsigned char)ch)) {
                min = 10 * min + char_to_int(ch);
                ch = *format++;
      } 
      else if (ch == '*') 
      {
            } else if (ch == '*') {
                min = va_arg(args, int);
                ch = *format++;
                state = DP_S_DOT;
      } 
      else 
            } else
                state = DP_S_DOT;
            break;
        case DP_S_DOT:
      if (ch == '.') 
      {
            if (ch == '.') {
                state = DP_S_MAX;
                ch = *format++;
      } 
      else 
            } else
                state = DP_S_MOD;
            break;
        case DP_S_MAX:
      if (isdigit((unsigned char)ch)) 
      {
            if (isdigit((unsigned char)ch)) {
                if (max < 0)
                    max = 0;
                max = 10 * max + char_to_int(ch);
                ch = *format++;
      } 
      else if (ch == '*') 
      {
            } else if (ch == '*') {
                max = va_arg(args, int);
                ch = *format++;
                state = DP_S_MOD;
      } 
      else 
            } else
                state = DP_S_MOD;
            break;
        case DP_S_MOD:
      /* Currently, we don't support Long Long, bummer */
      switch (ch) 
      {
            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++;
@@ -262,63 +284,65 @@ static void dopr (char *buffer, size_t maxlen, const char *format, va_list args)
            state = DP_S_CONV;
            break;
        case DP_S_CONV:
      switch (ch) 
      {
            switch (ch) {
            case 'd':
            case 'i':
	if (cflags == DP_C_SHORT) 
                switch (cflags) {
                case DP_C_SHORT:
                    value = va_arg(args, short int);
	else if (cflags == DP_C_LONG)
                    break;
                case DP_C_LONG:
                    value = va_arg(args, long int);
	else
	  value = va_arg (args, int);
	fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
                    break;
      case 'o':
	flags |= DP_F_UNSIGNED;
	if (cflags == DP_C_SHORT)
	  value = va_arg (args, unsigned short int);
	else if (cflags == DP_C_LONG)
	  value = va_arg (args, unsigned long int);
	else
	  value = va_arg (args, unsigned int);
	fmtint (buffer, &currlen, maxlen, value, 8, min, max, flags);
                case DP_C_LLONG:
                    value = va_arg(args, LLONG);
                    break;
      case 'u':
	flags |= DP_F_UNSIGNED;
	if (cflags == DP_C_SHORT)
	  value = va_arg (args, unsigned short int);
	else if (cflags == DP_C_LONG)
	  value = va_arg (args, unsigned long int);
	else
	  value = va_arg (args, unsigned int);
                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;
	if (cflags == DP_C_SHORT)
	  value = va_arg (args, unsigned short int);
	else if (cflags == DP_C_LONG)
	  value = va_arg (args, unsigned long int);
	else
	  value = va_arg (args, unsigned int);
	fmtint (buffer, &currlen, maxlen, value, 16, min, max, flags);
                switch (cflags) {
                case DP_C_SHORT:
                    value = va_arg(args,
                        unsigned short 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, long double);
                    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, long double);
                    fvalue = va_arg(args, LDOUBLE);
                else
                    fvalue = va_arg(args, double);
                break;
@@ -326,38 +350,40 @@ static void dopr (char *buffer, size_t maxlen, const char *format, va_list args)
                flags |= DP_F_UP;
            case 'g':
                if (cflags == DP_C_LDOUBLE)
	  fvalue = va_arg (args, long double);
                    fvalue = va_arg(args, LDOUBLE);
                else
                    fvalue = va_arg(args, double);
                break;
            case 'c':
	dopr_outch (buffer, &currlen, maxlen, va_arg (args, int));
                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, flags, min, max);
                    max = maxlen;
                fmtstr(buffer, &currlen, maxlen, strvalue,
                    flags, min, max);
                break;
            case 'p':
	strvalue = va_arg (args, void *);
	fmtint (buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
                value = (long)va_arg(args, void *);
                fmtint(buffer, &currlen, maxlen,
                    value, 16, min, max, flags);
                break;
      case 'n':
	if (cflags == DP_C_SHORT) 
	{
            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) 
	{
                } else if (cflags == DP_C_LONG) { /* XXX */
                    long int *num;
                    num = va_arg(args, long int *);
	  *num = currlen;
        } 
	else 
	{
                    *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;
@@ -371,7 +397,7 @@ static void dopr (char *buffer, size_t maxlen, const char *format, va_list args)
                ch = *format++;
                break;
            default:
	/* Unknown, skip */
                /* unknown, skip */
                break;
            }
            ch = *format++;
@@ -382,257 +408,239 @@ static void dopr (char *buffer, size_t maxlen, const char *format, va_list args)
        case DP_S_DONE:
            break;
        default:
      /* hmm? */
      break; /* some picky compilers need this */
            break;
        }
    }
  if (currlen < maxlen - 1) 
    if (currlen >= maxlen - 1)
        currlen = maxlen - 1;
    buffer[currlen] = '\0';
  else 
    buffer[maxlen - 1] = '\0';
    *retlen = currlen;
    return;
}

static void fmtstr (char *buffer, size_t *currlen, size_t maxlen,
		    char *value, int flags, int min, int max)
static void
fmtstr(
    char *buffer,
    size_t *currlen,
    size_t maxlen,
    char *value,
    int flags,
    int min,
    int max)
{
  int padlen, strln;     /* amount to pad */
    int padlen, strln;
    int cnt = 0;

    if (value == 0)
  {
        value = "<NULL>";
  }

  for (strln = 0; value[strln]; ++strln); /* strlen */
    for (strln = 0; value[strln]; ++strln)
        ;
    padlen = min - strln;
    if (padlen < 0)
        padlen = 0;
    if (flags & DP_F_MINUS)
    padlen = -padlen; /* Left Justify */
        padlen = -padlen;

  while ((padlen > 0) && (cnt < max)) 
  {
    while ((padlen > 0) && (cnt < max)) {
        dopr_outch(buffer, currlen, maxlen, ' ');
        --padlen;
        ++cnt;
    }
  while (*value && (cnt < max)) 
  {
    while (*value && (cnt < max)) {
        dopr_outch(buffer, currlen, maxlen, *value++);
        ++cnt;
    }
  while ((padlen < 0) && (cnt < max)) 
  {
    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,
		    long value, int base, 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)
{
    int signvalue = 0;
  unsigned long uvalue;
    unsigned LLONG uvalue;
    char convert[20];
    int place = 0;
  int spadlen = 0; /* amount to space pad */
  int zpadlen = 0; /* amount to zero pad */
    int spadlen = 0;
    int zpadlen = 0;
    int caps = 0;

    if (max < 0)
        max = 0;

    uvalue = value;

  if(!(flags & DP_F_UNSIGNED))
  {
    if (!(flags & DP_F_UNSIGNED)) {
        if (value < 0) {
            signvalue = '-';
            uvalue = -value;
    }
    else
      if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
        } else if (flags & DP_F_PLUS)
            signvalue = '+';
    else
      if (flags & DP_F_SPACE)
        else if (flags & DP_F_SPACE)
            signvalue = ' ';
    }
  
  if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */

    if (flags & DP_F_UP)
        caps = 1;
    do {
        convert[place++] =
            (caps ? "0123456789ABCDEF" : "0123456789abcdef")
            [uvalue % (unsigned) base];
        uvalue = (uvalue / (unsigned) base);
    } while (uvalue && (place < 20));
  if (place == 20) place--;
    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)
  {
    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 */
        spadlen = -spadlen;

#ifdef DEBUG_SNPRINTF
  dprint (1, (debugfile, "zpad: %d, spad: %d, min: %d, max: %d, place: %d\n",
      zpadlen, spadlen, min, max, place));
#endif

  /* Spaces */
  while (spadlen > 0) 
  {
    /* spaces */
    while (spadlen > 0) {
        dopr_outch(buffer, currlen, maxlen, ' ');
        --spadlen;
    }

  /* Sign */
    /* sign */
    if (signvalue)
        dopr_outch(buffer, currlen, maxlen, signvalue);

  /* Zeros */
  if (zpadlen > 0) 
  {
    while (zpadlen > 0)
    {
    /* zeros */
    if (zpadlen > 0) {
        while (zpadlen > 0) {
            dopr_outch(buffer, currlen, maxlen, '0');
            --zpadlen;
        }
    }

  /* Digits */
    /* digits */
    while (place > 0)
        dopr_outch(buffer, currlen, maxlen, convert[--place]);

  /* Left Justified spaces */
    /* left justified spaces */
    while (spadlen < 0) {
        dopr_outch(buffer, currlen, maxlen, ' ');
        ++spadlen;
    }
    return;
}

static long double abs_val (long double value)
static LDOUBLE
abs_val(LDOUBLE value)
{
  long double result = value;

    LDOUBLE result = value;
    if (value < 0)
        result = -value;

    return result;
}

static long double pow10 (int exp)
{
  long double result = 1;

  while (exp)
static LDOUBLE
pow10(int exp)
{
    LDOUBLE result = 1;
    while (exp) {
        result *= 10;
        exp--;
    }
  
    return result;
}

static long round (long double value)
static long
round(LDOUBLE value)
{
    long intpart;

  intpart = value;
    intpart = (long) value;
    value = value - intpart;
    if (value >= 0.5)
        intpart++;

    return intpart;
}

static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
		   long double fvalue, 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)
{
    int signvalue = 0;
  long double ufvalue;
    LDOUBLE ufvalue;
    char iconvert[20];
    char fconvert[20];
    int iplace = 0;
    int fplace = 0;
  int padlen = 0; /* amount to pad */
    int padlen = 0;
    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) */
    else if (flags & DP_F_PLUS)
        signvalue = '+';
    else
      if (flags & DP_F_SPACE)
    else if (flags & DP_F_SPACE)
        signvalue = ' ';

#if 0
  if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */
#endif

  intpart = ufvalue;
    intpart = (long)ufvalue;

  /* 
   * Sorry, we only support 9 digits past the decimal because of our 
   * conversion method
   */
    /* 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
   */
    /* 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))
  {
    if (fracpart >= pow10(max)) {
        intpart++;
        fracpart -= pow10(max);
    }

#ifdef DEBUG_SNPRINTF
  dprint (1, (debugfile, "fmtfp: %f =? %d.%d\n", fvalue, intpart, fracpart));
#endif

  /* Convert integer part */
    /* convert integer part */
    do {
        iconvert[iplace++] =
      (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
            (caps ? "0123456789ABCDEF"
              : "0123456789abcdef")[intpart % 10];
        intpart = (intpart / 10);
    } while (intpart && (iplace < 20));
  if (iplace == 20) iplace--;
    if (iplace == 20)
        iplace--;
    iconvert[iplace] = 0;

  /* Convert fractional part */
    /* convert fractional part */
    do {
        fconvert[fplace++] =
      (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
            (caps ? "0123456789ABCDEF"
              : "0123456789abcdef")[fracpart % 10];
        fracpart = (fracpart / 10);
    } while (fracpart && (fplace < 20));
  if (fplace == 20) fplace--;
    if (fplace == 20)
        fplace--;
    fconvert[fplace] = 0;

    /* -1 for decimal point, another -1 if we are printing a sign */
@@ -643,24 +651,20 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
    if (padlen < 0)
        padlen = 0;
    if (flags & DP_F_MINUS)
    padlen = -padlen; /* Left Justifty */
        padlen = -padlen;

  if ((flags & DP_F_ZERO) && (padlen > 0)) 
  {
    if (signvalue) 
    {
    if ((flags & DP_F_ZERO) && (padlen > 0)) {
        if (signvalue) {
            dopr_outch(buffer, currlen, maxlen, signvalue);
            --padlen;
            signvalue = 0;
        }
    while (padlen > 0)
    {
        while (padlen > 0) {
            dopr_outch(buffer, currlen, maxlen, '0');
            --padlen;
        }
    }
  while (padlen > 0)
  {
    while (padlen > 0) {
        dopr_outch(buffer, currlen, maxlen, ' ');
        --padlen;
    }
@@ -674,26 +678,31 @@ static void fmtfp (char *buffer, size_t *currlen, size_t maxlen,
     * 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)
  {
    }
    while (zpadlen > 0) {
        dopr_outch(buffer, currlen, maxlen, '0');
        --zpadlen;
    }

  while (padlen < 0) 
  {
    while (padlen < 0) {
        dopr_outch(buffer, currlen, maxlen, ' ');
        ++padlen;
    }
}

static void dopr_outch (char *buffer, size_t *currlen, size_t maxlen, char c)
static void
dopr_outch(
    char *buffer,
    size_t *currlen,
    size_t maxlen,
    int c)
{
    if (*currlen < maxlen)
    buffer[(*currlen)++] = c;
        buffer[(*currlen)++] = (char)c;
    return;
}