/* general.c -- Stuff that is used by all files. */
-/* Copyright (C) 1987-2009 Free Software Foundation, Inc.
+/* Copyright (C) 1987-2016 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
#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 "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 <tilde/tilde.h>
extern int errno;
#endif /* !errno */
-extern int expand_aliases;
-extern int interactive_comments;
-extern int check_hashed_filenames;
-extern int source_uses_path;
-extern int source_searches_cwd;
+#ifdef __CYGWIN__
+# include <sys/cygwin.h>
+#endif
static char *bash_special_tilde_expansions __P((char *));
static int unquoted_tilde_word __P((const char *));
/* A standard error message to use when getcwd() returns NULL. */
const char * const bash_getcwd_errstr = N_("getcwd: cannot access parent directories");
-/* Do whatever is necessary to initialize `Posix mode'. */
+/* 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
+};
+
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 */
/* 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 (DIGIT (*s) == 0)
if (result)
*result = 0;
+ if (string == 0)
+ return 0;
+
errno = 0;
value = strtoimax (string, &ep, 10);
if (errno || ep == string)
/* 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 || !(c = *name) || (legal_variable_starter (c) == 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,
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)
- char *string;
+ const char *string;
int flags;
{
- register char *s;
+ register const char *s;
for (s = string; *s; s++)
if (shellbreak (*s) || shellxquote (*s) || shellexp (*s) || (*s == '/'))
}
/* Returns non-zero if STRING is an assignment statement. The returned value
- is the index of the `=' sign. */
+ 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;
c = string[indx = 0];
#if defined (ARRAY_VARS)
- if ((legal_variable_starter (c) == 0) && (flags == 0 || c != '[')) /* ] */
+ if ((legal_variable_starter (c) == 0) && ((flags&1) == 0 || c != '[')) /* ] */
#else
if (legal_variable_starter (c) == 0)
#endif
#if defined (ARRAY_VARS)
if (c == '[')
{
- newi = skipsubscript (string, indx, 0);
+ 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 (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;
{
errno = 0;
- if (lseek ((fd), 0L, SEEK_CUR) < 0)
- return (errno == ESPIPE);
- return 0;
+ return ((lseek (fd, 0L, SEEK_CUR) < 0) && (errno == ESPIPE));
}
/* There is a bug in the NeXT 2.1 rlogind that causes opens
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;
int
check_binary_file (sample, sample_len)
- char *sample;
+ const char *sample;
int sample_len;
{
register int i;
int
file_exists (fn)
- char *fn;
+ const char *fn;
{
struct stat sb;
int
file_isdir (fn)
- char *fn;
+ const char *fn;
{
struct stat sb;
int
file_iswdir (fn)
- char *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
-dot_or_dotdot (string)
+path_dot_or_dotdot (string)
const char *string;
{
if (string == 0 || *string == '\0' || *string != '.')
begin with. */
char *
make_absolute (string, dot_path)
- char *string, *dot_path;
+ const char *string, *dot_path;
{
char *result;
{
char pathbuf[PATH_MAX + 1];
- cygwin_conv_to_full_posix_path (string, pathbuf);
+ /* 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
*nbeg++ = '.';
nlen = nend - ntail;
- memcpy (nbeg, ntail, nlen);
+ 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. */
int old_immed, old_term, r;
char *ret;
+#if 0
old_immed = interrupt_immediately;
old_term = terminate_immediately;
- interrupt_immediately = terminate_immediately = 1;
+ /* 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);
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);
}
*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);
+}
+
+