134226Sbostic /* 2*34233Sbostic * Copyright (c) 1988 Regents of the University of California. 3*34233Sbostic * All rights reserved. 434226Sbostic * 5*34233Sbostic * Redistribution and use in source and binary forms are permitted 6*34233Sbostic * provided that this notice is preserved and that due credit is given 7*34233Sbostic * to the University of California at Berkeley. The name of the University 8*34233Sbostic * may not be used to endorse or promote products derived from this 9*34233Sbostic * software without specific prior written permission. This software 10*34233Sbostic * is provided ``as is'' without express or implied warranty. 1134226Sbostic * 12*34233Sbostic * Originally derived from code posted by Steve Summit to USENET, 13*34233Sbostic * dated 3/25/87 1434226Sbostic */ 1534226Sbostic 16*34233Sbostic #if defined(LIBC_SCCS) && !defined(lint) 17*34233Sbostic static char sccsid[] = "@(#)vfprintf.c 5.2 (Berkeley) 05/07/88"; 18*34233Sbostic #endif /* LIBC_SCCS and not lint */ 19*34233Sbostic 20*34233Sbostic #include <sys/param.h> 21*34233Sbostic #include <varargs.h> 2234226Sbostic #include <stdio.h> 23*34233Sbostic #include <ctype.h> 2434226Sbostic 25*34233Sbostic #define MAXBUF (sizeof(long) * 8) /* enough for binary */ 26*34233Sbostic #define PUTC(ch, fd) { ++cnt; putc(ch, fd); } 27*34233Sbostic #define todigit(ch) ((ch) - '0') 2834226Sbostic 29*34233Sbostic doprnt(fmt, argp, fd) 30*34233Sbostic register char *fmt; 31*34233Sbostic va_list argp; 32*34233Sbostic register FILE *fd; 3334226Sbostic { 34*34233Sbostic register u_long reg_ulong; 35*34233Sbostic register long reg_long; 36*34233Sbostic register int base; 37*34233Sbostic register char *digs, *p, padc; 38*34233Sbostic char printsign, buf[MAXBUF]; 39*34233Sbostic int alternate, cnt, n, ladjust, length, setlong, prec, size; 4034226Sbostic 41*34233Sbostic for (cnt = 0; *fmt; ++fmt) { 42*34233Sbostic if (*fmt != '%') { 43*34233Sbostic PUTC(*fmt, fd); 44*34233Sbostic continue; 4534226Sbostic } 4634226Sbostic 47*34233Sbostic alternate = ladjust = length = setlong = 0; 48*34233Sbostic prec = -1; 49*34233Sbostic padc = ' '; 50*34233Sbostic printsign = '\0'; 5134226Sbostic 52*34233Sbostic flags: switch (*++fmt) { 53*34233Sbostic case '#': 54*34233Sbostic alternate = 1; 55*34233Sbostic goto flags; 56*34233Sbostic case '%': /* "%#%" prints as "%" */ 57*34233Sbostic PUTC('%', fd); 58*34233Sbostic continue; 59*34233Sbostic case '*': 60*34233Sbostic if ((length = va_arg(argp, int)) < 0) { 61*34233Sbostic ladjust = !ladjust; 62*34233Sbostic length = -length; 6334226Sbostic } 64*34233Sbostic goto flags; 65*34233Sbostic case '+': 66*34233Sbostic printsign = '+'; 67*34233Sbostic goto flags; 68*34233Sbostic case '-': 69*34233Sbostic ladjust = 1; 70*34233Sbostic goto flags; 71*34233Sbostic case '.': 72*34233Sbostic if (isdigit(*++fmt)) { 73*34233Sbostic do { 74*34233Sbostic prec = 10 * prec + todigit(*fmt); 75*34233Sbostic } while isdigit(*++fmt); 76*34233Sbostic --fmt; 7734226Sbostic } 78*34233Sbostic else if (*fmt == '*') 79*34233Sbostic prec = va_arg(argp, int); 80*34233Sbostic goto flags; 81*34233Sbostic case '0': 82*34233Sbostic padc = '0'; 83*34233Sbostic goto flags; 84*34233Sbostic case '1': case '2': case '3': case '4': 85*34233Sbostic case '5': case '6': case '7': case '8': case '9': 86*34233Sbostic do { 87*34233Sbostic length = 10 * length + todigit(*fmt); 88*34233Sbostic } while isdigit(*++fmt); 89*34233Sbostic --fmt; 90*34233Sbostic case 'l': 91*34233Sbostic setlong = 1; 92*34233Sbostic goto flags; 9334226Sbostic } 9434226Sbostic 95*34233Sbostic digs = "0123456789abcdef"; 9634226Sbostic 97*34233Sbostic switch (*fmt) { 9834226Sbostic case 'c': 99*34233Sbostic PUTC(va_arg(argp, int), fd); 10034226Sbostic break; 10134226Sbostic case 'd': 102*34233Sbostic if (setlong) 103*34233Sbostic reg_long = va_arg(argp, long); 104*34233Sbostic else 105*34233Sbostic reg_long = va_arg(argp, int); 106*34233Sbostic if (reg_long < 0) { 107*34233Sbostic reg_ulong = -reg_long; 108*34233Sbostic printsign = '-'; 109*34233Sbostic } 110*34233Sbostic else { 111*34233Sbostic reg_ulong = reg_long; 112*34233Sbostic } 113*34233Sbostic if (printsign) 114*34233Sbostic PUTC(printsign, fd); 11534226Sbostic base = 10; 11634226Sbostic goto donum; 11734226Sbostic case 'o': 118*34233Sbostic if (setlong) 119*34233Sbostic reg_ulong = va_arg(argp, long); 120*34233Sbostic else 121*34233Sbostic reg_ulong = va_arg(argp, int); 12234226Sbostic base = 8; 12334226Sbostic goto donum; 12434226Sbostic case 's': 125*34233Sbostic if (!(p = va_arg(argp, char *))) 126*34233Sbostic p = "(null)"; 127*34233Sbostic if (length > 0 && !ladjust) { 128*34233Sbostic char *savep; 12934226Sbostic 130*34233Sbostic savep = p; 131*34233Sbostic for (n = 0; *p && (prec == -1 || n < prec); 132*34233Sbostic n++, p++); 133*34233Sbostic p = savep; 134*34233Sbostic while (n++ < length) 135*34233Sbostic PUTC(' ', fd); 136*34233Sbostic } 137*34233Sbostic for (n = 0; *p; ++p) { 138*34233Sbostic if (++n > prec && prec != -1) 13934226Sbostic break; 140*34233Sbostic PUTC(*p, fd); 141*34233Sbostic } 142*34233Sbostic if (n < length && ladjust) 143*34233Sbostic do { 144*34233Sbostic PUTC(' ', fd); 145*34233Sbostic } while (++n < length); 14634226Sbostic break; 14734226Sbostic case 'u': 148*34233Sbostic if (setlong) 149*34233Sbostic reg_ulong = va_arg(argp, long); 150*34233Sbostic else 151*34233Sbostic reg_ulong = va_arg(argp, int); 15234226Sbostic base = 10; 15334226Sbostic goto donum; 15434226Sbostic case 'X': 15534226Sbostic digs = "0123456789ABCDEF"; 156*34233Sbostic /*FALLTHROUGH*/ 15734226Sbostic case 'x': 158*34233Sbostic if (setlong) 159*34233Sbostic reg_ulong = va_arg(argp, long); 160*34233Sbostic else 161*34233Sbostic reg_ulong = va_arg(argp, int); 162*34233Sbostic if (alternate && reg_ulong) { 163*34233Sbostic PUTC('0', fd); 164*34233Sbostic PUTC(*fmt, fd); 165*34233Sbostic } 16634226Sbostic base = 16; 167*34233Sbostic donum: p = &buf[sizeof(buf) - 1]; 168*34233Sbostic do { 169*34233Sbostic *p-- = digs[reg_ulong % base]; 170*34233Sbostic reg_ulong /= base; 171*34233Sbostic } while(reg_ulong); 172*34233Sbostic size = &buf[sizeof(buf) - 1] - p; 173*34233Sbostic if (reg_ulong && alternate && *fmt == 'o') { 174*34233Sbostic if (size < --length && !ladjust) 175*34233Sbostic do { 176*34233Sbostic PUTC(padc, fd); 177*34233Sbostic } while (--length > size); 178*34233Sbostic PUTC('0', fd); 179*34233Sbostic while (++p != &buf[MAXBUF]) 180*34233Sbostic PUTC(*p, fd); 181*34233Sbostic if (size < length) /* must be ladjust */ 182*34233Sbostic for (; length > size; --length) 183*34233Sbostic PUTC(padc, fd); 184*34233Sbostic } 185*34233Sbostic else { 186*34233Sbostic if (size < length && !ladjust) 187*34233Sbostic do { 188*34233Sbostic PUTC(padc, fd); 189*34233Sbostic } while (--length > size); 190*34233Sbostic while (++p != &buf[MAXBUF]) 191*34233Sbostic PUTC(*p, fd); 192*34233Sbostic if (size < length) /* must be ladjust */ 193*34233Sbostic for (; length > size; --length) 194*34233Sbostic PUTC(padc, fd); 195*34233Sbostic } 19634226Sbostic break; 197*34233Sbostic case '\0': /* "%?" prints ?, unless ? is NULL */ 198*34233Sbostic return(cnt); 19934226Sbostic default: 200*34233Sbostic PUTC(*fmt, fd); 20134226Sbostic } 20234226Sbostic } 203*34233Sbostic return(cnt); 20434226Sbostic } 205