Imported from ../bash-2.04.tar.gz.
This commit is contained in:
parent
b72432fdcc
commit
bb70624e96
387 changed files with 28522 additions and 9334 deletions
384
parse.y
384
parse.y
|
@ -6,7 +6,7 @@
|
|||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
|
@ -16,7 +16,7 @@
|
|||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file LICENSE. 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"
|
||||
|
@ -100,6 +100,7 @@ extern Function *last_shell_builtin, *this_shell_builtin;
|
|||
extern int bash_input_fd_changed;
|
||||
#endif
|
||||
|
||||
extern int errno;
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* "Forward" declarations */
|
||||
|
@ -177,6 +178,9 @@ static int function_dstart;
|
|||
/* The line number in a script on which a function body starts. */
|
||||
static int function_bstart;
|
||||
|
||||
/* The line number in a script at which an arithmetic for command starts. */
|
||||
static int arith_for_lineno;
|
||||
|
||||
static REDIRECTEE redir;
|
||||
%}
|
||||
|
||||
|
@ -196,12 +200,12 @@ static REDIRECTEE redir;
|
|||
third group are recognized only under special circumstances. */
|
||||
%token IF THEN ELSE ELIF FI CASE ESAC FOR SELECT WHILE UNTIL DO DONE FUNCTION
|
||||
%token COND_START COND_END COND_ERROR
|
||||
%token IN BANG TIME TIMEOPT
|
||||
%token IN BANG TIME TIMEOPT
|
||||
|
||||
/* More general tokens. yylex () knows how to make these. */
|
||||
%token <word> WORD ASSIGNMENT_WORD
|
||||
%token <number> NUMBER
|
||||
%token <word_list> ARITH_CMD
|
||||
%token <word_list> ARITH_CMD ARITH_FOR_EXPRS
|
||||
%token <command> COND_CMD
|
||||
%token AND_AND OR_OR GREATER_GREATER LESS_LESS LESS_AND
|
||||
%token GREATER_AND SEMI_SEMI LESS_LESS_MINUS AND_GREATER LESS_GREATER
|
||||
|
@ -215,6 +219,7 @@ static REDIRECTEE redir;
|
|||
%type <command> for_command select_command case_command group_command
|
||||
%type <command> arith_command
|
||||
%type <command> cond_command
|
||||
%type <command> arith_for_command
|
||||
%type <command> function_def if_command elif_clause subshell
|
||||
%type <redirect> redirection redirection_list
|
||||
%type <element> simple_command_element
|
||||
|
@ -462,6 +467,14 @@ command: simple_command
|
|||
be attached to the function and performed when
|
||||
the function is executed, not as part of the
|
||||
function definition command. */
|
||||
/* XXX - I don't think it matters, but we might
|
||||
want to change this in the future to avoid
|
||||
problems differentiating between a function
|
||||
definition with a redirection and a function
|
||||
definition containing a single command with a
|
||||
redirection. The two are semantically equivalent,
|
||||
though -- the only difference is in how the
|
||||
command printing code displays the redirections. */
|
||||
if (tc->type == cm_function_def)
|
||||
{
|
||||
tc = tc->value.Function_def->command;
|
||||
|
@ -501,6 +514,8 @@ shell_command: for_command
|
|||
{ $$ = $1; }
|
||||
| cond_command
|
||||
{ $$ = $1; }
|
||||
| arith_for_command
|
||||
{ $$ = $1; }
|
||||
| function_def
|
||||
{ $$ = $1; }
|
||||
;
|
||||
|
@ -519,6 +534,11 @@ for_command: FOR WORD newline_list DO compound_list DONE
|
|||
{ $$ = make_for_command ($2, REVERSE_LIST ($5, WORD_LIST *), $9); }
|
||||
;
|
||||
|
||||
arith_for_command: FOR ARITH_FOR_EXPRS list_terminator newline_list DO compound_list DONE
|
||||
{ $$ = make_arith_for_command ($2, $6, arith_for_lineno); }
|
||||
| FOR ARITH_FOR_EXPRS list_terminator newline_list '{' compound_list '}'
|
||||
{ $$ = make_arith_for_command ($2, $6, arith_for_lineno); }
|
||||
;
|
||||
select_command: SELECT WORD newline_list DO list DONE
|
||||
{
|
||||
$$ = make_select_command ($2, add_string_to_list ("\"$@\"", (WORD_LIST *)NULL), $5);
|
||||
|
@ -565,7 +585,10 @@ function_def: WORD '(' ')' newline_list group_command
|
|||
;
|
||||
|
||||
subshell: '(' compound_list ')'
|
||||
{ $2->flags |= CMD_WANT_SUBSHELL; $$ = $2; }
|
||||
{
|
||||
$$ = make_subshell_command ($2);
|
||||
$$->flags |= CMD_WANT_SUBSHELL;
|
||||
}
|
||||
;
|
||||
|
||||
if_command: IF compound_list THEN compound_list FI
|
||||
|
@ -744,7 +767,7 @@ pipeline_command: pipeline
|
|||
}
|
||||
| timespec BANG pipeline
|
||||
{
|
||||
$3->flags |= $1;
|
||||
$3->flags |= $1|CMD_INVERT_RETURN;
|
||||
$$ = $3;
|
||||
}
|
||||
| BANG timespec pipeline
|
||||
|
@ -779,6 +802,7 @@ timespec: TIME
|
|||
#define PST_CASESTMT 0x080 /* parsing a case statement */
|
||||
#define PST_CONDCMD 0x100 /* parsing a [[...]] command */
|
||||
#define PST_CONDEXPR 0x200 /* parsing the guts of [[...]] */
|
||||
#define PST_ARITHFOR 0x400 /* parsing an arithmetic for command */
|
||||
|
||||
/* Initial size to allocate for tokens, and the
|
||||
amount to grow them by. */
|
||||
|
@ -1068,20 +1092,21 @@ with_input_from_string (string, name)
|
|||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* These two functions used to test the value of the HAVE_RESTARTABLE_SYSCALLS
|
||||
define, and just use getc/ungetc if it was defined, but since bash
|
||||
installs its signal handlers without the SA_RESTART flag, some signals
|
||||
(like SIGCHLD, SIGWINCH, etc.) received during a read(2) will not cause
|
||||
the read to be restarted. We need to restart it ourselves. */
|
||||
|
||||
static int
|
||||
yy_stream_get ()
|
||||
{
|
||||
int result = EOF;
|
||||
int result;
|
||||
|
||||
result = EOF;
|
||||
if (bash_input.location.file)
|
||||
{
|
||||
#if !defined (HAVE_RESTARTABLE_SYSCALLS)
|
||||
result = getc_with_restart (bash_input.location.file);
|
||||
#else /* HAVE_RESTARTABLE_SYSCALLS */
|
||||
result = getc (bash_input.location.file);
|
||||
result = (feof (bash_input.location.file)) ? EOF : (unsigned char)result;
|
||||
#endif /* HAVE_RESTARTABLE_SYSCALLS */
|
||||
}
|
||||
result = getc_with_restart (bash_input.location.file);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
|
@ -1089,11 +1114,7 @@ static int
|
|||
yy_stream_unget (c)
|
||||
int c;
|
||||
{
|
||||
#if !defined (HAVE_RESTARTABLE_SYSCALLS)
|
||||
return (ungetc_with_restart (c, bash_input.location.file));
|
||||
#else /* HAVE_RESTARTABLE_SYSCALLS */
|
||||
return (ungetc (c, bash_input.location.file));
|
||||
#endif /* HAVE_RESTARTABLE_SYSCALLS */
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1209,6 +1230,30 @@ stream_on_stack (type)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Save the current token state and return it in a malloced array. */
|
||||
int *
|
||||
save_token_state ()
|
||||
{
|
||||
int *ret;
|
||||
|
||||
ret = (int *)xmalloc (3 * sizeof (int));
|
||||
ret[0] = last_read_token;
|
||||
ret[1] = token_before_that;
|
||||
ret[2] = two_tokens_ago;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
restore_token_state (ts)
|
||||
int *ts;
|
||||
{
|
||||
if (ts == 0)
|
||||
return;
|
||||
last_read_token = ts[0];
|
||||
token_before_that = ts[1];
|
||||
two_tokens_ago = ts[2];
|
||||
}
|
||||
|
||||
/*
|
||||
* This is used to inhibit alias expansion and reserved word recognition
|
||||
* inside case statement pattern lists. A `case statement pattern list' is:
|
||||
|
@ -2204,8 +2249,36 @@ read_token (command)
|
|||
case '|':
|
||||
return (OR_OR);
|
||||
|
||||
#if defined (DPAREN_ARITHMETIC)
|
||||
#if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND)
|
||||
case '(': /* ) */
|
||||
# if defined (ARITH_FOR_COMMAND)
|
||||
if (last_read_token == FOR)
|
||||
{
|
||||
int cmdtyp, len;
|
||||
char *wval, *wv2;
|
||||
WORD_DESC *wd;
|
||||
|
||||
arith_for_lineno = line_number;
|
||||
cmdtyp = parse_arith_cmd (&wval);
|
||||
if (cmdtyp == 1)
|
||||
{
|
||||
/* parse_arith_cmd adds quotes at the beginning and end
|
||||
of the string it returns; we need to take those out. */
|
||||
len = strlen (wval);
|
||||
wv2 = xmalloc (len);
|
||||
strncpy (wv2, wval + 1, len - 2);
|
||||
wv2[len - 2] = '\0';
|
||||
wd = make_word (wv2);
|
||||
yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL);
|
||||
free (wval);
|
||||
free (wv2);
|
||||
return (ARITH_FOR_EXPRS);
|
||||
}
|
||||
else
|
||||
return -1; /* ERROR */
|
||||
}
|
||||
# endif
|
||||
# if defined (DPAREN_ARITHMETIC)
|
||||
if (reserved_word_acceptable (last_read_token))
|
||||
{
|
||||
int cmdtyp, sline;
|
||||
|
@ -2233,6 +2306,7 @@ read_token (command)
|
|||
return -1;
|
||||
}
|
||||
break;
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -2302,6 +2376,7 @@ read_token (command)
|
|||
correct error values if it reads EOF. */
|
||||
|
||||
#define P_FIRSTCLOSE 0x01
|
||||
#define P_ALLOWESC 0x02
|
||||
|
||||
static char matched_pair_error;
|
||||
static char *
|
||||
|
@ -2324,7 +2399,7 @@ parse_matched_pair (qc, open, close, lenp, flags)
|
|||
start_lineno = line_number;
|
||||
while (count)
|
||||
{
|
||||
ch = shell_getc (qc != '\'' && pass_next_character == 0);
|
||||
ch = shell_getc ((qc != '\'' || (flags & P_ALLOWESC)) && pass_next_character == 0);
|
||||
if (ch == EOF)
|
||||
{
|
||||
free (ret);
|
||||
|
@ -2362,6 +2437,11 @@ parse_matched_pair (qc, open, close, lenp, flags)
|
|||
}
|
||||
else if (ch == close) /* ending delimiter */
|
||||
count--;
|
||||
#if 1
|
||||
/* handle nested ${...} specially. */
|
||||
else if (open != close && was_dollar && open == '{' && ch == open) /* } */
|
||||
count++;
|
||||
#endif
|
||||
else if (((flags & P_FIRSTCLOSE) == 0) && ch == open) /* nested begin */
|
||||
count++;
|
||||
|
||||
|
@ -2370,7 +2450,11 @@ parse_matched_pair (qc, open, close, lenp, flags)
|
|||
ret[retind++] = ch;
|
||||
|
||||
if (open == '\'') /* '' inside grouping construct */
|
||||
continue;
|
||||
{
|
||||
if ((flags & P_ALLOWESC) && ch == '\\')
|
||||
pass_next_character++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ch == '\\') /* backslashes */
|
||||
pass_next_character++;
|
||||
|
@ -2449,7 +2533,7 @@ parse_matched_pair (qc, open, close, lenp, flags)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#if defined (DPAREN_ARITHMETIC)
|
||||
#if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND)
|
||||
/* We've seen a `(('. Look for the matching `))'. If we get it, return 1.
|
||||
If not, assume it's a nested subshell for backwards compatibility and
|
||||
return 0. In any case, put the characters we've consumed into a locally-
|
||||
|
@ -2473,7 +2557,7 @@ parse_arith_cmd (ep)
|
|||
if ((c = shell_getc (0)) != ')')
|
||||
rval = 0;
|
||||
|
||||
token = xmalloc(ttoklen + 4);
|
||||
token = xmalloc (ttoklen + 4);
|
||||
|
||||
/* (( ... )) -> "..." */
|
||||
token[0] = (rval == 1) ? '"' : '(';
|
||||
|
@ -2493,7 +2577,7 @@ parse_arith_cmd (ep)
|
|||
FREE (ttok);
|
||||
return rval;
|
||||
}
|
||||
#endif /* DPAREN_ARITHMETIC */
|
||||
#endif /* DPAREN_ARITHMETIC || ARITH_FOR_COMMAND */
|
||||
|
||||
#if defined (COND_COMMAND)
|
||||
static COND_COM *cond_term ();
|
||||
|
@ -2604,7 +2688,7 @@ cond_term ()
|
|||
|
||||
(void)cond_skip_newlines ();
|
||||
}
|
||||
else /* left argument to binary operator */
|
||||
else if (tok == WORD) /* left argument to binary operator */
|
||||
{
|
||||
/* lhs */
|
||||
tleft = make_cond_node (COND_TERM, yylval.word, (COND_COM *)NULL, (COND_COM *)NULL);
|
||||
|
@ -2649,6 +2733,14 @@ cond_term ()
|
|||
|
||||
(void)cond_skip_newlines ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tok < 256)
|
||||
parser_error (line_number, "unexpected token `%c' in conditional command", tok);
|
||||
else
|
||||
parser_error (line_number, "unexpected token %d in conditional command", tok);
|
||||
COND_RETURN_ERROR ();
|
||||
}
|
||||
return (term);
|
||||
}
|
||||
|
||||
|
@ -2809,7 +2901,7 @@ read_token_word (character)
|
|||
the command-oriented-history code. This way newlines
|
||||
appearing in the $(...) string get added to the
|
||||
history literally rather than causing a possibly-
|
||||
incorrect `;' to be added. */
|
||||
incorrect `;' to be added. ) */
|
||||
push_delimiter (dstack, peek_char);
|
||||
ttok = parse_matched_pair (cd, '(', ')', &ttoklen, 0);
|
||||
pop_delimiter (dstack);
|
||||
|
@ -2836,21 +2928,46 @@ read_token_word (character)
|
|||
int first_line;
|
||||
|
||||
first_line = line_number;
|
||||
ttok = parse_matched_pair (peek_char, peek_char, peek_char, &ttoklen, 0);
|
||||
push_delimiter (dstack, peek_char);
|
||||
ttok = parse_matched_pair (peek_char, peek_char, peek_char,
|
||||
&ttoklen,
|
||||
(peek_char == '\'') ? P_ALLOWESC : 0);
|
||||
pop_delimiter (dstack);
|
||||
if (ttok == &matched_pair_error)
|
||||
return -1;
|
||||
if (peek_char == '\'')
|
||||
ttrans = ansiexpand (ttok, 0, ttoklen - 1, &ttranslen);
|
||||
{
|
||||
ttrans = ansiexpand (ttok, 0, ttoklen - 1, &ttranslen);
|
||||
free (ttok);
|
||||
/* Insert the single quotes and correctly quote any
|
||||
embedded single quotes (allowed because P_ALLOWESC was
|
||||
passed to parse_matched_pair). */
|
||||
ttok = single_quote (ttrans);
|
||||
free (ttrans);
|
||||
ttrans = ttok;
|
||||
ttranslen = strlen (ttrans);
|
||||
}
|
||||
else
|
||||
ttrans = localeexpand (ttok, 0, ttoklen - 1, first_line, &ttranslen);
|
||||
free (ttok);
|
||||
{
|
||||
/* Try to locale-expand the converted string. */
|
||||
ttrans = localeexpand (ttok, 0, ttoklen - 1, first_line, &ttranslen);
|
||||
free (ttok);
|
||||
|
||||
/* Add the double quotes back */
|
||||
ttok = xmalloc (ttranslen + 3);
|
||||
ttok[0] = '"';
|
||||
strcpy (ttok + 1, ttrans);
|
||||
ttok[ttranslen + 1] = '"';
|
||||
ttok[ttranslen += 2] = '\0';
|
||||
free (ttrans);
|
||||
ttrans = ttok;
|
||||
}
|
||||
|
||||
RESIZE_MALLOCED_BUFFER (token, token_index, ttranslen + 2,
|
||||
token_buffer_size,
|
||||
TOKEN_DEFAULT_GROW_SIZE);
|
||||
token[token_index++] = peek_char;
|
||||
strcpy (token + token_index, ttrans);
|
||||
token_index += ttranslen;
|
||||
token[token_index++] = peek_char;
|
||||
FREE (ttrans);
|
||||
quoted = 1;
|
||||
all_digits = 0;
|
||||
|
@ -3036,7 +3153,7 @@ ansiexpand (string, start, end, lenp)
|
|||
|
||||
if (*temp)
|
||||
{
|
||||
t = ansicstr (temp, tlen, (int *)NULL, lenp);
|
||||
t = ansicstr (temp, tlen, 0, (int *)NULL, lenp);
|
||||
free (temp);
|
||||
return (t);
|
||||
}
|
||||
|
@ -3048,6 +3165,52 @@ ansiexpand (string, start, end, lenp)
|
|||
}
|
||||
}
|
||||
|
||||
/* Change a bash string into a string suitable for inclusion in a `po' file.
|
||||
This backslash-escapes `"' and `\' and changes newlines into \\\n"\n". */
|
||||
static char *
|
||||
mk_msgstr (string, foundnlp)
|
||||
char *string;
|
||||
int *foundnlp;
|
||||
{
|
||||
register int c, len;
|
||||
char *result, *r, *s;
|
||||
|
||||
for (len = 0, s = string; s && *s; s++)
|
||||
{
|
||||
len++;
|
||||
if (*s == '"' || *s == '\\')
|
||||
len++;
|
||||
else if (*s == '\n')
|
||||
len += 5;
|
||||
}
|
||||
|
||||
r = result = xmalloc (len + 3);
|
||||
*r++ = '"';
|
||||
|
||||
for (s = string; s && (c = *s); s++)
|
||||
{
|
||||
if (c == '\n') /* <NL> -> \n"<NL>" */
|
||||
{
|
||||
*r++ = '\\';
|
||||
*r++ = 'n';
|
||||
*r++ = '"';
|
||||
*r++ = '\n';
|
||||
*r++ = '"';
|
||||
if (foundnlp)
|
||||
*foundnlp = 1;
|
||||
continue;
|
||||
}
|
||||
if (c == '"' || c == '\\')
|
||||
*r++ = '\\';
|
||||
*r++ = c;
|
||||
}
|
||||
|
||||
*r++ = '"';
|
||||
*r++ = '\0';
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* $"..." -- Translate the portion of STRING between START and END
|
||||
according to current locale using gettext (if available) and return
|
||||
the result. The caller will take care of leaving the quotes intact.
|
||||
|
@ -3060,22 +3223,35 @@ localeexpand (string, start, end, lineno, lenp)
|
|||
char *string;
|
||||
int start, end, lineno, *lenp;
|
||||
{
|
||||
int len, tlen;
|
||||
char *temp, *t;
|
||||
int len, tlen, foundnl;
|
||||
char *temp, *t, *t2;
|
||||
|
||||
temp = xmalloc (end - start + 1);
|
||||
for (tlen = 0, len = start; len < end; )
|
||||
temp[tlen++] = string[len++];
|
||||
temp[tlen] = '\0';
|
||||
|
||||
/* If we're just dumping translatable strings, don't do anything. */
|
||||
/* If we're just dumping translatable strings, don't do anything with the
|
||||
string itself, but if we're dumping in `po' file format, convert it into a form more palatable to gettext(3)
|
||||
and friends by quoting `"' and `\' with backslashes and converting <NL>
|
||||
into `\n"<NL>"'. If we find a newline in TEMP, we first output a
|
||||
`msgid ""' line and then the translated string; otherwise we output the
|
||||
`msgid' and translated string all on one line. */
|
||||
if (dump_translatable_strings)
|
||||
{
|
||||
if (dump_po_strings)
|
||||
printf ("#: %s:%d\nmsgid \"%s\"\nmsgstr \"\"\n",
|
||||
(bash_input.name ? bash_input.name : "stdin"), lineno, temp);
|
||||
{
|
||||
foundnl = 0;
|
||||
t = mk_msgstr (temp, &foundnl);
|
||||
t2 = foundnl ? "\"\"\n" : "";
|
||||
|
||||
printf ("#: %s:%d\nmsgid %s%s\nmsgstr \"\"\n",
|
||||
(bash_input.name ? bash_input.name : "stdin"), lineno, t2, t);
|
||||
free (t);
|
||||
}
|
||||
else
|
||||
printf ("\"%s\"\n", temp);
|
||||
|
||||
if (lenp)
|
||||
*lenp = tlen;
|
||||
return (temp);
|
||||
|
@ -3211,6 +3387,17 @@ history_delimiting_chars ()
|
|||
else if (token_before_that == WORD && two_tokens_ago == FUNCTION)
|
||||
return " "; /* function def using `function name' without `()' */
|
||||
|
||||
else if (token_before_that == WORD && two_tokens_ago == FOR)
|
||||
{
|
||||
/* Tricky. `for i\nin ...' should not have a semicolon, but
|
||||
`for i\ndo ...' should. We do what we can. */
|
||||
for (i = shell_input_line_index; whitespace(shell_input_line[i]); i++)
|
||||
;
|
||||
if (shell_input_line[i] && shell_input_line[i] == 'i' && shell_input_line[i+1] == 'n')
|
||||
return " ";
|
||||
return ";";
|
||||
}
|
||||
|
||||
for (i = 0; no_semi_successors[i]; i++)
|
||||
{
|
||||
if (token_before_that == no_semi_successors[i])
|
||||
|
@ -3264,6 +3451,20 @@ prompt_again ()
|
|||
}
|
||||
}
|
||||
|
||||
int
|
||||
get_current_prompt_level ()
|
||||
{
|
||||
return ((current_prompt_string && current_prompt_string == ps2_prompt) ? 2 : 1);
|
||||
}
|
||||
|
||||
void
|
||||
set_current_prompt_level (x)
|
||||
int x;
|
||||
{
|
||||
prompt_string_pointer = (x == 2) ? &ps2_prompt : &ps1_prompt;
|
||||
current_prompt_string = *prompt_string_pointer;
|
||||
}
|
||||
|
||||
static void
|
||||
print_prompt ()
|
||||
{
|
||||
|
@ -3279,6 +3480,8 @@ print_prompt ()
|
|||
\d the date in Day Mon Date format
|
||||
\h the hostname up to the first `.'
|
||||
\H the hostname
|
||||
\j the number of active jobs
|
||||
\l the basename of the shell's tty device name
|
||||
\n CRLF
|
||||
\s the name of the shell
|
||||
\t the time in 24-hour hh:mm:ss format
|
||||
|
@ -3479,7 +3682,14 @@ decode_prompt_string (string)
|
|||
/* If we're going to be expanding the prompt string later,
|
||||
quote the directory name. */
|
||||
if (promptvars || posixly_correct)
|
||||
#if 0
|
||||
temp = backslash_quote (t_string);
|
||||
#else
|
||||
/* Make sure that expand_prompt_string is called with a
|
||||
second argument of Q_DOUBLE_QUOTE if we use this
|
||||
function here. */
|
||||
temp = backslash_quote_for_double_quotes (t_string);
|
||||
#endif
|
||||
else
|
||||
temp = savestring (t_string);
|
||||
|
||||
|
@ -3487,6 +3697,8 @@ decode_prompt_string (string)
|
|||
}
|
||||
|
||||
case 'u':
|
||||
if (current_user.user_name == 0)
|
||||
get_current_user_info ();
|
||||
temp = savestring (current_user.user_name);
|
||||
goto add_string;
|
||||
|
||||
|
@ -3517,6 +3729,20 @@ decode_prompt_string (string)
|
|||
*t = '\0';
|
||||
goto add_string;
|
||||
|
||||
case 'j':
|
||||
temp = itos (count_all_jobs ());
|
||||
goto add_string;
|
||||
|
||||
case 'l':
|
||||
#if defined (HAVE_TTYNAME)
|
||||
temp = (char *)ttyname (fileno (stdin));
|
||||
t = temp ? base_pathname (temp) : "tty";
|
||||
temp = savestring (t);
|
||||
#else
|
||||
temp = savestring ("tty");
|
||||
#endif /* !HAVE_TTYNAME */
|
||||
goto add_string;
|
||||
|
||||
#if defined (READLINE)
|
||||
case '[':
|
||||
case ']':
|
||||
|
@ -3578,7 +3804,11 @@ decode_prompt_string (string)
|
|||
the prompt string. */
|
||||
if (promptvars || posixly_correct)
|
||||
{
|
||||
#if 0
|
||||
list = expand_string_unsplit (result, Q_DOUBLE_QUOTES);
|
||||
#else
|
||||
list = expand_prompt_string (result, Q_DOUBLE_QUOTES);
|
||||
#endif
|
||||
free (result);
|
||||
result = string_list (list);
|
||||
dispose_words (list);
|
||||
|
@ -3653,11 +3883,7 @@ report_syntax_error (message)
|
|||
if (token_end || (i == 0 && token_end == 0))
|
||||
{
|
||||
if (token_end)
|
||||
{
|
||||
msg = xmalloc (1 + (token_end - i));
|
||||
strncpy (msg, t + i, token_end - i);
|
||||
msg[token_end - i] = '\0';
|
||||
}
|
||||
msg = substring (t, i, token_end);
|
||||
else /* one-character token */
|
||||
{
|
||||
msg2[0] = t[i];
|
||||
|
@ -3761,3 +3987,73 @@ handle_eof_input_unit ()
|
|||
EOF_Reached = 1;
|
||||
}
|
||||
}
|
||||
|
||||
static WORD_LIST parse_string_error;
|
||||
|
||||
/* Take a string and run it through the shell parser, returning the
|
||||
resultant word list. Used by compound array assignment. */
|
||||
WORD_LIST *
|
||||
parse_string_to_word_list (s, whom)
|
||||
char *s, *whom;
|
||||
{
|
||||
WORD_LIST *wl;
|
||||
int tok, orig_line_number, orig_input_terminator;
|
||||
#if defined (HISTORY)
|
||||
int old_remember_on_history, old_history_expansion_inhibited;
|
||||
#endif
|
||||
|
||||
#if defined (HISTORY)
|
||||
old_remember_on_history = remember_on_history;
|
||||
# if defined (BANG_HISTORY)
|
||||
old_history_expansion_inhibited = history_expansion_inhibited;
|
||||
# endif
|
||||
bash_history_disable ();
|
||||
#endif
|
||||
|
||||
orig_line_number = line_number;
|
||||
orig_input_terminator = shell_input_line_terminator;
|
||||
|
||||
push_stream (1);
|
||||
last_read_token = '\n';
|
||||
|
||||
with_input_from_string (s, whom);
|
||||
wl = (WORD_LIST *)NULL;
|
||||
while ((tok = read_token (READ)) != yacc_EOF)
|
||||
{
|
||||
if (tok == '\n' && *bash_input.location.string == '\0')
|
||||
break;
|
||||
if (tok != WORD && tok != ASSIGNMENT_WORD)
|
||||
{
|
||||
line_number = orig_line_number + line_number - 1;
|
||||
yyerror (); /* does the right thing */
|
||||
if (wl)
|
||||
dispose_words (wl);
|
||||
wl = &parse_string_error;
|
||||
break;
|
||||
}
|
||||
wl = make_word_list (yylval.word, wl);
|
||||
}
|
||||
|
||||
last_read_token = '\n';
|
||||
pop_stream ();
|
||||
|
||||
#if defined (HISTORY)
|
||||
remember_on_history = old_remember_on_history;
|
||||
# if defined (BANG_HISTORY)
|
||||
history_expansion_inhibited = old_history_expansion_inhibited;
|
||||
# endif /* BANG_HISTORY */
|
||||
#endif /* HISTORY */
|
||||
|
||||
shell_input_line_terminator = orig_input_terminator;
|
||||
|
||||
if (wl == &parse_string_error)
|
||||
{
|
||||
last_command_exit_value = EXECUTION_FAILURE;
|
||||
if (interactive_shell == 0 && posixly_correct)
|
||||
jump_to_top_level (FORCE_EOF);
|
||||
else
|
||||
jump_to_top_level (DISCARD);
|
||||
}
|
||||
|
||||
return (REVERSE_LIST (wl, WORD_LIST *));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue