fmtfmt.c revision da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968
/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1985-2007 AT&T Knowledge Ventures *
* and is licensed under the *
* Common Public License, Version 1.0 *
* by AT&T Knowledge Ventures *
* *
* A copy of the License is available at *
* http://www.opensource.org/licenses/cpl1.0.txt *
* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* Glenn Fowler <gsf@research.att.com> *
* David Korn <dgk@research.att.com> *
* Phong Vo <kpv@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* Glenn Fowler
* AT&T Research
*
* return printf(3) format signature given format string
* the format signature contains one char per format optionally preceded
* by the number of `*' args
* c char
* d double
* D long double
* f float
* h short
* i int
* j long long
* l long
* p void*
* s string
* t ptrdiff_t
* z size_t
* ? unknown
*/
#include <ast.h>
#include <ctype.h>
char*
fmtfmt(const char* as)
{
register char* s = (char*)as;
char* buf;
int i;
int c;
int a;
int q;
int x;
int t;
int m;
int n;
int z;
char formats[256];
unsigned int extra[elementsof(formats)];
z = 1;
i = m = 0;
for (;;)
{
switch (*s++)
{
case 0:
break;
case '%':
if (*s == '%')
continue;
n = 0;
a = 0;
q = 0;
t = '?';
x = 0;
for (;;)
{
switch (c = *s++)
{
case 0:
s--;
break;
case '(':
q++;
continue;
case ')':
if (--q <= 0)
n = 0;
continue;
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9':
n = n * 10 + (c - '0');
continue;
case '$':
a = n;
n = 0;
continue;
case '*':
x++;
n = 0;
continue;
case 'h':
if (!q)
t = t == 'h' ? 'c' : 'h';
continue;
case 'l':
if (!q)
t = t == 'l' ? 'j' : 'l';
continue;
case 'j':
case 't':
case 'z':
if (!q)
t = c;
continue;
case 'c':
case 'p':
case 's':
if (!q)
{
t = c;
break;
}
continue;
case 'e':
case 'g':
if (!q)
{
switch (t)
{
case 'j':
t = 'D';
break;
default:
t = 'd';
break;
}
break;
}
continue;
case 'f':
if (!q)
{
switch (t)
{
case 'j':
t = 'D';
break;
case 'l':
t = 'd';
break;
default:
t = c;
break;
}
break;
}
continue;
default:
if (!q && isalpha(c))
{
if (t == '?')
t = 'i';
break;
}
n = 0;
continue;
}
break;
}
if (a)
i = a;
else
i++;
if (i < elementsof(formats))
{
formats[i] = t;
if (extra[i] = x)
do z++; while (x /= 10);
if (m < i)
m = i;
}
continue;
default:
continue;
}
break;
}
s = buf = fmtbuf(m + z);
for (i = 1; i <= m; i++)
{
if (extra[i])
s += sfsprintf(s, 10, "%d", extra[m]);
*s++ = formats[i];
}
*s = 0;
return buf;
}