1 /* 2 * Copyright (c) 1988 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that this notice is preserved and that due credit is given 7 * to the University of California at Berkeley. The name of the University 8 * may not be used to endorse or promote products derived from this 9 * software without specific prior written permission. This software 10 * is provided ``as is'' without express or implied warranty. 11 */ 12 13 #if defined(LIBC_SCCS) && !defined(lint) 14 static char sccsid[] = "@(#)vfprintf.c 5.3 (Berkeley) 05/08/88"; 15 #endif /* LIBC_SCCS and not lint */ 16 17 #include <sys/param.h> 18 #include <varargs.h> 19 #include <stdio.h> 20 #include <ctype.h> 21 22 #define GETARG(r) \ 23 r = argsize&LONGINT ? va_arg(argp, long) : \ 24 argsize&SHORTINT ? va_arg(argp, short) : va_arg(argp, int); 25 26 #define DEFPREC 6 /* default precision */ 27 #define MAXBUF 1024 28 #define PUTC(ch, fd) { ++cnt; putc(ch, fd); } 29 #define todigit(ch) ((ch) - '0') 30 #define tochar(ch) ((ch) + '0') 31 32 #define LONGINT 0x01 33 #define LONGDBL 0x02 34 #define SHORTINT 0x04 35 36 x_doprnt(fmt, argp, fp) 37 register char *fmt; 38 va_list argp; 39 register FILE *fp; 40 { 41 register u_long reg_ulong; 42 register long reg_long; 43 register int base; 44 register char *digs, *bp, *t, padc; 45 double _double; 46 char argsize, printsign, buf[MAXBUF], *fcvt(); 47 int alternate, cnt, decpt, n, ladjust, width, prec, sign, size; 48 49 for (cnt = 0; *fmt; ++fmt) { 50 if (*fmt != '%') { 51 PUTC(*fmt, fp); 52 continue; 53 } 54 55 alternate = ladjust = width = 0; 56 prec = -1; 57 padc = ' '; 58 argsize = printsign = '\0'; 59 60 flags: switch (*++fmt) { 61 case '#': 62 alternate = 1; 63 goto flags; 64 case '%': /* "%#%" prints as "%" */ 65 PUTC('%', fp); 66 continue; 67 case '*': 68 /* 69 * ``A negative field width argument is taken as a 70 * - flag followed by a positive field width.'' 71 * -- ANSI X3J11 72 * They don't exclude field widths read from args. 73 */ 74 if ((width = va_arg(argp, int)) >= 0) 75 goto flags; 76 width = -width; 77 /*FALLTHROUGH*/ 78 case '-': 79 ladjust = 1; 80 goto flags; 81 case '+': 82 printsign = '+'; 83 goto flags; 84 case '.': 85 if (*++fmt == '*') 86 prec = va_arg(argp, int); 87 else if (isdigit(*fmt)) { 88 prec = 0; 89 do { 90 prec = 10 * prec + todigit(*fmt); 91 } while isdigit(*++fmt); 92 --fmt; 93 } 94 else { 95 prec = 0; 96 --fmt; 97 goto flags; 98 } 99 if (prec < 0) 100 prec = -1; 101 goto flags; 102 case '0': 103 padc = '0'; 104 /*FALLTHROUGH*/ 105 case '1': case '2': case '3': case '4': 106 case '5': case '6': case '7': case '8': case '9': 107 do { 108 width = 10 * width + todigit(*fmt); 109 } while isdigit(*++fmt); 110 --fmt; 111 case 'L': 112 argsize |= LONGDBL; 113 goto flags; 114 case 'h': 115 argsize |= SHORTINT; 116 goto flags; 117 case 'l': 118 argsize |= LONGINT; 119 goto flags; 120 } 121 122 digs = "0123456789abcdef"; 123 124 switch (*fmt) { 125 case 'c': 126 PUTC(va_arg(argp, int), fp); 127 break; 128 case 'f': 129 if (prec == -1) 130 prec = DEFPREC; 131 _double = va_arg(argp, double); 132 t = fcvt(_double, prec + 1, &decpt, &sign); 133 if (sign) 134 printsign = '-'; 135 bp = buf; 136 if (decpt >= 0) 137 for (;;) { 138 *bp++ = *t ? *t++ : '0'; 139 if (!--decpt) 140 break; 141 } 142 if (alternate || prec > 0) 143 *bp++ = '.'; 144 while (decpt++) { 145 *bp++ = *t ? *t++ : '0'; 146 --prec; 147 } 148 while (prec--) 149 *bp++ = *t ? *t++ : '0'; 150 size = bp - buf; 151 if (size < width && !ladjust) 152 do { 153 PUTC(padc, fp); 154 } while (--width > size); 155 for (t = buf; t < bp; ++t) 156 PUTC(*t, fp); 157 for (; width > size; --width) 158 PUTC(padc, fp); 159 break; 160 case 'd': 161 case 'i': 162 GETARG(reg_long); 163 if (reg_long < 0) { 164 reg_ulong = -reg_long; 165 printsign = '-'; 166 } 167 else { 168 reg_ulong = reg_long; 169 } 170 if (printsign) 171 PUTC(printsign, fp); 172 base = 10; 173 goto num1; 174 case 'n': 175 *(va_arg(argp, int *)) = cnt; 176 break; 177 case 'o': 178 GETARG(reg_ulong); 179 base = 8; 180 if (!reg_ulong || !alternate) 181 goto num1; 182 bp = buf + sizeof(buf) - 1; 183 do { 184 *bp-- = digs[reg_ulong % base]; 185 reg_ulong /= base; 186 } while(reg_ulong); 187 size = &buf[sizeof(buf) - 1] - bp; 188 if (size < --width && !ladjust) 189 do { 190 PUTC(padc, fp); 191 } while (--width > size); 192 PUTC('0', fp); 193 goto num3; 194 break; 195 case 'p': 196 case 's': 197 if (!(bp = va_arg(argp, char *))) 198 bp = "(null)"; 199 if (width > 0 && !ladjust) { 200 char *savep; 201 202 savep = bp; 203 for (n = 0; *bp && (prec < 0 || n < prec); 204 n++, bp++); 205 bp = savep; 206 while (n++ < width) 207 PUTC(' ', fp); 208 } 209 for (n = 0; *bp; ++bp) { 210 if (++n > prec && prec >= 0) 211 break; 212 PUTC(*bp, fp); 213 } 214 if (n < width && ladjust) 215 do { 216 PUTC(' ', fp); 217 } while (++n < width); 218 break; 219 case 'u': 220 GETARG(reg_ulong); 221 base = 10; 222 goto num1; 223 case 'X': 224 digs = "0123456789ABCDEF"; 225 /*FALLTHROUGH*/ 226 case 'x': 227 GETARG(reg_ulong); 228 if (alternate && reg_ulong) { 229 PUTC('0', fp); 230 PUTC(*fmt, fp); 231 } 232 base = 16; 233 num1: bp = buf + sizeof(buf) - 1; 234 do { 235 *bp-- = digs[reg_ulong % base]; 236 reg_ulong /= base; 237 } while(reg_ulong); 238 size = &buf[sizeof(buf) - 1] - bp; 239 for (; size < prec; *bp-- = '0', ++size); 240 if (size < width && !ladjust) 241 do { 242 PUTC(padc, fp); 243 } while (--width > size); 244 num3: while (++bp != &buf[MAXBUF]) 245 PUTC(*bp, fp); 246 for (; width > size; --width) 247 PUTC(padc, fp); 248 break; 249 case '\0': /* "%?" prints ?, unless ? is NULL */ 250 return(ferror(fp) ? -1 : cnt); 251 default: 252 PUTC(*fmt, fp); 253 } 254 } 255 return(ferror(fp) ? -1 : cnt); 256 } 257 258