os/ossrv/genericopenlibs/cstdlib/LSTDIO/VFPRINTF.C
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
/*
sl@0
     2
* FUNCTION
sl@0
     3
* <<vprintf>>, <<vfprintf>>, <<vsprintf>>---format argument list
sl@0
     4
* INDEX
sl@0
     5
* vprintf
sl@0
     6
* INDEX
sl@0
     7
* vfprintf
sl@0
     8
* INDEX
sl@0
     9
* vsprintf
sl@0
    10
* ANSI_SYNOPSIS
sl@0
    11
* #include <stdio.h>
sl@0
    12
* #include <stdarg.h>
sl@0
    13
* int vprintf(const char *<[fmt]>, va_list <[list]>);
sl@0
    14
* int vfprintf(FILE *<[fp]>, const char *<[fmt]>, va_list <[list]>);
sl@0
    15
* int vsprintf(char *<[str]>, const char *<[fmt]>, va_list <[list]>);
sl@0
    16
* int _vprintf_r(void *<[reent]>, const char *<[fmt]>,
sl@0
    17
* va_list <[list]>);
sl@0
    18
* int _vfprintf_r(void *<[reent]>, FILE *<[fp]>, const char *<[fmt]>,
sl@0
    19
* va_list <[list]>);
sl@0
    20
* int _vsprintf_r(void *<[reent]>, char *<[str]>, const char *<[fmt]>,
sl@0
    21
* va_list <[list]>);
sl@0
    22
* TRAD_SYNOPSIS
sl@0
    23
* #include <stdio.h>
sl@0
    24
* #include <varargs.h>
sl@0
    25
* int vprintf( <[fmt]>, <[list]>)
sl@0
    26
* char *<[fmt]>;
sl@0
    27
* va_list <[list]>;
sl@0
    28
* int vfprintf(<[fp]>, <[fmt]>, <[list]>)
sl@0
    29
* FILE *<[fp]>;
sl@0
    30
* char *<[fmt]>;
sl@0
    31
* va_list <[list]>;
sl@0
    32
* int vsprintf(<[str]>, <[fmt]>, <[list]>)
sl@0
    33
* char *<[str]>;
sl@0
    34
* char *<[fmt]>;
sl@0
    35
* va_list <[list]>;
sl@0
    36
* int _vprintf_r(<[reent]>, <[fmt]>, <[list]>)
sl@0
    37
* char *<[reent]>;
sl@0
    38
* char *<[fmt]>;
sl@0
    39
* va_list <[list]>;
sl@0
    40
* int _vfprintf_r(<[reent]>, <[fp]>, <[fmt]>, <[list]>)
sl@0
    41
* char *<[reent]>;
sl@0
    42
* FILE *<[fp]>;
sl@0
    43
* char *<[fmt]>;
sl@0
    44
* va_list <[list]>;
sl@0
    45
* int _vsprintf_r(<[reent]>, <[str]>, <[fmt]>, <[list]>)
sl@0
    46
* char *<[reent]>;
sl@0
    47
* char *<[str]>;
sl@0
    48
* char *<[fmt]>;
sl@0
    49
* va_list <[list]>;
sl@0
    50
* <<vprintf>>, <<vfprintf>>, and <<vsprintf>> are (respectively)
sl@0
    51
* variants of <<printf>>, <<fprintf>>, and <<sprintf>>.  They differ
sl@0
    52
* only in allowing their caller to pass the variable argument list as a
sl@0
    53
* <<va_list>> object (initialized by <<va_start>>) rather than directly
sl@0
    54
* accepting a variable number of arguments.
sl@0
    55
* RETURNS
sl@0
    56
* The return values are consistent with the corresponding functions:
sl@0
    57
* <<vsprintf>> returns the number of bytes in the output string,
sl@0
    58
* save that the concluding <<NULL>> is not counted.
sl@0
    59
* <<vprintf>> and <<vfprintf>> return the number of characters transmitted.
sl@0
    60
* If an error occurs, <<vprintf>> and <<vfprintf>> return <<EOF>>. No
sl@0
    61
* error returns occur for <<vsprintf>>.
sl@0
    62
* PORTABILITY
sl@0
    63
* ANSI C requires all three functions.
sl@0
    64
* Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
sl@0
    65
* <<lseek>>, <<read>>, <<sbrk>>, <<write>>.
sl@0
    66
* 
sl@0
    67
*
sl@0
    68
*/
sl@0
    69
sl@0
    70
sl@0
    71
sl@0
    72
/*-
sl@0
    73
 * Copyright (c) 1990 The Regents of the University of California.
sl@0
    74
 * All rights reserved.
sl@0
    75
 *
sl@0
    76
 * This code is derived from software contributed to Berkeley by
sl@0
    77
 * Chris Torek.
sl@0
    78
 *
sl@0
    79
 * Redistribution and use in source and binary forms, with or without
sl@0
    80
 * modification, are permitted provided that the following conditions
sl@0
    81
 * are met:
sl@0
    82
 * 1. Redistributions of source code must retain the above copyright
sl@0
    83
 *    notice, this list of conditions and the following disclaimer.
sl@0
    84
 * 2. Redistributions in binary form must reproduce the above copyright
sl@0
    85
 *    notice, this list of conditions and the following disclaimer in the
sl@0
    86
 *    documentation and/or other materials provided with the distribution.
sl@0
    87
 * 3. All advertising materials mentioning features or use of this software
sl@0
    88
 *    must display the following acknowledgement:
sl@0
    89
 *	This product includes software developed by the University of
sl@0
    90
 *	California, Berkeley and its contributors.
sl@0
    91
 * 4. Neither the name of the University nor the names of its contributors
sl@0
    92
 *    may be used to endorse or promote products derived from this software
sl@0
    93
 *    without specific prior written permission.
sl@0
    94
 *
sl@0
    95
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
sl@0
    96
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
sl@0
    97
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
sl@0
    98
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
sl@0
    99
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
sl@0
   100
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
sl@0
   101
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
sl@0
   102
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
sl@0
   103
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
sl@0
   104
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
sl@0
   105
 * SUCH DAMAGE.
sl@0
   106
 */
