Imported from ../bash-2.05b.tar.gz.

This commit is contained in:
Jari Aalto 2002-07-17 14:10:11 +00:00
commit 7117c2d221
362 changed files with 34387 additions and 15063 deletions

View file

@ -1,7 +1,7 @@
This file is printf.def, from which is created printf.c.
It implements the builtin "printf" in Bash.
Copyright (C) 1997 Free Software Foundation, Inc.
Copyright (C) 1997-2002 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@ -56,18 +56,17 @@ $END
#include "../bashansi.h"
#define NEED_STRTOIMAX_DECL
#include "../shell.h"
#include "stdc.h"
#include "bashgetopt.h"
#include "common.h"
/* This should use the ISO C constant format strings; I'll do that later. */
#if SIZEOF_LONG < SIZEOF_LONG_LONG
# define INTMAX_CONV "ll"
#else
# define INTMAX_CONV "l"
#if !defined (PRIdMAX)
# if HAVE_LONG_LONG
# define PRIdMAX "lld"
# else
# define PRIdMAX "ld"
# endif
#endif
#if !defined (errno)
@ -104,25 +103,28 @@ extern int errno;
#define SKIP1 "#'-+ 0"
#define LENMODS "hjlLtz"
static void printf_erange __P((char *));
static void printstr __P((char *, char *, int, int, int));
static int tescape __P((char *, int, char *, int *));
static char *bexpand __P((char *, int, int *, int *));
static char *mklong __P((char *, char *));
static char *mklong __P((char *, char *, size_t));
static int getchr __P((void));
static char *getstr __P((void));
static int getint __P((void));
static long getlong __P((void));
static unsigned long getulong __P((void));
#if defined (HAVE_LONG_LONG)
static long long getllong __P((void));
static unsigned long long getullong __P((void));
#endif
static intmax_t getintmax __P((void));
static uintmax_t getuintmax __P((void));
static double getdouble __P((void));
#if defined (HAVE_LONG_DOUBLE) && HAVE_DECL_STRTOLD
static long double getldouble __P((void));
typedef long double floatmax_t;
# define FLOATMAX_CONV "L"
# define strtofltmax strtold
#else
typedef double floatmax_t;
# define FLOATMAX_CONV ""
# define strtofltmax strtod
#endif
static floatmax_t getfloatmax __P((void));
static int asciicode __P((void));
static WORD_LIST *garglist;
@ -138,18 +140,15 @@ printf_builtin (list)
{
int ch, fieldwidth, precision;
int have_fieldwidth, have_precision;
long tw;
intmax_t tw;
char convch, thisch, nextch, *format, *modstart, *fmt, *start;
conversion_error = 0;
retval = EXECUTION_SUCCESS;
reset_internal_getopt ();
if (internal_getopt (list, "") != -1)
{
builtin_usage();
return (EX_USAGE);
}
list = loptend;
if (no_options (list))
return (EX_USAGE);
list = loptend; /* skip over possible `--' */
if (list == 0)
{
@ -288,7 +287,7 @@ printf_builtin (list)
bind_var_to_int (var, tw);
else
{
builtin_error ("%s: invalid variable name", var);
sh_invalidid (var);
PRETURN (EXECUTION_FAILURE);
}
}
@ -322,7 +321,10 @@ printf_builtin (list)
char *p, *xp;
p = getstr ();
xp = sh_backslash_quote (p);
if (ansic_shouldquote (p))
xp = ansic_quote (p, 0, (int *)0);
else
xp = sh_backslash_quote (p);
if (xp)
{
/* Use printstr to get fieldwidth and precision right. */
@ -336,32 +338,23 @@ printf_builtin (list)
case 'i':
{
char *f;
#if defined (HAVE_LONG_LONG)
if (thisch == 'l' && nextch == 'l')
{
long long p;
long p;
intmax_t pp;
p = getllong ();
f = mklong (start, "ll");
PF(f, p);
}
else
#endif
if (thisch == 'j')
p = pp = getintmax ();
if (p != pp)
{
intmax_t p;
p = getintmax ();
f = mklong (start, INTMAX_CONV);
PF(f, p);
f = mklong (start, PRIdMAX, sizeof (PRIdMAX) - 2);
PF (f, pp);
}
else
{
long p;
p = getlong ();
f = mklong (start, "l");
PF(f, p);
/* Optimize the common case where the integer fits
in "long". This also works around some long
long and/or intmax_t library bugs in the common
case, e.g. glibc 2.2 x86. */
f = mklong (start, "l", 1);
PF (f, p);
}
break;
}
@ -372,31 +365,18 @@ printf_builtin (list)
case 'X':
{
char *f;
#if defined (HAVE_LONG_LONG)
if (thisch == 'l' && nextch == 'l')
{
unsigned long long p;
unsigned long p;
uintmax_t pp;
p = getullong ();
f = mklong (start, "ll");
PF(f, p);
}
else
#endif
if (thisch == 'j')
p = pp = getuintmax ();
if (p != pp)
{
uintmax_t p;
p = getuintmax ();
f = mklong (start, INTMAX_CONV);
PF(f, p);
f = mklong (start, PRIdMAX, sizeof (PRIdMAX) - 2);
PF (f, pp);
}
else
{
unsigned long p;
p = getulong ();
f = mklong (start, "l");
f = mklong (start, "l", 1);
PF (f, p);
}
break;
@ -414,24 +394,11 @@ printf_builtin (list)
#endif
{
char *f;
#if defined (HAVE_LONG_DOUBLE) && HAVE_DECL_STRTOLD
if (thisch == 'L')
{
long double p;
floatmax_t p;
p = getldouble ();
f = mklong (start, "L");
PF (f, p);
}
else
#endif
{
double p;
p = getdouble ();
f = mklong (start, "");
PF (f, p);
}
p = getfloatmax ();
f = mklong (start, FLOATMAX_CONV, sizeof(FLOATMAX_CONV) - 1);
PF (f, p);
break;
}
@ -454,6 +421,13 @@ printf_builtin (list)
PRETURN (retval);
}
static void
printf_erange (s)
char *s;
{
builtin_error ("warning: %s: %s", s, strerror(ERANGE));
}
/* We duplicate a lot of what printf(3) does here. */
static void
printstr (fmt, string, len, fieldwidth, precision)
@ -605,16 +579,11 @@ tescape (estart, trans_squote, cp, sawc)
/* %b octal constants are `\0' followed by one, two, or three
octal digits... */
case '0':
for (temp = 3, evalue = 0; ISOCTAL (*p) && temp--; p++)
evalue = (evalue * 8) + OCTVALUE (*p);
*cp = evalue & 0xFF;
break;
/* but, as an extension, the other echo-like octal escape
sequences are supported as well. */
case '1': case '2': case '3': case '4':
case '5': case '6': case '7':
for (temp = 2, evalue = c - '0'; ISOCTAL (*p) && temp--; p++)
for (temp = 2+(c=='0'), evalue = c - '0'; ISOCTAL (*p) && temp--; p++)
evalue = (evalue * 8) + OCTVALUE (*p);
*cp = evalue & 0xFF;
break;
@ -706,14 +675,14 @@ bexpand (string, len, sawc, lenp)
}
static char *
mklong (str, modifiers)
mklong (str, modifiers, mlen)
char *str;
char *modifiers;
size_t mlen;
{
size_t len, slen, mlen;
size_t len, slen;
slen = strlen (str);
mlen = strlen (modifiers);
len = slen + mlen + 1;
if (len > conv_bufsize)
@ -759,152 +728,24 @@ getstr ()
static int
getint ()
{
long ret;
intmax_t ret;
ret = getlong ();
ret = getintmax ();
if (ret > INT_MAX)
{
builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE));
printf_erange (garglist->word->word);
ret = INT_MAX;
}
else if (ret < INT_MIN)
{
builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE));
printf_erange (garglist->word->word);
ret = INT_MIN;
}
return ((int)ret);
}
static long
getlong ()
{
long ret;
char *ep;
if (garglist == 0)
return (0);
if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
return asciicode ();
errno = 0;
ret = strtol (garglist->word->word, &ep, 0);
if (*ep)
{
builtin_error ("%s: invalid number", garglist->word->word);
/* POSIX.2 says ``...a diagnostic message shall be written to standard
error, and the utility shall not exit with a zero exit status, but
shall continue processing any remaining operands and shall write the
value accumulated at the time the error was detected to standard
output.'' Yecch. */
ret = 0;
conversion_error = 1;
}
else if (errno == ERANGE)
builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE));
garglist = garglist->next;
return (ret);
}
static unsigned long
getulong ()
{
unsigned long ret;
char *ep;
if (garglist == 0)
return (0);
if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
return asciicode ();
errno = 0;
ret = strtoul (garglist->word->word, &ep, 0);
if (*ep)
{
builtin_error ("%s: invalid number", garglist->word->word);
/* Same thing about POSIX.2 conversion error requirements as getlong(). */
ret = 0;
conversion_error = 1;
}
else if (errno == ERANGE)
builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE));
garglist = garglist->next;
return (ret);
}
#if defined (HAVE_LONG_LONG)
static long long
getllong ()
{
long long ret;
char *ep;
if (garglist == 0)
return (0);
if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
return asciicode ();
errno = 0;
ret = strtoll (garglist->word->word, &ep, 0);
if (*ep)
{
builtin_error ("%s: invalid number", garglist->word->word);
/* POSIX.2 says ``...a diagnostic message shall be written to standard
error, and the utility shall not exit with a zero exit status, but
shall continue processing any remaining operands and shall write the
value accumulated at the time the error was detected to standard
output.'' Yecch. */
ret = 0;
conversion_error = 1;
}
else if (errno == ERANGE)
builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE));
garglist = garglist->next;
return (ret);
}
static unsigned long long
getullong ()
{
unsigned long long ret;
char *ep;
if (garglist == 0)
return (0);
if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
return asciicode ();
errno = 0;
ret = strtoull (garglist->word->word, &ep, 0);
if (*ep)
{
builtin_error ("%s: invalid number", garglist->word->word);
/* Same thing about POSIX.2 conversion error requirements as getlong(). */
ret = 0;
conversion_error = 1;
}
else if (errno == ERANGE)
builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE));
garglist = garglist->next;
return (ret);
}
#endif /* HAVE_LONG_LONG */
static intmax_t
getintmax ()
{
@ -922,7 +763,7 @@ getintmax ()
if (*ep)
{
builtin_error ("%s: invalid number", garglist->word->word);
sh_invalidnum (garglist->word->word);
/* POSIX.2 says ``...a diagnostic message shall be written to standard
error, and the utility shall not exit with a zero exit status, but
shall continue processing any remaining operands and shall write the
@ -932,7 +773,7 @@ getintmax ()
conversion_error = 1;
}
else if (errno == ERANGE)
builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE));
printf_erange (garglist->word->word);
garglist = garglist->next;
return (ret);
@ -955,22 +796,22 @@ getuintmax ()
if (*ep)
{
builtin_error ("%s: invalid number", garglist->word->word);
/* Same thing about POSIX.2 conversion error requirements as getlong(). */
sh_invalidnum (garglist->word->word);
/* Same POSIX.2 conversion error requirements as getintmax(). */
ret = 0;
conversion_error = 1;
}
else if (errno == ERANGE)
builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE));
printf_erange (garglist->word->word);
garglist = garglist->next;
return (ret);
}
static double
getdouble ()
static floatmax_t
getfloatmax ()
{
double ret;
floatmax_t ret;
char *ep;
if (garglist == 0)
@ -980,53 +821,22 @@ getdouble ()
return asciicode ();
errno = 0;
ret = strtod (garglist->word->word, &ep);
ret = strtofltmax (garglist->word->word, &ep);
if (*ep)
{
builtin_error ("%s: invalid number", garglist->word->word);
sh_invalidnum (garglist->word->word);
/* Same thing about POSIX.2 conversion error requirements. */
ret = 0;
conversion_error = 1;
}
else if (errno == ERANGE)
builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE));
printf_erange (garglist->word->word);
garglist = garglist->next;
return (ret);
}
#if defined (HAVE_LONG_DOUBLE) && HAVE_DECL_STRTOLD
static long double
getldouble ()
{
long double ret;
char *ep;
if (garglist == 0)
return (0);
if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
return (asciicode ());
errno = 0;
ret = strtold (garglist->word->word, &ep);
if (*ep)
{
builtin_error ("%s: invalid number", garglist->word->word);
/* Same thing about POSIX.2 conversion error requirements. */
ret = 0;
conversion_error = 1;
}
else if (errno == ERANGE)
builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE));
garglist = garglist->next;
return (ret);
}
#endif /* HAVE_LONG_DOUBLE && HAVE_DECL_STRTOLD */
/* NO check is needed for garglist here. */
static int
asciicode ()