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

This commit is contained in:
Jari Aalto
2009-09-12 16:46:55 +00:00
parent f73dda092b
commit 7117c2d221
362 changed files with 34387 additions and 15063 deletions
+38 -7
View File
@@ -2,7 +2,7 @@
# Makefile for the Bash library
#
#
# Copyright (C) 1998 Free Software Foundation, Inc.
# Copyright (C) 1998-2002 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -68,10 +68,12 @@ LIBRARY_NAME = libsh.a
CSOURCES = clktck.c clock.c getcwd.c getenv.c oslib.c setlinebuf.c \
strcasecmp.c strerror.c strtod.c strtol.c strtoul.c \
vprint.c itos.c rename.c zread.c zwrite.c shtty.c \
inet_aton.c netopen.c strpbrk.c timeval.c makepath.c pathcanon.c \
pathphys.c tmpfile.c stringlist.c stringvec.c spell.c \
shquote.c strtrans.c strindex.c snprintf.c mailstat.c fmtulong.c \
fmtullong.c strtoll.c strtoull.c strtoimax.c strtoumax.c
inet_aton.c netconn.c netopen.c strpbrk.c timeval.c makepath.c \
pathcanon.c pathphys.c tmpfile.c stringlist.c stringvec.c spell.c \
shquote.c strtrans.c strindex.c snprintf.c mailstat.c \
fmtulong.c fmtullong.c fmtumax.c \
strtoll.c strtoull.c strtoimax.c strtoumax.c memset.c \
mktime.c strftime.c xstrchr.c zcatfd.c
# The header files for this library.
HSOURCES =
@@ -80,10 +82,10 @@ HSOURCES =
LIBOBJS = @LIBOBJS@
OBJECTS = clktck.o clock.o getenv.o oslib.o setlinebuf.o \
itos.o zread.o zwrite.o shtty.o \
netopen.o timeval.o makepath.o pathcanon.o \
netconn.o netopen.o timeval.o makepath.o pathcanon.o \
pathphys.o tmpfile.o stringlist.o stringvec.o spell.o shquote.o \
strtrans.o strindex.o snprintf.o mailstat.o fmtulong.o \
fmtullong.o ${LIBOBJS}
fmtullong.o fmtumax.o xstrchr.o zcatfd.o ${LIBOBJS}
SUPPORT = Makefile
@@ -116,12 +118,16 @@ clktck.o: clktck.c
clock.o: clock.c
fmtullong.o: fmtullong.c
fmtulong.o: fmtulong.c
fmtumax.o: fmtumax.c
getcwd.o: getcwd.c
getenv.o: getenv.c
inet_aton.o: inet_aton.c
itos.o: itos.c
mailstat.o: mailstat.c
makepath.o: makepath.c
memset.o: memset.c
mktime.o: mktime.c
netconn.o: netconn.c
netopen.o: netopen.c
oslib.o: oslib.c
pathcanon.o: pathcanon.c
@@ -134,6 +140,7 @@ snprintf.o: snprintf.c
spell.o: spell.c
strcasecmp.o: strcasecmp.c
strerror.o: strerror.c
strftime.o: strftime.c
strindex.o: strindex.c
stringlist.o: stringlist.c
stringvec.o: stringvec.c
@@ -150,11 +157,14 @@ times.o: times.c
timeval.o: timeval.c
tmpfile.o: tmpfile.c
vprint.o: vprint.c
xstrchr.o: xstrchr.c
zcatfd.o: zcatfd.c
zread.o: zread.c
zwrite.o: zwrite.c
# dependencies for c files that include other c files
fmtullong.o: fmtulong.c
fmtumax.o: fmtulong.c
strtoll.o: strtol.c
strtoul.o: strtol.c
strtoull.o: strtol.c
@@ -164,12 +174,16 @@ clktck.o: ${BUILD_DIR}/config.h
clock.o: ${BUILD_DIR}/config.h
fmtullong.o: ${BUILD_DIR}/config.h
fmtulong.o: ${BUILD_DIR}/config.h
fmtumax.o: ${BUILD_DIR}/config.h
getcwd.o: ${BUILD_DIR}/config.h
getenv.o: ${BUILD_DIR}/config.h
inet_aton.o: ${BUILD_DIR}/config.h
itos.o: ${BUILD_DIR}/config.h
mailstat.o: ${BUILD_DIR}/config.h
makepath.o: ${BUILD_DIR}/config.h
memset.o: ${BUILD_DIR}/config.h
mktime.o: ${BUILD_DIR}/config.h
netconn.o: ${BUILD_DIR}/config.h
netopen.o: ${BUILD_DIR}/config.h
oslib.o: ${BUILD_DIR}/config.h
pathcanon.o: ${BUILD_DIR}/config.h
@@ -182,6 +196,7 @@ snprintf.o: ${BUILD_DIR}/config.h
spell.o: ${BUILD_DIR}/config.h
strcasecmp.o: ${BUILD_DIR}/config.h
strerror.o: ${BUILD_DIR}/config.h
strftime.o: ${BUILD_DIR}/config.h
strindex.o: ${BUILD_DIR}/config.h
stringlist.o: ${BUILD_DIR}/config.h
stringvec.o: ${BUILD_DIR}/config.h
@@ -198,6 +213,8 @@ times.o: ${BUILD_DIR}/config.h
timeval.o: ${BUILD_DIR}/config.h
tmpfile.o: ${BUILD_DIR}/config.h
vprint.o: ${BUILD_DIR}/config.h
xstrchr.o: ${BUILD_DIR}/config.h
zcatfd.o: ${BUILD_DIR}/config.h
zread.o: ${BUILD_DIR}/config.h
zwrite.o: ${BUILD_DIR}/config.h
@@ -237,6 +254,9 @@ makepath.o: ${topdir}/unwind_prot.h ${topdir}/dispose_cmd.h
makepath.o: ${topdir}/make_cmd.h ${topdir}/subst.h ${topdir}/sig.h
makepath.o: ${topdir}/pathnames.h ${topdir}/externs.h
netconn.o: ${BASHINCDIR}/posixstat.h ${BASHINCDIR}/filecntl.h
netconn.o: ${topdir}/bashtypes.h
netopen.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h ${topdir}/xmalloc.h
netopen.o: ${topdir}/shell.h ${topdir}/syntax.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h
netopen.o: ${topdir}/command.h ${BASHINCDIR}/stdc.h ${topdir}/error.h
@@ -280,6 +300,7 @@ pathphys.o: ${BASHINCDIR}/posixstat.h ${BASHINCDIR}/filecntl.h
pathphys.o: ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/chartypes.h
rename.o: ${topdir}/bashtypes.h ${BASHINCDIR}/stdc.h
rename.o: ${BASHINCDIR}/posixstat.h
setlinebuf.o: ${topdir}/xmalloc.h ${topdir}/bashansi.h
setlinebuf.o: ${BASHINCDIR}/ansi_stdlib.h ${BASHINCDIR}/stdc.h
@@ -395,3 +416,13 @@ fmtullong.o: ${BASHINCDIR}/ansi_stdlib.h
fmtullong.o: ${BASHINCDIR}/chartypes.h
fmtullong.o: ${BASHINCDIR}/stdc.h
fmtullong.o: ${BASHINCDIR}/typemax.h
fmtumax.o: ${topdir}/bashansi.h
fmtumax.o: ${BASHINCDIR}/ansi_stdlib.h
fmtumax.o: ${BASHINCDIR}/chartypes.h
fmtumax.o: ${BASHINCDIR}/stdc.h
fmtumax.o: ${BASHINCDIR}/typemax.h
xstrchr.o: ${topdir}/bashansi.h
xstrchr.o: ${BASHINCDIR}/ansi_stdlib.h
xstrchr.o: ${BASHINCDIR}/shmbutil.h
+4
View File
@@ -27,6 +27,10 @@
# include <unistd.h>
#endif
#if defined (HAVE_LIMITS_H)
# include <limits.h>
#endif
#if !defined (HAVE_SYSCONF) || !defined (_SC_CLK_TCK)
# if !defined (CLK_TCK)
# if defined (HZ)
+7 -2
View File
@@ -1,4 +1,6 @@
/* Copyright (C) 2001 Free Software Foundation, Inc.
/* fmtullong.c - convert `long long int' to string */
/* Copyright (C) 2001-2002 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
@@ -18,7 +20,10 @@ Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#ifdef HAVE_LONG_LONG
#define QUAD 1
#define LONG long long
#define UNSIGNED_LONG unsigned long long
#define fmtulong fmtullong
#include "fmtulong.c"
#endif
+5 -16
View File
@@ -1,6 +1,6 @@
/* fmtulong.c -- Convert unsigned long int to string. */
/* Copyright (C) 1998, Free Software Foundation, Inc.
/* Copyright (C) 1998-2002 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -67,20 +67,9 @@ extern int errno;
# define FL_UNSIGNED 0x08 /* don't add any sign */
#endif
#ifdef QUAD
/* fmtullong */
# define LONG long long
# define FMTUL_LONG_MAX LLONG_MAX
# define FMTUL_ULONG_MAX ULLONG_MAX
#else
#ifndef LONG
# define LONG long
# define FMTUL_LONG_MAX LONG_MAX
# define FMTUL_ULONG_MAX ULONG_MAX
#endif
/* Set the name */
#ifdef QUAD
# define fmtulong fmtullong
# define UNSIGNED_LONG unsigned long
#endif
/* `unsigned long' (or unsigned long long) to string conversion for a given
@@ -88,7 +77,7 @@ extern int errno;
check for buffer underflow, but currently does not. */
char *
fmtulong (ui, base, buf, len, flags)
unsigned LONG ui;
UNSIGNED_LONG ui;
int base;
char *buf;
size_t len;
@@ -134,7 +123,7 @@ fmtulong (ui, base, buf, len, flags)
}
/* Favor signed arithmetic over unsigned arithmetic; it is faster on
many machines. */
if (ui > FMTUL_LONG_MAX)
if ((LONG)ui < 0)
{
*p-- = TOCHAR (ui % 10);
si = ui / 10;
+25
View File
@@ -0,0 +1,25 @@
/* fmtumax.c -- Convert uintmax_t to string. */
/* Copyright (C) 2002 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
#include <config.h>
#define LONG intmax_t
#define UNSIGNED_LONG uintmax_t
#define fmtulong fmtumax
#include "fmtulong.c"
+144 -10
View File
@@ -1,7 +1,7 @@
/* getenv.c - get environment variable value from the shell's variable
list. */
/* 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.
@@ -28,8 +28,13 @@
#endif
#include <bashansi.h>
#include <errno.h>
#include <shell.h>
#ifndef errno
extern int errno;
#endif
extern char **environ;
/* We supply our own version of getenv () because we want library
@@ -43,21 +48,19 @@ static char *last_tempenv_value = (char *)NULL;
char *
getenv (name)
#if defined (__linux__) || defined (__bsdi__) || defined (convex)
const char *name;
#else
char const *name;
#endif /* !__linux__ && !__bsdi__ && !convex */
{
SHELL_VAR *var;
if (name == 0 || *name == '\0')
return ((char *)NULL);
var = find_tempenv_variable ((char *)name);
if (var)
{
FREE (last_tempenv_value);
last_tempenv_value = value_cell (var) ? savestring (value_cell (var)) : (char *)NULL;
dispose_variable (var);
return (last_tempenv_value);
}
else if (shell_variables)
@@ -88,12 +91,143 @@ getenv (name)
/* Some versions of Unix use _getenv instead. */
char *
_getenv (name)
#if defined (__linux__) || defined (__bsdi__) || defined (convex)
const char *name;
#else
char const *name;
#endif /* !__linux__ && !__bsdi__ && !convex */
{
return (getenv (name));
}
/* SUSv3 says argument is a `char *'; BSD implementations disagree */
int
putenv (str)
#ifndef HAVE_STD_PUTENV
const char *str;
#else
char *str;
#endif
{
SHELL_VAR *var;
char *name, *value;
int offset;
if (str == 0 || *str == '\0')
{
errno = EINVAL;
return -1;
}
offset = assignment (str);
if (str[offset] != '=')
{
errno = EINVAL;
return -1;
}
name = savestring (str);
name[offset] = 0;
value = name + offset + 1;
/* XXX - should we worry about readonly here? */
var = bind_variable (name, value);
if (var == 0)
{
errno = EINVAL;
return -1;
}
VUNSETATTR (var, att_invisible);
VSETATTR (var, att_exported);
return 0;
}
#if 0
int
_putenv (name)
#ifndef HAVE_STD_PUTENV
const char *name;
#else
char *name;
#endif
{
return putenv (name);
}
#endif
int
setenv (name, value, rewrite)
const char *name;
const char *value;
int rewrite;
{
SHELL_VAR *var;
char *v;
if (name == 0 || *name == '\0' || strchr (name, '=') != 0)
{
errno = EINVAL;
return -1;
}
var = 0;
v = value;
/* XXX - should we worry about readonly here? */
if (rewrite == 0)
var = find_variable (name);
if (var == 0)
var = bind_variable (name, v);
if (var == 0)
return -1;
VUNSETATTR (var, att_invisible);
VSETATTR (var, att_exported);
return 0;
}
#if 0
int
_setenv (name, value, rewrite)
const char *name;
const char *value;
int rewrite;
{
return setenv (name, value, rewrite);
}
#endif
/* SUSv3 says unsetenv returns int; existing implementations (BSD) disagree. */
#ifdef HAVE_STD_UNSETENV
#define UNSETENV_RETURN(N) return(N)
#define UNSETENV_RETTYPE int
#else
#define UNSETENV_RETURN(N) return
#define UNSETENV_RETTYPE void
#endif
UNSETENV_RETTYPE
unsetenv (name)
const char *name;
{
if (name == 0 || *name == '\0' || strchr (name, '=') != 0)
{
errno = EINVAL;
UNSETENV_RETURN(-1);
}
/* XXX - should we just remove the export attribute here? */
#if 1
unbind_variable (name);
#else
SHELL_VAR *v;
v = find_variable (name);
if (v)
VUNSETATTR (v, att_exported);
#endif
UNSETENV_RETURN(0);
}
#endif /* CAN_REDEFINE_GETENV */
+11 -12
View File
@@ -1,6 +1,6 @@
/* itos.c -- Convert integer to string. */
/* Copyright (C) 1998, Free Software Foundation, Inc.
/* Copyright (C) 1998-2002 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -27,47 +27,46 @@
#endif
#include <bashansi.h>
#include <chartypes.h>
#include "shell.h"
char *
inttostr (i, buf, len)
long i;
intmax_t i;
char *buf;
size_t len;
{
return (fmtulong (i, 10, buf, len, 0));
return (fmtumax (i, 10, buf, len, 0));
}
/* Integer to string conversion. This conses the string; the
caller should free it. */
char *
itos (i)
long i;
intmax_t i;
{
char *p, lbuf[INT_STRLEN_BOUND(long) + 1];
char *p, lbuf[INT_STRLEN_BOUND(intmax_t) + 1];
p = fmtulong (i, 10, lbuf, sizeof(lbuf), 0);
p = fmtumax (i, 10, lbuf, sizeof(lbuf), 0);
return (savestring (p));
}
char *
uinttostr (i, buf, len)
unsigned long i;
uintmax_t i;
char *buf;
size_t len;
{
return (fmtulong (i, 10, buf, len, FL_UNSIGNED));
return (fmtumax (i, 10, buf, len, FL_UNSIGNED));
}
/* Integer to string conversion. This conses the string; the
caller should free it. */
char *
uitos (i)
unsigned long i;
uintmax_t i;
{
char *p, lbuf[INT_STRLEN_BOUND(long) + 1];
char *p, lbuf[INT_STRLEN_BOUND(uintmax_t) + 1];
p = fmtulong (i, 10, lbuf, sizeof(lbuf), FL_UNSIGNED);
p = fmtumax (i, 10, lbuf, sizeof(lbuf), FL_UNSIGNED);
return (savestring (p));
}
+1 -1
View File
@@ -91,7 +91,7 @@ sh_makepath (path, dir, flags)
}
else
{
xpath = ((flags & MP_DOTILDE) && *path == '~') ? bash_tilde_expand (path) : (char *)path;
xpath = ((flags & MP_DOTILDE) && *path == '~') ? bash_tilde_expand (path, 0) : (char *)path;
pathlen = strlen (xpath);
}
+26
View File
@@ -0,0 +1,26 @@
/* memset.c -- set an area of memory to a given value
Copyright (C) 1991-2002 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
char *
memset (char *str, int c, unsigned int len)
{
register char *st = str;
while (len-- > 0)
*st++ = c;
return str;
}
+425
View File
@@ -0,0 +1,425 @@
/* Copyright (C) 1993-2002 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Paul Eggert (eggert@twinsun.com).
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB. If not,
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
/* Define this to have a standalone program to test this implementation of
mktime. */
/* #define DEBUG 1 */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef _LIBC
# define HAVE_LIMITS_H 1
# define HAVE_LOCALTIME_R 1
# define STDC_HEADERS 1
#endif
/* Assume that leap seconds are possible, unless told otherwise.
If the host has a `zic' command with a `-L leapsecondfilename' option,
then it supports leap seconds; otherwise it probably doesn't. */
#ifndef LEAP_SECONDS_POSSIBLE
#define LEAP_SECONDS_POSSIBLE 1
#endif
#ifndef VMS
#include <sys/types.h> /* Some systems define `time_t' here. */
#else
#include <stddef.h>
#endif
#include <time.h>
#if HAVE_LIMITS_H
#include <limits.h>
#endif
#if DEBUG
#include <stdio.h>
#if STDC_HEADERS
#include <stdlib.h>
#endif
/* Make it work even if the system's libc has its own mktime routine. */
#define mktime my_mktime
#endif /* DEBUG */
#ifndef __P
#if defined (__GNUC__) || (defined (__STDC__) && __STDC__)
#define __P(args) args
#else
#define __P(args) ()
#endif /* GCC. */
#endif /* Not __P. */
#ifndef CHAR_BIT
#define CHAR_BIT 8
#endif
#ifndef INT_MIN
#define INT_MIN (~0 << (sizeof (int) * CHAR_BIT - 1))
#endif
#ifndef INT_MAX
#define INT_MAX (~0 - INT_MIN)
#endif
#ifndef TIME_T_MIN
#define TIME_T_MIN (0 < (time_t) -1 ? (time_t) 0 \
: ~ (time_t) 0 << (sizeof (time_t) * CHAR_BIT - 1))
#endif
#ifndef TIME_T_MAX
#define TIME_T_MAX (~ (time_t) 0 - TIME_T_MIN)
#endif
#define TM_YEAR_BASE 1900
#define EPOCH_YEAR 1970
#ifndef __isleap
/* Nonzero if YEAR is a leap year (every 4 years,
except every 100th isn't, and every 400th is). */
#define __isleap(year) \
((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
#endif
/* How many days come before each month (0-12). */
const unsigned short int __mon_yday[2][13] =
{
/* Normal years. */
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
/* Leap years. */
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
};
static time_t ydhms_tm_diff __P ((int, int, int, int, int, const struct tm *));
time_t __mktime_internal __P ((struct tm *,
struct tm *(*) (const time_t *, struct tm *),
time_t *));
static struct tm *my_localtime_r __P ((const time_t *, struct tm *));
static struct tm *
my_localtime_r (t, tp)
const time_t *t;
struct tm *tp;
{
struct tm *l = localtime (t);
if (! l)
return 0;
*tp = *l;
return tp;
}
/* Yield the difference between (YEAR-YDAY HOUR:MIN:SEC) and (*TP),
measured in seconds, ignoring leap seconds.
YEAR uses the same numbering as TM->tm_year.
All values are in range, except possibly YEAR.
If overflow occurs, yield the low order bits of the correct answer. */
static time_t
ydhms_tm_diff (year, yday, hour, min, sec, tp)
int year, yday, hour, min, sec;
const struct tm *tp;
{
/* Compute intervening leap days correctly even if year is negative.
Take care to avoid int overflow. time_t overflow is OK, since
only the low order bits of the correct time_t answer are needed.
Don't convert to time_t until after all divisions are done, since
time_t might be unsigned. */
int a4 = (year >> 2) + (TM_YEAR_BASE >> 2) - ! (year & 3);
int b4 = (tp->tm_year >> 2) + (TM_YEAR_BASE >> 2) - ! (tp->tm_year & 3);
int a100 = a4 / 25 - (a4 % 25 < 0);
int b100 = b4 / 25 - (b4 % 25 < 0);
int a400 = a100 >> 2;
int b400 = b100 >> 2;
int intervening_leap_days = (a4 - b4) - (a100 - b100) + (a400 - b400);
time_t years = year - (time_t) tp->tm_year;
time_t days = (365 * years + intervening_leap_days
+ (yday - tp->tm_yday));
return (60 * (60 * (24 * days + (hour - tp->tm_hour))
+ (min - tp->tm_min))
+ (sec - tp->tm_sec));
}
static time_t localtime_offset;
/* Convert *TP to a time_t value. */
time_t
mktime (tp)
struct tm *tp;
{
#ifdef _LIBC
/* POSIX.1 8.1.1 requires that whenever mktime() is called, the
time zone names contained in the external variable `tzname' shall
be set as if the tzset() function had been called. */
__tzset ();
#endif
return __mktime_internal (tp, my_localtime_r, &localtime_offset);
}
/* Convert *TP to a time_t value, inverting
the monotonic and mostly-unit-linear conversion function CONVERT.
Use *OFFSET to keep track of a guess at the offset of the result,
compared to what the result would be for UTC without leap seconds.
If *OFFSET's guess is correct, only one CONVERT call is needed. */
time_t
__mktime_internal (tp, convert, offset)
struct tm *tp;
struct tm *(*convert) __P ((const time_t *, struct tm *));
time_t *offset;
{
time_t t, dt, t0;
struct tm tm;
/* The maximum number of probes (calls to CONVERT) should be enough
to handle any combinations of time zone rule changes, solar time,
and leap seconds. Posix.1 prohibits leap seconds, but some hosts
have them anyway. */
int remaining_probes = 4;
/* Time requested. Copy it in case CONVERT modifies *TP; this can
occur if TP is localtime's returned value and CONVERT is localtime. */
int sec = tp->tm_sec;
int min = tp->tm_min;
int hour = tp->tm_hour;
int mday = tp->tm_mday;
int mon = tp->tm_mon;
int year_requested = tp->tm_year;
int isdst = tp->tm_isdst;
/* Ensure that mon is in range, and set year accordingly. */
int mon_remainder = mon % 12;
int negative_mon_remainder = mon_remainder < 0;
int mon_years = mon / 12 - negative_mon_remainder;
int year = year_requested + mon_years;
/* The other values need not be in range:
the remaining code handles minor overflows correctly,
assuming int and time_t arithmetic wraps around.
Major overflows are caught at the end. */
/* Calculate day of year from year, month, and day of month.
The result need not be in range. */
int yday = ((__mon_yday[__isleap (year + TM_YEAR_BASE)]
[mon_remainder + 12 * negative_mon_remainder])
+ mday - 1);
#if LEAP_SECONDS_POSSIBLE
/* Handle out-of-range seconds specially,
since ydhms_tm_diff assumes every minute has 60 seconds. */
int sec_requested = sec;
if (sec < 0)
sec = 0;
if (59 < sec)
sec = 59;
#endif
/* Invert CONVERT by probing. First assume the same offset as last time.
Then repeatedly use the error to improve the guess. */
tm.tm_year = EPOCH_YEAR - TM_YEAR_BASE;
tm.tm_yday = tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
t0 = ydhms_tm_diff (year, yday, hour, min, sec, &tm);
for (t = t0 + *offset;
(dt = ydhms_tm_diff (year, yday, hour, min, sec, (*convert) (&t, &tm)));
t += dt)
if (--remaining_probes == 0)
return -1;
/* Check whether tm.tm_isdst has the requested value, if any. */
if (0 <= isdst && 0 <= tm.tm_isdst)
{
int dst_diff = (isdst != 0) - (tm.tm_isdst != 0);
if (dst_diff)
{
/* Move two hours in the direction indicated by the disagreement,
probe some more, and switch to a new time if found.
The largest known fallback due to daylight savings is two hours:
once, in Newfoundland, 1988-10-30 02:00 -> 00:00. */
time_t ot = t - 2 * 60 * 60 * dst_diff;
while (--remaining_probes != 0)
{
struct tm otm;
if (! (dt = ydhms_tm_diff (year, yday, hour, min, sec,
(*convert) (&ot, &otm))))
{
t = ot;
tm = otm;
break;
}
if ((ot += dt) == t)
break; /* Avoid a redundant probe. */
}
}
}
*offset = t - t0;
#if LEAP_SECONDS_POSSIBLE
if (sec_requested != tm.tm_sec)
{
/* Adjust time to reflect the tm_sec requested, not the normalized value.
Also, repair any damage from a false match due to a leap second. */
t += sec_requested - sec + (sec == 0 && tm.tm_sec == 60);
(*convert) (&t, &tm);
}
#endif
if (TIME_T_MAX / INT_MAX / 366 / 24 / 60 / 60 < 3)
{
/* time_t isn't large enough to rule out overflows in ydhms_tm_diff,
so check for major overflows. A gross check suffices,
since if t has overflowed, it is off by a multiple of
TIME_T_MAX - TIME_T_MIN + 1. So ignore any component of
the difference that is bounded by a small value. */
double dyear = (double) year_requested + mon_years - tm.tm_year;
double dday = 366 * dyear + mday;
double dsec = 60 * (60 * (24 * dday + hour) + min) + sec_requested;
if (TIME_T_MAX / 3 - TIME_T_MIN / 3 < (dsec < 0 ? - dsec : dsec))
return -1;
}
*tp = tm;
return t;
}
#ifdef weak_alias
weak_alias (mktime, timelocal)
#endif
#if DEBUG
static int
not_equal_tm (a, b)
struct tm *a;
struct tm *b;
{
return ((a->tm_sec ^ b->tm_sec)
| (a->tm_min ^ b->tm_min)
| (a->tm_hour ^ b->tm_hour)
| (a->tm_mday ^ b->tm_mday)
| (a->tm_mon ^ b->tm_mon)
| (a->tm_year ^ b->tm_year)
| (a->tm_mday ^ b->tm_mday)
| (a->tm_yday ^ b->tm_yday)
| (a->tm_isdst ^ b->tm_isdst));
}
static void
print_tm (tp)
struct tm *tp;
{
printf ("%04d-%02d-%02d %02d:%02d:%02d yday %03d wday %d isdst %d",
tp->tm_year + TM_YEAR_BASE, tp->tm_mon + 1, tp->tm_mday,
tp->tm_hour, tp->tm_min, tp->tm_sec,
tp->tm_yday, tp->tm_wday, tp->tm_isdst);
}
static int
check_result (tk, tmk, tl, tml)
time_t tk;
struct tm tmk;
time_t tl;
struct tm tml;
{
if (tk != tl || not_equal_tm (&tmk, &tml))
{
printf ("mktime (");
print_tm (&tmk);
printf (")\nyields (");
print_tm (&tml);
printf (") == %ld, should be %ld\n", (long) tl, (long) tk);
return 1;
}
return 0;
}
int
main (argc, argv)
int argc;
char **argv;
{
int status = 0;
struct tm tm, tmk, tml;
time_t tk, tl;
char trailer;
if ((argc == 3 || argc == 4)
&& (sscanf (argv[1], "%d-%d-%d%c",
&tm.tm_year, &tm.tm_mon, &tm.tm_mday, &trailer)
== 3)
&& (sscanf (argv[2], "%d:%d:%d%c",
&tm.tm_hour, &tm.tm_min, &tm.tm_sec, &trailer)
== 3))
{
tm.tm_year -= TM_YEAR_BASE;
tm.tm_mon--;
tm.tm_isdst = argc == 3 ? -1 : atoi (argv[3]);
tmk = tm;
tl = mktime (&tmk);
tml = *localtime (&tl);
printf ("mktime returns %ld == ", (long) tl);
print_tm (&tmk);
printf ("\n");
status = check_result (tl, tmk, tl, tml);
}
else if (argc == 4 || (argc == 5 && strcmp (argv[4], "-") == 0))
{
time_t from = atol (argv[1]);
time_t by = atol (argv[2]);
time_t to = atol (argv[3]);
if (argc == 4)
for (tl = from; tl <= to; tl += by)
{
tml = *localtime (&tl);
tmk = tml;
tk = mktime (&tmk);
status |= check_result (tk, tmk, tl, tml);
}
else
for (tl = from; tl <= to; tl += by)
{
/* Null benchmark. */
tml = *localtime (&tl);
tmk = tml;
tk = tl;
status |= check_result (tk, tmk, tl, tml);
}
}
else
printf ("Usage:\
\t%s YYYY-MM-DD HH:MM:SS [ISDST] # Test given time.\n\
\t%s FROM BY TO # Test values FROM, FROM+BY, ..., TO.\n\
\t%s FROM BY TO - # Do not test those values (for benchmark).\n",
argv[0], argv[0], argv[0]);
return status;
}
#endif /* DEBUG */
/*
Local Variables:
compile-command: "gcc -DDEBUG=1 -Wall -O -g mktime.c -o mktime"
End:
*/
+83
View File
@@ -0,0 +1,83 @@
/* netconn.c -- is a particular file descriptor a network connection?. */
/* Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
Bash is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with Bash; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
*/
#include <config.h>
#include <bashtypes.h>
#ifndef _MINIX
# include <sys/file.h>
#endif
#include <posixstat.h>
#include <filecntl.h>
#include <errno.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
/* The second and subsequent conditions must match those used to decide
whether or not to call getpeername() in isnetconn(). */
#if defined (HAVE_SYS_SOCKET_H) && defined (HAVE_GETPEERNAME) && !defined (SVR4_2)
# include <sys/socket.h>
#endif
/* Is FD a socket or network connection? */
int
isnetconn (fd)
int fd;
{
#if defined (HAVE_GETPEERNAME) && !defined (SVR4_2) && !defined (__BEOS__)
int rv;
socklen_t l;
struct sockaddr sa;
l = sizeof(sa);
rv = getpeername(fd, &sa, &l);
/* Solaris 2.5 getpeername() returns EINVAL if the fd is not a socket. */
return ((rv < 0 && (errno == ENOTSOCK || errno == EINVAL)) ? 0 : 1);
#else /* !HAVE_GETPEERNAME || SVR4_2 || __BEOS__ */
# if defined (SVR4) || defined (SVR4_2)
/* Sockets on SVR4 and SVR4.2 are character special (streams) devices. */
struct stat sb;
if (isatty (fd))
return (0);
if (fstat (fd, &sb) < 0)
return (0);
# if defined (S_ISFIFO)
if (S_ISFIFO (sb.st_mode))
return (0);
# endif /* S_ISFIFO */
return (S_ISCHR (sb.st_mode));
# else /* !SVR4 && !SVR4_2 */
# if defined (S_ISSOCK) && !defined (__BEOS__)
struct stat sb;
if (fstat (fd, &sb) < 0)
return (0);
return (S_ISSOCK (sb.st_mode));
# else /* !S_ISSOCK || __BEOS__ */
return (0);
# endif /* !S_ISSOCK || __BEOS__ */
# endif /* !SVR4 && !SVR4_2 */
#endif /* !HAVE_GETPEERNAME || SVR4_2 || __BEOS__ */
}
+4 -4
View File
@@ -5,7 +5,7 @@
* chet@ins.CWRU.Edu
*/
/* Copyright (C) 1987,1991 Free Software Foundation, Inc.
/* Copyright (C) 1987-2002 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -107,7 +107,7 @@ _getserv (serv, proto, pp)
int proto;
unsigned short *pp;
{
long l;
intmax_t l;
unsigned short s;
if (legal_number (serv, &l))
@@ -165,7 +165,7 @@ _netopen4(host, serv, typ)
return -1;
}
bzero ((char *)&sin, sizeof(sin));
memset ((char *)&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = p;
sin.sin_addr = ina;
@@ -205,7 +205,7 @@ _netopen6 (host, serv, typ)
struct addrinfo hints, *res, *res0;
int gerr;
bzero ((char *)&hints, sizeof (hints));
memset ((char *)&hints, 0, sizeof (hints));
/* XXX -- if problems with IPv6, set to PF_INET for IPv4 only */
#ifdef DEBUG /* PF_INET is the one that works for me */
hints.ai_family = PF_INET;
+57
View File
@@ -29,6 +29,10 @@
# include <unistd.h>
#endif
#if defined (HAVE_LIMITS_H)
# include <limits.h>
#endif
#include <posixstat.h>
#include <filecntl.h>
#include <bashansi.h>
@@ -237,3 +241,56 @@ mkfifo (path, mode)
#endif /* !S_IFIFO */
}
#endif /* !HAVE_MKFIFO && PROCESS_SUBSTITUTION */
#define DEFAULT_MAXGROUPS 64
int
getmaxgroups ()
{
static int maxgroups = -1;
if (maxgroups > 0)
return maxgroups;
#if defined (HAVE_SYSCONF) && defined (_SC_NGROUPS_MAX)
maxgroups = sysconf (_SC_NGROUPS_MAX);
#else
# if defined (NGROUPS_MAX)
maxgroups = NGROUPS_MAX;
# else /* !NGROUPS_MAX */
# if defined (NGROUPS)
maxgroups = NGROUPS;
# else /* !NGROUPS */
maxgroups = DEFAULT_MAXGROUPS;
# endif /* !NGROUPS */
# endif /* !NGROUPS_MAX */
#endif /* !HAVE_SYSCONF || !SC_NGROUPS_MAX */
if (maxgroups <= 0)
maxgroups = DEFAULT_MAXGROUPS;
return maxgroups;
}
long
getmaxchild ()
{
static long maxchild = -1L;
if (maxchild > 0)
return maxchild;
#if defined (HAVE_SYSCONF) && defined (_SC_CHILD_MAX)
maxchild = sysconf (_SC_CHILD_MAX);
#else
# if defined (CHILD_MAX)
maxchild = CHILD_MAX;
# else
# if defined (MAXUPRC)
maxchild = MAXUPRC;
# endif /* MAXUPRC */
# endif /* CHILD_MAX */
#endif /* !HAVE_SYSCONF || !_SC_CHILD_MAX */
return (maxchild);
}
+32
View File
@@ -37,6 +37,34 @@
#include "shell.h"
#if defined (__CYGWIN__)
#include <sys/cygwin.h>
static int
_is_cygdrive (path)
char *path;
{
static char user[MAXPATHLEN];
static char system[MAXPATHLEN];
static int first_time = 1;
/* If the path is the first part of a network path, treat it as
existing. */
if (path[0] == '/' && path[1] == '/' && !strchr (path + 2, '/'))
return 1;
/* Otherwise check for /cygdrive prefix. */
if (first_time)
{
char user_flags[MAXPATHLEN];
char system_flags[MAXPATHLEN];
/* Get the cygdrive info */
cygwin_internal (CW_GET_CYGDRIVE_INFO, user, system, user_flags, system_flags);
first_time = 0;
}
return !strcasecmp (path, user) || !strcasecmp (path, system);
}
#endif /* __CYGWIN__ */
/* Return 1 if PATH corresponds to a directory. A function for debugging. */
static int
_path_isdir (path)
@@ -46,6 +74,10 @@ _path_isdir (path)
struct stat sb;
l = stat (path, &sb) == 0 && S_ISDIR (sb.st_mode);
#if defined (__CYGWIN__)
if (l == 0)
l = _is_cygdrive (path);
#endif
return l;
}
+33 -2
View File
@@ -25,21 +25,52 @@
#if !defined (HAVE_RENAME)
#include <bashtypes.h>
#include <posixstat.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <errno.h>
#include <stdc.h>
#ifndef errno
extern int errno;
#endif
int
rename (from, to)
const char *from, *to;
{
unlink (to);
struct stat fb, tb;
if (stat (from, &fb) < 0)
return -1;
if (stat (to, &tb) < 0)
{
if (errno != ENOENT)
return -1;
}
else
{
if (fb.st_dev == tb.st_dev && fb.st_ino == tb.st_ino)
return 0; /* same file */
if (unlink (to) < 0 && errno != ENOENT)
return -1;
}
if (link (from, to) < 0)
return (-1);
unlink (from);
if (unlink (from) < 0 && errno != ENOENT)
{
int e = errno;
unlink (to);
errno = e;
return (-1);
}
return (0);
}
#endif /* !HAVE_RENAME */
+1
View File
@@ -147,6 +147,7 @@ sh_backslash_quote (string)
case '*': case '[': case '?': case ']': /* globbing chars */
case '^':
case '$': case '`': /* expansion chars */
case ',': /* brace expansion */
*r++ = '\\';
*r++ = c;
break;
+494 -99
View File
@@ -47,9 +47,7 @@
* Currently doesn't handle (and bash/readline doesn't use):
* *M$ width, precision specifications
* %N$ numbered argument conversions
* inf, nan floating values (could use isinf(), isnan())
* `,', `'' flags
* `C', `S' conversions
* inf, nan floating values imperfect (if isinf(), isnan() not in libc)
* support for `F' is imperfect, since underlying printf may not handle it
*/
@@ -65,10 +63,12 @@
#ifdef __linux__
#define HAVE_PRINTF_A_FORMAT
#endif
#define HAVE_ISINF_IN_LIBC
#define PREFER_STDARG
#define HAVE_STRINGIZE
#define HAVE_LIMITS_H
#define HAVE_STDDEF_H
#define HAVE_LOCALE_H
#define intmax_t long
#endif
@@ -96,12 +96,18 @@
#endif
#ifdef FLOATING_POINT
# include <float.h> /* for manifest constants */
# include <stdio.h> /* for sprintf */
#endif
#include <typemax.h>
#ifdef HAVE_LOCALE_H
# include <locale.h>
#endif
#include "stdc.h"
#include <shmbutil.h>
#ifndef DRIVER
# include "shell.h"
@@ -114,6 +120,10 @@ extern char *fmtulong __P((unsigned long int, int, char *, size_t, int));
extern char *fmtullong __P((unsigned long long int, int, char *, size_t, int));
#endif
#ifndef FREE
# define FREE(x) if (x) free (x)
#endif
/* Bound on length of the string representing an integer value of type T.
Subtract one for the sign bit if T is signed;
302 / 1000 is log10 (2) rounded up;
@@ -130,7 +140,7 @@ extern char *fmtullong __P((unsigned long long int, int, char *, size_t, int));
#define PF_ZEROPAD 0x00008 /* 0 */
#define PF_PLUS 0x00010 /* + */
#define PF_SPACE 0x00020 /* ' ' */
#define PF_COMMA 0x00040 /* , */
#define PF_THOUSANDS 0x00040 /* ' */
#define PF_DOT 0x00080 /* `.precision' */
#define PF_STAR_P 0x00100 /* `*' after precision */
@@ -158,6 +168,10 @@ extern char *fmtullong __P((unsigned long long int, int, char *, size_t, int));
static char intbuf[INT_STRLEN_BOUND(unsigned long) + 1];
static int decpoint;
static int thoussep;
static char *grouping;
/*
* For the FLOATING POINT FORMAT :
* the challenge was finding a way to
@@ -196,25 +210,27 @@ static char intbuf[INT_STRLEN_BOUND(unsigned long) + 1];
#define SWAP_INT(a,b) {int t; t = (a); (a) = (b); (b) = t;}
#define GETARG(type) (va_arg(args, type))
/* Macros that do proper sign extension and handle length modifiers. Used
for the integer conversion specifiers. */
#define GETSIGNED(p) \
(((p)->flags & PF_LONGINT) \
? va_arg(args, long) \
: (((p)->flags & PF_SHORTINT) ? (long)(short)va_arg(args, int) \
: (long)va_arg(args, int)))
? GETARG (long) \
: (((p)->flags & PF_SHORTINT) ? (long)(short)GETARG (int) \
: (long)GETARG (int)))
#define GETUNSIGNED(p) \
(((p)->flags & PF_LONGINT) \
? va_arg(args, unsigned long) \
: (((p)->flags & PF_SHORTINT) ? (unsigned long)(unsigned short)va_arg(args, int) \
: (unsigned long)va_arg(args, unsigned int)))
? GETARG (unsigned long) \
: (((p)->flags & PF_SHORTINT) ? (unsigned long)(unsigned short)GETARG (int) \
: (unsigned long)GETARG (unsigned int)))
#ifdef HAVE_LONG_DOUBLE
#define GETLDOUBLE(p) va_arg(args, long double)
#define GETLDOUBLE(p) GETARG (long double)
#endif
#define GETDOUBLE(p) va_arg(args, double)
#define GETDOUBLE(p) GETARG (double)
#define SET_SIZE_FLAGS(p, type) \
if (sizeof (type) > sizeof (int)) \
@@ -271,6 +287,8 @@ static void ldfallback __P((struct DATA *, const char *, const char *, long doub
static void dfallback __P((struct DATA *, const char *, const char *, double));
#endif
static char *groupnum __P((char *));
#ifdef DRIVER
static void memory_error_and_abort ();
static void *xmalloc __P((size_t));
@@ -317,6 +335,20 @@ static void xfree __P((void *));
} \
while (0)
/* Output a string. P->WIDTH has already been adjusted for padding. */
#define PUT_STRING(string, len, p) \
do \
{ \
PAD_RIGHT (p); \
while ((len)-- > 0) \
{ \
PUT_CHAR (*(string), (p)); \
(string)++; \
} \
PAD_LEFT (p); \
} \
while (0)
#define PUT_PLUS(d, p, zero) \
if ((d) > zero && (p)->justify == RIGHT) \
PUT_CHAR('+', p)
@@ -340,9 +372,34 @@ static void xfree __P((void *));
/* if width and prec. in the args */
#define STAR_ARGS(p) \
if ((p)->flags & PF_STAR_W) \
(p)->width = va_arg(args, int); \
(p)->width = GETARG (int); \
if ((p)->flags & PF_STAR_P) \
(p)->precision = va_arg(args, int)
(p)->precision = GETARG (int)
#if defined (HAVE_LOCALE_H)
# define GETLOCALEDATA(d, t, g) \
do \
{ \
struct lconv *lv; \
if ((d) == 0) { \
(d) = '.'; (t) = -1; (g) = 0; /* defaults */ \
lv = localeconv(); \
if (lv) \
{ \
if (lv->decimal_point && lv->decimal_point[0]) \
(d) = lv->decimal_point[0]; \
if (lv->thousands_sep && lv->thousands_sep[0]) \
(t) = lv->thousands_sep[0]; \
(g) = lv->grouping ? lv->grouping : ""; \
if (*(g) == '\0' || *(g) == CHAR_MAX || (t) == -1) (g) = 0; \
} \
} \
} \
while (0);
#else
# define GETLOCALEDATA(d, t, g) \
( (d) = '.', (t) = ',', g = "\003" )
#endif
#ifdef FLOATING_POINT
/*
@@ -496,6 +553,8 @@ numtoa(number, base, precision, fract)
integral_part[1] = '\0';
fraction_part[0] = '0';
fraction_part[1] = '\0';
if (fract)
*fract = fraction_part;
return integral_part;
}
@@ -570,7 +629,7 @@ number(p, d, base)
unsigned long d;
int base;
{
char *tmp;
char *tmp, *t;
long sd;
int flags;
@@ -580,6 +639,14 @@ number(p, d, base)
flags |= FL_HEXUPPER;
tmp = fmtulong (d, base, intbuf, sizeof(intbuf), flags);
t = 0;
if ((p->flags & PF_THOUSANDS))
{
GETLOCALEDATA(decpoint, thoussep, grouping);
if (grouping && (t = groupnum (tmp)))
tmp = t;
}
p->width -= strlen(tmp);
PAD_RIGHT(p);
@@ -609,6 +676,7 @@ number(p, d, base)
}
PAD_LEFT(p);
FREE (t);
}
#ifdef HAVE_LONG_LONG
@@ -621,7 +689,7 @@ lnumber(p, d, base)
unsigned long long d;
int base;
{
char *tmp;
char *tmp, *t;
long long sd;
int flags;
@@ -631,6 +699,14 @@ lnumber(p, d, base)
flags |= FL_HEXUPPER;
tmp = fmtullong (d, base, intbuf, sizeof(intbuf), flags);
t = 0;
if ((p->flags & PF_THOUSANDS))
{
GETLOCALEDATA(decpoint, thoussep, grouping);
if (grouping && (t = groupnum (tmp)))
tmp = t;
}
p->width -= strlen(tmp);
PAD_RIGHT(p);
@@ -660,6 +736,7 @@ lnumber(p, d, base)
}
PAD_LEFT(p);
FREE (t);
}
#endif
@@ -692,34 +769,162 @@ strings(p, tmp)
struct DATA *p;
char *tmp;
{
int i;
size_t len;
i = strlen(tmp);
len = strlen(tmp);
if (p->precision != NOT_FOUND) /* the smallest number */
i = (i < p->precision ? i : p->precision);
p->width -= i;
PAD_RIGHT(p);
while (i-- > 0)
{ /* put the sting */
PUT_CHAR(*tmp, p);
tmp++;
}
PAD_LEFT(p);
len = (len < p->precision ? len : p->precision);
p->width -= len;
PUT_STRING (tmp, len, p);
}
#if HANDLE_MULTIBYTE
/* %ls wide-character strings */
static void
wstrings(p, tmp)
struct DATA *p;
wchar_t *tmp;
{
size_t len;
mbstate_t mbs;
char *os;
const wchar_t *ws;
memset (&mbs, '\0', sizeof (mbstate_t));
ws = (const wchar_t *)tmp;
os = (char *)NULL;
if (p->precision != NOT_FOUND)
{
os = (char *)xmalloc (p->precision + 1);
len = wcsrtombs (os, &ws, p->precision, &mbs);
}
else
{
len = wcsrtombs (NULL, &ws, 0, &mbs);
if (len != (size_t)-1)
{
memset (&mbs, '\0', sizeof (mbstate_t));
os = (char *)xmalloc (len + 1);
(void)wcsrtombs (os, &ws, len + 1, &mbs);
}
}
if (len == (size_t)-1)
{
/* invalid multibyte sequence; bail now. */
FREE (os);
return;
}
p->width -= len;
PUT_STRING (os, len, p);
free (os);
}
static void
wchars (p, wc)
struct DATA *p;
wint_t wc;
{
char *lbuf, *l;
mbstate_t mbs;
size_t len;
lbuf = (char *)malloc (MB_CUR_MAX+1);
if (lbuf == 0)
return;
memset (&mbs, '\0', sizeof (mbstate_t));
len = wcrtomb (lbuf, wc, &mbs);
if (len == (size_t)-1)
/* conversion failed; bail now. */
return;
p->width -= len;
l = lbuf;
PUT_STRING (l, len, p);
free (lbuf);
}
#endif /* HANDLE_MULTIBYTE */
#ifdef FLOATING_POINT
#ifndef HAVE_ISINF_IN_LIBC
/* Half-assed versions, since we don't want to link with libm. */
static int
isinf(d)
double d;
{
#ifdef DBL_MAX
if (d < DBL_MIN)
return -1;
else if (d > DBL_MAX)
return 1;
else
#endif
return 0;
}
static int
isnan(d)
double d;
{
return 0;
}
#endif
/* Check for [+-]infinity and NaN. If MODE == 1, we check for Infinity, else
(mode == 2) we check for NaN. This does the necessary printing. Returns
1 if Inf or Nan, 0 if not. */
static int
chkinfnan(p, d, mode)
struct DATA *p;
double d;
int mode; /* == 1 for inf, == 2 for nan */
{
int i;
char *tmp;
char *big, *small;
i = (mode == 1) ? isinf(d) : isnan(d);
if (i == 0)
return 0;
big = (mode == 1) ? "INF" : "NAN";
small = (mode == 1) ? "inf" : "nan";
tmp = (*p->pf == 'F' || *p->pf == 'G' || *p->pf == 'E') ? big : small;
if (i < 0)
PUT_CHAR('-', p);
while (*tmp)
{
PUT_CHAR (*tmp, p);
tmp++;
}
return 1;
}
/* %f %F %g %G floating point representation */
static void
floating(p, d)
struct DATA *p;
double d;
{
char *tmp, *tmp2;
char *tmp, *tmp2, *t;
int i;
if (chkinfnan(p, d, 1) || chkinfnan(p, d, 2))
return; /* already printed nan or inf */
GETLOCALEDATA(decpoint, thoussep, grouping);
DEF_PREC(p);
d = ROUND(d, p);
tmp = dtoa(d, p->precision, &tmp2);
t = 0;
if ((p->flags & PF_THOUSANDS) && grouping && (t = groupnum (tmp)))
tmp = t;
/* calculate the padding. 1 for the dot */
p->width = p->width -
((d > 0. && p->justify == RIGHT) ? 1:0) -
@@ -728,17 +933,22 @@ floating(p, d)
PAD_RIGHT(p);
PUT_PLUS(d, p, 0.);
PUT_SPACE(d, p, 0.);
while (*tmp)
{ /* the integral */
PUT_CHAR(*tmp, p);
tmp++;
}
FREE (t);
if (p->precision != 0 || (p->flags & PF_ALTFORM))
PUT_CHAR('.', p); /* put the '.' */
PUT_CHAR(decpoint, p); /* put the '.' */
if ((*p->pf == 'g' || *p->pf == 'G') && (p->flags & PF_ALTFORM) == 0)
/* smash the trailing zeros unless altform */
for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
tmp2[i] = '\0';
tmp2[i] = '\0';
for (; *tmp2; tmp2++)
PUT_CHAR(*tmp2, p); /* the fraction */
@@ -752,69 +962,55 @@ exponent(p, d)
double d;
{
char *tmp, *tmp2;
int j, i, nsig, ndig;
int j, i;
if (chkinfnan(p, d, 1) || chkinfnan(p, d, 2))
return; /* already printed nan or inf */
GETLOCALEDATA(decpoint, thoussep, grouping);
DEF_PREC(p);
j = log_10(d);
d = d / pow_10(j); /* get the Mantissa */
d = ROUND(d, p);
tmp = dtoa(d, p->precision, &tmp2);
/* 1 for unit, 1 for the '.', 1 for 'e|E',
* 1 for '+|-', 2 for 'exp' */
/* calculate how much padding need */
p->width = p->width -
((d > 0. && p->justify == RIGHT) ? 1:0) -
((p->flags & PF_SPACE) ? 1:0) - p->precision - 6;
PAD_RIGHT(p);
PUT_PLUS(d, p, 0.);
PUT_SPACE(d, p, 0.);
/*
* When supplied %g or %G, an optional precision is the number of
* significant digits to print.
*
* nsig = number of significant digits we've printed (leading zeros are
* never significant)
* ndig = if non-zero, max number of significant digits to print (only
* applicable to %g/%G)
*/
nsig = ndig = 0;
if ((*p->pf == 'g' || *p->pf == 'G') && (p->flags & PF_DOT))
ndig = (p->precision == 0) ? 1 : p->precision;
while (*tmp)
{
PUT_CHAR(*tmp, p);
tmp++;
if (ndig && (++nsig >= ndig))
break;
}
if ((p->precision != 0 || (p->flags & PF_ALTFORM)) && (ndig == 0 || nsig < ndig))
PUT_CHAR('.', p); /* the '.' */
if (p->precision != 0 || (p->flags & PF_ALTFORM))
PUT_CHAR(decpoint, p); /* the '.' */
if ((*p->pf == 'g' || *p->pf == 'G') && (p->flags & PF_ALTFORM) == 0)
/* smash the trailing zeros unless altform */
for (i = strlen(tmp2) - 1; i >= 0 && tmp2[i] == '0'; i--)
tmp2[i] = '\0';
tmp2[i] = '\0';
for (; *tmp2; tmp2++)
{
if (ndig && (nsig++ >= ndig))
break;
PUT_CHAR(*tmp2, p); /* the fraction */
}
PUT_CHAR(*tmp2, p); /* the fraction */
/* the exponent put the 'e|E' */
if (*p->pf == 'g' || *p->pf == 'e')
{
PUT_CHAR('e', p);
}
PUT_CHAR('e', p);
else
PUT_CHAR('E', p);
PUT_CHAR('E', p);
/* the sign of the exp */
if (j > 0)
{
PUT_CHAR('+', p);
}
PUT_CHAR('+', p);
else
{
PUT_CHAR('-', p);
@@ -825,9 +1021,7 @@ exponent(p, d)
/* pad out to at least two spaces. pad with `0' if the exponent is a
single digit. */
if (j <= 9)
{
PUT_CHAR('0', p);
}
PUT_CHAR('0', p);
/* the exponent */
while (*tmp)
@@ -839,6 +1033,69 @@ exponent(p, d)
}
#endif
/* Return a new string with the digits in S grouped according to the locale's
grouping info and thousands separator. If no grouping should be performed,
this returns NULL; the caller needs to check for it. */
static char *
groupnum (s)
char *s;
{
char *se, *ret, *re, *g;
int len, slen;
if (grouping == 0 || *grouping <= 0 || *grouping == CHAR_MAX)
return ((char *)NULL);
/* find min grouping to size returned string */
for (len = *grouping, g = grouping; *g; g++)
if (*g > 0 && *g < len)
len = *g;
slen = strlen (s);
len = slen / len + 1;
ret = (char *)xmalloc (slen + len + 1);
re = ret + slen + len;
*re = '\0';
g = grouping;
se = s + slen;
len = *g;
while (se > s)
{
*--re = *--se;
/* handle `-' inserted by numtoa() and the fmtu* family here. */
if (se > s && se[-1] == '-')
continue;
/* begin new group. */
if (--len == 0 && se > s)
{
*--re = thoussep;
len = *++g; /* was g++, but that uses first char twice (glibc bug, too) */
if (*g == '\0')
len = *--g; /* use previous grouping */
else if (*g == CHAR_MAX)
{
do
*--re = *--se;
while (se > s);
break;
}
}
}
if (re > ret)
#ifdef HAVE_MEMMOVE
memmove (ret, re, strlen (re) + 1);
#else
strcpy (ret, re);
#endif
return ret;
}
/* initialize the conversion specifiers */
static void
init_conv_flag (p)
@@ -887,18 +1144,26 @@ vsnprintf_internal(data, string, length, format, args)
#endif
int state, i, c, n;
char *s;
#if HANDLE_MULTIBYTE
wchar_t *ws;
wint_t wc;
#endif
const char *convstart;
/* Sanity check, the string must be > 1. C99 actually says that LENGTH
can be zero here, in the case of snprintf/vsnprintf (it's never 0 in
the case of asprintf/vasprintf), and the return value is the number
/* Sanity check, the string length must be >= 0. C99 actually says that
LENGTH can be zero here, in the case of snprintf/vsnprintf (it's never
0 in the case of asprintf/vasprintf), and the return value is the number
of characters that would have been written. */
if (length < 1)
if (length < 0)
return -1;
if (format == 0)
return 0;
/* Reset these for each call because the locale might have changed. */
decpoint = thoussep = 0;
grouping = 0;
for (; c = *(data->pf); data->pf++)
{
if (c != '%')
@@ -966,8 +1231,8 @@ vsnprintf_internal(data, string, length, format, args)
data->flags |= PF_PLUS;
data->justify = RIGHT;
continue;
case ',':
data->flags |= PF_COMMA; /* not implemented yet */
case '\'':
data->flags |= PF_THOUSANDS;
continue;
case '1': case '2': case '3':
@@ -1043,9 +1308,18 @@ conv_break:
* else use %e|%E
*/
if (-4 < i && i < data->precision)
floating(data, d);
{
/* reset precision */
data->precision -= i + 1;
floating(data, d);
}
else
exponent(data, d);
{
/* reduce precision by 1 because of leading digit before
decimal point in e format. */
data->precision--;
exponent(data, d);
}
state = 0;
break;
case 'e':
@@ -1073,7 +1347,7 @@ conv_break:
#ifdef HAVE_LONG_LONG
if (data->flags & PF_LONGLONG)
{
ull = va_arg(args, unsigned long long);
ull = GETARG (unsigned long long);
lnumber(data, ull, 10);
}
else
@@ -1093,7 +1367,7 @@ conv_break:
#ifdef HAVE_LONG_LONG
if (data->flags & PF_LONGLONG)
{
ull = va_arg(args, long long);
ull = GETARG (long long);
lnumber(data, ull, 10);
}
else
@@ -1109,7 +1383,7 @@ conv_break:
#ifdef HAVE_LONG_LONG
if (data->flags & PF_LONGLONG)
{
ull = va_arg(args, unsigned long long);
ull = GETARG (unsigned long long);
lnumber(data, ull, 8);
}
else
@@ -1126,7 +1400,7 @@ conv_break:
#ifdef HAVE_LONG_LONG
if (data->flags & PF_LONGLONG)
{
ull = va_arg(args, unsigned long long);
ull = GETARG (unsigned long long);
lnumber(data, ull, 16);
}
else
@@ -1139,33 +1413,64 @@ conv_break:
break;
case 'p':
STAR_ARGS(data);
ul = (unsigned long)va_arg(args, void *);
ul = (unsigned long)GETARG (void *);
pointer(data, ul);
state = 0;
break;
#if HANDLE_MULTIBYTE
case 'C':
data->flags |= PF_LONGINT;
/* FALLTHROUGH */
#endif
case 'c': /* character */
ul = va_arg(args, int);
PUT_CHAR(ul, data);
STAR_ARGS(data);
#if HANDLE_MULTIBYTE
if (data->flags & PF_LONGINT)
{
wc = GETARG (wint_t);
wchars (data, wc);
}
else
#endif
{
ul = GETARG (int);
PUT_CHAR(ul, data);
}
state = 0;
break;
#if HANDLE_MULTIBYTE
case 'S':
data->flags |= PF_LONGINT;
/* FALLTHROUGH */
#endif
case 's': /* string */
STAR_ARGS(data);
s = va_arg(args, char *);
strings(data, s);
#if HANDLE_MULTIBYTE
if (data->flags & PF_LONGINT)
{
ws = GETARG (wchar_t *);
wstrings (data, ws);
}
else
#endif
{
s = GETARG (char *);
strings(data, s);
}
state = 0;
break;
case 'n':
#ifdef HAVE_LONG_LONG
if (data->flags & PF_LONGLONG)
*(va_arg(args, long long *)) = data->counter;
*(GETARG (long long *)) = data->counter;
else
#endif
if (data->flags & PF_LONGINT)
*(va_arg(args, long *)) = data->counter;
*(GETARG (long *)) = data->counter;
else if (data->flags & PF_SHORTINT)
*(va_arg(args, short *)) = data->counter;
*(GETARG (short *)) = data->counter;
else
*(va_arg(args, int *)) = data->counter;
*(GETARG (int *)) = data->counter;
state = 0;
break;
case '%': /* nothing just % */
@@ -1201,7 +1506,7 @@ ldfallback (data, fs, fe, ld)
char fmtbuf[FALLBACK_FMTSIZE], *obuf;
int fl;
obuf = xmalloc(LFALLBACK_BASE + (data->precision < 6 ? 6 : data->precision) + 2);
obuf = (char *)xmalloc(LFALLBACK_BASE + (data->precision < 6 ? 6 : data->precision) + 2);
fl = fe - fs + 1;
strncpy (fmtbuf, fs, fl);
fmtbuf[fl] = '\0';
@@ -1248,6 +1553,8 @@ vsnprintf(string, length, format, args)
{
struct DATA data;
if (string == 0 && length != 0)
return 0;
init_data (&data, string, length, format, PFM_SN);
return (vsnprintf_internal(&data, string, length, format, args));
}
@@ -1267,12 +1574,10 @@ snprintf(string, length, format, va_alist)
int rval;
va_list args;
#if defined(PREFER_STDARG)
va_start(args, format);
#else
va_start(args);
#endif
SH_VA_START(args, format);
if (string == 0 && length != 0)
return 0;
init_data (&data, string, length, format, PFM_SN);
rval = vsnprintf_internal (&data, string, length, format, args);
@@ -1319,11 +1624,7 @@ asprintf(stringp, format, va_alist)
int rval;
va_list args;
#if defined(PREFER_STDARG)
va_start(args, format);
#else
va_start(args);
#endif
SH_VA_START(args, format);
rval = vasprintf (stringp, format, args);
@@ -1378,10 +1679,6 @@ xfree(x)
free (x);
}
#ifdef FLOATING_POINT
# include <float.h>
#endif
/* set of small tests for snprintf() */
main()
{
@@ -1389,6 +1686,18 @@ main()
char *h;
int i, si, ai;
#ifdef HAVE_LOCALE_H
setlocale(LC_ALL, "");
#endif
#if 1
si = snprintf((char *)NULL, 0, "abcde\n");
printf("snprintf returns %d with NULL first argument and size of 0\n", si);
si = snprintf(holder, 0, "abcde\n");
printf("snprintf returns %d with non-NULL first argument and size of 0\n", si);
si = snprintf((char *)NULL, 16, "abcde\n");
printf("snprintf returns %d with NULL first argument and non-zero size\n", si);
/*
printf("Suite of test for snprintf:\n");
printf("a_format\n");
@@ -1660,6 +1969,92 @@ main()
printf ("<%d> <%s>\n", si, holder);
printf ("<%d> <%s>\n\n", ai, h);
/* huh? */
printf("/%%g/, 421.2345\n");
snprintf(holder, sizeof holder, "/%g/\n", 421.2345);
asprintf(&h, "/%g/\n", 421.2345);
printf("/%g/\n", 421.2345);
printf("%s", holder);
printf("%s\n", h);
printf("/%%g/, 4214.2345\n");
snprintf(holder, sizeof holder, "/%g/\n", 4214.2345);
asprintf(&h, "/%g/\n", 4214.2345);
printf("/%g/\n", 4214.2345);
printf("%s", holder);
printf("%s\n", h);
printf("/%%.5g/, 4214.2345\n");
snprintf(holder, sizeof holder, "/%.5g/\n", 4214.2345);
asprintf(&h, "/%.5g/\n", 4214.2345);
printf("/%.5g/\n", 4214.2345);
printf("%s", holder);
printf("%s\n", h);
printf("/%%.4g/, 4214.2345\n");
snprintf(holder, sizeof holder, "/%.4g/\n", 4214.2345);
asprintf(&h, "/%.4g/\n", 4214.2345);
printf("/%.4g/\n", 4214.2345);
printf("%s", holder);
printf("%s\n", h);
printf("/%%'ld %%'ld/, 12345, 1234567\n");
snprintf(holder, sizeof holder, "/%'ld %'ld/\n", 12345, 1234567);
asprintf(&h, "/%'ld %'ld/\n", 12345, 1234567);
printf("/%'ld %'ld/\n", 12345, 1234567);
printf("%s", holder);
printf("%s\n", h);
printf("/%%'ld %%'ld/, 336, 3336\n");
snprintf(holder, sizeof holder, "/%'ld %'ld/\n", 336, 3336);
asprintf(&h, "/%'ld %'ld/\n", 336, 3336);
printf("/%'ld %'ld/\n", 336, 3336);
printf("%s", holder);
printf("%s\n", h);
printf("/%%'ld %%'ld/, -42786, -142786\n");
snprintf(holder, sizeof holder, "/%'ld %'ld/\n", -42786, -142786);
asprintf(&h, "/%'ld %'ld/\n", -42786, -142786);
printf("/%'ld %'ld/\n", -42786, -142786);
printf("%s", holder);
printf("%s\n", h);
printf("/%%'f %%'f/, 421.2345, 421234.56789\n");
snprintf(holder, sizeof holder, "/%'f %'f/\n", 421.2345, 421234.56789);
asprintf(&h, "/%'f %'f/\n", 421.2345, 421234.56789);
printf("/%'f %'f/\n", 421.2345, 421234.56789);
printf("%s", holder);
printf("%s\n", h);
printf("/%%'f %%'f/, -421.2345, -421234.56789\n");
snprintf(holder, sizeof holder, "/%'f %'f/\n", -421.2345, -421234.56789);
asprintf(&h, "/%'f %'f/\n", -421.2345, -421234.56789);
printf("/%'f %'f/\n", -421.2345, -421234.56789);
printf("%s", holder);
printf("%s\n", h);
printf("/%%'g %%'g/, 421.2345, 421234.56789\n");
snprintf(holder, sizeof holder, "/%'g %'g/\n", 421.2345, 421234.56789);
asprintf(&h, "/%'g %'g/\n", 421.2345, 421234.56789);
printf("/%'g %'g/\n", 421.2345, 421234.56789);
printf("%s", holder);
printf("%s\n", h);
printf("/%%'g %%'g/, -421.2345, -421234.56789\n");
snprintf(holder, sizeof holder, "/%'g %'g/\n", -421.2345, -421234.56789);
asprintf(&h, "/%'g %'g/\n", -421.2345, -421234.56789);
printf("/%'g %'g/\n", -421.2345, -421234.56789);
printf("%s", holder);
printf("%s\n", h);
#endif
printf("/%%'g/, 4213455.8392\n");
snprintf(holder, sizeof holder, "/%'g/\n", 4213455.8392);
asprintf(&h, "/%'g/\n", 4213455.8392);
printf("/%'g/\n", 4213455.8392);
printf("%s", holder);
printf("%s\n", h);
exit (0);
}
#endif
+3 -1
View File
@@ -38,8 +38,10 @@ Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
#include <bashansi.h>
#include <maxpath.h>
#include <stdc.h>
static int mindist (), spdist ();
static int mindist __P((char *, char *, char *));
static int spdist __P((char *, char *));
/*
* `spname' and its helpers are inspired by the code in "The UNIX
+859
View File
@@ -0,0 +1,859 @@
/*
* Modified slightly by Chet Ramey for inclusion in Bash
*/
/*
* strftime.c
*
* Public-domain implementation of ISO C library routine.
*
* If you can't do prototypes, get GCC.
*
* The C99 standard now specifies just about all of the formats
* that were additional in the earlier versions of this file.
*
* For extensions from SunOS, add SUNOS_EXT.
* For extensions from HP/UX, add HPUX_EXT.
* For VMS dates, add VMS_EXT.
* For complete POSIX semantics, add POSIX_SEMANTICS.
*
* The code for %c, %x, and %X follows the C99 specification for
* the "C" locale.
*
* This version ignores LOCALE information.
* It also doesn't worry about multi-byte characters.
* So there.
*
* This file is also shipped with GAWK (GNU Awk), gawk specific bits of
* code are included if GAWK is defined.
*
* Arnold Robbins
* January, February, March, 1991
* Updated March, April 1992
* Updated April, 1993
* Updated February, 1994
* Updated May, 1994
* Updated January, 1995
* Updated September, 1995
* Updated January, 1996
* Updated July, 1997
* Updated October, 1999
* Updated September, 2000
*
* Fixes from ado@elsie.nci.nih.gov,
* February 1991, May 1992
* Fixes from Tor Lillqvist tml@tik.vtt.fi,
* May 1993
* Further fixes from ado@elsie.nci.nih.gov,
* February 1994
* %z code from chip@chinacat.unicom.com,
* Applied September 1995
* %V code fixed (again) and %G, %g added,
* January 1996
* %v code fixed, better configuration,
* July 1997
* Moved to C99 specification.
* September 2000
*/
#include <config.h>
#ifndef GAWK
#include <stdio.h>
#include <ctype.h>
#include <time.h>
#endif
#if defined(TM_IN_SYS_TIME)
#include <sys/types.h>
#include <sys/time.h>
#endif
#include <stdlib.h>
#include <string.h>
/* defaults: season to taste */
#define SUNOS_EXT 1 /* stuff in SunOS strftime routine */
#define VMS_EXT 1 /* include %v for VMS date format */
#define HPUX_EXT 1 /* non-conflicting stuff in HP-UX date */
#ifndef GAWK
#define POSIX_SEMANTICS 1 /* call tzset() if TZ changes */
#endif
#undef strchr /* avoid AIX weirdness */
extern void tzset(void);
static int weeknumber(const struct tm *timeptr, int firstweekday);
static int iso8601wknum(const struct tm *timeptr);
#ifdef __GNUC__
#define inline __inline__
#else
#define inline /**/
#endif
#define range(low, item, hi) max(low, min(item, hi))
#if !defined(OS2) && !defined(MSDOS) && defined(HAVE_TZNAME)
extern char *tzname[2];
extern int daylight;
#if defined(SOLARIS) || defined(mips)
extern long int timezone, altzone;
#else
extern int timezone, altzone;
#endif
#endif
#undef min /* just in case */
/* min --- return minimum of two numbers */
static inline int
min(int a, int b)
{
return (a < b ? a : b);
}
#undef max /* also, just in case */
/* max --- return maximum of two numbers */
static inline int
max(int a, int b)
{
return (a > b ? a : b);
}
/* strftime --- produce formatted time */
size_t
strftime(char *s, size_t maxsize, const char *format, const struct tm *timeptr)
{
char *endp = s + maxsize;
char *start = s;
auto char tbuf[100];
long off;
int i, w, y;
static short first = 1;
#ifdef POSIX_SEMANTICS
static char *savetz = NULL;
static int savetzlen = 0;
char *tz;
#endif /* POSIX_SEMANTICS */
#ifndef HAVE_TM_ZONE
#ifndef HAVE_TM_NAME
#ifndef HAVE_TZNAME
extern char *timezone();
struct timeval tv;
struct timezone zone;
#endif /* HAVE_TZNAME */
#endif /* HAVE_TM_NAME */
#endif /* HAVE_TM_ZONE */
/* various tables, useful in North America */
static const char *days_a[] = {
"Sun", "Mon", "Tue", "Wed",
"Thu", "Fri", "Sat",
};
static const char *days_l[] = {
"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday",
};
static const char *months_a[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
};
static const char *months_l[] = {
"January", "February", "March", "April",
"May", "June", "July", "August", "September",
"October", "November", "December",
};
static const char *ampm[] = { "AM", "PM", };
if (s == NULL || format == NULL || timeptr == NULL || maxsize == 0)
return 0;
/* quick check if we even need to bother */
if (strchr(format, '%') == NULL && strlen(format) + 1 >= maxsize)
return 0;
#ifndef POSIX_SEMANTICS
if (first) {
tzset();
first = 0;
}
#else /* POSIX_SEMANTICS */
#if defined (SHELL)
tz = get_string_value ("TZ");
#else
tz = getenv("TZ");
#endif
if (first) {
if (tz != NULL) {
int tzlen = strlen(tz);
savetz = (char *) malloc(tzlen + 1);
if (savetz != NULL) {
savetzlen = tzlen + 1;
strcpy(savetz, tz);
}
}
tzset();
first = 0;
}
/* if we have a saved TZ, and it is different, recapture and reset */
if (tz && savetz && (tz[0] != savetz[0] || strcmp(tz, savetz) != 0)) {
i = strlen(tz) + 1;
if (i > savetzlen) {
savetz = (char *) realloc(savetz, i);
if (savetz) {
savetzlen = i;
strcpy(savetz, tz);
}
} else
strcpy(savetz, tz);
tzset();
}
#endif /* POSIX_SEMANTICS */
for (; *format && s < endp - 1; format++) {
tbuf[0] = '\0';
if (*format != '%') {
*s++ = *format;
continue;
}
again:
switch (*++format) {
case '\0':
*s++ = '%';
goto out;
case '%':
*s++ = '%';
continue;
case 'a': /* abbreviated weekday name */
if (timeptr->tm_wday < 0 || timeptr->tm_wday > 6)
strcpy(tbuf, "?");
else
strcpy(tbuf, days_a[timeptr->tm_wday]);
break;
case 'A': /* full weekday name */
if (timeptr->tm_wday < 0 || timeptr->tm_wday > 6)
strcpy(tbuf, "?");
else
strcpy(tbuf, days_l[timeptr->tm_wday]);
break;
case 'b': /* abbreviated month name */
short_month:
if (timeptr->tm_mon < 0 || timeptr->tm_mon > 11)
strcpy(tbuf, "?");
else
strcpy(tbuf, months_a[timeptr->tm_mon]);
break;
case 'B': /* full month name */
if (timeptr->tm_mon < 0 || timeptr->tm_mon > 11)
strcpy(tbuf, "?");
else
strcpy(tbuf, months_l[timeptr->tm_mon]);
break;
case 'c': /* appropriate date and time representation */
/*
* This used to be:
*
* strftime(tbuf, sizeof tbuf, "%a %b %e %H:%M:%S %Y", timeptr);
*
* Now, per the ISO 1999 C standard, it this:
*/
strftime(tbuf, sizeof tbuf, "%A %B %d %T %Y", timeptr);
break;
case 'C':
century:
sprintf(tbuf, "%02d", (timeptr->tm_year + 1900) / 100);
break;
case 'd': /* day of the month, 01 - 31 */
i = range(1, timeptr->tm_mday, 31);
sprintf(tbuf, "%02d", i);
break;
case 'D': /* date as %m/%d/%y */
strftime(tbuf, sizeof tbuf, "%m/%d/%y", timeptr);
break;
case 'e': /* day of month, blank padded */
sprintf(tbuf, "%2d", range(1, timeptr->tm_mday, 31));
break;
case 'E':
/* POSIX (now C99) locale extensions, ignored for now */
goto again;
case 'F': /* ISO 8601 date representation */
strftime(tbuf, sizeof tbuf, "%Y-%m-%d", timeptr);
break;
case 'g':
case 'G':
/*
* Year of ISO week.
*
* If it's December but the ISO week number is one,
* that week is in next year.
* If it's January but the ISO week number is 52 or
* 53, that week is in last year.
* Otherwise, it's this year.
*/
w = iso8601wknum(timeptr);
if (timeptr->tm_mon == 11 && w == 1)
y = 1900 + timeptr->tm_year + 1;
else if (timeptr->tm_mon == 0 && w >= 52)
y = 1900 + timeptr->tm_year - 1;
else
y = 1900 + timeptr->tm_year;
if (*format == 'G')
sprintf(tbuf, "%d", y);
else
sprintf(tbuf, "%02d", y % 100);
break;
case 'h': /* abbreviated month name */
goto short_month;
case 'H': /* hour, 24-hour clock, 00 - 23 */
i = range(0, timeptr->tm_hour, 23);
sprintf(tbuf, "%02d", i);
break;
case 'I': /* hour, 12-hour clock, 01 - 12 */
i = range(0, timeptr->tm_hour, 23);
if (i == 0)
i = 12;
else if (i > 12)
i -= 12;
sprintf(tbuf, "%02d", i);
break;
case 'j': /* day of the year, 001 - 366 */
sprintf(tbuf, "%03d", timeptr->tm_yday + 1);
break;
case 'm': /* month, 01 - 12 */
i = range(0, timeptr->tm_mon, 11);
sprintf(tbuf, "%02d", i + 1);
break;
case 'M': /* minute, 00 - 59 */
i = range(0, timeptr->tm_min, 59);
sprintf(tbuf, "%02d", i);
break;
case 'n': /* same as \n */
tbuf[0] = '\n';
tbuf[1] = '\0';
break;
case 'O':
/* POSIX (now C99) locale extensions, ignored for now */
goto again;
case 'p': /* am or pm based on 12-hour clock */
i = range(0, timeptr->tm_hour, 23);
if (i < 12)
strcpy(tbuf, ampm[0]);
else
strcpy(tbuf, ampm[1]);
break;
case 'r': /* time as %I:%M:%S %p */
strftime(tbuf, sizeof tbuf, "%I:%M:%S %p", timeptr);
break;
case 'R': /* time as %H:%M */
strftime(tbuf, sizeof tbuf, "%H:%M", timeptr);
break;
#if defined(HAVE_MKTIME) || defined(GAWK)
case 's': /* time as seconds since the Epoch */
{
struct tm non_const_timeptr;
non_const_timeptr = *timeptr;
sprintf(tbuf, "%ld", mktime(& non_const_timeptr));
break;
}
#endif /* defined(HAVE_MKTIME) || defined(GAWK) */
case 'S': /* second, 00 - 60 */
i = range(0, timeptr->tm_sec, 60);
sprintf(tbuf, "%02d", i);
break;
case 't': /* same as \t */
tbuf[0] = '\t';
tbuf[1] = '\0';
break;
case 'T': /* time as %H:%M:%S */
the_time:
strftime(tbuf, sizeof tbuf, "%H:%M:%S", timeptr);
break;
case 'u':
/* ISO 8601: Weekday as a decimal number [1 (Monday) - 7] */
sprintf(tbuf, "%d", timeptr->tm_wday == 0 ? 7 :
timeptr->tm_wday);
break;
case 'U': /* week of year, Sunday is first day of week */
sprintf(tbuf, "%02d", weeknumber(timeptr, 0));
break;
case 'V': /* week of year according ISO 8601 */
sprintf(tbuf, "%02d", iso8601wknum(timeptr));
break;
case 'w': /* weekday, Sunday == 0, 0 - 6 */
i = range(0, timeptr->tm_wday, 6);
sprintf(tbuf, "%d", i);
break;
case 'W': /* week of year, Monday is first day of week */
sprintf(tbuf, "%02d", weeknumber(timeptr, 1));
break;
case 'x': /* appropriate date representation */
strftime(tbuf, sizeof tbuf, "%A %B %d %Y", timeptr);
break;
case 'X': /* appropriate time representation */
goto the_time;
break;
case 'y': /* year without a century, 00 - 99 */
year:
i = timeptr->tm_year % 100;
sprintf(tbuf, "%02d", i);
break;
case 'Y': /* year with century */
fullyear:
sprintf(tbuf, "%d", 1900 + timeptr->tm_year);
break;
/*
* From: Chip Rosenthal <chip@chinacat.unicom.com>
* Date: Sun, 19 Mar 1995 00:33:29 -0600 (CST)
*
* Warning: the %z [code] is implemented by inspecting the
* timezone name conditional compile settings, and
* inferring a method to get timezone offsets. I've tried
* this code on a couple of machines, but I don't doubt
* there is some system out there that won't like it.
* Maybe the easiest thing to do would be to bracket this
* with an #ifdef that can turn it off. The %z feature
* would be an admittedly obscure one that most folks can
* live without, but it would be a great help to those of
* us that muck around with various message processors.
*/
case 'z': /* time zone offset east of GMT e.g. -0600 */
#ifdef HAVE_TM_NAME
/*
* Systems with tm_name probably have tm_tzadj as
* secs west of GMT. Convert to mins east of GMT.
*/
off = -timeptr->tm_tzadj / 60;
#else /* !HAVE_TM_NAME */
#ifdef HAVE_TM_ZONE
/*
* Systems with tm_zone probably have tm_gmtoff as
* secs east of GMT. Convert to mins east of GMT.
*/
off = timeptr->tm_gmtoff / 60;
#else /* !HAVE_TM_ZONE */
#if HAVE_TZNAME
/*
* Systems with tzname[] probably have timezone as
* secs west of GMT. Convert to mins east of GMT.
*/
off = -(daylight ? timezone : altzone) / 60;
#else /* !HAVE_TZNAME */
off = -zone.tz_minuteswest;
#endif /* !HAVE_TZNAME */
#endif /* !HAVE_TM_ZONE */
#endif /* !HAVE_TM_NAME */
if (off < 0) {
tbuf[0] = '-';
off = -off;
} else {
tbuf[0] = '+';
}
sprintf(tbuf+1, "%02d%02d", off/60, off%60);
break;
case 'Z': /* time zone name or abbrevation */
#ifdef HAVE_TZNAME
i = (daylight && timeptr->tm_isdst > 0); /* 0 or 1 */
strcpy(tbuf, tzname[i]);
#else
#ifdef HAVE_TM_ZONE
strcpy(tbuf, timeptr->tm_zone);
#else
#ifdef HAVE_TM_NAME
strcpy(tbuf, timeptr->tm_name);
#else
gettimeofday(& tv, & zone);
strcpy(tbuf, timezone(zone.tz_minuteswest,
timeptr->tm_isdst > 0));
#endif /* HAVE_TM_NAME */
#endif /* HAVE_TM_ZONE */
#endif /* HAVE_TZNAME */
break;
#ifdef SUNOS_EXT
case 'k': /* hour, 24-hour clock, blank pad */
sprintf(tbuf, "%2d", range(0, timeptr->tm_hour, 23));
break;
case 'l': /* hour, 12-hour clock, 1 - 12, blank pad */
i = range(0, timeptr->tm_hour, 23);
if (i == 0)
i = 12;
else if (i > 12)
i -= 12;
sprintf(tbuf, "%2d", i);
break;
#endif
#ifdef HPUX_EXT
case 'N': /* Emperor/Era name */
/* this is essentially the same as the century */
goto century; /* %C */
case 'o': /* Emperor/Era year */
goto year; /* %y */
#endif /* HPUX_EXT */
#ifdef VMS_EXT
case 'v': /* date as dd-bbb-YYYY */
sprintf(tbuf, "%2d-%3.3s-%4d",
range(1, timeptr->tm_mday, 31),
months_a[range(0, timeptr->tm_mon, 11)],
timeptr->tm_year + 1900);
for (i = 3; i < 6; i++)
if (islower(tbuf[i]))
tbuf[i] = toupper(tbuf[i]);
break;
#endif
default:
tbuf[0] = '%';
tbuf[1] = *format;
tbuf[2] = '\0';
break;
}
i = strlen(tbuf);
if (i) {
if (s + i < endp - 1) {
strcpy(s, tbuf);
s += i;
} else
return 0;
}
}
out:
if (s < endp && *format == '\0') {
*s = '\0';
return (s - start);
} else
return 0;
}
/* isleap --- is a year a leap year? */
static int
isleap(int year)
{
return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0);
}
/* iso8601wknum --- compute week number according to ISO 8601 */
static int
iso8601wknum(const struct tm *timeptr)
{
/*
* From 1003.2:
* If the week (Monday to Sunday) containing January 1
* has four or more days in the new year, then it is week 1;
* otherwise it is the highest numbered week of the previous
* year (52 or 53), and the next week is week 1.
*
* ADR: This means if Jan 1 was Monday through Thursday,
* it was week 1, otherwise week 52 or 53.
*
* XPG4 erroneously included POSIX.2 rationale text in the
* main body of the standard. Thus it requires week 53.
*/
int weeknum, jan1day, diff;
/* get week number, Monday as first day of the week */
weeknum = weeknumber(timeptr, 1);
/*
* With thanks and tip of the hatlo to tml@tik.vtt.fi
*
* What day of the week does January 1 fall on?
* We know that
* (timeptr->tm_yday - jan1.tm_yday) MOD 7 ==
* (timeptr->tm_wday - jan1.tm_wday) MOD 7
* and that
* jan1.tm_yday == 0
* and that
* timeptr->tm_wday MOD 7 == timeptr->tm_wday
* from which it follows that. . .
*/
jan1day = timeptr->tm_wday - (timeptr->tm_yday % 7);
if (jan1day < 0)
jan1day += 7;
/*
* If Jan 1 was a Monday through Thursday, it was in
* week 1. Otherwise it was last year's highest week, which is
* this year's week 0.
*
* What does that mean?
* If Jan 1 was Monday, the week number is exactly right, it can
* never be 0.
* If it was Tuesday through Thursday, the weeknumber is one
* less than it should be, so we add one.
* Otherwise, Friday, Saturday or Sunday, the week number is
* OK, but if it is 0, it needs to be 52 or 53.
*/
switch (jan1day) {
case 1: /* Monday */
break;
case 2: /* Tuesday */
case 3: /* Wednesday */
case 4: /* Thursday */
weeknum++;
break;
case 5: /* Friday */
case 6: /* Saturday */
case 0: /* Sunday */
if (weeknum == 0) {
#ifdef USE_BROKEN_XPG4
/* XPG4 (as of March 1994) says 53 unconditionally */
weeknum = 53;
#else
/* get week number of last week of last year */
struct tm dec31ly; /* 12/31 last year */
dec31ly = *timeptr;
dec31ly.tm_year--;
dec31ly.tm_mon = 11;
dec31ly.tm_mday = 31;
dec31ly.tm_wday = (jan1day == 0) ? 6 : jan1day - 1;
dec31ly.tm_yday = 364 + isleap(dec31ly.tm_year + 1900);
weeknum = iso8601wknum(& dec31ly);
#endif
}
break;
}
if (timeptr->tm_mon == 11) {
/*
* The last week of the year
* can be in week 1 of next year.
* Sigh.
*
* This can only happen if
* M T W
* 29 30 31
* 30 31
* 31
*/
int wday, mday;
wday = timeptr->tm_wday;
mday = timeptr->tm_mday;
if ( (wday == 1 && (mday >= 29 && mday <= 31))
|| (wday == 2 && (mday == 30 || mday == 31))
|| (wday == 3 && mday == 31))
weeknum = 1;
}
return weeknum;
}
/* weeknumber --- figure how many weeks into the year */
/* With thanks and tip of the hatlo to ado@elsie.nci.nih.gov */
static int
weeknumber(const struct tm *timeptr, int firstweekday)
{
int wday = timeptr->tm_wday;
int ret;
if (firstweekday == 1) {
if (wday == 0) /* sunday */
wday = 6;
else
wday--;
}
ret = ((timeptr->tm_yday + 7 - wday) / 7);
if (ret < 0)
ret = 0;
return ret;
}
#if 0
/* ADR --- I'm loathe to mess with ado's code ... */
Date: Wed, 24 Apr 91 20:54:08 MDT
From: Michal Jaegermann <audfax!emory!vm.ucs.UAlberta.CA!NTOMCZAK>
To: arnold@audiofax.com
Hi Arnold,
in a process of fixing of strftime() in libraries on Atari ST I grabbed
some pieces of code from your own strftime. When doing that it came
to mind that your weeknumber() function compiles a little bit nicer
in the following form:
/*
* firstweekday is 0 if starting in Sunday, non-zero if in Monday
*/
{
return (timeptr->tm_yday - timeptr->tm_wday +
(firstweekday ? (timeptr->tm_wday ? 8 : 1) : 7)) / 7;
}
How nicer it depends on a compiler, of course, but always a tiny bit.
Cheers,
Michal
ntomczak@vm.ucs.ualberta.ca
#endif
#ifdef TEST_STRFTIME
/*
* NAME:
* tst
*
* SYNOPSIS:
* tst
*
* DESCRIPTION:
* "tst" is a test driver for the function "strftime".
*
* OPTIONS:
* None.
*
* AUTHOR:
* Karl Vogel
* Control Data Systems, Inc.
* vogelke@c-17igp.wpafb.af.mil
*
* BUGS:
* None noticed yet.
*
* COMPILE:
* cc -o tst -DTEST_STRFTIME strftime.c
*/
/* ADR: I reformatted this to my liking, and deleted some unneeded code. */
#ifndef NULL
#include <stdio.h>
#endif
#include <sys/time.h>
#include <string.h>
#define MAXTIME 132
/*
* Array of time formats.
*/
static char *array[] =
{
"(%%A) full weekday name, var length (Sunday..Saturday) %A",
"(%%B) full month name, var length (January..December) %B",
"(%%C) Century %C",
"(%%D) date (%%m/%%d/%%y) %D",
"(%%E) Locale extensions (ignored) %E",
"(%%F) full month name, var length (January..December) %F",
"(%%H) hour (24-hour clock, 00..23) %H",
"(%%I) hour (12-hour clock, 01..12) %I",
"(%%M) minute (00..59) %M",
"(%%N) Emporer/Era Name %N",
"(%%O) Locale extensions (ignored) %O",
"(%%R) time, 24-hour (%%H:%%M) %R",
"(%%S) second (00..60) %S",
"(%%T) time, 24-hour (%%H:%%M:%%S) %T",
"(%%U) week of year, Sunday as first day of week (00..53) %U",
"(%%V) week of year according to ISO 8601 %V",
"(%%W) week of year, Monday as first day of week (00..53) %W",
"(%%X) appropriate locale time representation (%H:%M:%S) %X",
"(%%Y) year with century (1970...) %Y",
"(%%Z) timezone (EDT), or blank if timezone not determinable %Z",
"(%%a) locale's abbreviated weekday name (Sun..Sat) %a",
"(%%b) locale's abbreviated month name (Jan..Dec) %b",
"(%%c) full date (Sat Nov 4 12:02:33 1989)%n%t%t%t %c",
"(%%d) day of the month (01..31) %d",
"(%%e) day of the month, blank-padded ( 1..31) %e",
"(%%h) should be same as (%%b) %h",
"(%%j) day of the year (001..366) %j",
"(%%k) hour, 24-hour clock, blank pad ( 0..23) %k",
"(%%l) hour, 12-hour clock, blank pad ( 0..12) %l",
"(%%m) month (01..12) %m",
"(%%o) Emporer/Era Year %o",
"(%%p) locale's AM or PM based on 12-hour clock %p",
"(%%r) time, 12-hour (same as %%I:%%M:%%S %%p) %r",
"(%%u) ISO 8601: Weekday as decimal number [1 (Monday) - 7] %u",
"(%%v) VMS date (dd-bbb-YYYY) %v",
"(%%w) day of week (0..6, Sunday == 0) %w",
"(%%x) appropriate locale date representation %x",
"(%%y) last two digits of year (00..99) %y",
"(%%z) timezone offset east of GMT as HHMM (e.g. -0500) %z",
(char *) NULL
};
/* main routine. */
int
main(argc, argv)
int argc;
char **argv;
{
long time();
char *next;
char string[MAXTIME];
int k;
int length;
struct tm *tm;
long clock;
/* Call the function. */
clock = time((long *) 0);
tm = localtime(&clock);
for (k = 0; next = array[k]; k++) {
length = strftime(string, MAXTIME, next, tm);
printf("%s\n", string);
}
exit(0);
}
#endif /* TEST_STRFTIME */
+66 -26
View File
@@ -1,6 +1,6 @@
/* stringlist.c - functions to handle a generic `list of strings' structure */
/* Copyright (C) 2000 Free Software Foundation, Inc.
/* Copyright (C) 2000-2002 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -37,7 +37,7 @@
/* Allocate a new STRINGLIST, with room for N strings. */
STRINGLIST *
alloc_stringlist (n)
strlist_create (n)
int n;
{
STRINGLIST *ret;
@@ -46,7 +46,7 @@ alloc_stringlist (n)
ret = (STRINGLIST *)xmalloc (sizeof (STRINGLIST));
if (n)
{
ret->list = alloc_array (n+1);
ret->list = strvec_create (n+1);
ret->list_size = n;
for (i = 0; i < n; i++)
ret->list[i] = (char *)NULL;
@@ -61,38 +61,64 @@ alloc_stringlist (n)
}
STRINGLIST *
realloc_stringlist (sl, n)
strlist_resize (sl, n)
STRINGLIST *sl;
int n;
{
register int i;
if (sl == 0)
return (sl = alloc_stringlist(n));
return (sl = strlist_create (n));
if (n > sl->list_size)
{
sl->list = (char **)xrealloc (sl->list, (n+1) * sizeof (char *));
sl->list = strvec_resize (sl->list, n + 1);
for (i = sl->list_size; i <= n; i++)
sl->list[i] = (char *)NULL;
sl->list_size = n;
}
return sl;
}
void
strlist_flush (sl)
STRINGLIST *sl;
{
if (sl == 0 || sl->list == 0)
return;
strvec_flush (sl->list);
sl->list_len = 0;
}
void
free_stringlist (sl)
strlist_dispose (sl)
STRINGLIST *sl;
{
if (sl == 0)
return;
if (sl->list)
free_array (sl->list);
strvec_dispose (sl->list);
free (sl);
}
int
strlist_remove (sl, s)
STRINGLIST *sl;
char *s;
{
int r;
if (sl == 0 || sl->list == 0 || sl->list_len == 0)
return 0;
r = strvec_remove (sl->list, s);
if (r)
sl->list_len--;
return r;
}
STRINGLIST *
copy_stringlist (sl)
strlist_copy (sl)
STRINGLIST *sl;
{
STRINGLIST *new;
@@ -100,8 +126,8 @@ copy_stringlist (sl)
if (sl == 0)
return ((STRINGLIST *)0);
new = alloc_stringlist (sl->list_size);
/* I'd like to use copy_array, but that doesn't copy everything. */
new = strlist_create (sl->list_size);
/* I'd like to use strvec_copy, but that doesn't copy everything. */
if (sl->list)
{
for (i = 0; i < sl->list_size; i++)
@@ -118,7 +144,7 @@ copy_stringlist (sl)
/* Return a new STRINGLIST with everything from M1 and M2. */
STRINGLIST *
merge_stringlists (m1, m2)
strlist_merge (m1, m2)
STRINGLIST *m1, *m2;
{
STRINGLIST *sl;
@@ -127,7 +153,7 @@ merge_stringlists (m1, m2)
l1 = m1 ? m1->list_len : 0;
l2 = m2 ? m2->list_len : 0;
sl = alloc_stringlist (l1 + l2 + 1);
sl = strlist_create (l1 + l2 + 1);
for (i = n = 0; i < l1; i++, n++)
sl->list[n] = STRDUP (m1->list[i]);
for (i = 0; i < l2; i++, n++)
@@ -139,20 +165,20 @@ merge_stringlists (m1, m2)
/* Make STRINGLIST M1 contain everything in M1 and M2. */
STRINGLIST *
append_stringlist (m1, m2)
strlist_append (m1, m2)
STRINGLIST *m1, *m2;
{
register int i, n, len1, len2;
if (m1 == 0)
return (m2 ? copy_stringlist (m2) : (STRINGLIST *)0);
return (m2 ? strlist_copy (m2) : (STRINGLIST *)0);
len1 = m1->list_len;
len2 = m2 ? m2->list_len : 0;
if (len2)
{
m1 = realloc_stringlist (m1, len1 + len2 + 1);
m1 = strlist_resize (m1, len1 + len2 + 1);
for (i = 0, n = len1; i < len2; i++, n++)
m1->list[n] = STRDUP (m2->list[i]);
m1->list[n] = (char *)NULL;
@@ -163,7 +189,7 @@ append_stringlist (m1, m2)
}
STRINGLIST *
prefix_suffix_stringlist (sl, prefix, suffix)
strlist_prefix_suffix (sl, prefix, suffix)
STRINGLIST *sl;
char *prefix, *suffix;
{
@@ -197,7 +223,7 @@ prefix_suffix_stringlist (sl, prefix, suffix)
}
void
print_stringlist (sl, prefix)
strlist_print (sl, prefix)
STRINGLIST *sl;
char *prefix;
{
@@ -210,18 +236,32 @@ print_stringlist (sl, prefix)
}
void
sort_stringlist (sl)
strlist_walk (sl, func)
STRINGLIST *sl;
sh_strlist_map_func_t *func;
{
register int i;
if (sl == 0)
return;
for (i = 0; i < sl->list_len; i++)
if ((*func)(sl->list[i]) < 0)
break;
}
void
strlist_sort (sl)
STRINGLIST *sl;
{
if (sl == 0 || sl->list_len == 0 || sl->list == 0)
return;
sort_char_array (sl->list);
strvec_sort (sl->list);
}
STRINGLIST *
word_list_to_stringlist (list, copy, starting_index, ip)
strlist_from_word_list (list, alloc, starting_index, ip)
WORD_LIST *list;
int copy, starting_index, *ip;
int alloc, starting_index, *ip;
{
STRINGLIST *ret;
int slen, len;
@@ -234,7 +274,7 @@ word_list_to_stringlist (list, copy, starting_index, ip)
}
slen = list_length (list);
ret = (STRINGLIST *)xmalloc (sizeof (STRINGLIST));
ret->list = word_list_to_argv (list, copy, starting_index, &len);
ret->list = strvec_from_word_list (list, alloc, starting_index, &len);
ret->list_size = slen + starting_index;
ret->list_len = len;
if (ip)
@@ -243,15 +283,15 @@ word_list_to_stringlist (list, copy, starting_index, ip)
}
WORD_LIST *
stringlist_to_word_list (sl, copy, starting_index)
strlist_to_word_list (sl, alloc, starting_index)
STRINGLIST *sl;
int copy, starting_index;
int alloc, starting_index;
{
WORD_LIST *list;
if (sl == 0 || sl->list == 0)
return ((WORD_LIST *)NULL);
list = argv_to_word_list (sl->list, copy, starting_index);
list = strvec_to_word_list (sl->list, alloc, starting_index);
return list;
}
+122 -29
View File
@@ -1,6 +1,6 @@
/* stringvec.c - function for managing arrays of strings. */
/* stringvec.c - functions for managing arrays of strings. */
/* Copyright (C) 2000 Free Software Foundation, Inc.
/* Copyright (C) 2000-2002 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -32,34 +32,25 @@
#include "shell.h"
#ifdef INCLUDE_UNUSED
/* Find NAME in ARRAY. Return the index of NAME, or -1 if not present.
ARRAY should be NULL terminated. */
int
find_name_in_array (name, array)
char *name, **array;
{
int i;
for (i = 0; array[i]; i++)
if (STREQ (name, array[i]))
return (i);
return (-1);
}
#endif
/* Allocate an array of strings with room for N members. */
char **
alloc_array (n)
strvec_create (n)
int n;
{
return ((char **)xmalloc ((n) * sizeof (char *)));
}
char **
strvec_resize (array, nsize)
char **array;
int nsize;
{
return ((char **)xrealloc (array, nsize * sizeof (char *)));
}
/* Return the length of ARRAY, a NULL terminated array of char *. */
int
array_len (array)
strvec_len (array)
char **array;
{
register int i;
@@ -70,7 +61,7 @@ array_len (array)
/* Free the contents of ARRAY, a NULL terminated array of char *. */
void
free_array_members (array)
strvec_flush (array)
char **array;
{
register int i;
@@ -83,26 +74,65 @@ free_array_members (array)
}
void
free_array (array)
strvec_dispose (array)
char **array;
{
if (array == 0)
return;
free_array_members (array);
strvec_flush (array);
free (array);
}
int
strvec_remove (array, name)
char **array, *name;
{
register int i, j;
char *x;
if (array == 0)
return 0;
for (i = 0; array[i]; i++)
if (STREQ (name, array[i]))
{
x = array[i];
for (j = i; array[j]; j++)
array[j] = array[j + 1];
free (x);
return 1;
}
return 0;
}
#ifdef INCLUDE_UNUSED
/* Find NAME in ARRAY. Return the index of NAME, or -1 if not present.
ARRAY should be NULL terminated. */
int
strvec_search (array, name)
char **array, *name;
{
int i;
for (i = 0; array[i]; i++)
if (STREQ (name, array[i]))
return (i);
return (-1);
}
#endif
/* Allocate and return a new copy of ARRAY and its contents. */
char **
copy_array (array)
strvec_copy (array)
char **array;
{
register int i;
int len;
char **ret;
len = array_len (array);
len = strvec_len (array);
ret = (char **)xmalloc ((len + 1) * sizeof (char *));
for (i = 0; array[i]; i++)
@@ -115,7 +145,7 @@ copy_array (array)
/* Comparison routine for use with qsort() on arrays of strings. Uses
strcoll(3) if available, otherwise it uses strcmp(3). */
int
qsort_string_compare (s1, s2)
strvec_strcmp (s1, s2)
register char **s1, **s2;
{
#if defined (HAVE_STRCOLL)
@@ -132,8 +162,71 @@ qsort_string_compare (s1, s2)
/* Sort ARRAY, a null terminated array of pointers to strings. */
void
sort_char_array (array)
strvec_sort (array)
char **array;
{
qsort (array, array_len (array), sizeof (char *), (QSFUNC *)qsort_string_compare);
qsort (array, strvec_len (array), sizeof (char *), (QSFUNC *)strvec_strcmp);
}
/* Cons up a new array of words. The words are taken from LIST,
which is a WORD_LIST *. If ALLOC is true, everything is malloc'ed,
so you should free everything in this array when you are done.
The array is NULL terminated. If IP is non-null, it gets the
number of words in the returned array. STARTING_INDEX says where
to start filling in the returned array; it can be used to reserve
space at the beginning of the array. */
char **
strvec_from_word_list (list, alloc, starting_index, ip)
WORD_LIST *list;
int alloc, starting_index, *ip;
{
int count;
char **array;
count = list_length (list);
array = (char **)xmalloc ((1 + count + starting_index) * sizeof (char *));
for (count = 0; count < starting_index; count++)
array[count] = (char *)NULL;
for (count = starting_index; list; count++, list = list->next)
array[count] = alloc ? savestring (list->word->word) : list->word->word;
array[count] = (char *)NULL;
if (ip)
*ip = count;
return (array);
}
/* Convert an array of strings into the form used internally by the shell.
ALLOC means to allocate new storage for each WORD_DESC in the returned
list rather than copy the values in ARRAY. STARTING_INDEX says where
in ARRAY to begin. */
WORD_LIST *
strvec_to_word_list (array, alloc, starting_index)
char **array;
int alloc, starting_index;
{
WORD_LIST *list;
WORD_DESC *w;
int i, count;
if (array == 0 || array[0] == 0)
return (WORD_LIST *)NULL;
for (count = 0; array[count]; count++)
;
for (i = starting_index, list = (WORD_LIST *)NULL; i < count; i++)
{
w = make_bare_word (alloc ? array[i] : "");
if (alloc == 0)
{
free (w->word);
w->word = array[i];
}
list = make_word_list (w, list);
}
return (REVERSE_LIST (list, WORD_LIST *));
}
+60 -17
View File
@@ -40,14 +40,15 @@
/* Convert STRING by expanding the escape sequences specified by the
ANSI C standard. If SAWC is non-null, 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. FOR_ECHO is a flag that
means, if non-zero, that we're translating a string for `echo -e',
and therefore should not treat a single quote as a character that
may be escaped with a backslash. */
returning. LEN is the length of STRING. If (FLAGS&1) is non-zero,
that we're translating a string for `echo -e', and therefore should not
treat a single quote as a character that may be escaped with a backslash.
If (FLAGS&2) is non-zero, we're expanding for the parser and want to
quote CTLESC and CTLNUL with CTLESC */
char *
ansicstr (string, len, for_echo, sawc, rlen)
ansicstr (string, len, flags, sawc, rlen)
char *string;
int len, for_echo, *sawc, *rlen;
int len, flags, *sawc, *rlen;
{
int c, temp;
char *ret, *r, *s;
@@ -55,7 +56,7 @@ ansicstr (string, len, for_echo, sawc, rlen)
if (string == 0 || *string == '\0')
return ((char *)NULL);
ret = (char *)xmalloc (len + 1);
ret = (char *)xmalloc (2*len + 1); /* 2*len for possible CTLESC */
for (r = ret, s = string; s && *s; )
{
c = *s++;
@@ -81,7 +82,12 @@ ansicstr (string, len, for_echo, sawc, rlen)
case 't': c = '\t'; break;
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
for (temp = 2, c -= '0'; ISOCTAL (*s) && temp--; s++)
/* If (FLAGS & 1), we're translating a string for echo -e (or
the equivalent xpg_echo option), so we obey the SUSv3/
POSIX-2001 requirement and accept 0-3 octal digits after
a leading `0'. */
temp = 2 + ((flags & 1) && (c == '0'));
for (c -= '0'; ISOCTAL (*s) && temp--; s++)
c = (c * 8) + OCTVALUE (*s);
c &= 0xFF;
break;
@@ -99,7 +105,7 @@ ansicstr (string, len, for_echo, sawc, rlen)
case '\\':
break;
case '\'':
if (for_echo)
if (flags & 1)
*r++ = '\\';
break;
case 'c':
@@ -111,8 +117,17 @@ ansicstr (string, len, for_echo, sawc, rlen)
*rlen = r - ret;
return ret;
}
else if ((flags & 1) == 0 && (c = *s))
{
s++;
c = TOCTRL(c);
break;
}
/*FALLTHROUGH*/
default: *r++ = '\\'; break;
}
if ((flags & 2) && (c == CTLESC || c == CTLNUL))
*r++ = CTLESC;
*r++ = c;
}
}
@@ -129,7 +144,7 @@ ansic_quote (str, flags, rlen)
char *str;
int flags, *rlen;
{
char *r, *ret, *s, obuf[8];
char *r, *ret, *s;
int l, rsize, t;
unsigned char c;
@@ -137,7 +152,7 @@ ansic_quote (str, flags, rlen)
return ((char *)0);
l = strlen (str);
rsize = 2 * l + 4;
rsize = 4 * l + 4;
r = ret = (char *)xmalloc (rsize);
*r++ = '$';
@@ -169,12 +184,10 @@ ansic_quote (str, flags, rlen)
default:
if (ISPRINT (c) == 0)
{
sprintf (obuf, "\\%.3o", c);
t = r - ret;
RESIZE_MALLOCED_BUFFER (ret, t, 5, rsize, 16);
r = ret + t; /* in case reallocated */
for (t = 0; t < 4; t++)
*r++ = obuf[t];
*r++ = '\\';
*r++ = TOCHAR ((c >> 6) & 07);
*r++ = TOCHAR ((c >> 3) & 07);
*r++ = TOCHAR (c & 07);
continue;
}
l = 0;
@@ -193,6 +206,7 @@ ansic_quote (str, flags, rlen)
}
/* return 1 if we need to quote with $'...' because of non-printing chars. */
int
ansic_shouldquote (string)
const char *string;
{
@@ -208,3 +222,32 @@ ansic_shouldquote (string)
return 0;
}
/* $'...' ANSI-C expand the portion of STRING between START and END and
return the result. The result cannot be longer than the input string. */
char *
ansiexpand (string, start, end, lenp)
char *string;
int start, end, *lenp;
{
char *temp, *t;
int len, tlen;
temp = (char *)xmalloc (end - start + 1);
for (tlen = 0, len = start; len < end; )
temp[tlen++] = string[len++];
temp[tlen] = '\0';
if (*temp)
{
t = ansicstr (temp, tlen, 2, (int *)NULL, lenp);
free (temp);
return (t);
}
else
{
if (lenp)
*lenp = 0;
return (temp);
}
}
+1
View File
@@ -24,6 +24,7 @@
#include <bashtypes.h>
#include <posixstat.h>
#include <posixtime.h>
#include <filecntl.h>
#if defined (HAVE_UNISTD_H)
+78
View File
@@ -0,0 +1,78 @@
/* xstrchr.c - strchr(3) that handles multibyte characters. */
/* Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
#include <config.h>
#ifdef HAVE_STDLIB_H
# include <stdlib.h>
#endif
#include "bashansi.h"
#include "shmbutil.h"
#undef xstrchr
/* In some locales, the non-first byte of some multibyte characters have
the same value as some ascii character. Faced with these strings, a
legacy strchr() might return the wrong value. */
char *
#if defined (PROTOTYPES)
xstrchr (const char *s, int c)
#else
xstrchr (s, c)
const char *s;
int c;
#endif
{
#if HANDLE_MULTIBYTE
char *pos;
mbstate_t state;
size_t strlength, mblength;
/* The locale encodings with said weird property are BIG5, BIG5-HKSCS,
GBK, GB18030, SHIFT_JIS, and JOHAB. They exhibit the problem only
when c >= 0x30. We can therefore use the faster bytewise search if
c <= 0x30. */
if ((unsigned char)c >= '0' && MB_CUR_MAX > 1)
{
pos = (char *)s;
memset (&state, '\0', sizeof(mbstate_t));
strlength = strlen (s);
while (strlength > 0)
{
mblength = mbrlen (pos, strlength, &state);
if (mblength == (size_t)-2 || mblength == (size_t)-1 || mblength == (size_t)0)
mblength = 1;
if (c == (unsigned char)*pos)
return pos;
strlength -= mblength;
pos += mblength;
}
return ((char *)NULL);
}
else
#endif
return (strchr (s, c));
}
+68
View File
@@ -0,0 +1,68 @@
/* Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
#include <config.h>
#include <sys/types.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <errno.h>
#include <stdc.h>
#if !defined (errno)
extern int errno;
#endif
extern ssize_t zread __P((int, char *, size_t));
extern int zwrite __P((int, char *, ssize_t));
/* Dump contents of file descriptor FD to OFD. FN is the filename for
error messages (not used right now). */
int
zcatfd (fd, ofd, fn)
int fd, ofd;
char *fn;
{
ssize_t nr;
int rval;
char lbuf[128];
rval = 0;
while (1)
{
nr = zread (fd, lbuf, sizeof (lbuf));
if (nr == 0)
break;
else if (nr < 0)
{
rval = -1;
break;
}
else if (zwrite (ofd, lbuf, nr) < 0)
{
rval = -1;
break;
}
}
return rval;
}
+2 -2
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 1999 Free Software Foundation, Inc.
/* Copyright (C) 1999-2002 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -58,7 +58,7 @@ zread (fd, buf, len)
#define NUM_INTR 3
ssize_t
zread1 (fd, buf, len)
zreadintr (fd, buf, len)
int fd;
char *buf;
size_t len;
+1 -1
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 1999 Free Software Foundation, Inc.
/* Copyright (C) 1999-2002 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.