sl@0
   107
sl@0
   108
/*
sl@0
   109
 * Actual printf innards.
sl@0
   110
 *
sl@0
   111
 * This code is large and complicated...
sl@0
   112
 */
sl@0
   113
sl@0
   114
#if 1
sl@0
   115
#define _NO_LONGLONG
sl@0
   116
#endif
sl@0
   117
sl@0
   118
#include <_ansi.h>
sl@0
   119
#include <stdio_r.h>
sl@0
   120
#include <stdlib_r.h>
sl@0
   121
#include <string.h>
sl@0
   122
#include <reent.h>
sl@0
   123
sl@0
   124
#include <stdarg.h>
sl@0
   125
sl@0
   126
#include "LOCAL.H"
sl@0
   127
#include "FVWRITE.H"
sl@0
   128
sl@0
   129
sl@0
   130
//cm
sl@0
   131
#include <stdlib.h>
sl@0
   132
sl@0
   133
sl@0
   134
/*
sl@0
   135
 * Flush out all the vectors defined by the given uio,
sl@0
   136
 * then reset it so that it can be reused.
sl@0
   137
 */
sl@0
   138
static int
sl@0
   139
__sprint(FILE *fp,register struct __suio *uio)
sl@0
   140
{
sl@0
   141
	register int err;
sl@0
   142
sl@0
   143
	if (uio->uio_resid == 0) {
sl@0
   144
		uio->uio_iovcnt = 0;
sl@0
   145
		return (0);
sl@0
   146
	}
sl@0
   147
	err = __sfvwrite(fp, uio);
sl@0
   148
	uio->uio_resid = 0;
sl@0
   149
	uio->uio_iovcnt = 0;
sl@0
   150
	return (err);
sl@0
   151
}
sl@0
   152
sl@0
   153
/*
sl@0
   154
 * Helper function for `fprintf to unbuffered unix file': creates a
sl@0
   155
 * temporary buffer.  We only work on write-only files; this avoids
sl@0
   156
 * worries about ungetc buffers and so forth.
sl@0
   157
 */
sl@0
   158
static int
sl@0
   159
__sbprintf(register FILE *fp,const char *fmt,va_list ap)
sl@0
   160
{
sl@0
   161
	int ret;
sl@0
   162
	FILE fake;
sl@0
   163
	unsigned char buf[BUFSIZ];
sl@0
   164
sl@0
   165
	/* copy the important variables */
sl@0
   166
	fake._data = fp->_data;
sl@0
   167
	fake._flags = (short)(fp->_flags & ~__SNBF);
sl@0
   168
	fake._file = fp->_file;
sl@0
   169
	fake._cookie = fp->_cookie;
sl@0
   170
	fake._write = fp->_write;
sl@0
   171
sl@0
   172
	/* set up the buffer */
sl@0
   173
	fake._bf._base = fake._p = buf;
sl@0
   174
	fake._bf._size = fake._w = sizeof(buf);
sl@0
   175
	fake._lbfsize = 0;	/* not actually used, but Just In Case */
sl@0
   176
sl@0
   177
	/* do the work, then copy any error status */
sl@0
   178
	ret = vfprintf(&fake, fmt, ap);
sl@0
   179
	if (ret >= 0 && fflush(&fake))
sl@0
   180
		ret = EOF;
sl@0
   181
	if (fake._flags & __SERR)
sl@0
   182
		fp->_flags |= __SERR;
sl@0
   183
	return (ret);
sl@0
   184
}
sl@0
   185
sl@0
   186
sl@0
   187
/* #include <locale.h>   for decimal_point */
sl@0
   188
#include <math.h>
sl@0
   189
#include "FLOATIO.H"
sl@0
   190
sl@0
   191
#define	BUF		(MAXEXP+MAXFRACT+1)	/* + decimal point */
sl@0
   192
#define	DEFPREC		6
sl@0
   193
sl@0
   194
extern int e32cvt (char *buf, int buflen, double, int width, int prec, int flags, int fmt);
sl@0
   195
sl@0
   196
sl@0
   197
/*
sl@0
   198
 * Macros for converting digits to letters and vice versa
sl@0
   199
 */
sl@0
   200
#define	to_digit(c)	((c) - '0')
sl@0
   201
#define is_digit(c)	((unsigned)to_digit(c) <= 9)
sl@0
   202
#define	to_char(n)	((n) + '0')
sl@0
   203
sl@0
   204
/*
sl@0
   205
 * Flags used during conversion.
sl@0
   206
 */
sl@0
   207
#define	ALT		0x001		/* alternate form */
sl@0
   208
#define	HEXPREFIX	0x002		/* add 0x or 0X prefix */
sl@0
   209
#define	LADJUST		0x004		/* left adjustment */
sl@0
   210
#define	LONGDBL		0x008		/* long double; unimplemented */
sl@0
   211
