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

This commit is contained in:
Jari Aalto 2001-11-13 17:56:06 +00:00
commit f73dda092b
303 changed files with 37069 additions and 28812 deletions

View file

@ -42,20 +42,33 @@ $END
#if defined (HAVE_LIMITS_H)
# include <limits.h>
#else
/* Assume 32-bit ints and longs. */
# define LONG_MAX 2147483647L
# define LONG_MIN (-2147483647L-1)
/* Assume 32-bit ints. */
# define INT_MAX 2147483647
# define INT_MIN (-2147483647-1)
#endif
#include <stdio.h>
#include <ctype.h>
#include <chartypes.h>
#ifdef HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#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"
#endif
#if !defined (errno)
extern int errno;
@ -63,57 +76,78 @@ extern int errno;
#define PF(f, func) \
do { \
if (fieldwidth && precision) \
(void)printf(f, fieldwidth, precision, func); \
else if (fieldwidth && precision == 0) \
(void)printf(f, fieldwidth, func); \
else if (precision) \
(void)printf(f, precision, func); \
if (have_fieldwidth && have_precision) \
tw += printf(f, fieldwidth, precision, func); \
else if (have_fieldwidth) \
tw += printf(f, fieldwidth, func); \
else if (have_precision) \
tw += printf(f, precision, func); \
else \
(void)printf(f, func); \
tw += printf(f, func); \
} while (0)
/* We free the buffer used by mklong() if it's `too big'. */
#define PRETURN(value) \
do { /* free (format); */ fflush (stdout); return (value); } while (0)
do \
{ \
if (conv_bufsize > 4096 ) \
{ \
free(conv_buf); \
conv_bufsize = 0; \
conv_buf = 0; \
} \
fflush (stdout); \
return (value); \
} \
while (0)
#define SKIP1 "#-+ 0"
#define SKIP2 "*0123456789"
#define SKIP1 "#'-+ 0"
#define LENMODS "hjlLtz"
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 *, int));
static char *mklong __P((char *, char *));
static int getchr __P((void));
static char *getstr __P((void));
static int getint __P((void));
static int getlong __P((long *));
static int getulong __P((unsigned long *));
static int getdouble __P((double *));
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));
#endif
static int asciicode __P((void));
static WORD_LIST *garglist;
static int retval;
static int conversion_error;
extern char *sh_backslash_quote ();
static char *conv_buf;
static size_t conv_bufsize;
int
printf_builtin (list)
WORD_LIST *list;
{
int ch, end, fieldwidth, precision, foundmod, fmtlen;
char convch, nextch, *format, *fmt, *start;
int ch, fieldwidth, precision;
int have_fieldwidth, have_precision;
long tw;
char convch, thisch, nextch, *format, *modstart, *fmt, *start;
conversion_error = 0;
retval = EXECUTION_SUCCESS;
reset_internal_getopt ();
while ((ch = internal_getopt (list, "")) != -1)
if (internal_getopt (list, "") != -1)
{
switch (ch)
{
case '?':
default:
builtin_usage();
return (EX_USAGE);
}
builtin_usage();
return (EX_USAGE);
}
list = loptend;
@ -140,18 +174,20 @@ printf_builtin (list)
format strings are reused as necessary to use up the provided
arguments, arguments of zero/null string are provided to use
up the format string. */
do
{
tw = 0;
/* find next format specification */
for (fmt = format; *fmt; fmt++)
{
precision = fieldwidth = foundmod = 0;
precision = fieldwidth = 0;
have_fieldwidth = have_precision = 0;
if (*fmt == '\\')
{
fmt++;
/* A NULL third argument to tescape means to not do special
/* A NULL fourth argument to tescape means to not do special
processing for \c. */
fmt += tescape (fmt, 1, &nextch, (int *)NULL);
putchar (nextch);
@ -177,27 +213,37 @@ printf_builtin (list)
/* found format specification, skip to field width */
for (; *fmt && strchr(SKIP1, *fmt); ++fmt)
;
fieldwidth = (*fmt == '*') ? getint () : 0;
/* skip to possible '.', get following precision */
for (; *fmt && strchr(SKIP2, *fmt); ++fmt)
;
/* Skip optional field width. */
if (*fmt == '*')
{
fmt++;
have_fieldwidth = 1;
fieldwidth = getint ();
}
else
while (DIGIT (*fmt))
fmt++;
/* Skip optional '.' and precision */
if (*fmt == '.')
{
++fmt;
precision = (*fmt == '*') ? getint () : 0;
if (*fmt == '*')
{
fmt++;
have_precision = 1;
precision = getint ();
}
else
while (DIGIT (*fmt))
fmt++;
}
/* skip to conversion char */
for (; *fmt && strchr(SKIP2, *fmt); ++fmt)
;
/* skip possible format modifiers */
if (*fmt == 'l' || *fmt == 'L' || *fmt == 'h')
{
fmt++;
foundmod = 1;
}
modstart = fmt;
while (*fmt && strchr (LENMODS, *fmt))
fmt++;
if (*fmt == 0)
{
@ -206,8 +252,11 @@ printf_builtin (list)
}
convch = *fmt;
nextch = fmt[1];
fmt[1] = '\0';
thisch = modstart[0];
nextch = modstart[1];
modstart[0] = convch;
modstart[1] = '\0';
switch(convch)
{
case 'c':
@ -228,6 +277,24 @@ printf_builtin (list)
break;
}
case 'n':
{
char *var;
var = getstr ();
if (var && *var)
{
if (legal_identifier (var))
bind_var_to_int (var, tw);
else
{
builtin_error ("%s: invalid variable name", var);
PRETURN (EXECUTION_FAILURE);
}
}
break;
}
case 'b': /* expand escapes in argument */
{
char *p, *xp;
@ -268,16 +335,34 @@ printf_builtin (list)
case 'd':
case 'i':
{
long p;
char *f;
#if defined (HAVE_LONG_LONG)
if (thisch == 'l' && nextch == 'l')
{
long long p;
if (foundmod == 0 && ((f = mklong (start, convch)) == NULL))
PRETURN (EXECUTION_FAILURE);
p = getllong ();
f = mklong (start, "ll");
PF(f, p);
}
else
f = start;
if (getlong (&p))
PRETURN (EXECUTION_FAILURE);
PF(f, p);
#endif
if (thisch == 'j')
{
intmax_t p;
p = getintmax ();
f = mklong (start, INTMAX_CONV);
PF(f, p);
}
else
{
long p;
p = getlong ();
f = mklong (start, "l");
PF(f, p);
}
break;
}
@ -286,30 +371,67 @@ printf_builtin (list)
case 'x':
case 'X':
{
unsigned long p;
char *f;
#if defined (HAVE_LONG_LONG)
if (thisch == 'l' && nextch == 'l')
{
unsigned long long p;
if (foundmod == 0 && ((f = mklong (start, convch)) == NULL))
PRETURN (EXECUTION_FAILURE);
p = getullong ();
f = mklong (start, "ll");
PF(f, p);
}
else
f = start;
if (getulong (&p))
PRETURN (EXECUTION_FAILURE);
PF (f, p);
#endif
if (thisch == 'j')
{
uintmax_t p;
p = getuintmax ();
f = mklong (start, INTMAX_CONV);
PF(f, p);
}
else
{
unsigned long p;
p = getulong ();
f = mklong (start, "l");
PF (f, p);
}
break;
}
case 'e':
case 'E':
case 'f':
case 'F':
case 'g':
case 'G':
#if defined (HAVE_PRINTF_A_FORMAT)
case 'a':
case 'A':
#endif
{
double p;
char *f;
#if defined (HAVE_LONG_DOUBLE) && HAVE_DECL_STRTOLD
if (thisch == 'L')
{
long double p;
if (getdouble (&p))
PRETURN (EXECUTION_FAILURE);
PF(start, p);
p = getldouble ();
f = mklong (start, "L");
PF (f, p);
}
else
#endif
{
double p;
p = getdouble ();
f = mklong (start, "");
PF (f, p);
}
break;
}
@ -320,11 +442,15 @@ printf_builtin (list)
PRETURN (EXECUTION_FAILURE);
}
fmt[1] = nextch;
modstart[0] = thisch;
modstart[1] = nextch;
}
}
while (garglist && garglist != list->next);
if (conversion_error)
retval = EXECUTION_FAILURE;
PRETURN (retval);
}
@ -352,10 +478,11 @@ printstr (fmt, string, len, fieldwidth, precision)
if (*fmt == '%')
fmt++;
ljust = fw = pr = 0;
ljust = fw = 0;
pr = -1;
/* skip flags */
while (*fmt == '#' || *fmt == '-' || *fmt == '+' || *fmt == ' ' || *fmt == '0')
while (strchr (SKIP1, *fmt))
{
if (*fmt == '-')
ljust = 1;
@ -367,11 +494,16 @@ printstr (fmt, string, len, fieldwidth, precision)
{
fmt++;
fw = fieldwidth;
if (fw < 0)
{
fw = -fw;
ljust = 1;
}
}
else if (isdigit (*fmt))
else if (DIGIT (*fmt))
{
fw = *fmt++ - '0';
while (isdigit (*fmt))
while (DIGIT (*fmt))
fw = (fw * 10) + (*fmt++ - '0');
}
@ -384,10 +516,10 @@ printstr (fmt, string, len, fieldwidth, precision)
fmt++;
pr = precision;
}
else if (isdigit (*fmt))
else if (DIGIT (*fmt))
{
pr = *fmt++ - '0';
while (isdigit (*fmt))
while (DIGIT (*fmt))
pr = (pr * 10) + (*fmt++ - '0');
}
}
@ -402,7 +534,7 @@ printstr (fmt, string, len, fieldwidth, precision)
#endif
/* chars from string to print */
nc = (pr > 0 && pr <= len) ? pr : len;
nc = (pr >= 0 && pr <= len) ? pr : len;
padlen = fw - nc;
if (padlen < 0)
@ -428,21 +560,6 @@ printstr (fmt, string, len, fieldwidth, precision)
recognize `\c' and use that as a string terminator. If we see \c, set
*SAWC to 1 before returning. LEN is the length of STRING. */
#ifdef isoctal
#undef isoctal
#endif
#define isoctal(c) ((c) >= '0' && (c) <= '7')
#define OCTVALUE(c) ((c) - '0')
#ifndef isxdigit
# define isxdigit(c) (isdigit((c)) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F'))
#endif
#define HEXVALUE(c) \
((c) >= 'a' && (c) <= 'f' ? (c)-'a'+10 : (c) >= 'A' && (c) <= 'F' ? (c)-'A'+10 : (c)-'0')
/* Translate a single backslash-escape sequence starting at ESTART (the
character after the backslash) and return the number of characters
consumed by the sequence. CP is the place to return the translated
@ -488,32 +605,32 @@ 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++)
for (temp = 3, evalue = 0; ISOCTAL (*p) && temp--; p++)
evalue = (evalue * 8) + OCTVALUE (*p);
*cp = evalue;
*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, evalue = c - '0'; ISOCTAL (*p) && temp--; p++)
evalue = (evalue * 8) + OCTVALUE (*p);
*cp = evalue;
*cp = evalue & 0xFF;
break;
/* And, as another extension, we allow \xNNN, where each N is a
hex digit. */
case 'x':
for (temp = 3, evalue = 0; isxdigit (*p) && temp--; p++)
for (temp = 2, evalue = 0; ISXDIGIT ((unsigned char)*p) && temp--; p++)
evalue = (evalue * 16) + HEXVALUE (*p);
if (temp == 3)
if (temp == 2)
{
builtin_error ("missing hex digit for \\x");
*cp = '\\';
return 0;
}
*cp = evalue;
*cp = evalue & 0xFF;
break;
case '\\': /* \\ -> \ */
@ -561,7 +678,7 @@ bexpand (string, len, sawc, lenp)
return ((char *)NULL);
}
ret = xmalloc (len + 1);
ret = (char *)xmalloc (len + 1);
for (r = ret, s = string; s && *s; )
{
c = *s++;
@ -589,19 +706,28 @@ bexpand (string, len, sawc, lenp)
}
static char *
mklong (str, ch)
mklong (str, modifiers)
char *str;
int ch;
char *modifiers;
{
static char copy[64];
int len;
size_t len, slen, mlen;
len = strlen (str) + 2;
FASTCOPY (str, copy, len - 3);
copy[len - 3] = 'l';
copy[len - 2] = ch;
copy[len - 1] = '\0';
return (copy);
slen = strlen (str);
mlen = strlen (modifiers);
len = slen + mlen + 1;
if (len > conv_bufsize)
{
conv_bufsize = (((len + 1023) >> 10) << 10);
conv_buf = (char *)xrealloc (conv_buf, conv_bufsize);
}
FASTCOPY (str, conv_buf, slen - 1);
FASTCOPY (modifiers, conv_buf + slen - 1, mlen);
conv_buf[len - 2] = str[slen - 1];
conv_buf[len - 1] = '\0';
return (conv_buf);
}
static int
@ -635,8 +761,7 @@ getint ()
{
long ret;
if (getlong (&ret))
return (0);
ret = getlong ();
if (ret > INT_MAX)
{
@ -652,62 +777,50 @@ getint ()
return ((int)ret);
}
static int
getlong (lp)
long *lp;
static long
getlong ()
{
long ret;
char *ep;
if (garglist == 0)
{
*lp = 0L;
return (0);
}
return (0);
if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
{
*lp = (long)asciicode ();
return (0);
}
return asciicode ();
errno = 0;
/* If we use 0 as the third argument, we can handle octal and hex, which
legal_number does not. (This was
if (legal_number (garglist->word->word, &ret) == 0)
) */
ret = strtol (garglist->word->word, &ep, 0);
if (*ep != '\0')
if (*ep)
{
builtin_error ("%s: invalid number", garglist->word->word);
return (1);
/* 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));
*lp = ret;
garglist = garglist->next;
return (0);
return (ret);
}
static int
getulong (ulp)
unsigned long *ulp;
static unsigned long
getulong ()
{
unsigned long ret;
char *ep;
if (garglist == 0)
{
*ulp = (unsigned long)0;
return (0);
}
return (0);
if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
{
*ulp = (unsigned long)asciicode ();
return (0);
}
return asciicode ();
errno = 0;
ret = strtoul (garglist->word->word, &ep, 0);
@ -715,50 +828,205 @@ getulong (ulp)
if (*ep)
{
builtin_error ("%s: invalid number", garglist->word->word);
return (1);
/* 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));
*ulp = ret;
garglist = garglist->next;
return (0);
return (ret);
}
static int
getdouble (dp)
double *dp;
#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 ()
{
intmax_t ret;
char *ep;
if (garglist == 0)
return (0);
if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
return asciicode ();
errno = 0;
ret = strtoimax (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 uintmax_t
getuintmax ()
{
uintmax_t ret;
char *ep;
if (garglist == 0)
return (0);
if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
return asciicode ();
errno = 0;
ret = strtoumax (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);
}
static double
getdouble ()
{
double ret;
char *ep;
if (garglist == 0)
{
*dp = (double)0;
return (0);
}
return (0);
if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
{
*dp = (double)asciicode ();
return (0);
}
return asciicode ();
errno = 0;
ret = strtod (garglist->word->word, &ep);
if (*ep)
{
builtin_error ("%s: invalid number", garglist->word->word);
return (1);
/* 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));
*dp = ret;
garglist = garglist->next;
return (0);
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 ()