mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-08-11 04:30:44 +02:00
Imported from ../bash-2.05b.tar.gz.
This commit is contained in:
+38
-7
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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:
|
||||
*/
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include <bashtypes.h>
|
||||
#include <posixstat.h>
|
||||
#include <posixtime.h>
|
||||
#include <filecntl.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user