#define	LONGINT		0x010		/* long integer */
sl@0
   212
#define	QUADINT		0x020		/* quad integer */
sl@0
   213
#define	SHORTINT	0x040		/* short integer */
sl@0
   214
#define	ZEROPAD		0x080		/* zero (as opposed to blank) pad */
sl@0
   215
#define FPT		0x100		/* Floating point number */
sl@0
   216
sl@0
   217
EXPORT_C int 
sl@0
   218
vfprintf (FILE * fp, const char *fmt0, va_list ap)
sl@0
   219
{
sl@0
   220
  return _vfprintf_r (fp->_data, fp, fmt0, ap);
sl@0
   221
}
sl@0
   222
sl@0
   223
/**
sl@0
   224
A reentrant version of vfprintf().
sl@0
   225
*/
sl@0
   226
EXPORT_C int 
sl@0
   227
_vfprintf_r (struct _reent *data, FILE * fp, const char *fmt0, va_list ap)
sl@0
   228
{
sl@0
   229
	register char *fmt;	/* format string */
sl@0
   230
	register int ch;	/* character from fmt */
sl@0
   231
	register int n, m;	/* handy integers (short term usage) */
sl@0
   232
	register char *cp;	/* handy char pointer (short term usage) */
sl@0
   233
	register struct __siov *iovp;/* for PRINT macro */
sl@0
   234
	register int flags;	/* flags as above */
sl@0
   235
	int ret;		/* return value accumulator */
sl@0
   236
	int width;		/* width from format (%8d), or 0 */
sl@0
   237
	int prec;		/* precision from format (%.3d), or -1 */
sl@0
   238
	char sign;		/* sign prefix (' ', '+', '-', or \0) */
sl@0
   239
	wchar_t wc;
sl@0
   240
#if 0
sl@0
   241
	char *decimal_point = "."; /* localeconv()->decimal_point; */
sl@0
   242
#endif
sl@0
   243
//	char softsign;		/* temporary negative sign for floats */
sl@0
   244
	double _double;		/* double precision arguments %[eEfgG] */
sl@0
   245
//	int expt;		/* integer value of exponent */
sl@0
   246
//	int expsize;		/* character count for expstr */
sl@0
   247
//	int ndig;		/* actual number of digits returned by cvt */
sl@0
   248
//	char expstr[7];		/* buffer for exponent string */
sl@0
   249
sl@0
   250
#ifndef _NO_LONGLONG
sl@0
   251
#define	quad_t	  long long
sl@0
   252
#define	u_quad_t  unsigned long long
sl@0
   253
#endif
sl@0
   254
sl@0
   255
#ifndef _NO_LONGLONG
sl@0
   256
	u_quad_t _uquad;	/* integer arguments %[diouxX] */
sl@0
   257
#else
sl@0
   258
	u_long _uquad;
sl@0
   259
#endif
sl@0
   260
	enum { OCT, DEC, HEX } base;/* base for [diouxX] conversion */
sl@0
   261
	int dprec;		/* a copy of prec if [diouxX], 0 otherwise */
sl@0
   262
	int realsz;		/* field size expanded by dprec */
sl@0
   263
	int size;		/* size of converted field or string */
sl@0
   264
	char *xdigs = NULL;	/* digits for [xX] conversion */
sl@0
   265
#define NIOV 8
sl@0
   266
	struct __suio uio;	/* output information: summary */
sl@0
   267
	struct __siov iov[NIOV];/* ... and individual io vectors */
sl@0
   268
	char buf[BUF];		/* space for %c, %[diouxX], %[eEfgG] */
sl@0
   269
	char ox[2];		/* space for 0x hex-prefix */
sl@0
   270
sl@0
   271
	/*
sl@0
   272
	 * Choose PADSIZE to trade efficiency vs. size.  If larger printf
sl@0
   273
	 * fields occur frequently, increase PADSIZE and make the initialisers
sl@0
   274
	 * below longer.
sl@0
   275
	 */
sl@0
   276
#define	PADSIZE	16		/* pad chunk size */
sl@0
   277
	static const char blanks[PADSIZE] =
sl@0
   278
	 {' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
sl@0
   279
	static const char zeroes[PADSIZE] =
sl@0
   280
	 {'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'};
sl@0
   281
sl@0
   282
	/*
sl@0
   283
	 * BEWARE, these `goto error' on error, and PAD uses `n'.
sl@0
   284
	 */
sl@0
   285
#define	PRINT(ptr, len) { \
sl@0
   286
	iovp->iov_base = (ptr); \
sl@0
   287
	iovp->iov_len = (len); \
sl@0
   288
	uio.uio_resid += (len); \
sl@0
   289
	iovp++; \
sl@0
   290
	if (++uio.uio_iovcnt >= NIOV) { \
sl@0
   291
		if (__sprint(fp, &uio)) \
sl@0
   292
			goto error; \
sl@0
   293
		iovp = iov; \
sl@0
   294
	} \
sl@0
   295
}
sl@0
   296
#define	PAD(howmany, with) { \
sl@0
   297
	if ((n = (howmany)) > 0) { \
sl@0
   298
		while (n > PADSIZE) { \
sl@0
   299
			PRINT(with, PADSIZE); \
sl@0
   300
			n -= PADSIZE; \
sl@0
   301
		} \
sl@0
   302
		PRINT(with, n); \
sl@0
   303
	} \
sl@0
   304
}
sl@0
   305
