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*34235Sbostic static char sccsid[] = "@(#)vfprintf.c 5.3 (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 22*34235Sbostic #define GETARG(r) \ 23*34235Sbostic r = argsize&LONGINT ? va_arg(argp, long) : \ 24*34235Sbostic argsize&SHORTINT ? va_arg(argp, short) : va_arg(argp, int); 25*34235Sbostic 26*34235Sbostic #define DEFPREC 6 /* default precision */ 27*34235Sbostic #define MAXBUF 1024 2834233Sbostic #define PUTC(ch, fd) { ++cnt; putc(ch, fd); } 2934233Sbostic #define todigit(ch) ((ch) - '0') 30*34235Sbostic #define tochar(ch) ((ch) + '0') 3134226Sbostic 32*34235Sbostic #define LONGINT 0x01 33*34235Sbostic #define LONGDBL 0x02 34*34235Sbostic #define SHORTINT 0x04 35*34235Sbostic 36*34235Sbostic x_doprnt(fmt, argp, fp) 3734233Sbostic register char *fmt; 3834233Sbostic va_list argp; 39*34235Sbostic register FILE *fp; 4034226Sbostic { 4134233Sbostic register u_long reg_ulong; 4234233Sbostic register long reg_long; 4334233Sbostic register int base; 44*34235Sbostic register char *digs, *bp, *t, padc; 45*34235Sbostic double _double; 46*34235Sbostic char argsize, printsign, buf[MAXBUF], *fcvt(); 47*34235Sbostic int alternate, cnt, decpt, n, ladjust, width, prec, sign, size; 4834226Sbostic 4934233Sbostic for (cnt = 0; *fmt; ++fmt) { 5034233Sbostic if (*fmt != '%') { 51*34235Sbostic PUTC(*fmt, fp); 5234233Sbostic continue; 5334226Sbostic } 5434226Sbostic 55*34235Sbostic alternate = ladjust = width = 0; 5634233Sbostic prec = -1; 5734233Sbostic padc = ' '; 58*34235Sbostic argsize = printsign = '\0'; 5934226Sbostic 6034233Sbostic flags: switch (*++fmt) { 6134233Sbostic case '#': 6234233Sbostic alternate = 1; 6334233Sbostic goto flags; 6434233Sbostic case '%': /* "%#%" prints as "%" */ 65*34235Sbostic PUTC('%', fp); 6634233Sbostic continue; 6734233Sbostic case '*': 68*34235Sbostic /* 69*34235Sbostic * ``A negative field width argument is taken as a 70*34235Sbostic * - flag followed by a positive field width.'' 71*34235Sbostic * -- ANSI X3J11 72*34235Sbostic * They don't exclude field widths read from args. 73*34235Sbostic */ 74*34235Sbostic if ((width = va_arg(argp, int)) >= 0) 75*34235Sbostic goto flags; 76*34235Sbostic width = -width; 77*34235Sbostic /*FALLTHROUGH*/ 78*34235Sbostic case '-': 79*34235Sbostic ladjust = 1; 8034233Sbostic goto flags; 8134233Sbostic case '+': 8234233Sbostic printsign = '+'; 8334233Sbostic goto flags; 8434233Sbostic case '.': 85*34235Sbostic if (*++fmt == '*') 86*34235Sbostic prec = va_arg(argp, int); 87*34235Sbostic else if (isdigit(*fmt)) { 88*34235Sbostic prec = 0; 8934233Sbostic do { 9034233Sbostic prec = 10 * prec + todigit(*fmt); 9134233Sbostic } while isdigit(*++fmt); 9234233Sbostic --fmt; 9334226Sbostic } 94*34235Sbostic else { 95*34235Sbostic prec = 0; 96*34235Sbostic --fmt; 97*34235Sbostic goto flags; 98*34235Sbostic } 99*34235Sbostic if (prec < 0) 100*34235Sbostic prec = -1; 10134233Sbostic goto flags; 10234233Sbostic case '0': 10334233Sbostic padc = '0'; 104*34235Sbostic /*FALLTHROUGH*/ 10534233Sbostic case '1': case '2': case '3': case '4': 10634233Sbostic case '5': case '6': case '7': case '8': case '9': 10734233Sbostic do { 108*34235Sbostic width = 10 * width + todigit(*fmt); 10934233Sbostic } while isdigit(*++fmt); 11034233Sbostic --fmt; 111*34235Sbostic case 'L': 112*34235Sbostic argsize |= LONGDBL; 113*34235Sbostic goto flags; 114*34235Sbostic case 'h': 115*34235Sbostic argsize |= SHORTINT; 116*34235Sbostic goto flags; 11734233Sbostic case 'l': 118*34235Sbostic argsize |= LONGINT; 11934233Sbostic goto flags; 12034226Sbostic } 12134226Sbostic 12234233Sbostic digs = "0123456789abcdef"; 12334226Sbostic 12434233Sbostic switch (*fmt) { 12534226Sbostic case 'c': 126*34235Sbostic PUTC(va_arg(argp, int), fp); 12734226Sbostic break; 128*34235Sbostic case 'f': 129*34235Sbostic if (prec == -1) 130*34235Sbostic prec = DEFPREC; 131*34235Sbostic _double = va_arg(argp, double); 132*34235Sbostic t = fcvt(_double, prec + 1, &decpt, &sign); 133*34235Sbostic if (sign) 134*34235Sbostic printsign = '-'; 135*34235Sbostic bp = buf; 136*34235Sbostic if (decpt >= 0) 137*34235Sbostic for (;;) { 138*34235Sbostic *bp++ = *t ? *t++ : '0'; 139*34235Sbostic if (!--decpt) 140*34235Sbostic break; 141*34235Sbostic } 142*34235Sbostic if (alternate || prec > 0) 143*34235Sbostic *bp++ = '.'; 144*34235Sbostic while (decpt++) { 145*34235Sbostic *bp++ = *t ? *t++ : '0'; 146*34235Sbostic --prec; 147*34235Sbostic } 148*34235Sbostic while (prec--) 149*34235Sbostic *bp++ = *t ? *t++ : '0'; 150*34235Sbostic size = bp - buf; 151*34235Sbostic if (size < width && !ladjust) 152*34235Sbostic do { 153*34235Sbostic PUTC(padc, fp); 154*34235Sbostic } while (--width > size); 155*34235Sbostic for (t = buf; t < bp; ++t) 156*34235Sbostic PUTC(*t, fp); 157*34235Sbostic for (; width > size; --width) 158*34235Sbostic PUTC(padc, fp); 159*34235Sbostic break; 16034226Sbostic case 'd': 161*34235Sbostic case 'i': 162*34235Sbostic GETARG(reg_long); 16334233Sbostic if (reg_long < 0) { 16434233Sbostic reg_ulong = -reg_long; 16534233Sbostic printsign = '-'; 16634233Sbostic } 16734233Sbostic else { 16834233Sbostic reg_ulong = reg_long; 16934233Sbostic } 17034233Sbostic if (printsign) 171*34235Sbostic PUTC(printsign, fp); 17234226Sbostic base = 10; 173*34235Sbostic goto num1; 174*34235Sbostic case 'n': 175*34235Sbostic *(va_arg(argp, int *)) = cnt; 176*34235Sbostic break; 17734226Sbostic case 'o': 178*34235Sbostic GETARG(reg_ulong); 17934226Sbostic base = 8; 180*34235Sbostic if (!reg_ulong || !alternate) 181*34235Sbostic goto num1; 182*34235Sbostic bp = buf + sizeof(buf) - 1; 183*34235Sbostic do { 184*34235Sbostic *bp-- = digs[reg_ulong % base]; 185*34235Sbostic reg_ulong /= base; 186*34235Sbostic } while(reg_ulong); 187*34235Sbostic size = &buf[sizeof(buf) - 1] - bp; 188*34235Sbostic if (size < --width && !ladjust) 189*34235Sbostic do { 190*34235Sbostic PUTC(padc, fp); 191*34235Sbostic } while (--width > size); 192*34235Sbostic PUTC('0', fp); 193*34235Sbostic goto num3; 194*34235Sbostic break; 195*34235Sbostic case 'p': 19634226Sbostic case 's': 197*34235Sbostic if (!(bp = va_arg(argp, char *))) 198*34235Sbostic bp = "(null)"; 199*34235Sbostic if (width > 0 && !ladjust) { 20034233Sbostic char *savep; 20134226Sbostic 202*34235Sbostic savep = bp; 203*34235Sbostic for (n = 0; *bp && (prec < 0 || n < prec); 204*34235Sbostic n++, bp++); 205*34235Sbostic bp = savep; 206*34235Sbostic while (n++ < width) 207*34235Sbostic PUTC(' ', fp); 20834233Sbostic } 209*34235Sbostic for (n = 0; *bp; ++bp) { 210*34235Sbostic if (++n > prec && prec >= 0) 21134226Sbostic break; 212*34235Sbostic PUTC(*bp, fp); 21334233Sbostic } 214*34235Sbostic if (n < width && ladjust) 21534233Sbostic do { 216*34235Sbostic PUTC(' ', fp); 217*34235Sbostic } while (++n < width); 21834226Sbostic break; 21934226Sbostic case 'u': 220*34235Sbostic GETARG(reg_ulong); 22134226Sbostic base = 10; 222*34235Sbostic goto num1; 22334226Sbostic case 'X': 22434226Sbostic digs = "0123456789ABCDEF"; 22534233Sbostic /*FALLTHROUGH*/ 22634226Sbostic case 'x': 227*34235Sbostic GETARG(reg_ulong); 22834233Sbostic if (alternate && reg_ulong) { 229*34235Sbostic PUTC('0', fp); 230*34235Sbostic PUTC(*fmt, fp); 23134233Sbostic } 23234226Sbostic base = 16; 233*34235Sbostic num1: bp = buf + sizeof(buf) - 1; 23434233Sbostic do { 235*34235Sbostic *bp-- = digs[reg_ulong % base]; 23634233Sbostic reg_ulong /= base; 23734233Sbostic } while(reg_ulong); 238*34235Sbostic size = &buf[sizeof(buf) - 1] - bp; 239*34235Sbostic for (; size < prec; *bp-- = '0', ++size); 240*34235Sbostic if (size < width && !ladjust) 241*34235Sbostic do { 242*34235Sbostic PUTC(padc, fp); 243*34235Sbostic } while (--width > size); 244*34235Sbostic num3: while (++bp != &buf[MAXBUF]) 245*34235Sbostic PUTC(*bp, fp); 246*34235Sbostic for (; width > size; --width) 247*34235Sbostic PUTC(padc, fp); 24834226Sbostic break; 24934233Sbostic case '\0': /* "%?" prints ?, unless ? is NULL */ 250*34235Sbostic return(ferror(fp) ? -1 : cnt); 25134226Sbostic default: 252*34235Sbostic PUTC(*fmt, fp); 25334226Sbostic } 25434226Sbostic } 255*34235Sbostic return(ferror(fp) ? -1 : cnt); 25634226Sbostic } 257*34235Sbostic 258