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