Imported from ../bash-1.14.7.tar.gz.
This commit is contained in:
commit
726f63884d
402 changed files with 150297 additions and 0 deletions
276
builtins/read.def
Normal file
276
builtins/read.def
Normal file
|
@ -0,0 +1,276 @@
|
|||
This file is read.def, from which is created read.c.
|
||||
It implements the builtin "read" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
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
|
||||
version.
|
||||
|
||||
Bash 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 Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES read.c
|
||||
|
||||
$BUILTIN read
|
||||
$FUNCTION read_builtin
|
||||
$SHORT_DOC read [-r] [name ...]
|
||||
One line is read from the standard input, and the first word is
|
||||
assigned to the first NAME, the second word to the second NAME, etc.
|
||||
with leftover words assigned to the last NAME. Only the characters
|
||||
found in $IFS are recognized as word delimiters. The return code is
|
||||
zero, unless end-of-file is encountered. If the -r option is given,
|
||||
this signifies `raw' input, and backslash processing is disabled.
|
||||
$END
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../shell.h"
|
||||
#include "common.h"
|
||||
|
||||
#define issep(c) (strchr (ifs_chars, (c)) != (char *)0)
|
||||
|
||||
static int stream_close ();
|
||||
|
||||
extern int interrupt_immediately;
|
||||
|
||||
/* Read the value of the shell variables whose names follow.
|
||||
The reading is done from the current input stream, whatever
|
||||
that may be. Successive words of the input line are assigned
|
||||
to the variables mentioned in LIST. The last variable in LIST
|
||||
gets the remainder of the words on the line. If no variables
|
||||
are mentioned in LIST, then the default variable is $REPLY.
|
||||
|
||||
S. R. Bourne's shell complains if you don't name a variable
|
||||
to receive the stuff that is read. GNU's shell doesn't. This
|
||||
allows you to let the user type random things. */
|
||||
read_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
register char *varname;
|
||||
int size, c, i, fildes, raw_mode, pass_next, saw_escape, retval;
|
||||
char *input_string, *orig_input_string, *ifs_chars, *t;
|
||||
FILE *input_stream;
|
||||
SHELL_VAR *var;
|
||||
|
||||
i = 0; /* Index into the string that we are reading. */
|
||||
raw_mode = 0; /* Not reading raw input be default. */
|
||||
|
||||
while (list)
|
||||
{
|
||||
if (ISOPTION (list->word->word, 'r'))
|
||||
{
|
||||
raw_mode = 1;
|
||||
list = list->next;
|
||||
}
|
||||
else if (ISOPTION (list->word->word, '-'))
|
||||
{
|
||||
list = list->next;
|
||||
break;
|
||||
}
|
||||
else if (*list->word->word == '-')
|
||||
{
|
||||
bad_option (list->word->word);
|
||||
builtin_error ("usage: read [-r] [name ...]");
|
||||
return (EX_USAGE);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
/* We need unbuffered input from stdin. So we make a new stream with
|
||||
the same file descriptor as stdin, then unbuffer it. */
|
||||
fildes = dup (fileno (stdin));
|
||||
|
||||
if (fildes == -1)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
input_stream = fdopen (fildes, "r");
|
||||
|
||||
if (!input_stream)
|
||||
{
|
||||
close (fildes);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
var = find_variable ("IFS");
|
||||
ifs_chars = var ? value_cell (var) : " \t\n";
|
||||
|
||||
input_string = xmalloc (size = 128);
|
||||
|
||||
setbuf (input_stream, (char *)NULL);
|
||||
|
||||
begin_unwind_frame ("read_builtin");
|
||||
add_unwind_protect (xfree, input_string);
|
||||
add_unwind_protect (stream_close, input_stream);
|
||||
interrupt_immediately++;
|
||||
|
||||
pass_next = 0; /* Non-zero signifies last char was backslash. */
|
||||
saw_escape = 0; /* Non-zero signifies that we saw an escape char */
|
||||
|
||||
while ((c = getc (input_stream)) != EOF)
|
||||
{
|
||||
if (i + 2 >= size)
|
||||
input_string = xrealloc (input_string, size += 128);
|
||||
|
||||
/* If the next character is to be accepted verbatim, a backslash
|
||||
newline pair still disappears from the input. */
|
||||
if (pass_next)
|
||||
{
|
||||
if (c == '\n')
|
||||
i--; /* back up over the CTLESC */
|
||||
else
|
||||
input_string[i++] = c;
|
||||
pass_next = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '\\' && !raw_mode)
|
||||
{
|
||||
pass_next++;
|
||||
saw_escape++;
|
||||
input_string[i++] = CTLESC;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '\n')
|
||||
break;
|
||||
|
||||
if (c == CTLESC || c == CTLNUL)
|
||||
{
|
||||
saw_escape++;
|
||||
input_string[i++] = CTLESC;
|
||||
}
|
||||
|
||||
input_string[i++] = c;
|
||||
}
|
||||
input_string[i] = '\0';
|
||||
|
||||
interrupt_immediately--;
|
||||
discard_unwind_frame ("read_builtin");
|
||||
|
||||
fclose (input_stream);
|
||||
|
||||
if (c == EOF)
|
||||
{
|
||||
retval = EXECUTION_FAILURE;
|
||||
/* input_string[0] = '\0'; */
|
||||
}
|
||||
else
|
||||
retval = EXECUTION_SUCCESS;
|
||||
|
||||
if (!list)
|
||||
{
|
||||
if (saw_escape)
|
||||
{
|
||||
t = dequote_string (input_string);
|
||||
var = bind_variable ("REPLY", t);
|
||||
free (t);
|
||||
}
|
||||
else
|
||||
var = bind_variable ("REPLY", input_string);
|
||||
var->attributes &= ~att_invisible;
|
||||
free (input_string);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This code implements the Posix.2 spec for splitting the words
|
||||
read and assigning them to variables. If $IFS is unset, we
|
||||
use the default value of " \t\n". */
|
||||
orig_input_string = input_string;
|
||||
|
||||
/* Remove IFS white space at the beginning of the input string. If
|
||||
$IFS is null, no field splitting is performed. */
|
||||
for (t = input_string; *ifs_chars && spctabnl (*t) && issep (*t); t++)
|
||||
;
|
||||
input_string = t;
|
||||
|
||||
for (; list->next; list = list->next)
|
||||
{
|
||||
char *e, *t1;
|
||||
|
||||
varname = list->word->word;
|
||||
if (legal_identifier (varname) == 0)
|
||||
{
|
||||
builtin_error ("%s: not a legal variable name", varname);
|
||||
free (orig_input_string);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* If there are more variables than words read from the input,
|
||||
the remaining variables are set to the empty string. */
|
||||
if (*input_string)
|
||||
{
|
||||
/* This call updates INPUT_STRING. */
|
||||
t = get_word_from_string (&input_string, ifs_chars, &e);
|
||||
if (t)
|
||||
*e = '\0';
|
||||
/* Don't bother to remove the CTLESC unless we added one
|
||||
somewhere while reading the string. */
|
||||
if (t && saw_escape)
|
||||
{
|
||||
t1 = dequote_string (t);
|
||||
var = bind_variable (varname, t1);
|
||||
free (t1);
|
||||
}
|
||||
else
|
||||
var = bind_variable (varname, t);
|
||||
}
|
||||
else
|
||||
{
|
||||
t = (char *)0;
|
||||
var = bind_variable (varname, "");
|
||||
}
|
||||
|
||||
stupidly_hack_special_variables (varname);
|
||||
var->attributes &= ~att_invisible;
|
||||
|
||||
if (t)
|
||||
free (t);
|
||||
}
|
||||
|
||||
if (legal_identifier (list->word->word) == 0)
|
||||
{
|
||||
builtin_error ("%s: not a legal variable name", list->word->word);
|
||||
free (orig_input_string);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* This has to be done this way rather than using string_list
|
||||
and list_string because Posix.2 says that the last variable gets the
|
||||
remaining words and their intervening separators. */
|
||||
input_string = strip_trailing_ifs_whitespace (input_string, ifs_chars,
|
||||
saw_escape);
|
||||
|
||||
if (saw_escape)
|
||||
{
|
||||
t = dequote_string (input_string);
|
||||
var = bind_variable (list->word->word, t);
|
||||
free (t);
|
||||
}
|
||||
else
|
||||
var = bind_variable (list->word->word, input_string);
|
||||
stupidly_hack_special_variables (list->word->word);
|
||||
var->attributes &= ~att_invisible;
|
||||
free (orig_input_string);
|
||||
}
|
||||
|
||||
return (retval);
|
||||
}
|
||||
|
||||
/* This way I don't have to know whether fclose () is a
|
||||
function or a macro. */
|
||||
static int
|
||||
stream_close (file)
|
||||
FILE *file;
|
||||
{
|
||||
return (fclose (file));
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue