/*
* Portable vfprintf  by Robert A. Larson <[email protected]>
*
* Copyright 1989 Robert A. Larson.
* Distribution in any form is allowed as long as the author
* retains credit, changes are noted by their author and the
* copyright message remains intact.  This program comes as-is
* with no warentee of fitness for any purpouse.
*
* Thanks to Doug Gwen, Chris Torek, and others who helped clarify
* the ansi printf specs.
*
* Please send any bug fixes and improvments to [email protected] .
* The use of goto is NOT a bug.
*
* Feb  7, 1989         blarson         First usenet release
*
* Changes for use with the IDA sendmail made by Paul Pomes, University
* of Illinois, Computing Services Office.  The original version is checked
* in to the RCS directory as number 1.1.
*/

/* This code implements the vsprintf function, without relying on
* the existance of _doprint or other system specific code.
*
* Define NOVOID if void * is not a supported type.
*
* Two compile options are available for efficency:
*      INTSPRINTF      should be defined if sprintf is int and returns
*                      the number of chacters formated.
*      LONGINT         should be defined if sizeof(long) == sizeof(int)
*
*      They only make the code smaller and faster, they need not be
*      defined.
*
* UNSIGNEDSPECIAL should be defined if unsigned is treated differently
* than int in argument passing.  If this is definded, and LONGINT is not,
* the compiler must support the type unsingned long.
*
* Most quirks and bugs of the available sprintf fuction are duplicated,
* however * in the width and precision fields will work correctly
* even if sprintf does not support this, as will the n format.
*
* Bad format strings, or those with very long width and precision
* fields (including expanded * fields) will cause undesired results.
*/
#include "conf.h"

#ifdef NO_VFPRINTF
#include <stdio.h>

#ifdef __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif

# if !defined(lint)
static char sccsid[] = "@(#)vprint.c    1.1 (USC) 2/7/89";
static char rcsid[] = "@(#)$Id: vprintf.c,v 1.2 1992/07/28 05:02:43 paul Exp $";
# endif /* not lint */

# ifndef __STDC__
#  define NOVOID                        /* a possibly reasonable assumption */
# endif /* !__STDC__ */

# ifdef OSK                     /* os9/68k can take advantage of both */
#  define LONGINT
#  define INTSPRINTF
# endif /* OSK */

/* This must be a typedef not a #define! */
# ifdef NOVOID
typedef char *pointer;
# else /* !NOVOID */
typedef void *pointer;
# endif /* NOVOID */

# ifdef INTSPRINTF
#  define Sprintf(string,format,arg)    (sprintf((string),(format),(arg)))
# else /* !INTSPRINTF */
# define Sprintf(string,format,arg)     (\
       sprintf((string),(format),(arg)),\
       strlen(string)\
)
# endif /* INTSPRINTF */

typedef int *intp;

int
# ifdef __STDC__
vsprintf (char *dest, const char *format, va_list args)
# else /* !__STDC__ */
vsprintf (dest, format, args)
       char    *dest;
       register char *format;
       va_list  args;
# endif /* __STDC__ */
{
       register char *dp = dest;
       register char c;
       register char *tp;
       char     tempfmt[64];

# ifndef LONGINT
       int      longflag;

# endif /* !LONGINT */

       tempfmt[0] = '%';
       while (c = *format++) {
               if (c == '%') {
                       tp = &tempfmt[1];
# ifndef LONGINT
                       longflag = 0;
# endif /* !LONGINT */
       continue_format:
                       switch (c = *format++) {
                           case 's':
                               *tp++ = c;
                               *tp = '\0';
                               dp += Sprintf (dp, tempfmt, va_arg (args, char *));
                               break;
                           case 'u':
                           case 'x':
                           case 'o':
                           case 'X':
# ifdef UNSIGNEDSPECIAL
                               *tp++ = c;
                               *tp = '\0';
#  ifndef LONGINT
                               if (longflag)
                                       dp += Sprintf (dp, tempfmt, va_arg (args, unsigned long));
                               else
#  endif /* !LONGINT */
                                       dp += Sprintf (dp, tempfmt, va_arg (args, unsigned));
                               break;
# endif /* UNSIGNEDSPECIAL */
                           case 'd':
                           case 'c':
                           case 'i':
                               *tp++ = c;
                               *tp = '\0';
# ifndef LONGINT
                               if (longflag)
                                       dp += Sprintf (dp, tempfmt, va_arg (args, long));
                               else
# endif /* !LONGINT */
                                       dp += Sprintf (dp, tempfmt, va_arg (args, int));
                               break;
                           case 'f':
                           case 'e':
                           case 'E':
                           case 'g':
                           case 'G':
                               *tp++ = c;
                               *tp = '\0';
                               dp += Sprintf (dp, tempfmt, va_arg (args, double));
                               break;
                           case 'p':
                               *tp++ = c;
                               *tp = '\0';
                               dp += Sprintf (dp, tempfmt, va_arg (args, pointer));
                               break;
                           case '-':
                           case '+':
                           case '0':
                           case '1':
                           case '2':
                           case '3':
                           case '4':
                           case '5':
                           case '6':
                           case '7':
                           case '8':
                           case '9':
                           case '.':
                           case ' ':
                           case '#':
                           case 'h':
                               *tp++ = c;
                               goto continue_format;
                           case 'l':
# ifndef LONGINT
                               longflag = 1;
                               *tp++ = c;
# endif /* !LONGINT */
                               goto continue_format;
                           case '*':
                               tp += Sprintf (tp, "%d", va_arg (args, int));
                               goto continue_format;
                           case 'n':
                               *va_arg (args, intp) = dp - dest;
                               break;
                           case '%':
                           default:
                               *dp++ = c;
                               break;
                       }
               } else
                       *dp++ = c;
       }
       *dp = '\0';
       return dp - dest;
}


