136725Sbostic /* 236725Sbostic * Copyright (c) 1989 The Regents of the University of California. 336725Sbostic * All rights reserved. 436725Sbostic * 542758Sbostic * %sccs.include.redist.c% 636725Sbostic */ 736725Sbostic 8*53564Smarc #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*53564Smarc static char sccsid[] = "@(#)printf.c 5.11 (Berkeley) 05/14/92"; 1836725Sbostic #endif /* not lint */ 1936725Sbostic 20*53564Smarc 2136725Sbostic #include <sys/types.h> 2250477Sbostic #include <errno.h> 23*53564Smarc #ifndef SHELL 2436725Sbostic #include <stdio.h> 25*53564Smarc #endif 2650477Sbostic #include <stdlib.h> 2750477Sbostic #include <string.h> 2836725Sbostic 29*53564Smarc #ifdef SHELL 30*53564Smarc #define main printfcmd 31*53564Smarc #define err error 32*53564Smarc #include "/usr/src/devel/sh/bltin/bltin.h" 33*53564Smarc #endif 34*53564Smarc 3536725Sbostic #define PF(f, func) { \ 3636725Sbostic if (fieldwidth) \ 3736725Sbostic if (precision) \ 3836811Sbostic (void)printf(f, fieldwidth, precision, func); \ 3936725Sbostic else \ 4036811Sbostic (void)printf(f, fieldwidth, func); \ 4136725Sbostic else if (precision) \ 4236811Sbostic (void)printf(f, precision, func); \ 4336725Sbostic else \ 4436811Sbostic (void)printf(f, func); \ 4536725Sbostic } 4636725Sbostic 4750477Sbostic static int asciicode __P((void)); 48*53564Smarc #ifndef SHELL 4950477Sbostic static void err __P((const char *fmt, ...)); 50*53564Smarc #endif 5150477Sbostic static void escape __P((char *)); 5250477Sbostic static int getchr __P((void)); 5350477Sbostic static double getdouble __P((void)); 5450477Sbostic static int getint __P((void)); 5550477Sbostic static long getlong __P((void)); 5650477Sbostic static char *getstr __P((void)); 5750477Sbostic static char *mklong __P((char *, int)); 5836725Sbostic 5950477Sbostic static char **gargv; 6050477Sbostic 6150477Sbostic int 6250477Sbostic #ifdef BUILTIN 6350477Sbostic progprintf(argc, argv) 6450477Sbostic #else 6536725Sbostic main(argc, argv) 6650477Sbostic #endif 6736725Sbostic int argc; 6836725Sbostic char **argv; 6936725Sbostic { 7036725Sbostic static char *skip1, *skip2; 7136725Sbostic register char *format, *fmt, *start; 7236811Sbostic register int end, fieldwidth, precision; 7350477Sbostic char convch, nextch; 7436725Sbostic 7536725Sbostic if (argc < 2) { 7650477Sbostic (void)fprintf(stderr, "usage: printf format [arg ...]\n"); 7750477Sbostic return (1); 7836725Sbostic } 7936725Sbostic 8036725Sbostic /* 8136725Sbostic * Basic algorithm is to scan the format string for conversion 8236725Sbostic * specifications -- once one is found, find out if the field 8336725Sbostic * width or precision is a '*'; if it is, gather up value. Note, 8436725Sbostic * format strings are reused as necessary to use up the provided 8536725Sbostic * arguments, arguments of zero/null string are provided to use 8636725Sbostic * up the format string. 8736725Sbostic */ 8836725Sbostic skip1 = "#-+ 0"; 8936725Sbostic skip2 = "*0123456789"; 9036725Sbostic 9136725Sbostic escape(fmt = format = *++argv); /* backslash interpretation */ 9236725Sbostic gargv = ++argv; 9336811Sbostic for (;;) { 9436725Sbostic end = 0; 9536725Sbostic /* find next format specification */ 9636725Sbostic next: for (start = fmt;; ++fmt) { 9736725Sbostic if (!*fmt) { 9836725Sbostic /* avoid infinite loop */ 9936725Sbostic if (end == 1) { 10050477Sbostic err("missing format character"); 10150477Sbostic return (1); 10236725Sbostic } 10336725Sbostic end = 1; 10436725Sbostic if (fmt > start) 10536811Sbostic (void)printf("%s", start); 10636725Sbostic if (!*gargv) 10750477Sbostic return (0); 10836725Sbostic fmt = format; 10936725Sbostic goto next; 11036725Sbostic } 11136725Sbostic /* %% prints a % */ 11238480Sbostic if (*fmt == '%') { 11338480Sbostic if (*++fmt != '%') 11438480Sbostic break; 11538480Sbostic *fmt++ = '\0'; 11638480Sbostic (void)printf("%s", start); 11738480Sbostic goto next; 11838480Sbostic } 11936725Sbostic } 12036725Sbostic 12136725Sbostic /* skip to field width */ 12236725Sbostic for (; index(skip1, *fmt); ++fmt); 12336879Sbostic fieldwidth = *fmt == '*' ? getint() : 0; 12436879Sbostic 12536879Sbostic /* skip to possible '.', get following precision */ 12636725Sbostic for (; index(skip2, *fmt); ++fmt); 12736725Sbostic if (*fmt == '.') 12836725Sbostic ++fmt; 12936879Sbostic precision = *fmt == '*' ? getint() : 0; 13036879Sbostic 13136725Sbostic /* skip to conversion char */ 13236725Sbostic for (; index(skip2, *fmt); ++fmt); 13336725Sbostic if (!*fmt) { 13450477Sbostic err("missing format character"); 13550477Sbostic return (1); 13636725Sbostic } 13736725Sbostic 13836725Sbostic convch = *fmt; 13936725Sbostic nextch = *++fmt; 14036725Sbostic *fmt = '\0'; 14136725Sbostic switch(convch) { 14236725Sbostic case 'c': { 14350477Sbostic char p; 14450477Sbostic 14550477Sbostic p = getchr(); 14636725Sbostic PF(start, p); 14736725Sbostic break; 14836725Sbostic } 14936725Sbostic case 's': { 15050477Sbostic char *p; 15150477Sbostic 15250477Sbostic p = getstr(); 15336725Sbostic PF(start, p); 15436725Sbostic break; 15536725Sbostic } 15636729Sbostic case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': { 15750477Sbostic long p; 15850477Sbostic char *f; 15950477Sbostic 16050477Sbostic if ((f = mklong(start, convch)) == NULL) 16150477Sbostic return (1); 16250477Sbostic p = getlong(); 16336725Sbostic PF(f, p); 16436725Sbostic break; 16536725Sbostic } 16636725Sbostic case 'e': case 'E': case 'f': case 'g': case 'G': { 16750477Sbostic double p; 16850477Sbostic 16950477Sbostic p = getdouble(); 17036725Sbostic PF(start, p); 17136725Sbostic break; 17236725Sbostic } 17336725Sbostic default: 17450477Sbostic err("illegal format character.\n"); 17550477Sbostic return (1); 17636725Sbostic } 17736725Sbostic *fmt = nextch; 17836725Sbostic } 17936725Sbostic /* NOTREACHED */ 18036725Sbostic } 18136725Sbostic 18250477Sbostic static char * 18336725Sbostic mklong(str, ch) 18450477Sbostic char *str; 18550477Sbostic int ch; 18636725Sbostic { 187*53564Smarc static char copy[64]; 18836725Sbostic int len; 18936725Sbostic 19036725Sbostic len = strlen(str) + 2; 191*53564Smarc bcopy(str, copy, len - 3); 192*53564Smarc copy[len - 3] = 'l'; 193*53564Smarc copy[len - 2] = ch; 194*53564Smarc copy[len - 1] = '\0'; 19536725Sbostic return(copy); 19636725Sbostic } 19736725Sbostic 19850477Sbostic static void 19936725Sbostic escape(fmt) 20036725Sbostic register char *fmt; 20136725Sbostic { 20236725Sbostic register char *store; 20336725Sbostic register int value, c; 20436725Sbostic 20536725Sbostic for (store = fmt; c = *fmt; ++fmt, ++store) { 20636725Sbostic if (c != '\\') { 20736725Sbostic *store = c; 20836725Sbostic continue; 20936725Sbostic } 21036725Sbostic switch (*++fmt) { 21136725Sbostic case '\0': /* EOS, user error */ 21236725Sbostic *store = '\\'; 21336725Sbostic *++store = '\0'; 21436725Sbostic return; 21536725Sbostic case '\\': /* backslash */ 21636728Sbostic case '\'': /* single quote */ 21736728Sbostic *store = *fmt; 21836725Sbostic break; 21936725Sbostic case 'a': /* bell/alert */ 22036725Sbostic *store = '\7'; 22136725Sbostic break; 22236725Sbostic case 'b': /* backspace */ 22336725Sbostic *store = '\b'; 22436725Sbostic break; 22536725Sbostic case 'f': /* form-feed */ 22636725Sbostic *store = '\f'; 22736725Sbostic break; 22836725Sbostic case 'n': /* newline */ 22936725Sbostic *store = '\n'; 23036725Sbostic break; 23136725Sbostic case 'r': /* carriage-return */ 23236725Sbostic *store = '\r'; 23336725Sbostic break; 23436725Sbostic case 't': /* horizontal tab */ 23536725Sbostic *store = '\t'; 23636725Sbostic break; 23736725Sbostic case 'v': /* vertical tab */ 23836725Sbostic *store = '\13'; 23936725Sbostic break; 24036725Sbostic /* octal constant */ 24136725Sbostic case '0': case '1': case '2': case '3': 24236725Sbostic case '4': case '5': case '6': case '7': 24336725Sbostic for (c = 3, value = 0; 24436725Sbostic c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) { 24536725Sbostic value <<= 3; 24636725Sbostic value += *fmt - '0'; 24736725Sbostic } 24836725Sbostic --fmt; 24936725Sbostic *store = value; 25036725Sbostic break; 25136725Sbostic default: 25236725Sbostic *store = *fmt; 25336725Sbostic break; 25436725Sbostic } 25536725Sbostic } 25636725Sbostic *store = '\0'; 25736725Sbostic } 25836725Sbostic 25950477Sbostic static int 26036725Sbostic getchr() 26136725Sbostic { 26236725Sbostic if (!*gargv) 26350477Sbostic return('\0'); 26436725Sbostic return((int)**gargv++); 26536725Sbostic } 26636725Sbostic 26750477Sbostic static char * 26836725Sbostic getstr() 26936725Sbostic { 27036725Sbostic if (!*gargv) 27136725Sbostic return(""); 27236725Sbostic return(*gargv++); 27336725Sbostic } 27436725Sbostic 275*53564Smarc static char *Number = "+-.0123456789"; 27650477Sbostic static int 27736725Sbostic getint() 27836725Sbostic { 27936725Sbostic if (!*gargv) 28036725Sbostic return(0); 281*53564Smarc if (index(Number, **gargv)) 28236725Sbostic return(atoi(*gargv++)); 28336725Sbostic return(asciicode()); 28436725Sbostic } 28536725Sbostic 28650477Sbostic static long 28736725Sbostic getlong() 28836725Sbostic { 28936725Sbostic if (!*gargv) 29036725Sbostic return((long)0); 291*53564Smarc if (index(Number, **gargv)) 29240959Sbostic return(strtol(*gargv++, (char **)NULL, 0)); 29336725Sbostic return((long)asciicode()); 29436725Sbostic } 29536725Sbostic 29650477Sbostic static double 29736725Sbostic getdouble() 29836725Sbostic { 29936725Sbostic if (!*gargv) 30036725Sbostic return((double)0); 301*53564Smarc if (index(Number, **gargv)) 30236725Sbostic return(atof(*gargv++)); 30336725Sbostic return((double)asciicode()); 30436725Sbostic } 30536725Sbostic 30650477Sbostic static int 30736725Sbostic asciicode() 30836725Sbostic { 30950477Sbostic register int ch; 31036725Sbostic 31136725Sbostic ch = **gargv; 31236725Sbostic if (ch == '\'' || ch == '"') 31336725Sbostic ch = (*gargv)[1]; 31436725Sbostic ++gargv; 31536725Sbostic return(ch); 31636725Sbostic } 31750477Sbostic 318*53564Smarc #ifndef SHELL 31950477Sbostic #if __STDC__ 32050477Sbostic #include <stdarg.h> 32150477Sbostic #else 32250477Sbostic #include <varargs.h> 32350477Sbostic #endif 32450477Sbostic 32550477Sbostic static void 32650477Sbostic #if __STDC__ 32750477Sbostic err(const char *fmt, ...) 32850477Sbostic #else 32950477Sbostic err(fmt, va_alist) 33050477Sbostic char *fmt; 33150477Sbostic va_dcl 33250477Sbostic #endif 33350477Sbostic { 33450477Sbostic va_list ap; 33550477Sbostic #if __STDC__ 33650477Sbostic va_start(ap, fmt); 33750477Sbostic #else 33850477Sbostic va_start(ap); 33950477Sbostic #endif 34050477Sbostic (void)fprintf(stderr, "printf: "); 34150477Sbostic (void)vfprintf(stderr, fmt, ap); 34250477Sbostic va_end(ap); 34350477Sbostic (void)fprintf(stderr, "\n"); 34450477Sbostic } 345*53564Smarc #endif /* !SHELL */ 346