136725Sbostic /* 236725Sbostic * Copyright (c) 1989 The Regents of the University of California. 336725Sbostic * All rights reserved. 436725Sbostic * 536725Sbostic * Redistribution and use in source and binary forms are permitted 636725Sbostic * provided that the above copyright notice and this paragraph are 736725Sbostic * duplicated in all such forms and that any documentation, 836725Sbostic * advertising materials, and other materials related to such 936725Sbostic * distribution and use acknowledge that the software was developed 1036725Sbostic * by the University of California, Berkeley. The name of the 1136725Sbostic * University may not be used to endorse or promote products derived 1236725Sbostic * from this software without specific prior written permission. 1336725Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1436725Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1536725Sbostic * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1636725Sbostic */ 1736725Sbostic 1836725Sbostic #ifndef lint 1936725Sbostic char copyright[] = 2036725Sbostic "@(#) Copyright (c) 1989 The Regents of the University of California.\n\ 2136725Sbostic All rights reserved.\n"; 2236725Sbostic #endif /* not lint */ 2336725Sbostic 2436725Sbostic #ifndef lint 25*36811Sbostic static char sccsid[] = "@(#)printf.c 5.4 (Berkeley) 02/16/89"; 2636725Sbostic #endif /* not lint */ 2736725Sbostic 2836725Sbostic #include <sys/types.h> 2936725Sbostic #include <stdio.h> 3036725Sbostic 3136725Sbostic #define PF(f, func) { \ 3236725Sbostic if (fieldwidth) \ 3336725Sbostic if (precision) \ 34*36811Sbostic (void)printf(f, fieldwidth, precision, func); \ 3536725Sbostic else \ 36*36811Sbostic (void)printf(f, fieldwidth, func); \ 3736725Sbostic else if (precision) \ 38*36811Sbostic (void)printf(f, precision, func); \ 3936725Sbostic else \ 40*36811Sbostic (void)printf(f, func); \ 4136725Sbostic } 4236725Sbostic 4336725Sbostic char **gargv; 4436725Sbostic 4536725Sbostic main(argc, argv) 4636725Sbostic int argc; 4736725Sbostic char **argv; 4836725Sbostic { 4936725Sbostic static char *skip1, *skip2; 5036725Sbostic register char *format, *fmt, *start; 51*36811Sbostic register int end, fieldwidth, precision; 5236725Sbostic char convch, nextch, *getstr(), *index(), *mklong(); 5336725Sbostic double getdouble(); 5436725Sbostic long getlong(); 5536725Sbostic 5636725Sbostic if (argc < 2) { 5736725Sbostic fprintf(stderr, "usage: printf format [arg ...]\n"); 58*36811Sbostic exit(1); 5936725Sbostic } 6036725Sbostic 6136725Sbostic /* 6236725Sbostic * Basic algorithm is to scan the format string for conversion 6336725Sbostic * specifications -- once one is found, find out if the field 6436725Sbostic * width or precision is a '*'; if it is, gather up value. Note, 6536725Sbostic * format strings are reused as necessary to use up the provided 6636725Sbostic * arguments, arguments of zero/null string are provided to use 6736725Sbostic * up the format string. 6836725Sbostic */ 6936725Sbostic skip1 = "#-+ 0"; 7036725Sbostic skip2 = "*0123456789"; 7136725Sbostic 7236725Sbostic escape(fmt = format = *++argv); /* backslash interpretation */ 7336725Sbostic gargv = ++argv; 74*36811Sbostic for (;;) { 7536725Sbostic end = 0; 7636725Sbostic /* find next format specification */ 7736725Sbostic next: for (start = fmt;; ++fmt) { 7836725Sbostic if (!*fmt) { 7936725Sbostic /* avoid infinite loop */ 8036725Sbostic if (end == 1) { 8136725Sbostic fprintf(stderr, 8236725Sbostic "printf: missing format character.\n"); 83*36811Sbostic exit(1); 8436725Sbostic } 8536725Sbostic end = 1; 8636725Sbostic if (fmt > start) 87*36811Sbostic (void)printf("%s", start); 8836725Sbostic if (!*gargv) 89*36811Sbostic exit(0); 9036725Sbostic fmt = format; 9136725Sbostic goto next; 9236725Sbostic } 9336725Sbostic /* %% prints a % */ 9436725Sbostic if (*fmt == '%' && *++fmt != '%') 9536725Sbostic break; 9636725Sbostic } 9736725Sbostic 9836725Sbostic /* skip to field width */ 9936725Sbostic for (; index(skip1, *fmt); ++fmt); 10036725Sbostic if (*fmt == '*') 10136725Sbostic fieldwidth = getint(); 10236725Sbostic /* skip to possible '.' */ 10336725Sbostic for (; index(skip2, *fmt); ++fmt); 10436725Sbostic if (*fmt == '.') 10536725Sbostic ++fmt; 10636725Sbostic if (*fmt == '*') 10736725Sbostic precision = getint(); 10836725Sbostic /* skip to conversion char */ 10936725Sbostic for (; index(skip2, *fmt); ++fmt); 11036725Sbostic if (!*fmt) { 11136725Sbostic fprintf(stderr, "printf: missing format character.\n"); 112*36811Sbostic exit(1); 11336725Sbostic } 11436725Sbostic 11536725Sbostic convch = *fmt; 11636725Sbostic nextch = *++fmt; 11736725Sbostic *fmt = '\0'; 11836725Sbostic switch(convch) { 11936725Sbostic case 'c': { 12036725Sbostic char p = getchr(); 12136725Sbostic PF(start, p); 12236725Sbostic break; 12336725Sbostic } 12436725Sbostic case 's': { 12536725Sbostic char *p = getstr(); 12636725Sbostic PF(start, p); 12736725Sbostic break; 12836725Sbostic } 12936729Sbostic case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': { 13036725Sbostic char *f = mklong(start, convch); 13136725Sbostic long p = getlong(); 13236725Sbostic PF(f, p); 13336725Sbostic break; 13436725Sbostic } 13536725Sbostic case 'e': case 'E': case 'f': case 'g': case 'G': { 13636725Sbostic double p = getdouble(); 13736725Sbostic PF(start, p); 13836725Sbostic break; 13936725Sbostic } 14036725Sbostic default: 14136725Sbostic fprintf(stderr, "printf: illegal format character.\n"); 142*36811Sbostic exit(1); 14336725Sbostic } 14436725Sbostic *fmt = nextch; 14536725Sbostic } 14636725Sbostic /* NOTREACHED */ 14736725Sbostic } 14836725Sbostic 14936725Sbostic char * 15036725Sbostic mklong(str, ch) 15136725Sbostic char *str, ch; 15236725Sbostic { 15336725Sbostic int len; 15436725Sbostic char *copy, *malloc(); 15536725Sbostic 15636725Sbostic len = strlen(str) + 2; 15736725Sbostic if (!(copy = malloc((u_int)len))) { /* never freed; XXX */ 15836725Sbostic fprintf(stderr, "printf: out of memory.\n"); 159*36811Sbostic exit(1); 16036725Sbostic } 16136725Sbostic bcopy(str, copy, len - 3); 16236725Sbostic copy[len - 3] = 'l'; 16336725Sbostic copy[len - 2] = ch; 16436725Sbostic copy[len - 1] = '\0'; 16536725Sbostic return(copy); 16636725Sbostic } 16736725Sbostic 16836725Sbostic escape(fmt) 16936725Sbostic register char *fmt; 17036725Sbostic { 17136725Sbostic register char *store; 17236725Sbostic register int value, c; 17336725Sbostic 17436725Sbostic for (store = fmt; c = *fmt; ++fmt, ++store) { 17536725Sbostic if (c != '\\') { 17636725Sbostic *store = c; 17736725Sbostic continue; 17836725Sbostic } 17936725Sbostic switch (*++fmt) { 18036725Sbostic case '\0': /* EOS, user error */ 18136725Sbostic *store = '\\'; 18236725Sbostic *++store = '\0'; 18336725Sbostic return; 18436725Sbostic case '\\': /* backslash */ 18536728Sbostic case '\'': /* single quote */ 18636728Sbostic *store = *fmt; 18736725Sbostic break; 18836725Sbostic case 'a': /* bell/alert */ 18936725Sbostic *store = '\7'; 19036725Sbostic break; 19136725Sbostic case 'b': /* backspace */ 19236725Sbostic *store = '\b'; 19336725Sbostic break; 19436725Sbostic case 'f': /* form-feed */ 19536725Sbostic *store = '\f'; 19636725Sbostic break; 19736725Sbostic case 'n': /* newline */ 19836725Sbostic *store = '\n'; 19936725Sbostic break; 20036725Sbostic case 'r': /* carriage-return */ 20136725Sbostic *store = '\r'; 20236725Sbostic break; 20336725Sbostic case 't': /* horizontal tab */ 20436725Sbostic *store = '\t'; 20536725Sbostic break; 20636725Sbostic case 'v': /* vertical tab */ 20736725Sbostic *store = '\13'; 20836725Sbostic break; 20936725Sbostic /* octal constant */ 21036725Sbostic case '0': case '1': case '2': case '3': 21136725Sbostic case '4': case '5': case '6': case '7': 21236725Sbostic for (c = 3, value = 0; 21336725Sbostic c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) { 21436725Sbostic value <<= 3; 21536725Sbostic value += *fmt - '0'; 21636725Sbostic } 21736725Sbostic --fmt; 21836725Sbostic *store = value; 21936725Sbostic break; 22036725Sbostic default: 22136725Sbostic *store = *fmt; 22236725Sbostic break; 22336725Sbostic } 22436725Sbostic } 22536725Sbostic *store = '\0'; 22636725Sbostic } 22736725Sbostic 22836725Sbostic getchr() 22936725Sbostic { 23036725Sbostic if (!*gargv) 23136725Sbostic return((int)'\0'); 23236725Sbostic return((int)**gargv++); 23336725Sbostic } 23436725Sbostic 23536725Sbostic char * 23636725Sbostic getstr() 23736725Sbostic { 23836725Sbostic if (!*gargv) 23936725Sbostic return(""); 24036725Sbostic return(*gargv++); 24136725Sbostic } 24236725Sbostic 24336725Sbostic static char *number = "+-0123456789"; 24436725Sbostic getint() 24536725Sbostic { 24636725Sbostic if (!*gargv) 24736725Sbostic return(0); 24836725Sbostic if (index(number, **gargv)) 24936725Sbostic return(atoi(*gargv++)); 25036725Sbostic return(asciicode()); 25136725Sbostic } 25236725Sbostic 25336725Sbostic long 25436725Sbostic getlong() 25536725Sbostic { 25636725Sbostic long atol(); 25736725Sbostic 25836725Sbostic if (!*gargv) 25936725Sbostic return((long)0); 26036725Sbostic if (index(number, **gargv)) 26136725Sbostic return(atol(*gargv++)); 26236725Sbostic return((long)asciicode()); 26336725Sbostic } 26436725Sbostic 26536725Sbostic double 26636725Sbostic getdouble() 26736725Sbostic { 26836725Sbostic double atof(); 26936725Sbostic 27036725Sbostic if (!*gargv) 27136725Sbostic return((double)0); 27236725Sbostic if (index(number, **gargv)) 27336725Sbostic return(atof(*gargv++)); 27436725Sbostic return((double)asciicode()); 27536725Sbostic } 27636725Sbostic 27736725Sbostic asciicode() 27836725Sbostic { 27936725Sbostic register char ch; 28036725Sbostic 28136725Sbostic ch = **gargv; 28236725Sbostic if (ch == '\'' || ch == '"') 28336725Sbostic ch = (*gargv)[1]; 28436725Sbostic ++gargv; 28536725Sbostic return(ch); 28636725Sbostic } 287