/* general.c -- Stuff that is used by all files. */
-/* Copyright (C) 1987-2004 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2011 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 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 3 of the License, 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.
+ 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. */
+ You should have received a copy of the GNU General Public License
+ along with Bash. If not, see <http://www.gnu.org/licenses/>.
+*/
#include "config.h"
#include "bashtypes.h"
-#ifndef _MINIX
+#if defined (HAVE_SYS_PARAM_H)
# include <sys/param.h>
#endif
#include "posixstat.h"
#include "bashintl.h"
#include "shell.h"
+#include "test.h"
+#include "trap.h"
+
#include <tilde/tilde.h>
#if !defined (errno)
#endif /* !errno */
extern int expand_aliases;
-extern int interrupt_immediately;
extern int interactive_comments;
extern int check_hashed_filenames;
extern int source_uses_path;
static void initialize_group_array __P((void));
/* A standard error message to use when getcwd() returns NULL. */
-char *bash_getcwd_errstr = N_("getcwd: cannot access parent directories");
+const char * const bash_getcwd_errstr = N_("getcwd: cannot access parent directories");
/* Do whatever is necessary to initialize `Posix mode'. */
void
if (on != 0)
{
interactive_comments = source_uses_path = expand_aliases = 1;
+ source_searches_cwd = 0;
}
/* Things that should be turned on when posix mode is disabled. */
neg = 0;
while (s && *s && whitespace (*s))
s++;
- if (*s == '-' || *s == '+')
+ if (s && (*s == '-' || *s == '+'))
{
neg = *s == '-';
s++;
not null. */
int
legal_number (string, result)
- char *string;
+ const char *string;
intmax_t *result;
{
intmax_t value;
if (result)
*result = 0;
+ if (string == 0)
+ return 0;
+
errno = 0;
value = strtoimax (string, &ep, 10);
- if (errno)
+ if (errno || ep == string)
return 0; /* errno is set on overflow or underflow */
/* Skip any trailing whitespace, since strtoimax does not. */
/* If *string is not '\0' but *ep is '\0' on return, the entire string
is valid. */
- if (string && *string && *ep == '\0')
+ if (*string && *ep == '\0')
{
if (result)
*result = value;
#if defined (ARRAY_VARS)
if (c == '[')
{
- newi = skipsubscript (string, indx);
+ newi = skipsubscript (string, indx, 0);
if (string[newi++] != ']')
return (0);
+ if (string[newi] == '+' && string[newi+1] == '=')
+ return (newi + 1);
return ((string[newi] == '=') ? newi : 0);
}
#endif /* ARRAY_VARS */
+ /* Check for `+=' */
+ if (c == '+' && string[indx+1] == '=')
+ return (indx + 1);
+
/* Variable names in assignment statements may contain only letters,
digits, and `_'. */
if (legal_variable_char (c) == 0)
return (fcntl (fd, F_GETFD, 0) >= 0);
}
+int
+fd_ispipe (fd)
+ int fd;
+{
+ errno = 0;
+ if (lseek ((fd), 0L, SEEK_CUR) < 0)
+ return (errno == ESPIPE);
+ return 0;
+}
+
/* There is a bug in the NeXT 2.1 rlogind that causes opens
of /dev/tty to fail. */
return;
tty_fd = open (tty, O_RDWR|O_NONBLOCK);
}
- close (tty_fd);
+ if (tty_fd >= 0)
+ close (tty_fd);
}
/* Return 1 if PATH1 and PATH2 are the same file. This is kind of
c = sample[i];
if (c == '\n')
return (0);
-
- if (ISSPACE (c) == 0 && ISPRINT (c) == 0)
+ if (c == '\0')
return (1);
}
return (0);
}
+/* **************************************************************** */
+/* */
+/* Functions to manipulate pipes */
+/* */
+/* **************************************************************** */
+
+int
+sh_openpipe (pv)
+ int *pv;
+{
+ int r;
+
+ if ((r = pipe (pv)) < 0)
+ return r;
+
+ pv[0] = move_to_high_fd (pv[0], 1, 64);
+ pv[1] = move_to_high_fd (pv[1], 1, 64);
+
+ return 0;
+}
+
+int
+sh_closepipe (pv)
+ int *pv;
+{
+ if (pv[0] >= 0)
+ close (pv[0]);
+
+ if (pv[1] >= 0)
+ close (pv[1]);
+
+ pv[0] = pv[1] = -1;
+ return 0;
+}
+
/* **************************************************************** */
/* */
/* Functions to inspect pathnames */
/* */
/* **************************************************************** */
+int
+file_exists (fn)
+ char *fn;
+{
+ struct stat sb;
+
+ return (stat (fn, &sb) == 0);
+}
+
int
file_isdir (fn)
char *fn;
file_iswdir (fn)
char *fn;
{
- return (file_isdir (fn) && test_eaccess (fn, W_OK) == 0);
+ return (file_isdir (fn) && sh_eaccess (fn, W_OK) == 0);
}
-
-/* **************************************************************** */
-/* */
-/* Functions to manipulate pathnames */
-/* */
-/* **************************************************************** */
-
-/* Turn STRING (a pathname) into an absolute pathname, assuming that
- DOT_PATH contains the symbolic location of `.'. This always
- returns a new string, even if STRING was an absolute pathname to
- begin with. */
-char *
-make_absolute (string, dot_path)
- char *string, *dot_path;
+/* Return 1 if STRING is "." or "..", optionally followed by a directory
+ separator */
+int
+path_dot_or_dotdot (string)
+ const char *string;
{
- char *result;
-
- if (dot_path == 0 || ABSPATH(string))
-#ifdef __CYGWIN__
- {
- char pathbuf[PATH_MAX + 1];
+ if (string == 0 || *string == '\0' || *string != '.')
+ return (0);
- cygwin_conv_to_full_posix_path (string, pathbuf);
- result = savestring (pathbuf);
- }
-#else
- result = savestring (string);
-#endif
- else
- result = sh_makepath (dot_path, string, 0);
+ /* string[0] == '.' */
+ if (PATHSEP(string[1]) || (string[1] == '.' && PATHSEP(string[2])))
+ return (1);
- return (result);
+ return (0);
}
/* Return 1 if STRING contains an absolute pathname, else 0. Used by `cd'
absolute_program (string)
const char *string;
{
- return ((char *)xstrchr (string, '/') != (char *)NULL);
+ return ((char *)mbschr (string, '/') != (char *)NULL);
+}
+
+/* **************************************************************** */
+/* */
+/* Functions to manipulate pathnames */
+/* */
+/* **************************************************************** */
+
+/* Turn STRING (a pathname) into an absolute pathname, assuming that
+ DOT_PATH contains the symbolic location of `.'. This always
+ returns a new string, even if STRING was an absolute pathname to
+ begin with. */
+char *
+make_absolute (string, dot_path)
+ char *string, *dot_path;
+{
+ char *result;
+
+ if (dot_path == 0 || ABSPATH(string))
+#ifdef __CYGWIN__
+ {
+ char pathbuf[PATH_MAX + 1];
+
+ cygwin_conv_to_full_posix_path (string, pathbuf);
+ result = savestring (pathbuf);
+ }
+#else
+ result = savestring (string);
+#endif
+ else
+ result = sh_makepath (dot_path, string, 0);
+
+ return (result);
}
/* Return the `basename' of the pathname in STRING (the stuff after the
- last '/'). If STRING is not a full pathname, simply return it. */
+ last '/'). If STRING is `/', just return it. */
char *
base_pathname (string)
char *string;
{
char *p;
+#if 0
if (absolute_pathname (string) == 0)
return (string);
+#endif
+
+ if (string[0] == '/' && string[1] == 0)
+ return (string);
p = (char *)strrchr (string, '/');
return (p ? ++p : string);
return (name);
}
+/* Trim NAME. If NAME begins with `~/', skip over tilde prefix. Trim to
+ keep any tilde prefix and PROMPT_DIRTRIM trailing directory components
+ and replace the intervening characters with `...' */
+char *
+trim_pathname (name, maxlen)
+ char *name;
+ int maxlen;
+{
+ int nlen, ndirs;
+ intmax_t nskip;
+ char *nbeg, *nend, *ntail, *v;
+
+ if (name == 0 || (nlen = strlen (name)) == 0)
+ return name;
+ nend = name + nlen;
+
+ v = get_string_value ("PROMPT_DIRTRIM");
+ if (v == 0 || *v == 0)
+ return name;
+ if (legal_number (v, &nskip) == 0 || nskip <= 0)
+ return name;
+
+ /* Skip over tilde prefix */
+ nbeg = name;
+ if (name[0] == '~')
+ for (nbeg = name; *nbeg; nbeg++)
+ if (*nbeg == '/')
+ {
+ nbeg++;
+ break;
+ }
+ if (*nbeg == 0)
+ return name;
+
+ for (ndirs = 0, ntail = nbeg; *ntail; ntail++)
+ if (*ntail == '/')
+ ndirs++;
+ if (ndirs < nskip)
+ return name;
+
+ for (ntail = (*nend == '/') ? nend : nend - 1; ntail > nbeg; ntail--)
+ {
+ if (*ntail == '/')
+ nskip--;
+ if (nskip == 0)
+ break;
+ }
+ if (ntail == nbeg)
+ return name;
+
+ /* Now we want to return name[0..nbeg]+"..."+ntail, modifying name in place */
+ nlen = ntail - nbeg;
+ if (nlen <= 3)
+ return name;
+
+ *nbeg++ = '.';
+ *nbeg++ = '.';
+ *nbeg++ = '.';
+
+ nlen = nend - ntail;
+ memmove (nbeg, ntail, nlen);
+ nbeg[nlen] = '\0';
+
+ return name;
+}
+
/* Given a string containing units of information separated by colons,
return the next one pointed to by (P_INDEX), or NULL if there are no more.
Advance (P_INDEX) to the character after the colon. */
#endif
static char **bash_tilde_prefixes;
+static char **bash_tilde_prefixes2;
static char **bash_tilde_suffixes;
+static char **bash_tilde_suffixes2;
/* If tilde_expand hasn't been able to expand the text, perhaps it
is a special shell expansion. This function is installed as the
bash_tilde_prefixes[1] = ":~";
bash_tilde_prefixes[2] = (char *)NULL;
+ bash_tilde_prefixes2 = strvec_create (2);
+ bash_tilde_prefixes2[0] = ":~";
+ bash_tilde_prefixes2[1] = (char *)NULL;
+
tilde_additional_prefixes = bash_tilde_prefixes;
bash_tilde_suffixes = strvec_create (3);
bash_tilde_suffixes[2] = (char *)NULL;
tilde_additional_suffixes = bash_tilde_suffixes;
+
+ bash_tilde_suffixes2 = strvec_create (2);
+ bash_tilde_suffixes2[0] = ":";
+ bash_tilde_suffixes2[1] = (char *)NULL;
}
}
return 1;
}
+/* Find the end of the tilde-prefix starting at S, and return the tilde
+ prefix in newly-allocated memory. Return the length of the string in
+ *LENP. FLAGS tells whether or not we're in an assignment context --
+ if so, `:' delimits the end of the tilde prefix as well. */
+char *
+bash_tilde_find_word (s, flags, lenp)
+ const char *s;
+ int flags, *lenp;
+{
+ const char *r;
+ char *ret;
+ int l;
+
+ for (r = s; *r && *r != '/'; r++)
+ {
+ /* Short-circuit immediately if we see a quote character. Even though
+ POSIX says that `the first unquoted slash' (or `:') terminates the
+ tilde-prefix, in practice, any quoted portion of the tilde prefix
+ will cause it to not be expanded. */
+ if (*r == '\\' || *r == '\'' || *r == '"')
+ {
+ ret = savestring (s);
+ if (lenp)
+ *lenp = 0;
+ return ret;
+ }
+ else if (flags && *r == ':')
+ break;
+ }
+ l = r - s;
+ ret = xmalloc (l + 1);
+ strncpy (ret, s, l);
+ ret[l] = '\0';
+ if (lenp)
+ *lenp = l;
+ return ret;
+}
+
/* Tilde-expand S by running it through the tilde expansion library.
ASSIGN_P is 1 if this is a variable assignment, so the alternate
- tilde prefixes should be enabled (`=~' and `:~', see above). */
+ tilde prefixes should be enabled (`=~' and `:~', see above). If
+ ASSIGN_P is 2, we are expanding the rhs of an assignment statement,
+ so `=~' is not valid. */
char *
bash_tilde_expand (s, assign_p)
const char *s;
int assign_p;
{
- int old_immed, r;
+ int old_immed, old_term, r;
char *ret;
old_immed = interrupt_immediately;
- interrupt_immediately = 1;
- tilde_additional_prefixes = assign_p ? bash_tilde_prefixes : (char **)0;
+ old_term = terminate_immediately;
+ /* We want to be able to interrupt tilde expansion. Ordinarily, we can just
+ jump to top_level, but we don't want to run any trap commands in a signal
+ handler context. We might be able to get away with just checking for
+ things like SIGINT and SIGQUIT. */
+ if (any_signals_trapped () < 0)
+ interrupt_immediately = 1;
+ terminate_immediately = 1;
+
+ tilde_additional_prefixes = assign_p == 0 ? (char **)0
+ : (assign_p == 2 ? bash_tilde_prefixes2 : bash_tilde_prefixes);
+ if (assign_p == 2)
+ tilde_additional_suffixes = bash_tilde_suffixes2;
+
r = (*s == '~') ? unquoted_tilde_word (s) : 1;
ret = r ? tilde_expand (s) : savestring (s);
+
interrupt_immediately = old_immed;
+ terminate_immediately = old_term;
+
+ QUIT;
+
return (ret);
}