#include "m4.h"
#ifdef HAVE_EFGCVT
#define MAXFIELD 128
#define ECVTMAX 18
#define FCVTMAX (18+38+4)
#if HAVE_EFGCVT <= 1
extern char *ecvt (), *fcvt (), *gcvt ();
#endif
#ifndef STDC_HEADERS
extern int atoi ();
extern long atol ();
extern double atof ();
#endif
#define min(a, b) ((a) < (b) ? (a) : (b))
static char const digits[] = "0123456789abcdef";
static char const Digits[] = "0123456789ABCDEF";
static char *
ulong_to_str (register unsigned long val, char *str, int base,
const char *digits)
{
register char *s = &str[MAXFIELD];
*--s = '\0';
do
{
*--s = digits[val % base];
val /= base;
}
while (val > 0);
return s;
}
static char *
clr0 (char *s)
{
register char *t;
for (t = s + strlen (s); *--t == '0' && t > s;)
*t = '\0';
return s;
}
#endif
#define ARG_INT(argc, argv) \
((argc == 0) ? 0 : \
(--argc, argv++, atoi (TOKEN_DATA_TEXT (argv[-1]))))
#define ARG_UINT(argc, argv) \
((argc == 0) ? 0 : \
(--argc, argv++, (unsigned int) atoi (TOKEN_DATA_TEXT (argv[-1]))))
#define ARG_LONG(argc, argv) \
((argc == 0) ? 0 : \
(--argc, argv++, atol (TOKEN_DATA_TEXT (argv[-1]))))
#define ARG_ULONG(argc, argv) \
((argc == 0) ? 0 : \
(--argc, argv++, (unsigned long) atol (TOKEN_DATA_TEXT (argv[-1]))))
#define ARG_STR(argc, argv) \
((argc == 0) ? "" : \
(--argc, argv++, TOKEN_DATA_TEXT (argv[-1])))
#define ARG_DOUBLE(argc, argv) \
((argc == 0) ? 0 : \
(--argc, argv++, atof (TOKEN_DATA_TEXT (argv[-1]))))
void
format (struct obstack *obs, int argc, token_data **argv)
{
#ifdef HAVE_EFGCVT
const char *fmt;
int c;
char fc;
char flags;
char ljust;
char mandsign;
char noplus;
char alternate;
char zeropad;
char plus;
int width;
int prec;
int maxch;
char lflag;
char hflag;
char sign;
int ppad;
const char *prefix;
int lpad;
register char *s;
int rpad;
const char *suffix;
char str[MAXFIELD];
int length;
int padding;
register int i;
#define LENGTH(s) (&str[MAXFIELD-1] - (s))
#define HAS_SIGN (sign != '\0')
fmt = ARG_STR (argc, argv);
for (;;)
{
while ((c = *fmt++) != '%')
{
if (c == 0)
return;
obstack_1grow (obs, c);
}
if (*fmt == '%')
{
obstack_1grow (obs, '%');
fmt++;
continue;
}
flags = 1;
ljust = mandsign = noplus = alternate = zeropad = 0;
do
{
switch (*fmt)
{
case '-':
ljust = 1;
break;
case '+':
mandsign = 1;
break;
case ' ':
noplus = 1;
break;
case '0':
zeropad = 1;
break;
case '#':
alternate = 1;
break;
default:
flags = 0;
break;
}
}
while (flags && fmt++);
plus = '\0';
if (mandsign)
plus = '+';
else if (noplus)
plus = ' ';
if (ljust)
zeropad = 0;
width = -1;
if (*fmt == '*')
{
width = ARG_INT (argc, argv);
fmt++;
}
else if (isdigit (*fmt))
{
width = 0;
do
{
width = width * 10 + *fmt++ - '0';
}
while (isdigit (*fmt));
}
prec = -1;
if (*fmt == '.')
{
if (*(++fmt) == '*')
{
prec = ARG_INT (argc, argv);
++fmt;
}
else if (isdigit (*fmt))
{
prec = 0;
do
{
prec = prec * 10 + *fmt++ - '0';
}
while (isdigit (*fmt))
;
}
}
lflag = (*fmt == 'l');
hflag = (*fmt == 'h');
if (lflag || hflag)
fmt++;
sign = '\0';
ppad = lpad = rpad = 0;
maxch = -1;
prefix = suffix = "";
switch (fc = *fmt++)
{
case '\0':
return;
case 'c':
c = ARG_INT (argc, argv);
str[0] = (unsigned char) c;
str[1] = '\0';
s = str;
break;
case 's':
s = ARG_STR (argc, argv);
maxch = prec;
break;
case 'd':
case 'i':
if (lflag)
{
long val = ARG_LONG (argc, argv);
if (val < 0)
{
val = -val;
sign = '-';
}
else
sign = plus;
s = ulong_to_str ((unsigned long) val, str, 10, digits);
}
else
{
int val = ARG_INT (argc, argv);
if (hflag)
val = (short) val;
if (val < 0)
{
val = -val;
sign = '-';
}
else
sign = plus;
s = ulong_to_str ((unsigned long) val, str, 10, digits);
}
if (zeropad)
lpad = width - LENGTH (s) - HAS_SIGN;
break;
case 'o':
if (lflag)
{
unsigned long val = ARG_ULONG (argc, argv);
s = ulong_to_str ((unsigned long) val, str, 8, digits);
}
else
{
unsigned int val = ARG_UINT (argc, argv);
if (hflag)
val = (unsigned short) val;
s = ulong_to_str ((unsigned long) val, str, 8, digits);
}
if (alternate)
prefix = "0";
if (zeropad)
lpad = width - LENGTH (s) - alternate;
break;
case 'x':
case 'X':
if (lflag)
{
unsigned long val = ARG_ULONG (argc, argv);
s = ulong_to_str ((unsigned long) val, str, 16,
(fc == 'x') ? digits : Digits);
}
else
{
unsigned int val = ARG_UINT (argc, argv);
if (hflag)
val = (unsigned short) val;
s = ulong_to_str ((unsigned long) val, str, 16,
(fc == 'x') ? digits : Digits);
}
if (alternate)
prefix = (fc == 'X') ? "0X" : "0x";
if (zeropad)
lpad = width - LENGTH (s) - 2*alternate;
break;
case 'u':
if (lflag)
{
unsigned long val = ARG_ULONG (argc, argv);
s = ulong_to_str ((unsigned long) val, str, 10, digits);
}
else
{
unsigned int val = ARG_UINT (argc, argv);
if (hflag)
val = (unsigned short) val;
s = ulong_to_str ((unsigned long) val, str, 10, digits);
}
if (zeropad)
lpad = width - LENGTH (s);
break;
case 'e':
case 'E':
{
char *t;
int sgn, decpt, exp, n;
double val = ARG_DOUBLE (argc, argv);
if (prec < 0)
prec = 6;
t = clr0 (ecvt (val, min (prec + 1, ECVTMAX), &decpt, &sgn));
sign = sgn ? '-' : plus;
n = prec;
s = str;
exp = (t[0] == '0' && t[1] == '\0') ? 0 : decpt - 1;
*s++ = *t++;
if (n > 0 || alternate)
*s++ = '.';
while (*t != '\0' && --n >= 0)
*s++ = *t++;
*s = '\0';
rpad = n;
sgn = 0;
if (exp < 0)
{
exp = -exp;
sgn = 1;
}
t = ulong_to_str ((unsigned long) exp, str, 10, digits);
if (exp < 10)
*--t = '0';
*--t = sgn ? '-' : '+';
*--t = fc;
if (zeropad)
{
lpad = width - HAS_SIGN - (s - str) - LENGTH (t);
if (rpad > 0)
lpad -= rpad;
}
suffix = t;
s = str;
}
break;
case 'f':
{
const char *t;
int sgn, decpt, n;
double val = ARG_DOUBLE (argc, argv);
if (prec < 0)
prec = 6;
t = clr0 (fcvt (val, min (prec, FCVTMAX), &decpt, &sgn));
sign = sgn ? '-' : plus;
n = prec;
s = str;
if (decpt <= 0)
{
prefix = (n > 0 || alternate) ? "0." : "0";
lpad = min (-decpt, prec);
n -= lpad;
}
else
{
while (--decpt >= 0)
*s++ = *t++;
if (n > 0 || alternate)
*s++ = '.';
}
while (*t && --n >= 0)
*s++ = *t++;
*s = '\0';
rpad = n;
if (zeropad)
ppad = width - HAS_SIGN - (prefix[1] ? 2 : 1) - lpad -
(s - str) - rpad;
s = str;
}
break;
default:
continue;
}
if (lpad < 0)
lpad = 0;
if (rpad < 0)
rpad = 0;
if (width < 0)
width = 0;
i = strlen (s);
if (maxch <= 0 || maxch > i)
maxch = i;
length = (HAS_SIGN + ppad + strlen (prefix) + lpad + maxch
+ rpad + strlen (suffix));
padding = 0;
if (width != 0)
{
padding = width - length;
}
if (ljust == 0)
for (i = padding; --i >= 0;)
obstack_1grow (obs, ' ');
if (HAS_SIGN)
obstack_1grow (obs, sign);
for (i = ppad; --i >= 0;)
obstack_1grow (obs, '0');
for (; *prefix; ++prefix)
obstack_1grow (obs, *prefix);
for (i = lpad; --i >= 0;)
obstack_1grow (obs, '0');
for (i = maxch; --i >= 0; ++s)
obstack_1grow (obs, *s);
for (i = rpad; --i >= 0;)
obstack_1grow (obs, '0');
for (; *suffix; ++suffix)
obstack_1grow (obs, *suffix);
if (ljust != 0)
for (i = padding; --i >= 0;)
obstack_1grow (obs, ' ');
}
#else
char *fmt;
const char *fstart;
int c;
char flags;
int width;
int prec;
char lflag;
char hflag;
char str[256];
enum {INT, UINT, LONG, ULONG, DOUBLE, STR} datatype;
fmt = ARG_STR (argc, argv);
for (;;)
{
while ((c = *fmt++) != '%')
{
if (c == 0)
return;
obstack_1grow (obs, c);
}
fstart = fmt - 1;
if (*fmt == '%')
{
obstack_1grow (obs, '%');
fmt++;
continue;
}
flags = 1;
do
{
switch (*fmt)
{
case '-':
case '+':
case ' ':
case '0':
case '#':
break;
default:
flags = 0;
break;
}
}
while (flags && fmt++);
width = -1;
if (*fmt == '*')
{
width = ARG_INT (argc, argv);
fmt++;
}
else if (isdigit (*fmt))
{
do
{
fmt++;
}
while (isdigit (*fmt));
}
prec = -1;
if (*fmt == '.')
{
if (*(++fmt) == '*')
{
prec = ARG_INT (argc, argv);
++fmt;
}
else if (isdigit (*fmt))
{
do
{
fmt++;
}
while (isdigit (*fmt));
}
}
lflag = (*fmt == 'l');
hflag = (*fmt == 'h');
if (lflag || hflag)
fmt++;
switch (*fmt++)
{
case '\0':
return;
case 'c':
datatype = INT;
break;
case 's':
datatype = STR;
break;
case 'd':
case 'i':
if (lflag)
{
datatype = LONG;
}
else
{
datatype = INT;
}
break;
case 'o':
case 'x':
case 'X':
case 'u':
if (lflag)
{
datatype = ULONG;
}
else
{
datatype = UINT;
}
break;
case 'e':
case 'E':
case 'f':
datatype = DOUBLE;
break;
default:
continue;
}
c = *fmt;
*fmt = '\0';
switch(datatype)
{
case INT:
if (width != -1 && prec != -1)
sprintf (str, fstart, width, prec, ARG_INT(argc, argv));
else if (width != -1)
sprintf (str, fstart, width, ARG_INT(argc, argv));
else if (prec != -1)
sprintf (str, fstart, prec, ARG_INT(argc, argv));
else
sprintf (str, fstart, ARG_INT(argc, argv));
break;
case UINT:
if (width != -1 && prec != -1)
sprintf (str, fstart, width, prec, ARG_UINT(argc, argv));
else if (width != -1)
sprintf (str, fstart, width, ARG_UINT(argc, argv));
else if (prec != -1)
sprintf (str, fstart, prec, ARG_UINT(argc, argv));
else
sprintf (str, fstart, ARG_UINT(argc, argv));
break;
case LONG:
if (width != -1 && prec != -1)
sprintf (str, fstart, width, prec, ARG_LONG(argc, argv));
else if (width != -1)
sprintf (str, fstart, width, ARG_LONG(argc, argv));
else if (prec != -1)
sprintf (str, fstart, prec, ARG_LONG(argc, argv));
else
sprintf (str, fstart, ARG_LONG(argc, argv));
break;
case ULONG:
if (width != -1 && prec != -1)
sprintf (str, fstart, width, prec, ARG_ULONG(argc, argv));
else if (width != -1)
sprintf (str, fstart, width, ARG_ULONG(argc, argv));
else if (prec != -1)
sprintf (str, fstart, prec, ARG_ULONG(argc, argv));
else
sprintf (str, fstart, ARG_ULONG(argc, argv));
break;
case DOUBLE:
if (width != -1 && prec != -1)
sprintf (str, fstart, width, prec, ARG_DOUBLE(argc, argv));
else if (width != -1)
sprintf (str, fstart, width, ARG_DOUBLE(argc, argv));
else if (prec != -1)
sprintf (str, fstart, prec, ARG_DOUBLE(argc, argv));
else
sprintf (str, fstart, ARG_DOUBLE(argc, argv));
break;
case STR:
if (width != -1 && prec != -1)
sprintf (str, fstart, width, prec, ARG_STR(argc, argv));
else if (width != -1)
sprintf (str, fstart, width, ARG_STR(argc, argv));
else if (prec != -1)
sprintf (str, fstart, prec, ARG_STR(argc, argv));
else
sprintf (str, fstart, ARG_STR(argc, argv));
break;
}
*fmt = c;
obstack_grow (obs, str, strlen (str));
}
#endif
}