1*f967d548SGarrett D'Amore /* 2*f967d548SGarrett D'Amore * Copyright 2010 Nexenta Systems, Inc. All rights reserved. 3*f967d548SGarrett D'Amore * Copyright (c) 1989, 1993 4*f967d548SGarrett D'Amore * The Regents of the University of California. All rights reserved. 5*f967d548SGarrett D'Amore * 6*f967d548SGarrett D'Amore * Redistribution and use in source and binary forms, with or without 7*f967d548SGarrett D'Amore * modification, are permitted provided that the following conditions 8*f967d548SGarrett D'Amore * are met: 9*f967d548SGarrett D'Amore * 1. Redistributions of source code must retain the above copyright 10*f967d548SGarrett D'Amore * notice, this list of conditions and the following disclaimer. 11*f967d548SGarrett D'Amore * 2. Redistributions in binary form must reproduce the above copyright 12*f967d548SGarrett D'Amore * notice, this list of conditions and the following disclaimer in the 13*f967d548SGarrett D'Amore * documentation and/or other materials provided with the distribution. 14*f967d548SGarrett D'Amore * 4. Neither the name of the University nor the names of its contributors 15*f967d548SGarrett D'Amore * may be used to endorse or promote products derived from this software 16*f967d548SGarrett D'Amore * without specific prior written permission. 17*f967d548SGarrett D'Amore * 18*f967d548SGarrett D'Amore * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19*f967d548SGarrett D'Amore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20*f967d548SGarrett D'Amore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21*f967d548SGarrett D'Amore * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22*f967d548SGarrett D'Amore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23*f967d548SGarrett D'Amore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24*f967d548SGarrett D'Amore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25*f967d548SGarrett D'Amore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26*f967d548SGarrett D'Amore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27*f967d548SGarrett D'Amore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28*f967d548SGarrett D'Amore * SUCH DAMAGE. 29*f967d548SGarrett D'Amore */ 30*f967d548SGarrett D'Amore 31*f967d548SGarrett D'Amore #include <sys/types.h> 32*f967d548SGarrett D'Amore 33*f967d548SGarrett D'Amore #include <err.h> 34*f967d548SGarrett D'Amore #include <errno.h> 35*f967d548SGarrett D'Amore #include <inttypes.h> 36*f967d548SGarrett D'Amore #include <limits.h> 37*f967d548SGarrett D'Amore #include <stdio.h> 38*f967d548SGarrett D'Amore #include <stdlib.h> 39*f967d548SGarrett D'Amore #include <string.h> 40*f967d548SGarrett D'Amore #include <unistd.h> 41*f967d548SGarrett D'Amore #include <locale.h> 42*f967d548SGarrett D'Amore #include <note.h> 43*f967d548SGarrett D'Amore 44*f967d548SGarrett D'Amore #define warnx1(a, b, c) warnx(a) 45*f967d548SGarrett D'Amore #define warnx2(a, b, c) warnx(a, b) 46*f967d548SGarrett D'Amore #define warnx3(a, b, c) warnx(a, b, c) 47*f967d548SGarrett D'Amore 48*f967d548SGarrett D'Amore #define PTRDIFF(x, y) ((uintptr_t)(x) - (uintptr_t)(y)) 49*f967d548SGarrett D'Amore 50*f967d548SGarrett D'Amore #define _(x) gettext(x) 51*f967d548SGarrett D'Amore 52*f967d548SGarrett D'Amore #define PF(f, func) do { \ 53*f967d548SGarrett D'Amore char *b = NULL; \ 54*f967d548SGarrett D'Amore int dollar = 0; \ 55*f967d548SGarrett D'Amore if (*f == '$') { \ 56*f967d548SGarrett D'Amore dollar++; \ 57*f967d548SGarrett D'Amore *f = '%'; \ 58*f967d548SGarrett D'Amore } \ 59*f967d548SGarrett D'Amore if (havewidth) \ 60*f967d548SGarrett D'Amore if (haveprec) \ 61*f967d548SGarrett D'Amore (void) asprintf(&b, f, fieldwidth, precision, func); \ 62*f967d548SGarrett D'Amore else \ 63*f967d548SGarrett D'Amore (void) asprintf(&b, f, fieldwidth, func); \ 64*f967d548SGarrett D'Amore else if (haveprec) \ 65*f967d548SGarrett D'Amore (void) asprintf(&b, f, precision, func); \ 66*f967d548SGarrett D'Amore else \ 67*f967d548SGarrett D'Amore (void) asprintf(&b, f, func); \ 68*f967d548SGarrett D'Amore if (b) { \ 69*f967d548SGarrett D'Amore (void) fputs(b, stdout); \ 70*f967d548SGarrett D'Amore free(b); \ 71*f967d548SGarrett D'Amore } \ 72*f967d548SGarrett D'Amore if (dollar) \ 73*f967d548SGarrett D'Amore *f = '$'; \ 74*f967d548SGarrett D'Amore _NOTE(CONSTCOND) } while (0) 75*f967d548SGarrett D'Amore 76*f967d548SGarrett D'Amore static int asciicode(void); 77*f967d548SGarrett D'Amore static char *doformat(char *, int *); 78*f967d548SGarrett D'Amore static int escape(char *, int, size_t *); 79*f967d548SGarrett D'Amore static int getchr(void); 80*f967d548SGarrett D'Amore static int getfloating(long double *, int); 81*f967d548SGarrett D'Amore static int getint(int *); 82*f967d548SGarrett D'Amore static int getnum(intmax_t *, uintmax_t *, int); 83*f967d548SGarrett D'Amore static const char 84*f967d548SGarrett D'Amore *getstr(void); 85*f967d548SGarrett D'Amore static char *mknum(char *, char); 86*f967d548SGarrett D'Amore static void usage(void); 87*f967d548SGarrett D'Amore 88*f967d548SGarrett D'Amore static int myargc; 89*f967d548SGarrett D'Amore static char **myargv; 90*f967d548SGarrett D'Amore static char **gargv; 91*f967d548SGarrett D'Amore 92*f967d548SGarrett D'Amore int 93*f967d548SGarrett D'Amore main(int argc, char *argv[]) 94*f967d548SGarrett D'Amore { 95*f967d548SGarrett D'Amore size_t len; 96*f967d548SGarrett D'Amore int chopped, end, rval; 97*f967d548SGarrett D'Amore char *format, *fmt, *start; 98*f967d548SGarrett D'Amore 99*f967d548SGarrett D'Amore (void) setlocale(LC_ALL, ""); 100*f967d548SGarrett D'Amore 101*f967d548SGarrett D'Amore argv++; 102*f967d548SGarrett D'Amore argc--; 103*f967d548SGarrett D'Amore 104*f967d548SGarrett D'Amore /* 105*f967d548SGarrett D'Amore * POSIX says: Standard utilities that do not accept options, 106*f967d548SGarrett D'Amore * but that do accept operands, shall recognize "--" as a 107*f967d548SGarrett D'Amore * first argument to be discarded. 108*f967d548SGarrett D'Amore */ 109*f967d548SGarrett D'Amore if (strcmp(argv[0], "--") == 0) { 110*f967d548SGarrett D'Amore argc--; 111*f967d548SGarrett D'Amore argv++; 112*f967d548SGarrett D'Amore } 113*f967d548SGarrett D'Amore 114*f967d548SGarrett D'Amore if (argc < 1) { 115*f967d548SGarrett D'Amore usage(); 116*f967d548SGarrett D'Amore return (1); 117*f967d548SGarrett D'Amore } 118*f967d548SGarrett D'Amore 119*f967d548SGarrett D'Amore /* 120*f967d548SGarrett D'Amore * Basic algorithm is to scan the format string for conversion 121*f967d548SGarrett D'Amore * specifications -- once one is found, find out if the field 122*f967d548SGarrett D'Amore * width or precision is a '*'; if it is, gather up value. Note, 123*f967d548SGarrett D'Amore * format strings are reused as necessary to use up the provided 124*f967d548SGarrett D'Amore * arguments, arguments of zero/null string are provided to use 125*f967d548SGarrett D'Amore * up the format string. 126*f967d548SGarrett D'Amore */ 127*f967d548SGarrett D'Amore fmt = format = *argv; 128*f967d548SGarrett D'Amore chopped = escape(fmt, 1, &len); /* backslash interpretation */ 129*f967d548SGarrett D'Amore rval = end = 0; 130*f967d548SGarrett D'Amore gargv = ++argv; 131*f967d548SGarrett D'Amore 132*f967d548SGarrett D'Amore for (;;) { 133*f967d548SGarrett D'Amore char **maxargv = gargv; 134*f967d548SGarrett D'Amore 135*f967d548SGarrett D'Amore myargv = gargv; 136*f967d548SGarrett D'Amore for (myargc = 0; gargv[myargc]; myargc++) 137*f967d548SGarrett D'Amore /* nop */; 138*f967d548SGarrett D'Amore start = fmt; 139*f967d548SGarrett D'Amore while (fmt < format + len) { 140*f967d548SGarrett D'Amore if (fmt[0] == '%') { 141*f967d548SGarrett D'Amore (void) fwrite(start, 1, PTRDIFF(fmt, start), 142*f967d548SGarrett D'Amore stdout); 143*f967d548SGarrett D'Amore if (fmt[1] == '%') { 144*f967d548SGarrett D'Amore /* %% prints a % */ 145*f967d548SGarrett D'Amore (void) putchar('%'); 146*f967d548SGarrett D'Amore fmt += 2; 147*f967d548SGarrett D'Amore } else { 148*f967d548SGarrett D'Amore fmt = doformat(fmt, &rval); 149*f967d548SGarrett D'Amore if (fmt == NULL) 150*f967d548SGarrett D'Amore return (1); 151*f967d548SGarrett D'Amore end = 0; 152*f967d548SGarrett D'Amore } 153*f967d548SGarrett D'Amore start = fmt; 154*f967d548SGarrett D'Amore } else 155*f967d548SGarrett D'Amore fmt++; 156*f967d548SGarrett D'Amore if (gargv > maxargv) 157*f967d548SGarrett D'Amore maxargv = gargv; 158*f967d548SGarrett D'Amore } 159*f967d548SGarrett D'Amore gargv = maxargv; 160*f967d548SGarrett D'Amore 161*f967d548SGarrett D'Amore if (end == 1) { 162*f967d548SGarrett D'Amore warnx1(_("missing format character"), NULL, NULL); 163*f967d548SGarrett D'Amore return (1); 164*f967d548SGarrett D'Amore } 165*f967d548SGarrett D'Amore (void) fwrite(start, 1, PTRDIFF(fmt, start), stdout); 166*f967d548SGarrett D'Amore if (chopped || !*gargv) 167*f967d548SGarrett D'Amore return (rval); 168*f967d548SGarrett D'Amore /* Restart at the beginning of the format string. */ 169*f967d548SGarrett D'Amore fmt = format; 170*f967d548SGarrett D'Amore end = 1; 171*f967d548SGarrett D'Amore } 172*f967d548SGarrett D'Amore /* NOTREACHED */ 173*f967d548SGarrett D'Amore } 174*f967d548SGarrett D'Amore 175*f967d548SGarrett D'Amore 176*f967d548SGarrett D'Amore static char * 177*f967d548SGarrett D'Amore doformat(char *start, int *rval) 178*f967d548SGarrett D'Amore { 179*f967d548SGarrett D'Amore static const char skip1[] = "#'-+ 0"; 180*f967d548SGarrett D'Amore static const char skip2[] = "0123456789"; 181*f967d548SGarrett D'Amore char *fmt; 182*f967d548SGarrett D'Amore int fieldwidth, haveprec, havewidth, mod_ldbl, precision; 183*f967d548SGarrett D'Amore char convch, nextch; 184*f967d548SGarrett D'Amore 185*f967d548SGarrett D'Amore fmt = start + 1; 186*f967d548SGarrett D'Amore 187*f967d548SGarrett D'Amore /* look for "n$" field index specifier */ 188*f967d548SGarrett D'Amore fmt += strspn(fmt, skip2); 189*f967d548SGarrett D'Amore if ((*fmt == '$') && (fmt != (start + 1))) { 190*f967d548SGarrett D'Amore int idx = atoi(start + 1); 191*f967d548SGarrett D'Amore if (idx <= myargc) { 192*f967d548SGarrett D'Amore gargv = &myargv[idx - 1]; 193*f967d548SGarrett D'Amore } else { 194*f967d548SGarrett D'Amore gargv = &myargv[myargc]; 195*f967d548SGarrett D'Amore } 196*f967d548SGarrett D'Amore start = fmt; 197*f967d548SGarrett D'Amore fmt++; 198*f967d548SGarrett D'Amore } else { 199*f967d548SGarrett D'Amore fmt = start + 1; 200*f967d548SGarrett D'Amore } 201*f967d548SGarrett D'Amore 202*f967d548SGarrett D'Amore /* skip to field width */ 203*f967d548SGarrett D'Amore fmt += strspn(fmt, skip1); 204*f967d548SGarrett D'Amore if (*fmt == '*') { 205*f967d548SGarrett D'Amore if (getint(&fieldwidth)) 206*f967d548SGarrett D'Amore return (NULL); 207*f967d548SGarrett D'Amore havewidth = 1; 208*f967d548SGarrett D'Amore ++fmt; 209*f967d548SGarrett D'Amore } else { 210*f967d548SGarrett D'Amore havewidth = 0; 211*f967d548SGarrett D'Amore 212*f967d548SGarrett D'Amore /* skip to possible '.', get following precision */ 213*f967d548SGarrett D'Amore fmt += strspn(fmt, skip2); 214*f967d548SGarrett D'Amore } 215*f967d548SGarrett D'Amore if (*fmt == '.') { 216*f967d548SGarrett D'Amore /* precision present? */ 217*f967d548SGarrett D'Amore ++fmt; 218*f967d548SGarrett D'Amore if (*fmt == '*') { 219*f967d548SGarrett D'Amore if (getint(&precision)) 220*f967d548SGarrett D'Amore return (NULL); 221*f967d548SGarrett D'Amore haveprec = 1; 222*f967d548SGarrett D'Amore ++fmt; 223*f967d548SGarrett D'Amore } else { 224*f967d548SGarrett D'Amore haveprec = 0; 225*f967d548SGarrett D'Amore 226*f967d548SGarrett D'Amore /* skip to conversion char */ 227*f967d548SGarrett D'Amore fmt += strspn(fmt, skip2); 228*f967d548SGarrett D'Amore } 229*f967d548SGarrett D'Amore } else 230*f967d548SGarrett D'Amore haveprec = 0; 231*f967d548SGarrett D'Amore if (!*fmt) { 232*f967d548SGarrett D'Amore warnx1(_("missing format character"), NULL, NULL); 233*f967d548SGarrett D'Amore return (NULL); 234*f967d548SGarrett D'Amore } 235*f967d548SGarrett D'Amore 236*f967d548SGarrett D'Amore /* 237*f967d548SGarrett D'Amore * Look for a length modifier. POSIX doesn't have these, so 238*f967d548SGarrett D'Amore * we only support them for floating-point conversions, which 239*f967d548SGarrett D'Amore * are extensions. This is useful because the L modifier can 240*f967d548SGarrett D'Amore * be used to gain extra range and precision, while omitting 241*f967d548SGarrett D'Amore * it is more likely to produce consistent results on different 242*f967d548SGarrett D'Amore * architectures. This is not so important for integers 243*f967d548SGarrett D'Amore * because overflow is the only bad thing that can happen to 244*f967d548SGarrett D'Amore * them, but consider the command printf %a 1.1 245*f967d548SGarrett D'Amore */ 246*f967d548SGarrett D'Amore if (*fmt == 'L') { 247*f967d548SGarrett D'Amore mod_ldbl = 1; 248*f967d548SGarrett D'Amore fmt++; 249*f967d548SGarrett D'Amore if (!strchr("aAeEfFgG", *fmt)) { 250*f967d548SGarrett D'Amore warnx2(_("bad modifier L for %%%c"), *fmt, NULL); 251*f967d548SGarrett D'Amore return (NULL); 252*f967d548SGarrett D'Amore } 253*f967d548SGarrett D'Amore } else { 254*f967d548SGarrett D'Amore mod_ldbl = 0; 255*f967d548SGarrett D'Amore } 256*f967d548SGarrett D'Amore 257*f967d548SGarrett D'Amore convch = *fmt; 258*f967d548SGarrett D'Amore nextch = *++fmt; 259*f967d548SGarrett D'Amore *fmt = '\0'; 260*f967d548SGarrett D'Amore switch (convch) { 261*f967d548SGarrett D'Amore case 'b': { 262*f967d548SGarrett D'Amore size_t len; 263*f967d548SGarrett D'Amore char *p; 264*f967d548SGarrett D'Amore int getout; 265*f967d548SGarrett D'Amore 266*f967d548SGarrett D'Amore p = strdup(getstr()); 267*f967d548SGarrett D'Amore if (p == NULL) { 268*f967d548SGarrett D'Amore warnx2("%s", strerror(ENOMEM), NULL); 269*f967d548SGarrett D'Amore return (NULL); 270*f967d548SGarrett D'Amore } 271*f967d548SGarrett D'Amore getout = escape(p, 0, &len); 272*f967d548SGarrett D'Amore *(fmt - 1) = 's'; 273*f967d548SGarrett D'Amore PF(start, p); 274*f967d548SGarrett D'Amore *(fmt - 1) = 'b'; 275*f967d548SGarrett D'Amore free(p); 276*f967d548SGarrett D'Amore 277*f967d548SGarrett D'Amore if (getout) 278*f967d548SGarrett D'Amore return (fmt); 279*f967d548SGarrett D'Amore break; 280*f967d548SGarrett D'Amore } 281*f967d548SGarrett D'Amore case 'c': { 282*f967d548SGarrett D'Amore char p; 283*f967d548SGarrett D'Amore 284*f967d548SGarrett D'Amore p = getchr(); 285*f967d548SGarrett D'Amore PF(start, p); 286*f967d548SGarrett D'Amore break; 287*f967d548SGarrett D'Amore } 288*f967d548SGarrett D'Amore case 's': { 289*f967d548SGarrett D'Amore const char *p; 290*f967d548SGarrett D'Amore 291*f967d548SGarrett D'Amore p = getstr(); 292*f967d548SGarrett D'Amore PF(start, p); 293*f967d548SGarrett D'Amore break; 294*f967d548SGarrett D'Amore } 295*f967d548SGarrett D'Amore case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': { 296*f967d548SGarrett D'Amore char *f; 297*f967d548SGarrett D'Amore intmax_t val; 298*f967d548SGarrett D'Amore uintmax_t uval; 299*f967d548SGarrett D'Amore int signedconv; 300*f967d548SGarrett D'Amore 301*f967d548SGarrett D'Amore signedconv = (convch == 'd' || convch == 'i'); 302*f967d548SGarrett D'Amore if ((f = mknum(start, convch)) == NULL) 303*f967d548SGarrett D'Amore return (NULL); 304*f967d548SGarrett D'Amore if (getnum(&val, &uval, signedconv)) 305*f967d548SGarrett D'Amore *rval = 1; 306*f967d548SGarrett D'Amore if (signedconv) 307*f967d548SGarrett D'Amore PF(f, val); 308*f967d548SGarrett D'Amore else 309*f967d548SGarrett D'Amore PF(f, uval); 310*f967d548SGarrett D'Amore break; 311*f967d548SGarrett D'Amore } 312*f967d548SGarrett D'Amore case 'e': case 'E': 313*f967d548SGarrett D'Amore case 'f': case 'F': 314*f967d548SGarrett D'Amore case 'g': case 'G': 315*f967d548SGarrett D'Amore case 'a': case 'A': { 316*f967d548SGarrett D'Amore long double p; 317*f967d548SGarrett D'Amore 318*f967d548SGarrett D'Amore if (getfloating(&p, mod_ldbl)) 319*f967d548SGarrett D'Amore *rval = 1; 320*f967d548SGarrett D'Amore if (mod_ldbl) 321*f967d548SGarrett D'Amore PF(start, p); 322*f967d548SGarrett D'Amore else 323*f967d548SGarrett D'Amore PF(start, (double)p); 324*f967d548SGarrett D'Amore break; 325*f967d548SGarrett D'Amore } 326*f967d548SGarrett D'Amore default: 327*f967d548SGarrett D'Amore warnx2(_("illegal format character %c"), convch, NULL); 328*f967d548SGarrett D'Amore return (NULL); 329*f967d548SGarrett D'Amore } 330*f967d548SGarrett D'Amore *fmt = nextch; 331*f967d548SGarrett D'Amore return (fmt); 332*f967d548SGarrett D'Amore } 333*f967d548SGarrett D'Amore 334*f967d548SGarrett D'Amore static char * 335*f967d548SGarrett D'Amore mknum(char *str, char ch) 336*f967d548SGarrett D'Amore { 337*f967d548SGarrett D'Amore static char *copy; 338*f967d548SGarrett D'Amore static size_t copy_size; 339*f967d548SGarrett D'Amore char *newcopy; 340*f967d548SGarrett D'Amore size_t len, newlen; 341*f967d548SGarrett D'Amore 342*f967d548SGarrett D'Amore len = strlen(str) + 2; 343*f967d548SGarrett D'Amore if (len > copy_size) { 344*f967d548SGarrett D'Amore newlen = ((len + 1023) >> 10) << 10; 345*f967d548SGarrett D'Amore if ((newcopy = realloc(copy, newlen)) == NULL) { 346*f967d548SGarrett D'Amore warnx2("%s", strerror(ENOMEM), NULL); 347*f967d548SGarrett D'Amore return (NULL); 348*f967d548SGarrett D'Amore } 349*f967d548SGarrett D'Amore copy = newcopy; 350*f967d548SGarrett D'Amore copy_size = newlen; 351*f967d548SGarrett D'Amore } 352*f967d548SGarrett D'Amore 353*f967d548SGarrett D'Amore (void) memmove(copy, str, len - 3); 354*f967d548SGarrett D'Amore copy[len - 3] = 'j'; 355*f967d548SGarrett D'Amore copy[len - 2] = ch; 356*f967d548SGarrett D'Amore copy[len - 1] = '\0'; 357*f967d548SGarrett D'Amore return (copy); 358*f967d548SGarrett D'Amore } 359*f967d548SGarrett D'Amore 360*f967d548SGarrett D'Amore static int 361*f967d548SGarrett D'Amore escape(char *fmt, int percent, size_t *len) 362*f967d548SGarrett D'Amore { 363*f967d548SGarrett D'Amore char *save, *store, c; 364*f967d548SGarrett D'Amore int value; 365*f967d548SGarrett D'Amore 366*f967d548SGarrett D'Amore for (save = store = fmt; ((c = *fmt) != 0); ++fmt, ++store) { 367*f967d548SGarrett D'Amore if (c != '\\') { 368*f967d548SGarrett D'Amore *store = c; 369*f967d548SGarrett D'Amore continue; 370*f967d548SGarrett D'Amore } 371*f967d548SGarrett D'Amore switch (*++fmt) { 372*f967d548SGarrett D'Amore case '\0': /* EOS, user error */ 373*f967d548SGarrett D'Amore *store = '\\'; 374*f967d548SGarrett D'Amore *++store = '\0'; 375*f967d548SGarrett D'Amore *len = PTRDIFF(store, save); 376*f967d548SGarrett D'Amore return (0); 377*f967d548SGarrett D'Amore case '\\': /* backslash */ 378*f967d548SGarrett D'Amore case '\'': /* single quote */ 379*f967d548SGarrett D'Amore *store = *fmt; 380*f967d548SGarrett D'Amore break; 381*f967d548SGarrett D'Amore case 'a': /* bell/alert */ 382*f967d548SGarrett D'Amore *store = '\a'; 383*f967d548SGarrett D'Amore break; 384*f967d548SGarrett D'Amore case 'b': /* backspace */ 385*f967d548SGarrett D'Amore *store = '\b'; 386*f967d548SGarrett D'Amore break; 387*f967d548SGarrett D'Amore case 'c': 388*f967d548SGarrett D'Amore *store = '\0'; 389*f967d548SGarrett D'Amore *len = PTRDIFF(store, save); 390*f967d548SGarrett D'Amore return (1); 391*f967d548SGarrett D'Amore case 'f': /* form-feed */ 392*f967d548SGarrett D'Amore *store = '\f'; 393*f967d548SGarrett D'Amore break; 394*f967d548SGarrett D'Amore case 'n': /* newline */ 395*f967d548SGarrett D'Amore *store = '\n'; 396*f967d548SGarrett D'Amore break; 397*f967d548SGarrett D'Amore case 'r': /* carriage-return */ 398*f967d548SGarrett D'Amore *store = '\r'; 399*f967d548SGarrett D'Amore break; 400*f967d548SGarrett D'Amore case 't': /* horizontal tab */ 401*f967d548SGarrett D'Amore *store = '\t'; 402*f967d548SGarrett D'Amore break; 403*f967d548SGarrett D'Amore case 'v': /* vertical tab */ 404*f967d548SGarrett D'Amore *store = '\v'; 405*f967d548SGarrett D'Amore break; 406*f967d548SGarrett D'Amore /* octal constant */ 407*f967d548SGarrett D'Amore case '0': case '1': case '2': case '3': 408*f967d548SGarrett D'Amore case '4': case '5': case '6': case '7': 409*f967d548SGarrett D'Amore c = (!percent && *fmt == '0') ? 4 : 3; 410*f967d548SGarrett D'Amore for (value = 0; 411*f967d548SGarrett D'Amore c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) { 412*f967d548SGarrett D'Amore value <<= 3; 413*f967d548SGarrett D'Amore value += *fmt - '0'; 414*f967d548SGarrett D'Amore } 415*f967d548SGarrett D'Amore --fmt; 416*f967d548SGarrett D'Amore if (percent && value == '%') { 417*f967d548SGarrett D'Amore *store++ = '%'; 418*f967d548SGarrett D'Amore *store = '%'; 419*f967d548SGarrett D'Amore } else 420*f967d548SGarrett D'Amore *store = (char)value; 421*f967d548SGarrett D'Amore break; 422*f967d548SGarrett D'Amore default: 423*f967d548SGarrett D'Amore *store = *fmt; 424*f967d548SGarrett D'Amore break; 425*f967d548SGarrett D'Amore } 426*f967d548SGarrett D'Amore } 427*f967d548SGarrett D'Amore *store = '\0'; 428*f967d548SGarrett D'Amore *len = PTRDIFF(store, save); 429*f967d548SGarrett D'Amore return (0); 430*f967d548SGarrett D'Amore } 431*f967d548SGarrett D'Amore 432*f967d548SGarrett D'Amore static int 433*f967d548SGarrett D'Amore getchr(void) 434*f967d548SGarrett D'Amore { 435*f967d548SGarrett D'Amore if (!*gargv) 436*f967d548SGarrett D'Amore return ('\0'); 437*f967d548SGarrett D'Amore return ((int)**gargv++); 438*f967d548SGarrett D'Amore } 439*f967d548SGarrett D'Amore 440*f967d548SGarrett D'Amore static const char * 441*f967d548SGarrett D'Amore getstr(void) 442*f967d548SGarrett D'Amore { 443*f967d548SGarrett D'Amore if (!*gargv) 444*f967d548SGarrett D'Amore return (""); 445*f967d548SGarrett D'Amore return (*gargv++); 446*f967d548SGarrett D'Amore } 447*f967d548SGarrett D'Amore 448*f967d548SGarrett D'Amore static int 449*f967d548SGarrett D'Amore getint(int *ip) 450*f967d548SGarrett D'Amore { 451*f967d548SGarrett D'Amore intmax_t val; 452*f967d548SGarrett D'Amore uintmax_t uval; 453*f967d548SGarrett D'Amore int rval; 454*f967d548SGarrett D'Amore 455*f967d548SGarrett D'Amore if (getnum(&val, &uval, 1)) 456*f967d548SGarrett D'Amore return (1); 457*f967d548SGarrett D'Amore rval = 0; 458*f967d548SGarrett D'Amore if (val < INT_MIN || val > INT_MAX) { 459*f967d548SGarrett D'Amore warnx3("%s: %s", *gargv, strerror(ERANGE)); 460*f967d548SGarrett D'Amore rval = 1; 461*f967d548SGarrett D'Amore } 462*f967d548SGarrett D'Amore *ip = (int)val; 463*f967d548SGarrett D'Amore return (rval); 464*f967d548SGarrett D'Amore } 465*f967d548SGarrett D'Amore 466*f967d548SGarrett D'Amore static int 467*f967d548SGarrett D'Amore getnum(intmax_t *ip, uintmax_t *uip, int signedconv) 468*f967d548SGarrett D'Amore { 469*f967d548SGarrett D'Amore char *ep; 470*f967d548SGarrett D'Amore int rval; 471*f967d548SGarrett D'Amore 472*f967d548SGarrett D'Amore if (!*gargv) { 473*f967d548SGarrett D'Amore *ip = 0; 474*f967d548SGarrett D'Amore return (0); 475*f967d548SGarrett D'Amore } 476*f967d548SGarrett D'Amore if (**gargv == '"' || **gargv == '\'') { 477*f967d548SGarrett D'Amore if (signedconv) 478*f967d548SGarrett D'Amore *ip = asciicode(); 479*f967d548SGarrett D'Amore else 480*f967d548SGarrett D'Amore *uip = asciicode(); 481*f967d548SGarrett D'Amore return (0); 482*f967d548SGarrett D'Amore } 483*f967d548SGarrett D'Amore rval = 0; 484*f967d548SGarrett D'Amore errno = 0; 485*f967d548SGarrett D'Amore if (signedconv) 486*f967d548SGarrett D'Amore *ip = strtoimax(*gargv, &ep, 0); 487*f967d548SGarrett D'Amore else 488*f967d548SGarrett D'Amore *uip = strtoumax(*gargv, &ep, 0); 489*f967d548SGarrett D'Amore if (ep == *gargv) { 490*f967d548SGarrett D'Amore warnx2(_("%s: expected numeric value"), *gargv, NULL); 491*f967d548SGarrett D'Amore rval = 1; 492*f967d548SGarrett D'Amore } else if (*ep != '\0') { 493*f967d548SGarrett D'Amore warnx2(_("%s: not completely converted"), *gargv, NULL); 494*f967d548SGarrett D'Amore rval = 1; 495*f967d548SGarrett D'Amore } 496*f967d548SGarrett D'Amore if (errno == ERANGE) { 497*f967d548SGarrett D'Amore warnx3("%s: %s", *gargv, strerror(ERANGE)); 498*f967d548SGarrett D'Amore rval = 1; 499*f967d548SGarrett D'Amore } 500*f967d548SGarrett D'Amore ++gargv; 501*f967d548SGarrett D'Amore return (rval); 502*f967d548SGarrett D'Amore } 503*f967d548SGarrett D'Amore 504*f967d548SGarrett D'Amore static int 505*f967d548SGarrett D'Amore getfloating(long double *dp, int mod_ldbl) 506*f967d548SGarrett D'Amore { 507*f967d548SGarrett D'Amore char *ep; 508*f967d548SGarrett D'Amore int rval; 509*f967d548SGarrett D'Amore 510*f967d548SGarrett D'Amore if (!*gargv) { 511*f967d548SGarrett D'Amore *dp = 0.0; 512*f967d548SGarrett D'Amore return (0); 513*f967d548SGarrett D'Amore } 514*f967d548SGarrett D'Amore if (**gargv == '"' || **gargv == '\'') { 515*f967d548SGarrett D'Amore *dp = asciicode(); 516*f967d548SGarrett D'Amore return (0); 517*f967d548SGarrett D'Amore } 518*f967d548SGarrett D'Amore rval = 0; 519*f967d548SGarrett D'Amore errno = 0; 520*f967d548SGarrett D'Amore if (mod_ldbl) 521*f967d548SGarrett D'Amore *dp = strtold(*gargv, &ep); 522*f967d548SGarrett D'Amore else 523*f967d548SGarrett D'Amore *dp = strtod(*gargv, &ep); 524*f967d548SGarrett D'Amore if (ep == *gargv) { 525*f967d548SGarrett D'Amore warnx2(_("%s: expected numeric value"), *gargv, NULL); 526*f967d548SGarrett D'Amore rval = 1; 527*f967d548SGarrett D'Amore } else if (*ep != '\0') { 528*f967d548SGarrett D'Amore warnx2(_("%s: not completely converted"), *gargv, NULL); 529*f967d548SGarrett D'Amore rval = 1; 530*f967d548SGarrett D'Amore } 531*f967d548SGarrett D'Amore if (errno == ERANGE) { 532*f967d548SGarrett D'Amore warnx3("%s: %s", *gargv, strerror(ERANGE)); 533*f967d548SGarrett D'Amore rval = 1; 534*f967d548SGarrett D'Amore } 535*f967d548SGarrett D'Amore ++gargv; 536*f967d548SGarrett D'Amore return (rval); 537*f967d548SGarrett D'Amore } 538*f967d548SGarrett D'Amore 539*f967d548SGarrett D'Amore static int 540*f967d548SGarrett D'Amore asciicode(void) 541*f967d548SGarrett D'Amore { 542*f967d548SGarrett D'Amore int ch; 543*f967d548SGarrett D'Amore 544*f967d548SGarrett D'Amore ch = **gargv; 545*f967d548SGarrett D'Amore if (ch == '\'' || ch == '"') 546*f967d548SGarrett D'Amore ch = (*gargv)[1]; 547*f967d548SGarrett D'Amore ++gargv; 548*f967d548SGarrett D'Amore return (ch); 549*f967d548SGarrett D'Amore } 550*f967d548SGarrett D'Amore 551*f967d548SGarrett D'Amore static void 552*f967d548SGarrett D'Amore usage(void) 553*f967d548SGarrett D'Amore { 554*f967d548SGarrett D'Amore (void) fprintf(stderr, _("usage: printf format [arguments ...]\n")); 555*f967d548SGarrett D'Amore } 556