#include <config.h>
#include <stdio.h>
#include <ctype.h>
#ifdef STDC_HEADERS
#include <float.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "lisp.h"
#ifndef DBL_MAX_10_EXP
#define DBL_MAX_10_EXP 308
#endif
#include "charset.h"
static int doprnt1 ();
int
doprnt (buffer, bufsize, format, format_end, nargs, args)
char *buffer;
register int bufsize;
char *format;
char *format_end;
int nargs;
char **args;
{
return doprnt1 (0, buffer, bufsize, format, format_end, nargs, args);
}
int
doprnt_lisp (buffer, bufsize, format, format_end, nargs, args)
char *buffer;
register int bufsize;
char *format;
char *format_end;
int nargs;
char **args;
{
return doprnt1 (1, buffer, bufsize, format, format_end, nargs, args);
}
static int
doprnt1 (lispstrings, buffer, bufsize, format, format_end, nargs, args)
int lispstrings;
char *buffer;
register int bufsize;
char *format;
char *format_end;
int nargs;
char **args;
{
int cnt = 0;
register char *fmt = format;
register char *bufptr = buffer;
char tembuf[DBL_MAX_10_EXP + 100];
int size_allocated = sizeof (tembuf);
char *sprintf_buffer = tembuf;
char *big_buffer = 0;
register int tem;
unsigned char *string;
char fixed_buffer[20];
char *fmtcpy;
int minlen;
unsigned char charbuf[5];
if (format_end == 0)
format_end = format + strlen (format);
if ((format_end - format + 1) < sizeof (fixed_buffer))
fmtcpy = fixed_buffer;
else
fmtcpy = (char *) alloca (format_end - format + 1);
bufsize--;
while (fmt != format_end && bufsize > 0)
{
if (*fmt == '%')
{
int size_bound = 0;
int width;
fmt++;
string = (unsigned char *)fmtcpy;
*string++ = '%';
while (1)
{
*string++ = *fmt;
if ('0' <= *fmt && *fmt <= '9')
{
int n = *fmt - '0';
while ('0' <= fmt[1] && fmt[1] <= '9')
{
if (n * 10 / 10 != n
|| (n = n * 10 + (fmt[1] - '0')) < 0)
error ("Format width or precision too large");
*string++ = *++fmt;
}
if (size_bound < n)
size_bound = n;
}
else if (*fmt == '-' || *fmt == ' ' || *fmt == '.')
;
else
break;
fmt++;
}
*string = 0;
size_bound += DBL_MAX_10_EXP + 50;
if (size_bound < 0)
error ("Format width or precision too large");
if (size_bound > size_allocated)
{
if (big_buffer)
big_buffer = (char *) xrealloc (big_buffer, size_bound);
else
big_buffer = (char *) xmalloc (size_bound);
sprintf_buffer = big_buffer;
size_allocated = size_bound;
}
minlen = 0;
switch (*fmt++)
{
default:
error ("Invalid format operation %%%c", fmt[-1]);
case 'd':
case 'o':
case 'x':
if (cnt == nargs)
error ("Not enough arguments for format string");
if (sizeof (int) == sizeof (EMACS_INT))
;
else if (sizeof (long) == sizeof (EMACS_INT))
string[1] = string[0],
string[0] = string[-1],
string[-1] = 'l',
string++;
else
abort ();
sprintf (sprintf_buffer, fmtcpy, args[cnt++]);
string = (unsigned char *)sprintf_buffer;
goto doit;
case 'f':
case 'e':
case 'g':
{
union { double d; char *half[2]; } u;
if (cnt + 1 == nargs)
error ("not enough arguments for format string");
u.half[0] = args[cnt++];
u.half[1] = args[cnt++];
sprintf (sprintf_buffer, fmtcpy, u.d);
string = (unsigned char *)sprintf_buffer;
goto doit;
}
case 'S':
string[-1] = 's';
case 's':
if (cnt == nargs)
error ("not enough arguments for format string");
if (fmtcpy[1] != 's')
minlen = atoi (&fmtcpy[1]);
if (lispstrings)
{
string = ((struct Lisp_String *)args[cnt])->data;
tem = STRING_BYTES ((struct Lisp_String *)args[cnt]);
cnt++;
}
else
{
string = (unsigned char *)args[cnt++];
tem = strlen (string);
}
width = strwidth (string, tem);
goto doit1;
doit:
width = tem = strlen (string);
doit1:
if (minlen > 0)
{
while (minlen > width && bufsize > 0)
{
*bufptr++ = ' ';
bufsize--;
minlen--;
}
minlen = 0;
}
if (tem > bufsize)
{
tem = bufsize;
while (!CHAR_HEAD_P (string[tem - 1])) tem--;
bcopy (string, bufptr, tem);
width = strwidth (bufptr, tem);
}
else
bcopy (string, bufptr, tem);
bufptr += tem;
bufsize -= tem;
if (minlen < 0)
{
while (minlen < - width && bufsize > 0)
{
*bufptr++ = ' ';
bufsize--;
minlen++;
}
minlen = 0;
}
continue;
case 'c':
if (cnt == nargs)
error ("not enough arguments for format string");
tem = CHAR_STRING ((int) (EMACS_INT) args[cnt], charbuf);
string = charbuf;
cnt++;
string[tem] = 0;
width = strwidth (string, tem);
if (fmtcpy[1] != 'c')
minlen = atoi (&fmtcpy[1]);
goto doit1;
case '%':
fmt--;
}
}
{
char *save_bufptr = bufptr;
do { *bufptr++ = *fmt++; }
while (--bufsize > 0 && !CHAR_HEAD_P (*fmt));
if (!CHAR_HEAD_P (*fmt))
{
bufptr = save_bufptr;
break;
}
}
};
if (big_buffer)
xfree (big_buffer);
*bufptr = 0;
return bufptr - buffer;
}