tc.printf.c revision 131962
1/* $Header: /src/pub/tcsh/tc.printf.c,v 3.24 2003/12/02 17:59:30 christos Exp $ */ 2/* 3 * tc.printf.c: A public-domain, minimal printf/sprintf routine that prints 4 * through the putchar() routine. Feel free to use for 5 * anything... -- 7/17/87 Paul Placeway 6 */ 7/*- 8 * Copyright (c) 1980, 1991 The Regents of the University of California. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35#include "sh.h" 36 37RCSID("$Id: tc.printf.c,v 3.24 2003/12/02 17:59:30 christos Exp $") 38 39#ifdef lint 40#undef va_arg 41#define va_arg(a, b) (a ? (b) 0 : (b) 0) 42#endif 43 44#define INF 32766 /* should be bigger than any field to print */ 45 46static char buf[128]; 47 48static void xaddchar __P((int)); 49static void doprnt __P((void (*) __P((int)), const char *, va_list)); 50 51static void 52doprnt(addchar, sfmt, ap) 53 void (*addchar) __P((int)); 54 const char *sfmt; 55 va_list ap; 56{ 57 char *bp; 58 const char *f; 59#ifdef SHORT_STRINGS 60 Char *Bp; 61#endif /* SHORT_STRINGS */ 62#ifdef HAVE_QUAD 63 long long l; 64 unsigned long long u; 65#else 66 long l; 67 unsigned long u; 68#endif 69 int i; 70 int fmt; 71 unsigned char pad = ' '; 72 int flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0; 73 int sign = 0; 74 int attributes = 0; 75 76 77 f = sfmt; 78 for (; *f; f++) { 79 if (*f != '%') { /* then just out the char */ 80 (*addchar) ((int) (((unsigned char)*f) | attributes)); 81 } 82 else { 83 f++; /* skip the % */ 84 85 if (*f == '-') { /* minus: flush left */ 86 flush_left = 1; 87 f++; 88 } 89 90 if (*f == '0' || *f == '.') { 91 /* padding with 0 rather than blank */ 92 pad = '0'; 93 f++; 94 } 95 if (*f == '*') { /* field width */ 96 f_width = va_arg(ap, int); 97 f++; 98 } 99 else if (Isdigit((unsigned char) *f)) { 100 f_width = atoi(f); 101 while (Isdigit((unsigned char) *f)) 102 f++; /* skip the digits */ 103 } 104 105 if (*f == '.') { /* precision */ 106 f++; 107 if (*f == '*') { 108 prec = va_arg(ap, int); 109 f++; 110 } 111 else if (Isdigit((unsigned char) *f)) { 112 prec = atoi((char *) f); 113 while (Isdigit((unsigned char) *f)) 114 f++; /* skip the digits */ 115 } 116 } 117 118 if (*f == '#') { /* alternate form */ 119 hash = 1; 120 f++; 121 } 122 123 if (*f == 'l') { /* long format */ 124 do_long++; 125 f++; 126 if (*f == 'l') { 127 do_long++; 128 f++; 129 } 130 } 131 132 fmt = (unsigned char) *f; 133 if (fmt != 'S' && fmt != 'Q' && Isupper(fmt)) { 134 do_long = 1; 135 fmt = Tolower(fmt); 136 } 137 bp = buf; 138 switch (fmt) { /* do the format */ 139 case 'd': 140 switch (do_long) { 141 case 0: 142 l = (long) (va_arg(ap, int)); 143 break; 144 case 1: 145#ifndef HAVE_QUAD 146 default: 147#endif 148 l = va_arg(ap, long); 149 break; 150#ifdef HAVE_QUAD 151 default: 152 l = va_arg(ap, long long); 153 break; 154#endif 155 } 156 157 if (l < 0) { 158 sign = 1; 159 l = -l; 160 } 161 do { 162 *bp++ = (char) (l % 10) + '0'; 163 } while ((l /= 10) > 0); 164 if (sign) 165 *bp++ = '-'; 166 f_width = f_width - (int) (bp - buf); 167 if (!flush_left) 168 while (f_width-- > 0) 169 (*addchar) ((int) (pad | attributes)); 170 for (bp--; bp >= buf; bp--) 171 (*addchar) ((int) (((unsigned char) *bp) | attributes)); 172 if (flush_left) 173 while (f_width-- > 0) 174 (*addchar) ((int) (' ' | attributes)); 175 break; 176 177 case 'p': 178 do_long = 1; 179 hash = 1; 180 fmt = 'x'; 181 /*FALLTHROUGH*/ 182 case 'o': 183 case 'x': 184 case 'u': 185 switch (do_long) { 186 case 0: 187 u = (unsigned long) (va_arg(ap, unsigned int)); 188 break; 189 case 1: 190#ifndef HAVE_QUAD 191 default: 192#endif 193 u = va_arg(ap, unsigned long); 194 break; 195#ifdef HAVE_QUAD 196 default: 197 u = va_arg(ap, unsigned long long); 198 break; 199#endif 200 } 201 if (fmt == 'u') { /* unsigned decimal */ 202 do { 203 *bp++ = (char) (u % 10) + '0'; 204 } while ((u /= 10) > 0); 205 } 206 else if (fmt == 'o') { /* octal */ 207 do { 208 *bp++ = (char) (u % 8) + '0'; 209 } while ((u /= 8) > 0); 210 if (hash) 211 *bp++ = '0'; 212 } 213 else if (fmt == 'x') { /* hex */ 214 do { 215 i = (int) (u % 16); 216 if (i < 10) 217 *bp++ = i + '0'; 218 else 219 *bp++ = i - 10 + 'a'; 220 } while ((u /= 16) > 0); 221 if (hash) { 222 *bp++ = 'x'; 223 *bp++ = '0'; 224 } 225 } 226 i = f_width - (int) (bp - buf); 227 if (!flush_left) 228 while (i-- > 0) 229 (*addchar) ((int) (pad | attributes)); 230 for (bp--; bp >= buf; bp--) 231 (*addchar) ((int) (((unsigned char) *bp) | attributes)); 232 if (flush_left) 233 while (i-- > 0) 234 (*addchar) ((int) (' ' | attributes)); 235 break; 236 237 238 case 'c': 239 i = va_arg(ap, int); 240 (*addchar) ((int) (i | attributes)); 241 break; 242 243 case 'S': 244 case 'Q': 245#ifdef SHORT_STRINGS 246 Bp = va_arg(ap, Char *); 247 if (!Bp) { 248 bp = NULL; 249 goto lcase_s; 250 } 251 f_width = f_width - Strlen(Bp); 252 if (!flush_left) 253 while (f_width-- > 0) 254 (*addchar) ((int) (pad | attributes)); 255 for (i = 0; *Bp && i < prec; i++) { 256 if (fmt == 'Q' && *Bp & QUOTE) 257 (*addchar) ((int) ('\\' | attributes)); 258 (*addchar) ((int) ((*Bp & TRIM) | attributes)); 259 Bp++; 260 } 261 if (flush_left) 262 while (f_width-- > 0) 263 (*addchar) ((int) (' ' | attributes)); 264 break; 265#endif /* SHORT_STRINGS */ 266 267 case 's': 268 case 'q': 269 bp = va_arg(ap, char *); 270lcase_s: 271 if (!bp) 272 bp = "(nil)"; 273 f_width = f_width - strlen((char *) bp); 274 if (!flush_left) 275 while (f_width-- > 0) 276 (*addchar) ((int) (pad | attributes)); 277 for (i = 0; *bp && i < prec; i++) { 278 if (fmt == 'q' && *bp & QUOTE) 279 (*addchar) ((int) ('\\' | attributes)); 280 (*addchar) ((int) (((unsigned char) *bp & TRIM) | 281 attributes)); 282 bp++; 283 } 284 if (flush_left) 285 while (f_width-- > 0) 286 (*addchar) ((int) (' ' | attributes)); 287 break; 288 289 case 'a': 290 attributes = va_arg(ap, int); 291 break; 292 293 case '%': 294 (*addchar) ((int) ('%' | attributes)); 295 break; 296 297 default: 298 break; 299 } 300 flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0; 301 sign = 0; 302 pad = ' '; 303 } 304 } 305} 306 307 308static char *xstring, *xestring; 309static void 310xaddchar(c) 311 int c; 312{ 313 if (xestring == xstring) 314 *xstring = '\0'; 315 else 316 *xstring++ = (char) c; 317} 318 319 320pret_t 321/*VARARGS*/ 322#ifdef FUNCPROTO 323xsnprintf(char *str, size_t size, const char *fmt, ...) 324#else 325xsnprintf(va_alist) 326 va_dcl 327#endif 328{ 329 va_list va; 330#ifdef FUNCPROTO 331 va_start(va, fmt); 332#else 333 char *str, *fmt; 334 size_t size; 335 336 va_start(va); 337 str = va_arg(va, char *); 338 size = va_arg(va, size_t); 339 fmt = va_arg(va, char *); 340#endif 341 342 xstring = str; 343 xestring = str + size - 1; 344 doprnt(xaddchar, fmt, va); 345 va_end(va); 346 *xstring++ = '\0'; 347#ifdef PURIFY 348 return 1; 349#endif 350} 351 352pret_t 353/*VARARGS*/ 354#ifdef FUNCPROTO 355xprintf(const char *fmt, ...) 356#else 357xprintf(va_alist) 358 va_dcl 359#endif 360{ 361 va_list va; 362#ifdef FUNCPROTO 363 va_start(va, fmt); 364#else 365 char *fmt; 366 367 va_start(va); 368 fmt = va_arg(va, char *); 369#endif 370 doprnt(xputchar, fmt, va); 371 va_end(va); 372#ifdef PURIFY 373 return 1; 374#endif 375} 376 377 378pret_t 379xvprintf(fmt, va) 380 const char *fmt; 381 va_list va; 382{ 383 doprnt(xputchar, fmt, va); 384#ifdef PURIFY 385 return 1; 386#endif 387} 388 389pret_t 390xvsnprintf(str, size, fmt, va) 391 char *str; 392 size_t size; 393 const char *fmt; 394 va_list va; 395{ 396 xstring = str; 397 xestring = str + size - 1; 398 doprnt(xaddchar, fmt, va); 399 *xstring++ = '\0'; 400#ifdef PURIFY 401 return 1; 402#endif 403} 404 405 406 407#ifdef PURIFY 408/* Purify uses (some of..) the following functions to output memory-use 409 * debugging info. Given all the messing with file descriptors that 410 * tcsh does, the easiest way I could think of to get it (Purify) to 411 * print anything was by replacing some standard functions with 412 * ones that do tcsh output directly - see dumb hook in doreaddirs() 413 * (sh.dir.c) -sg 414 */ 415#ifndef FILE 416#define FILE int 417#endif 418int 419#ifdef FUNCPROTO 420fprintf(FILE *fp, const char* fmt, ...) 421#else 422fprintf(va_alist) 423 va_dcl 424#endif 425{ 426 va_list va; 427#ifdef FUNCPROTO 428 va_start(va, fmt); 429#else 430 FILE *fp; 431 const char *fmt; 432 433 va_start(va); 434 fp = va_arg(va, FILE *); 435 fmt = va_arg(va, const char *); 436#endif 437 doprnt(xputchar, fmt, va); 438 va_end(va); 439 return 1; 440} 441 442int 443vfprintf(fp, fmt, va) 444 FILE *fp; 445 const char *fmt; 446 va_list va; 447{ 448 doprnt(xputchar, fmt, va); 449 return 1; 450} 451 452#endif /* PURIFY */ 453