/*
   Unix snprintf implementation.
   Version 1.1
   Code by Caolán McNamara <caolan@skynet.ie>
   
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   
   Revision History:

   1.1:
      *  added changes from Miles Bader
      *  corrected a bug with %f
      *  added support for %#g
      *  added more comments :-)
   1.0:
      *  supporting must ANSI syntaxic_sugars
   0.0:
      *  suppot %s %c %d

 THANKS(for the patches and ideas):
     Miles Bader
     Cyrille Rustom
     Jacek Slabocewiz
     Mike Parker(mouse)
 ------------------------------------

 Modified by Salvador E. Tropea (c) 2003.
 Don't blame Caolán for the bugs introduced by me ;-)
 I removed all the pre-ANSI previsions because they make the code unreadable
and I don't plan to support such an old compilers.
 I modified (or at least tried to ;-) the code to return not the used length
but the length needed to put all. This is the standard behavior and not what
Caolán implemented. In fact this code gets useless without it because I use
a first call without a buffer to determine the length of the buffer in most
cases.

*/

#include <cl/needs.h>

#ifdef NEEDS_SNPRINTF

#include <stdarg.h>
#include <stdlib.h>    /* for atoi() */
#include <ctype.h>
#include <string.h>    /* strlen() and others */

/* 
 * For the FLOATING POINT FORMAT :
 *  the challenge was finding a way to
 *  manipulate the Real numbers without having
 *  to resort to mathematical function(it
 *  would require to link with -lm) and not
 *  going down to the bit pattern(not portable)
 *
 *  so a number, a real is:

      real = integral + fraction

      integral = ... + a(2)*10^2 + a(1)*10^1 + a(0)*10^0
      fraction = b(1)*10^-1 + b(2)*10^-2 + ...

      where:
       0 <= a(i) => 9 
       0 <= b(i) => 9 
 
    from then it was simple math
 */

/*
 * size of the buffer for the integral part
 * and the fraction part 
 */
#define MAX_INT  99 + 1 /* 1 for the null */
#define MAX_FRACT 29 + 1

/* 
 * numtoa() uses PRIVATE buffers to store the results,
 * So this function is not reentrant
 */
#define itoa(n) numtoa(n, 10, 0, (char **)0) 
#define otoa(n) numtoa(n, 8, 0, (char **)0)
#define htoa(n) numtoa(n, 16, 0, (char **)0)
#define dtoa(n, p, f) numtoa(n, 10, p, f)

#define SWAP_INT(a,b) {int t; t = (a); (a) = (b); (b) = t;}

/* this struct holds everything we need */
struct DATA {
  int length;
  char *holder;
  int counter;
  const char *pf;
/* FLAGS */
  int width, precision;
  int justify; char pad;
  int square, space, star_w, star_p, a_long ;
};

#define PRIVATE static
#define PUBLIC
/* signature of the functions */
/* the floating point stuff */
  PRIVATE double pow_10(int);
  PRIVATE int log_10(double);
  PRIVATE double integral(double, double *);
  PRIVATE char * numtoa(double, int, int, char **);

/* for the format */
  PRIVATE void conv_flag(char *, struct DATA *);
  PRIVATE void floating(struct DATA *, double);
  PRIVATE void exponent(struct DATA *, double);
  PRIVATE void decimal(struct DATA *, double);
  PRIVATE void octal(struct DATA *, double);
  PRIVATE void hexa(struct DATA *, double);
  PRIVATE void strings(struct DATA *, char *);

/* those are defines specific to snprintf to hopefully
 * make the code clearer :-)
 */
#define RIGHT 1
#define LEFT  0
#define NOT_FOUND -1
#define FOUND 1
#define MAX_FIELD 15

/* the conversion flags */
#define isflag(c) ((c) == '#' || (c) == ' ' || \
                   (c) == '*' || (c) == '+' || \
                   (c) == '-' || (c) == '.' || \
                   isdigit(c))

/* round off to the precision */
#define ROUND(d, p) \
            (d < 0.) ? \
             d - pow_10(-(p)->precision) * 0.5 : \
             d + pow_10(-(p)->precision) * 0.5

/* set default precision */
#define DEF_PREC(p) \
            if ((p)->precision == NOT_FOUND) \
              (p)->precision = 6

/* put a char */
#define PUT_CHAR(c, p) \
            { \
            if ((p)->counter < (p)->length) \
              *(p)->holder++ = (c); \
            (p)->counter++; /* SET: Moved outside if */ \
            }

