diff options
author | Jari Aalto <jari.aalto@cante.net> | 2001-04-06 19:14:31 +0000 |
---|---|---|
committer | Jari Aalto <jari.aalto@cante.net> | 2009-09-12 16:46:53 +0000 |
commit | 28ef6c316f1aff914bb95ac09787a3c83c1815fd (patch) | |
tree | 2812fe7ffc9beec4f99856906ddfcafda54cf16a /lib/sh | |
parent | bb70624e964126b7ac4ff085ba163a9c35ffa18f (diff) | |
download | bash-28ef6c316f1aff914bb95ac09787a3c83c1815fd.tar.gz |
Imported from ../bash-2.05.tar.gz.
Diffstat (limited to 'lib/sh')
-rw-r--r-- | lib/sh/Makefile.in | 107 | ||||
-rw-r--r-- | lib/sh/makepath.c | 19 | ||||
-rw-r--r-- | lib/sh/netopen.c | 24 | ||||
-rw-r--r-- | lib/sh/pathcanon.c | 195 | ||||
-rw-r--r-- | lib/sh/pathphys.c | 256 | ||||
-rw-r--r-- | lib/sh/shquote.c | 57 | ||||
-rw-r--r-- | lib/sh/spell.c | 186 | ||||
-rw-r--r-- | lib/sh/strcasecmp.c | 2 | ||||
-rw-r--r-- | lib/sh/strindex.c | 52 | ||||
-rw-r--r-- | lib/sh/stringlist.c | 248 | ||||
-rw-r--r-- | lib/sh/stringvec.c | 141 | ||||
-rw-r--r-- | lib/sh/strtol.c | 4 | ||||
-rw-r--r-- | lib/sh/strtrans.c | 205 | ||||
-rw-r--r-- | lib/sh/times.c | 2 | ||||
-rw-r--r-- | lib/sh/tmpfile.c | 183 | ||||
-rw-r--r-- | lib/sh/zread.c | 2 | ||||
-rw-r--r-- | lib/sh/zwrite.c | 1 |
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) { |