/* general.c -- Stuff that is used by all files. */
-/* Copyright (C) 1987-1999 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2016 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 "filecntl.h"
#include "bashansi.h"
#include <stdio.h>
-#include <ctype.h>
+#include "chartypes.h"
#include <errno.h>
+#include "bashintl.h"
+
#include "shell.h"
-#include <tilde/tilde.h>
+#include "parser.h"
+#include "flags.h"
+#include "findcmd.h"
+#include "test.h"
+#include "trap.h"
+
+#include "builtins/common.h"
+
+#if defined (HAVE_MBSTR_H) && defined (HAVE_MBSCHR)
+# include <mbstr.h> /* mbschr */
+#endif
-#include "maxpath.h"
+#include <tilde/tilde.h>
#if !defined (errno)
extern int errno;
#endif /* !errno */
-#ifndef to_upper
-# define to_upper(c) (islower(c) ? toupper(c) : (c))
-# define to_lower(c) (isupper(c) ? tolower(c) : (c))
+#ifdef __CYGWIN__
+# include <sys/cygwin.h>
#endif
-extern int interactive_shell, expand_aliases;
-extern int interrupt_immediately;
-extern int interactive_comments;
-extern int check_hashed_filenames;
-extern int source_uses_path;
-extern int source_searches_cwd;
+static char *bash_special_tilde_expansions __P((char *));
+static int unquoted_tilde_word __P((const char *));
+static void initialize_group_array __P((void));
/* A standard error message to use when getcwd() returns NULL. */
-char *bash_getcwd_errstr = "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'. This currently
+ modifies the following variables which are controlled via shopt:
+ interactive_comments
+ source_uses_path
+ expand_aliases
+ inherit_errexit
+ print_shift_error
+
+ and the following variables which cannot be user-modified:
+
+ source_searches_cwd
+
+ If we add to the first list, we need to change the table and functions
+ below */
+
+static struct {
+ int *posix_mode_var;
+} posix_vars[] =
+{
+ &interactive_comments,
+ &source_uses_path,
+ &expand_aliases,
+ &inherit_errexit,
+ &print_shift_error,
+ 0
+};
-/* Do whatever is necessary to initialize `Posix mode'. */
void
posix_initialize (on)
int on;
if (on != 0)
{
interactive_comments = source_uses_path = expand_aliases = 1;
+ inherit_errexit = 1;
+ source_searches_cwd = 0;
+ print_shift_error = 1;
+
}
/* Things that should be turned on when posix mode is disabled. */
{
source_searches_cwd = 1;
expand_aliases = interactive_shell;
+ print_shift_error = 0;
}
}
+int
+num_posix_options ()
+{
+ return ((sizeof (posix_vars) / sizeof (posix_vars[0])) - 1);
+}
+
+char *
+get_posix_options (bitmap)
+ char *bitmap;
+{
+ register int i;
+
+ if (bitmap == 0)
+ bitmap = (char *)xmalloc (num_posix_options ()); /* no trailing NULL */
+ for (i = 0; posix_vars[i].posix_mode_var; i++)
+ bitmap[i] = *(posix_vars[i].posix_mode_var);
+ return bitmap;
+}
+
+void
+set_posix_options (bitmap)
+ const char *bitmap;
+{
+ register int i;
+
+ for (i = 0; posix_vars[i].posix_mode_var; i++)
+ *(posix_vars[i].posix_mode_var) = bitmap[i];
+}
+
/* **************************************************************** */
/* */
/* Functions to convert to and from and display non-standard types */
neg = 0;
while (s && *s && whitespace (*s))
s++;
- if (*s == '-' || *s == '+')
+ if (s && (*s == '-' || *s == '+'))
{
neg = *s == '-';
s++;
}
- for ( ; s && *s && digit (*s); s++)
- ret = (ret * 10) + digit_value (*s);
+ for ( ; s && *s && DIGIT (*s); s++)
+ ret = (ret * 10) + TODIGIT (*s);
return (neg ? -ret : ret);
}
RLIMTYPE n;
int addnl;
{
- char s[sizeof (RLIMTYPE) * 3 + 1];
- int len;
+ char s[INT_STRLEN_BOUND (RLIMTYPE) + 1], *p;
- if (n == 0)
- {
- printf ("0%s", addnl ? "\n" : "");
- return;
- }
+ p = s + sizeof(s);
+ *--p = '\0';
if (n < 0)
{
- putchar ('-');
- n = -n;
+ do
+ *--p = '0' - n % 10;
+ while ((n /= 10) != 0);
+
+ *--p = '-';
+ }
+ else
+ {
+ do
+ *--p = '0' + n % 10;
+ while ((n /= 10) != 0);
}
- len = sizeof (RLIMTYPE) * 3 + 1;
- s[--len] = '\0';
- for ( ; n != 0; n /= 10)
- s[--len] = n % 10 + '0';
- printf ("%s%s", s + len, addnl ? "\n" : "");
+ printf ("%s%s", p, addnl ? "\n" : "");
}
#endif /* RLIMTYPE */
/* Return non-zero if all of the characters in STRING are digits. */
int
all_digits (string)
- char *string;
+ const char *string;
{
- register char *s;
+ register const char *s;
for (s = string; *s; s++)
- if (isdigit (*s) == 0)
+ if (DIGIT (*s) == 0)
return (0);
return (1);
/* Return non-zero if the characters pointed to by STRING constitute a
valid number. Stuff the converted number into RESULT if RESULT is
- a non-null pointer to a long. */
+ not null. */
int
legal_number (string, result)
- char *string;
- long *result;
+ const char *string;
+ intmax_t *result;
{
- long value;
+ intmax_t value;
char *ep;
if (result)
*result = 0;
- value = strtol (string, &ep, 10);
+ if (string == 0)
+ return 0;
+
+ errno = 0;
+ value = strtoimax (string, &ep, 10);
+ if (errno || ep == string)
+ return 0; /* errno is set on overflow or underflow */
- /* Skip any trailing whitespace, since strtol does not. */
+ /* Skip any trailing whitespace, since strtoimax does not. */
while (whitespace (*ep))
ep++;
/* 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;
digit. */
int
legal_identifier (name)
- char *name;
+ const char *name;
{
- register char *s;
+ register const char *s;
+ unsigned char c;
- if (!name || !*name || (legal_variable_starter (*name) == 0))
+ if (!name || !(c = *name) || (legal_variable_starter (c) == 0))
return (0);
- for (s = name + 1; *s; s++)
+ for (s = name + 1; (c = *s) != 0; s++)
{
- if (legal_variable_char (*s) == 0)
+ if (legal_variable_char (c) == 0)
return (0);
}
return (1);
}
+/* Return 1 if NAME is a valid value that can be assigned to a nameref
+ variable. FLAGS can be 2, in which case the name is going to be used
+ to create a variable. Other values are currently unused, but could
+ be used to allow values to be stored and indirectly referenced, but
+ not used in assignments. */
+int
+valid_nameref_value (name, flags)
+ const char *name;
+ int flags;
+{
+ if (name == 0 || *name == 0)
+ return 0;
+
+ /* valid identifier */
+#if defined (ARRAY_VARS)
+ if (legal_identifier (name) || (flags != 2 && valid_array_reference (name, 0)))
+#else
+ if (legal_identifier (name))
+#endif
+ return 1;
+
+ return 0;
+}
+
+int
+check_selfref (name, value, flags)
+ const char *name;
+ char *value;
+ int flags;
+{
+ char *t;
+
+ if (STREQ (name, value))
+ return 1;
+
+#if defined (ARRAY_VARS)
+ if (valid_array_reference (value, 0))
+ {
+ t = array_variable_name (value, 0, (char **)NULL, (int *)NULL);
+ if (t && STREQ (name, t))
+ {
+ free (t);
+ return 1;
+ }
+ free (t);
+ }
+#endif
+
+ return 0; /* not a self reference */
+}
+
/* Make sure that WORD is a valid shell identifier, i.e.
does not contain a dollar sign, nor is quoted in any way. Nor
does it consist of all digits. If CHECK_WORD is non-zero,
{
if ((word->flags & (W_HASDOLLAR|W_QUOTED)) || all_digits (word->word))
{
- internal_error ("`%s': not a valid identifier", word->word);
+ internal_error (_("`%s': not a valid identifier"), word->word);
return (0);
}
else if (check_word && legal_identifier (word->word) == 0)
{
- internal_error ("`%s': not a valid identifier", word->word);
+ internal_error (_("`%s': not a valid identifier"), word->word);
return (0);
}
else
return (1);
}
+/* Return 1 if STRING is a function name that the shell will import from
+ the environment. Currently we reject attempts to import shell functions
+ containing slashes, beginning with newlines or containing blanks. In
+ Posix mode, we require that STRING be a valid shell identifier. Not
+ used yet. */
+int
+importable_function_name (string, len)
+ const char *string;
+ size_t len;
+{
+ if (absolute_program (string)) /* don't allow slash */
+ return 0;
+ if (*string == '\n') /* can't start with a newline */
+ return 0;
+ if (shellblank (*string) || shellblank(string[len-1]))
+ return 0;
+ return (posixly_correct ? legal_identifier (string) : 1);
+}
+
+int
+exportable_function_name (string)
+ const char *string;
+{
+ if (absolute_program (string))
+ return 0;
+ if (mbschr (string, '=') != 0)
+ return 0;
+ return 1;
+}
+
+/* Return 1 if STRING comprises a valid alias name. The shell accepts
+ essentially all characters except those which must be quoted to the
+ parser (which disqualifies them from alias expansion anyway) and `/'. */
+int
+legal_alias_name (string, flags)
+ const char *string;
+ int flags;
+{
+ register const char *s;
+
+ for (s = string; *s; s++)
+ if (shellbreak (*s) || shellxquote (*s) || shellexp (*s) || (*s == '/'))
+ return 0;
+ return 1;
+}
+
+/* Returns non-zero if STRING is an assignment statement. The returned value
+ is the index of the `=' sign. If FLAGS&1 we are expecting a compound assignment
+ and don't want an array subscript before the `='. */
+int
+assignment (string, flags)
+ const char *string;
+ int flags;
+{
+ register unsigned char c;
+ register int newi, indx;
+
+ c = string[indx = 0];
+
+#if defined (ARRAY_VARS)
+ if ((legal_variable_starter (c) == 0) && ((flags&1) == 0 || c != '[')) /* ] */
+#else
+ if (legal_variable_starter (c) == 0)
+#endif
+ return (0);
+
+ while (c = string[indx])
+ {
+ /* The following is safe. Note that '=' at the start of a word
+ is not an assignment statement. */
+ if (c == '=')
+ return (indx);
+
+#if defined (ARRAY_VARS)
+ if (c == '[')
+ {
+ newi = skipsubscript (string, indx, (flags & 2) ? 1 : 0);
+ /* XXX - why not check for blank subscripts here, if we do in
+ valid_array_reference? */
+ 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 (0);
+
+ indx++;
+ }
+ return (0);
+}
+
+int
+line_isblank (line)
+ const char *line;
+{
+ register int i;
+
+ if (line == 0)
+ return 0; /* XXX */
+ for (i = 0; line[i]; i++)
+ if (isblank ((unsigned char)line[i]) == 0)
+ break;
+ return (line[i] == '\0');
+}
+
/* **************************************************************** */
/* */
/* Functions to manage files and file descriptors */
return 0;
}
+/* Just a wrapper for the define in include/filecntl.h */
+int
+sh_setclexec (fd)
+ int fd;
+{
+ return (SET_CLOSE_ON_EXEC (fd));
+}
+
+/* Return 1 if file descriptor FD is valid; 0 otherwise. */
+int
+sh_validfd (fd)
+ int fd;
+{
+ return (fcntl (fd, F_GETFD, 0) >= 0);
+}
+
+int
+fd_ispipe (fd)
+ int fd;
+{
+ errno = 0;
+ return ((lseek (fd, 0L, SEEK_CUR) < 0) && (errno == ESPIPE));
+}
+
/* 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
corresponding to PATH1 and PATH2, respectively. */
int
same_file (path1, path2, stp1, stp2)
- char *path1, *path2;
+ const char *path1, *path2;
struct stat *stp1, *stp2;
{
struct stat st1, st2;
nfds = getdtablesize ();
if (nfds <= 0)
nfds = 20;
- if (nfds > 256)
- nfds = 256;
+ if (nfds > HIGH_FD_MAX)
+ nfds = HIGH_FD_MAX; /* reasonable maximum */
}
else
nfds = maxfd;
if (fcntl (nfds, F_GETFD, &ignore) == -1)
break;
- if (nfds && fd != nfds && (script_fd = dup2 (fd, nfds)) != -1)
+ if (nfds > 3 && fd != nfds && (script_fd = dup2 (fd, nfds)) != -1)
{
if (check_new == 0 || fd != fileno (stderr)) /* don't close stderr */
close (fd);
return (script_fd);
}
+ /* OK, we didn't find one less than our artificial maximum; return the
+ original file descriptor. */
return (fd);
}
check up to the first newline, or SAMPLE_LEN, whichever comes first.
All of the characters must be printable or whitespace. */
-#if !defined (isspace)
-#define isspace(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\f')
-#endif
-
-#if !defined (isprint)
-#define isprint(c) (isletter(c) || digit(c) || ispunct(c))
-#endif
-
int
check_binary_file (sample, sample_len)
- unsigned char *sample;
+ const char *sample;
int sample_len;
{
register int i;
+ unsigned char c;
for (i = 0; i < sample_len; i++)
{
- if (sample[i] == '\n')
+ c = sample[i];
+ if (c == '\n')
return (0);
-
- if (isspace (sample[i]) == 0 && isprint (sample[i]) == 0)
+ if (c == '\0')
return (1);
}
/* **************************************************************** */
/* */
-/* Functions to manipulate pathnames */
+/* Functions to manipulate pipes */
/* */
/* **************************************************************** */
-/* 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;
+int
+sh_openpipe (pv)
+ int *pv;
{
- char *result;
+ int r;
- if (dot_path == 0 || ABSPATH(string))
- result = savestring (string);
- else
- result = sh_makepath (dot_path, string, 0);
+ if ((r = pipe (pv)) < 0)
+ return r;
- return (result);
+ 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)
+ const char *fn;
+{
+ struct stat sb;
+
+ return (stat (fn, &sb) == 0);
+}
+
+int
+file_isdir (fn)
+ const char *fn;
+{
+ struct stat sb;
+
+ return ((stat (fn, &sb) == 0) && S_ISDIR (sb.st_mode));
+}
+
+int
+file_iswdir (fn)
+ const char *fn;
+{
+ return (file_isdir (fn) && sh_eaccess (fn, W_OK) == 0);
+}
+
+/* Return 1 if STRING is "." or "..", optionally followed by a directory
+ separator */
+int
+path_dot_or_dotdot (string)
+ const char *string;
+{
+ if (string == 0 || *string == '\0' || *string != '.')
+ return (0);
+
+ /* string[0] == '.' */
+ if (PATHSEP(string[1]) || (string[1] == '.' && PATHSEP(string[2])))
+ return (1);
+
+ return (0);
}
/* Return 1 if STRING contains an absolute pathname, else 0. Used by `cd'
to decide whether or not to look up a directory name in $CDPATH. */
int
absolute_pathname (string)
- char *string;
+ const char *string;
{
if (string == 0 || *string == '\0')
return (0);
up through $PATH. */
int
absolute_program (string)
- char *string;
+ const char *string;
{
- return ((char *)strchr (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)
+ const char *string, *dot_path;
+{
+ char *result;
+
+ if (dot_path == 0 || ABSPATH(string))
+#ifdef __CYGWIN__
+ {
+ char pathbuf[PATH_MAX + 1];
+
+ /* WAS cygwin_conv_to_full_posix_path (string, pathbuf); */
+ cygwin_conv_path (CCP_WIN_A_TO_POSIX, string, pathbuf, PATH_MAX);
+ 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);
{
char *ret;
- file = (*file == '~') ? bash_tilde_expand (file) : savestring (file);
+ file = (*file == '~') ? bash_tilde_expand (file, 0) : savestring (file);
if (ABSPATH(file))
return (file);
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;
+}
+
+/* Return a printable representation of FN without special characters. The
+ caller is responsible for freeing memory if this returns something other
+ than its argument. If FLAGS is non-zero, we are printing for portable
+ re-input and should single-quote filenames appropriately. */
+char *
+printable_filename (fn, flags)
+ char *fn;
+ int flags;
+{
+ char *newf;
+
+ if (ansic_shouldquote (fn))
+ newf = ansic_quote (fn, 0, NULL);
+ else if (flags && sh_contains_shell_metas (fn))
+ newf = sh_single_quote (fn);
+ else
+ newf = fn;
+
+ return newf;
+}
+
/* 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. */
if (string[i])
(*p_index)++;
/* Return "" in the case of a trailing `:'. */
- value = xmalloc (1);
+ value = (char *)xmalloc (1);
value[0] = '\0';
}
else
extern char *get_dirstack_from_string __P((char *));
#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
tilde_expansion_preexpansion_hook. It knows how to expand ~- and ~+.
else if (text[0] == '-' && text[1] == '\0')
result = get_string_value ("OLDPWD");
#if defined (PUSHD_AND_POPD)
- else if (isdigit (*text) || ((*text == '+' || *text == '-') && isdigit (text[1])))
+ else if (DIGIT (*text) || ((*text == '+' || *text == '-') && DIGIT (text[1])))
result = get_dirstack_from_string (text);
#endif
static int times_called = 0;
/* Tell the tilde expander that we want a crack first. */
- tilde_expansion_preexpansion_hook = (CPFunction *)bash_special_tilde_expansions;
+ tilde_expansion_preexpansion_hook = bash_special_tilde_expansions;
/* Tell the tilde expander about special strings which start a tilde
expansion, and the special strings that end one. Only do this once.
tilde_initialize () is called from within bashline_reinitialize (). */
if (times_called++ == 0)
{
- tilde_additional_prefixes = alloc_array (3);
- tilde_additional_prefixes[0] = "=~";
- tilde_additional_prefixes[1] = ":~";
- tilde_additional_prefixes[2] = (char *)NULL;
+ bash_tilde_prefixes = strvec_create (3);
+ bash_tilde_prefixes[0] = "=~";
+ 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[0] = ":";
+ bash_tilde_suffixes[1] = "=~"; /* XXX - ?? */
+ 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;
+ }
+}
- tilde_additional_suffixes = alloc_array (3);
- tilde_additional_suffixes[0] = ":";
- tilde_additional_suffixes[1] = "=~";
- tilde_additional_suffixes[2] = (char *)NULL;
+/* POSIX.2, 3.6.1: A tilde-prefix consists of an unquoted tilde character
+ at the beginning of the word, followed by all of the characters preceding
+ the first unquoted slash in the word, or all the characters in the word
+ if there is no slash...If none of the characters in the tilde-prefix are
+ quoted, the characters in the tilde-prefix following the tilde shell be
+ treated as a possible login name. */
+
+#define TILDE_END(c) ((c) == '\0' || (c) == '/' || (c) == ':')
+
+static int
+unquoted_tilde_word (s)
+ const char *s;
+{
+ const char *r;
+
+ for (r = s; TILDE_END(*r) == 0; r++)
+ {
+ switch (*r)
+ {
+ case '\\':
+ case '\'':
+ case '"':
+ return 0;
+ }
}
+ 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_expand (s)
- char *s;
+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). 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;
+ int old_immed, old_term, r;
char *ret;
+#if 0
old_immed = interrupt_immediately;
- interrupt_immediately = 1;
- ret = tilde_expand (s);
+ 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;
+#endif
+
+ 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);
+
+#if 0
interrupt_immediately = old_immed;
+ terminate_immediately = old_term;
+#endif
+
+ QUIT;
+
return (ret);
}
# define NOGROUP (gid_t) -1
#endif
-#if defined (HAVE_SYSCONF) && defined (_SC_NGROUPS_MAX)
-# define getmaxgroups() sysconf(_SC_NGROUPS_MAX)
-#else
-# if defined (NGROUPS_MAX)
-# define getmaxgroups() NGROUPS_MAX
-# else /* !NGROUPS_MAX */
-# if defined (NGROUPS)
-# define getmaxgroups() NGROUPS
-# else /* !NGROUPS */
-# define getmaxgroups() 64
-# endif /* !NGROUPS */
-# endif /* !NGROUPS_MAX */
-#endif /* !HAVE_SYSCONF || !SC_NGROUPS_MAX */
-
static void
initialize_group_array ()
{
{
static char **group_vector = (char **)NULL;
register int i;
- char *nbuf;
if (group_vector)
{
return (char **)NULL;
}
- group_vector = alloc_array (ngroups);
+ group_vector = strvec_create (ngroups);
for (i = 0; i < ngroups; i++)
- {
- nbuf = itos ((int)group_array[i]);
- group_vector[i] = nbuf;
- }
+ group_vector[i] = itos (group_array[i]);
if (ngp)
*ngp = ngroups;
*ngp = ngroups;
return group_iarray;
}
+
+/* **************************************************************** */
+/* */
+/* Miscellaneous functions */
+/* */
+/* **************************************************************** */
+
+/* Return a value for PATH that is guaranteed to find all of the standard
+ utilities. This uses Posix.2 configuration variables, if present. It
+ uses a value defined in config.h as a last resort. */
+char *
+conf_standard_path ()
+{
+#if defined (_CS_PATH) && defined (HAVE_CONFSTR)
+ char *p;
+ size_t len;
+
+ len = (size_t)confstr (_CS_PATH, (char *)NULL, (size_t)0);
+ if (len > 0)
+ {
+ p = (char *)xmalloc (len + 2);
+ *p = '\0';
+ confstr (_CS_PATH, p, len);
+ return (p);
+ }
+ else
+ return (savestring (STANDARD_UTILS_PATH));
+#else /* !_CS_PATH || !HAVE_CONFSTR */
+# if defined (CS_PATH)
+ return (savestring (CS_PATH));
+# else
+ return (savestring (STANDARD_UTILS_PATH));
+# endif /* !CS_PATH */
+#endif /* !_CS_PATH || !HAVE_CONFSTR */
+}
+
+int
+default_columns ()
+{
+ char *v;
+ int c;
+
+ c = -1;
+ v = get_string_value ("COLUMNS");
+ if (v && *v)
+ {
+ c = atoi (v);
+ if (c > 0)
+ return c;
+ }
+
+ if (check_window_size)
+ get_new_window_size (0, (int *)0, &c);
+
+ return (c > 0 ? c : 80);
+}
+
+