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 * Originally derived from code posted by Steve Summit to USENET, 13 * dated 3/25/87 14 */ 15 16 #if defined(LIBC_SCCS) && !defined(lint) 17 static char sccsid[] = "@(#)vfprintf.c 5.2 (Berkeley) 05/07/88"; 18 #endif /* LIBC_SCCS and not lint */ 19 20 #include <sys/param.h> 21 #include <varargs.h> 22 #include <stdio.h> 23 #include <ctype.h> 24 25 #define MAXBUF (sizeof(long) * 8) /* enough for binary */ 26 #define PUTC(ch, fd) { ++cnt; putc(ch, fd); } 27 #define todigit(ch) ((ch) - '0') 28 29 doprnt(fmt, argp, fd) 30 register char *fmt; 31 va_list argp; 32 register FILE *fd; 33 { 34 register u_long reg_ulong; 35 register long reg_long; 36 register int base; 37 register char *digs, *p, padc; 38 char printsign, buf[MAXBUF]; 39 int alternate, cnt, n, ladjust, length, setlong, prec, size; 40 41 for (cnt = 0; *fmt; ++fmt) { 42 if (*fmt != '%') { 43 PUTC(*fmt, fd); 44 continue; 45 } 46 47 alternate = ladjust = length = setlong = 0; 48 prec = -1; 49 padc = ' '; 50 printsign = '\0'; 51 52 flags: switch (*++fmt) { 53 case '#': 54 alternate = 1; 55 goto flags; 56 case '%': /* "%#%" prints as "%" */ 57 PUTC('%', fd); 58 continue; 59 case '*': 60 if ((length = va_arg(argp, int)) < 0) { 61 ladjust = !ladjust; 62 length = -length; 63 } 64 goto flags; 65 case '+': 66 printsign = '+'; 67 goto flags; 68 case '-': 69 ladjust = 1; 70 goto flags; 71 case '.': 72 if (isdigit(*++fmt)) { 73 do { 74 prec = 10 * prec + todigit(*fmt); 75 } while isdigit(*++fmt); 76 --fmt; 77 } 78 else if (*fmt == '*') 79 prec = va_arg(argp, int); 80 goto flags; 81 case '0': 82 padc = '0'; 83 goto flags; 84 case '1': case '2': case '3': case '4': 85 case '5': case '6': case '7': case '8': case '9': 86 do { 87 length = 10 * length + todigit(*fmt); 88 } while isdigit(*++fmt); 89 --fmt; 90 case 'l': 91 setlong = 1; 92 goto flags; 93 } 94 95 digs = "0123456789abcdef"; 96 97 switch (*fmt) { 98 case 'c': 99 PUTC(va_arg(argp, int), fd); 100 break; 101 case 'd': 102 if (setlong) 103 reg_long = va_arg(argp, long); 104 else 105 reg_long = va_arg(argp, int); 106 if (reg_long < 0) { 107 reg_ulong = -reg_long; 108 printsign = '-'; 109 } 110 else { 111 reg_ulong = reg_long; 112 } 113 if (printsign) 114 PUTC(printsign, fd); 115 base = 10; 116 goto donum; 117 case 'o': 118 if (setlong) 119 reg_ulong = va_arg(argp, long); 120 else 121 reg_ulong = va_arg(argp, int); 122 base = 8; 123 goto donum; 124 case 's': 125 if (!(p = va_arg(argp, char *))) 126 p = "(null)"; 127 if (length > 0 && !ladjust) { 128 char *savep; 129 130 savep = p; 131 for (n = 0; *p && (prec == -1 || n < prec); 132 n++, p++); 133 p = savep; 134 while (n++ < length) 135 PUTC(' ', fd); 136 } 137 for (n = 0; *p; ++p) { 138 if (++n > prec && prec != -1) 139 break; 140 PUTC(*p, fd); 141 } 142 if (n < length && ladjust) 143 do { 144 PUTC(' ', fd); 145 } while (++n < length); 146 break; 147 case 'u': 148 if (setlong) 149 reg_ulong = va_arg(argp, long); 150 else 151 reg_ulong = va_arg(argp, int); 152 base = 10; 153 goto donum; 154 case 'X': 155 digs = "0123456789ABCDEF"; 156 /*FALLTHROUGH*/ 157 case 'x': 158 if (setlong) 159 reg_ulong = va_arg(argp, long); 160 else 161 reg_ulong = va_arg(argp, int); 162 if (alternate && reg_ulong) { 163 PUTC('0', fd); 164 PUTC(*fmt, fd); 165 } 166 base = 16; 167 donum: p = &buf[sizeof(buf) - 1]; 168 do { 169 *p-- = digs[reg_ulong % base]; 170 reg_ulong /= base; 171 } while(reg_ulong); 172 size = &buf[sizeof(buf) - 1] - p; 173 if (reg_ulong && alternate && *fmt == 'o') { 174 if (size < --length && !ladjust) 175 do { 176 PUTC(padc, fd); 177 } while (--length > size); 178 PUTC('0', fd); 179 while (++p != &buf[MAXBUF]) 180 PUTC(*p, fd); 181 if (size < length) /* must be ladjust */ 182 for (; length > size; --length) 183 PUTC(padc, fd); 184 } 185 else { 186 if (size < length && !ladjust) 187 do { 188 PUTC(padc, fd); 189 } while (--length > size); 190 while (++p != &buf[MAXBUF]) 191 PUTC(*p, fd); 192 if (size < length) /* must be ladjust */ 193 for (; length > size; --length) 194 PUTC(padc, fd); 195 } 196 break; 197 case '\0': /* "%?" prints ?, unless ? is NULL */ 198 return(cnt); 199 default: 200 PUTC(*fmt, fd); 201 } 202 } 203 return(cnt); 204 } 205