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*34241Sbostic static char sccsid[] = "@(#)vfprintf.c 5.5 (Berkeley) 05/09/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 22*34241Sbostic #define MAXBUF 120 /* should hold any number */ 2334235Sbostic #define DEFPREC 6 /* default precision */ 2434226Sbostic 2534236Sbostic #define PUTC(ch, fd) {++cnt; putc(ch, fd);} 2634236Sbostic 2734235Sbostic #define LONGINT 0x01 2834235Sbostic #define LONGDBL 0x02 2934235Sbostic #define SHORTINT 0x04 30*34241Sbostic #define GETARG(r) \ 31*34241Sbostic r = argsize&LONGINT ? va_arg(argp, long) : \ 32*34241Sbostic argsize&SHORTINT ? va_arg(argp, short) : va_arg(argp, int); 3334235Sbostic 3434235Sbostic x_doprnt(fmt, argp, fp) 3534233Sbostic register char *fmt; 3634233Sbostic va_list argp; 3734235Sbostic register FILE *fp; 3834226Sbostic { 3934233Sbostic register u_long reg_ulong; 4034233Sbostic register long reg_long; 4134233Sbostic register int base; 4234235Sbostic register char *digs, *bp, *t, padc; 4334235Sbostic double _double; 4434236Sbostic char argsize, printsign, buf[MAXBUF], *ecvt(), *fcvt(); 4534235Sbostic int alternate, cnt, decpt, n, ladjust, width, prec, sign, size; 4634226Sbostic 4734233Sbostic for (cnt = 0; *fmt; ++fmt) { 4834233Sbostic if (*fmt != '%') { 4934235Sbostic PUTC(*fmt, fp); 5034233Sbostic continue; 5134226Sbostic } 5234226Sbostic 5334235Sbostic alternate = ladjust = width = 0; 5434233Sbostic prec = -1; 5534233Sbostic padc = ' '; 5634235Sbostic argsize = printsign = '\0'; 5734226Sbostic 5834233Sbostic flags: switch (*++fmt) { 5934233Sbostic case '#': 6034233Sbostic alternate = 1; 6134233Sbostic goto flags; 6234233Sbostic case '%': /* "%#%" prints as "%" */ 6334235Sbostic PUTC('%', fp); 6434233Sbostic continue; 6534233Sbostic case '*': 6634235Sbostic /* 6734235Sbostic * ``A negative field width argument is taken as a 6834235Sbostic * - flag followed by a positive field width.'' 6934235Sbostic * -- ANSI X3J11 7034235Sbostic * They don't exclude field widths read from args. 7134235Sbostic */ 7234235Sbostic if ((width = va_arg(argp, int)) >= 0) 7334235Sbostic goto flags; 7434235Sbostic width = -width; 7534235Sbostic /*FALLTHROUGH*/ 7634235Sbostic case '-': 7734235Sbostic ladjust = 1; 7834233Sbostic goto flags; 7934233Sbostic case '+': 8034233Sbostic printsign = '+'; 8134233Sbostic goto flags; 8234233Sbostic case '.': 8334235Sbostic if (*++fmt == '*') 8434235Sbostic prec = va_arg(argp, int); 8534235Sbostic else if (isdigit(*fmt)) { 8634235Sbostic prec = 0; 8734233Sbostic do { 8834236Sbostic prec = 10 * prec + *fmt - '0'; 8934233Sbostic } while isdigit(*++fmt); 9034233Sbostic --fmt; 9134226Sbostic } 9234235Sbostic else { 9334235Sbostic prec = 0; 9434235Sbostic --fmt; 9534235Sbostic goto flags; 9634235Sbostic } 9734235Sbostic if (prec < 0) 9834235Sbostic prec = -1; 9934233Sbostic goto flags; 10034233Sbostic case '0': 10134233Sbostic padc = '0'; 10234235Sbostic /*FALLTHROUGH*/ 10334233Sbostic case '1': case '2': case '3': case '4': 10434233Sbostic case '5': case '6': case '7': case '8': case '9': 10534233Sbostic do { 10634236Sbostic width = 10 * width + *fmt - '0'; 10734233Sbostic } while isdigit(*++fmt); 10834233Sbostic --fmt; 10934235Sbostic case 'L': 11034235Sbostic argsize |= LONGDBL; 11134235Sbostic goto flags; 11234235Sbostic case 'h': 11334235Sbostic argsize |= SHORTINT; 11434235Sbostic goto flags; 11534233Sbostic case 'l': 11634235Sbostic argsize |= LONGINT; 11734233Sbostic goto flags; 11834226Sbostic } 11934226Sbostic 12034233Sbostic digs = "0123456789abcdef"; 12134226Sbostic 12234233Sbostic switch (*fmt) { 12334226Sbostic case 'c': 12434235Sbostic PUTC(va_arg(argp, int), fp); 12534226Sbostic break; 126*34241Sbostic case 'd': 127*34241Sbostic case 'i': 128*34241Sbostic GETARG(reg_long); 129*34241Sbostic if (reg_long < 0) { 130*34241Sbostic reg_ulong = -reg_long; 131*34241Sbostic printsign = '-'; 132*34241Sbostic } 133*34241Sbostic else { 134*34241Sbostic reg_ulong = reg_long; 135*34241Sbostic } 136*34241Sbostic if (printsign) 137*34241Sbostic PUTC(printsign, fp); 138*34241Sbostic base = 10; 139*34241Sbostic goto num1; 14034236Sbostic case 'E': 14134236Sbostic case 'e': 14234236Sbostic if (prec == -1) 14334236Sbostic prec = DEFPREC; 14434236Sbostic _double = va_arg(argp, double); 145*34241Sbostic t = fcvt(_double, prec + 1, &decpt, &sign); 146*34241Sbostic gise: bp = buf; 14734236Sbostic *bp++ = *t ? *t++ : '0'; 14834236Sbostic if (alternate || prec > 0) 14934236Sbostic *bp++ = '.'; 15034236Sbostic while (prec--) 15134236Sbostic *bp++ = *t ? *t++ : '0'; 15234236Sbostic *bp++ = *fmt; 153*34241Sbostic if (decpt > 0 || !_double) { 154*34241Sbostic *bp++ = '+'; 155*34241Sbostic --decpt; 156*34241Sbostic } 157*34241Sbostic else { 158*34241Sbostic *bp++ = '-'; 159*34241Sbostic decpt = -decpt + 1; 160*34241Sbostic } 161*34241Sbostic /* exponents <= 99 in ANSI X3J11 */ 162*34241Sbostic *bp++ = (int)(decpt / 10) + '0'; 163*34241Sbostic *bp++ = (int)(decpt % 10) + '0'; 16434236Sbostic goto pbuf; 16534235Sbostic case 'f': 16634235Sbostic if (prec == -1) 16734235Sbostic prec = DEFPREC; 16834235Sbostic _double = va_arg(argp, double); 16934235Sbostic t = fcvt(_double, prec + 1, &decpt, &sign); 170*34241Sbostic gisf: bp = buf; 17134235Sbostic if (decpt >= 0) 17234235Sbostic for (;;) { 17334235Sbostic *bp++ = *t ? *t++ : '0'; 17434235Sbostic if (!--decpt) 17534235Sbostic break; 17634235Sbostic } 177*34241Sbostic if (alternate || prec > 0) { 178*34241Sbostic if (decpt < 0) 179*34241Sbostic *bp++ = '0'; 18034235Sbostic *bp++ = '.'; 181*34241Sbostic } 18234235Sbostic while (decpt++) { 183*34241Sbostic *bp++ = '0'; 18434235Sbostic --prec; 18534235Sbostic } 18634235Sbostic while (prec--) 18734235Sbostic *bp++ = *t ? *t++ : '0'; 18834236Sbostic pbuf: size = bp - buf; 18934236Sbostic if (sign || printsign) 19034236Sbostic PUTC(sign ? '-' : printsign, fp); 19134235Sbostic if (size < width && !ladjust) 19234235Sbostic do { 19334235Sbostic PUTC(padc, fp); 19434235Sbostic } while (--width > size); 19534235Sbostic for (t = buf; t < bp; ++t) 19634235Sbostic PUTC(*t, fp); 19734235Sbostic for (; width > size; --width) 19834235Sbostic PUTC(padc, fp); 19934235Sbostic break; 200*34241Sbostic case 'G': 201*34241Sbostic case 'g': { 202*34241Sbostic int gotoe; 203*34241Sbostic 204*34241Sbostic if (prec == -1) 205*34241Sbostic prec = DEFPREC; 206*34241Sbostic _double = va_arg(argp, double); 207*34241Sbostic t = fcvt(_double, prec + 1, &decpt, &sign); 208*34241Sbostic gotoe = decpt > prec; 209*34241Sbostic if (!alternate) { 210*34241Sbostic for (bp = t + prec + decpt; prec && 211*34241Sbostic *--bp == '0'; --prec); 21234233Sbostic } 213*34241Sbostic if (gotoe || decpt < -3) { 214*34241Sbostic *fmt -= 2; 215*34241Sbostic goto gise; 21634233Sbostic } 217*34241Sbostic --*fmt; 218*34241Sbostic goto gisf; 219*34241Sbostic } 22034235Sbostic case 'n': 22134235Sbostic *(va_arg(argp, int *)) = cnt; 22234235Sbostic break; 22334226Sbostic case 'o': 22434235Sbostic GETARG(reg_ulong); 22534226Sbostic base = 8; 22634235Sbostic if (!reg_ulong || !alternate) 22734235Sbostic goto num1; 22834235Sbostic bp = buf + sizeof(buf) - 1; 22934235Sbostic do { 23034235Sbostic *bp-- = digs[reg_ulong % base]; 23134235Sbostic reg_ulong /= base; 23234235Sbostic } while(reg_ulong); 23334235Sbostic size = &buf[sizeof(buf) - 1] - bp; 23434235Sbostic if (size < --width && !ladjust) 23534235Sbostic do { 23634235Sbostic PUTC(padc, fp); 23734235Sbostic } while (--width > size); 23834235Sbostic PUTC('0', fp); 23934236Sbostic goto num2; 24034235Sbostic break; 24134235Sbostic case 'p': 24234226Sbostic case 's': 24334235Sbostic if (!(bp = va_arg(argp, char *))) 24434235Sbostic bp = "(null)"; 24534235Sbostic if (width > 0 && !ladjust) { 24634233Sbostic char *savep; 24734226Sbostic 24834235Sbostic savep = bp; 24934235Sbostic for (n = 0; *bp && (prec < 0 || n < prec); 25034235Sbostic n++, bp++); 25134235Sbostic bp = savep; 25234235Sbostic while (n++ < width) 25334235Sbostic PUTC(' ', fp); 25434233Sbostic } 25534235Sbostic for (n = 0; *bp; ++bp) { 25634235Sbostic if (++n > prec && prec >= 0) 25734226Sbostic break; 25834235Sbostic PUTC(*bp, fp); 25934233Sbostic } 26034235Sbostic if (n < width && ladjust) 26134233Sbostic do { 26234235Sbostic PUTC(' ', fp); 26334235Sbostic } while (++n < width); 26434226Sbostic break; 26534226Sbostic case 'u': 26634235Sbostic GETARG(reg_ulong); 26734226Sbostic base = 10; 26834235Sbostic goto num1; 26934226Sbostic case 'X': 27034226Sbostic digs = "0123456789ABCDEF"; 27134233Sbostic /*FALLTHROUGH*/ 27234226Sbostic case 'x': 27334235Sbostic GETARG(reg_ulong); 27434233Sbostic if (alternate && reg_ulong) { 27534235Sbostic PUTC('0', fp); 27634235Sbostic PUTC(*fmt, fp); 27734233Sbostic } 27834226Sbostic base = 16; 27934235Sbostic num1: bp = buf + sizeof(buf) - 1; 28034233Sbostic do { 28134235Sbostic *bp-- = digs[reg_ulong % base]; 28234233Sbostic reg_ulong /= base; 28334233Sbostic } while(reg_ulong); 28434235Sbostic size = &buf[sizeof(buf) - 1] - bp; 28534235Sbostic for (; size < prec; *bp-- = '0', ++size); 28634235Sbostic if (size < width && !ladjust) 28734235Sbostic do { 28834235Sbostic PUTC(padc, fp); 28934235Sbostic } while (--width > size); 29034236Sbostic num2: while (++bp != &buf[MAXBUF]) 29134235Sbostic PUTC(*bp, fp); 29234235Sbostic for (; width > size; --width) 29334235Sbostic PUTC(padc, fp); 29434226Sbostic break; 29534233Sbostic case '\0': /* "%?" prints ?, unless ? is NULL */ 29634235Sbostic return(ferror(fp) ? -1 : cnt); 29734226Sbostic default: 29834235Sbostic PUTC(*fmt, fp); 29934226Sbostic } 30034226Sbostic } 30134235Sbostic return(ferror(fp) ? -1 : cnt); 30234226Sbostic } 303