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