#include "config.h"
#if !defined(HAVE_VPRINTF) || !defined(HAVE_SNPRINTF)
/* AIX requires this to be the first thing in the file. */
#ifdef __GNUC__
#define alloca __builtin_alloca
#else /* not __GNUC__ */
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#else /* not HAVE_ALLOCA_H */
#ifdef _AIX
#pragma alloca
#endif /* not _AIX */
#endif /* not HAVE_ALLOCA_H */
#endif /* not __GNUC__ */
#include <sys/types.h>
#include <stdio.h>
#ifdef HAVE_STRING_H
#include <string.h>
#else
#include <strings.h>
#endif
#include <ctype.h>
/* Portable vfprintf by Robert A. Larson <blarson@skat.usc.edu> */
/* Hacked up by Jason Downs <downsj@xenotropic.com> */
/* 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 blarson@skat.usc.edu .
* The use of goto is NOT a bug.
*/
/* Feb 7, 1989 blarson First usenet release */
/* 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.
*/
#if (SIZEOF_INT == SIZEOF_LONG)
#define LONGINT
#else
#undef LONGINT
#endif
#if defined(aiws)
#define INTSPRINTF
#else
#undef INTSPRINTF
#endif
#define UNSIGNEDSPECIAL
#ifdef INTSPRINTF
#define Sprintf(string,format,arg) (sprintf((string),(format),(arg)))
#else
#define Sprintf(string,format,arg) (\
sprintf((string),(format),(arg)),\
strlen(string)\
)
#endif
#if defined(HAVE_STDARG_H) && defined(__STDC__)
#include <stdarg.h>
#else
#include <varargs.h>
#endif
typedef int *intp;
#if !defined(HAVE_VPRINTF)
#if defined(HAVE_STDARG_H) && defined(__STDC__)
int vsprintf(char *dest, const char *format, ...)
#else
int vsprintf(dest, format, va_alist)
char *dest;
const char *format;
va_dcl
#endif
{
register char *dp = dest;
register char c;
register char *tp;
char tempfmt[64];
#ifndef LONGINT
int longflag;
#endif
va_list args;
#if defined(HAVE_STDARG_H) && defined(__STDC__)
va_start(args, format);
#else
va_start(args);
#endif
tempfmt[0] = '%';
while((c = *format++)) {
if(c=='%') {
tp = &tempfmt[1];
#ifndef LONGINT
longflag = 0;
#endif
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
dp += Sprintf(dp, tempfmt, va_arg(args, unsigned));
break;
#endif
case 'd':
case 'c':
case 'i':
*tp++ = c;
*tp = '\0';
#ifndef LONGINT
if(longflag)
dp += Sprintf(dp, tempfmt, va_arg(args, long));
else
#endif
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, VOID *));
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
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';
va_end(args);
return(dp - dest);
}
#if defined(HAVE_STDARG_H) && defined(__STDC__)
int vfprintf(FILE *dest, const char *format, ...)
#else
int vfprintf(dest, format, va_alist)
FILE *dest;
const char *format;
va_dcl
#endif
{
register char c;
register char *tp;
register int count = 0;
char tempfmt[64];
#ifndef LONGINT
int longflag;
#endif
va_list args;
#if defined(HAVE_STDARG_H) && defined(__STDC__)
va_start(args, format);
#else
va_start(args);
#endif
tempfmt[0] = '%';
while((c = *format++)) {
if(c=='%') {
tp = &tempfmt[1];
#ifndef LONGINT
longflag = 0;
#endif
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
count += fprintf(dest, tempfmt, va_arg(args, unsigned));
break;
#endif
case 'd':
case 'c':
case 'i':
*tp++ = c;
*tp = '\0';
#ifndef LONGINT
if(longflag)
count += fprintf(dest, tempfmt, va_arg(args, long));
else
#endif
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, VOID *));
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
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++;
}
}
va_end(args);
return(count);
}
#if defined(HAVE_STDARG_H) && defined(__STDC__)
int vprintf(char *format, ...)
#else
int vprintf(format, va_alist)
char *format;
va_dcl
#endif
{
va_list args;
return(vfprintf(stdout, format, args));
}
#endif
#if !defined(HAVE_SNPRINTF)
#if defined(HAVE_STDARG_H) && defined(__STDC__)
int snprintf(char *dest, size_t size, const char *format, ...)
#else
int snprintf(dest, size, format, va_alist)
char *dest;
size_t size;
const char *format;
va_dcl
#endif
{
register char *dp = dest;
register char c;
register char *tp, *sa;
char tempfmt[64], tempbuf[128];
#ifndef LONGINT
int longflag;
#endif
int outspace = 0;
va_list args;
#if defined(HAVE_STDARG_H) && defined(__STDC__)
va_start(args, format);
#else
va_start(args);
#endif
tempfmt[0] = '%';
while((c = *format++) && !outspace) {
if(c=='%') {
tp = &tempfmt[1];
#ifndef LONGINT
longflag = 0;
#endif
continue_format:
switch((c = *format++)) {
case 's': {
int padding;
register char *ptr, *buff;
*tp++ = c;
*tp = '\0';
/* Scan for padding. */
for(ptr = tempfmt; *ptr && !isdigit(*ptr); ptr++);
if(isdigit(*ptr)) {
padding = (int)strtol(ptr, NULL, 10);
if(padding < 0)
padding = abs(padding);
} else
padding = 0;
sa = va_arg(args, char *);
if(padding) {
padding = (padding > strlen(sa)) ? padding : strlen(sa);
/* Allocate a buffer to hold the return. */
buff = (char *)alloca(padding+1);
if(buff == (char *)NULL)
return(-1); /* XXX */
/* Call sprintf() in order to get padding right. */
sprintf(buff, tempfmt, sa);
if(strlen(buff) >= (size - (dp - dest))) {
buff[size - ((dp - dest)+1)] = '\0';
outspace++;
}
strcpy(dp, buff);
dp += strlen(buff);
} else {
/* We can't write into sa! */
ptr = sa;
while(*ptr && ((dp - dest) < (size-1)))
*dp++ = *ptr++;
/* We don't terminate, but we do check for overflow. */
if((dp - dest) >= size)
outspace++;
}
} break;
case 'u':
case 'x':
case 'o':
case 'X':
#ifdef UNSIGNEDSPECIAL
*tp++ = c;
*tp = '\0';
#ifndef LONGINT
if(longflag)
sprintf(tempbuf, tempfmt, va_arg(args, unsigned long));
else
#endif
sprintf(tempbuf, tempfmt, va_arg(args, unsigned));
if(strlen(tempbuf) >= (size - (dp - dest))) {
tempbuf[size - ((dp - dest)+1)] = '\0';
outspace++;
}
strcpy(dp, tempbuf);
dp += strlen(tempbuf);
break;
#endif
case 'd':
case 'c':
case 'i':
*tp++ = c;
*tp = '\0';
#ifndef LONGINT
if(longflag)
sprintf(tempbuf, tempfmt, va_arg(args, long));
else
#endif
sprintf(tempbuf, tempfmt, va_arg(args, int));
if(strlen(tempbuf) >= (size - (dp - dest))) {
tempbuf[size - ((dp - dest)+1)] = '\0';
outspace++;
}
strcpy(dp, tempbuf);
dp += strlen(tempbuf);
break;
case 'f':
case 'e':
case 'E':
case 'g':
case 'G':
*tp++ = c;
*tp = '\0';
sprintf(tempbuf, tempfmt, va_arg(args, double));
if(strlen(tempbuf) >= (size - (dp - dest))) {
tempbuf[size - ((dp - dest)+1)] = '\0';
outspace++;
}
strcpy(dp, tempbuf);
dp += strlen(tempbuf);
break;
case 'p':
*tp++ = c;
*tp = '\0';
sprintf(tempbuf, tempfmt, va_arg(args, VOID *));
if(strlen(tempbuf) >= (size - (dp - dest))) {
tempbuf[size - ((dp - dest)+1)] = '\0';
outspace++;
}
strcpy(dp, tempbuf);
dp += strlen(tempbuf);
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
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:
if((size - (dp - dest)) > 1)
*dp++ = c;
else
outspace++;
break;
}
} else {
if((size - (dp - dest)) > 1)
*dp++ = c;
else
outspace++;
}
}
*dp = '\0';
va_end(args);
return(dp - dest);
}
#endif
#endif