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: }

Defined functions

asciicode defined in line 395; used 3 times
escape defined in line 254; used 2 times
getchr defined in line 316; used 2 times
getdouble defined in line 385; used 2 times
getint defined in line 333; used 3 times
getlong defined in line 349; used 3 times
getstr defined in line 324; used 2 times
main defined in line 94; never used
mklong defined in line 236; used 2 times
progprintf defined in line 94; never used
usage defined in line 407; used 3 times

Defined variables

Number defined in line 332; used 2 times
copyright defined in line 35; never used
gargv defined in line 92; used 20 times
sccsid defined in line 39; never used

Defined macros

EOF defined in line 46; used 1 times
PF defined in line 70; used 4 times
main defined in line 61; never used
warnx defined in line 62; used 7 times
Last modified: 1995-04-03
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3503
Valid CSS Valid XHTML 1.0 Strict