summaryrefslogtreecommitdiff
path: root/lib/sh
diff options
context:
space:
mode:
authorJari Aalto <jari.aalto@cante.net>2001-04-06 19:14:31 +0000
committerJari Aalto <jari.aalto@cante.net>2009-09-12 16:46:53 +0000
commit28ef6c316f1aff914bb95ac09787a3c83c1815fd (patch)
tree2812fe7ffc9beec4f99856906ddfcafda54cf16a /lib/sh
parentbb70624e964126b7ac4ff085ba163a9c35ffa18f (diff)
downloadbash-28ef6c316f1aff914bb95ac09787a3c83c1815fd.tar.gz
Imported from ../bash-2.05.tar.gz.
Diffstat (limited to 'lib/sh')
-rw-r--r--lib/sh/Makefile.in107
-rw-r--r--lib/sh/makepath.c19
-rw-r--r--lib/sh/netopen.c24
-rw-r--r--lib/sh/pathcanon.c195
-rw-r--r--lib/sh/pathphys.c256
-rw-r--r--lib/sh/shquote.c57
-rw-r--r--lib/sh/spell.c186
-rw-r--r--lib/sh/strcasecmp.c2
-rw-r--r--lib/sh/strindex.c52
-rw-r--r--lib/sh/stringlist.c248
-rw-r--r--lib/sh/stringvec.c141
-rw-r--r--lib/sh/strtol.c4
-rw-r--r--lib/sh/strtrans.c205
-rw-r--r--lib/sh/times.c2
-rw-r--r--lib/sh/tmpfile.c183
-rw-r--r--lib/sh/zread.c2
-rw-r--r--lib/sh/zwrite.c1
17 files changed, 1639 insertions, 45 deletions
diff --git a/lib/sh/Makefile.in b/lib/sh/Makefile.in
index 789c5448..1c52e0d8 100644
--- a/lib/sh/Makefile.in
+++ b/lib/sh/Makefile.in
@@ -64,7 +64,9 @@ 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
+ 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
# The header files for this library.
HSOURCES =
@@ -73,7 +75,9 @@ HSOURCES =
OBJECTS = clktck.o clock.o getcwd.o getenv.o oslib.o setlinebuf.o \
strcasecmp.o strerror.o strtod.o strtol.o strtoul.o \
vprint.o itos.o rename.o zread.o zwrite.o shtty.o \
- inet_aton.o netopen.o strpbrk.o timeval.o makepath.o
+ inet_aton.o netopen.o strpbrk.o timeval.o makepath.o pathcanon.o \
+ pathphys.o tmpfile.o stringlist.o stringvec.o spell.o shquote.o \
+ strtrans.o strindex.o
SUPPORT = Makefile
@@ -108,20 +112,29 @@ getcwd.o: getcwd.c
getenv.o: getenv.c
inet_aton.o: inet_aton.c
itos.o: itos.c
+makepath.o: makepath.c
netopen.o: netopen.c
oslib.o: oslib.c
+pathcanon.o: pathcanon.c
+pathphys.o: pathphys.c
rename.o: rename.c
setlinebuf.o: setlinebuf.c
shquote.o: shquote.c
shtty.o: shtty.c
+spell.o: spell.c
strcasecmp.o: strcasecmp.c
strerror.o: strerror.c
+strindex.o: strindex.c
+stringlist.o: stringlist.c
+stringvec.o: stringvec.c
strpbrk.o: strpbrk.c
strtod.o: strtod.c
strtol.o: strtol.c
strtoul.o: strtoul.c
+strtrans.o: strtrans.c
times.o: times.c
timeval.o: timeval.c
+tmpfile.o: tmpfile.c
vprint.o: vprint.c
zread.o: zread.c
zwrite.o: zwrite.c
@@ -133,20 +146,29 @@ 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
+makepath.o: ${BUILD_DIR}/config.h
netopen.o: ${BUILD_DIR}/config.h
oslib.o: ${BUILD_DIR}/config.h
+pathcanon.o: ${BUILD_DIR}/config.h
+pathphys.o: ${BUILD_DIR}/config.h
rename.o: ${BUILD_DIR}/config.h
setlinebuf.o: ${BUILD_DIR}/config.h
shquote.o: ${BUILD_DIR}/config.h
shtty.o: ${BUILD_DIR}/config.h
+spell.o: ${BUILD_DIR}/config.h
strcasecmp.o: ${BUILD_DIR}/config.h
strerror.o: ${BUILD_DIR}/config.h
+strindex.o: ${BUILD_DIR}/config.h
+stringlist.o: ${BUILD_DIR}/config.h
+stringvec.o: ${BUILD_DIR}/config.h
strpbrk.o: ${BUILD_DIR}/config.h
strtod.o: ${BUILD_DIR}/config.h
strtol.o: ${BUILD_DIR}/config.h
strtoul.o: ${BUILD_DIR}/config.h
+strtrans.o: ${BUILD_DIR}/config.h
times.o: ${BUILD_DIR}/config.h
timeval.o: ${BUILD_DIR}/config.h
+tmpfile.o: ${BUILD_DIR}/config.h
vprint.o: ${BUILD_DIR}/config.h
zread.o: ${BUILD_DIR}/config.h
zwrite.o: ${BUILD_DIR}/config.h
@@ -158,7 +180,7 @@ getcwd.o: ${BASHINCDIR}/posixstat.h ${BASHINCDIR}/posixdir.h
getcwd.o: ${BASHINCDIR}/memalloc.h ${BASHINCDIR}/ansi_stdlib.h
getenv.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h
-getenv.o: ${topdir}/shell.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h
+getenv.o: ${topdir}/shell.h ${topdir}/syntax.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h
getenv.o: ${topdir}/command.h ${BASHINCDIR}/stdc.h ${topdir}/error.h
getenv.o: ${topdir}/general.h ${topdir}/bashtypes.h ${topdir}/variables.h
getenv.o: ${topdir}/array.h ${topdir}/hashlib.h ${topdir}/quit.h
@@ -170,7 +192,7 @@ inet_aton.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h
inet_aton.o: ${BASHINCDIR}/stdc.h
itos.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h
-itos.o: ${topdir}/shell.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h
+itos.o: ${topdir}/shell.h ${topdir}/syntax.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h
itos.o: ${topdir}/command.h ${BASHINCDIR}/stdc.h ${topdir}/error.h
itos.o: ${topdir}/general.h ${topdir}/bashtypes.h ${topdir}/variables.h
itos.o: ${topdir}/array.h ${topdir}/hashlib.h ${topdir}/quit.h
@@ -178,10 +200,19 @@ itos.o: ${topdir}/unwind_prot.h ${topdir}/dispose_cmd.h
itos.o: ${topdir}/make_cmd.h ${topdir}/subst.h ${topdir}/sig.h
itos.o: ${topdir}/pathnames.h ${topdir}/externs.h
+makepath.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h
+makepath.o: ${topdir}/shell.h ${topdir}/syntax.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h
+makepath.o: ${topdir}/command.h ${BASHINCDIR}/stdc.h ${topdir}/error.h
+makepath.o: ${topdir}/general.h ${topdir}/bashtypes.h ${topdir}/variables.h
+makepath.o: ${topdir}/array.h ${topdir}/hashlib.h ${topdir}/quit.h
+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
+
netopen.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h
oslib.o: ${topdir}/bashtypes.h ${topdir}/bashansi.h ${BASHINCDIR}/maxpath.h
-oslib.o: ${topdir}/shell.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h
+oslib.o: ${topdir}/shell.h ${topdir}/syntax.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h
oslib.o: ${topdir}/command.h ${BASHINCDIR}/stdc.h ${topdir}/error.h
oslib.o: ${topdir}/general.h ${topdir}/bashtypes.h ${topdir}/variables.h
oslib.o: ${topdir}/array.h ${topdir}/hashlib.h ${topdir}/quit.h
@@ -191,15 +222,42 @@ oslib.o: ${topdir}/pathnames.h ${topdir}/externs.h
oslib.o: ${BASHINCDIR}/posixstat.h ${BASHINCDIR}/filecntl.h
oslib.o: ${BASHINCDIR}/ansi_stdlib.h
+pathcanon.o: ${topdir}/bashtypes.h ${topdir}/bashansi.h ${BASHINCDIR}/maxpath.h
+pathcanon.o: ${topdir}/shell.h ${topdir}/syntax.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h
+pathcanon.o: ${topdir}/command.h ${BASHINCDIR}/stdc.h ${topdir}/error.h
+pathcanon.o: ${topdir}/general.h ${topdir}/bashtypes.h ${topdir}/variables.h
+pathcanon.o: ${topdir}/array.h ${topdir}/hashlib.h ${topdir}/quit.h
+pathcanon.o: ${topdir}/unwind_prot.h ${topdir}/dispose_cmd.h
+pathcanon.o: ${topdir}/make_cmd.h ${topdir}/subst.h ${topdir}/sig.h
+pathcanon.o: ${topdir}/pathnames.h ${topdir}/externs.h
+pathcanon.o: ${BASHINCDIR}/posixstat.h ${BASHINCDIR}/filecntl.h
+pathcanon.o: ${BASHINCDIR}/ansi_stdlib.h
+
+pathphys.o: ${topdir}/bashtypes.h ${topdir}/bashansi.h ${BASHINCDIR}/maxpath.h
+pathphys.o: ${topdir}/shell.h ${topdir}/syntax.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h
+pathphys.o: ${topdir}/command.h ${BASHINCDIR}/stdc.h ${topdir}/error.h
+pathphys.o: ${topdir}/general.h ${topdir}/bashtypes.h ${topdir}/variables.h
+pathphys.o: ${topdir}/array.h ${topdir}/hashlib.h ${topdir}/quit.h
+pathphys.o: ${topdir}/unwind_prot.h ${topdir}/dispose_cmd.h
+pathphys.o: ${topdir}/make_cmd.h ${topdir}/subst.h ${topdir}/sig.h
+pathphys.o: ${topdir}/pathnames.h ${topdir}/externs.h
+pathphys.o: ${BASHINCDIR}/posixstat.h ${BASHINCDIR}/filecntl.h
+pathphys.o: ${BASHINCDIR}/ansi_stdlib.h
+
rename.o: ${topdir}/bashtypes.h ${BASHINCDIR}/stdc.h
shtty.o: ${BASHINCDIR}/shtty.h
shtty.o: ${BASHINCDIR}/stdc.h
-strcasecmp.o: ${BASHINCDIR}/stdc.h ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h
+spell.o: ${topdir}/bashtypes.h
+spell.o: ${BASHINCDIR}/posixstat.h ${BASHINCDIR}/posixdir.h
+spell.o: ${BASHINCDIR}/ansi_stdlib.h
+
+strcasecmp.o: ${BASHINCDIR}/stdc.h ${topdir}/bashansi.h
+strcasecmp.o: ${BASHINCDIR}/ansi_stdlib.h
strerror.o: ${topdir}/bashtypes.h
-strerror.o: ${topdir}/shell.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h
+strerror.o: ${topdir}/shell.h ${topdir}/syntax.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h
strerror.o: ${topdir}/command.h ${BASHINCDIR}/stdc.h ${topdir}/error.h
strerror.o: ${topdir}/general.h ${topdir}/bashtypes.h ${topdir}/variables.h
strerror.o: ${topdir}/array.h ${topdir}/hashlib.h ${topdir}/quit.h
@@ -207,6 +265,27 @@ strerror.o: ${topdir}/unwind_prot.h ${topdir}/dispose_cmd.h
strerror.o: ${topdir}/make_cmd.h ${topdir}/subst.h ${topdir}/sig.h
strerror.o: ${topdir}/pathnames.h ${topdir}/externs.h
+strindex.o: ${BASHINCDIR}/stdc.h ${topdir}/bashansi.h
+strindex.o: ${BASHINCDIR}/ansi_stdlib.h
+
+stringlist.o: ${topdir}/bashansi.h
+stringlist.o: ${topdir}/shell.h ${topdir}/syntax.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h
+stringlist.o: ${topdir}/command.h ${BASHINCDIR}/stdc.h ${topdir}/error.h
+stringlist.o: ${topdir}/general.h ${topdir}/bashtypes.h ${topdir}/variables.h
+stringlist.o: ${topdir}/array.h ${topdir}/hashlib.h ${topdir}/quit.h
+stringlist.o: ${topdir}/unwind_prot.h ${topdir}/dispose_cmd.h
+stringlist.o: ${topdir}/make_cmd.h ${topdir}/subst.h ${topdir}/sig.h
+stringlist.o: ${topdir}/pathnames.h ${topdir}/externs.h
+
+stringvec.o: ${topdir}/bashansi.h
+stringvec.o: ${topdir}/shell.h ${topdir}/syntax.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h
+stringvec.o: ${topdir}/command.h ${BASHINCDIR}/stdc.h ${topdir}/error.h
+stringvec.o: ${topdir}/general.h ${topdir}/bashtypes.h ${topdir}/variables.h
+stringvec.o: ${topdir}/array.h ${topdir}/hashlib.h ${topdir}/quit.h
+stringvec.o: ${topdir}/unwind_prot.h ${topdir}/dispose_cmd.h
+stringvec.o: ${topdir}/make_cmd.h ${topdir}/subst.h ${topdir}/sig.h
+stringvec.o: ${topdir}/pathnames.h ${topdir}/externs.h
+
strpbrk.o: ${BASHINCDIR}/stdc.h
strtod.o: ${topdir}/bashansi.h
@@ -218,9 +297,23 @@ strtol.o: ${BASHINCDIR}/ansi_stdlib.h
strtoul.o: ${topdir}/bashansi.h
strtoul.o: ${BASHINCDIR}/ansi_stdlib.h
+strtrans.o: ${topdir}/bashansi.h
+strtrans.o: ${BASHINCDIR}/ansi_stdlib.h
+strtrans.o: ${topdir}/shell.h ${topdir}/syntax.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h
+strtrans.o: ${topdir}/command.h ${BASHINCDIR}/stdc.h ${topdir}/error.h
+strtrans.o: ${topdir}/general.h ${topdir}/bashtypes.h ${topdir}/variables.h
+strtrans.o: ${topdir}/array.h ${topdir}/hashlib.h ${topdir}/quit.h
+strtrans.o: ${topdir}/unwind_prot.h ${topdir}/dispose_cmd.h
+strtrans.o: ${topdir}/make_cmd.h ${topdir}/subst.h ${topdir}/sig.h
+strtrans.o: ${topdir}/pathnames.h ${topdir}/externs.h
+
times.o: ${BASHINCDIR}/systimes.h
times.o: ${BASHINCDIR}/posixtime.h
timeval.o: ${BASHINCDIR}/posixtime.h
+tmpfile.o: ${topdir}/bashtypes.h
+tmpfile.o: ${BASHINCDIR}/posixstat.h
+tmpfile.o: ${BASHINCDIR}/filecntl.h
+
clock.o: ${BASHINCDIR}/posixtime.h
diff --git a/lib/sh/makepath.c b/lib/sh/makepath.c
index dfc12108..ba2bcb9c 100644
--- a/lib/sh/makepath.c
+++ b/lib/sh/makepath.c
@@ -68,7 +68,7 @@ sh_makepath (path, dir, flags)
int flags;
{
int dirlen, pathlen;
- char *ret, *xpath;
+ char *ret, *xpath, *r, *s;
if (path == 0 || *path == '\0')
{
@@ -102,14 +102,15 @@ sh_makepath (path, dir, flags)
dirlen -= 2;
}
- ret = xmalloc (2 + dirlen + pathlen);
- strcpy (ret, xpath);
- if (xpath[pathlen - 1] != '/')
- {
- ret[pathlen++] = '/';
- ret[pathlen] = '\0';
- }
- strcpy (ret + pathlen, dir);
+ r = ret = xmalloc (2 + dirlen + pathlen);
+ s = xpath;
+ while (*s)
+ *r++ = *s++;
+ if (s[-1] != '/')
+ *r++ = '/';
+ s = dir;
+ while (*r++ = *s++)
+ ;
if (xpath != path)
free (xpath);
return (ret);
diff --git a/lib/sh/netopen.c b/lib/sh/netopen.c
index 789a9b39..f0b0b9b8 100644
--- a/lib/sh/netopen.c
+++ b/lib/sh/netopen.c
@@ -97,8 +97,9 @@ _getaddr (host, ap)
/* Return 1 if SERV is a valid port number and stuff the converted value into
PP in network byte order. */
static int
-_getserv (serv, pp)
+_getserv (serv, proto, pp)
char *serv;
+ int proto;
unsigned short *pp;
{
long l;
@@ -115,7 +116,20 @@ _getserv (serv, pp)
return 1;
}
else
+#if defined (HAVE_GETSERVBYNAME)
+ {
+ struct servent *se;
+
+ se = getservbyname (serv, (proto == 't') ? "tcp" : "udp");
+ if (se == 0)
+ return 0;
+ if (pp)
+ *pp = se->s_port; /* ports returned in network byte order */
+ return 1;
+ }
+#else /* !HAVE_GETSERVBYNAME */
return 0;
+#endif /* !HAVE_GETSERVBYNAME */
}
static int
@@ -126,18 +140,20 @@ _netopen(host, serv, typ)
struct in_addr ina;
struct sockaddr_in sin;
unsigned short p;
- int s;
+ int s, e;
char **cp;
if (_getaddr(host, &ina) == 0)
{
internal_error ("%s: host unknown", host);
+ errno = EINVAL;
return -1;
}
- if (_getserv(serv, &p) == 0)
+ if (_getserv(serv, typ, &p) == 0)
{
internal_error("%s: invalid service", serv);
+ errno = EINVAL;
return -1;
}
@@ -155,8 +171,10 @@ _netopen(host, serv, typ)
if (connect (s, (struct sockaddr *)&sin, sizeof (sin)) < 0)
{
+ e = errno;
sys_error("connect");
close(s);
+ errno = e;
return (-1);
}
diff --git a/lib/sh/pathcanon.c b/lib/sh/pathcanon.c
new file mode 100644
index 00000000..41fc727a
--- /dev/null
+++ b/lib/sh/pathcanon.c
@@ -0,0 +1,195 @@
+/* pathcanon.c -- Canonicalize and manipulate pathnames. */
+
+/* Copyright (C) 2000 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/param.h>
+#endif
+#include "posixstat.h"
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include "filecntl.h"
+#include "bashansi.h"
+#include <stdio.h>
+
+#include "shell.h"
+
+#include "maxpath.h"
+
+/* Return 1 if PATH corresponds to a directory. A function for debugging. */
+static int
+_path_isdir (path)
+ char *path;
+{
+ int l;
+ struct stat sb;
+
+ l = stat (path, &sb) == 0 && S_ISDIR (sb.st_mode);
+ return l;
+}
+
+/* Canonicalize PATH, and return a new path. The new path differs from PATH
+ in that:
+ Multple `/'s are collapsed to a single `/'.
+ Leading `./'s and trailing `/.'s are removed.
+ Trailing `/'s are removed.
+ Non-leading `../'s and trailing `..'s are handled by removing
+ portions of the path. */
+
+/* Look for ROOTEDPATH, PATHSEP, DIRSEP, and ISDIRSEP in ../../general.h */
+
+#define DOUBLE_SLASH(p) ((p[0] == '/') && (p[1] == '/') && p[2] != '/')
+
+char *
+sh_canonpath (path, flags)
+ char *path;
+ int flags;
+{
+ char stub_char;
+ char *result, *p, *q, *base, *dotdot;
+ int rooted, double_slash_path;
+
+ /* The result cannot be larger than the input PATH. */
+ result = (flags & PATH_NOALLOC) ? path : savestring (path);
+
+ /* POSIX.2 says to leave a leading `//' alone. On cygwin, we skip over any
+ leading `x:' (dos drive name). */
+ if (rooted = ROOTEDPATH(path))
+ {
+ stub_char = DIRSEP;
+#if defined (__CYGWIN__)
+ base = (isalpha(result[0]) && result[1] == ':') ? result + 3 : result + 1;
+#else
+ base = result + 1;
+#endif
+ double_slash_path = DOUBLE_SLASH (path);
+ base += double_slash_path;
+ }
+ else
+ {
+ stub_char = '.';
+#if defined (__CYGWIN__)
+ base = (isalpha(result[0]) && result[1] == ':') ? result + 2 : result;
+#else
+ base = result;
+#endif
+ }
+
+ /*
+ * invariants:
+ * base points to the portion of the path we want to modify
+ * p points at beginning of path element we're considering.
+ * q points just past the last path element we wrote (no slash).
+ * dotdot points just past the point where .. cannot backtrack
+ * any further (no slash).
+ */
+ p = q = dotdot = base;
+
+ while (*p)
+ {
+ if (ISDIRSEP(p[0])) /* null element */
+ p++;
+ else if(p[0] == '.' && PATHSEP(p[1])) /* . and ./ */
+ p += 1; /* don't count the separator in case it is nul */
+ else if (p[0] == '.' && p[1] == '.' && PATHSEP(p[2])) /* .. and ../ */
+ {
+ p += 2; /* skip `..' */
+ if (q > dotdot) /* can backtrack */
+ {
+ if (flags & PATH_CHECKDOTDOT)
+ {
+ char c;
+
+ /* Make sure what we have so far corresponds to a valid
+ path before we chop some of it off. */
+ c = *q;
+ *q = '\0';
+ if (_path_isdir (result) == 0)
+ {
+ if ((flags & PATH_NOALLOC) == 0)
+ free (result);
+ return ((char *)NULL);
+ }
+ *q = c;
+ }
+
+ while (--q > dotdot && ISDIRSEP(*q) == 0)
+ ;
+ }
+ else if (rooted == 0)
+ {
+ /* /.. is / but ./../ is .. */
+ if (q != base)
+ *q++ = DIRSEP;
+ *q++ = '.';
+ *q++ = '.';
+ dotdot = q;
+ }
+ }
+ else /* real path element */
+ {
+ /* add separator if not at start of work portion of result */
+ if (q != base)
+ *q++ = DIRSEP;
+ while (*p && (ISDIRSEP(*p) == 0))
+ *q++ = *p++;
+ /* Check here for a valid directory with _path_isdir. */
+ if (flags & PATH_CHECKEXISTS)
+ {
+ char c;
+
+ /* Make sure what we have so far corresponds to a valid
+ path before we chop some of it off. */
+ c = *q;
+ *q = '\0';
+ if (_path_isdir (result) == 0)
+ {
+ if ((flags & PATH_NOALLOC) == 0)
+ free (result);
+ return ((char *)NULL);
+ }
+ *q = c;
+ }
+ }
+ }
+
+ /* Empty string is really ``.'' or `/', depending on what we started with. */
+ if (q == result)
+ *q++ = stub_char;
+ *q = '\0';
+
+ /* If the result starts with `//', but the original path does not, we
+ can turn the // into /. Because of how we set `base', this should never
+ be true, but it's a sanity check. */
+ if (DOUBLE_SLASH(result) && double_slash_path == 0)
+ {
+ if (result[2] == '\0') /* short-circuit for bare `//' */
+ result[1] = '\0';
+ else
+ strcpy (result, result + 1);
+ }
+
+ return (result);
+}
diff --git a/lib/sh/pathphys.c b/lib/sh/pathphys.c
new file mode 100644
index 00000000..eb585241
--- /dev/null
+++ b/lib/sh/pathphys.c
@@ -0,0 +1,256 @@
+/* pathphys.c -- Return pathname with all symlinks expanded. */
+
+/* Copyright (C) 2000 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/param.h>
+#endif
+#include "posixstat.h"
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include "filecntl.h"
+#include "bashansi.h"
+#include <stdio.h>
+#include <errno.h>
+
+#include "shell.h"
+
+#include "maxpath.h"
+
+#if !defined (MAXSYMLINKS)
+# define MAXSYMLINKS 32
+#endif
+
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+extern char *get_working_directory __P((char *));
+
+static int
+_path_readlink (path, buf, bufsiz)
+ char *path;
+ char *buf;
+ int bufsiz;
+{
+#ifdef HAVE_READLINK
+ return readlink (path, buf, bufsiz);
+#else
+ errno = EINVAL;
+ return -1;
+#endif
+}
+
+/* Look for ROOTEDPATH, PATHSEP, DIRSEP, and ISDIRSEP in ../../general.h */
+
+#define DOUBLE_SLASH(p) ((p[0] == '/') && (p[1] == '/') && p[2] != '/')
+
+/*
+ * Return PATH with all symlinks expanded in newly-allocated memory.
+ * This always gets a full pathname.
+ */
+
+char *
+sh_physpath (path, flags)
+ char *path;
+ int flags;
+{
+ char tbuf[PATH_MAX+1], linkbuf[PATH_MAX+1];
+ char *result, *p, *q, *qsave, *qbase, *workpath;
+ int double_slash_path, linklen, nlink;
+
+ nlink = 0;
+ q = result = xmalloc (PATH_MAX + 1);
+
+ workpath = xmalloc (PATH_MAX + 1);
+ strcpy (workpath, path);
+
+ /* This always gets an absolute pathname. */
+
+ /* POSIX.2 says to leave a leading `//' alone. On cygwin, we skip over any
+ leading `x:' (dos drive name). */
+#if defined (__CYGWIN__)
+ qbase = (isalpha(workpath[0]) && workpath[1] == ':') ? workpath + 3 : workpath + 1;
+#else
+ qbase = workpath + 1;
+#endif
+ double_slash_path = DOUBLE_SLASH (workpath);
+ qbase += double_slash_path;
+
+ for (p = workpath; p < qbase; )
+ *q++ = *p++;
+ qbase = q;
+
+ /*
+ * invariants:
+ * qbase points to the portion of the result path we want to modify
+ * p points at beginning of path element we're considering.
+ * q points just past the last path element we wrote (no slash).
+ *
+ * XXX -- need to fix error checking for too-long pathnames
+ */
+
+ while (*p)
+ {
+ if (ISDIRSEP(p[0])) /* null element */
+ p++;
+ else if(p[0] == '.' && PATHSEP(p[1])) /* . and ./ */
+ p += 1; /* don't count the separator in case it is nul */
+ else if (p[0] == '.' && p[1] == '.' && PATHSEP(p[2])) /* .. and ../ */
+ {
+ p += 2; /* skip `..' */
+ if (q > qbase)
+ {
+ while (--q > qbase && ISDIRSEP(*q) == 0)
+ ;
+ }
+ }
+ else /* real path element */
+ {
+ /* add separator if not at start of work portion of result */
+ qsave = q;
+ if (q != qbase)
+ *q++ = DIRSEP;
+ while (*p && (ISDIRSEP(*p) == 0))
+ *q++ = *p++;
+
+ *q = '\0';
+
+ linklen = _path_readlink (result, linkbuf, PATH_MAX);
+ if (linklen < 0) /* if errno == EINVAL, it's not a symlink */
+ {
+ if (errno != EINVAL)
+ goto error;
+ continue;
+ }
+
+ /* It's a symlink, and the value is in LINKBUF. */
+ nlink++;
+ if (nlink > MAXSYMLINKS)
+ {
+#ifdef ELOOP
+ errno = ELOOP;
+#endif
+error:
+ free (result);
+ free (workpath);
+ return ((char *)NULL);
+ }
+
+ linkbuf[linklen] = '\0';
+
+ /* Form the new pathname by copying the link value to a temporary
+ buffer and appending the rest of `workpath'. Reset p to point
+ to the start of the rest of the path. If the link value is an
+ absolute pathname, reset p, q, and qbase. If not, reset p
+ and q. */
+ strcpy (tbuf, linkbuf);
+ tbuf[linklen] = '/';
+ strcpy (tbuf + linklen, p);
+ strcpy (workpath, tbuf);
+
+ if (ABSPATH(linkbuf))
+ {
+ q = result;
+ /* Duplicating some code here... */
+#if defined (__CYGWIN__)
+ qbase = (isalpha(workpath[0]) && workpath[1] == ':') ? workpath + 3 : workpath + 1;
+#else
+ qbase = workpath + 1;
+#endif
+ double_slash_path = DOUBLE_SLASH (workpath);
+ qbase += double_slash_path;
+
+ for (p = workpath; p < qbase; )
+ *q++ = *p++;
+ qbase = q;
+ }
+ else
+ {
+ p = workpath;
+ q = qsave;
+ }
+ }
+ }
+
+ *q = '\0';
+ free (workpath);
+
+ /* If the result starts with `//', but the original path does not, we
+ can turn the // into /. Because of how we set `qbase', this should never
+ be true, but it's a sanity check. */
+ if (DOUBLE_SLASH(result) && double_slash_path == 0)
+ {
+ if (result[2] == '\0') /* short-circuit for bare `//' */
+ result[1] = '\0';
+ else
+ strcpy (result, result + 1);
+ }
+
+ return (result);
+}
+
+char *
+sh_realpath (pathname, resolved)
+ const char *pathname;
+ char *resolved;
+{
+ char *tdir, *wd;
+
+ if (pathname == 0 || *pathname == '\0')
+ {
+ errno = (pathname == 0) ? EINVAL : ENOENT;
+ return ((char *)NULL);
+ }
+
+ if (ABSPATH (pathname) == 0)
+ {
+ wd = get_working_directory ("sh_realpath");
+ if (wd == 0)
+ return ((char *)NULL);
+ tdir = sh_makepath ((char *)pathname, wd, 0);
+ free (wd);
+ }
+ else
+ tdir = savestring (pathname);
+
+ wd = sh_physpath (tdir, 0);
+ free (tdir);
+
+ if (resolved == 0)
+ return (wd);
+
+ if (wd)
+ {
+ strncpy (resolved, wd, PATH_MAX - 1);
+ resolved[PATH_MAX - 1] = '\0';
+ return resolved;
+ }
+ else
+ {
+ resolved[0] = '\0';
+ return wd;
+ }
+}
diff --git a/lib/sh/shquote.c b/lib/sh/shquote.c
index ab8009da..981e9673 100644
--- a/lib/sh/shquote.c
+++ b/lib/sh/shquote.c
@@ -27,9 +27,7 @@
#include <stdio.h>
-#if !defined(slashify_in_quotes)
-# define slashify_in_quotes "\\`$\"\n"
-#endif
+#include "syntax.h"
extern char *xmalloc ();
@@ -42,7 +40,7 @@ extern char *xmalloc ();
/* Return a new string which is the single-quoted version of STRING.
Used by alias and trap, among others. */
char *
-single_quote (string)
+sh_single_quote (string)
char *string;
{
register int c;
@@ -72,7 +70,7 @@ single_quote (string)
/* Quote STRING using double quotes. Return a new string. */
char *
-double_quote (string)
+sh_double_quote (string)
char *string;
{
register int c;
@@ -84,18 +82,10 @@ double_quote (string)
for (s = string; s && (c = *s); s++)
{
- switch (c)
- {
- case '"':
- case '$':
- case '`':
- case '\\':
- case '\n': /* XXX */
- *r++ = '\\';
- default:
- *r++ = c;
- break;
- }
+ if (sh_syntaxtab[c] & CBSDQUOTE)
+ *r++ = '\\';
+
+ *r++ = c;
}
*r++ = '"';
@@ -107,7 +97,7 @@ double_quote (string)
/* Remove backslashes that are quoting characters that are special between
double quotes. Return a new string. */
char *
-un_double_quote (string)
+sh_un_double_quote (string)
char *string;
{
register int c, pass_next;
@@ -123,7 +113,7 @@ un_double_quote (string)
pass_next = 0;
continue;
}
- if (c == '\\' && strchr (slashify_in_quotes, s[1]))
+ if (c == '\\' && (sh_syntaxtab[s[1]] & CBSDQUOTE))
{
pass_next = 1;
continue;
@@ -138,7 +128,7 @@ un_double_quote (string)
/* Quote special characters in STRING using backslashes. Return a new
string. */
char *
-backslash_quote (string)
+sh_backslash_quote (string)
char *string;
{
int c;
@@ -182,8 +172,33 @@ backslash_quote (string)
return (result);
}
+#if defined (PROMPT_STRING_DECODE)
+/* Quote characters that get special treatment when in double quotes in STRING
+ using backslashes. Return a new string. */
+char *
+sh_backslash_quote_for_double_quotes (string)
+ char *string;
+{
+ int c;
+ char *result, *r, *s;
+
+ result = xmalloc (2 * strlen (string) + 1);
+
+ for (r = result, s = string; s && (c = *s); s++)
+ {
+ if (sh_syntaxtab[c] & CBSDQUOTE)
+ *r++ = '\\';
+
+ *r++ = c;
+ }
+
+ *r = '\0';
+ return (result);
+}
+#endif /* PROMPT_STRING_DECODE */
+
int
-contains_shell_metas (string)
+sh_contains_shell_metas (string)
char *string;
{
char *s;
diff --git a/lib/sh/spell.c b/lib/sh/spell.c
new file mode 100644
index 00000000..6da63762
--- /dev/null
+++ b/lib/sh/spell.c
@@ -0,0 +1,186 @@
+/* spell.c -- spelling correction for pathnames. */
+
+/* Copyright (C) 2000 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>
+
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#include <bashtypes.h>
+#include <posixdir.h>
+#include <posixstat.h>
+#ifndef _MINIX
+#include <sys/param.h>
+#endif
+
+#include <stdio.h>
+
+#include <bashansi.h>
+#include <maxpath.h>
+
+static int mindist (), spdist ();
+
+/*
+ * `spname' and its helpers are inspired by the code in "The UNIX
+ * Programming Environment", Kernighan & Pike, Prentice-Hall 1984,
+ * pages 209 - 213.
+ */
+
+/*
+ * `spname' -- return a correctly spelled filename
+ *
+ * int spname(char * oldname, char * newname)
+ * Returns: -1 if no reasonable match found
+ * 0 if exact match found
+ * 1 if corrected
+ * Stores corrected name in `newname'.
+ */
+int
+spname(oldname, newname)
+ char *oldname;
+ char *newname;
+{
+ char *op, *np, *p;
+ char guess[PATH_MAX + 1], best[PATH_MAX + 1];
+
+ op = oldname;
+ np = newname;
+ for (;;)
+ {
+ while (*op == '/') /* Skip slashes */
+ *np++ = *op++;
+ *np = '\0';
+
+ if (*op == '\0') /* Exact or corrected */
+ {
+ /* `.' is rarely the right thing. */
+ if (oldname[1] == '\0' && newname[1] == '\0' &&
+ oldname[0] != '.' && newname[0] == '.')
+ return -1;
+ return strcmp(oldname, newname) != 0;
+ }
+
+ /* Copy next component into guess */
+ for (p = guess; *op != '/' && *op != '\0'; op++)
+ if (p < guess + PATH_MAX)
+ *p++ = *op;
+ *p = '\0';
+
+ if (mindist(newname, guess, best) >= 3)
+ return -1; /* Hopeless */
+
+ /*
+ * Add to end of newname
+ */
+ for (p = best; *np = *p++; np++)
+ ;
+ }
+}
+
+/*
+ * Search directory for a guess
+ */
+static int
+mindist(dir, guess, best)
+ char *dir;
+ char *guess;
+ char *best;
+{
+ DIR *fd;
+ struct dirent *dp;
+ int dist, x;
+
+ dist = 3; /* Worst distance */
+ if (*dir == '\0')
+ dir = ".";
+
+ if ((fd = opendir(dir)) == NULL)
+ return dist;
+
+ while ((dp = readdir(fd)) != NULL)
+ {
+ /*
+ * Look for a better guess. If the new guess is as
+ * good as the current one, we take it. This way,
+ * any single character match will be a better match
+ * than ".".
+ */
+ x = spdist(dp->d_name, guess);
+ if (x <= dist && x != 3)
+ {
+ strcpy(best, dp->d_name);
+ dist = x;
+ if (dist == 0) /* Exact match */
+ break;
+ }
+ }
+ (void)closedir(fd);
+
+ /* Don't return `.' */
+ if (best[0] == '.' && best[1] == '\0')
+ dist = 3;
+ return dist;
+}
+
+/*
+ * `spdist' -- return the "distance" between two names.
+ *
+ * int spname(char * oldname, char * newname)
+ * Returns: 0 if strings are identical
+ * 1 if two characters are transposed
+ * 2 if one character is wrong, added or deleted
+ * 3 otherwise
+ */
+static int
+spdist(cur, new)
+ char *cur, *new;
+{
+ while (*cur == *new)
+ {
+ if (*cur == '\0')
+ return 0; /* Exact match */
+ cur++;
+ new++;
+ }
+
+ if (*cur)
+ {
+ if (*new)
+ {
+ if (cur[1] && new[1] && cur[0] == new[1] && cur[1] == new[0] && strcmp (cur + 2, new + 2) == 0)
+ return 1; /* Transposition */
+
+ if (strcmp (cur + 1, new + 1) == 0)
+ return 2; /* One character mismatch */
+ }
+
+ if (strcmp(&cur[1], &new[0]) == 0)
+ return 2; /* Extra character */
+ }
+
+ if (*new && strcmp(cur, new + 1) == 0)
+ return 2; /* Missing character */
+
+ return 3;
+}
diff --git a/lib/sh/strcasecmp.c b/lib/sh/strcasecmp.c
index 74d98cb5..1e15c021 100644
--- a/lib/sh/strcasecmp.c
+++ b/lib/sh/strcasecmp.c
@@ -79,7 +79,7 @@ strcasecmp (string1, string2)
while ((r = to_lower (*s1) - to_lower (*s2)) == 0)
{
if (*s1++ == '\0')
- return 0;
+ return 0;
s2++;
}
diff --git a/lib/sh/strindex.c b/lib/sh/strindex.c
new file mode 100644
index 00000000..9d3f3021
--- /dev/null
+++ b/lib/sh/strindex.c
@@ -0,0 +1,52 @@
+/* strindex.c - Find if one string appears as a substring of another string,
+ without regard to case. */
+
+/* Copyright (C) 2000
+ 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 "bashansi.h"
+#include <ctype.h>
+
+#include <stdc.h>
+
+#ifndef to_upper
+# define to_upper(c) (islower(c) ? toupper(c) : (c))
+# define to_lower(c) (isupper(c) ? tolower(c) : (c))
+#endif
+
+/* Determine if s2 occurs in s1. If so, return a pointer to the
+ match in s1. The compare is case insensitive. This is a
+ case-insensitive strstr(3). */
+char *
+strindex (s1, s2)
+ const char *s1;
+ const char *s2;
+{
+ register int i, l, len, c;
+
+ c = to_upper (s2[0]);
+ len = strlen (s1);
+ l = strlen (s2);
+ for (i = 0; (len - i) >= l; i++)
+ if ((to_upper (s1[i]) == c) && (strncasecmp (s1 + i, s2, l) == 0))
+ return ((char *)s1 + i);
+ return ((char *)0);
+}
diff --git a/lib/sh/stringlist.c b/lib/sh/stringlist.c
new file mode 100644
index 00000000..8fc57cbb
--- /dev/null
+++ b/lib/sh/stringlist.c
@@ -0,0 +1,248 @@
+/* stringlist.c - functions to handle a generic `list of strings' structure */
+
+/* Copyright (C) 2000 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>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include "bashansi.h"
+
+#include "shell.h"
+
+#ifdef STRDUP
+# undef STRDUP
+#endif
+#define STRDUP(x) ((x) ? savestring (x) : (char *)NULL)
+
+/* Allocate a new STRINGLIST, with room for N strings. */
+
+STRINGLIST *
+alloc_stringlist (n)
+ int n;
+{
+ STRINGLIST *ret;
+ register int i;
+
+ ret = (STRINGLIST *)xmalloc (sizeof (STRINGLIST));
+ if (n)
+ {
+ ret->list = alloc_array (n+1);
+ ret->list_size = n;
+ for (i = 0; i < n; i++)
+ ret->list[i] = (char *)NULL;
+ }
+ else
+ {
+ ret->list = (char **)NULL;
+ ret->list_size = 0;
+ }
+ ret->list_len = 0;
+ return ret;
+}
+
+STRINGLIST *
+realloc_stringlist (sl, n)
+ STRINGLIST *sl;
+ int n;
+{
+ register int i;
+
+ if (n > sl->list_size)
+ {
+ sl->list = (char **)xrealloc (sl->list, (n+1) * sizeof (char *));
+ for (i = sl->list_size; i <= n; i++)
+ sl->list[i] = (char *)NULL;
+ sl->list_size = n;
+ }
+ return sl;
+}
+
+void
+free_stringlist (sl)
+ STRINGLIST *sl;
+{
+ if (sl == 0)
+ return;
+ if (sl->list)
+ free_array (sl->list);
+ free (sl);
+}
+
+STRINGLIST *
+copy_stringlist (sl)
+ STRINGLIST *sl;
+{
+ STRINGLIST *new;
+ register int i;
+
+ new = alloc_stringlist (sl->list_size);
+ /* I'd like to use copy_array, but that doesn't copy everything. */
+ if (sl->list)
+ {
+ for (i = 0; i < sl->list_size; i++)
+ new->list[i] = STRDUP (sl->list[i]);
+ }
+ new->list_size = sl->list_size;
+ new->list_len = sl->list_len;
+ /* just being careful */
+ if (new->list)
+ new->list[new->list_len] = (char *)NULL;
+ return new;
+}
+
+/* Return a new STRINGLIST with everything from M1 and M2. */
+
+STRINGLIST *
+merge_stringlists (m1, m2)
+ STRINGLIST *m1, *m2;
+{
+ STRINGLIST *sl;
+ int i, n, l1, l2;
+
+ l1 = m1 ? m1->list_len : 0;
+ l2 = m2 ? m2->list_len : 0;
+
+ sl = alloc_stringlist (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++)
+ sl->list[n] = STRDUP (m2->list[i]);
+ sl->list_len = n;
+ sl->list[n] = (char *)NULL;
+}
+
+/* Make STRINGLIST M1 contain everything in M1 and M2. */
+STRINGLIST *
+append_stringlist (m1, m2)
+ STRINGLIST *m1, *m2;
+{
+ register int i, n, len1, len2;
+
+ if (m1 == 0)
+ {
+ m1 = copy_stringlist (m2);
+ return m1;
+ }
+
+ len1 = m1->list_len;
+ len2 = m2 ? m2->list_len : 0;
+
+ if (len2)
+ {
+ m1 = realloc_stringlist (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;
+ m1->list_len = n;
+ }
+
+ return m1;
+}
+
+STRINGLIST *
+prefix_suffix_stringlist (sl, prefix, suffix)
+ STRINGLIST *sl;
+ char *prefix, *suffix;
+{
+ int plen, slen, tlen, llen, i;
+ char *t;
+
+ if (sl == 0 || sl->list == 0 || sl->list_len == 0)
+ return sl;
+
+ plen = STRLEN (prefix);
+ slen = STRLEN (suffix);
+
+ if (plen == 0 && slen == 0)
+ return (sl);
+
+ for (i = 0; i < sl->list_len; i++)
+ {
+ llen = STRLEN (sl->list[i]);
+ tlen = plen + llen + slen + 1;
+ t = xmalloc (tlen + 1);
+ if (plen)
+ strcpy (t, prefix);
+ strcpy (t + plen, sl->list[i]);
+ if (slen)
+ strcpy (t + plen + llen, suffix);
+ free (sl->list[i]);
+ sl->list[i] = t;
+ }
+
+ return (sl);
+}
+
+void
+print_stringlist (sl, prefix)
+ STRINGLIST *sl;
+ char *prefix;
+{
+ register int i;
+
+ if (sl == 0)
+ return;
+ for (i = 0; i < sl->list_len; i++)
+ printf ("%s%s\n", prefix ? prefix : "", sl->list[i]);
+}
+
+void
+sort_stringlist (sl)
+ STRINGLIST *sl;
+{
+ if (sl == 0 || sl->list_len == 0 || sl->list == 0)
+ return;
+ sort_char_array (sl->list);
+}
+
+STRINGLIST *
+word_list_to_stringlist (list, copy, starting_index, ip)
+ WORD_LIST *list;
+ int copy, starting_index, *ip;
+{
+ STRINGLIST *ret;
+ int slen, len;
+
+ slen = list_length (list);
+ ret = (STRINGLIST *)xmalloc (sizeof (STRINGLIST));
+ ret->list = word_list_to_argv (list, copy, starting_index, &len);
+ ret->list_size = slen + starting_index;
+ ret->list_len = len;
+ if (ip)
+ *ip = len;
+ return ret;
+}
+
+WORD_LIST *
+stringlist_to_word_list (sl, copy, starting_index)
+ STRINGLIST *sl;
+ int copy, 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);
+ return list;
+}
diff --git a/lib/sh/stringvec.c b/lib/sh/stringvec.c
new file mode 100644
index 00000000..977ef486
--- /dev/null
+++ b/lib/sh/stringvec.c
@@ -0,0 +1,141 @@
+/* stringvec.c - function for managing arrays of strings. */
+
+/* Copyright (C) 2000 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"
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include "bashansi.h"
+#include <stdio.h>
+#include <ctype.h>
+
+#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)
+ int n;
+{
+ return ((char **)xmalloc ((n) * sizeof (char *)));
+}
+
+/* Return the length of ARRAY, a NULL terminated array of char *. */
+int
+array_len (array)
+ char **array;
+{
+ register int i;
+
+ for (i = 0; array[i]; i++);
+ return (i);
+}
+
+/* Free the contents of ARRAY, a NULL terminated array of char *. */
+void
+free_array_members (array)
+ char **array;
+{
+ register int i;
+
+ if (array == 0)
+ return;
+
+ for (i = 0; array[i]; i++)
+ free (array[i]);
+}
+
+void
+free_array (array)
+ char **array;
+{
+ if (array == 0)
+ return;
+
+ free_array_members (array);
+ free (array);
+}
+
+/* Allocate and return a new copy of ARRAY and its contents. */
+char **
+copy_array (array)
+ char **array;
+{
+ register int i;
+ int len;
+ char **new_array;
+
+ len = array_len (array);
+
+ new_array = (char **)xmalloc ((len + 1) * sizeof (char *));
+ for (i = 0; array[i]; i++)
+ new_array[i] = savestring (array[i]);
+ new_array[i] = (char *)NULL;
+
+ return (new_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)
+ register char **s1, **s2;
+{
+#if defined (HAVE_STRCOLL)
+ return (strcoll (*s1, *s2));
+#else /* !HAVE_STRCOLL */
+ int result;
+
+ if ((result = **s1 - **s2) == 0)
+ result = strcmp (*s1, *s2);
+
+ return (result);
+#endif /* !HAVE_STRCOLL */
+}
+
+/* Sort ARRAY, a null terminated array of pointers to strings. */
+void
+sort_char_array (array)
+ char **array;
+{
+ qsort (array, array_len (array), sizeof (char *),
+ (Function *)qsort_string_compare);
+}
+
diff --git a/lib/sh/strtol.c b/lib/sh/strtol.c
index 8e3aa39f..e990932e 100644
--- a/lib/sh/strtol.c
+++ b/lib/sh/strtol.c
@@ -204,8 +204,8 @@ noconv:
if (save - nptr >= 2 && toupper (save[-1]) == 'X' && save[-2] == '0')
*endptr = (char *) &save[-1];
else
- /* There was no number to convert. */
- *endptr = (char *) nptr;
+ /* There was no number to convert. */
+ *endptr = (char *) nptr;
}
return 0L;
diff --git a/lib/sh/strtrans.c b/lib/sh/strtrans.c
new file mode 100644
index 00000000..7005c465
--- /dev/null
+++ b/lib/sh/strtrans.c
@@ -0,0 +1,205 @@
+/* strtrans.c - Translate and untranslate strings with ANSI-C escape
+ sequences. */
+
+/* Copyright (C) 2000
+ 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>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include "bashansi.h"
+#include <stdio.h>
+#include <ctype.h>
+
+#include "shell.h"
+
+#ifdef ESC
+#undef ESC
+#endif
+#define ESC '\033' /* ASCII */
+
+#ifndef ISOCTAL
+#define ISOCTAL(c) ((c) >= '0' && (c) <= '7')
+#endif
+
+#ifndef OCTVALUE
+#define OCTVALUE(c) ((c) - '0')
+#endif
+
+#ifndef isxdigit
+# define isxdigit(c) (isdigit((c)) || ((c) >= 'a' && (c) <= 'f') || ((c) >= 'A' && (c) <= 'F'))
+#endif
+
+#define HEXVALUE(c) \
+ ((c) >= 'a' && (c) <= 'f' ? (c)-'a'+10 : (c) >= 'A' && (c) <= 'F' ? (c)-'A'+10 : (c)-'0')
+
+/* 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. */
+char *
+ansicstr (string, len, for_echo, sawc, rlen)
+ char *string;
+ int len, for_echo, *sawc, *rlen;
+{
+ int c, temp;
+ char *ret, *r, *s;
+
+ if (string == 0 || *string == '\0')
+ return ((char *)NULL);
+
+ ret = xmalloc (len + 1);
+ for (r = ret, s = string; s && *s; )
+ {
+ c = *s++;
+ if (c != '\\' || *s == '\0')
+ *r++ = c;
+ else
+ {
+ switch (c = *s++)
+ {
+#if defined (__STDC__)
+ case 'a': c = '\a'; break;
+ case 'v': c = '\v'; break;
+#else
+ case 'a': c = '\007'; break;
+ case 'v': c = (int) 0x0B; break;
+#endif
+ case 'b': c = '\b'; break;
+ case 'e': case 'E': /* ESC -- non-ANSI */
+ c = ESC; break;
+ case 'f': c = '\f'; break;
+ case 'n': c = '\n'; break;
+ case 'r': c = '\r'; break;
+ 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++)
+ c = (c * 8) + OCTVALUE (*s);
+ break;
+ case 'x': /* Hex digit -- non-ANSI */
+ for (temp = 3, c = 0; isxdigit (*s) && temp--; s++)
+ c = (c * 16) + HEXVALUE (*s);
+ /* \x followed by non-hex digits is passed through unchanged */
+ if (temp == 3)
+ {
+ *r++ = '\\';
+ c = 'x';
+ }
+ break;
+ case '\\':
+ break;
+ case '\'':
+ if (for_echo)
+ *r++ = '\\';
+ break;
+ case 'c':
+ if (sawc)
+ {
+ *sawc = 1;
+ *r = '\0';
+ if (rlen)
+ *rlen = r - ret;
+ return ret;
+ }
+ default: *r++ = '\\'; break;
+ }
+ *r++ = c;
+ }
+ }
+ *r = '\0';
+ if (rlen)
+ *rlen = r - ret;
+ return ret;
+}
+
+/* Take a string STR, possibly containing non-printing characters, and turn it
+ into a $'...' ANSI-C style quoted string. Returns a new string. */
+char *
+ansic_quote (str, flags, rlen)
+ char *str;
+ int flags, *rlen;
+{
+ char *r, *ret, *s, obuf[8];
+ int l, c, rsize, t;
+
+ if (str == 0 || *str == 0)
+ return ((char *)0);
+
+ l = strlen (str);
+ rsize = 2 * l + 4;
+ r = ret = xmalloc (rsize);
+
+ *r++ = '$';
+ *r++ = '\'';
+
+ for (s = str, l = 0; *s; s++)
+ {
+ c = *(unsigned char *)s;
+ l = 1; /* 1 == add backslash; 0 == no backslash */
+ switch (c)
+ {
+ case ESC: c = 'E'; break;
+#ifdef __STDC__
+ case '\a': c = 'a'; break;
+ case '\v': c = 'v'; break;
+#else
+ case '\007': c = 'a'; break;
+ case 0x0b: c = 'v'; break;
+#endif
+
+ case '\b': c = 'b'; break;
+ case '\f': c = 'f'; break;
+ case '\n': c = 'n'; break;
+ case '\r': c = 'r'; break;
+ case '\t': c = 't'; break;
+ case '\\':
+ case '\'':
+ break;
+ 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];
+ continue;
+ }
+ l = 0;
+ break;
+ }
+ if (l)
+ *r++ = '\\';
+ *r++ = c;
+ }
+
+ *r++ = '\'';
+ *r = '\0';
+ if (rlen)
+ *rlen = r - ret;
+ return ret;
+}
diff --git a/lib/sh/times.c b/lib/sh/times.c
index 240aafe1..e26e41c6 100644
--- a/lib/sh/times.c
+++ b/lib/sh/times.c
@@ -60,7 +60,7 @@ times(tms)
if (gettimeofday(&tv, (struct timezone *) 0) < 0)
return ((clock_t)-1);
- rv = (clock_t)(CONVTCK(tv));
+ rv = (clock_t)(CONVTCK(tv));
#else /* !HAVE_GETRUSAGE */
if (clk_tck == -1)
clk_tck = get_clk_tck();
diff --git a/lib/sh/tmpfile.c b/lib/sh/tmpfile.c
new file mode 100644
index 00000000..6912e5cc
--- /dev/null
+++ b/lib/sh/tmpfile.c
@@ -0,0 +1,183 @@
+/*
+ * tmpfile.c - functions to create and safely open temp files for the shell.
+ */
+
+/* Copyright (C) 2000 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>
+#include <posixstat.h>
+#include <filecntl.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+
+#include <shell.h>
+
+#ifndef errno
+extern int errno;
+#endif
+
+#define BASEOPENFLAGS (O_CREAT | O_TRUNC | O_EXCL)
+
+#define DEFAULT_TMPDIR "." /* bogus default, should be changed */
+#define DEFAULT_NAMEROOT "shtmp"
+
+extern int dollar_dollar_pid;
+
+static char *sys_tmpdir = (char *)NULL;
+static int ntmpfiles;
+static int tmpnamelen = -1;
+static unsigned long filenum = 1L;
+
+static char *
+get_sys_tmpdir ()
+{
+ struct stat sb;
+
+ if (sys_tmpdir)
+ return sys_tmpdir;
+
+ sys_tmpdir = "/tmp";
+ if (stat (sys_tmpdir, &sb) == 0)
+ return sys_tmpdir;
+
+ sys_tmpdir = "/var/tmp";
+ if (stat (sys_tmpdir, &sb) == 0)
+ return sys_tmpdir;
+
+ sys_tmpdir = "/usr/tmp";
+ if (stat (sys_tmpdir, &sb) == 0)
+ return sys_tmpdir;
+
+#ifdef P_tmpdir
+ sys_tmpdir = P_tmpdir;
+#else
+ sys_tmpdir = DEFAULT_TMPDIR;
+#endif
+
+ return sys_tmpdir;
+}
+
+static char *
+get_tmpdir (flags)
+ int flags;
+{
+ char *tdir;
+
+ tdir = (flags & MT_USETMPDIR) ? get_string_value ("TMPDIR") : (char *)NULL;
+ if (tdir == 0)
+ tdir = get_sys_tmpdir ();
+
+#if defined (HAVE_PATHCONF) && defined (_PC_NAME_MAX)
+ if (tmpnamelen == -1)
+ tmpnamelen = pathconf (tdir, _PC_NAME_MAX);
+#else
+ tmpnamelen = 0;
+#endif
+
+ return tdir;
+}
+
+char *
+sh_mktmpname (nameroot, flags)
+ char *nameroot;
+ int flags;
+{
+ char *filename, *tdir;
+ struct stat sb;
+ int r, tdlen;
+
+ filename = xmalloc (PATH_MAX + 1);
+ tdir = get_tmpdir (flags);
+ tdlen = strlen (tdir);
+
+ if (nameroot == 0)
+ nameroot = DEFAULT_NAMEROOT;
+
+ while (1)
+ {
+ filenum *= (int)time ((time_t *)0) * dollar_dollar_pid *
+ ((flags & MT_USERANDOM) ? get_random_number () : ntmpfiles++);
+ sprintf (filename, "%s/%s-%lu", tdir, nameroot, filenum);
+ if (tmpnamelen > 0 && tmpnamelen < 32)
+ filename[tdlen + 1 + tmpnamelen] = '\0';
+#ifdef HAVE_LSTAT
+ r = lstat (filename, &sb);
+#else
+ r = stat (filename, &sb);
+#endif
+ if (r < 0 && errno == ENOENT)
+ break;
+ }
+
+ return filename;
+}
+
+int
+sh_mktmpfd (nameroot, flags, namep)
+ char *nameroot;
+ int flags;
+ char **namep;
+{
+ char *filename, *tdir;
+ int fd, tdlen;
+
+ filename = xmalloc (PATH_MAX + 1);
+ tdir = get_tmpdir (flags);
+ tdlen = strlen (tdir);
+
+ if (nameroot == 0)
+ nameroot = DEFAULT_NAMEROOT;
+
+ do
+ {
+ filenum *= (int)time ((time_t *)0) * dollar_dollar_pid *
+ ((flags & MT_USERANDOM) ? get_random_number () : ntmpfiles++);
+ sprintf (filename, "%s/%s-%lu", tdir, nameroot, filenum);
+ if (tmpnamelen > 0 && tmpnamelen < 32)
+ filename[tdlen + 1 + tmpnamelen] = '\0';
+ fd = open (filename, BASEOPENFLAGS | ((flags & MT_READWRITE) ? O_RDWR : O_WRONLY), 0600);
+ }
+ while (fd < 0 && errno == EEXIST);
+
+ if (namep)
+ *namep = filename;
+ else
+ free (filename);
+
+ return fd;
+}
+
+FILE *
+sh_mktmpfp (nameroot, flags, namep)
+ char *nameroot;
+ int flags;
+ char **namep;
+{
+ int fd;
+
+ fd = sh_mktmpfd (nameroot, flags, namep);
+ return ((fd >= 0) ? (fdopen (fd, (flags & MT_READWRITE) ? "w+" : "w")) : (FILE *)NULL);
+}
diff --git a/lib/sh/zread.c b/lib/sh/zread.c
index 0b23b38d..0d5320a1 100644
--- a/lib/sh/zread.c
+++ b/lib/sh/zread.c
@@ -69,7 +69,7 @@ zread1 (fd, buf, len)
{
r = read (fd, buf, len);
if (r >= 0)
- return r;
+ return r;
if (r == -1 && errno == EINTR)
{
if (++nintr > NUM_INTR)
diff --git a/lib/sh/zwrite.c b/lib/sh/zwrite.c
index 25550f8f..d36ca5f4 100644
--- a/lib/sh/zwrite.c
+++ b/lib/sh/zwrite.c
@@ -49,6 +49,7 @@ zwrite (fd, buf, nb)
n -= i;
if (n <= 0)
return nb;
+ buf += i;
}
else if (i == 0)
{