/* general.c -- Stuff that is used by all files. */
-/* Copyright (C) 1987, 1988, 1989, 1990, 1991, 1992
- Free Software Foundation, Inc.
+/* Copyright (C) 1987-2004 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
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, 675 Mass Ave, Cambridge, MA 02139, USA. */
+ Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
#include "config.h"
#include "filecntl.h"
#include "bashansi.h"
#include <stdio.h>
-#include <ctype.h>
+#include "chartypes.h"
#include <errno.h>
-#include "shell.h"
-#include <tilde/tilde.h>
+#include "bashintl.h"
-#if defined (TIME_WITH_SYS_TIME)
-# include <sys/time.h>
-# include <time.h>
-#else
-# if defined (HAVE_SYS_TIME_H)
-# include <sys/time.h>
-# else
-# include <time.h>
-# endif
-#endif
+#include "shell.h"
+#include "test.h"
-#include <sys/times.h>
-#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))
-#endif
-
+extern int 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";
+char *bash_getcwd_errstr = N_("getcwd: cannot access parent directories");
/* Do whatever is necessary to initialize `Posix mode'. */
void
posix_initialize (on)
int on;
{
- interactive_comments = on != 0;
+ /* Things that should be turned on when posix mode is enabled. */
+ if (on != 0)
+ {
+ interactive_comments = source_uses_path = expand_aliases = 1;
+ }
+
+ /* Things that should be turned on when posix mode is disabled. */
+ if (on == 0)
+ {
+ source_searches_cwd = 1;
+ expand_aliases = interactive_shell;
+ }
}
/* **************************************************************** */
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 */
-#if defined (HAVE_TIMEVAL)
-/* Convert a pointer to a struct timeval to seconds and thousandths of a
- second, returning the values in *SP and *SFP, respectively. This does
- rounding on the fractional part, not just truncation to three places. */
-void
-timeval_to_secs (tvp, sp, sfp)
- struct timeval *tvp;
- long *sp;
- int *sfp;
-{
- int rest;
-
- *sp = tvp->tv_sec;
-
- *sfp = tvp->tv_usec % 1000000; /* pretty much a no-op */
- rest = *sfp % 1000;
- *sfp = (*sfp * 1000) / 1000000;
- if (rest >= 500)
- *sfp += 1;
-}
-
-/* Print the contents of a struct timeval * in a standard way to stdio
- stream FP. */
-void
-print_timeval (fp, tvp)
- FILE *fp;
- struct timeval *tvp;
-{
- int minutes, seconds_fraction;
- long seconds;
-
- timeval_to_secs (tvp, &seconds, &seconds_fraction);
-
- minutes = seconds / 60;
- seconds %= 60;
-
- fprintf (fp, "%0dm%0ld.%03ds", minutes, seconds, seconds_fraction);
-}
-#endif /* HAVE_TIMEVAL */
-
-#if defined (HAVE_TIMES)
-void
-clock_t_to_secs (t, sp, sfp)
- clock_t t;
- long *sp;
- int *sfp;
-{
- static long clk_tck = 0;
-
- if (clk_tck == 0)
- clk_tck = get_clk_tck ();
-
- *sfp = t % clk_tck;
- *sfp = (*sfp * 1000) / clk_tck;
-
- *sp = t / clk_tck;
-}
-
-/* Print the time defined by a time_t (returned by the `times' and `time'
- system calls) in a standard way to stdion stream FP. This is scaled in
- terms of HZ, which is what is returned by the `times' call. */
-void
-print_time_in_hz (fp, t)
- FILE *fp;
- clock_t t;
-{
- int minutes, seconds_fraction;
- long seconds;
-
- clock_t_to_secs (t, &seconds, &seconds_fraction);
-
- minutes = seconds / 60;
- seconds %= 60;
-
- fprintf (fp, "%0dm%0ld.%03ds", minutes, seconds, seconds_fraction);
-}
-#endif /* HAVE_TIMES */
-
/* **************************************************************** */
/* */
/* Input Validation Functions */
all_digits (string)
char *string;
{
- while (*string)
- {
- if (!digit (*string))
- return (0);
- else
- string++;
- }
+ register char *s;
+
+ for (s = string; *s; s++)
+ 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;
+ intmax_t *result;
{
- long value;
+ intmax_t value;
char *ep;
if (result)
*result = 0;
- value = strtol (string, &ep, 10);
+ errno = 0;
+ value = strtoimax (string, &ep, 10);
+ if (errno)
+ return 0; /* errno is set on overflow or underflow */
+
+ /* 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. */
char *name;
{
register 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)
- return (0);
+ if (legal_variable_char (c) == 0)
+ return (0);
}
return (1);
}
{
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 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)
+ char *string;
+ int flags;
+{
+ register 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. */
+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 == 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);
+ 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);
+}
+
/* **************************************************************** */
/* */
/* Functions to manage files and file descriptors */
#endif /* O_NDELAY */
/* Make sure no-delay mode is not set on file descriptor FD. */
-void
-unset_nodelay_mode (fd)
+int
+sh_unset_nodelay_mode (fd)
int fd;
{
- int flags, set;
+ int flags, bflags;
if ((flags = fcntl (fd, F_GETFL, 0)) < 0)
- return;
+ return -1;
- set = 0;
+ bflags = 0;
/* This is defined to O_NDELAY in filecntl.h if O_NONBLOCK is not present
and O_NDELAY is defined. */
- if (flags & O_NONBLOCK)
+#ifdef O_NONBLOCK
+ bflags |= O_NONBLOCK;
+#endif
+
+#ifdef O_NDELAY
+ bflags |= O_NDELAY;
+#endif
+
+ if (flags & bflags)
{
- flags &= ~O_NONBLOCK;
- set++;
+ flags &= ~bflags;
+ return (fcntl (fd, F_SETFL, flags));
}
- if (set)
- fcntl (fd, F_SETFL, flags);
+ return 0;
+}
+
+/* Return 1 if file descriptor FD is valid; 0 otherwise. */
+int
+sh_validfd (fd)
+ int fd;
+{
+ return (fcntl (fd, F_GETFD, 0) >= 0);
}
- /* There is a bug in the NeXT 2.1 rlogind that causes opens
- of /dev/tty to fail. */
+/* There is a bug in the NeXT 2.1 rlogind that causes opens
+ of /dev/tty to fail. */
+
+#if defined (__BEOS__)
+/* On BeOS, opening in non-blocking mode exposes a bug in BeOS, so turn it
+ into a no-op. This should probably go away in the future. */
+# undef O_NONBLOCK
+# define O_NONBLOCK 0
+#endif /* __BEOS__ */
+
void
check_dev_tty ()
{
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;
+ 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 (ISSPACE (c) == 0 && ISPRINT (c) == 0)
return (1);
}
/* **************************************************************** */
/* */
-/* Functions to manipulate pathnames */
+/* Functions to inspect pathnames */
/* */
/* **************************************************************** */
-/* Return 1 if PATH corresponds to a directory. */
-static int
-canon_stat (path)
- char *path;
+int
+file_isdir (fn)
+ char *fn;
{
- int l;
- char *s;
struct stat sb;
- l = strlen (path);
- s = xmalloc (l + 3);
- strcpy (s, path);
- s[l] = '/';
- s[l+1] = '.';
- s[l+2] = '\0';
- l = stat (s, &sb) == 0 && S_ISDIR (sb.st_mode);
- free (s);
- return l;
+ return ((stat (fn, &sb) == 0) && S_ISDIR (sb.st_mode));
}
-/* 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. */
-char *
-canonicalize_pathname (path)
- char *path;
+int
+file_iswdir (fn)
+ char *fn;
{
- register int i, start;
- char stub_char;
- char *result;
-
- /* The result cannot be larger than the input PATH. */
- result = savestring (path);
-
- stub_char = (*path == '/') ? '/' : '.';
-
- /* Walk along RESULT looking for things to compact. */
- i = 0;
- while (1)
- {
- if (!result[i])
- break;
-
- while (result[i] && result[i] != '/')
- i++;
-
- start = i++;
-
- /* If we didn't find any slashes, then there is nothing left to do. */
- if (!result[start])
- break;
-
- /* Handle multiple `/'s in a row. */
- while (result[i] == '/')
- i++;
+ return (file_isdir (fn) && test_eaccess (fn, W_OK) == 0);
+}
-#if 0
- if ((start + 1) != i)
-#else
- /* Leave a leading `//' alone, as POSIX requires. */
- if ((start + 1) != i && (start != 0 || i != 2))
-#endif
- {
- strcpy (result + start + 1, result + i);
- i = start + 1;
- /* Make sure that what we have so far corresponds to a directory.
- If it does not, just punt. */
- if (*result)
- {
- char c;
- c = result[start];
- result[start] = '\0';
- if (canon_stat (result) == 0)
- {
- free (result);
- return ((char *)NULL);
- }
- result[start] = c;
- }
- }
-#if 0
- /* Handle backslash-quoted `/'. */
- if (start > 0 && result[start - 1] == '\\')
- continue;
-#endif
+/* 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)
+ const char *string;
+{
+ if (string == 0 || *string == '\0')
+ return (0);
- /* Check for trailing `/'. */
- if (start && !result[i])
- {
- zero_last:
- result[--i] = '\0';
- break;
- }
+ if (ABSPATH(string))
+ return (1);
- /* Check for `../', `./' or trailing `.' by itself. */
- if (result[i] == '.')
- {
- /* Handle trailing `.' by itself. */
- if (!result[i + 1])
- goto zero_last;
-
- /* Handle `./'. */
- if (result[i + 1] == '/')
- {
- strcpy (result + i, result + i + 1);
- i = (start < 0) ? 0 : start;
- continue;
- }
-
- /* Handle `../' or trailing `..' by itself. */
- if (result[i + 1] == '.' &&
- (result[i + 2] == '/' || !result[i + 2]))
- {
- /* Make sure that the last component corresponds to a directory
- before blindly chopping it off. */
- if (i)
- {
- result[i] = '\0';
- if (canon_stat (result) == 0)
- {
- free (result);
- return ((char *)NULL);
- }
- result[i] = '.';
- }
- while (--start > -1 && result[start] != '/');
- strcpy (result + start + 1, result + i + 2);
-#if 0 /* Unnecessary */
- if (*result && canon_stat (result) == 0)
- {
- free (result);
- return ((char *)NULL);
- }
-#endif
- i = (start < 0) ? 0 : start;
- continue;
- }
- }
- }
+ if (string[0] == '.' && PATHSEP(string[1])) /* . and ./ */
+ return (1);
- if (!*result)
- {
- *result = stub_char;
- result[1] = '\0';
- }
+ if (string[0] == '.' && string[1] == '.' && PATHSEP(string[2])) /* .. and ../ */
+ return (1);
-#if 1
- /* Turn `//' into `/' -- XXX experimental */
- if (result[0] == '/' && result[1] == '/' && result[2] == '\0')
- result[1] = '\0';
-#endif
+ return (0);
+}
- return (result);
+/* Return 1 if STRING is an absolute program name; it is absolute if it
+ contains any slashes. This is used to decide whether or not to look
+ up through $PATH. */
+int
+absolute_program (string)
+ const char *string;
+{
+ return ((char *)xstrchr (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
char *string, *dot_path;
{
char *result;
- int result_len;
- if (dot_path == 0 || *string == '/')
- result = savestring (string);
- else
+ if (dot_path == 0 || ABSPATH(string))
+#ifdef __CYGWIN__
{
- if (dot_path[0])
- {
- result_len = strlen (dot_path);
- result = xmalloc (2 + result_len + strlen (string));
- strcpy (result, dot_path);
- if (result[result_len - 1] != '/')
- {
- result[result_len++] = '/';
- result[result_len] = '\0';
- }
- }
- else
- {
- result = xmalloc (3 + strlen (string));
- result[0] = '.'; result[1] = '/'; result[2] = '\0';
- result_len = 2;
- }
+ char pathbuf[PATH_MAX + 1];
- strcpy (result + result_len, string);
+ 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 1 if STRING contains an absolute pathname, else 0. */
-int
-absolute_pathname (string)
- char *string;
-{
- if (!string || !*string)
- return (0);
-
- if (*string == '/')
- return (1);
-
- if (*string++ == '.')
- {
- if (!*string || *string == '/' ||
- (*string == '.' && (string[1] == '\0' || string[1] == '/')))
- return (1);
- }
- return (0);
-}
-
-/* Return 1 if STRING is an absolute program name; it is absolute if it
- contains any slashes. This is used to decide whether or not to look
- up through $PATH. */
-int
-absolute_program (string)
- char *string;
-{
- return ((char *)strchr (string, '/') != (char *)NULL);
-}
-
/* 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 (!absolute_pathname (string))
+#if 0
+ if (absolute_pathname (string) == 0)
+ return (string);
+#endif
+
+ if (string[0] == '/' && string[1] == 0)
return (string);
p = (char *)strrchr (string, '/');
full_pathname (file)
char *file;
{
- char *disposer;
- char *current_dir;
- int dlen;
+ char *ret;
- file = (*file == '~') ? bash_tilde_expand (file) : savestring (file);
+ file = (*file == '~') ? bash_tilde_expand (file, 0) : savestring (file);
- if ((*file == '/') && absolute_pathname (file))
+ if (ABSPATH(file))
return (file);
- disposer = file;
+ ret = sh_makepath ((char *)NULL, file, (MP_DOCWD|MP_RMDOT));
+ free (file);
- /* XXX - this should probably be just PATH_MAX or PATH_MAX + 1 */
- current_dir = xmalloc (2 + PATH_MAX + strlen (file));
- if (getcwd (current_dir, PATH_MAX) == 0)
- {
- sys_error (bash_getcwd_errstr);
- free (disposer);
- free (current_dir);
- return ((char *)NULL);
- }
- dlen = strlen (current_dir);
- current_dir[dlen++] = '/';
-
- /* Turn /foo/./bar into /foo/bar. */
- if (file[0] == '.' && file[1] == '/')
- file += 2;
-
- strcpy (current_dir + dlen, file);
- free (disposer);
- return (current_dir);
+ return (ret);
}
/* A slightly related function. Get the prettiest name of this
if (string[i])
(*p_index)++;
/* Return "" in the case of a trailing `:'. */
- value = xmalloc (1);
+ value = (char *)xmalloc (1);
value[0] = '\0';
}
else
- {
- len = i - start;
- value = xmalloc (1 + len);
- strncpy (value, string + start, len);
- value [len] = '\0';
- }
+ value = substring (string, start, i);
return (value);
}
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 = (char **)xmalloc (3 * sizeof (char *));
- tilde_additional_prefixes[0] = "=~";
- tilde_additional_prefixes[1] = ":~";
- tilde_additional_prefixes[2] = (char *)NULL;
-
- tilde_additional_suffixes = (char **)xmalloc (3 * sizeof (char *));
- tilde_additional_suffixes[0] = ":";
- tilde_additional_suffixes[1] = "=~";
- tilde_additional_suffixes[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;
}
}
+/* 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;
{
- int old_immed;
+ 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, r;
char *ret;
old_immed = interrupt_immediately;
interrupt_immediately = 1;
- ret = tilde_expand (s);
+
+ 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;
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 ()
{
if (i == ngroups && ngroups < maxgroups)
{
for (i = ngroups; i > 0; i--)
- group_array[i] = group_array[i - 1];
+ group_array[i] = group_array[i - 1];
group_array[0] = current_user.gid;
ngroups++;
}
if (group_array[0] != current_user.gid)
{
for (i = 0; i < ngroups; i++)
- if (group_array[i] == current_user.gid)
- break;
+ if (group_array[i] == current_user.gid)
+ break;
if (i < ngroups)
{
group_array[i] = group_array[0];
{
static char **group_vector = (char **)NULL;
register int i;
- char *nbuf;
if (group_vector)
{
return (char **)NULL;
}
- group_vector = (char **)xmalloc (ngroups * sizeof (char *));
+ group_vector = strvec_create (ngroups);
for (i = 0; i < ngroups; i++)
+ group_vector[i] = itos (group_array[i]);
+
+ if (ngp)
+ *ngp = ngroups;
+ return group_vector;
+}
+
+int *
+get_group_array (ngp)
+ int *ngp;
+{
+ int i;
+ static int *group_iarray = (int *)NULL;
+
+ if (group_iarray)
+ {
+ if (ngp)
+ *ngp = ngroups;
+ return (group_iarray);
+ }
+
+ if (ngroups == 0)
+ initialize_group_array ();
+
+ if (ngroups <= 0)
{
- nbuf = itos ((int)group_array[i]);
- group_vector[i] = nbuf;
+ if (ngp)
+ *ngp = 0;
+ return (int *)NULL;
}
+
+ group_iarray = (int *)xmalloc (ngroups * sizeof (int));
+ for (i = 0; i < ngroups; i++)
+ group_iarray[i] = (int)group_array[i];
+
if (ngp)
*ngp = ngroups;
- return group_vector;
+ return group_iarray;
}