#define	FLUSH() { \
sl@0
   306
	if (uio.uio_resid && __sprint(fp, &uio)) \
sl@0
   307
		goto error; \
sl@0
   308
	uio.uio_iovcnt = 0; \
sl@0
   309
	iovp = iov; \
sl@0
   310
}
sl@0
   311
sl@0
   312
	/*
sl@0
   313
	 * To extend shorts properly, we need both signed and unsigned
sl@0
   314
	 * argument extraction methods.
sl@0
   315
	 */
sl@0
   316
#ifndef _NO_LONGLONG
sl@0
   317
#define	SARG() \
sl@0
   318
	(flags&QUADINT ? va_arg(ap, quad_t) : \
sl@0
   319
	    flags&LONGINT ? va_arg(ap, long) : \
sl@0
   320
	    flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
sl@0
   321
	    (long)va_arg(ap, int))
sl@0
   322
#define	UARG() \
sl@0
   323
	(flags&QUADINT ? va_arg(ap, u_quad_t) : \
sl@0
   324
	    flags&LONGINT ? va_arg(ap, u_long) : \
sl@0
   325
	    flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
sl@0
   326
	    (u_long)va_arg(ap, u_int))
sl@0
   327
#else
sl@0
   328
#define	SARG() \
sl@0
   329
	(flags&LONGINT ? va_arg(ap, long) : \
sl@0
   330
	    flags&SHORTINT ? (long)(short)va_arg(ap, int) : \
sl@0
   331
	    (long)va_arg(ap, int))
sl@0
   332
#define	UARG() \
sl@0
   333
	(flags&LONGINT ? va_arg(ap, u_long) : \
sl@0
   334
	    flags&SHORTINT ? (u_long)(u_short)va_arg(ap, int) : \
sl@0
   335
	    (u_long)va_arg(ap, u_int))
sl@0
   336
#endif
sl@0
   337
sl@0
   338
	CHECK_INIT (fp);
sl@0
   339
sl@0
   340
	/* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
sl@0
   341
	if (cantwrite(fp))
sl@0
   342
		return (EOF);
sl@0
   343
sl@0
   344
	/* optimise fprintf(stderr) (and other unbuffered Unix files) */
sl@0
   345
	if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
sl@0
   346
	    fp->_file >= 0)
sl@0
   347
		return (__sbprintf(fp, fmt0, ap));
sl@0
   348
sl@0
   349
	fmt = (char *)fmt0;
sl@0
   350
	uio.uio_iov = iovp = iov;
sl@0
   351
	uio.uio_resid = 0;
sl@0
   352
	uio.uio_iovcnt = 0;
sl@0
   353
	ret = 0;
sl@0
   354
sl@0
   355
	/*
sl@0
   356
	 * Scan the format for conversions (`%' character).
sl@0
   357
	 */