/* SET: put a char, no increment */
#define PUT_EOS(p) \
            { \
            if ((p)->counter <= (p)->length) \
              *(p)->holder = 0; \
            }

#define PUT_PLUS(d, p) \
            if ((d) > 0. && (p)->justify == RIGHT) \
              PUT_CHAR('+', p)

#define PUT_SPACE(d, p) \
            if ((p)->space == FOUND && (d) > 0.) \
              PUT_CHAR(' ', p)

/* pad right */ 
#define PAD_RIGHT(p) \
            if ((p)->width > 0 && (p)->justify != LEFT) \
              for (; (p)->width > 0; (p)->width--) \
                 PUT_CHAR((p)->pad, p)

/* pad left */
#define PAD_LEFT(p) \
            if ((p)->width > 0 && (p)->justify == LEFT) \
              for (; (p)->width > 0; (p)->width--) \
                 PUT_CHAR((p)->pad, p)

/* if width and prec. in the args */
#define STAR_ARGS(p) \
            if ((p)->star_w == FOUND) \
              (p)->width = va_arg(args, int); \
            if ((p)->star_p == FOUND) \
              (p)->precision = va_arg(args, int)
              
/*
 * Find the nth power of 10
 */
PRIVATE double
pow_10(int n)
{ 
  int i;
  double P;

  if (n < 0)
    for (i = 1, P = 1., n = -n ; i <= n ; i++) {P *= .1;}
  else
    for (i = 1, P = 1. ; i <= n ; i++) {P *= 10.0;}
  return P;
}

/*
 * Find the integral part of the log in base 10 
 * Note: this not a real log10()
         I just need and approximation(integerpart) of x in:
          10^x ~= r
 * log_10(200) = 2;
 * log_10(250) = 2;
 */
PRIVATE int
log_10(double r)
{ 
  int i = 0;
  double result = 1.;

  if (r < 0.)
    r = -r;

  if (r < 1.) {
    while (result >= r) {result *= .1; i++;}
    return (-i);
  } else {
    while (result <= r) {result *= 10.; i++;}
    return (i - 1);
  }
}

/*
 * This function return the fraction part of a double
 * and set in ip the integral part.
 * In many ways it resemble the modf() found on most Un*x
 */
PRIVATE double
integral(double real, double * ip)
{ 
  int j;
  double i, s, p;
  double real_integral = 0.;

/* take care of the obvious */
/* equal to zero ? */
  if (real == 0.) {
    *ip = 0.;
    return (0.);
  }

/* negative number ? */
  if (real < 0.)
    real = -real;

/* a fraction ? */
  if ( real < 1.) {
    *ip = 0.;
    return real;
  }
/* the real work :-) */
  for (j = log_10(real); j >= 0; j--) {
    p = pow_10(j);
    s = (real - real_integral)/p;
    i = 0.;
    while (i + 1. <= s) {i++;}
    real_integral += i*p;
  }
  *ip = real_integral;
  return (real - real_integral);
}

#define PRECISION 1.e-6
/* 
 * return an ascii representation of the integral part of the number
 * and set fract to be an ascii representation of the fraction part
 * the container for the fraction and the integral part or staticly
 * declare with fix size 
 */
PRIVATE char *
numtoa(double number, int base, int precision, char ** fract)
{
  register int i, j;
  double ip, fp; /* integer and fraction part */
  double fraction;
  int digits = MAX_INT - 1;
  static char integral_part[MAX_INT];
  static char fraction_part[MAX_FRACT];
  double sign;
  int ch;

/* taking care of the obvious case: 0.0 */
  if (number == 0.) { 
    integral_part[0] = '0';
    integral_part[1] = '\0';
    fraction_part[0] = '0';
    fraction_part[1] = '\0';
    return integral_part;
  }

/* for negative numbers */
  if ((sign = number) < 0.) {
    number = -number;
    digits--; /* sign consume one digit */
  } 

  fraction = integral(number, &ip);
  number = ip;
/* do the integral part */
  if ( ip == 0.) {
    integral_part[0] = '0';
    i = 1;
  } else {
    for ( i = 0; i < digits && number != 0.; ++i) {
      number /= base;
      fp = integral(number, &ip);
      ch = (int)((fp + PRECISION)*base); /* force to round */
      integral_part[i] = (ch <= 9) ? ch + '0' : ch + 'a' - 10;
      if (! isxdigit(integral_part[i])) /* bail out overflow !! */
        break; 
      number = ip;
     }
  }
     
/* Oh No !! out of bound, ho well fill it up ! */
  if (number != 0.)
    for (i = 0; i < digits; ++i)
      integral_part[i] = '9';

/* put the sign ? */
  if (sign < 0.)
    integral_part[i++] = '-';

  integral_part[i] = '\0';

/* reverse every thing */
  for ( i--, j = 0; j < i; j++, i--)
    SWAP_INT(integral_part[i], integral_part[j]);  

/* the fractionnal part */
  for (i=0, fp=fraction; precision > 0 && i < MAX_FRACT ; i++, precision--	) {
    fraction_part[i] = (int)((fp + PRECISION)*10. + '0');
    if (! isdigit(fraction_part[i])) /* underflow ? */
      break;
    fp = (fp*10.0) - (double)(long)((fp + PRECISION)*10.);
  }
  fraction_part[i] = '\0';

  if (fract != (char **)0)
    *fract = fraction_part;

  return integral_part;

}

