tc.printf.c revision 145479
1264269Ssbruno/* $Header: /src/pub/tcsh/tc.printf.c,v 3.27 2005/01/05 16:06:15 christos Exp $ */ 2264269Ssbruno/* 3264269Ssbruno * tc.printf.c: A public-domain, minimal printf/sprintf routine that prints 4264269Ssbruno * through the putchar() routine. Feel free to use for 5264269Ssbruno * anything... -- 7/17/87 Paul Placeway 6264269Ssbruno */ 7264269Ssbruno/*- 8264269Ssbruno * Copyright (c) 1980, 1991 The Regents of the University of California. 9264269Ssbruno * All rights reserved. 10264269Ssbruno * 11264269Ssbruno * Redistribution and use in source and binary forms, with or without 12264269Ssbruno * modification, are permitted provided that the following conditions 13264269Ssbruno * are met: 14264269Ssbruno * 1. Redistributions of source code must retain the above copyright 15264269Ssbruno * notice, this list of conditions and the following disclaimer. 16264269Ssbruno * 2. Redistributions in binary form must reproduce the above copyright 17264269Ssbruno * notice, this list of conditions and the following disclaimer in the 18264269Ssbruno * documentation and/or other materials provided with the distribution. 19264269Ssbruno * 3. Neither the name of the University nor the names of its contributors 20264269Ssbruno * may be used to endorse or promote products derived from this software 21264269Ssbruno * without specific prior written permission. 22264269Ssbruno * 23264269Ssbruno * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24264269Ssbruno * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25264269Ssbruno * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26264269Ssbruno * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27264269Ssbruno * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28264269Ssbruno * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29264269Ssbruno * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30264269Ssbruno * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31264269Ssbruno * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32264269Ssbruno * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33264269Ssbruno * SUCH DAMAGE. 34264269Ssbruno */ 35264269Ssbruno#include "sh.h" 36264269Ssbruno 37264269SsbrunoRCSID("$Id: tc.printf.c,v 3.27 2005/01/05 16:06:15 christos Exp $") 38264269Ssbruno 39264269Ssbruno#ifdef lint 40264269Ssbruno#undef va_arg 41264269Ssbruno#define va_arg(a, b) (a ? (b) 0 : (b) 0) 42264269Ssbruno#endif 43264269Ssbruno 44264269Ssbruno#define INF 32766 /* should be bigger than any field to print */ 45264269Ssbruno 46264269Ssbrunostatic char buf[128]; 47264269Ssbrunostatic char snil[] = "(nil)"; 48264269Ssbruno 49264269Ssbrunostatic void xaddchar __P((int)); 50264269Ssbrunostatic void doprnt __P((void (*) __P((int)), const char *, va_list)); 51264269Ssbruno 52264269Ssbrunostatic void 53264269Ssbrunodoprnt(addchar, sfmt, ap) 54264269Ssbruno void (*addchar) __P((int)); 55264269Ssbruno const char *sfmt; 56264269Ssbruno va_list ap; 57264269Ssbruno{ 58264269Ssbruno char *bp; 59264269Ssbruno const char *f; 60264269Ssbruno#ifdef SHORT_STRINGS 61264269Ssbruno Char *Bp; 62264269Ssbruno#endif /* SHORT_STRINGS */ 63264269Ssbruno#ifdef HAVE_LONG_LONG 64264269Ssbruno long long l; 65264269Ssbruno unsigned long long u; 66264269Ssbruno#else 67264269Ssbruno long l; 68264269Ssbruno unsigned long u; 69264269Ssbruno#endif 70264269Ssbruno int i; 71264269Ssbruno int fmt; 72264269Ssbruno unsigned char pad = ' '; 73264269Ssbruno int flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0; 74264269Ssbruno int sign = 0; 75264269Ssbruno int attributes = 0; 76264269Ssbruno 77264269Ssbruno 78264269Ssbruno f = sfmt; 79264269Ssbruno for (; *f; f++) { 80264269Ssbruno if (*f != '%') { /* then just out the char */ 81264269Ssbruno (*addchar) ((int) (((unsigned char)*f) | attributes)); 82264269Ssbruno } 83264269Ssbruno else { 84264269Ssbruno f++; /* skip the % */ 85264269Ssbruno 86264269Ssbruno if (*f == '-') { /* minus: flush left */ 87264269Ssbruno flush_left = 1; 88264269Ssbruno f++; 89264269Ssbruno } 90264269Ssbruno 91264269Ssbruno if (*f == '0' || *f == '.') { 92264269Ssbruno /* padding with 0 rather than blank */ 93264269Ssbruno pad = '0'; 94264269Ssbruno f++; 95264269Ssbruno } 96264269Ssbruno if (*f == '*') { /* field width */ 97264269Ssbruno f_width = va_arg(ap, int); 98264269Ssbruno f++; 99264269Ssbruno } 100264269Ssbruno else if (isdigit((unsigned char) *f)) { 101264269Ssbruno f_width = atoi(f); 102264269Ssbruno while (isdigit((unsigned char) *f)) 103264269Ssbruno f++; /* skip the digits */ 104264269Ssbruno } 105264269Ssbruno 106264269Ssbruno if (*f == '.') { /* precision */ 107264269Ssbruno f++; 108264269Ssbruno if (*f == '*') { 109264269Ssbruno prec = va_arg(ap, int); 110264269Ssbruno f++; 111264269Ssbruno } 112264269Ssbruno else if (isdigit((unsigned char) *f)) { 113264269Ssbruno prec = atoi(f); 114264269Ssbruno while (isdigit((unsigned char) *f)) 115264269Ssbruno f++; /* skip the digits */ 116264269Ssbruno } 117264269Ssbruno } 118264269Ssbruno 119264269Ssbruno if (*f == '#') { /* alternate form */ 120264269Ssbruno hash = 1; 121264269Ssbruno f++; 122264269Ssbruno } 123264269Ssbruno 124264269Ssbruno if (*f == 'l') { /* long format */ 125264269Ssbruno do_long++; 126264269Ssbruno f++; 127264269Ssbruno if (*f == 'l') { 128264269Ssbruno do_long++; 129264269Ssbruno f++; 130264269Ssbruno } 131264269Ssbruno } 132264269Ssbruno 133264269Ssbruno fmt = (unsigned char) *f; 134264269Ssbruno if (fmt != 'S' && fmt != 'Q' && isupper(fmt)) { 135264269Ssbruno do_long = 1; 136264269Ssbruno fmt = tolower(fmt); 137264269Ssbruno } 138264269Ssbruno bp = buf; 139264269Ssbruno switch (fmt) { /* do the format */ 140264269Ssbruno case 'd': 141264269Ssbruno switch (do_long) { 142264269Ssbruno case 0: 143264269Ssbruno l = (long) (va_arg(ap, int)); 144264269Ssbruno break; 145264269Ssbruno case 1: 146264269Ssbruno#ifndef HAVE_LONG_LONG 147264269Ssbruno default: 148264269Ssbruno#endif 149264269Ssbruno l = va_arg(ap, long); 150264269Ssbruno break; 151264269Ssbruno#ifdef HAVE_LONG_LONG 152264269Ssbruno default: 153264269Ssbruno l = va_arg(ap, long long); 154264269Ssbruno break; 155264269Ssbruno#endif 156264269Ssbruno } 157264269Ssbruno 158264269Ssbruno if (l < 0) { 159264269Ssbruno sign = 1; 160264269Ssbruno l = -l; 161264269Ssbruno } 162264269Ssbruno do { 163264269Ssbruno *bp++ = (char) (l % 10) + '0'; 164264269Ssbruno } while ((l /= 10) > 0); 165264269Ssbruno if (sign) 166264269Ssbruno *bp++ = '-'; 167264269Ssbruno f_width = f_width - (int) (bp - buf); 168264269Ssbruno if (!flush_left) 169264269Ssbruno while (f_width-- > 0) 170264269Ssbruno (*addchar) ((int) (pad | attributes)); 171264269Ssbruno for (bp--; bp >= buf; bp--) 172264269Ssbruno (*addchar) ((int) (((unsigned char) *bp) | attributes)); 173264269Ssbruno if (flush_left) 174264269Ssbruno while (f_width-- > 0) 175264269Ssbruno (*addchar) ((int) (' ' | attributes)); 176264269Ssbruno break; 177264269Ssbruno 178264269Ssbruno case 'p': 179264269Ssbruno do_long = 1; 180264269Ssbruno hash = 1; 181264269Ssbruno fmt = 'x'; 182264269Ssbruno /*FALLTHROUGH*/ 183264269Ssbruno case 'o': 184264269Ssbruno case 'x': 185264269Ssbruno case 'u': 186264269Ssbruno switch (do_long) { 187264269Ssbruno case 0: 188264269Ssbruno u = (unsigned long) (va_arg(ap, unsigned int)); 189264269Ssbruno break; 190264269Ssbruno case 1: 191264269Ssbruno#ifndef HAVE_LONG_LONG 192264269Ssbruno default: 193264269Ssbruno#endif 194264269Ssbruno u = va_arg(ap, unsigned long); 195264269Ssbruno break; 196264269Ssbruno#ifdef HAVE_LONG_LONG 197264269Ssbruno default: 198264269Ssbruno u = va_arg(ap, unsigned long long); 199264269Ssbruno break; 200264269Ssbruno#endif 201264269Ssbruno } 202264269Ssbruno if (fmt == 'u') { /* unsigned decimal */ 203264269Ssbruno do { 204264269Ssbruno *bp++ = (char) (u % 10) + '0'; 205264269Ssbruno } while ((u /= 10) > 0); 206264269Ssbruno } 207264269Ssbruno else if (fmt == 'o') { /* octal */ 208264269Ssbruno do { 209264269Ssbruno *bp++ = (char) (u % 8) + '0'; 210264269Ssbruno } while ((u /= 8) > 0); 211264269Ssbruno if (hash) 212264269Ssbruno *bp++ = '0'; 213264269Ssbruno } 214264269Ssbruno else if (fmt == 'x') { /* hex */ 215264269Ssbruno do { 216264269Ssbruno i = (int) (u % 16); 217264269Ssbruno if (i < 10) 218264269Ssbruno *bp++ = i + '0'; 219264269Ssbruno else 220264269Ssbruno *bp++ = i - 10 + 'a'; 221264269Ssbruno } while ((u /= 16) > 0); 222264269Ssbruno if (hash) { 223264269Ssbruno *bp++ = 'x'; 224264269Ssbruno *bp++ = '0'; 225264269Ssbruno } 226264269Ssbruno } 227264269Ssbruno i = f_width - (int) (bp - buf); 228264269Ssbruno if (!flush_left) 229264269Ssbruno while (i-- > 0) 230264269Ssbruno (*addchar) ((int) (pad | attributes)); 231264269Ssbruno for (bp--; bp >= buf; bp--) 232264269Ssbruno (*addchar) ((int) (((unsigned char) *bp) | attributes)); 233264269Ssbruno if (flush_left) 234264269Ssbruno while (i-- > 0) 235264269Ssbruno (*addchar) ((int) (' ' | attributes)); 236264269Ssbruno break; 237264269Ssbruno 238264269Ssbruno 239264269Ssbruno case 'c': 240264269Ssbruno i = va_arg(ap, int); 241264269Ssbruno (*addchar) ((int) (i | attributes)); 242264269Ssbruno break; 243264269Ssbruno 244264269Ssbruno case 'S': 245264269Ssbruno case 'Q': 246264269Ssbruno#ifdef SHORT_STRINGS 247264269Ssbruno Bp = va_arg(ap, Char *); 248264269Ssbruno if (!Bp) { 249264269Ssbruno bp = NULL; 250264269Ssbruno goto lcase_s; 251264269Ssbruno } 252264269Ssbruno f_width = f_width - Strlen(Bp); 253264269Ssbruno if (!flush_left) 254264269Ssbruno while (f_width-- > 0) 255264269Ssbruno (*addchar) ((int) (pad | attributes)); 256264269Ssbruno for (i = 0; *Bp && i < prec; i++) { 257264269Ssbruno char cbuf[MB_LEN_MAX]; 258264269Ssbruno size_t pos, len; 259264269Ssbruno 260264269Ssbruno if (fmt == 'Q' && *Bp & QUOTE) 261264269Ssbruno (*addchar) ((int) ('\\' | attributes)); 262264269Ssbruno len = one_wctomb(cbuf, *Bp & CHAR); 263264269Ssbruno for (pos = 0; pos < len; pos++) 264264269Ssbruno (*addchar) ((int) ((unsigned char)cbuf[pos] 265264269Ssbruno | attributes | (*Bp & ATTRIBUTES))); 266264269Ssbruno Bp++; 267264269Ssbruno } 268264269Ssbruno if (flush_left) 269264269Ssbruno while (f_width-- > 0) 270264269Ssbruno (*addchar) ((int) (' ' | attributes)); 271264269Ssbruno break; 272264269Ssbruno#endif /* SHORT_STRINGS */ 273264269Ssbruno 274264269Ssbruno case 's': 275264269Ssbruno case 'q': 276264269Ssbruno bp = va_arg(ap, char *); 277264269Ssbrunolcase_s: 278264269Ssbruno if (!bp) 279264269Ssbruno bp = snil; 280264269Ssbruno f_width = f_width - strlen((char *) bp); 281264269Ssbruno if (!flush_left) 282264269Ssbruno while (f_width-- > 0) 283264269Ssbruno (*addchar) ((int) (pad | attributes)); 284264269Ssbruno for (i = 0; *bp && i < prec; i++) { 285264269Ssbruno if (fmt == 'q' && *bp & QUOTE) 286264269Ssbruno (*addchar) ((int) ('\\' | attributes)); 287264269Ssbruno (*addchar) ((int) (((unsigned char) *bp & TRIM) | 288264269Ssbruno attributes)); 289264269Ssbruno bp++; 290264269Ssbruno } 291264269Ssbruno if (flush_left) 292264269Ssbruno while (f_width-- > 0) 293264269Ssbruno (*addchar) ((int) (' ' | attributes)); 294264269Ssbruno break; 295264269Ssbruno 296264269Ssbruno case 'a': 297264269Ssbruno attributes = va_arg(ap, int); 298264269Ssbruno break; 299264269Ssbruno 300264269Ssbruno case '%': 301264269Ssbruno (*addchar) ((int) ('%' | attributes)); 302264269Ssbruno break; 303264269Ssbruno 304264269Ssbruno default: 305264269Ssbruno break; 306264269Ssbruno } 307264269Ssbruno flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0; 308264269Ssbruno sign = 0; 309264269Ssbruno pad = ' '; 310264269Ssbruno } 311264269Ssbruno } 312264269Ssbruno} 313264269Ssbruno 314264269Ssbruno 315264269Ssbrunostatic char *xstring, *xestring; 316264269Ssbrunostatic void 317264269Ssbrunoxaddchar(c) 318264269Ssbruno int c; 319264269Ssbruno{ 320264269Ssbruno if (xestring == xstring) 321264269Ssbruno *xstring = '\0'; 322264269Ssbruno else 323264269Ssbruno *xstring++ = (char) c; 324264269Ssbruno} 325264269Ssbruno 326264269Ssbruno 327264269Ssbrunopret_t 328264269Ssbruno/*VARARGS*/ 329264269Ssbruno#ifdef PROTOTYPES 330264269Ssbrunoxsnprintf(char *str, size_t size, const char *fmt, ...) 331264269Ssbruno#else 332264269Ssbrunoxsnprintf(va_alist) 333264269Ssbruno va_dcl 334264269Ssbruno#endif 335264269Ssbruno{ 336264269Ssbruno va_list va; 337264269Ssbruno#ifdef PROTOTYPES 338264269Ssbruno va_start(va, fmt); 339264269Ssbruno#else 340264269Ssbruno char *str, *fmt; 341264269Ssbruno size_t size; 342264269Ssbruno 343264269Ssbruno va_start(va); 344264269Ssbruno str = va_arg(va, char *); 345264269Ssbruno size = va_arg(va, size_t); 346264269Ssbruno fmt = va_arg(va, char *); 347264269Ssbruno#endif 348264269Ssbruno 349264269Ssbruno xstring = str; 350264269Ssbruno xestring = str + size - 1; 351264269Ssbruno doprnt(xaddchar, fmt, va); 352264269Ssbruno va_end(va); 353264269Ssbruno *xstring++ = '\0'; 354264269Ssbruno#ifdef PURIFY 355264269Ssbruno return 1; 356264269Ssbruno#endif 357264269Ssbruno} 358264269Ssbruno 359264269Ssbrunopret_t 360264269Ssbruno/*VARARGS*/ 361264269Ssbruno#ifdef PROTOTYPES 362264269Ssbrunoxprintf(const char *fmt, ...) 363264269Ssbruno#else 364264269Ssbrunoxprintf(va_alist) 365264269Ssbruno va_dcl 366287463Ssbruno#endif 367264269Ssbruno{ 368264269Ssbruno va_list va; 369264269Ssbruno#ifdef PROTOTYPES 370264269Ssbruno va_start(va, fmt); 371264269Ssbruno#else 372264269Ssbruno char *fmt; 373264269Ssbruno 374278961Ssbruno va_start(va); 375264269Ssbruno fmt = va_arg(va, char *); 376278961Ssbruno#endif 377278961Ssbruno doprnt(xputchar, fmt, va); 378264269Ssbruno va_end(va); 379264269Ssbruno#ifdef PURIFY 380264269Ssbruno return 1; 381264269Ssbruno#endif 382264269Ssbruno} 383264269Ssbruno 384264269Ssbruno 385264269Ssbrunopret_t 386264269Ssbrunoxvprintf(fmt, va) 387264269Ssbruno const char *fmt; 388264269Ssbruno va_list va; 389264269Ssbruno{ 390264269Ssbruno doprnt(xputchar, fmt, va); 391264269Ssbruno#ifdef PURIFY 392264269Ssbruno return 1; 393264269Ssbruno#endif 394264269Ssbruno} 395264269Ssbruno 396264269Ssbrunopret_t 397264269Ssbrunoxvsnprintf(str, size, fmt, va) 398264269Ssbruno char *str; 399264269Ssbruno size_t size; 400264269Ssbruno const char *fmt; 401264269Ssbruno va_list va; 402264269Ssbruno{ 403264269Ssbruno xstring = str; 404264269Ssbruno xestring = str + size - 1; 405264269Ssbruno doprnt(xaddchar, fmt, va); 406264269Ssbruno *xstring++ = '\0'; 407264269Ssbruno#ifdef PURIFY 408264269Ssbruno return 1; 409264269Ssbruno#endif 410264269Ssbruno} 411264269Ssbruno 412264269Ssbruno 413264269Ssbruno 414264269Ssbruno#ifdef PURIFY 415264269Ssbruno/* Purify uses (some of..) the following functions to output memory-use 416264269Ssbruno * debugging info. Given all the messing with file descriptors that 417264269Ssbruno * tcsh does, the easiest way I could think of to get it (Purify) to 418264269Ssbruno * print anything was by replacing some standard functions with 419264269Ssbruno * ones that do tcsh output directly - see dumb hook in doreaddirs() 420264269Ssbruno * (sh.dir.c) -sg 421264269Ssbruno */ 422264269Ssbruno#ifndef FILE 423264269Ssbruno#define FILE int 424264269Ssbruno#endif 425264269Ssbrunoint 426264269Ssbruno#ifdef PROTOTYPES 427264269Ssbrunofprintf(FILE *fp, const char* fmt, ...) 428264269Ssbruno#else 429264269Ssbrunofprintf(va_alist) 430264269Ssbruno va_dcl 431264269Ssbruno#endif 432264269Ssbruno{ 433264269Ssbruno va_list va; 434264269Ssbruno#ifdef PROTOTYPES 435264269Ssbruno va_start(va, fmt); 436264269Ssbruno#else 437264269Ssbruno FILE *fp; 438264269Ssbruno const char *fmt; 439264269Ssbruno 440264269Ssbruno va_start(va); 441264269Ssbruno fp = va_arg(va, FILE *); 442264269Ssbruno fmt = va_arg(va, const char *); 443264269Ssbruno#endif 444264269Ssbruno doprnt(xputchar, fmt, va); 445264269Ssbruno va_end(va); 446264269Ssbruno return 1; 447264269Ssbruno} 448264269Ssbruno 449264269Ssbrunoint 450264269Ssbrunovfprintf(fp, fmt, va) 451264269Ssbruno FILE *fp; 452264269Ssbruno const char *fmt; 453264269Ssbruno va_list va; 454264269Ssbruno{ 455264269Ssbruno doprnt(xputchar, fmt, va); 456264269Ssbruno return 1; 457264269Ssbruno} 458264269Ssbruno 459264269Ssbruno#endif /* PURIFY */ 460264269Ssbruno