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*38480Sbostic static char sccsid[] = "@(#)printf.c 5.6 (Berkeley) 07/20/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) \ 3436811Sbostic (void)printf(f, fieldwidth, precision, func); \ 3536725Sbostic else \ 3636811Sbostic (void)printf(f, fieldwidth, func); \ 3736725Sbostic else if (precision) \ 3836811Sbostic (void)printf(f, precision, func); \ 3936725Sbostic else \ 4036811Sbostic (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; 5136811Sbostic 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"); 5836811Sbostic 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; 7436811Sbostic 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"); 8336811Sbostic exit(1); 8436725Sbostic } 8536725Sbostic end = 1; 8636725Sbostic if (fmt > start) 8736811Sbostic (void)printf("%s", start); 8836725Sbostic if (!*gargv) 8936811Sbostic exit(0); 9036725Sbostic fmt = format; 9136725Sbostic goto next; 9236725Sbostic } 9336725Sbostic /* %% prints a % */ 94*38480Sbostic if (*fmt == '%') { 95*38480Sbostic if (*++fmt != '%') 96*38480Sbostic break; 97*38480Sbostic *fmt++ = '\0'; 98*38480Sbostic (void)printf("%s", start); 99*38480Sbostic goto next; 100*38480Sbostic } 10136725Sbostic } 10236725Sbostic 10336725Sbostic /* skip to field width */ 10436725Sbostic for (; index(skip1, *fmt); ++fmt); 10536879Sbostic fieldwidth = *fmt == '*' ? getint() : 0; 10636879Sbostic 10736879Sbostic /* skip to possible '.', get following precision */ 10836725Sbostic for (; index(skip2, *fmt); ++fmt); 10936725Sbostic if (*fmt == '.') 11036725Sbostic ++fmt; 11136879Sbostic precision = *fmt == '*' ? getint() : 0; 11236879Sbostic 11336725Sbostic /* skip to conversion char */ 11436725Sbostic for (; index(skip2, *fmt); ++fmt); 11536725Sbostic if (!*fmt) { 11636725Sbostic fprintf(stderr, "printf: missing format character.\n"); 11736811Sbostic exit(1); 11836725Sbostic } 11936725Sbostic 12036725Sbostic convch = *fmt; 12136725Sbostic nextch = *++fmt; 12236725Sbostic *fmt = '\0'; 12336725Sbostic switch(convch) { 12436725Sbostic case 'c': { 12536725Sbostic char p = getchr(); 12636725Sbostic PF(start, p); 12736725Sbostic break; 12836725Sbostic } 12936725Sbostic case 's': { 13036725Sbostic char *p = getstr(); 13136725Sbostic PF(start, p); 13236725Sbostic break; 13336725Sbostic } 13436729Sbostic case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': { 13536725Sbostic char *f = mklong(start, convch); 13636725Sbostic long p = getlong(); 13736725Sbostic PF(f, p); 13836725Sbostic break; 13936725Sbostic } 14036725Sbostic case 'e': case 'E': case 'f': case 'g': case 'G': { 14136725Sbostic double p = getdouble(); 14236725Sbostic PF(start, p); 14336725Sbostic break; 14436725Sbostic } 14536725Sbostic default: 14636725Sbostic fprintf(stderr, "printf: illegal format character.\n"); 14736811Sbostic exit(1); 14836725Sbostic } 14936725Sbostic *fmt = nextch; 15036725Sbostic } 15136725Sbostic /* NOTREACHED */ 15236725Sbostic } 15336725Sbostic 15436725Sbostic char * 15536725Sbostic mklong(str, ch) 15636725Sbostic char *str, ch; 15736725Sbostic { 15836725Sbostic int len; 15936725Sbostic char *copy, *malloc(); 16036725Sbostic 16136725Sbostic len = strlen(str) + 2; 16236725Sbostic if (!(copy = malloc((u_int)len))) { /* never freed; XXX */ 16336725Sbostic fprintf(stderr, "printf: out of memory.\n"); 16436811Sbostic exit(1); 16536725Sbostic } 16636725Sbostic bcopy(str, copy, len - 3); 16736725Sbostic copy[len - 3] = 'l'; 16836725Sbostic copy[len - 2] = ch; 16936725Sbostic copy[len - 1] = '\0'; 17036725Sbostic return(copy); 17136725Sbostic } 17236725Sbostic 17336725Sbostic escape(fmt) 17436725Sbostic register char *fmt; 17536725Sbostic { 17636725Sbostic register char *store; 17736725Sbostic register int value, c; 17836725Sbostic 17936725Sbostic for (store = fmt; c = *fmt; ++fmt, ++store) { 18036725Sbostic if (c != '\\') { 18136725Sbostic *store = c; 18236725Sbostic continue; 18336725Sbostic } 18436725Sbostic switch (*++fmt) { 18536725Sbostic case '\0': /* EOS, user error */ 18636725Sbostic *store = '\\'; 18736725Sbostic *++store = '\0'; 18836725Sbostic return; 18936725Sbostic case '\\': /* backslash */ 19036728Sbostic case '\'': /* single quote */ 19136728Sbostic *store = *fmt; 19236725Sbostic break; 19336725Sbostic case 'a': /* bell/alert */ 19436725Sbostic *store = '\7'; 19536725Sbostic break; 19636725Sbostic case 'b': /* backspace */ 19736725Sbostic *store = '\b'; 19836725Sbostic break; 19936725Sbostic case 'f': /* form-feed */ 20036725Sbostic *store = '\f'; 20136725Sbostic break; 20236725Sbostic case 'n': /* newline */ 20336725Sbostic *store = '\n'; 20436725Sbostic break; 20536725Sbostic case 'r': /* carriage-return */ 20636725Sbostic *store = '\r'; 20736725Sbostic break; 20836725Sbostic case 't': /* horizontal tab */ 20936725Sbostic *store = '\t'; 21036725Sbostic break; 21136725Sbostic case 'v': /* vertical tab */ 21236725Sbostic *store = '\13'; 21336725Sbostic break; 21436725Sbostic /* octal constant */ 21536725Sbostic case '0': case '1': case '2': case '3': 21636725Sbostic case '4': case '5': case '6': case '7': 21736725Sbostic for (c = 3, value = 0; 21836725Sbostic c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) { 21936725Sbostic value <<= 3; 22036725Sbostic value += *fmt - '0'; 22136725Sbostic } 22236725Sbostic --fmt; 22336725Sbostic *store = value; 22436725Sbostic break; 22536725Sbostic default: 22636725Sbostic *store = *fmt; 22736725Sbostic break; 22836725Sbostic } 22936725Sbostic } 23036725Sbostic *store = '\0'; 23136725Sbostic } 23236725Sbostic 23336725Sbostic getchr() 23436725Sbostic { 23536725Sbostic if (!*gargv) 23636725Sbostic return((int)'\0'); 23736725Sbostic return((int)**gargv++); 23836725Sbostic } 23936725Sbostic 24036725Sbostic char * 24136725Sbostic getstr() 24236725Sbostic { 24336725Sbostic if (!*gargv) 24436725Sbostic return(""); 24536725Sbostic return(*gargv++); 24636725Sbostic } 24736725Sbostic 24836725Sbostic static char *number = "+-0123456789"; 24936725Sbostic getint() 25036725Sbostic { 25136725Sbostic if (!*gargv) 25236725Sbostic return(0); 25336725Sbostic if (index(number, **gargv)) 25436725Sbostic return(atoi(*gargv++)); 25536725Sbostic return(asciicode()); 25636725Sbostic } 25736725Sbostic 25836725Sbostic long 25936725Sbostic getlong() 26036725Sbostic { 26136725Sbostic long atol(); 26236725Sbostic 26336725Sbostic if (!*gargv) 26436725Sbostic return((long)0); 26536725Sbostic if (index(number, **gargv)) 26636725Sbostic return(atol(*gargv++)); 26736725Sbostic return((long)asciicode()); 26836725Sbostic } 26936725Sbostic 27036725Sbostic double 27136725Sbostic getdouble() 27236725Sbostic { 27336725Sbostic double atof(); 27436725Sbostic 27536725Sbostic if (!*gargv) 27636725Sbostic return((double)0); 27736725Sbostic if (index(number, **gargv)) 27836725Sbostic return(atof(*gargv++)); 27936725Sbostic return((double)asciicode()); 28036725Sbostic } 28136725Sbostic 28236725Sbostic asciicode() 28336725Sbostic { 28436725Sbostic register char ch; 28536725Sbostic 28636725Sbostic ch = **gargv; 28736725Sbostic if (ch == '\'' || ch == '"') 28836725Sbostic ch = (*gargv)[1]; 28936725Sbostic ++gargv; 29036725Sbostic return(ch); 29136725Sbostic } 292