sl@0
   358
	for (;;) {
sl@0
   359
		cp = fmt;
sl@0
   360
		while ((n = mbtowc(&wc, fmt, MB_CUR_MAX)) > 0) {
sl@0
   361
			fmt += n;
sl@0
   362
			if (wc == L'%') {
sl@0
   363
				fmt--;
sl@0
   364
				break;
sl@0
   365
			}
sl@0
   366
		}
sl@0
   367
		if ((m = fmt - cp) != 0) {
sl@0
   368
			PRINT(cp, m);
sl@0
   369
			ret += m;
sl@0
   370
		}
sl@0
   371
		if (n <= 0)
sl@0
   372
			goto done;
sl@0
   373
		fmt++;		/* skip over '%' */
sl@0
   374
sl@0
   375
		flags = 0;
sl@0
   376
		dprec = 0;
sl@0
   377
		width = 0;
sl@0
   378
		prec = -1;
sl@0
   379
		sign = '\0';
sl@0
   380
sl@0
   381
rflag:		ch = *fmt++;
sl@0
   382
reswitch:	switch (ch) {
sl@0
   383
		case ' ':
sl@0
   384
			/*
sl@0
   385
			 * ``If the space and + flags both appear, the space
sl@0
   386
			 * flag will be ignored.''
sl@0
   387
			 *	-- ANSI X3J11
sl@0
   388
			 */
sl@0
   389
			if (!sign)
sl@0
   390
				sign = ' ';
sl@0
   391
			goto rflag;
sl@0
   392
		case '#':
sl@0
   393
			flags |= ALT;
sl@0
   394
			goto rflag;
sl@0
   395
		case '*':
sl@0
   396
			/*
sl@0
   397
			 * ``A negative field width argument is taken as a
sl@0
   398
			 * - flag followed by a positive field width.''
sl@0
   399
			 *	-- ANSI X3J11
sl@0
   400
			 * They don't exclude field widths read from args.
sl@0
   401
			 */
sl@0
   402
			if ((width = va_arg(ap, int)) >= 0)
sl@0
   403
				goto rflag;
sl@0
   404
			width = -width;
sl@0
   405
			/* FALLTHROUGH */
sl@0
   406
		case '-':
sl@0
   407
			flags |= LADJUST;
sl@0
   408
			goto rflag;
sl@0
   409
		case '+':
sl@0
   410
			sign = '+';
sl@0
   411
			goto rflag;
sl@0
   412
		case '.':
sl@0
   413
			if ((ch = *fmt++) == '*') {
sl@0
   414
				n = va_arg(ap, int);
sl@0
   415
				prec = n < 0 ? -1 : n;
sl@0
   416
				goto rflag;
sl@0
   417
			}
sl@0
   418
			n = 0;
sl@0
   419
			while (is_digit(ch)) {
sl@0
   420
				n = 10 * n + to_digit(ch);
sl@0
   421
				ch = *fmt++;
sl@0
   422
			}
sl@0
   423
			prec = n < 0 ? -1 : n;
sl@0
   424
			goto reswitch;
sl@0
   425
		case '0':
sl@0
   426
			/*
sl@0
   427
			 * ``Note that 0 is taken as a flag, not as the
sl@0
   428
			 * beginning of a field width.''
sl@0
   429
			 *	-- ANSI X3J11
sl@0
   430
			 */
sl@0
   431
			flags |= ZEROPAD;
sl@0
   432
			goto rflag;
sl@0
   433
		case '1': case '2': case '3': case '4':
sl@0
   434
		case '5': case '6': case '7': case '8': case '9':
sl@0
   435
			n = 0;
sl@0
   436
			do {
sl@0
   437
				n = 10 * n + to_digit(ch);
sl@0
   438
				ch = *fmt++;
sl@0
   439
			} while (is_digit(ch));
sl@0
   440
			width = n;
sl@0
   441
			goto reswitch;
sl@0
   442
		case 'L':
sl@0
   443
			flags |= LONGDBL;
sl@0
   444
			goto rflag;
sl@0
   445
		case 'h':
sl@0
   446
			flags |= SHORTINT;
sl@0
   447
			goto rflag;
sl@0
   448
		case 'l':
sl@0
   449
			if (*fmt == 'l') {
sl@0
   450
				fmt++;
sl@0
   451
				flags |= QUADINT;
sl@0
   452
			} else {
sl@0
   453
				flags |= LONGINT;
sl@0
   454
			}
sl@0
   455
			goto rflag;
sl@0
   456
		case 'q':
sl@0
   457
			flags |= QUADINT;
sl@0
   458
			goto rflag;
sl@0
   459
		case 'c':
sl@0
   460
			*(cp = buf) = (char)va_arg(ap, int);
sl@0
   461
			size = 1;
sl@0
   462
			sign = '\0';
sl@0
   463
			break;
sl@0
   464
		case 'D':
sl@0
   465
			flags |= LONGINT;
sl@0
   466
			/*FALLTHROUGH*/
sl@0
   467
		case 'd':
sl@0
   468
		case 'i':
sl@0
   469
			_uquad = SARG();
sl@0
   470
#ifndef _NO_LONGLONG
sl@0
   471
			if ((quad_t)_uquad < 0)
sl@0
   472
#else
sl@0
   473
			if ((long) _uquad < 0)
sl@0
   474
#endif
sl@0
   475
			{
sl@0
   476
sl@0
   477
#ifndef _NO_LONGLONG
sl@0
   478
				_uquad = -_uquad;
sl@0
   479
#else
sl@0
   480
				_uquad = (u_long)(-(long)_uquad);
sl@0
   481
#endif
sl@0
   482
				sign = '-';
sl@0
   483
			}
sl@0
   484
			base = DEC;
sl@0
   485
			goto number;
sl@0
   486
sl@0
   487
		case 'e':
sl@0
   488
		case 'E':
sl@0
   489
		case 'f':
sl@0
   490
		case 'g':
sl@0
   491
		case 'G':
sl@0
   492
			if (prec == -1) {
sl@0
   493
				prec = DEFPREC;
sl@0
   494
			} else if ((ch == 'g' || ch == 'G') && prec == 0) {
sl@0
   495
				prec = 1;
sl@0
   496
			}
sl@0
   497
sl@0
   498
			if (flags & LONGDBL) {
sl@0
   499
				_double = (double) va_arg(ap, long double);
sl@0
   500
			} else {
sl@0
   501
				_double = va_arg(ap, double);
sl@0
   502
			}
sl@0
   503
sl@0
   504
			/* do this before tricky precision changes */
sl@0
   505
			if (isinf(_double)) {
sl@0
   506
				if (_double < 0)
sl@0
   507
					sign = '-';
sl@0
   508
				cp = "Inf";
sl@0
   509
				size = 3;
sl@0
   510
				break;
sl@0
   511
			}
sl@0
   512
			if (isnan(_double)) {
sl@0
   513
				cp = "NaN";
sl@0
   514
				size = 3;
sl@0
   515
				break;
sl@0
   516
			}
sl@0
   517
			flags |= FPT;
sl@0
   518
#if 0
sl@0
   519
			cp = cvt(data, _double, prec, flags, &softsign,
sl@0
   520
				&expt, ch, &ndig);
sl@0
   521
			if (ch == 'g' || ch == 'G') {
sl@0
   522
				if (expt <= -4 || expt > prec)
sl@0
   523
					ch = (ch == 'g') ? 'e' : 'E';
sl@0
   524
				else
sl@0
   525
					ch = 'g';
sl@0
   526
			} 
sl@0
   527
			if (ch <= 'e') {	/* 'e' or 'E' fmt */
sl@0
   528
				--expt;
sl@0
   529
				expsize = exponent(expstr, expt, ch);
sl@0
   530
				size = expsize + ndig;
sl@0
   531
				if (ndig > 1 || flags & ALT)
sl@0
   532
					++size;
sl@0
   533
			} else if (ch == 'f') {		/* f fmt */
sl@0
   534
				if (expt > 0) {
sl@0
   535
					size = expt;
sl@0
   536
					if (prec || flags & ALT)
sl@0
   537
						size += prec + 1;
sl@0
   538
				} else	/* "0.X" */
sl@0
   539
					size = prec + 2;
sl@0
   540
			} else if (expt >= ndig) {	/* fixed g fmt */
sl@0
   541
				size = expt;
sl@0
   542
				if (flags & ALT)
sl@0
   543
					++size;
sl@0
   544
			} else
sl@0
   545
				size = ndig + (expt > 0 ?
sl@0
   546
					1 : 2 - expt);
sl@0
   547
sl@0
   548
			if (softsign)
sl@0
   549
				sign = '-';
sl@0
   550
#else
sl@0
   551
			if (_double < 0) {
sl@0
   552
				_double = -_double;
sl@0
   553
				sign = '-';
sl@0
   554
			}
sl@0
   555
			size = e32cvt(buf, BUF, _double, width, prec, flags, ch);
sl@0
   556
			cp=buf;
sl@0
   557
#endif
sl@0
   558
			break;
sl@0
   559
sl@0
   560
		case 'n':
sl@0
   561
#ifndef _NO_LONGLONG
sl@0
   562
			if (flags & QUADINT)
sl@0
   563
				*va_arg(ap, quad_t *) = ret;
sl@0
   564
			else 
sl@0
   565
#endif
sl@0
   566
			if (flags & LONGINT)
sl@0
   567
				*va_arg(ap, long *) = ret;
sl@0
   568
			else if (flags & SHORTINT)
sl@0
   569
				*va_arg(ap, short *) = (short)ret;
sl@0
   570
			else
sl@0
   571
				*va_arg(ap, int *) = ret;
sl@0
   572
			continue;	/* no output */
sl@0
   573
		case 'O':
sl@0
   574
			flags |= LONGINT;
sl@0
   575
			/*FALLTHROUGH*/
sl@0
   576
		case 'o':
sl@0
   577
			_uquad = UARG();
sl@0
   578
			base = OCT;
sl@0
   579
			goto nosign;
sl@0
   580
		case 'p':
sl@0
   581
			/*
sl@0
   582
			 * ``The argument shall be a pointer to void.  The
sl@0
   583
			 * value of the pointer is converted to a sequence
sl@0
   584
			 * of printable characters, in an implementation-
sl@0
   585
			 * defined manner.''
sl@0
   586
			 *	-- ANSI X3J11
sl@0
   587
			 */
sl@0
   588
			/* NOSTRICT */
sl@0
   589
			_uquad = (u_long)va_arg(ap, void *);
sl@0
   590
			base = HEX;
sl@0
   591
			xdigs = "0123456789abcdef";
sl@0
   592
			flags |= HEXPREFIX;
sl@0
   593
			ch = 'x';
sl@0
   594
			goto nosign;
sl@0
   595
		case 's':
sl@0
   596
			if ((cp = va_arg(ap, char *)) == NULL)
sl@0
   597
				cp = "(null)";
sl@0
   598
			if (prec >= 0) {
sl@0
   599
				/*
sl@0
   600
				 * can't use strlen; can only look for the
sl@0
   601
				 * NUL in the first `prec' characters, and
sl@0
   602
				 * strlen() will go further.
sl@0
   603
				 */
sl@0
   604
				char *p = (char *)memchr(cp, 0, prec);
sl@0
   605
sl@0
   606
				if (p != NULL) {
sl@0
   607
					size = p - cp;
sl@0
   608
					if (size > prec)
sl@0
   609
						size = prec;
sl@0
   610
				} else
sl@0
   611
					size = prec;
sl@0
   612
			} else
sl@0
   613
				size = strlen(cp);
sl@0
   614
			sign = '\0';
sl@0
   615
			break;
sl@0
   616
		case 'U':
sl@0
   617
			flags |= LONGINT;
sl@0
   618
			/*FALLTHROUGH*/
sl@0
   619
		case 'u':
sl@0
   620
			_uquad = UARG();
sl@0
   621
			base = DEC;
sl@0
   622
			goto nosign;
sl@0
   623
		case 'X':
sl@0
   624
			xdigs = "0123456789ABCDEF";
sl@0
   625
			goto hex;
sl@0
   626
		case 'x':
sl@0
   627
			xdigs = "0123456789abcdef";
sl@0
   628
hex:			_uquad = UARG();
sl@0
   629
			base = HEX;
sl@0
   630
			/* leading 0x/X only if non-zero */
sl@0
   631
			if (flags & ALT && _uquad != 0)
sl@0
   632
				flags |= HEXPREFIX;
sl@0
   633
sl@0
   634
			/* unsigned conversions */
sl@0
   635
nosign:			sign = '\0';
sl@0
   636
			/*
sl@0
   637
			 * ``... diouXx conversions ... if a precision is
sl@0
   638
			 * specified, the 0 flag will be ignored.''
sl@0
   639
			 *	-- ANSI X3J11
sl@0
   640
			 */
sl@0
   641
number:			if ((dprec = prec) >= 0)
sl@0
   642
				flags &= ~ZEROPAD;
sl@0
   643
sl@0
   644
			/*
sl@0
   645
			 * ``The result of converting a zero value with an
sl@0
   646
			 * explicit precision of zero is no characters.''
sl@0
   647
			 *	-- ANSI X3J11
sl@0
   648
			 */
sl@0
   649
			cp = buf + BUF;
sl@0
   650
			if (_uquad != 0 || prec != 0) {
sl@0
   651
				/*
sl@0
   652
				 * Unsigned mod is hard, and unsigned mod
sl@0
   653
				 * by a constant is easier than that by
sl@0
   654
				 * a variable; hence this switch.
sl@0
   655
				 */
sl@0
   656
				switch (base) {
sl@0
   657
				case OCT:
sl@0
   658
					do {
sl@0
   659
						*--cp = (char)to_char(_uquad & 7);
sl@0
   660
						_uquad >>= 3;
sl@0
   661
					} while (_uquad);
sl@0
   662
					/* handle octal leading 0 */
sl@0
   663
					if (flags & ALT && *cp != '0')
sl@0
   664
						*--cp = '0';
sl@0
   665
					break;
sl@0
   666
sl@0
   667
				case DEC:
sl@0
   668
					/* many numbers are 1 digit */
sl@0
   669
					while (_uquad >= 10) {
sl@0
   670
						*--cp = (char)to_char(_uquad % 10);
sl@0
   671
						_uquad /= 10;
sl@0
   672
					}
sl@0
   673
					*--cp = (char)to_char(_uquad);
sl@0
   674
					break;
sl@0
   675
sl@0
   676
				case HEX:
sl@0
   677
					do {
sl@0
   678
						*--cp = xdigs[_uquad & 15];
sl@0
   679
						_uquad >>= 4;
sl@0
   680
					} while (_uquad);
sl@0
   681
					break;
sl@0
   682
sl@0
   683
				default:
sl@0
   684
					cp = "bug in vfprintf: bad base";
sl@0
   685
					size = strlen(cp);
sl@0
   686
					goto skipsize;
sl@0
   687
				}
sl@0
   688
			}
sl@0
   689
			/* Workaround GCC compiler bug: size = buf + BUF - cp */
sl@0
   690
			{
sl@0
   691
				char *temp = buf+BUF;
sl@0
   692
				size = temp - cp;
sl@0
   693
			}
sl@0
   694
		skipsize:
sl@0
   695
			break;
sl@0
   696
		default:	/* "%?" prints ?, unless ? is NUL */
sl@0
   697
			if (ch == '\0')
sl@0
   698
				goto done;
sl@0
   699
			/* pretend it was %c with argument ch */
sl@0
   700
			cp = buf;
sl@0
   701
			*cp = (char)ch;
sl@0
   702
			size = 1;
sl@0
   703
			sign = '\0';
sl@0
   704
			break;
sl@0
   705
		}
sl@0
   706
sl@0
   707
		/*
sl@0
   708
		 * All reasonable formats wind up here.  At this point, `cp'
sl@0
   709
		 * points to a string which (if not flags&LADJUST) should be
sl@0
   710
		 * padded out to `width' places.  If flags&ZEROPAD, it should
sl@0
   711
		 * first be prefixed by any sign or other prefix; otherwise,
sl@0
   712
		 * it should be blank padded before the prefix is emitted.
sl@0
   713
		 * After any left-hand padding and prefixing, emit zeroes
sl@0
   714
		 * required by a decimal [diouxX] precision, then print the
sl@0
   715
		 * string proper, then emit zeroes required by any leftover
sl@0
   716
		 * floating precision; finally, if LADJUST, pad with blanks.
sl@0
   717
		 *
sl@0
   718
		 * Compute actual size, so we know how much to pad.
sl@0
   719
		 * size excludes decimal prec; realsz includes it.
sl@0
   720
		 */
sl@0
   721
		realsz = dprec > size ? dprec : size;
sl@0
   722
		if (sign)
sl@0
   723
			realsz++;
sl@0
   724
		else if (flags & HEXPREFIX)
sl@0
   725
			realsz+= 2;
sl@0
   726
sl@0
   727
		/* right-adjusting blank padding */
sl@0
   728
		if ((flags & (LADJUST|ZEROPAD)) == 0)
sl@0
   729
			PAD(width - realsz, blanks);
sl@0
   730
sl@0
   731
		/* prefix */
sl@0
   732
		if (sign) {
sl@0
   733
			PRINT(&sign, 1);
sl@0
   734
		} else if (flags & HEXPREFIX) {
sl@0
   735
			ox[0] = '0';
sl@0
   736
			ox[1] = (char)ch;
sl@0
   737
			PRINT(ox, 2);
sl@0
   738
		}
sl@0
   739
sl@0
   740
		/* right-adjusting zero padding */
sl@0
   741
		if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
sl@0
   742
			PAD(width - realsz, zeroes);
sl@0
   743
sl@0
   744
		/* leading zeroes from decimal precision */
sl@0
   745
		PAD(dprec - size, zeroes);
sl@0
   746
sl@0
   747
		/* the string or number proper */
sl@0
   748
		PRINT(cp, size);
sl@0
   749
#if 0
sl@0
   750
		} else {	/* glue together f_p fragments */
sl@0
   751
			if (ch >= 'f') {	/* 'f' or 'g' */
sl@0
   752
				if (_double == 0) {
sl@0
   753
					/* kludge for __dtoa irregularity */
sl@0
   754
					PRINT("0", 1);
sl@0
   755
					if (expt < ndig || (flags & ALT) != 0) {
sl@0
   756
						PRINT(decimal_point, 1);
sl@0
   757
						PAD(ndig - 1, zeroes);
sl@0
   758
					}
sl@0
   759
				} else if (expt <= 0) {
sl@0
   760
					PRINT("0", 1);
sl@0
   761
					PRINT(decimal_point, 1);
sl@0
   762
					PAD(-expt, zeroes);
sl@0
   763
					PRINT(cp, ndig);
sl@0
   764
				} else if (expt >= ndig) {
sl@0
   765
					PRINT(cp, ndig);
sl@0
   766
					PAD(expt - ndig, zeroes);
sl@0
   767
					if (flags & ALT)
sl@0
   768
						PRINT(".", 1);
sl@0
   769
				} else {
sl@0
   770
					PRINT(cp, expt);
sl@0
   771
					cp += expt;
sl@0
   772
					PRINT(".", 1);
sl@0
   773
					PRINT(cp, ndig-expt);
sl@0
   774
				}
sl@0
   775
			} else {	/* 'e' or 'E' */
sl@0
   776
				if (ndig > 1 || flags & ALT) {
sl@0
   777
					ox[0] = *cp++;
sl@0
   778
					ox[1] = '.';
sl@0
   779
					PRINT(ox, 2);
sl@0
   780
					if (_double || (flags & ALT) == 0) {
sl@0
   781
						PRINT(cp, ndig-1);
sl@0
   782
					} else	/* 0.[0..] */
sl@0
   783
						/* __dtoa irregularity */
sl@0
   784
						PAD(ndig - 1, zeroes);
sl@0
   785
				} else	/* XeYYY */
sl@0
   786
					PRINT(cp, 1);
sl@0
   787
				PRINT(expstr, expsize);
sl@0
   788
			}
sl@0
   789
		}