/* for %d and friends, it puts in holder
 * the representation with the right padding
 */
PRIVATE void
decimal(struct DATA *p, double d)
{
  char *tmp;

  tmp = itoa(d);
  p->width -= strlen(tmp);
  PAD_RIGHT(p);
  PUT_PLUS(d, p);
  PUT_SPACE(d, p);
  while (*tmp) { /* the integral */
    PUT_CHAR(*tmp, p);
    tmp++;
  }
  PAD_LEFT(p);
}

/* for %o octal representation */
PRIVATE void
octal(struct DATA *p, double d)
{
  char *tmp;

  tmp = otoa(d);
  p->width -= strlen(tmp);
  PAD_RIGHT(p);
  if (p->square == FOUND) /* had prefix '0' for octal */
    PUT_CHAR('0', p);
  while (*tmp) { /* octal */
    PUT_CHAR(*tmp, p);
    tmp++;
  }
  PAD_LEFT(p);
}

/* for %x %X hexadecimal representation */
PRIVATE void
hexa(struct DATA *p, double d)
{
  char *tmp;

  tmp = htoa(d);
  p->width -= strlen(tmp);
  PAD_RIGHT(p);
  if (p->square == FOUND) { /* prefix '0x' for hexa */
    PUT_CHAR('0', p); PUT_CHAR(*p->pf, p);
  }
  while (*tmp) { /* hexa */
    PUT_CHAR((*p->pf == 'X' ? toupper(*tmp) : *tmp), p);
    tmp++;
  }
  PAD_LEFT(p);
}

/* %s strings */
PRIVATE void
strings(struct DATA *p, char *tmp)
{
  int i;

  i = strlen(tmp);
  if (p->precision != NOT_FOUND) /* the smallest number */
    i = (i < p->precision ? i : p->precision);
  p->width -= i;
  PAD_RIGHT(p);
  while (i-- > 0) { /* put the sting */
    PUT_CHAR(*tmp, p);
    tmp++;
  }
  PAD_LEFT(p);
}

/* %f or %g  floating point representation */
PRIVATE void
floating(struct DATA *p, double d)
{
  char *tmp, *tmp2;
  int i;

  DEF_PREC(p);
  d = ROUND(d, p);
  tmp = dtoa(d, p->precision, &tmp2);
  /* calculate the padding. 1 for the dot */
  p->width = p->width -
            ((d > 0. && p->justify == RIGHT) ? 1:0) -
            ((p->space == FOUND) ? 1:0) -
            strlen(tmp) - p->precision - 1;
  PAD_RIGHT(p);  
  PUT_PLUS(d, p);
  PUT_SPACE(d, p);
  while (*tmp) { /* the integral */
    PUT_CHAR(*tmp, p);
    tmp++;
  }
  if (p->precision != 0 || p->square == FOUND)
    PUT_CHAR('.', p);  /* put the '.' */
  if (*p->pf == 'g' || *p->pf == 'G') /* smash the trailing zeros */
    for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
       tmp2[i] = '\0'; 
  for (; *tmp2; tmp2++)
    PUT_CHAR(*tmp2, p); /* the fraction */
  
  PAD_LEFT(p);
} 

