1/* printf.c, created from printf.def. */ 2#line 23 "printf.def" 3 4#line 38 "printf.def" 5 6#include <config.h> 7 8#include "../bashtypes.h" 9 10#include <errno.h> 11#if defined (HAVE_LIMITS_H) 12# include <limits.h> 13#else 14 /* Assume 32-bit ints. */ 15# define INT_MAX 2147483647 16# define INT_MIN (-2147483647-1) 17#endif 18 19#if defined (PREFER_STDARG) 20# include <stdarg.h> 21#else 22# include <varargs.h> 23#endif 24 25#include <stdio.h> 26#include <chartypes.h> 27 28#ifdef HAVE_INTTYPES_H 29# include <inttypes.h> 30#endif 31 32#include "../bashansi.h" 33#include "../bashintl.h" 34 35#include "../shell.h" 36#include "stdc.h" 37#include "bashgetopt.h" 38#include "common.h" 39 40#if defined (PRI_MACROS_BROKEN) 41# undef PRIdMAX 42#endif 43 44#if !defined (PRIdMAX) 45# if HAVE_LONG_LONG 46# define PRIdMAX "lld" 47# else 48# define PRIdMAX "ld" 49# endif 50#endif 51 52#if !defined (errno) 53extern int errno; 54#endif 55 56#define PC(c) \ 57 do { \ 58 char b[2]; \ 59 tw++; \ 60 b[0] = c; b[1] = '\0'; \ 61 if (vflag) \ 62 vbadd (b, 1); \ 63 else \ 64 putchar (c); \ 65 } while (0) 66 67#define PF(f, func) \ 68 do { \ 69 char *b = 0; \ 70 int nw; \ 71 clearerr (stdout); \ 72 if (have_fieldwidth && have_precision) \ 73 nw = asprintf(&b, f, fieldwidth, precision, func); \ 74 else if (have_fieldwidth) \ 75 nw = asprintf(&b, f, fieldwidth, func); \ 76 else if (have_precision) \ 77 nw = asprintf(&b, f, precision, func); \ 78 else \ 79 nw = asprintf(&b, f, func); \ 80 tw += nw; \ 81 if (b) \ 82 { \ 83 if (vflag) \ 84 (void)vbadd (b, nw); \ 85 else \ 86 (void)fputs (b, stdout); \ 87 if (ferror (stdout)) \ 88 { \ 89 sh_wrerror (); \ 90 clearerr (stdout); \ 91 return (EXECUTION_FAILURE); \ 92 } \ 93 free (b); \ 94 } \ 95 } while (0) 96 97/* We free the buffer used by mklong() if it's `too big'. */ 98#define PRETURN(value) \ 99 do \ 100 { \ 101 if (vflag) \ 102 { \ 103 bind_variable (vname, vbuf, 0); \ 104 stupidly_hack_special_variables (vname); \ 105 } \ 106 if (conv_bufsize > 4096 ) \ 107 { \ 108 free (conv_buf); \ 109 conv_bufsize = 0; \ 110 conv_buf = 0; \ 111 } \ 112 if (vbsize > 4096) \ 113 { \ 114 free (vbuf); \ 115 vbsize = 0; \ 116 vbuf = 0; \ 117 } \ 118 fflush (stdout); \ 119 if (ferror (stdout)) \ 120 { \ 121 clearerr (stdout); \ 122 return (EXECUTION_FAILURE); \ 123 } \ 124 return (value); \ 125 } \ 126 while (0) 127 128#define SKIP1 "#'-+ 0" 129#define LENMODS "hjlLtz" 130 131#ifndef HAVE_ASPRINTF 132extern int asprintf __P((char **, const char *, ...)) __attribute__((__format__ (printf, 2, 3))); 133#endif 134 135static void printf_erange __P((char *)); 136static int printstr __P((char *, char *, int, int, int)); 137static int tescape __P((char *, char *, int *)); 138static char *bexpand __P((char *, int, int *, int *)); 139static char *vbadd __P((char *, int)); 140static char *mklong __P((char *, char *, size_t)); 141static int getchr __P((void)); 142static char *getstr __P((void)); 143static int getint __P((void)); 144static intmax_t getintmax __P((void)); 145static uintmax_t getuintmax __P((void)); 146 147#if defined (HAVE_LONG_DOUBLE) && HAVE_DECL_STRTOLD && !defined(STRTOLD_BROKEN) 148typedef long double floatmax_t; 149# define FLOATMAX_CONV "L" 150# define strtofltmax strtold 151#else 152typedef double floatmax_t; 153# define FLOATMAX_CONV "" 154# define strtofltmax strtod 155#endif 156static floatmax_t getfloatmax __P((void)); 157 158static int asciicode __P((void)); 159 160static WORD_LIST *garglist; 161static int retval; 162static int conversion_error; 163 164/* printf -v var support */ 165static int vflag = 0; 166static char *vbuf, *vname; 167static size_t vbsize; 168static int vblen; 169 170static intmax_t tw; 171 172static char *conv_buf; 173static size_t conv_bufsize; 174 175int 176printf_builtin (list) 177 WORD_LIST *list; 178{ 179 int ch, fieldwidth, precision; 180 int have_fieldwidth, have_precision; 181 char convch, thisch, nextch, *format, *modstart, *fmt, *start; 182 183 conversion_error = 0; 184 retval = EXECUTION_SUCCESS; 185 186 vflag = 0; 187 188 reset_internal_getopt (); 189 while ((ch = internal_getopt (list, "v:")) != -1) 190 { 191 switch (ch) 192 { 193 case 'v': 194 if (legal_identifier (vname = list_optarg)) 195 { 196 vflag = 1; 197 vblen = 0; 198 } 199 else 200 { 201 sh_invalidid (vname); 202 return (EX_USAGE); 203 } 204 break; 205 default: 206 builtin_usage (); 207 return (EX_USAGE); 208 } 209 } 210 list = loptend; /* skip over possible `--' */ 211 212 if (list == 0) 213 { 214 builtin_usage (); 215 return (EX_USAGE); 216 } 217 218 if (list->word->word == 0 || list->word->word[0] == '\0') 219 return (EXECUTION_SUCCESS); 220 221 format = list->word->word; 222 tw = 0; 223 224 garglist = list->next; 225 226 /* If the format string is empty after preprocessing, return immediately. */ 227 if (format == 0 || *format == 0) 228 return (EXECUTION_SUCCESS); 229 230 /* Basic algorithm is to scan the format string for conversion 231 specifications -- once one is found, find out if the field 232 width or precision is a '*'; if it is, gather up value. Note, 233 format strings are reused as necessary to use up the provided 234 arguments, arguments of zero/null string are provided to use 235 up the format string. */ 236 do 237 { 238 tw = 0; 239 /* find next format specification */ 240 for (fmt = format; *fmt; fmt++) 241 { 242 precision = fieldwidth = 0; 243 have_fieldwidth = have_precision = 0; 244 245 if (*fmt == '\\') 246 { 247 fmt++; 248 /* A NULL third argument to tescape means to bypass the 249 special processing for arguments to %b. */ 250 fmt += tescape (fmt, &nextch, (int *)NULL); 251 PC (nextch); 252 fmt--; /* for loop will increment it for us again */ 253 continue; 254 } 255 256 if (*fmt != '%') 257 { 258 PC (*fmt); 259 continue; 260 } 261 262 /* ASSERT(*fmt == '%') */ 263 start = fmt++; 264 265 if (*fmt == '%') /* %% prints a % */ 266 { 267 PC ('%'); 268 continue; 269 } 270 271 /* found format specification, skip to field width */ 272 for (; *fmt && strchr(SKIP1, *fmt); ++fmt) 273 ; 274 275 /* Skip optional field width. */ 276 if (*fmt == '*') 277 { 278 fmt++; 279 have_fieldwidth = 1; 280 fieldwidth = getint (); 281 } 282 else 283 while (DIGIT (*fmt)) 284 fmt++; 285 286 /* Skip optional '.' and precision */ 287 if (*fmt == '.') 288 { 289 ++fmt; 290 if (*fmt == '*') 291 { 292 fmt++; 293 have_precision = 1; 294 precision = getint (); 295 } 296 else 297 { 298 /* Negative precisions are allowed but treated as if the 299 precision were missing; I would like to allow a leading 300 `+' in the precision number as an extension, but lots 301 of asprintf/fprintf implementations get this wrong. */ 302#if 0 303 if (*fmt == '-' || *fmt == '+') 304#else 305 if (*fmt == '-') 306#endif 307 fmt++; 308 while (DIGIT (*fmt)) 309 fmt++; 310 } 311 } 312 313 /* skip possible format modifiers */ 314 modstart = fmt; 315 while (*fmt && strchr (LENMODS, *fmt)) 316 fmt++; 317 318 if (*fmt == 0) 319 { 320 builtin_error (_("`%s': missing format character"), start); 321 PRETURN (EXECUTION_FAILURE); 322 } 323 324 convch = *fmt; 325 thisch = modstart[0]; 326 nextch = modstart[1]; 327 modstart[0] = convch; 328 modstart[1] = '\0'; 329 330 switch(convch) 331 { 332 case 'c': 333 { 334 char p; 335 336 p = getchr (); 337 PF(start, p); 338 break; 339 } 340 341 case 's': 342 { 343 char *p; 344 345 p = getstr (); 346 PF(start, p); 347 break; 348 } 349 350 case 'n': 351 { 352 char *var; 353 354 var = getstr (); 355 if (var && *var) 356 { 357 if (legal_identifier (var)) 358 bind_var_to_int (var, tw); 359 else 360 { 361 sh_invalidid (var); 362 PRETURN (EXECUTION_FAILURE); 363 } 364 } 365 break; 366 } 367 368 case 'b': /* expand escapes in argument */ 369 { 370 char *p, *xp; 371 int rlen, r; 372 373 p = getstr (); 374 ch = rlen = r = 0; 375 xp = bexpand (p, strlen (p), &ch, &rlen); 376 377 if (xp) 378 { 379 /* Have to use printstr because of possible NUL bytes 380 in XP -- printf does not handle that well. */ 381 r = printstr (start, xp, rlen, fieldwidth, precision); 382 if (r < 0) 383 { 384 sh_wrerror (); 385 clearerr (stdout); 386 retval = EXECUTION_FAILURE; 387 } 388 free (xp); 389 } 390 391 if (ch || r < 0) 392 PRETURN (retval); 393 break; 394 } 395 396 case 'q': /* print with shell quoting */ 397 { 398 char *p, *xp; 399 int r; 400 401 r = 0; 402 p = getstr (); 403 if (p && *p == 0) /* XXX - getstr never returns null */ 404 xp = savestring ("''"); 405 else if (ansic_shouldquote (p)) 406 xp = ansic_quote (p, 0, (int *)0); 407 else 408 xp = sh_backslash_quote (p); 409 if (xp) 410 { 411 /* Use printstr to get fieldwidth and precision right. */ 412 r = printstr (start, xp, strlen (xp), fieldwidth, precision); 413 if (r < 0) 414 { 415 sh_wrerror (); 416 clearerr (stdout); 417 } 418 free (xp); 419 } 420 421 if (r < 0) 422 PRETURN (EXECUTION_FAILURE); 423 break; 424 } 425 426 case 'd': 427 case 'i': 428 { 429 char *f; 430 long p; 431 intmax_t pp; 432 433 p = pp = getintmax (); 434 if (p != pp) 435 { 436 f = mklong (start, PRIdMAX, sizeof (PRIdMAX) - 2); 437 PF (f, pp); 438 } 439 else 440 { 441 /* Optimize the common case where the integer fits 442 in "long". This also works around some long 443 long and/or intmax_t library bugs in the common 444 case, e.g. glibc 2.2 x86. */ 445 f = mklong (start, "l", 1); 446 PF (f, p); 447 } 448 break; 449 } 450 451 case 'o': 452 case 'u': 453 case 'x': 454 case 'X': 455 { 456 char *f; 457 unsigned long p; 458 uintmax_t pp; 459 460 p = pp = getuintmax (); 461 if (p != pp) 462 { 463 f = mklong (start, PRIdMAX, sizeof (PRIdMAX) - 2); 464 PF (f, pp); 465 } 466 else 467 { 468 f = mklong (start, "l", 1); 469 PF (f, p); 470 } 471 break; 472 } 473 474 case 'e': 475 case 'E': 476 case 'f': 477 case 'F': 478 case 'g': 479 case 'G': 480#if defined (HAVE_PRINTF_A_FORMAT) 481 case 'a': 482 case 'A': 483#endif 484 { 485 char *f; 486 floatmax_t p; 487 488 p = getfloatmax (); 489 f = mklong (start, FLOATMAX_CONV, sizeof(FLOATMAX_CONV) - 1); 490 PF (f, p); 491 break; 492 } 493 494 /* We don't output unrecognized format characters; we print an 495 error message and return a failure exit status. */ 496 default: 497 builtin_error (_("`%c': invalid format character"), convch); 498 PRETURN (EXECUTION_FAILURE); 499 } 500 501 modstart[0] = thisch; 502 modstart[1] = nextch; 503 } 504 505 if (ferror (stdout)) 506 { 507 sh_wrerror (); 508 clearerr (stdout); 509 PRETURN (EXECUTION_FAILURE); 510 } 511 } 512 while (garglist && garglist != list->next); 513 514 if (conversion_error) 515 retval = EXECUTION_FAILURE; 516 517 PRETURN (retval); 518} 519 520static void 521printf_erange (s) 522 char *s; 523{ 524 builtin_error ("warning: %s: %s", s, strerror(ERANGE)); 525} 526 527/* We duplicate a lot of what printf(3) does here. */ 528static int 529printstr (fmt, string, len, fieldwidth, precision) 530 char *fmt; /* format */ 531 char *string; /* expanded string argument */ 532 int len; /* length of expanded string */ 533 int fieldwidth; /* argument for width of `*' */ 534 int precision; /* argument for precision of `*' */ 535{ 536#if 0 537 char *s; 538#endif 539 int padlen, nc, ljust, i; 540 int fw, pr; /* fieldwidth and precision */ 541 542#if 0 543 if (string == 0 || *string == '\0') 544#else 545 if (string == 0 || len == 0) 546#endif 547 return 0; 548 549#if 0 550 s = fmt; 551#endif 552 if (*fmt == '%') 553 fmt++; 554 555 ljust = fw = 0; 556 pr = -1; 557 558 /* skip flags */ 559 while (strchr (SKIP1, *fmt)) 560 { 561 if (*fmt == '-') 562 ljust = 1; 563 fmt++; 564 } 565 566 /* get fieldwidth, if present */ 567 if (*fmt == '*') 568 { 569 fmt++; 570 fw = fieldwidth; 571 if (fw < 0) 572 { 573 fw = -fw; 574 ljust = 1; 575 } 576 } 577 else if (DIGIT (*fmt)) 578 { 579 fw = *fmt++ - '0'; 580 while (DIGIT (*fmt)) 581 fw = (fw * 10) + (*fmt++ - '0'); 582 } 583 584 /* get precision, if present */ 585 if (*fmt == '.') 586 { 587 fmt++; 588 if (*fmt == '*') 589 { 590 fmt++; 591 pr = precision; 592 } 593 else if (DIGIT (*fmt)) 594 { 595 pr = *fmt++ - '0'; 596 while (DIGIT (*fmt)) 597 pr = (pr * 10) + (*fmt++ - '0'); 598 } 599 } 600 601#if 0 602 /* If we remove this, get rid of `s'. */ 603 if (*fmt != 'b' && *fmt != 'q') 604 { 605 internal_error ("format parsing problem: %s", s); 606 fw = pr = 0; 607 } 608#endif 609 610 /* chars from string to print */ 611 nc = (pr >= 0 && pr <= len) ? pr : len; 612 613 padlen = fw - nc; 614 if (padlen < 0) 615 padlen = 0; 616 if (ljust) 617 padlen = -padlen; 618 619 /* leading pad characters */ 620 for (; padlen > 0; padlen--) 621 PC (' '); 622 623 /* output NC characters from STRING */ 624 for (i = 0; i < nc; i++) 625 PC (string[i]); 626 627 /* output any necessary trailing padding */ 628 for (; padlen < 0; padlen++) 629 PC (' '); 630 631 return (ferror (stdout) ? -1 : 0); 632} 633 634/* Convert STRING by expanding the escape sequences specified by the 635 POSIX standard for printf's `%b' format string. If SAWC is non-null, 636 perform the processing appropriate for %b arguments. In particular, 637 recognize `\c' and use that as a string terminator. If we see \c, set 638 *SAWC to 1 before returning. LEN is the length of STRING. */ 639 640/* Translate a single backslash-escape sequence starting at ESTART (the 641 character after the backslash) and return the number of characters 642 consumed by the sequence. CP is the place to return the translated 643 value. *SAWC is set to 1 if the escape sequence was \c, since that means 644 to short-circuit the rest of the processing. If SAWC is null, we don't 645 do the \c short-circuiting, and \c is treated as an unrecognized escape 646 sequence; we also bypass the other processing specific to %b arguments. */ 647static int 648tescape (estart, cp, sawc) 649 char *estart; 650 char *cp; 651 int *sawc; 652{ 653 register char *p; 654 int temp, c, evalue; 655 656 p = estart; 657 658 switch (c = *p++) 659 { 660#if defined (__STDC__) 661 case 'a': *cp = '\a'; break; 662#else 663 case 'a': *cp = '\007'; break; 664#endif 665 666 case 'b': *cp = '\b'; break; 667 668 case 'e': 669 case 'E': *cp = '\033'; break; /* ESC -- non-ANSI */ 670 671 case 'f': *cp = '\f'; break; 672 673 case 'n': *cp = '\n'; break; 674 675 case 'r': *cp = '\r'; break; 676 677 case 't': *cp = '\t'; break; 678 679 case 'v': *cp = '\v'; break; 680 681 /* The octal escape sequences are `\0' followed by up to three octal 682 digits (if SAWC), or `\' followed by up to three octal digits (if 683 !SAWC). As an extension, we allow the latter form even if SAWC. */ 684 case '0': case '1': case '2': case '3': 685 case '4': case '5': case '6': case '7': 686 evalue = OCTVALUE (c); 687 for (temp = 2 + (!evalue && !!sawc); ISOCTAL (*p) && temp--; p++) 688 evalue = (evalue * 8) + OCTVALUE (*p); 689 *cp = evalue & 0xFF; 690 break; 691 692 /* And, as another extension, we allow \xNNN, where each N is a 693 hex digit. */ 694 case 'x': 695#if 0 696 for (evalue = 0; ISXDIGIT ((unsigned char)*p); p++) 697#else 698 for (temp = 2, evalue = 0; ISXDIGIT ((unsigned char)*p) && temp--; p++) 699#endif 700 evalue = (evalue * 16) + HEXVALUE (*p); 701 if (p == estart + 1) 702 { 703 builtin_error (_("missing hex digit for \\x")); 704 *cp = '\\'; 705 return 0; 706 } 707 *cp = evalue & 0xFF; 708 break; 709 710 case '\\': /* \\ -> \ */ 711 *cp = c; 712 break; 713 714 /* SAWC == 0 means that \', \", and \? are recognized as escape 715 sequences, though the only processing performed is backslash 716 removal. */ 717 case '\'': case '"': case '?': 718 if (!sawc) 719 *cp = c; 720 else 721 { 722 *cp = '\\'; 723 return 0; 724 } 725 break; 726 727 case 'c': 728 if (sawc) 729 { 730 *sawc = 1; 731 break; 732 } 733 /* other backslash escapes are passed through unaltered */ 734 default: 735 *cp = '\\'; 736 return 0; 737 } 738 return (p - estart); 739} 740 741static char * 742bexpand (string, len, sawc, lenp) 743 char *string; 744 int len, *sawc, *lenp; 745{ 746 int temp; 747 char *ret, *r, *s, c; 748 749#if 0 750 if (string == 0 || *string == '\0') 751#else 752 if (string == 0 || len == 0) 753#endif 754 { 755 if (sawc) 756 *sawc = 0; 757 if (lenp) 758 *lenp = 0; 759 return ((char *)NULL); 760 } 761 762 ret = (char *)xmalloc (len + 1); 763 for (r = ret, s = string; s && *s; ) 764 { 765 c = *s++; 766 if (c != '\\' || *s == '\0') 767 { 768 *r++ = c; 769 continue; 770 } 771 temp = 0; 772 s += tescape (s, &c, &temp); 773 if (temp) 774 { 775 if (sawc) 776 *sawc = 1; 777 break; 778 } 779 780 *r++ = c; 781 } 782 783 *r = '\0'; 784 if (lenp) 785 *lenp = r - ret; 786 return ret; 787} 788 789static char * 790vbadd (buf, blen) 791 char *buf; 792 int blen; 793{ 794 size_t nlen; 795 796 nlen = vblen + blen + 1; 797 if (nlen >= vbsize) 798 { 799 vbsize = ((nlen + 63) >> 6) << 6; 800 vbuf = (char *)xrealloc (vbuf, vbsize); 801 } 802 803 if (blen == 1) 804 vbuf[vblen++] = buf[0]; 805 else 806 { 807 FASTCOPY (buf, vbuf + vblen, blen); 808 vblen += blen; 809 } 810 vbuf[vblen] = '\0'; 811 812#ifdef DEBUG 813 if (strlen (vbuf) != vblen) 814 internal_error ("printf:vbadd: vblen (%d) != strlen (vbuf) (%d)", vblen, (int)strlen (vbuf)); 815#endif 816 817 return vbuf; 818} 819 820static char * 821mklong (str, modifiers, mlen) 822 char *str; 823 char *modifiers; 824 size_t mlen; 825{ 826 size_t len, slen; 827 828 slen = strlen (str); 829 len = slen + mlen + 1; 830 831 if (len > conv_bufsize) 832 { 833 conv_bufsize = (((len + 1023) >> 10) << 10); 834 conv_buf = (char *)xrealloc (conv_buf, conv_bufsize); 835 } 836 837 FASTCOPY (str, conv_buf, slen - 1); 838 FASTCOPY (modifiers, conv_buf + slen - 1, mlen); 839 840 conv_buf[len - 2] = str[slen - 1]; 841 conv_buf[len - 1] = '\0'; 842 return (conv_buf); 843} 844 845static int 846getchr () 847{ 848 int ret; 849 850 if (garglist == 0) 851 return ('\0'); 852 853 ret = (int)garglist->word->word[0]; 854 garglist = garglist->next; 855 return ret; 856} 857 858static char * 859getstr () 860{ 861 char *ret; 862 863 if (garglist == 0) 864 return (""); 865 866 ret = garglist->word->word; 867 garglist = garglist->next; 868 return ret; 869} 870 871static int 872getint () 873{ 874 intmax_t ret; 875 876 ret = getintmax (); 877 878 if (ret > INT_MAX) 879 { 880 printf_erange (garglist->word->word); 881 ret = INT_MAX; 882 } 883 else if (ret < INT_MIN) 884 { 885 printf_erange (garglist->word->word); 886 ret = INT_MIN; 887 } 888 889 return ((int)ret); 890} 891 892static intmax_t 893getintmax () 894{ 895 intmax_t ret; 896 char *ep; 897 898 if (garglist == 0) 899 return (0); 900 901 if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"') 902 return asciicode (); 903 904 errno = 0; 905 ret = strtoimax (garglist->word->word, &ep, 0); 906 907 if (*ep) 908 { 909 sh_invalidnum (garglist->word->word); 910 /* POSIX.2 says ``...a diagnostic message shall be written to standard 911 error, and the utility shall not exit with a zero exit status, but 912 shall continue processing any remaining operands and shall write the 913 value accumulated at the time the error was detected to standard 914 output.'' Yecch. */ 915 ret = 0; 916 conversion_error = 1; 917 } 918 else if (errno == ERANGE) 919 printf_erange (garglist->word->word); 920 921 garglist = garglist->next; 922 return (ret); 923} 924 925static uintmax_t 926getuintmax () 927{ 928 uintmax_t ret; 929 char *ep; 930 931 if (garglist == 0) 932 return (0); 933 934 if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"') 935 return asciicode (); 936 937 errno = 0; 938 ret = strtoumax (garglist->word->word, &ep, 0); 939 940 if (*ep) 941 { 942 sh_invalidnum (garglist->word->word); 943 /* Same POSIX.2 conversion error requirements as getintmax(). */ 944 ret = 0; 945 conversion_error = 1; 946 } 947 else if (errno == ERANGE) 948 printf_erange (garglist->word->word); 949 950 garglist = garglist->next; 951 return (ret); 952} 953 954static floatmax_t 955getfloatmax () 956{ 957 floatmax_t ret; 958 char *ep; 959 960 if (garglist == 0) 961 return (0); 962 963 if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"') 964 return asciicode (); 965 966 errno = 0; 967 ret = strtofltmax (garglist->word->word, &ep); 968 969 if (*ep) 970 { 971 sh_invalidnum (garglist->word->word); 972 /* Same thing about POSIX.2 conversion error requirements. */ 973 ret = 0; 974 conversion_error = 1; 975 } 976 else if (errno == ERANGE) 977 printf_erange (garglist->word->word); 978 979 garglist = garglist->next; 980 return (ret); 981} 982 983/* NO check is needed for garglist here. */ 984static int 985asciicode () 986{ 987 register int ch; 988 989 ch = garglist->word->word[1]; 990 garglist = garglist->next; 991 return (ch); 992} 993