1: /* 2: * Copyright (c) 1989, 1993 3: * The Regents of the University of California. All rights reserved. 4: * 5: * Redistribution and use in source and binary forms, with or without 6: * modification, are permitted provided that the following conditions 7: * are met: 8: * 1. Redistributions of source code must retain the above copyright 9: * notice, this list of conditions and the following disclaimer. 10: * 2. Redistributions in binary form must reproduce the above copyright 11: * notice, this list of conditions and the following disclaimer in the 12: * documentation and/or other materials provided with the distribution. 13: * 3. All advertising materials mentioning features or use of this software 14: * must display the following acknowledgement: 15: * This product includes software developed by the University of 16: * California, Berkeley and its contributors. 17: * 4. Neither the name of the University nor the names of its contributors 18: * may be used to endorse or promote products derived from this software 19: * without specific prior written permission. 20: * 21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31: * SUCH DAMAGE. 32: */ 33: 34: #if !defined(BUILTIN) && !defined(SHELL) && !defined(lint) && defined(DOSCCS) 35: static char copyright[] = 36: "@(#) Copyright (c) 1989, 1993\n\ 37: The Regents of the University of California. All rights reserved.\n"; 38: 39: static char sccsid[] = "@(#)printf.c 8.1 (Berkeley) 7/20/93"; 40: #endif /* not lint */ 41: 42: #include <sys/types.h> 43: 44: #include <errno.h> 45: #ifdef SHELL 46: #define EOF -1 47: #else 48: #include <stdio.h> 49: #endif 50: #include <string.h> 51: 52: extern double atof(); 53: extern long strtol(); 54: extern int errno; 55: 56: /* 57: * XXX 58: * This *has* to go away. TK. 59: */ 60: #ifdef SHELL 61: #define main printfcmd 62: #define warnx(a, b, c) { \ 63: char buf[64]; \ 64: (void)sprintf(buf, sizeof(buf), a, b, c); \ 65: error(buf); \ 66: } 67: #include "../../bin/sh/bltin/bltin.h" 68: #endif 69: 70: #define PF(f, func) { \ 71: if (fieldwidth) \ 72: if (precision) \ 73: (void)printf(f, fieldwidth, precision, func); \ 74: else \ 75: (void)printf(f, fieldwidth, func); \ 76: else if (precision) \ 77: (void)printf(f, precision, func); \ 78: else \ 79: (void)printf(f, func); \ 80: } 81: 82: static int asciicode(); 83: static void escape(); 84: static int getchr(); 85: static double getdouble(); 86: static int getint(); 87: static int getlong(); 88: static char *getstr(); 89: static char *mklong(); 90: static void usage(); 91: 92: static char **gargv; 93: 94: int 95: #ifdef BUILTIN 96: progprintf(argc, argv) 97: #else 98: main(argc, argv) 99: #endif 100: int argc; 101: char *argv[]; 102: { 103: extern int optind; 104: static char *skip1, *skip2; 105: int ch, end, fieldwidth, precision; 106: char convch, nextch, *format, *start; 107: register char *fmt; 108: 109: while ((ch = getopt(argc, argv, "")) != EOF) 110: switch (ch) { 111: case '?': 112: default: 113: usage(); 114: return (1); 115: } 116: argc -= optind; 117: argv += optind; 118: 119: if (argc < 1) { 120: usage(); 121: return (1); 122: } 123: 124: /* 125: * Basic algorithm is to scan the format string for conversion 126: * specifications -- once one is found, find out if the field 127: * width or precision is a '*'; if it is, gather up value. Note, 128: * format strings are reused as necessary to use up the provided 129: * arguments, arguments of zero/null string are provided to use 130: * up the format string. 131: */ 132: skip1 = "#-+ 0"; 133: skip2 = "*0123456789"; 134: 135: escape(fmt = format = *argv); /* backslash interpretation */ 136: gargv = ++argv; 137: for (;;) { 138: end = 0; 139: /* find next format specification */ 140: next: for (start = fmt;; ++fmt) { 141: if (!*fmt) { 142: /* avoid infinite loop */ 143: if (end == 1) { 144: warnx("missing format character", 145: NULL, NULL); 146: return (1); 147: } 148: end = 1; 149: if (fmt > start) 150: (void)printf("%s", start); 151: if (!*gargv) 152: return (0); 153: fmt = format; 154: goto next; 155: } 156: /* %% prints a % */ 157: if (*fmt == '%') { 158: if (*++fmt != '%') 159: break; 160: *fmt++ = '\0'; 161: (void)printf("%s", start); 162: goto next; 163: } 164: } 165: 166: /* skip to field width */ 167: for (; strchr(skip1, *fmt); ++fmt); 168: if (*fmt == '*') { 169: if (getint(&fieldwidth)) 170: return (1); 171: } else 172: fieldwidth = 0; 173: 174: /* skip to possible '.', get following precision */ 175: for (; strchr(skip2, *fmt); ++fmt); 176: if (*fmt == '.') 177: ++fmt; 178: if (*fmt == '*') { 179: if (getint(&precision)) 180: return (1); 181: } else 182: precision = 0; 183: 184: /* skip to conversion char */ 185: for (; strchr(skip2, *fmt); ++fmt); 186: if (!*fmt) { 187: warnx("missing format character", NULL, NULL); 188: return (1); 189: } 190: 191: convch = *fmt; 192: nextch = *++fmt; 193: *fmt = '\0'; 194: switch(convch) { 195: case 'c': { 196: char p; 197: 198: p = getchr(); 199: PF(start, p); 200: break; 201: } 202: case 's': { 203: char *p; 204: 205: p = getstr(); 206: PF(start, p); 207: break; 208: } 209: case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': { 210: long p; 211: char *f; 212: 213: if ((f = mklong(start, convch)) == NULL) 214: return (1); 215: if (getlong(&p)) 216: return (1); 217: PF(f, p); 218: break; 219: } 220: case 'e': case 'E': case 'f': case 'g': case 'G': { 221: double p; 222: 223: p = getdouble(); 224: PF(start, p); 225: break; 226: } 227: default: 228: warnx("illegal format character", NULL, NULL); 229: return (1); 230: } 231: *fmt = nextch; 232: } 233: /* NOTREACHED */ 234: } 235: 236: static char * 237: mklong(str, ch) 238: register char *str; 239: int ch; 240: { 241: static char copy[64]; 242: register int len; 243: 244: if (ch == 'X') /* XXX */ 245: ch = 'x'; 246: len = strlen(str) + 2; 247: bcopy(str, copy, len - 3); 248: copy[len - 3] = 'l'; 249: copy[len - 2] = ch; 250: copy[len - 1] = '\0'; 251: return (copy); 252: } 253: 254: static void 255: escape(fmt) 256: register char *fmt; 257: { 258: register char *store; 259: register int value; 260: int c; 261: 262: for (store = fmt; c = *fmt; ++fmt, ++store) { 263: if (c != '\\') { 264: *store = c; 265: continue; 266: } 267: switch (*++fmt) { 268: case '\0': /* EOS, user error */ 269: *store = '\\'; 270: *++store = '\0'; 271: return; 272: case '\\': /* backslash */ 273: case '\'': /* single quote */ 274: *store = *fmt; 275: break; 276: case 'a': /* bell/alert */ 277: *store = '\7'; 278: break; 279: case 'b': /* backspace */ 280: *store = '\b'; 281: break; 282: case 'f': /* form-feed */ 283: *store = '\f'; 284: break; 285: case 'n': /* newline */ 286: *store = '\n'; 287: break; 288: case 'r': /* carriage-return */ 289: *store = '\r'; 290: break; 291: case 't': /* horizontal tab */ 292: *store = '\t'; 293: break; 294: case 'v': /* vertical tab */ 295: *store = '\13'; 296: break; 297: /* octal constant */ 298: case '0': case '1': case '2': case '3': 299: case '4': case '5': case '6': case '7': 300: for (c = 3, value = 0; 301: c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) { 302: value <<= 3; 303: value += *fmt - '0'; 304: } 305: --fmt; 306: *store = value; 307: break; 308: default: 309: *store = *fmt; 310: break; 311: } 312: } 313: *store = '\0'; 314: } 315: 316: static int 317: getchr() 318: { 319: if (!*gargv) 320: return ('\0'); 321: return ((int)**gargv++); 322: } 323: 324: static char * 325: getstr() 326: { 327: if (!*gargv) 328: return (""); 329: return (*gargv++); 330: } 331: 332: static char *Number = "+-.0123456789"; 333: static int 334: getint(ip) 335: int *ip; 336: { 337: long val; 338: 339: if (getlong(&val)) 340: return (1); 341: if (val > 65535) { 342: warnx("%s: %s", *gargv, strerror(ERANGE)); 343: return (1); 344: } 345: *ip = val; 346: return (0); 347: } 348: 349: static int 350: getlong(lp) 351: register long *lp; 352: { 353: long val; 354: char *ep; 355: 356: if (!*gargv) { 357: *lp = 0; 358: return (0); 359: } 360: if (strchr(Number, **gargv)) { 361: errno = 0; 362: val = strtol(*gargv, &ep, 0); 363: if (*ep != '\0') { 364: warnx("%s: illegal number", *gargv, NULL); 365: return (1); 366: } 367: if (errno == ERANGE) 368: if (val == 2147483647L) { 369: warnx("%s: %s", *gargv, strerror(ERANGE)); 370: return (1); 371: } 372: if (val == (-2147483647L-1)) { 373: warnx("%s: %s", *gargv, strerror(ERANGE)); 374: return (1); 375: } 376: 377: *lp = val; 378: ++gargv; 379: return (0); 380: } 381: *lp = (long)asciicode(); 382: return (0); 383: } 384: 385: static double 386: getdouble() 387: { 388: if (!*gargv) 389: return ((double)0); 390: if (strchr(Number, **gargv)) 391: return (atof(*gargv++)); 392: return ((double)asciicode()); 393: } 394: 395: static int 396: asciicode() 397: { 398: register int ch; 399: 400: ch = **gargv; 401: if (ch == '\'' || ch == '"') 402: ch = (*gargv)[1]; 403: ++gargv; 404: return (ch); 405: } 406: 407: static void 408: usage() 409: { 410: (void)fprintf(stderr, "usage: printf format [arg ...]\n"); 411: }