/* %e %E %g exponent representation */
PRIVATE void
exponent(struct DATA *p, double d)
{
  char *tmp, *tmp2;
  int j, i;

  DEF_PREC(p);
  j = log_10(d);
  d = d / pow_10(j);  /* get the Mantissa */
  d = ROUND(d, p);                  
  tmp = dtoa(d, p->precision, &tmp2);
  /* 1 for unit, 1 for the '.', 1 for 'e|E',
   * 1 for '+|-', 3 for 'exp' */
  /* calculate how much padding need */
  p->width = p->width - 
             ((d > 0. && p->justify == RIGHT) ? 1:0) -
             ((p->space == FOUND) ? 1:0) - p->precision - 7;
  PAD_RIGHT(p);
  PUT_PLUS(d, p);
  PUT_SPACE(d, p);
  while (*tmp) {/* the integral */
    PUT_CHAR(*tmp, p);
    tmp++;
  }
  if (p->precision != 0 || p->square == FOUND)
    PUT_CHAR('.', p);  /* the '.' */
  if (*p->pf == 'g' || *p->pf == 'G') /* smash the trailing zeros */
    for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
       tmp2[i] = '\0'; 
  for (; *tmp2; tmp2++)
    PUT_CHAR(*tmp2, p); /* the fraction */

  if (*p->pf == 'g' || *p->pf == 'e') { /* the exponent put the 'e|E' */
     PUT_CHAR('e', p);
   } else
     PUT_CHAR('E', p);
   if (j > 0) {  /* the sign of the exp */
     PUT_CHAR('+', p);
   } else {
     PUT_CHAR('-', p);
     j = -j;
   }
   tmp = itoa((double)j);
   if (j < 9) {  /* need to pad the exponent with 0 '000' */
     PUT_CHAR('0', p); PUT_CHAR('0', p);
   } else if (j < 99)
     PUT_CHAR('0', p);
   while (*tmp) { /* the exponent */
     PUT_CHAR(*tmp, p);
     tmp++;
   }
   PAD_LEFT(p);
}

/* initialize the conversion specifiers */
PRIVATE void
conv_flag(char * s, struct DATA * p)
{
  char number[MAX_FIELD/2];
  int i;

  p->precision = p->width = NOT_FOUND;
  p->star_w = p->star_p = NOT_FOUND;
  p->square = p->space = NOT_FOUND;
  p->a_long = p->justify = NOT_FOUND;
  p->pad = ' ';

  for(;s && *s ;s++) {
    switch(*s) {
      case ' ': p->space = FOUND; break;
      case '#': p->square = FOUND; break;
      case '*': if (p->width == NOT_FOUND)
                  p->width = p->star_w = FOUND;
                else
                  p->precision = p->star_p = FOUND;
                break;
      case '+': p->justify = RIGHT; break;
      case '-': p->justify = LEFT; break;
      case '.': if (p->width == NOT_FOUND)
                  p->width = 0;
                break;
      case '0': p->pad = '0'; break;
      case '1': case '2': case '3':
      case '4': case '5': case '6':
      case '7': case '8': case '9':     /* gob all the digits */
        for (i = 0; isdigit(*s); i++, s++) 
          if (i < MAX_FIELD/2 - 1)
            number[i] = *s;
        number[i] = '\0';
        if (p->width == NOT_FOUND)
          p->width = atoi(number);
        else
          p->precision = atoi(number);
        s--;   /* went to far go back */
        break;
    }
  }
}

