#include "m4.h"
#include "xvasprintf.h"
#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)
{
char *fmt;
const char *fstart;
int c;
char flags;
int width;
int prec;
char lflag;
char hflag;
char *str;
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 (to_uchar (*fmt)))
{
do
{
fmt++;
}
while (isdigit (to_uchar (*fmt)));
}
prec = -1;
if (*fmt == '.')
{
if (*(++fmt) == '*')
{
prec = ARG_INT (argc, argv);
++fmt;
}
else if (isdigit (to_uchar (*fmt)))
{
do
{
fmt++;
}
while (isdigit (to_uchar (*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':
case 'F':
case 'g':
case 'G':
datatype = DOUBLE;
break;
default:
continue;
}
c = *fmt;
*fmt = '\0';
switch(datatype)
{
case INT:
if (width != -1 && prec != -1)
str = xasprintf (fstart, width, prec, ARG_INT(argc, argv));
else if (width != -1)
str = xasprintf (fstart, width, ARG_INT(argc, argv));
else if (prec != -1)
str = xasprintf (fstart, prec, ARG_INT(argc, argv));
else
str = xasprintf (fstart, ARG_INT(argc, argv));
break;
case UINT:
if (width != -1 && prec != -1)
str = xasprintf (fstart, width, prec, ARG_UINT(argc, argv));
else if (width != -1)
str = xasprintf (fstart, width, ARG_UINT(argc, argv));
else if (prec != -1)
str = xasprintf (fstart, prec, ARG_UINT(argc, argv));
else
str = xasprintf (fstart, ARG_UINT(argc, argv));
break;
case LONG:
if (width != -1 && prec != -1)
str = xasprintf (fstart, width, prec, ARG_LONG(argc, argv));
else if (width != -1)
str = xasprintf (fstart, width, ARG_LONG(argc, argv));
else if (prec != -1)
str = xasprintf (fstart, prec, ARG_LONG(argc, argv));
else
str = xasprintf (fstart, ARG_LONG(argc, argv));
break;
case ULONG:
if (width != -1 && prec != -1)
str = xasprintf (fstart, width, prec, ARG_ULONG(argc, argv));
else if (width != -1)
str = xasprintf (fstart, width, ARG_ULONG(argc, argv));
else if (prec != -1)
str = xasprintf (fstart, prec, ARG_ULONG(argc, argv));
else
str = xasprintf (fstart, ARG_ULONG(argc, argv));
break;
case DOUBLE:
if (width != -1 && prec != -1)
str = xasprintf (fstart, width, prec, ARG_DOUBLE(argc, argv));
else if (width != -1)
str = xasprintf (fstart, width, ARG_DOUBLE(argc, argv));
else if (prec != -1)
str = xasprintf (fstart, prec, ARG_DOUBLE(argc, argv));
else
str = xasprintf (fstart, ARG_DOUBLE(argc, argv));
break;
case STR:
if (width != -1 && prec != -1)
str = xasprintf (fstart, width, prec, ARG_STR(argc, argv));
else if (width != -1)
str = xasprintf (fstart, width, ARG_STR(argc, argv));
else if (prec != -1)
str = xasprintf (fstart, prec, ARG_STR(argc, argv));
else
str = xasprintf (fstart, ARG_STR(argc, argv));
break;
default:
abort();
}
*fmt = c;
if (str == NULL)
continue;
obstack_grow (obs, str, strlen (str));
free (str);
}
}