1 From stevesu@copper.UUCP Wed Mar 25 23:35:32 1987 2 Path: seismo!ut-sally!husc6!bacchus!mit-eddie!genrad!decvax!tektronix!teklds!copper!stevesu 3 From: stevesu@copper.TEK.COM (Steve Summit) 4 Newsgroups: net.sources 5 Subject: Public Domain _doprnt in C 6 Message-ID: <938@copper.TEK.COM> 7 Date: 26 Mar 87 04:35:32 GMT 8 Reply-To: stevesu@copper.UUCP (Steve Summit) 9 Distribution: world 10 Organization: Tektronix, Inc., Beaverton, OR. 11 Lines: 420 12 13 Mark Pulver is looking for a C version of _doprnt, so I thought 14 I'd pass mine along. I wrote this from the ground up; it is 15 absolutely underived from anything proprietary. 16 17 This version is not complete, and has the following two key 18 omissions: 19 20 It doesn't do floating point (%f, %e, or %g). 21 22 It will handle %ld (%lx, etc.) incorrectly on machines 23 where sizeof(long) != sizeof(int). 24 25 It also does not implement the %# stuff which appeared in the 4.2 26 documentation but which I haven't seen in any implementation yet. 27 28 I believe it handles everything else correctly, although I have 29 not tested it exhaustively. 30 31 There are two "fun" additions: %b is binary, and %r is roman. 32 33 You are free to use this code as you wish, but please leave the 34 identification comment intact. I can offer no support for this 35 code, although if I ever implement floating point or pdp11 36 support (I'm acutely embarrassed to admit making the typical VAX 37 int/long equivalence assumption) I'll try to remember to post 38 those additions. 39 40 Steve Summit 41 stevesu@copper.tek.com 42 43 --------------------- cut here for doprnt.c --------------------- 44 /* 45 * Common code for printf et al. 46 * 47 * The calling routine typically takes a variable number of arguments, 48 * and passes the address of the first one. This implementation 49 * assumes a straightforward, stack implementation, aligned to the 50 * machine's wordsize. Increasing addresses are assumed to point to 51 * successive arguments (left-to-right), as is the case for a machine 52 * with a downward-growing stack with arguments pushed right-to-left. 53 * 54 * To write, for example, fprintf() using this routine, the code 55 * 56 * fprintf(fd, format, args) 57 * FILE *fd; 58 * char *format; 59 * { 60 * _doprnt(format, &args, fd); 61 * } 62 * 63 * would suffice. (This example does not handle the fprintf's "return 64 * value" correctly, but who looks at the return value of fprintf 65 * anyway?) 66 * 67 * This version implements the following printf features: 68 * 69 * %d decimal conversion 70 * %u unsigned conversion 71 * %x hexadecimal conversion 72 * %X hexadecimal conversion with capital letters 73 * %o octal conversion 74 * %c character 75 * %s string 76 * %m.n field width, precision 77 * %-m.n left adjustment 78 * %0m.n zero-padding 79 * %*.* width and precision taken from arguments 80 * 81 * This version does not implement %f, %e, or %g. It accepts, but 82 * ignores, an `l' as in %ld, %lo, %lx, and %lu, and therefore will not 83 * work correctly on machines for which sizeof(long) != sizeof(int). 84 * It does not even parse %D, %O, or %U; you should be using %ld, %o and 85 * %lu if you mean long conversion. 86 * 87 * This version implements the following nonstandard features: 88 * 89 * %b binary conversion 90 * %r roman numeral conversion 91 * %R roman numeral conversion with capital letters 92 * 93 * As mentioned, this version does not return any reasonable value. 94 * 95 * Permission is granted to use, modify, or propagate this code as 96 * long as this notice is incorporated. 97 * 98 * Steve Summit 3/25/87 99 */ 100 101 #include <stdio.h> 102 103 #define TRUE 1 104 #define FALSE 0 105 106 #define ROMAN 107 108 #define isdigit(d) ((d) >= '0' && (d) <= '9') 109 #define Ctod(c) ((c) - '0') 110 111 #define MAXBUF (sizeof(long int) * 8) /* enough for binary */ 112 113 #ifdef ROMAN 114 static tack(); 115 static doit(); 116 #endif 117 118 _doprnt(fmt, argp, fd) 119 register char *fmt; 120 register int *argp; 121 FILE *fd; 122 { 123 register char *p; 124 char *p2; 125 int size; 126 int length; 127 int prec; 128 int ladjust; 129 char padc; 130 int n; 131 unsigned int u; 132 int base; 133 char buf[MAXBUF]; 134 int negflag; 135 char *digs; 136 #ifdef ROMAN 137 char *rdigs; 138 int d; 139 #endif 140 141 while(*fmt != '\0') 142 { 143 if(*fmt != '%') 144 { 145 putc(*fmt++, fd); 146 continue; 147 } 148 149 fmt++; 150 151 if(*fmt == 'l') 152 fmt++; /* need to use it if sizeof(int) < sizeof(long) */ 153 154 length = 0; 155 prec = -1; 156 ladjust = FALSE; 157 padc = ' '; 158 159 if(*fmt == '-') 160 { 161 ladjust = TRUE; 162 fmt++; 163 } 164 165 if(*fmt == '0') 166 { 167 padc = '0'; 168 fmt++; 169 } 170 171 if(isdigit(*fmt)) 172 { 173 while(isdigit(*fmt)) 174 length = 10 * length + Ctod(*fmt++); 175 } 176 else if(*fmt == '*') 177 { 178 length = *argp++; 179 fmt++; 180 if(length < 0) 181 { 182 ladjust = !ladjust; 183 length = -length; 184 } 185 } 186 187 if(*fmt == '.') 188 { 189 fmt++; 190 if(isdigit(*fmt)) 191 { 192 prec = 0; 193 while(isdigit(*fmt)) 194 prec = 10 * prec + Ctod(*fmt++); 195 } 196 else if(*fmt == '*') 197 { 198 prec = *argp++; 199 fmt++; 200 } 201 } 202 203 negflag = FALSE; 204 digs = "0123456789abcdef"; 205 #ifdef ROMAN 206 rdigs = " mdclxvi"; 207 #endif 208 209 switch(*fmt) 210 { 211 case 'b': 212 case 'B': 213 u = *argp++; 214 base = 2; 215 goto donum; 216 217 case 'c': 218 putc(*argp++, fd); 219 break; 220 221 case 'd': 222 case 'D': 223 n = *argp++; 224 225 if(n >= 0) 226 u = n; 227 else { 228 u = -n; 229 negflag = TRUE; 230 } 231 232 base = 10; 233 234 goto donum; 235 236 case 'o': 237 case 'O': 238 u = *argp++; 239 base = 8; 240 goto donum; 241 #ifdef ROMAN 242 case 'R': 243 rdigs = " MDCLXVI"; 244 case 'r': 245 n = *argp++; 246 p2 = &buf[MAXBUF - 1]; 247 248 d = n % 10; 249 tack(d, &rdigs[6], &p2); 250 n = n / 10; 251 252 d = n % 10; 253 tack(d, &rdigs[4], &p2); 254 n = n / 10; 255 256 d = n % 10; 257 tack(d, &rdigs[2], &p2); 258 n /= 10; 259 260 d = n % 10; 261 tack(d, rdigs, &p2); 262 263 p = p2; 264 265 goto putpad; 266 #endif 267 case 's': 268 p = (char *)(*argp++); 269 270 if(p == NULL) 271 p = "(NULL)"; 272 273 if(length > 0 && !ladjust) 274 { 275 n = 0; 276 p2 = p; 277 278 for(; *p != '\0' && 279 (prec == -1 || n < prec); p++) 280 n++; 281 282 p = p2; 283 284 while(n < length) 285 { 286 putc(' ', fd); 287 n++; 288 } 289 } 290 291 n = 0; 292 293 while(*p != '\0') 294 { 295 if(++n > prec && prec != -1) 296 break; 297 298 putc(*p++, fd); 299 } 300 301 if(n < length && ladjust) 302 { 303 while(n < length) 304 { 305 putc(' ', fd); 306 n++; 307 } 308 } 309 310 break; 311 312 case 'u': 313 case 'U': 314 u = *argp++; 315 base = 10; 316 goto donum; 317 318 case 'X': 319 digs = "0123456789ABCDEF"; 320 case 'x': 321 u = *argp++; 322 base = 16; 323 324 donum: p = &buf[MAXBUF - 1]; 325 326 do { 327 *p-- = digs[u % base]; 328 u /= base; 329 } while(u != 0); 330 331 if(negflag) 332 putc('-', fd); 333 putpad: 334 size = &buf[MAXBUF - 1] - p; 335 336 if(size < length && !ladjust) 337 { 338 while(length > size) 339 { 340 putc(padc, fd); 341 length--; 342 } 343 } 344 345 while(++p != &buf[MAXBUF]) 346 putc(*p, fd); 347 348 if(size < length) /* must be ladjust */ 349 { 350 while(length > size) 351 { 352 putc(padc, fd); 353 length--; 354 } 355 } 356 357 break; 358 359 case '\0': 360 fmt--; 361 break; 362 363 default: 364 putc(*fmt, fd); 365 } 366 fmt++; 367 } 368 } 369 370 #ifdef ROMAN 371 372 static 373 tack(d, digs, p) 374 int d; 375 char *digs; 376 char **p; 377 { 378 if(d == 0) return; 379 if(d >= 1 && d <= 3) 380 { 381 doit(d, digs[2], p); 382 return; 383 } 384 385 if(d == 4 || d == 5) 386 { 387 **p = digs[1]; 388 (*p)--; 389 } 390 391 if(d == 4) 392 { 393 **p = digs[2]; 394 (*p)--; 395 return; 396 } 397 398 if(d == 5) return; 399 400 if(d >= 6 && d <= 8) 401 { 402 doit(d - 5, digs[2], p); 403 **p = digs[1]; 404 (*p)--; 405 return; 406 } 407 408 /* d == 9 */ 409 410 **p = digs[0]; 411 (*p)--; 412 **p = digs[2]; 413 (*p)--; 414 return; 415 } 416 417 static 418 doit(d, one, p) 419 int d; 420 char one; 421 char **p; 422 { 423 int i; 424 425 for(i = 0; i < d; i++) 426 { 427 **p = one; 428 (*p)--; 429 } 430 } 431 432 #endif 433