int
# ifdef __STDC__
vfprintf (FILE *dest, const char *format, va_list args)
# else /* !__STDC__ */
vfprintf (dest, format, args)
       FILE    *dest;
       register char *format;
       va_list  args;
# endif /* __STDC__ */
{
       register char c;
       register char *tp;
       register int count = 0;
       char     tempfmt[64];

# ifndef LONGINT
       int      longflag;

# endif /* !LONGINT */

       tempfmt[0] = '%';
       while (c = *format++) {
               if (c == '%') {
                       tp = &tempfmt[1];
# ifndef LONGINT
                       longflag = 0;
# endif /* !LONGINT */
       continue_format:
                       switch (c = *format++) {
                           case 's':
                               *tp++ = c;
                               *tp = '\0';
                               count += fprintf (dest, tempfmt, va_arg (args, char *));
                               break;
                           case 'u':
                           case 'x':
                           case 'o':
                           case 'X':
# ifdef UNSIGNEDSPECIAL
                               *tp++ = c;
                               *tp = '\0';
#  ifndef LONGINT
                               if (longflag)
                                       count += fprintf (dest, tempfmt, va_arg (args, unsigned long));
                               else
#  endif /* !LONGINT */
                                       count += fprintf (dest, tempfmt, va_arg (args, unsigned));
                               break;
# endif /* UNSIGNEDSPECIAL */
                           case 'd':
                           case 'c':
                           case 'i':
                               *tp++ = c;
                               *tp = '\0';
# ifndef LONGINT
                               if (longflag)
                                       count += fprintf (dest, tempfmt, va_arg (args, long));
                               else
# endif /* !LONGINT */
                                       count += fprintf (dest, tempfmt, va_arg (args, int));
                               break;
                           case 'f':
                           case 'e':
                           case 'E':
                           case 'g':
                           case 'G':
                               *tp++ = c;
                               *tp = '\0';
                               count += fprintf (dest, tempfmt, va_arg (args, double));
                               break;
                           case 'p':
                               *tp++ = c;
                               *tp = '\0';
                               count += fprintf (dest, tempfmt, va_arg (args, pointer));
                               break;
                           case '-':
                           case '+':
                           case '0':
                           case '1':
                           case '2':
                           case '3':
                           case '4':
                           case '5':
                           case '6':
                           case '7':
                           case '8':
                           case '9':
                           case '.':
                           case ' ':
                           case '#':
                           case 'h':
                               *tp++ = c;
                               goto continue_format;
                           case 'l':
# ifndef LONGINT
                               longflag = 1;
                               *tp++ = c;
# endif /* !LONGINT */
                               goto continue_format;
                           case '*':
                               tp += Sprintf (tp, "%d", va_arg (args, int));
                               goto continue_format;
                           case 'n':
                               *va_arg (args, intp) = count;
                               break;
                           case '%':
                           default:
                               putc (c, dest);
                               count++;
                               break;
                       }
               } else {
                       putc (c, dest);
                       count++;
               }
       }
       return count;
}

int
# ifdef __STDC__
vprintf (const char *format, va_list args)
# else /* !__STDC__ */
vprintf (format, args)
       register char *format;
       va_list  args;
# endif /* __STDC__ */
{
       register int nchars;
       nchars = vfprintf (stdout, format, args);
       return nchars;
}

#endif /* NO_VFPRINTF */