Initial import of the CDE 2.1.30 sources from the Open Group.
This commit is contained in:
569
cde/programs/dtdocbook/sgmls/xfprintf.c
Normal file
569
cde/programs/dtdocbook/sgmls/xfprintf.c
Normal file
@@ -0,0 +1,569 @@
|
||||
/* $XConsortium: xfprintf.c /main/3 1996/06/19 17:19:16 drk $ */
|
||||
/* xfprintf.c -
|
||||
X/Open extended v?fprintf implemented in terms of v?fprintf.
|
||||
|
||||
Written by James Clark (jjc@jclark.com).
|
||||
*/
|
||||
|
||||
/* Compile with:
|
||||
|
||||
-DVARARGS to use varargs.h instead of stdarg.h
|
||||
-DLONG_DOUBLE_MISSING if your compiler doesn't like `long double'
|
||||
-DFP_SUPPORT to include floating point stuff
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifndef HAVE_EXTENDED_PRINTF
|
||||
|
||||
#include "std.h"
|
||||
|
||||
#ifdef lint
|
||||
/* avoid stupid lint warnings */
|
||||
#undef va_arg
|
||||
#define va_arg(ap, type) (ap, (type)0)
|
||||
#endif
|
||||
|
||||
#ifdef FP_SUPPORT
|
||||
#ifdef LONG_DOUBLE_MISSING
|
||||
typedef double long_double;
|
||||
#else
|
||||
typedef long double long_double;
|
||||
#endif
|
||||
#endif /* FP_SUPPORT */
|
||||
|
||||
#ifndef __STDC__
|
||||
#define const /* as nothing */
|
||||
#endif
|
||||
|
||||
#ifdef USE_PROTOTYPES
|
||||
#define P(parms) parms
|
||||
#else
|
||||
#define P(parms) ()
|
||||
#endif
|
||||
|
||||
#ifdef VARARGS
|
||||
typedef int (*printer)();
|
||||
#else
|
||||
typedef int (*printer)(UNIV, const char *, ...);
|
||||
#endif
|
||||
|
||||
enum arg_type {
|
||||
NONE,
|
||||
INT,
|
||||
UNSIGNED,
|
||||
LONG,
|
||||
UNSIGNED_LONG,
|
||||
#ifdef FP_SUPPORT
|
||||
DOUBLE,
|
||||
LONG_DOUBLE,
|
||||
#endif /* FP_SUPPORT */
|
||||
PCHAR,
|
||||
PINT,
|
||||
PLONG,
|
||||
PSHORT
|
||||
};
|
||||
|
||||
union arg {
|
||||
int i;
|
||||
unsigned u;
|
||||
long l;
|
||||
unsigned long ul;
|
||||
#ifdef FP_SUPPORT
|
||||
double d;
|
||||
long_double ld;
|
||||
#endif /* FP_SUPPORT */
|
||||
char *pc;
|
||||
UNIV pv;
|
||||
int *pi;
|
||||
short *ps;
|
||||
long *pl;
|
||||
};
|
||||
|
||||
#define NEXT 0
|
||||
#define MISSING 10
|
||||
|
||||
struct spec {
|
||||
enum arg_type type;
|
||||
char pos;
|
||||
char field_width;
|
||||
char precision;
|
||||
};
|
||||
|
||||
#define FLAG_CHARS "-+ #0"
|
||||
|
||||
static int parse_spec P((const char **, struct spec *));
|
||||
static int find_arg_types P((const char *, enum arg_type *));
|
||||
static void get_arg P((enum arg_type, va_list *, union arg *));
|
||||
static int do_arg P((UNIV, printer, const char *, enum arg_type, union arg *));
|
||||
static int xdoprt P((UNIV, printer, const char *, va_list));
|
||||
static int printit P((UNIV, printer, const char *, va_list, int, union arg *));
|
||||
static int maybe_positional P((const char *));
|
||||
|
||||
/* Return 1 if sucessful, 0 otherwise. **pp points to character after % */
|
||||
|
||||
static int parse_spec(pp, sp)
|
||||
const char **pp;
|
||||
struct spec *sp;
|
||||
{
|
||||
char modifier = 0;
|
||||
sp->pos = NEXT;
|
||||
if (isdigit((unsigned char)(**pp)) && (*pp)[1] == '$') {
|
||||
if (**pp == '0')
|
||||
return 0;
|
||||
sp->pos = **pp - '0';
|
||||
*pp += 2;
|
||||
}
|
||||
|
||||
while (**pp != '\0' && strchr(FLAG_CHARS, **pp))
|
||||
*pp += 1;
|
||||
|
||||
/* handle the field width */
|
||||
|
||||
sp->field_width = MISSING;
|
||||
if (**pp == '*') {
|
||||
*pp += 1;
|
||||
if (isdigit((unsigned char)**pp) && (*pp)[1] == '$') {
|
||||
if (**pp == '0')
|
||||
return 0;
|
||||
sp->field_width = **pp - '0';
|
||||
*pp += 2;
|
||||
}
|
||||
else
|
||||
sp->field_width = NEXT;
|
||||
}
|
||||
else {
|
||||
while (isdigit((unsigned char)**pp))
|
||||
*pp += 1;
|
||||
}
|
||||
|
||||
/* handle the precision */
|
||||
sp->precision = MISSING;
|
||||
if (**pp == '.') {
|
||||
*pp += 1;
|
||||
if (**pp == '*') {
|
||||
*pp += 1;
|
||||
if (isdigit((unsigned char)**pp) && (*pp)[1] == '$') {
|
||||
if (**pp == '0')
|
||||
return 0;
|
||||
sp->precision = **pp - '0';
|
||||
*pp += 2;
|
||||
}
|
||||
else
|
||||
sp->precision = NEXT;
|
||||
}
|
||||
else {
|
||||
while (isdigit((unsigned char)**pp))
|
||||
*pp += 1;
|
||||
}
|
||||
}
|
||||
/* handle h l or L */
|
||||
|
||||
if (**pp == 'h' || **pp == 'l' || **pp == 'L') {
|
||||
modifier = **pp;
|
||||
*pp += 1;
|
||||
}
|
||||
|
||||
switch (**pp) {
|
||||
case 'd':
|
||||
case 'i':
|
||||
sp->type = modifier == 'l' ? LONG : INT;
|
||||
break;
|
||||
case 'o':
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'X':
|
||||
sp->type = modifier == 'l' ? UNSIGNED_LONG : UNSIGNED;
|
||||
break;
|
||||
#ifdef FP_SUPPORT
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'f':
|
||||
case 'g':
|
||||
case 'G':
|
||||
sp->type = modifier == 'L' ? LONG_DOUBLE : DOUBLE;
|
||||
break;
|
||||
#endif /* FP_SUPPORT */
|
||||
case 'c':
|
||||
sp->type = INT;
|
||||
break;
|
||||
case 's':
|
||||
sp->type = PCHAR;
|
||||
break;
|
||||
case 'p':
|
||||
/* a pointer to void has the same representation as a pointer to char */
|
||||
sp->type = PCHAR;
|
||||
break;
|
||||
case 'n':
|
||||
if (modifier == 'h')
|
||||
sp->type = PSHORT;
|
||||
else if (modifier == 'l')
|
||||
sp->type = PLONG;
|
||||
else
|
||||
sp->type = PINT;
|
||||
break;
|
||||
case '%':
|
||||
sp->type = NONE;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
*pp += 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int find_arg_types(format, arg_type)
|
||||
const char *format;
|
||||
enum arg_type *arg_type;
|
||||
{
|
||||
int i, pos;
|
||||
const char *p;
|
||||
struct spec spec;
|
||||
|
||||
for (i = 0; i < 9; i++)
|
||||
arg_type[i] = NONE;
|
||||
|
||||
pos = 0;
|
||||
|
||||
p = format;
|
||||
while (*p)
|
||||
if (*p == '%') {
|
||||
p++;
|
||||
if (!parse_spec(&p, &spec))
|
||||
return 0;
|
||||
if (spec.type != NONE) {
|
||||
int n;
|
||||
if (spec.pos == NEXT)
|
||||
n = pos++;
|
||||
else
|
||||
n = spec.pos - 1;
|
||||
if (n < 9) {
|
||||
enum arg_type t = arg_type[n];
|
||||
if (t != NONE && t != spec.type)
|
||||
return 0;
|
||||
arg_type[n] = spec.type;
|
||||
}
|
||||
}
|
||||
if (spec.field_width != MISSING) {
|
||||
int n;
|
||||
if (spec.field_width == NEXT)
|
||||
n = pos++;
|
||||
else
|
||||
n = spec.field_width - 1;
|
||||
if (n < 9) {
|
||||
enum arg_type t = arg_type[n];
|
||||
if (t != NONE && t != INT)
|
||||
return 0;
|
||||
arg_type[n] = INT;
|
||||
}
|
||||
}
|
||||
if (spec.precision != MISSING) {
|
||||
int n;
|
||||
if (spec.precision == NEXT)
|
||||
n = pos++;
|
||||
else
|
||||
n = spec.precision - 1;
|
||||
if (n < 9) {
|
||||
enum arg_type t = arg_type[n];
|
||||
if (t != NONE && t != INT)
|
||||
return 0;
|
||||
arg_type[n] = INT;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
p++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void get_arg(arg_type, app, argp)
|
||||
enum arg_type arg_type;
|
||||
va_list *app;
|
||||
union arg *argp;
|
||||
{
|
||||
switch (arg_type) {
|
||||
case NONE:
|
||||
break;
|
||||
case INT:
|
||||
argp->i = va_arg(*app, int);
|
||||
break;
|
||||
case UNSIGNED:
|
||||
argp->u = va_arg(*app, unsigned);
|
||||
break;
|
||||
case LONG:
|
||||
argp->l = va_arg(*app, long);
|
||||
break;
|
||||
case UNSIGNED_LONG:
|
||||
argp->ul = va_arg(*app, unsigned long);
|
||||
break;
|
||||
#ifdef FP_SUPPORT
|
||||
case DOUBLE:
|
||||
argp->d = va_arg(*app, double);
|
||||
break;
|
||||
case LONG_DOUBLE:
|
||||
argp->ld = va_arg(*app, long_double);
|
||||
break;
|
||||
#endif /* FP_SUPPORT */
|
||||
case PCHAR:
|
||||
argp->pc = va_arg(*app, char *);
|
||||
break;
|
||||
case PINT:
|
||||
argp->pi = va_arg(*app, int *);
|
||||
break;
|
||||
case PSHORT:
|
||||
argp->ps = va_arg(*app, short *);
|
||||
break;
|
||||
case PLONG:
|
||||
argp->pl = va_arg(*app, long *);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static int do_arg(handle, func, buf, arg_type, argp)
|
||||
UNIV handle;
|
||||
printer func;
|
||||
const char *buf;
|
||||
enum arg_type arg_type;
|
||||
union arg *argp;
|
||||
{
|
||||
switch (arg_type) {
|
||||
case NONE:
|
||||
return (*func)(handle, buf);
|
||||
case INT:
|
||||
return (*func)(handle, buf, argp->i);
|
||||
case UNSIGNED:
|
||||
return (*func)(handle, buf, argp->u);
|
||||
case LONG:
|
||||
return (*func)(handle, buf, argp->l);
|
||||
case UNSIGNED_LONG:
|
||||
return (*func)(handle, buf, argp->ul);
|
||||
#ifdef FP_SUPPORT
|
||||
case DOUBLE:
|
||||
return (*func)(handle, buf, argp->d);
|
||||
case LONG_DOUBLE:
|
||||
return (*func)(handle, buf, argp->ld);
|
||||
#endif /* FP_SUPPORT */
|
||||
case PCHAR:
|
||||
return (*func)(handle, buf, argp->pc);
|
||||
case PINT:
|
||||
return (*func)(handle, buf, argp->pi);
|
||||
case PSHORT:
|
||||
return (*func)(handle, buf, argp->ps);
|
||||
case PLONG:
|
||||
return (*func)(handle, buf, argp->pl);
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
static int printit(handle, func, p, ap, nargs, arg)
|
||||
UNIV handle;
|
||||
printer func;
|
||||
const char *p;
|
||||
va_list ap;
|
||||
int nargs;
|
||||
union arg *arg;
|
||||
{
|
||||
char buf[512]; /* enough for a spec */
|
||||
int count = 0;
|
||||
int pos = 0;
|
||||
|
||||
while (*p)
|
||||
if (*p == '%') {
|
||||
char *q;
|
||||
struct spec spec;
|
||||
const char *start;
|
||||
int had_field_width;
|
||||
union arg *argp;
|
||||
union arg a;
|
||||
int res;
|
||||
|
||||
start = ++p;
|
||||
if (!parse_spec(&p, &spec))
|
||||
abort(); /* should have caught it in find_arg_types */
|
||||
|
||||
buf[0] = '%';
|
||||
q = buf + 1;
|
||||
|
||||
if (spec.pos != NEXT)
|
||||
start += 2;
|
||||
|
||||
/* substitute in precision and field width if necessary */
|
||||
had_field_width = 0;
|
||||
while (start < p) {
|
||||
if (*start == '*') {
|
||||
char c;
|
||||
int n, val;
|
||||
|
||||
start++;
|
||||
if (!had_field_width && spec.field_width != MISSING) {
|
||||
c = spec.field_width;
|
||||
had_field_width = 1;
|
||||
}
|
||||
else
|
||||
c = spec.precision;
|
||||
if (c == NEXT)
|
||||
n = pos++;
|
||||
else {
|
||||
start += 2;
|
||||
n = c - 1;
|
||||
}
|
||||
if (n >= nargs)
|
||||
val = va_arg(ap, int);
|
||||
else
|
||||
val = arg[n].i;
|
||||
|
||||
/* ignore negative precision */
|
||||
if (val >= 0 || q[-1] != '.') {
|
||||
(void)sprintf(q, "%d", val);
|
||||
q = strchr(q, '\0');
|
||||
}
|
||||
}
|
||||
else
|
||||
*q++ = *start++;
|
||||
}
|
||||
*q++ = '\0';
|
||||
|
||||
argp = 0;
|
||||
if (spec.type != NONE) {
|
||||
int n = spec.pos == NEXT ? pos++ : spec.pos - 1;
|
||||
if (n >= nargs) {
|
||||
get_arg(spec.type, &ap, &a);
|
||||
argp = &a;
|
||||
}
|
||||
else
|
||||
argp = arg + n;
|
||||
}
|
||||
|
||||
res = do_arg(handle, func, buf, spec.type, argp);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
count += res;
|
||||
}
|
||||
else {
|
||||
if ((*func)(handle, "%c", *p++) < 0)
|
||||
return -1;
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/* Do a quick check to see if it may contains any positional thingies. */
|
||||
|
||||
static int maybe_positional(format)
|
||||
const char *format;
|
||||
{
|
||||
const char *p;
|
||||
|
||||
p = format;
|
||||
for (;;) {
|
||||
p = strchr(p, '$');
|
||||
if (!p)
|
||||
return 0;
|
||||
if (p - format >= 2
|
||||
&& isdigit((unsigned char)p[-1])
|
||||
&& (p[-2] == '%' || p[-2] == '*'))
|
||||
break; /* might be a positional thingy */
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int xdoprt(handle, func, format, ap)
|
||||
UNIV handle;
|
||||
printer func;
|
||||
const char *format;
|
||||
va_list ap;
|
||||
{
|
||||
enum arg_type arg_type[9];
|
||||
union arg arg[9];
|
||||
int nargs, i;
|
||||
|
||||
if (!find_arg_types(format, arg_type))
|
||||
return -1;
|
||||
|
||||
for (nargs = 0; nargs < 9; nargs++)
|
||||
if (arg_type[nargs] == NONE)
|
||||
break;
|
||||
|
||||
for (i = nargs; i < 9; i++)
|
||||
if (arg_type[i] != NONE)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < nargs; i++)
|
||||
get_arg(arg_type[i], &ap, arg + i);
|
||||
|
||||
return printit(handle, func, format, ap, nargs, arg);
|
||||
}
|
||||
|
||||
#ifdef VARARGS
|
||||
static int do_fprintf(va_alist) va_dcl
|
||||
#else
|
||||
static int do_fprintf(UNIV p, const char *format,...)
|
||||
#endif
|
||||
{
|
||||
#ifdef VARARGS
|
||||
UNIV p;
|
||||
const char *format;
|
||||
#endif
|
||||
va_list ap;
|
||||
int res;
|
||||
|
||||
#ifdef VARARGS
|
||||
va_start(ap);
|
||||
p = va_arg(ap, UNIV);
|
||||
format = va_arg(ap, char *);
|
||||
#else
|
||||
va_start(ap, format);
|
||||
#endif
|
||||
|
||||
res = vfprintf((FILE *)p, format, ap);
|
||||
va_end(ap);
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifdef VARARGS
|
||||
int xfprintf(va_alist) va_dcl
|
||||
#else
|
||||
int xfprintf(FILE *fp, const char *format, ...)
|
||||
#endif
|
||||
{
|
||||
#ifdef VARARGS
|
||||
FILE *fp;
|
||||
char *format;
|
||||
#endif
|
||||
va_list ap;
|
||||
int res;
|
||||
|
||||
#ifdef VARARGS
|
||||
va_start(ap);
|
||||
fp = va_arg(ap, FILE *);
|
||||
format = va_arg(ap, char *);
|
||||
#else
|
||||
va_start(ap, format);
|
||||
#endif
|
||||
if (maybe_positional(format))
|
||||
res = xdoprt((UNIV)fp, do_fprintf, format, ap);
|
||||
else
|
||||
res = vfprintf(fp, format, ap);
|
||||
va_end(ap);
|
||||
return res;
|
||||
}
|
||||
|
||||
int xvfprintf(fp, format, ap)
|
||||
FILE *fp;
|
||||
const char *format;
|
||||
va_list ap;
|
||||
{
|
||||
int res;
|
||||
if (maybe_positional(format))
|
||||
res = xdoprt((UNIV)fp, do_fprintf, format, ap);
|
||||
else
|
||||
res = vfprintf(fp, format, ap);
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif /* not HAVE_EXTENDED_PRINTF */
|
||||
Reference in New Issue
Block a user