mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-06-26 07:13:10 +02:00
commit bash-20161118 snapshot
This commit is contained in:
@@ -12389,3 +12389,72 @@ lib/readline/display.c
|
||||
calls to mbrlen and mbrtowc
|
||||
- rl_redisplay: if in a UTF-8 locale, take advantage of that to avoid
|
||||
calls to mbrtowc
|
||||
|
||||
11/17
|
||||
-----
|
||||
lib/readline/histlib.h
|
||||
- PATTERN_SEARCH: new flag for history search interfaces, means to
|
||||
search for a pattern as Posix specifies
|
||||
|
||||
lib/readline/histsearch.c
|
||||
- history_search_internal: now takes a `flags' argument instead of just
|
||||
an `anchored' argument to accommodate PATTERN_SEARCH
|
||||
- _hs_history_patsearch: new internal interface to use when flags
|
||||
specify PATTERN_SEARCH
|
||||
|
||||
lib/readline/rlprivate.h
|
||||
- SF_PATTERN: new flag for non-incremental search contexts, means to
|
||||
treat search string as a pattern (maps to PATTERN_SEARCH)
|
||||
|
||||
lib/readline/search.c
|
||||
- noninc_dosearch: takes an additional `flags' argument for SF_PATTERN
|
||||
- noninc_search_from_pos: takes an additional `flags' argument for
|
||||
SF_PATTERN
|
||||
- noninc_dosearch: pass flags argument through to noninc_search_from_pos
|
||||
- _rl_nsearch_init: if we are in vi command mode, and `pchar' (key used
|
||||
to invoke the search) is `?' or `/', add SF_PATTERN to the flags
|
||||
to conform to Posix spec for vi-mode editing
|
||||
- _rl_nsearch_dosearch: if cxt->sflags indicates that we should do a
|
||||
pattern search, pass SF_PATTERN to noninc_search_from_pos
|
||||
- rl_noninc_forward_search_again: if in vi command mode and key == `N',
|
||||
make sure flags arg passed to noninc_dosearch includes SF_PATTERN
|
||||
- rl_noninc_reverse_search_again: if in vi command mode and key == `n',
|
||||
make sure flags arg passed to noninc_dosearch includes SF_PATTERN
|
||||
- rl_history_search_internal: pass extra flags arg to noninc_search_from_pos
|
||||
|
||||
11/18
|
||||
-----
|
||||
lib/readline/search.c
|
||||
- noninc_search_from_pos: takes a new argument, a pointer to int where
|
||||
it stores the offset of the match in the history line (if non-NULL),
|
||||
modified callers
|
||||
- rl_history_search_internal: pass newcol pointer to
|
||||
noninc_search_from_pos to avoid having to recompute the match offset
|
||||
in the matching history entry
|
||||
|
||||
config.h.in
|
||||
- define HAVE_FNMATCH if we have the fnmatch function (configure was
|
||||
already checking for it)
|
||||
|
||||
lib/readline/histsearch.c
|
||||
- _hs_history_patsearch: transform the pattern into one ending in a
|
||||
`*' to avoid having to perform multiple match attempts from each
|
||||
index in the history line
|
||||
- history_search_internal: changes to handle pattern matching if
|
||||
PATTERN_SEARCH is in the flags and HAVE_FNMATCH is defined. This
|
||||
makes vi-mode history searching treat the user-specified search
|
||||
string as an fnmatch pattern, as Posix requires. Fixes issue
|
||||
reported by <jwdevel@gmail.com>
|
||||
|
||||
11/19
|
||||
-----
|
||||
builtins/shopt.def
|
||||
- shopt_enable_hostname_completion: only declare this if READLINE
|
||||
defined, since that's the only time it's used. Reported by
|
||||
isabella parakiss <izaberina@gmail.com>
|
||||
|
||||
11/20
|
||||
-----
|
||||
builtins/common.c
|
||||
- display_signal_list: make `kill -l 0' print `EXIT', modifying change
|
||||
from 9/17
|
||||
|
||||
@@ -631,6 +631,7 @@ support/mkversion.sh f 755
|
||||
support/mksignames.c f
|
||||
support/signames.c f
|
||||
support/bashbug.sh f
|
||||
support/bashbug.sh.in f
|
||||
support/man2html.c f
|
||||
support/recho.c f
|
||||
support/zecho.c f
|
||||
|
||||
+2
-2
@@ -767,7 +767,7 @@ display_signal_list (list, forcecols)
|
||||
mapped into signal numbers. */
|
||||
if (lsignum > 128)
|
||||
lsignum -= 128;
|
||||
if (lsignum <= 0 || lsignum >= NSIG)
|
||||
if (lsignum < 0 || lsignum >= NSIG)
|
||||
{
|
||||
sh_invalidsig (list->word->word);
|
||||
result = EXECUTION_FAILURE;
|
||||
@@ -784,7 +784,7 @@ display_signal_list (list, forcecols)
|
||||
}
|
||||
/* POSIX.2 says that `kill -l signum' prints the signal name without
|
||||
the `SIG' prefix. */
|
||||
printf ("%s\n", (this_shell_builtin == kill_builtin) ? name + 3 : name);
|
||||
printf ("%s\n", (this_shell_builtin == kill_builtin && signum > 0) ? name + 3 : name);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+3
-1
@@ -121,7 +121,6 @@ extern int debugging_mode;
|
||||
static void shopt_error __P((char *));
|
||||
|
||||
static int set_shellopts_after_change __P((char *, int));
|
||||
static int shopt_enable_hostname_completion __P((char *, int));
|
||||
static int set_compatibility_level __P((char *, int));
|
||||
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
@@ -129,6 +128,7 @@ static int set_restricted_shell __P((char *, int));
|
||||
#endif
|
||||
|
||||
#if defined (READLINE)
|
||||
static int shopt_enable_hostname_completion __P((char *, int));
|
||||
static int shopt_set_complete_direxpand __P((char *, int));
|
||||
#endif
|
||||
|
||||
@@ -576,6 +576,7 @@ shopt_set_debug_mode (option_name, mode)
|
||||
return (0);
|
||||
}
|
||||
|
||||
#if defined (READLINE)
|
||||
static int
|
||||
shopt_enable_hostname_completion (option_name, mode)
|
||||
char *option_name;
|
||||
@@ -583,6 +584,7 @@ shopt_enable_hostname_completion (option_name, mode)
|
||||
{
|
||||
return (enable_hostname_completion (mode));
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
set_compatibility_level (option_name, mode)
|
||||
|
||||
@@ -608,6 +608,9 @@
|
||||
/* Define if you have the fcntl function. */
|
||||
#undef HAVE_FCNTL
|
||||
|
||||
/* Define if you have the fnmatch function. */
|
||||
#undef HAVE_FNMATCH
|
||||
|
||||
/* Define if you have the fpurge/__fpurge function. */
|
||||
#undef HAVE_FPURGE
|
||||
#undef HAVE___FPURGE
|
||||
|
||||
@@ -69,11 +69,17 @@ extern char *strchr ();
|
||||
#define NO_PREV_SUBST 4
|
||||
|
||||
/* Possible definitions for history starting point specification. */
|
||||
#define ANCHORED_SEARCH 1
|
||||
#define NON_ANCHORED_SEARCH 0
|
||||
#define NON_ANCHORED_SEARCH 0
|
||||
#define ANCHORED_SEARCH 0x01
|
||||
#define PATTERN_SEARCH 0x02
|
||||
|
||||
/* Possible definitions for what style of writing the history file we want. */
|
||||
#define HISTORY_APPEND 0
|
||||
#define HISTORY_OVERWRITE 1
|
||||
|
||||
/* internal extern function declarations used by other parts of the library */
|
||||
|
||||
/* histsearch.c */
|
||||
extern int _hs_history_patsearch PARAMS((const char *, int, int));
|
||||
|
||||
#endif /* !_HISTLIB_H_ */
|
||||
|
||||
@@ -39,8 +39,13 @@
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_FNMATCH)
|
||||
# include <fnmatch.h>
|
||||
#endif
|
||||
|
||||
#include "history.h"
|
||||
#include "histlib.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
/* The list of alternate characters that can delimit a history search
|
||||
string. */
|
||||
@@ -59,18 +64,24 @@ static int history_search_internal PARAMS((const char *, int, int));
|
||||
returned. */
|
||||
|
||||
static int
|
||||
history_search_internal (string, direction, anchored)
|
||||
history_search_internal (string, direction, flags)
|
||||
const char *string;
|
||||
int direction, anchored;
|
||||
int direction, flags;
|
||||
{
|
||||
register int i, reverse;
|
||||
register char *line;
|
||||
register int line_index;
|
||||
int string_len;
|
||||
int string_len, anchored, patsearch;
|
||||
HIST_ENTRY **the_history; /* local */
|
||||
|
||||
i = history_offset;
|
||||
reverse = (direction < 0);
|
||||
anchored = (flags & ANCHORED_SEARCH);
|
||||
#if defined (HAVE_FNMATCH)
|
||||
patsearch = (flags & PATTERN_SEARCH);
|
||||
#else
|
||||
patsearch = 0;
|
||||
#endif
|
||||
|
||||
/* Take care of trivial cases first. */
|
||||
if (string == 0 || *string == '\0')
|
||||
@@ -98,7 +109,7 @@ history_search_internal (string, direction, anchored)
|
||||
line_index = strlen (line);
|
||||
|
||||
/* If STRING is longer than line, no match. */
|
||||
if (string_len > line_index)
|
||||
if (patsearch == 0 && (string_len > line_index))
|
||||
{
|
||||
NEXT_LINE ();
|
||||
continue;
|
||||
@@ -107,6 +118,17 @@ history_search_internal (string, direction, anchored)
|
||||
/* Handle anchored searches first. */
|
||||
if (anchored == ANCHORED_SEARCH)
|
||||
{
|
||||
#if defined (HAVE_FNMATCH)
|
||||
if (patsearch)
|
||||
{
|
||||
if (fnmatch (string, line, 0) == 0)
|
||||
{
|
||||
history_offset = i;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (STREQN (string, line, string_len))
|
||||
{
|
||||
history_offset = i;
|
||||
@@ -120,10 +142,21 @@ history_search_internal (string, direction, anchored)
|
||||
/* Do substring search. */
|
||||
if (reverse)
|
||||
{
|
||||
line_index -= string_len;
|
||||
line_index -= (patsearch == 0) ? string_len : 1;
|
||||
|
||||
while (line_index >= 0)
|
||||
{
|
||||
#if defined (HAVE_FNMATCH)
|
||||
if (patsearch)
|
||||
{
|
||||
if (fnmatch (string, line + line_index, 0) == 0)
|
||||
{
|
||||
history_offset = i;
|
||||
return (line_index);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (STREQN (string, line + line_index, string_len))
|
||||
{
|
||||
history_offset = i;
|
||||
@@ -141,6 +174,17 @@ history_search_internal (string, direction, anchored)
|
||||
|
||||
while (line_index < limit)
|
||||
{
|
||||
#if defined (HAVE_FNMATCH)
|
||||
if (patsearch)
|
||||
{
|
||||
if (fnmatch (string, line + line_index, 0) == 0)
|
||||
{
|
||||
history_offset = i;
|
||||
return (line_index);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (STREQN (string, line + line_index, string_len))
|
||||
{
|
||||
history_offset = i;
|
||||
@@ -153,6 +197,51 @@ history_search_internal (string, direction, anchored)
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
_hs_history_patsearch (string, direction, flags)
|
||||
const char *string;
|
||||
int direction, flags;
|
||||
{
|
||||
char *pat;
|
||||
size_t len;
|
||||
int ret, unescaped_backslash;
|
||||
|
||||
#if defined (HAVE_FNMATCH)
|
||||
/* Assume that the string passed does not have a leading `^' and any
|
||||
anchored search request is captured in FLAGS */
|
||||
len = strlen (string);
|
||||
ret = len - 1;
|
||||
/* fnmatch is required to reject a pattern that ends with an unescaped
|
||||
backslash */
|
||||
if (unescaped_backslash = (string[ret] == '\\'))
|
||||
{
|
||||
while (ret > 0 && string[--ret] == '\\')
|
||||
unescaped_backslash = 1 - unescaped_backslash;
|
||||
}
|
||||
if (unescaped_backslash)
|
||||
return -1;
|
||||
pat = (char *)xmalloc (len + 2);
|
||||
/* Attempt to reduce the number of searches by tacking a `*' onto the end
|
||||
of a pattern that doesn't have one. Assume a pattern that ends in a
|
||||
backslash contains an even number of trailing backslashes; we check
|
||||
above */
|
||||
strcpy (pat, string);
|
||||
if (pat[len - 1] != '*')
|
||||
{
|
||||
pat[len] = '*'; /* XXX */
|
||||
pat[len+1] = '\0';
|
||||
}
|
||||
#else
|
||||
pat = string;
|
||||
#endif
|
||||
|
||||
ret = history_search_internal (pat, direction, flags|PATTERN_SEARCH);
|
||||
|
||||
if (pat != string)
|
||||
free (pat);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Do a non-anchored search for STRING through the history in DIRECTION. */
|
||||
int
|
||||
history_search (string, direction)
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
#define SF_FOUND 0x02
|
||||
#define SF_FAILED 0x04
|
||||
#define SF_CHGKMAP 0x08
|
||||
#define SF_PATTERN 0x10 /* unused so far */
|
||||
|
||||
typedef struct __rl_search_context
|
||||
{
|
||||
|
||||
+57
-17
@@ -1,6 +1,6 @@
|
||||
/* search.c - code for non-incremental searching in emacs and vi modes. */
|
||||
|
||||
/* Copyright (C) 1992-2015 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1992-2016 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the GNU Readline Library (Readline), a library
|
||||
for reading lines of text with interactive input and history editing.
|
||||
@@ -73,8 +73,8 @@ static char *history_search_string;
|
||||
static int history_string_size;
|
||||
|
||||
static void make_history_line_current PARAMS((HIST_ENTRY *));
|
||||
static int noninc_search_from_pos PARAMS((char *, int, int));
|
||||
static int noninc_dosearch PARAMS((char *, int));
|
||||
static int noninc_search_from_pos PARAMS((char *, int, int, int, int *));
|
||||
static int noninc_dosearch PARAMS((char *, int, int));
|
||||
static int noninc_search PARAMS((int, int));
|
||||
static int rl_history_search_internal PARAMS((int, int));
|
||||
static void rl_history_search_reinit PARAMS((int));
|
||||
@@ -112,11 +112,13 @@ make_history_line_current (entry)
|
||||
for STRING. DIR < 0 means to search backwards through the history list,
|
||||
DIR >= 0 means to search forward. */
|
||||
static int
|
||||
noninc_search_from_pos (string, pos, dir)
|
||||
noninc_search_from_pos (string, pos, dir, flags, ncp)
|
||||
char *string;
|
||||
int pos, dir;
|
||||
int pos, dir, flags;
|
||||
int *ncp;
|
||||
{
|
||||
int ret, old;
|
||||
int ret, old, sflags;
|
||||
char *s;
|
||||
|
||||
if (pos < 0)
|
||||
return -1;
|
||||
@@ -126,12 +128,28 @@ noninc_search_from_pos (string, pos, dir)
|
||||
return -1;
|
||||
|
||||
RL_SETSTATE(RL_STATE_SEARCH);
|
||||
if (*string == '^')
|
||||
/* These functions return the match offset in the line; history_offset gives
|
||||
the matching line in the history list */
|
||||
if (flags & SF_PATTERN)
|
||||
{
|
||||
s = string;
|
||||
sflags = 0; /* Non-anchored search */
|
||||
if (*s == '^')
|
||||
{
|
||||
sflags |= ANCHORED_SEARCH;
|
||||
s++;
|
||||
}
|
||||
ret = _hs_history_patsearch (string, dir, sflags);
|
||||
}
|
||||
else if (*string == '^')
|
||||
ret = history_search_prefix (string + 1, dir);
|
||||
else
|
||||
ret = history_search (string, dir);
|
||||
RL_UNSETSTATE(RL_STATE_SEARCH);
|
||||
|
||||
if (ncp)
|
||||
*ncp = ret; /* caller will catch -1 to indicate no-op */
|
||||
|
||||
if (ret != -1)
|
||||
ret = where_history ();
|
||||
|
||||
@@ -143,9 +161,10 @@ noninc_search_from_pos (string, pos, dir)
|
||||
search is backwards through previous entries, else through subsequent
|
||||
entries. Returns 1 if the search was successful, 0 otherwise. */
|
||||
static int
|
||||
noninc_dosearch (string, dir)
|
||||
noninc_dosearch (string, dir, flags)
|
||||
char *string;
|
||||
int dir;
|
||||
int flags;
|
||||
{
|
||||
int oldpos, pos;
|
||||
HIST_ENTRY *entry;
|
||||
@@ -156,7 +175,7 @@ noninc_dosearch (string, dir)
|
||||
return 0;
|
||||
}
|
||||
|
||||
pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir);
|
||||
pos = noninc_search_from_pos (string, noninc_history_pos + dir, dir, flags, (int *)0);
|
||||
if (pos == -1)
|
||||
{
|
||||
/* Search failed, current history position unchanged. */
|
||||
@@ -197,6 +216,10 @@ _rl_nsearch_init (dir, pchar)
|
||||
cxt = _rl_scxt_alloc (RL_SEARCH_NSEARCH, 0);
|
||||
if (dir < 0)
|
||||
cxt->sflags |= SF_REVERSE; /* not strictly needed */
|
||||
#if defined (VI_MODE)
|
||||
if (VI_COMMAND_MODE() && (pchar == '?' || pchar == '/'))
|
||||
cxt->sflags |= SF_PATTERN;
|
||||
#endif
|
||||
|
||||
cxt->direction = dir;
|
||||
cxt->history_pos = cxt->save_line;
|
||||
@@ -340,7 +363,7 @@ _rl_nsearch_dosearch (cxt)
|
||||
}
|
||||
|
||||
rl_restore_prompt ();
|
||||
return (noninc_dosearch (noninc_search_string, cxt->direction));
|
||||
return (noninc_dosearch (noninc_search_string, cxt->direction, cxt->sflags&SF_PATTERN));
|
||||
}
|
||||
|
||||
/* Search non-interactively through the history list. DIR < 0 means to
|
||||
@@ -400,7 +423,8 @@ rl_noninc_reverse_search (count, key)
|
||||
}
|
||||
|
||||
/* Search forward through the history list for the last string searched
|
||||
for. If there is no saved search string, abort. */
|
||||
for. If there is no saved search string, abort. If the vi-mode code
|
||||
calls this, KEY will be `N'. */
|
||||
int
|
||||
rl_noninc_forward_search_again (count, key)
|
||||
int count, key;
|
||||
@@ -412,12 +436,18 @@ rl_noninc_forward_search_again (count, key)
|
||||
rl_ding ();
|
||||
return (1);
|
||||
}
|
||||
r = noninc_dosearch (noninc_search_string, 1);
|
||||
#if defined (VI_MODE)
|
||||
if (VI_COMMAND_MODE() && key == 'N')
|
||||
r = noninc_dosearch (noninc_search_string, 1, SF_PATTERN);
|
||||
else
|
||||
#endif
|
||||
r = noninc_dosearch (noninc_search_string, 1, 0);
|
||||
return (r != 1);
|
||||
}
|
||||
|
||||
/* Reverse search in the history list for the last string searched
|
||||
for. If there is no saved search string, abort. */
|
||||
for. If there is no saved search string, abort. If the vi-mode code
|
||||
calls this, KEY will be `n'. */
|
||||
int
|
||||
rl_noninc_reverse_search_again (count, key)
|
||||
int count, key;
|
||||
@@ -429,7 +459,12 @@ rl_noninc_reverse_search_again (count, key)
|
||||
rl_ding ();
|
||||
return (1);
|
||||
}
|
||||
r = noninc_dosearch (noninc_search_string, -1);
|
||||
#if defined (VI_MODE)
|
||||
if (VI_COMMAND_MODE() && key == 'n')
|
||||
r = noninc_dosearch (noninc_search_string, -1, SF_PATTERN);
|
||||
else
|
||||
#endif
|
||||
r = noninc_dosearch (noninc_search_string, -1, 0);
|
||||
return (r != 1);
|
||||
}
|
||||
|
||||
@@ -455,7 +490,7 @@ rl_history_search_internal (count, dir)
|
||||
int count, dir;
|
||||
{
|
||||
HIST_ENTRY *temp;
|
||||
int ret, oldpos;
|
||||
int ret, oldpos, newcol;
|
||||
char *t;
|
||||
|
||||
rl_maybe_save_line ();
|
||||
@@ -469,7 +504,7 @@ rl_history_search_internal (count, dir)
|
||||
while (count)
|
||||
{
|
||||
RL_CHECK_SIGNALS ();
|
||||
ret = noninc_search_from_pos (history_search_string, rl_history_search_pos + dir, dir);
|
||||
ret = noninc_search_from_pos (history_search_string, rl_history_search_pos + dir, dir, 0, &newcol);
|
||||
if (ret == -1)
|
||||
break;
|
||||
|
||||
@@ -512,12 +547,17 @@ rl_history_search_internal (count, dir)
|
||||
/* Copy the line we found into the current line buffer. */
|
||||
make_history_line_current (temp);
|
||||
|
||||
/* decide where to put rl_point -- need to change this for pattern search */
|
||||
if (rl_history_search_flags & ANCHORED_SEARCH)
|
||||
rl_point = rl_history_search_len; /* easy case */
|
||||
else
|
||||
{
|
||||
t = strstr (rl_line_buffer, history_search_string);
|
||||
#if 0
|
||||
t = strstr (rl_line_buffer, history_search_string); /* XXX */
|
||||
rl_point = t ? (int)(t - rl_line_buffer) + rl_history_search_len : rl_end;
|
||||
#else
|
||||
rl_point = (newcol >= 0) ? newcol : rl_end;
|
||||
#endif
|
||||
}
|
||||
rl_mark = rl_end;
|
||||
|
||||
|
||||
@@ -2977,9 +2977,9 @@ special_case_tokens (tokstr)
|
||||
the designers disagree. */
|
||||
if (esacs_needed_count)
|
||||
{
|
||||
esacs_needed_count--;
|
||||
if (STREQ (tokstr, "esac"))
|
||||
if (last_read_token == IN && STREQ (tokstr, "esac"))
|
||||
{
|
||||
esacs_needed_count--;
|
||||
parser_state &= ~PST_CASEPAT;
|
||||
return (ESAC);
|
||||
}
|
||||
|
||||
+1
-1
@@ -1243,7 +1243,7 @@ gen_command_matches (cs, cmd, text, line, ind, lwords, nw, cw)
|
||||
}
|
||||
cscmd[cmdlen] = '\0';
|
||||
|
||||
tw = command_substitute (cscmd, 0);
|
||||
tw = command_substitute (cscmd, 0, 0);
|
||||
csbuf = tw ? tw->word : (char *)NULL;
|
||||
if (tw)
|
||||
dispose_word_desc (tw);
|
||||
|
||||
@@ -3715,7 +3715,14 @@ expand_string_assignment (string, quoted)
|
||||
|
||||
expand_no_split_dollar_star = 1;
|
||||
|
||||
#if 0
|
||||
/* Other shells (ksh93) do it this way, affects how $@ is expanded in
|
||||
constructs like bar=${@#0} (preserves the spaces resulting from the
|
||||
expansion of $@ in a context where you don't do word splitting) */
|
||||
td.flags = W_ASSIGNRHS|W_NOSPLIT2;
|
||||
#else
|
||||
td.flags = W_ASSIGNRHS;
|
||||
#endif
|
||||
td.word = savestring (string);
|
||||
value = call_expand_word_internal (&td, quoted, 0, (int *)NULL, (int *)NULL);
|
||||
FREE (td.word);
|
||||
@@ -6004,8 +6011,13 @@ read_comsub (fd, quoted, rflag)
|
||||
istring = (char *)NULL;
|
||||
istring_index = istring_size = bufn = tflag = 0;
|
||||
|
||||
#if 0
|
||||
for (skip_ctlesc = skip_ctlnul = 0, s = ifs_value; s && *s; s++)
|
||||
skip_ctlesc |= *s == CTLESC, skip_ctlnul |= *s == CTLNUL;
|
||||
#else
|
||||
skip_ctlesc = ifs_cmap[CTLESC];
|
||||
skip_ctlnul = ifs_cmap[CTLNUL];
|
||||
#endif
|
||||
|
||||
nullbyte = 0;
|
||||
|
||||
@@ -6108,9 +6120,10 @@ read_comsub (fd, quoted, rflag)
|
||||
/* Perform command substitution on STRING. This returns a WORD_DESC * with the
|
||||
contained string possibly quoted. */
|
||||
WORD_DESC *
|
||||
command_substitute (string, quoted)
|
||||
command_substitute (string, quoted, flags)
|
||||
char *string;
|
||||
int quoted;
|
||||
int flags;
|
||||
{
|
||||
pid_t pid, old_pid, old_pipeline_pgrp, old_async_pid;
|
||||
char *istring, *s;
|
||||
@@ -8925,7 +8938,7 @@ comsub:
|
||||
temp1 = substring (string, *sindex, zindex+1);
|
||||
else
|
||||
{
|
||||
tdesc = command_substitute (temp, quoted);
|
||||
tdesc = command_substitute (temp, quoted, pflags&PF_ASSIGNRHS);
|
||||
temp1 = tdesc ? tdesc->word : (char *)NULL;
|
||||
if (tdesc)
|
||||
dispose_word_desc (tdesc);
|
||||
@@ -9459,7 +9472,7 @@ add_string:
|
||||
else
|
||||
{
|
||||
de_backslash (temp);
|
||||
tword = command_substitute (temp, quoted);
|
||||
tword = command_substitute (temp, quoted, 0);
|
||||
temp1 = tword ? tword->word : (char *)NULL;
|
||||
if (tword)
|
||||
dispose_word_desc (tword);
|
||||
|
||||
@@ -258,7 +258,7 @@ extern WORD_LIST *expand_words_no_vars __P((WORD_LIST *));
|
||||
command substitution, arithmetic expansion, and word splitting. */
|
||||
extern WORD_LIST *expand_words_shellexp __P((WORD_LIST *));
|
||||
|
||||
extern WORD_DESC *command_substitute __P((char *, int));
|
||||
extern WORD_DESC *command_substitute __P((char *, int, int));
|
||||
extern char *pat_subst __P((char *, char *, char *, int));
|
||||
|
||||
extern int fifos_pending __P((void));
|
||||
|
||||
@@ -0,0 +1,272 @@
|
||||
#!/bin/sh -
|
||||
#
|
||||
# bashbug - create a bug report and mail it to the bug address
|
||||
#
|
||||
# The bug address depends on the release status of the shell. Versions
|
||||
# with status `devel', `alpha', `beta', or `rc' mail bug reports to
|
||||
# chet@cwru.edu and, optionally, to bash-testers@cwru.edu.
|
||||
# Other versions send mail to bug-bash@gnu.org.
|
||||
#
|
||||
# Copyright (C) 1996-2004 Free Software Foundation, Inc.
|
||||
#
|
||||
# This program 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.
|
||||
#
|
||||
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
#
|
||||
# configuration section:
|
||||
# these variables are filled in by the make target in Makefile
|
||||
#
|
||||
MACHINE="@host_cpu@"
|
||||
OS="@host_os@"
|
||||
CC="@CC@"
|
||||
CFLAGS="@CFLAGS@"
|
||||
RELEASE="@BASHVERS@"
|
||||
PATCHLEVEL="!PATCHLEVEL!"
|
||||
RELSTATUS="@RELSTATUS@"
|
||||
MACHTYPE="@host@"
|
||||
|
||||
PATH=/bin:/usr/bin:/usr/local/bin:$PATH
|
||||
export PATH
|
||||
|
||||
# Check if TMPDIR is set, default to /tmp
|
||||
: ${TMPDIR:=/tmp}
|
||||
|
||||
#Securely create a temporary directory for the temporary files
|
||||
TEMPDIR=$TMPDIR/bbug.$$
|
||||
(umask 077 && mkdir $TEMPDIR) || {
|
||||
echo "$0: could not create temporary directory" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
TEMPFILE1=$TEMPDIR/bbug1
|
||||
TEMPFILE2=$TEMPDIR/bbug2
|
||||
|
||||
USAGE="Usage: $0 [--help] [--version] [bug-report-email-address]"
|
||||
VERSTR="GNU bashbug, version ${RELEASE}.${PATCHLEVEL}-${RELSTATUS}"
|
||||
|
||||
do_help= do_version=
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--help) shift ; do_help=y ;;
|
||||
--version) shift ; do_version=y ;;
|
||||
--) shift ; break ;;
|
||||
-*) echo "bashbug: ${1}: invalid option" >&2
|
||||
echo "$USAGE" >&2
|
||||
exit 2 ;;
|
||||
*) break ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -n "$do_version" ]; then
|
||||
echo "${VERSTR}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -n "$do_help" ]; then
|
||||
echo "${VERSTR}"
|
||||
echo "${USAGE}"
|
||||
echo
|
||||
cat << HERE_EOF
|
||||
Bashbug is used to send mail to the Bash maintainers
|
||||
for when Bash doesn't behave like you'd like, or expect.
|
||||
|
||||
Bashbug will start up your editor (as defined by the shell's
|
||||
EDITOR environment variable) with a preformatted bug report
|
||||
template for you to fill in. The report will be mailed to the
|
||||
bug-bash mailing list by default. See the manual for details.
|
||||
|
||||
If you invoke bashbug by accident, just quit your editor without
|
||||
saving any changes to the template, and no bug report will be sent.
|
||||
HERE_EOF
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Figure out how to echo a string without a trailing newline
|
||||
N=`echo 'hi there\c'`
|
||||
case "$N" in
|
||||
*c) n=-n c= ;;
|
||||
*) n= c='\c' ;;
|
||||
esac
|
||||
|
||||
BASHTESTERS="bash-testers@cwru.edu"
|
||||
|
||||
case "$RELSTATUS" in
|
||||
alpha*|beta*|devel*|rc*) BUGBASH=chet@cwru.edu ;;
|
||||
*) BUGBASH=bug-bash@gnu.org ;;
|
||||
esac
|
||||
|
||||
case "$RELSTATUS" in
|
||||
alpha*|beta*|devel*|rc*)
|
||||
echo "$0: This is a testing release. Would you like your bug report"
|
||||
echo "$0: to be sent to the bash-testers mailing list?"
|
||||
echo $n "$0: Send to bash-testers? $c"
|
||||
read ans
|
||||
case "$ans" in
|
||||
y*|Y*) BUGBASH="${BUGBASH},${BASHTESTERS}" ;;
|
||||
esac ;;
|
||||
esac
|
||||
|
||||
BUGADDR="${1-$BUGBASH}"
|
||||
|
||||
if [ -z "$DEFEDITOR" ] && [ -z "$EDITOR" ]; then
|
||||
if [ -x /usr/bin/editor ]; then
|
||||
DEFEDITOR=editor
|
||||
elif [ -x /usr/local/bin/ce ]; then
|
||||
DEFEDITOR=ce
|
||||
elif [ -x /usr/local/bin/emacs ]; then
|
||||
DEFEDITOR=emacs
|
||||
elif [ -x /usr/contrib/bin/emacs ]; then
|
||||
DEFEDITOR=emacs
|
||||
elif [ -x /usr/bin/emacs ]; then
|
||||
DEFEDITOR=emacs
|
||||
elif [ -x /usr/bin/xemacs ]; then
|
||||
DEFEDITOR=xemacs
|
||||
elif [ -x /usr/contrib/bin/jove ]; then
|
||||
DEFEDITOR=jove
|
||||
elif [ -x /usr/local/bin/jove ]; then
|
||||
DEFEDITOR=jove
|
||||
elif [ -x /usr/bin/vi ]; then
|
||||
DEFEDITOR=vi
|
||||
else
|
||||
echo "$0: No default editor found: attempting to use vi" >&2
|
||||
DEFEDITOR=vi
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
: ${EDITOR=$DEFEDITOR}
|
||||
|
||||
: ${USER=${LOGNAME-`whoami`}}
|
||||
|
||||
trap 'rm -rf "$TEMPDIR"; exit 1' 1 2 3 13 15
|
||||
trap 'rm -rf "$TEMPDIR"' 0
|
||||
|
||||
UN=
|
||||
if (uname) >/dev/null 2>&1; then
|
||||
UN=`uname -a`
|
||||
fi
|
||||
|
||||
if [ -f /usr/lib/sendmail ] ; then
|
||||
RMAIL="/usr/lib/sendmail"
|
||||
SMARGS="-i -t"
|
||||
elif [ -f /usr/sbin/sendmail ] ; then
|
||||
RMAIL="/usr/sbin/sendmail"
|
||||
SMARGS="-i -t"
|
||||
else
|
||||
RMAIL=rmail
|
||||
SMARGS="$BUGADDR"
|
||||
fi
|
||||
|
||||
INITIAL_SUBJECT='[50 character or so descriptive subject here (for reference)]'
|
||||
|
||||
cat > "$TEMPFILE1" <<EOF
|
||||
From: ${USER}
|
||||
To: ${BUGADDR}
|
||||
Subject: ${INITIAL_SUBJECT}
|
||||
|
||||
Configuration Information [Automatically generated, do not change]:
|
||||
Machine: $MACHINE
|
||||
OS: $OS
|
||||
Compiler: $CC
|
||||
Compilation CFLAGS: $CFLAGS
|
||||
uname output: $UN
|
||||
Machine Type: $MACHTYPE
|
||||
|
||||
Bash Version: $RELEASE
|
||||
Patch Level: $PATCHLEVEL
|
||||
Release Status: $RELSTATUS
|
||||
|
||||
Description:
|
||||
[Detailed description of the problem, suggestion, or complaint.]
|
||||
|
||||
Repeat-By:
|
||||
[Describe the sequence of events that causes the problem
|
||||
to occur.]
|
||||
|
||||
Fix:
|
||||
[Description of how to fix the problem. If you don't know a
|
||||
fix for the problem, don't include this section.]
|
||||
EOF
|
||||
|
||||
cp "$TEMPFILE1" "$TEMPFILE2"
|
||||
chmod u+w "$TEMPFILE1"
|
||||
|
||||
trap '' 2 # ignore interrupts while in editor
|
||||
|
||||
edstat=1
|
||||
while [ $edstat -ne 0 ]; do
|
||||
$EDITOR "$TEMPFILE1"
|
||||
edstat=$?
|
||||
|
||||
if [ $edstat -ne 0 ]; then
|
||||
echo "$0: editor \`$EDITOR' exited with nonzero status."
|
||||
echo "$0: Perhaps it was interrupted."
|
||||
echo "$0: Type \`y' to give up, and lose your bug report;"
|
||||
echo "$0: type \`n' to re-enter the editor."
|
||||
echo $n "$0: Do you want to give up? $c"
|
||||
|
||||
read ans
|
||||
case "$ans" in
|
||||
[Yy]*) exit 1 ;;
|
||||
esac
|
||||
|
||||
continue
|
||||
fi
|
||||
|
||||
# find the subject from the temp file and see if it's been changed
|
||||
CURR_SUB=`grep '^Subject: ' "$TEMPFILE1" | sed 's|^Subject:[ ]*||' | sed 1q`
|
||||
|
||||
case "$CURR_SUB" in
|
||||
"${INITIAL_SUBJECT}")
|
||||
echo
|
||||
echo "$0: You have not changed the subject from the default."
|
||||
echo "$0: Please use a more descriptive subject header."
|
||||
echo "$0: Type \`y' to give up, and lose your bug report;"
|
||||
echo "$0: type \`n' to re-enter the editor."
|
||||
echo $n "$0: Do you want to give up? $c"
|
||||
|
||||
read ans
|
||||
case "$ans" in
|
||||
[Yy]*) exit 1 ;;
|
||||
esac
|
||||
|
||||
echo "$0: The editor will be restarted in five seconds."
|
||||
sleep 5
|
||||
edstat=1
|
||||
;;
|
||||
esac
|
||||
|
||||
done
|
||||
|
||||
trap 'rm -rf "$TEMPDIR"; exit 1' 2 # restore trap on SIGINT
|
||||
|
||||
if cmp -s "$TEMPFILE1" "$TEMPFILE2"
|
||||
then
|
||||
echo "File not changed, no bug report submitted."
|
||||
exit
|
||||
fi
|
||||
|
||||
echo $n "Send bug report to ${BUGADDR}? [y/n] $c"
|
||||
read ans
|
||||
case "$ans" in
|
||||
[Nn]*) exit 0 ;;
|
||||
esac
|
||||
|
||||
${RMAIL} $SMARGS < "$TEMPFILE1" || {
|
||||
cat "$TEMPFILE1" >> $HOME/dead.bashbug
|
||||
echo "$0: mail to ${BUGADDR} failed: report saved in $HOME/dead.bashbug" >&2
|
||||
echo "$0: please send it manually to ${BUGADDR}" >&2
|
||||
}
|
||||
|
||||
exit 0
|
||||
Reference in New Issue
Block a user