sl@0
   790
#endif
sl@0
   791
		/* left-adjusting padding (always blank) */
sl@0
   792
		if (flags & LADJUST)
sl@0
   793
			PAD(width - realsz, blanks);
sl@0
   794
sl@0
   795
		/* finally, adjust ret */
sl@0
   796
		ret += width > realsz ? width : realsz;
sl@0
   797
sl@0
   798
		FLUSH();	/* copy out the I/O vectors */
sl@0
   799
	}
sl@0
   800
done:
sl@0
   801
	FLUSH();
sl@0
   802
error:
sl@0
   803
	return (__sferror(fp) ? EOF : ret);
sl@0
   804
	/* NOTREACHED */
sl@0
   805
}
sl@0
   806
sl@0
   807
#if 0
sl@0
   808
static char *
sl@0
   809
cvt(struct _reent *data,double value,int ndigits, int flags, char *sign, int *decpt, int ch, int *length)
sl@0
   810
{
sl@0
   811
	int mode, dsgn;
sl@0
   812
	char *digits, *bp, *rve;
sl@0
   813
sl@0
   814
	if (ch == 'f') {
sl@0
   815
		mode = 3;		/* ndigits after the decimal point */
sl@0
   816
	} else {
sl@0
   817
		/* To obtain ndigits after the decimal point for the 'e' 
sl@0
   818
		 * and 'E' formats, round to ndigits + 1 significant 
sl@0
   819
		 * figures.
sl@0
   820
		 */
sl@0
   821
		if (ch == 'e' || ch == 'E') {
sl@0
   822
			ndigits++;
sl@0
   823
		}
sl@0
   824
		mode = 2;		/* ndigits significant digits */
sl@0
   825
	}
sl@0
   826
sl@0
   827
	if (value < 0) {
sl@0
   828
		value = -value;
sl@0
   829
		*sign = '-';
sl@0
   830
	} else
sl@0
   831
		*sign = '\000';
sl@0
   832
	digits = _dtoa_r(data, value, mode, ndigits, decpt, &dsgn, &rve);
sl@0
   833
	if ((ch != 'g' && ch != 'G') || flags & ALT) {	/* Print trailing zeros */
sl@0
   834
		bp = digits + ndigits;
sl@0
   835
		if (ch == 'f') {
sl@0
   836
			if (*digits == '0' && value)
sl@0
   837
				*decpt = -ndigits + 1;
sl@0
   838
			bp += *decpt;
sl@0
   839
		}
sl@0
   840
		if (value == 0)	/* kludge for __dtoa irregularity */
sl@0
   841
			rve = bp;
sl@0
   842
		while (rve < bp)
sl@0
   843
			*rve++ = '0';
sl@0
   844
	}
sl@0
   845
	*length = rve - digits;
sl@0
   846
	return (digits);
sl@0
   847
}
sl@0
   848
