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