136725Sbostic /* 236725Sbostic * Copyright (c) 1989 The Regents of the University of California. 336725Sbostic * All rights reserved. 436725Sbostic * 542758Sbostic * %sccs.include.redist.c% 636725Sbostic */ 736725Sbostic 853564Smarc #if ! defined(BUILTIN) && ! defined(SHELL) 936725Sbostic #ifndef lint 1036725Sbostic char copyright[] = 1136725Sbostic "@(#) Copyright (c) 1989 The Regents of the University of California.\n\ 1236725Sbostic All rights reserved.\n"; 1336725Sbostic #endif /* not lint */ 1450477Sbostic #endif 1536725Sbostic 1636725Sbostic #ifndef lint 17*55444Smarc static char sccsid[] = "@(#)printf.c 5.12 (Berkeley) 07/20/92"; 1836725Sbostic #endif /* not lint */ 1936725Sbostic 2053564Smarc 2136725Sbostic #include <sys/types.h> 2250477Sbostic #include <errno.h> 2353564Smarc #ifndef SHELL 2436725Sbostic #include <stdio.h> 2553564Smarc #endif 2650477Sbostic #include <stdlib.h> 2750477Sbostic #include <string.h> 2836725Sbostic 29*55444Smarc /* 30*55444Smarc * XXX 31*55444Smarc * This *has* to go away. TK. 32*55444Smarc */ 3353564Smarc #ifdef SHELL 3453564Smarc #define main printfcmd 3553564Smarc #define err error 36*55444Smarc #include "../../bin/sh/bltin/bltin.h" 3753564Smarc #endif 3853564Smarc 3936725Sbostic #define PF(f, func) { \ 4036725Sbostic if (fieldwidth) \ 4136725Sbostic if (precision) \ 4236811Sbostic (void)printf(f, fieldwidth, precision, func); \ 4336725Sbostic else \ 4436811Sbostic (void)printf(f, fieldwidth, func); \ 4536725Sbostic else if (precision) \ 4636811Sbostic (void)printf(f, precision, func); \ 4736725Sbostic else \ 4836811Sbostic (void)printf(f, func); \ 4936725Sbostic } 5036725Sbostic 5150477Sbostic static int asciicode __P((void)); 5253564Smarc #ifndef SHELL 5350477Sbostic static void err __P((const char *fmt, ...)); 5453564Smarc #endif 5550477Sbostic static void escape __P((char *)); 5650477Sbostic static int getchr __P((void)); 5750477Sbostic static double getdouble __P((void)); 5850477Sbostic static int getint __P((void)); 5950477Sbostic static long getlong __P((void)); 6050477Sbostic static char *getstr __P((void)); 6150477Sbostic static char *mklong __P((char *, int)); 6236725Sbostic 6350477Sbostic static char **gargv; 6450477Sbostic 6550477Sbostic int 6650477Sbostic #ifdef BUILTIN 6750477Sbostic progprintf(argc, argv) 6850477Sbostic #else 6936725Sbostic main(argc, argv) 7050477Sbostic #endif 7136725Sbostic int argc; 7236725Sbostic char **argv; 7336725Sbostic { 7436725Sbostic static char *skip1, *skip2; 7536725Sbostic register char *format, *fmt, *start; 7636811Sbostic register int end, fieldwidth, precision; 7750477Sbostic char convch, nextch; 7836725Sbostic 7936725Sbostic if (argc < 2) { 8050477Sbostic (void)fprintf(stderr, "usage: printf format [arg ...]\n"); 8150477Sbostic return (1); 8236725Sbostic } 8336725Sbostic 8436725Sbostic /* 8536725Sbostic * Basic algorithm is to scan the format string for conversion 8636725Sbostic * specifications -- once one is found, find out if the field 8736725Sbostic * width or precision is a '*'; if it is, gather up value. Note, 8836725Sbostic * format strings are reused as necessary to use up the provided 8936725Sbostic * arguments, arguments of zero/null string are provided to use 9036725Sbostic * up the format string. 9136725Sbostic */ 9236725Sbostic skip1 = "#-+ 0"; 9336725Sbostic skip2 = "*0123456789"; 9436725Sbostic 9536725Sbostic escape(fmt = format = *++argv); /* backslash interpretation */ 9636725Sbostic gargv = ++argv; 9736811Sbostic for (;;) { 9836725Sbostic end = 0; 9936725Sbostic /* find next format specification */ 10036725Sbostic next: for (start = fmt;; ++fmt) { 10136725Sbostic if (!*fmt) { 10236725Sbostic /* avoid infinite loop */ 10336725Sbostic if (end == 1) { 10450477Sbostic err("missing format character"); 10550477Sbostic return (1); 10636725Sbostic } 10736725Sbostic end = 1; 10836725Sbostic if (fmt > start) 10936811Sbostic (void)printf("%s", start); 11036725Sbostic if (!*gargv) 11150477Sbostic return (0); 11236725Sbostic fmt = format; 11336725Sbostic goto next; 11436725Sbostic } 11536725Sbostic /* %% prints a % */ 11638480Sbostic if (*fmt == '%') { 11738480Sbostic if (*++fmt != '%') 11838480Sbostic break; 11938480Sbostic *fmt++ = '\0'; 12038480Sbostic (void)printf("%s", start); 12138480Sbostic goto next; 12238480Sbostic } 12336725Sbostic } 12436725Sbostic 12536725Sbostic /* skip to field width */ 12636725Sbostic for (; index(skip1, *fmt); ++fmt); 12736879Sbostic fieldwidth = *fmt == '*' ? getint() : 0; 12836879Sbostic 12936879Sbostic /* skip to possible '.', get following precision */ 13036725Sbostic for (; index(skip2, *fmt); ++fmt); 13136725Sbostic if (*fmt == '.') 13236725Sbostic ++fmt; 13336879Sbostic precision = *fmt == '*' ? getint() : 0; 13436879Sbostic 13536725Sbostic /* skip to conversion char */ 13636725Sbostic for (; index(skip2, *fmt); ++fmt); 13736725Sbostic if (!*fmt) { 13850477Sbostic err("missing format character"); 13950477Sbostic return (1); 14036725Sbostic } 14136725Sbostic 14236725Sbostic convch = *fmt; 14336725Sbostic nextch = *++fmt; 14436725Sbostic *fmt = '\0'; 14536725Sbostic switch(convch) { 14636725Sbostic case 'c': { 14750477Sbostic char p; 14850477Sbostic 14950477Sbostic p = getchr(); 15036725Sbostic PF(start, p); 15136725Sbostic break; 15236725Sbostic } 15336725Sbostic case 's': { 15450477Sbostic char *p; 15550477Sbostic 15650477Sbostic p = getstr(); 15736725Sbostic PF(start, p); 15836725Sbostic break; 15936725Sbostic } 16036729Sbostic case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': { 16150477Sbostic long p; 16250477Sbostic char *f; 16350477Sbostic 16450477Sbostic if ((f = mklong(start, convch)) == NULL) 16550477Sbostic return (1); 16650477Sbostic p = getlong(); 16736725Sbostic PF(f, p); 16836725Sbostic break; 16936725Sbostic } 17036725Sbostic case 'e': case 'E': case 'f': case 'g': case 'G': { 17150477Sbostic double p; 17250477Sbostic 17350477Sbostic p = getdouble(); 17436725Sbostic PF(start, p); 17536725Sbostic break; 17636725Sbostic } 17736725Sbostic default: 17850477Sbostic err("illegal format character.\n"); 17950477Sbostic return (1); 18036725Sbostic } 18136725Sbostic *fmt = nextch; 18236725Sbostic } 18336725Sbostic /* NOTREACHED */ 18436725Sbostic } 18536725Sbostic 18650477Sbostic static char * 18736725Sbostic mklong(str, ch) 18850477Sbostic char *str; 18950477Sbostic int ch; 19036725Sbostic { 19153564Smarc static char copy[64]; 19236725Sbostic int len; 19336725Sbostic 19436725Sbostic len = strlen(str) + 2; 19553564Smarc bcopy(str, copy, len - 3); 19653564Smarc copy[len - 3] = 'l'; 19753564Smarc copy[len - 2] = ch; 19853564Smarc copy[len - 1] = '\0'; 19936725Sbostic return(copy); 20036725Sbostic } 20136725Sbostic 20250477Sbostic static void 20336725Sbostic escape(fmt) 20436725Sbostic register char *fmt; 20536725Sbostic { 20636725Sbostic register char *store; 20736725Sbostic register int value, c; 20836725Sbostic 20936725Sbostic for (store = fmt; c = *fmt; ++fmt, ++store) { 21036725Sbostic if (c != '\\') { 21136725Sbostic *store = c; 21236725Sbostic continue; 21336725Sbostic } 21436725Sbostic switch (*++fmt) { 21536725Sbostic case '\0': /* EOS, user error */ 21636725Sbostic *store = '\\'; 21736725Sbostic *++store = '\0'; 21836725Sbostic return; 21936725Sbostic case '\\': /* backslash */ 22036728Sbostic case '\'': /* single quote */ 22136728Sbostic *store = *fmt; 22236725Sbostic break; 22336725Sbostic case 'a': /* bell/alert */ 22436725Sbostic *store = '\7'; 22536725Sbostic break; 22636725Sbostic case 'b': /* backspace */ 22736725Sbostic *store = '\b'; 22836725Sbostic break; 22936725Sbostic case 'f': /* form-feed */ 23036725Sbostic *store = '\f'; 23136725Sbostic break; 23236725Sbostic case 'n': /* newline */ 23336725Sbostic *store = '\n'; 23436725Sbostic break; 23536725Sbostic case 'r': /* carriage-return */ 23636725Sbostic *store = '\r'; 23736725Sbostic break; 23836725Sbostic case 't': /* horizontal tab */ 23936725Sbostic *store = '\t'; 24036725Sbostic break; 24136725Sbostic case 'v': /* vertical tab */ 24236725Sbostic *store = '\13'; 24336725Sbostic break; 24436725Sbostic /* octal constant */ 24536725Sbostic case '0': case '1': case '2': case '3': 24636725Sbostic case '4': case '5': case '6': case '7': 24736725Sbostic for (c = 3, value = 0; 24836725Sbostic c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) { 24936725Sbostic value <<= 3; 25036725Sbostic value += *fmt - '0'; 25136725Sbostic } 25236725Sbostic --fmt; 25336725Sbostic *store = value; 25436725Sbostic break; 25536725Sbostic default: 25636725Sbostic *store = *fmt; 25736725Sbostic break; 25836725Sbostic } 25936725Sbostic } 26036725Sbostic *store = '\0'; 26136725Sbostic } 26236725Sbostic 26350477Sbostic static int 26436725Sbostic getchr() 26536725Sbostic { 26636725Sbostic if (!*gargv) 26750477Sbostic return('\0'); 26836725Sbostic return((int)**gargv++); 26936725Sbostic } 27036725Sbostic 27150477Sbostic static char * 27236725Sbostic getstr() 27336725Sbostic { 27436725Sbostic if (!*gargv) 27536725Sbostic return(""); 27636725Sbostic return(*gargv++); 27736725Sbostic } 27836725Sbostic 27953564Smarc static char *Number = "+-.0123456789"; 28050477Sbostic static int 28136725Sbostic getint() 28236725Sbostic { 28336725Sbostic if (!*gargv) 28436725Sbostic return(0); 28553564Smarc if (index(Number, **gargv)) 28636725Sbostic return(atoi(*gargv++)); 28736725Sbostic return(asciicode()); 28836725Sbostic } 28936725Sbostic 29050477Sbostic static long 29136725Sbostic getlong() 29236725Sbostic { 29336725Sbostic if (!*gargv) 29436725Sbostic return((long)0); 29553564Smarc if (index(Number, **gargv)) 29640959Sbostic return(strtol(*gargv++, (char **)NULL, 0)); 29736725Sbostic return((long)asciicode()); 29836725Sbostic } 29936725Sbostic 30050477Sbostic static double 30136725Sbostic getdouble() 30236725Sbostic { 30336725Sbostic if (!*gargv) 30436725Sbostic return((double)0); 30553564Smarc if (index(Number, **gargv)) 30636725Sbostic return(atof(*gargv++)); 30736725Sbostic return((double)asciicode()); 30836725Sbostic } 30936725Sbostic 31050477Sbostic static int 31136725Sbostic asciicode() 31236725Sbostic { 31350477Sbostic register int ch; 31436725Sbostic 31536725Sbostic ch = **gargv; 31636725Sbostic if (ch == '\'' || ch == '"') 31736725Sbostic ch = (*gargv)[1]; 31836725Sbostic ++gargv; 31936725Sbostic return(ch); 32036725Sbostic } 32150477Sbostic 32253564Smarc #ifndef SHELL 32350477Sbostic #if __STDC__ 32450477Sbostic #include <stdarg.h> 32550477Sbostic #else 32650477Sbostic #include <varargs.h> 32750477Sbostic #endif 32850477Sbostic 32950477Sbostic static void 33050477Sbostic #if __STDC__ 33150477Sbostic err(const char *fmt, ...) 33250477Sbostic #else 33350477Sbostic err(fmt, va_alist) 33450477Sbostic char *fmt; 33550477Sbostic va_dcl 33650477Sbostic #endif 33750477Sbostic { 33850477Sbostic va_list ap; 33950477Sbostic #if __STDC__ 34050477Sbostic va_start(ap, fmt); 34150477Sbostic #else 34250477Sbostic va_start(ap); 34350477Sbostic #endif 34450477Sbostic (void)fprintf(stderr, "printf: "); 34550477Sbostic (void)vfprintf(stderr, fmt, ap); 34650477Sbostic va_end(ap); 34750477Sbostic (void)fprintf(stderr, "\n"); 34850477Sbostic } 34953564Smarc #endif /* !SHELL */ 350