PUBLIC int
CLY_vsnprintf(char *string, size_t length, const char * format, va_list args)
{
  struct DATA data;
  char conv_field[MAX_FIELD];
  double d; /* temporary holder */
  int state;
  int i;

  data.length = length - 1; /* leave room for '\0' */
  data.holder = string;
  data.pf = format;
  data.counter = 0;


/* sanity check, the string must be > 1
   SET: Wrong! we must compute the length!
  if (length < 1)
    return -1; */


  for (; *data.pf /*SET: && (data.counter < data.length)*/; data.pf++) {
    if ( *data.pf == '%' ) { /* we got a magic % cookie */
      conv_flag((char *)0, &data); /* initialise format flags */
      for (state = 1; *data.pf && state;) {
        switch (*(++data.pf)) {
          case '\0': /* a NULL here ? ? bail out */
            PUT_EOS(&data);
            return data.counter;
            break;
          case 'f':  /* float, double */
            STAR_ARGS(&data);
            d = va_arg(args, double);
            floating(&data, d);  
            state = 0;
            break;
          case 'g': 
          case 'G':
            STAR_ARGS(&data);
            DEF_PREC(&data);
            d = va_arg(args, double);
            i = log_10(d);
            /*
             * for '%g|%G' ANSI: use f if exponent
             * is in the range or [-4,p] exclusively
             * else use %e|%E
             */
            if (-4 < i && i < data.precision)
              floating(&data, d);
            else
              exponent(&data, d);
            state = 0;
            break;
          case 'e':
          case 'E':  /* Exponent double */
            STAR_ARGS(&data);
            d = va_arg(args, double);
            exponent(&data, d);
            state = 0;
            break;
          case 'u':
          case 'd':  /* decimal */
            STAR_ARGS(&data);
            if (data.a_long == FOUND)
              d = va_arg(args, long);
            else
              d = va_arg(args, int);
            decimal(&data, d);
            state = 0;
            break;
          case 'o':  /* octal */
            STAR_ARGS(&data);
            if (data.a_long == FOUND)
              d = va_arg(args, long);
            else
              d = va_arg(args, int);
            octal(&data, d);
            state = 0;
            break;
          case 'x': 
          case 'X':  /* hexadecimal */
            STAR_ARGS(&data);
            if (data.a_long == FOUND)
              d = va_arg(args, long);
            else
              d = va_arg(args, int);
            hexa(&data, d);
            state = 0;
            break;
          case 'c': /* character */
            d = va_arg(args, int);
            PUT_CHAR((char)d, &data);
            state = 0;
            break;
          case 's':  /* string */
            STAR_ARGS(&data);
            strings(&data, va_arg(args, char *));
            state = 0;
            break;
          case 'n':
             *(va_arg(args, int *)) = data.counter; /* what's the count ? */
             state = 0;
             break;
          case 'l':
            data.a_long = FOUND;
            break;
          case 'h':
            break;
          case '%':  /* nothing just % */
            PUT_CHAR('%', &data);
            state = 0;
            break;
          case '#': case ' ': case '+': case '*':
          case '-': case '.': case '0': case '1': 
          case '2': case '3': case '4': case '5':
          case '6': case '7': case '8': case '9':
           /* initialize width and precision */
            for (i = 0; isflag(*data.pf); i++, data.pf++) 
              if (i < MAX_FIELD - 1)
                conv_field[i] = *data.pf;
            conv_field[i] = '\0';
            conv_flag(conv_field, &data);
            data.pf--;   /* went to far go back */
            break;
          default:
            /* is this an error ? maybe bail out */
            state = 0;
            break;
        } /* end switch */
      } /* end of for state */
    } else { /* not % */
      PUT_CHAR(*data.pf, &data);  /* add the char the string */
    }
  }

  PUT_EOS(&data); /* the end ye ! */

  return data.counter;
}

#ifndef HAVE_SNPRINTF

PUBLIC int
CLY_snprintf(char *string, size_t length, const char * format, ...)
{
  int rval;
  va_list args;

  va_start(args, format);

  rval = CLY_vsnprintf (string, length, format, args);

  va_end(args);

  return rval;
}

#endif /* HAVE_SNPRINTF */


#ifdef DRIVER

#include <stdio.h>

