1: /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.00/RCS/tc.printf.c,v 3.0 1991/07/04 21:49:28 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. All advertising materials mentioning features or use of this software 20: * must display the following acknowledgement: 21: * This product includes software developed by the University of 22: * California, Berkeley and its contributors. 23: * 4. Neither the name of the University nor the names of its contributors 24: * may be used to endorse or promote products derived from this software 25: * without specific prior written permission. 26: * 27: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37: * SUCH DAMAGE. 38: */ 39: #include "config.h" 40: #if !defined(lint) && !defined(pdp11) 41: static char *rcsid() 42: { return "$Id: tc.printf.c,v 3.0 1991/07/04 21:49:28 christos Exp $"; } 43: #endif 44: 45: #include "sh.h" 46: 47: #ifdef lint 48: #undef va_arg 49: #define va_arg(a, b) (a ? (b) 0 : (b) 0) 50: #endif 51: 52: #define INF 32766 /* should be bigger than any field to print */ 53: 54: static unsigned char buf[128]; 55: 56: static void xaddchar __P((int)); 57: static void doprnt __P((void (*) __P((int)), char *, va_list)); 58: 59: static void 60: doprnt(addchar, sfmt, ap) 61: void (*addchar)(); 62: char *sfmt; 63: va_list ap; 64: { 65: register unsigned char *f, *bp; 66: register long l; 67: register u_long u; 68: register int i; 69: register int fmt; 70: register unsigned char pad = ' '; 71: int flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0; 72: int sign = 0; 73: int attributes = 0; 74: 75: 76: f = (unsigned char *) sfmt; 77: for (; *f; f++) { 78: if (*f != '%') { /* then just out the char */ 79: (*addchar) ((int) (*f | attributes)); 80: } 81: else { 82: f++; /* skip the % */ 83: 84: if (*f == '-') { /* minus: flush left */ 85: flush_left = 1; 86: f++; 87: } 88: 89: if (*f == '0' || *f == '.') { 90: /* padding with 0 rather than blank */ 91: pad = '0'; 92: f++; 93: } 94: if (*f == '*') { /* field width */ 95: f_width = va_arg(ap, int); 96: f++; 97: } 98: else if (Isdigit(*f)) { 99: f_width = atoi((char *) f); 100: while (Isdigit(*f)) 101: f++; /* skip the digits */ 102: } 103: 104: if (*f == '.') { /* precision */ 105: f++; 106: if (*f == '*') { 107: prec = va_arg(ap, int); 108: f++; 109: } 110: else if (Isdigit(*f)) { 111: prec = atoi((char *) f); 112: while (Isdigit(*f)) 113: f++; /* skip the digits */ 114: } 115: } 116: 117: if (*f == '#') { /* alternate form */ 118: hash = 1; 119: f++; 120: } 121: 122: if (*f == 'l') { /* long format */ 123: do_long = 1; 124: f++; 125: } 126: 127: fmt = *f; 128: if (Isupper(fmt)) { 129: do_long = 1; 130: fmt = Tolower(fmt); 131: } 132: bp = buf; 133: switch (fmt) { /* do the format */ 134: case 'd': 135: if (do_long) 136: l = va_arg(ap, long); 137: else 138: l = (long) (va_arg(ap, int)); 139: if (l < 0) { 140: sign = 1; 141: l = -l; 142: } 143: do { 144: *bp++ = l % 10 + '0'; 145: } while ((l /= 10) > 0); 146: if (sign) 147: *bp++ = '-'; 148: f_width = f_width - (bp - buf); 149: if (!flush_left) 150: while (f_width-- > 0) 151: (*addchar) ((int) (pad | attributes)); 152: for (bp--; bp >= buf; bp--) 153: (*addchar) ((int) (*bp | attributes)); 154: if (flush_left) 155: while (f_width-- > 0) 156: (*addchar) ((int) (' ' | attributes)); 157: break; 158: 159: case 'o': 160: case 'x': 161: case 'u': 162: if (do_long) 163: u = va_arg(ap, u_long); 164: else 165: u = (u_long) (va_arg(ap, unsigned)); 166: if (fmt == 'u') { /* unsigned decimal */ 167: do { 168: *bp++ = u % 10 + '0'; 169: } while ((u /= 10) > 0); 170: } 171: else if (fmt == 'o') { /* octal */ 172: do { 173: *bp++ = u % 8 + '0'; 174: } while ((u /= 8) > 0); 175: if (hash) 176: *bp++ = '0'; 177: } 178: else if (fmt == 'x') { /* hex */ 179: do { 180: i = u % 16; 181: if (i < 10) 182: *bp++ = i + '0'; 183: else 184: *bp++ = i - 10 + 'a'; 185: } while ((u /= 16) > 0); 186: if (hash) { 187: *bp++ = 'x'; 188: *bp++ = '0'; 189: } 190: } 191: i = f_width - (bp - buf); 192: if (!flush_left) 193: while (i-- > 0) 194: (*addchar) ((int) (pad | attributes)); 195: for (bp--; bp >= buf; bp--) 196: (*addchar) ((int) (*bp | attributes)); 197: if (flush_left) 198: while (i-- > 0) 199: (*addchar) ((int) (' ' | attributes)); 200: break; 201: 202: 203: case 'c': 204: i = va_arg(ap, int); 205: (*addchar) ((int) (i | attributes)); 206: break; 207: 208: case 's': 209: bp = va_arg(ap, unsigned char *); 210: if (!bp) 211: bp = (unsigned char *) "(nil)"; 212: f_width = f_width - strlen((char *) bp); 213: if (!flush_left) 214: while (f_width-- > 0) 215: (*addchar) ((int) (pad | attributes)); 216: for (i = 0; *bp && i < prec; i++) { 217: (*addchar) ((int) (*bp | attributes)); 218: bp++; 219: } 220: if (flush_left) 221: while (f_width-- > 0) 222: (*addchar) ((int) (' ' | attributes)); 223: 224: break; 225: 226: case 'a': 227: attributes = va_arg(ap, int); 228: break; 229: 230: case '%': 231: (*addchar) ((int) ('%' | attributes)); 232: break; 233: } 234: flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0; 235: sign = 0; 236: pad = ' '; 237: } 238: } 239: } 240: 241: 242: static unsigned char *xstring; 243: static void 244: xaddchar(c) 245: int c; 246: { 247: *xstring++ = c; 248: } 249: 250: 251: void 252: /*VARARGS*/ 253: #if __STDC__ 254: xsprintf(char *str, char *fmt, ...) 255: #else 256: xsprintf(va_alist) 257: va_dcl 258: #endif 259: { 260: va_list va; 261: #if __STDC__ 262: va_start(va, fmt); 263: #else 264: char *str, *fmt; 265: 266: va_start(va); 267: str = va_arg(va, char *); 268: fmt = va_arg(va, char *); 269: #endif 270: 271: xstring = (unsigned char *) str; 272: doprnt(xaddchar, fmt, va); 273: va_end(va); 274: *xstring++ = '\0'; 275: } 276: 277: 278: void 279: /*VARARGS*/ 280: #if __STDC__ 281: xprintf(char *fmt, ...) 282: #else 283: xprintf(va_alist) 284: va_dcl 285: #endif 286: { 287: va_list va; 288: #if __STDC__ 289: va_start(va, fmt); 290: #else 291: char *fmt; 292: 293: va_start(va); 294: fmt = va_arg(va, char *); 295: #endif 296: doprnt(xputchar, fmt, va); 297: va_end(va); 298: } 299: 300: 301: void 302: xvprintf(fmt, va) 303: char *fmt; 304: va_list va; 305: { 306: doprnt(xputchar, fmt, va); 307: } 308: 309: void 310: xvsprintf(str, fmt, va) 311: char *str; 312: char *fmt; 313: va_list va; 314: { 315: xstring = (unsigned char *) str; 316: doprnt(xaddchar, fmt, va); 317: *xstring++ = '\0'; 318: }