136725Sbostic /* 236725Sbostic * Copyright (c) 1989 The Regents of the University of California. 336725Sbostic * All rights reserved. 436725Sbostic * 5*42758Sbostic * %sccs.include.redist.c% 636725Sbostic */ 736725Sbostic 836725Sbostic #ifndef lint 936725Sbostic char copyright[] = 1036725Sbostic "@(#) Copyright (c) 1989 The Regents of the University of California.\n\ 1136725Sbostic All rights reserved.\n"; 1236725Sbostic #endif /* not lint */ 1336725Sbostic 1436725Sbostic #ifndef lint 15*42758Sbostic static char sccsid[] = "@(#)printf.c 5.9 (Berkeley) 06/01/90"; 1636725Sbostic #endif /* not lint */ 1736725Sbostic 1836725Sbostic #include <sys/types.h> 1936725Sbostic #include <stdio.h> 2036725Sbostic 2136725Sbostic #define PF(f, func) { \ 2236725Sbostic if (fieldwidth) \ 2336725Sbostic if (precision) \ 2436811Sbostic (void)printf(f, fieldwidth, precision, func); \ 2536725Sbostic else \ 2636811Sbostic (void)printf(f, fieldwidth, func); \ 2736725Sbostic else if (precision) \ 2836811Sbostic (void)printf(f, precision, func); \ 2936725Sbostic else \ 3036811Sbostic (void)printf(f, func); \ 3136725Sbostic } 3236725Sbostic 3336725Sbostic char **gargv; 3436725Sbostic 3536725Sbostic main(argc, argv) 3636725Sbostic int argc; 3736725Sbostic char **argv; 3836725Sbostic { 3936725Sbostic static char *skip1, *skip2; 4036725Sbostic register char *format, *fmt, *start; 4136811Sbostic register int end, fieldwidth, precision; 4236725Sbostic char convch, nextch, *getstr(), *index(), *mklong(); 4336725Sbostic double getdouble(); 4436725Sbostic long getlong(); 4536725Sbostic 4636725Sbostic if (argc < 2) { 4736725Sbostic fprintf(stderr, "usage: printf format [arg ...]\n"); 4836811Sbostic exit(1); 4936725Sbostic } 5036725Sbostic 5136725Sbostic /* 5236725Sbostic * Basic algorithm is to scan the format string for conversion 5336725Sbostic * specifications -- once one is found, find out if the field 5436725Sbostic * width or precision is a '*'; if it is, gather up value. Note, 5536725Sbostic * format strings are reused as necessary to use up the provided 5636725Sbostic * arguments, arguments of zero/null string are provided to use 5736725Sbostic * up the format string. 5836725Sbostic */ 5936725Sbostic skip1 = "#-+ 0"; 6036725Sbostic skip2 = "*0123456789"; 6136725Sbostic 6236725Sbostic escape(fmt = format = *++argv); /* backslash interpretation */ 6336725Sbostic gargv = ++argv; 6436811Sbostic for (;;) { 6536725Sbostic end = 0; 6636725Sbostic /* find next format specification */ 6736725Sbostic next: for (start = fmt;; ++fmt) { 6836725Sbostic if (!*fmt) { 6936725Sbostic /* avoid infinite loop */ 7036725Sbostic if (end == 1) { 7136725Sbostic fprintf(stderr, 7236725Sbostic "printf: missing format character.\n"); 7336811Sbostic exit(1); 7436725Sbostic } 7536725Sbostic end = 1; 7636725Sbostic if (fmt > start) 7736811Sbostic (void)printf("%s", start); 7836725Sbostic if (!*gargv) 7936811Sbostic exit(0); 8036725Sbostic fmt = format; 8136725Sbostic goto next; 8236725Sbostic } 8336725Sbostic /* %% prints a % */ 8438480Sbostic if (*fmt == '%') { 8538480Sbostic if (*++fmt != '%') 8638480Sbostic break; 8738480Sbostic *fmt++ = '\0'; 8838480Sbostic (void)printf("%s", start); 8938480Sbostic goto next; 9038480Sbostic } 9136725Sbostic } 9236725Sbostic 9336725Sbostic /* skip to field width */ 9436725Sbostic for (; index(skip1, *fmt); ++fmt); 9536879Sbostic fieldwidth = *fmt == '*' ? getint() : 0; 9636879Sbostic 9736879Sbostic /* skip to possible '.', get following precision */ 9836725Sbostic for (; index(skip2, *fmt); ++fmt); 9936725Sbostic if (*fmt == '.') 10036725Sbostic ++fmt; 10136879Sbostic precision = *fmt == '*' ? getint() : 0; 10236879Sbostic 10336725Sbostic /* skip to conversion char */ 10436725Sbostic for (; index(skip2, *fmt); ++fmt); 10536725Sbostic if (!*fmt) { 10636725Sbostic fprintf(stderr, "printf: missing format character.\n"); 10736811Sbostic exit(1); 10836725Sbostic } 10936725Sbostic 11036725Sbostic convch = *fmt; 11136725Sbostic nextch = *++fmt; 11236725Sbostic *fmt = '\0'; 11336725Sbostic switch(convch) { 11436725Sbostic case 'c': { 11536725Sbostic char p = getchr(); 11636725Sbostic PF(start, p); 11736725Sbostic break; 11836725Sbostic } 11936725Sbostic case 's': { 12036725Sbostic char *p = getstr(); 12136725Sbostic PF(start, p); 12236725Sbostic break; 12336725Sbostic } 12436729Sbostic case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': { 12536725Sbostic char *f = mklong(start, convch); 12636725Sbostic long p = getlong(); 12736725Sbostic PF(f, p); 12836725Sbostic break; 12936725Sbostic } 13036725Sbostic case 'e': case 'E': case 'f': case 'g': case 'G': { 13136725Sbostic double p = getdouble(); 13236725Sbostic PF(start, p); 13336725Sbostic break; 13436725Sbostic } 13536725Sbostic default: 13636725Sbostic fprintf(stderr, "printf: illegal format character.\n"); 13736811Sbostic exit(1); 13836725Sbostic } 13936725Sbostic *fmt = nextch; 14036725Sbostic } 14136725Sbostic /* NOTREACHED */ 14236725Sbostic } 14336725Sbostic 14436725Sbostic char * 14536725Sbostic mklong(str, ch) 14636725Sbostic char *str, ch; 14736725Sbostic { 14836725Sbostic int len; 14936725Sbostic char *copy, *malloc(); 15036725Sbostic 15136725Sbostic len = strlen(str) + 2; 15236725Sbostic if (!(copy = malloc((u_int)len))) { /* never freed; XXX */ 15336725Sbostic fprintf(stderr, "printf: out of memory.\n"); 15436811Sbostic exit(1); 15536725Sbostic } 15636725Sbostic bcopy(str, copy, len - 3); 15736725Sbostic copy[len - 3] = 'l'; 15836725Sbostic copy[len - 2] = ch; 15936725Sbostic copy[len - 1] = '\0'; 16036725Sbostic return(copy); 16136725Sbostic } 16236725Sbostic 16336725Sbostic escape(fmt) 16436725Sbostic register char *fmt; 16536725Sbostic { 16636725Sbostic register char *store; 16736725Sbostic register int value, c; 16836725Sbostic 16936725Sbostic for (store = fmt; c = *fmt; ++fmt, ++store) { 17036725Sbostic if (c != '\\') { 17136725Sbostic *store = c; 17236725Sbostic continue; 17336725Sbostic } 17436725Sbostic switch (*++fmt) { 17536725Sbostic case '\0': /* EOS, user error */ 17636725Sbostic *store = '\\'; 17736725Sbostic *++store = '\0'; 17836725Sbostic return; 17936725Sbostic case '\\': /* backslash */ 18036728Sbostic case '\'': /* single quote */ 18136728Sbostic *store = *fmt; 18236725Sbostic break; 18336725Sbostic case 'a': /* bell/alert */ 18436725Sbostic *store = '\7'; 18536725Sbostic break; 18636725Sbostic case 'b': /* backspace */ 18736725Sbostic *store = '\b'; 18836725Sbostic break; 18936725Sbostic case 'f': /* form-feed */ 19036725Sbostic *store = '\f'; 19136725Sbostic break; 19236725Sbostic case 'n': /* newline */ 19336725Sbostic *store = '\n'; 19436725Sbostic break; 19536725Sbostic case 'r': /* carriage-return */ 19636725Sbostic *store = '\r'; 19736725Sbostic break; 19836725Sbostic case 't': /* horizontal tab */ 19936725Sbostic *store = '\t'; 20036725Sbostic break; 20136725Sbostic case 'v': /* vertical tab */ 20236725Sbostic *store = '\13'; 20336725Sbostic break; 20436725Sbostic /* octal constant */ 20536725Sbostic case '0': case '1': case '2': case '3': 20636725Sbostic case '4': case '5': case '6': case '7': 20736725Sbostic for (c = 3, value = 0; 20836725Sbostic c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) { 20936725Sbostic value <<= 3; 21036725Sbostic value += *fmt - '0'; 21136725Sbostic } 21236725Sbostic --fmt; 21336725Sbostic *store = value; 21436725Sbostic break; 21536725Sbostic default: 21636725Sbostic *store = *fmt; 21736725Sbostic break; 21836725Sbostic } 21936725Sbostic } 22036725Sbostic *store = '\0'; 22136725Sbostic } 22236725Sbostic 22336725Sbostic getchr() 22436725Sbostic { 22536725Sbostic if (!*gargv) 22636725Sbostic return((int)'\0'); 22736725Sbostic return((int)**gargv++); 22836725Sbostic } 22936725Sbostic 23036725Sbostic char * 23136725Sbostic getstr() 23236725Sbostic { 23336725Sbostic if (!*gargv) 23436725Sbostic return(""); 23536725Sbostic return(*gargv++); 23636725Sbostic } 23736725Sbostic 23838481Sbostic static char *number = "+-.0123456789"; 23936725Sbostic getint() 24036725Sbostic { 24136725Sbostic if (!*gargv) 24236725Sbostic return(0); 24336725Sbostic if (index(number, **gargv)) 24436725Sbostic return(atoi(*gargv++)); 24536725Sbostic return(asciicode()); 24636725Sbostic } 24736725Sbostic 24836725Sbostic long 24936725Sbostic getlong() 25036725Sbostic { 25136725Sbostic long atol(); 25236725Sbostic 25336725Sbostic if (!*gargv) 25436725Sbostic return((long)0); 25536725Sbostic if (index(number, **gargv)) 25640959Sbostic return(strtol(*gargv++, (char **)NULL, 0)); 25736725Sbostic return((long)asciicode()); 25836725Sbostic } 25936725Sbostic 26036725Sbostic double 26136725Sbostic getdouble() 26236725Sbostic { 26336725Sbostic double atof(); 26436725Sbostic 26536725Sbostic if (!*gargv) 26636725Sbostic return((double)0); 26736725Sbostic if (index(number, **gargv)) 26836725Sbostic return(atof(*gargv++)); 26936725Sbostic return((double)asciicode()); 27036725Sbostic } 27136725Sbostic 27236725Sbostic asciicode() 27336725Sbostic { 27436725Sbostic register char ch; 27536725Sbostic 27636725Sbostic ch = **gargv; 27736725Sbostic if (ch == '\'' || ch == '"') 27836725Sbostic ch = (*gargv)[1]; 27936725Sbostic ++gargv; 28036725Sbostic return(ch); 28136725Sbostic } 282