X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=general.c;h=3384e84b9edfb6b38fae02fa48c275d9f51cbbe3;hb=95732b497d12c98613bb3c5db16b61f377501a59;hp=5b978dcf82fc565fc9fd03795c53d53045850541;hpb=b72432fdcc59300c6fe7c9d6c8a31ad3447933f5;p=platform%2Fupstream%2Fbash.git diff --git a/general.c b/general.c index 5b978dc..3384e84 100644 --- a/general.c +++ b/general.c @@ -1,7 +1,6 @@ /* 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. @@ -17,7 +16,7 @@ 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" @@ -34,47 +33,51 @@ #include "filecntl.h" #include "bashansi.h" #include -#include +#include "chartypes.h" #include -#include "shell.h" -#include +#include "bashintl.h" -#if defined (TIME_WITH_SYS_TIME) -# include -# include -#else -# if defined (HAVE_SYS_TIME_H) -# include -# else -# include -# endif -#endif +#include "shell.h" +#include "test.h" -#include -#include "maxpath.h" +#include #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; + } } /* **************************************************************** */ @@ -100,8 +103,8 @@ string_to_rlimtype (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); } @@ -110,120 +113,29 @@ print_rlimtype (n, addnl) 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; - } - - 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" : ""); -} -#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; + do + *--p = '0' - n % 10; + while ((n /= 10) != 0); - *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; - - /* Sanity check */ - if (*sfp >= 1000) - { - *sp += 1; - *sfp -= 1000; + *--p = '-'; } -} - -/* 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; - - /* Sanity check */ - if (*sfp >= 1000) + else { - *sp += 1; - *sfp -= 1000; + do + *--p = '0' + n % 10; + while ((n /= 10) != 0); } -} - -/* 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); + printf ("%s%s", p, addnl ? "\n" : ""); } -#endif /* HAVE_TIMES */ +#endif /* RLIMTYPE */ /* **************************************************************** */ /* */ @@ -236,31 +148,37 @@ int 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. */ @@ -285,14 +203,15 @@ legal_identifier (name) 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); } @@ -309,18 +228,86 @@ check_identifier (word, check_word) { 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 */ @@ -338,27 +325,42 @@ check_identifier (word, check_word) #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 @@ -434,8 +436,8 @@ move_to_high_fd (fd, check_new, maxfd) 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; @@ -444,13 +446,15 @@ move_to_high_fd (fd, check_new, 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); } @@ -459,27 +463,21 @@ move_to_high_fd (fd, check_new, maxfd) 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); } @@ -488,179 +486,63 @@ check_binary_file (sample, sample_len) /* **************************************************************** */ /* */ -/* 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 the result starts with `//', but the original path does not, we - can turn the // into /. */ - if ((result[0] == '/' && result[1] == '/' && result[2] != '/') && - (path[0] != '/' || path[1] != '/' || path[2] == '/')) - { - char *r2; - if (result[2] == '\0') /* short-circuit for bare `//' */ - result[1] = '\0'; - else - { - r2 = savestring (result + 1); - free (result); - result = r2; - } - } + 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 @@ -670,75 +552,38 @@ make_absolute (string, dot_path) 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, '/'); @@ -753,37 +598,17 @@ char * 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; - - /* 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); - if (current_dir[0] == '/' && dlen > 1) - current_dir[dlen++] = '/'; - - /* Turn /foo/./bar into /foo/bar. */ - if (file[0] == '.' && file[1] == '/') - file += 2; + ret = sh_makepath ((char *)NULL, file, (MP_DOCWD|MP_RMDOT)); + free (file); - strcpy (current_dir + dlen, file); - free (disposer); - return (current_dir); + return (ret); } /* A slightly related function. Get the prettiest name of this @@ -850,16 +675,11 @@ extract_colon_unit (string, p_index) 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); } @@ -874,6 +694,11 @@ extract_colon_unit (string, p_index) 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 ~+. @@ -892,7 +717,7 @@ bash_special_tilde_expansions (text) 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 @@ -908,35 +733,126 @@ tilde_initialize () 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; +{ + 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, 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); } @@ -956,20 +872,6 @@ static GETGROUPS_T *group_array = (GETGROUPS_T *)NULL; # 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 () { @@ -1001,7 +903,7 @@ 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++; } @@ -1012,8 +914,8 @@ initialize_group_array () 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]; @@ -1062,7 +964,6 @@ get_group_list (ngp) { static char **group_vector = (char **)NULL; register int i; - char *nbuf; if (group_vector) { @@ -1081,12 +982,9 @@ get_group_list (ngp) return (char **)NULL; } - group_vector = (char **)xmalloc (ngroups * sizeof (char *)); + 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;