sl@0
   849
static int
sl@0
   850
exponent(char *p0, int exp, int fmtch)
sl@0
   851
{
sl@0
   852
	register char *p, *t;
sl@0
   853
	char expbuf[MAXEXP];
sl@0
   854
sl@0
   855
	p = p0;
sl@0
   856
	*p++ = (char)fmtch;
sl@0
   857
	if (exp < 0) {
sl@0
   858
		exp = -exp;
sl@0
   859
		*p++ = '-';
sl@0
   860
	}
sl@0
   861
	else
sl@0
   862
		*p++ = '+';
sl@0
   863
	t = expbuf + MAXEXP;
sl@0
   864
	if (exp > 9) {
sl@0
   865
		do {
sl@0
   866
			*--t = (char)to_char(exp % 10);
sl@0
   867
		} while ((exp /= 10) > 9);
sl@0
   868
		*--t = (char)to_char(exp);
sl@0
   869
		for (; t < expbuf + MAXEXP; *p++ = *t++);
sl@0
   870
	}
sl@0
   871
	else {
sl@0
   872
		*p++ = '0';
sl@0
   873
		*p++ = (char)to_char(exp);
sl@0
   874
	}
sl@0
   875
	return (p - p0);
sl@0
   876
}
sl@0
   877
#endif