1*36725Sbostic /* 2*36725Sbostic * Copyright (c) 1989 The Regents of the University of California. 3*36725Sbostic * All rights reserved. 4*36725Sbostic * 5*36725Sbostic * Redistribution and use in source and binary forms are permitted 6*36725Sbostic * provided that the above copyright notice and this paragraph are 7*36725Sbostic * duplicated in all such forms and that any documentation, 8*36725Sbostic * advertising materials, and other materials related to such 9*36725Sbostic * distribution and use acknowledge that the software was developed 10*36725Sbostic * by the University of California, Berkeley. The name of the 11*36725Sbostic * University may not be used to endorse or promote products derived 12*36725Sbostic * from this software without specific prior written permission. 13*36725Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*36725Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*36725Sbostic * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16*36725Sbostic */ 17*36725Sbostic 18*36725Sbostic #ifndef lint 19*36725Sbostic char copyright[] = 20*36725Sbostic "@(#) Copyright (c) 1989 The Regents of the University of California.\n\ 21*36725Sbostic All rights reserved.\n"; 22*36725Sbostic #endif /* not lint */ 23*36725Sbostic 24*36725Sbostic #ifndef lint 25*36725Sbostic static char sccsid[] = "@(#)printf.c 5.1 (Berkeley) 02/12/89"; 26*36725Sbostic #endif /* not lint */ 27*36725Sbostic 28*36725Sbostic #include <sys/types.h> 29*36725Sbostic #include <stdio.h> 30*36725Sbostic 31*36725Sbostic #define PF(f, func) { \ 32*36725Sbostic if (fieldwidth) \ 33*36725Sbostic if (precision) \ 34*36725Sbostic cnt += printf(f, fieldwidth, precision, func); \ 35*36725Sbostic else \ 36*36725Sbostic cnt += printf(f, fieldwidth, func); \ 37*36725Sbostic else if (precision) \ 38*36725Sbostic cnt += printf(f, precision, func); \ 39*36725Sbostic else \ 40*36725Sbostic cnt += printf(f, func); \ 41*36725Sbostic } 42*36725Sbostic 43*36725Sbostic char **gargv; 44*36725Sbostic 45*36725Sbostic main(argc, argv) 46*36725Sbostic int argc; 47*36725Sbostic char **argv; 48*36725Sbostic { 49*36725Sbostic static char *skip1, *skip2; 50*36725Sbostic register char *format, *fmt, *start; 51*36725Sbostic register int end, cnt, fieldwidth, precision; 52*36725Sbostic char convch, nextch, *getstr(), *index(), *mklong(); 53*36725Sbostic double getdouble(); 54*36725Sbostic long getlong(); 55*36725Sbostic 56*36725Sbostic if (argc < 2) { 57*36725Sbostic fprintf(stderr, "usage: printf format [arg ...]\n"); 58*36725Sbostic exit(0); 59*36725Sbostic } 60*36725Sbostic 61*36725Sbostic /* 62*36725Sbostic * Basic algorithm is to scan the format string for conversion 63*36725Sbostic * specifications -- once one is found, find out if the field 64*36725Sbostic * width or precision is a '*'; if it is, gather up value. Note, 65*36725Sbostic * format strings are reused as necessary to use up the provided 66*36725Sbostic * arguments, arguments of zero/null string are provided to use 67*36725Sbostic * up the format string. 68*36725Sbostic */ 69*36725Sbostic skip1 = "#-+ 0"; 70*36725Sbostic skip2 = "*0123456789"; 71*36725Sbostic 72*36725Sbostic escape(fmt = format = *++argv); /* backslash interpretation */ 73*36725Sbostic gargv = ++argv; 74*36725Sbostic for (cnt = 0;;) { 75*36725Sbostic end = 0; 76*36725Sbostic /* find next format specification */ 77*36725Sbostic next: for (start = fmt;; ++fmt) { 78*36725Sbostic if (!*fmt) { 79*36725Sbostic /* avoid infinite loop */ 80*36725Sbostic if (end == 1) { 81*36725Sbostic fprintf(stderr, 82*36725Sbostic "printf: missing format character.\n"); 83*36725Sbostic exit(0); 84*36725Sbostic } 85*36725Sbostic end = 1; 86*36725Sbostic if (fmt > start) 87*36725Sbostic cnt += printf("%s", start); 88*36725Sbostic if (!*gargv) 89*36725Sbostic exit(cnt); 90*36725Sbostic fmt = format; 91*36725Sbostic goto next; 92*36725Sbostic } 93*36725Sbostic /* %% prints a % */ 94*36725Sbostic if (*fmt == '%' && *++fmt != '%') 95*36725Sbostic break; 96*36725Sbostic } 97*36725Sbostic 98*36725Sbostic /* skip to field width */ 99*36725Sbostic for (; index(skip1, *fmt); ++fmt); 100*36725Sbostic if (*fmt == '*') 101*36725Sbostic fieldwidth = getint(); 102*36725Sbostic /* skip to possible '.' */ 103*36725Sbostic for (; index(skip2, *fmt); ++fmt); 104*36725Sbostic if (*fmt == '.') 105*36725Sbostic ++fmt; 106*36725Sbostic if (*fmt == '*') 107*36725Sbostic precision = getint(); 108*36725Sbostic /* skip to conversion char */ 109*36725Sbostic for (; index(skip2, *fmt); ++fmt); 110*36725Sbostic if (!*fmt) { 111*36725Sbostic fprintf(stderr, "printf: missing format character.\n"); 112*36725Sbostic exit(-1); 113*36725Sbostic } 114*36725Sbostic 115*36725Sbostic convch = *fmt; 116*36725Sbostic nextch = *++fmt; 117*36725Sbostic *fmt = '\0'; 118*36725Sbostic switch(convch) { 119*36725Sbostic case 'c': { 120*36725Sbostic char p = getchr(); 121*36725Sbostic PF(start, p); 122*36725Sbostic break; 123*36725Sbostic } 124*36725Sbostic case 's': { 125*36725Sbostic char *p = getstr(); 126*36725Sbostic PF(start, p); 127*36725Sbostic break; 128*36725Sbostic } 129*36725Sbostic case 'd': case 'o': case 'u': case 'x': case 'X': { 130*36725Sbostic char *f = mklong(start, convch); 131*36725Sbostic long p = getlong(); 132*36725Sbostic PF(f, p); 133*36725Sbostic break; 134*36725Sbostic } 135*36725Sbostic case 'e': case 'E': case 'f': case 'g': case 'G': { 136*36725Sbostic double p = getdouble(); 137*36725Sbostic PF(start, p); 138*36725Sbostic break; 139*36725Sbostic } 140*36725Sbostic default: 141*36725Sbostic fprintf(stderr, "printf: illegal format character.\n"); 142*36725Sbostic exit(-1); 143*36725Sbostic } 144*36725Sbostic *fmt = nextch; 145*36725Sbostic } 146*36725Sbostic /* NOTREACHED */ 147*36725Sbostic } 148*36725Sbostic 149*36725Sbostic char * 150*36725Sbostic mklong(str, ch) 151*36725Sbostic char *str, ch; 152*36725Sbostic { 153*36725Sbostic int len; 154*36725Sbostic char *copy, *malloc(); 155*36725Sbostic 156*36725Sbostic len = strlen(str) + 2; 157*36725Sbostic if (!(copy = malloc((u_int)len))) { /* never freed; XXX */ 158*36725Sbostic fprintf(stderr, "printf: out of memory.\n"); 159*36725Sbostic exit(-1); 160*36725Sbostic } 161*36725Sbostic bcopy(str, copy, len - 3); 162*36725Sbostic copy[len - 3] = 'l'; 163*36725Sbostic copy[len - 2] = ch; 164*36725Sbostic copy[len - 1] = '\0'; 165*36725Sbostic return(copy); 166*36725Sbostic } 167*36725Sbostic 168*36725Sbostic escape(fmt) 169*36725Sbostic register char *fmt; 170*36725Sbostic { 171*36725Sbostic register char *store; 172*36725Sbostic register int value, c; 173*36725Sbostic 174*36725Sbostic for (store = fmt; c = *fmt; ++fmt, ++store) { 175*36725Sbostic if (c != '\\') { 176*36725Sbostic *store = c; 177*36725Sbostic continue; 178*36725Sbostic } 179*36725Sbostic switch (*++fmt) { 180*36725Sbostic case '\0': /* EOS, user error */ 181*36725Sbostic *store = '\\'; 182*36725Sbostic *++store = '\0'; 183*36725Sbostic return; 184*36725Sbostic case '\\': /* backslash */ 185*36725Sbostic *store = '\\'; 186*36725Sbostic break; 187*36725Sbostic case 'a': /* bell/alert */ 188*36725Sbostic *store = '\7'; 189*36725Sbostic break; 190*36725Sbostic case 'b': /* backspace */ 191*36725Sbostic *store = '\b'; 192*36725Sbostic break; 193*36725Sbostic case 'f': /* form-feed */ 194*36725Sbostic *store = '\f'; 195*36725Sbostic break; 196*36725Sbostic case 'n': /* newline */ 197*36725Sbostic *store = '\n'; 198*36725Sbostic break; 199*36725Sbostic case 'r': /* carriage-return */ 200*36725Sbostic *store = '\r'; 201*36725Sbostic break; 202*36725Sbostic case 't': /* horizontal tab */ 203*36725Sbostic *store = '\t'; 204*36725Sbostic break; 205*36725Sbostic case 'v': /* vertical tab */ 206*36725Sbostic *store = '\13'; 207*36725Sbostic break; 208*36725Sbostic /* octal constant */ 209*36725Sbostic case '0': case '1': case '2': case '3': 210*36725Sbostic case '4': case '5': case '6': case '7': 211*36725Sbostic for (c = 3, value = 0; 212*36725Sbostic c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) { 213*36725Sbostic value <<= 3; 214*36725Sbostic value += *fmt - '0'; 215*36725Sbostic } 216*36725Sbostic --fmt; 217*36725Sbostic *store = value; 218*36725Sbostic break; 219*36725Sbostic default: 220*36725Sbostic *store = *fmt; 221*36725Sbostic break; 222*36725Sbostic } 223*36725Sbostic } 224*36725Sbostic *store = '\0'; 225*36725Sbostic } 226*36725Sbostic 227*36725Sbostic getchr() 228*36725Sbostic { 229*36725Sbostic if (!*gargv) 230*36725Sbostic return((int)'\0'); 231*36725Sbostic return((int)**gargv++); 232*36725Sbostic } 233*36725Sbostic 234*36725Sbostic char * 235*36725Sbostic getstr() 236*36725Sbostic { 237*36725Sbostic if (!*gargv) 238*36725Sbostic return(""); 239*36725Sbostic return(*gargv++); 240*36725Sbostic } 241*36725Sbostic 242*36725Sbostic static char *number = "+-0123456789"; 243*36725Sbostic getint() 244*36725Sbostic { 245*36725Sbostic if (!*gargv) 246*36725Sbostic return(0); 247*36725Sbostic if (index(number, **gargv)) 248*36725Sbostic return(atoi(*gargv++)); 249*36725Sbostic return(asciicode()); 250*36725Sbostic } 251*36725Sbostic 252*36725Sbostic long 253*36725Sbostic getlong() 254*36725Sbostic { 255*36725Sbostic long atol(); 256*36725Sbostic 257*36725Sbostic if (!*gargv) 258*36725Sbostic return((long)0); 259*36725Sbostic if (index(number, **gargv)) 260*36725Sbostic return(atol(*gargv++)); 261*36725Sbostic return((long)asciicode()); 262*36725Sbostic } 263*36725Sbostic 264*36725Sbostic double 265*36725Sbostic getdouble() 266*36725Sbostic { 267*36725Sbostic double atof(); 268*36725Sbostic 269*36725Sbostic if (!*gargv) 270*36725Sbostic return((double)0); 271*36725Sbostic if (index(number, **gargv)) 272*36725Sbostic return(atof(*gargv++)); 273*36725Sbostic return((double)asciicode()); 274*36725Sbostic } 275*36725Sbostic 276*36725Sbostic asciicode() 277*36725Sbostic { 278*36725Sbostic register char ch; 279*36725Sbostic 280*36725Sbostic ch = **gargv; 281*36725Sbostic if (ch == '\'' || ch == '"') 282*36725Sbostic ch = (*gargv)[1]; 283*36725Sbostic ++gargv; 284*36725Sbostic return(ch); 285*36725Sbostic } 286