134226Sbostic /* 234233Sbostic * Copyright (c) 1988 Regents of the University of California. 334233Sbostic * All rights reserved. 434226Sbostic * 534233Sbostic * Redistribution and use in source and binary forms are permitted 634233Sbostic * provided that this notice is preserved and that due credit is given 734233Sbostic * to the University of California at Berkeley. The name of the University 834233Sbostic * may not be used to endorse or promote products derived from this 934233Sbostic * software without specific prior written permission. This software 1034233Sbostic * is provided ``as is'' without express or implied warranty. 1134226Sbostic */ 1234226Sbostic 1334233Sbostic #if defined(LIBC_SCCS) && !defined(lint) 14*34236Sbostic static char sccsid[] = "@(#)vfprintf.c 5.4 (Berkeley) 05/08/88"; 1534233Sbostic #endif /* LIBC_SCCS and not lint */ 1634233Sbostic 1734233Sbostic #include <sys/param.h> 1834233Sbostic #include <varargs.h> 1934226Sbostic #include <stdio.h> 2034233Sbostic #include <ctype.h> 2134226Sbostic 2234235Sbostic #define GETARG(r) \ 2334235Sbostic r = argsize&LONGINT ? va_arg(argp, long) : \ 2434235Sbostic argsize&SHORTINT ? va_arg(argp, short) : va_arg(argp, int); 2534235Sbostic 26*34236Sbostic #define MAXBUF 1024 /* should hold any number */ 27*34236Sbostic #define MAXEXP 10 /* should hold any exponent */ 28*34236Sbostic 2934235Sbostic #define DEFPREC 6 /* default precision */ 3034226Sbostic 31*34236Sbostic #define PUTC(ch, fd) {++cnt; putc(ch, fd);} 32*34236Sbostic 3334235Sbostic #define LONGINT 0x01 3434235Sbostic #define LONGDBL 0x02 3534235Sbostic #define SHORTINT 0x04 3634235Sbostic 3734235Sbostic x_doprnt(fmt, argp, fp) 3834233Sbostic register char *fmt; 3934233Sbostic va_list argp; 4034235Sbostic register FILE *fp; 4134226Sbostic { 4234233Sbostic register u_long reg_ulong; 4334233Sbostic register long reg_long; 4434233Sbostic register int base; 4534235Sbostic register char *digs, *bp, *t, padc; 4634235Sbostic double _double; 47*34236Sbostic char argsize, printsign, buf[MAXBUF], *ecvt(), *fcvt(); 4834235Sbostic int alternate, cnt, decpt, n, ladjust, width, prec, sign, size; 4934226Sbostic 5034233Sbostic for (cnt = 0; *fmt; ++fmt) { 5134233Sbostic if (*fmt != '%') { 5234235Sbostic PUTC(*fmt, fp); 5334233Sbostic continue; 5434226Sbostic } 5534226Sbostic 5634235Sbostic alternate = ladjust = width = 0; 5734233Sbostic prec = -1; 5834233Sbostic padc = ' '; 5934235Sbostic argsize = printsign = '\0'; 6034226Sbostic 6134233Sbostic flags: switch (*++fmt) { 6234233Sbostic case '#': 6334233Sbostic alternate = 1; 6434233Sbostic goto flags; 6534233Sbostic case '%': /* "%#%" prints as "%" */ 6634235Sbostic PUTC('%', fp); 6734233Sbostic continue; 6834233Sbostic case '*': 6934235Sbostic /* 7034235Sbostic * ``A negative field width argument is taken as a 7134235Sbostic * - flag followed by a positive field width.'' 7234235Sbostic * -- ANSI X3J11 7334235Sbostic * They don't exclude field widths read from args. 7434235Sbostic */ 7534235Sbostic if ((width = va_arg(argp, int)) >= 0) 7634235Sbostic goto flags; 7734235Sbostic width = -width; 7834235Sbostic /*FALLTHROUGH*/ 7934235Sbostic case '-': 8034235Sbostic ladjust = 1; 8134233Sbostic goto flags; 8234233Sbostic case '+': 8334233Sbostic printsign = '+'; 8434233Sbostic goto flags; 8534233Sbostic case '.': 8634235Sbostic if (*++fmt == '*') 8734235Sbostic prec = va_arg(argp, int); 8834235Sbostic else if (isdigit(*fmt)) { 8934235Sbostic prec = 0; 9034233Sbostic do { 91*34236Sbostic prec = 10 * prec + *fmt - '0'; 9234233Sbostic } while isdigit(*++fmt); 9334233Sbostic --fmt; 9434226Sbostic } 9534235Sbostic else { 9634235Sbostic prec = 0; 9734235Sbostic --fmt; 9834235Sbostic goto flags; 9934235Sbostic } 10034235Sbostic if (prec < 0) 10134235Sbostic prec = -1; 10234233Sbostic goto flags; 10334233Sbostic case '0': 10434233Sbostic padc = '0'; 10534235Sbostic /*FALLTHROUGH*/ 10634233Sbostic case '1': case '2': case '3': case '4': 10734233Sbostic case '5': case '6': case '7': case '8': case '9': 10834233Sbostic do { 109*34236Sbostic width = 10 * width + *fmt - '0'; 11034233Sbostic } while isdigit(*++fmt); 11134233Sbostic --fmt; 11234235Sbostic case 'L': 11334235Sbostic argsize |= LONGDBL; 11434235Sbostic goto flags; 11534235Sbostic case 'h': 11634235Sbostic argsize |= SHORTINT; 11734235Sbostic goto flags; 11834233Sbostic case 'l': 11934235Sbostic argsize |= LONGINT; 12034233Sbostic goto flags; 12134226Sbostic } 12234226Sbostic 12334233Sbostic digs = "0123456789abcdef"; 12434226Sbostic 12534233Sbostic switch (*fmt) { 12634226Sbostic case 'c': 12734235Sbostic PUTC(va_arg(argp, int), fp); 12834226Sbostic break; 129*34236Sbostic case 'E': 130*34236Sbostic case 'e': 131*34236Sbostic if (prec == -1) 132*34236Sbostic prec = DEFPREC; 133*34236Sbostic _double = va_arg(argp, double); 134*34236Sbostic t = ecvt(_double, prec + 1, &decpt, &sign); 135*34236Sbostic bp = buf; 136*34236Sbostic *bp++ = *t ? *t++ : '0'; 137*34236Sbostic if (alternate || prec > 0) 138*34236Sbostic *bp++ = '.'; 139*34236Sbostic while (prec--) 140*34236Sbostic *bp++ = *t ? *t++ : '0'; 141*34236Sbostic *bp++ = *fmt; 142*34236Sbostic *bp++ = (decpt > 0 || !_double) ? '+' : '-'; 143*34236Sbostic /* we know exponents <= 99 */ 144*34236Sbostic --decpt; 145*34236Sbostic *bp++ = (int)decpt / 10 + '0'; 146*34236Sbostic *bp++ = (int)decpt % 10 + '0'; 147*34236Sbostic goto pbuf; 14834235Sbostic case 'f': 14934235Sbostic if (prec == -1) 15034235Sbostic prec = DEFPREC; 15134235Sbostic _double = va_arg(argp, double); 15234235Sbostic t = fcvt(_double, prec + 1, &decpt, &sign); 15334235Sbostic bp = buf; 15434235Sbostic if (decpt >= 0) 15534235Sbostic for (;;) { 15634235Sbostic *bp++ = *t ? *t++ : '0'; 15734235Sbostic if (!--decpt) 15834235Sbostic break; 15934235Sbostic } 16034235Sbostic if (alternate || prec > 0) 16134235Sbostic *bp++ = '.'; 16234235Sbostic while (decpt++) { 16334235Sbostic *bp++ = *t ? *t++ : '0'; 16434235Sbostic --prec; 16534235Sbostic } 16634235Sbostic while (prec--) 16734235Sbostic *bp++ = *t ? *t++ : '0'; 168*34236Sbostic pbuf: size = bp - buf; 169*34236Sbostic if (sign || printsign) 170*34236Sbostic PUTC(sign ? '-' : printsign, fp); 17134235Sbostic if (size < width && !ladjust) 17234235Sbostic do { 17334235Sbostic PUTC(padc, fp); 17434235Sbostic } while (--width > size); 17534235Sbostic for (t = buf; t < bp; ++t) 17634235Sbostic PUTC(*t, fp); 17734235Sbostic for (; width > size; --width) 17834235Sbostic PUTC(padc, fp); 17934235Sbostic break; 18034226Sbostic case 'd': 18134235Sbostic case 'i': 18234235Sbostic GETARG(reg_long); 18334233Sbostic if (reg_long < 0) { 18434233Sbostic reg_ulong = -reg_long; 18534233Sbostic printsign = '-'; 18634233Sbostic } 18734233Sbostic else { 18834233Sbostic reg_ulong = reg_long; 18934233Sbostic } 19034233Sbostic if (printsign) 19134235Sbostic PUTC(printsign, fp); 19234226Sbostic base = 10; 19334235Sbostic goto num1; 19434235Sbostic case 'n': 19534235Sbostic *(va_arg(argp, int *)) = cnt; 19634235Sbostic break; 19734226Sbostic case 'o': 19834235Sbostic GETARG(reg_ulong); 19934226Sbostic base = 8; 20034235Sbostic if (!reg_ulong || !alternate) 20134235Sbostic goto num1; 20234235Sbostic bp = buf + sizeof(buf) - 1; 20334235Sbostic do { 20434235Sbostic *bp-- = digs[reg_ulong % base]; 20534235Sbostic reg_ulong /= base; 20634235Sbostic } while(reg_ulong); 20734235Sbostic size = &buf[sizeof(buf) - 1] - bp; 20834235Sbostic if (size < --width && !ladjust) 20934235Sbostic do { 21034235Sbostic PUTC(padc, fp); 21134235Sbostic } while (--width > size); 21234235Sbostic PUTC('0', fp); 213*34236Sbostic goto num2; 21434235Sbostic break; 21534235Sbostic case 'p': 21634226Sbostic case 's': 21734235Sbostic if (!(bp = va_arg(argp, char *))) 21834235Sbostic bp = "(null)"; 21934235Sbostic if (width > 0 && !ladjust) { 22034233Sbostic char *savep; 22134226Sbostic 22234235Sbostic savep = bp; 22334235Sbostic for (n = 0; *bp && (prec < 0 || n < prec); 22434235Sbostic n++, bp++); 22534235Sbostic bp = savep; 22634235Sbostic while (n++ < width) 22734235Sbostic PUTC(' ', fp); 22834233Sbostic } 22934235Sbostic for (n = 0; *bp; ++bp) { 23034235Sbostic if (++n > prec && prec >= 0) 23134226Sbostic break; 23234235Sbostic PUTC(*bp, fp); 23334233Sbostic } 23434235Sbostic if (n < width && ladjust) 23534233Sbostic do { 23634235Sbostic PUTC(' ', fp); 23734235Sbostic } while (++n < width); 23834226Sbostic break; 23934226Sbostic case 'u': 24034235Sbostic GETARG(reg_ulong); 24134226Sbostic base = 10; 24234235Sbostic goto num1; 24334226Sbostic case 'X': 24434226Sbostic digs = "0123456789ABCDEF"; 24534233Sbostic /*FALLTHROUGH*/ 24634226Sbostic case 'x': 24734235Sbostic GETARG(reg_ulong); 24834233Sbostic if (alternate && reg_ulong) { 24934235Sbostic PUTC('0', fp); 25034235Sbostic PUTC(*fmt, fp); 25134233Sbostic } 25234226Sbostic base = 16; 25334235Sbostic num1: bp = buf + sizeof(buf) - 1; 25434233Sbostic do { 25534235Sbostic *bp-- = digs[reg_ulong % base]; 25634233Sbostic reg_ulong /= base; 25734233Sbostic } while(reg_ulong); 25834235Sbostic size = &buf[sizeof(buf) - 1] - bp; 25934235Sbostic for (; size < prec; *bp-- = '0', ++size); 26034235Sbostic if (size < width && !ladjust) 26134235Sbostic do { 26234235Sbostic PUTC(padc, fp); 26334235Sbostic } while (--width > size); 264*34236Sbostic num2: while (++bp != &buf[MAXBUF]) 26534235Sbostic PUTC(*bp, fp); 26634235Sbostic for (; width > size; --width) 26734235Sbostic PUTC(padc, fp); 26834226Sbostic break; 26934233Sbostic case '\0': /* "%?" prints ?, unless ? is NULL */ 27034235Sbostic return(ferror(fp) ? -1 : cnt); 27134226Sbostic default: 27234235Sbostic PUTC(*fmt, fp); 27334226Sbostic } 27434226Sbostic } 27534235Sbostic return(ferror(fp) ? -1 : cnt); 27634226Sbostic } 277