/* set of small tests for snprintf() */
int main()
{
  char holder[100];
  int i;

/*
  printf("Suite of test for snprintf:\n");
  printf("a_format\n");
  printf("printf() format\n");
  printf("snprintf() format\n\n");
*/
/* Checking the field widths */

  printf("/%%d/, 336\n");
  CLY_snprintf(holder, sizeof holder, "/%d/\n", 336);
  printf("/%d/\n", 336);
  printf("%s\n", holder);

  printf("/%%2d/, 336\n");
  CLY_snprintf(holder, sizeof holder, "/%2d/\n", 336);
  printf("/%2d/\n", 336);
  printf("%s\n", holder);

  printf("/%%10d/, 336\n");
  CLY_snprintf(holder, sizeof holder, "/%10d/\n", 336);
  printf("/%10d/\n", 336);
  printf("%s\n", holder);

  printf("/%%-10d/, 336\n");
  CLY_snprintf(holder, sizeof holder, "/%-10d/\n", 336);
  printf("/%-10d/\n", 336);
  printf("%s\n", holder);


/* floating points */

  printf("/%%f/, 1234.56\n");
  CLY_snprintf(holder, sizeof holder, "/%f/\n", 1234.56);
  printf("/%f/\n", 1234.56);
  printf("%s\n", holder);

  printf("/%%e/, 1234.56\n");
  CLY_snprintf(holder, sizeof holder, "/%e/\n", 1234.56);
  printf("/%e/\n", 1234.56);
  printf("%s\n", holder);

  printf("/%%4.2f/, 1234.56\n");
  CLY_snprintf(holder, sizeof holder, "/%4.2f/\n", 1234.56);
  printf("/%4.2f/\n", 1234.56);
  printf("%s\n", holder);

  printf("/%%3.1f/, 1234.56\n");
  CLY_snprintf(holder, sizeof holder, "/%3.1f/\n", 1234.56);
  printf("/%3.1f/\n", 1234.56);
  printf("%s\n", holder);

  printf("/%%10.3f/, 1234.56\n");
  CLY_snprintf(holder, sizeof holder, "/%10.3f/\n", 1234.56);
  printf("/%10.3f/\n", 1234.56);
  printf("%s\n", holder);

  printf("/%%10.3e/, 1234.56\n");
  CLY_snprintf(holder, sizeof holder, "/%10.3e/\n", 1234.56);
  printf("/%10.3e/\n", 1234.56);
  printf("%s\n", holder);

  printf("/%%+4.2f/, 1234.56\n");
  CLY_snprintf(holder, sizeof holder, "/%+4.2f/\n", 1234.56);
  printf("/%+4.2f/\n", 1234.56);
  printf("%s\n", holder);

  printf("/%%010.2f/, 1234.56\n");
  CLY_snprintf(holder, sizeof holder, "/%010.2f/\n", 1234.56);
  printf("/%010.2f/\n", 1234.56);
  printf("%s\n", holder);

#define BLURB "Outstanding acting !"
/* strings precisions */

  printf("/%%2s/, \"%s\"\n", BLURB);
  CLY_snprintf(holder, sizeof holder, "/%2s/\n", BLURB);
  printf("/%2s/\n", BLURB);
  printf("%s\n", holder);

  printf("/%%22s/ %s\n", BLURB);
  CLY_snprintf(holder, sizeof holder, "/%22s/\n", BLURB);
  printf("/%22s/\n", BLURB);
  printf("%s\n", holder);

  printf("/%%22.5s/ %s\n", BLURB);
  CLY_snprintf(holder, sizeof holder, "/%22.5s/\n", BLURB);
  printf("/%22.5s/\n", BLURB);
  printf("%s\n", holder);

  printf("/%%-22.5s/ %s\n", BLURB);
  CLY_snprintf(holder, sizeof holder, "/%-22.5s/\n", BLURB);
  printf("/%-22.5s/\n", BLURB);
  printf("%s\n", holder);

/* see some flags */

  printf("%%x %%X %%#x, 31, 31, 31\n");
  CLY_snprintf(holder, sizeof holder, "%x %X %#x\n", 31, 31, 31);
  printf("%x %X %#x\n", 31, 31, 31);
  printf("%s\n", holder);

  printf("**%%d**%% d**%% d**, 42, 42, -42\n");
  CLY_snprintf(holder, sizeof holder, "**%d**% d**% d**\n", 42, 42, -42);
  printf("**%d**% d**% d**\n", 42, 42, -42);
  printf("%s\n", holder);

/* other flags */

  printf("/%%g/, 31.4\n");
  CLY_snprintf(holder, sizeof holder, "/%g/\n", 31.4);
  printf("/%g/\n", 31.4);
  printf("%s\n", holder);

  printf("/%%.6g/, 31.4\n");
  CLY_snprintf(holder, sizeof holder, "/%.6g/\n", 31.4);
  printf("/%.6g/\n", 31.4);
  printf("%s\n", holder);

  printf("/%%.1G/, 31.4\n");
  CLY_snprintf(holder, sizeof holder, "/%.1G/\n", 31.4);
  printf("/%.1G/\n", 31.4);
  printf("%s\n", holder);

  printf("abc%%n\n");
  printf("abc%n", &i); printf("%d\n", i);
  CLY_snprintf(holder, sizeof holder, "abc%n", &i);
  printf("%s", holder); printf("%d\n\n", i);
  
  printf("%%*.*s --> 10.10\n");
  CLY_snprintf(holder, sizeof holder, "%*.*s\n", 10, 10, BLURB);
  printf("%*.*s\n", 10, 10, BLURB);
  printf("%s\n", holder);

  printf("%%%%%%%%\n");
  CLY_snprintf(holder, sizeof holder, "%%%%\n");
  printf("%%%%\n");
  printf("%s\n", holder);

#define BIG "Hello this is a too big string for the buffer"
  printf("A buffer to small of 10, trying to put this:\n");
  printf("<%%>, %s\n", BIG); 
  i = CLY_snprintf(holder, 10, "%s\n", BIG);
  printf("<%s>\n", BIG);
  printf("<%s>\n", holder);
  printf("Value returned is %d\n",i);

  return 0;
}
#endif

#endif /* NEEDS_SNPRINTF */

