#line 23 "read.def"
#line 49 "read.def"
#include <config.h>
#include "bashtypes.h"
#include "posixstat.h"
#include <stdio.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <signal.h>
#include <errno.h>
#ifdef __CYGWIN__
# include <fcntl.h>
# include <io.h>
#endif
#include "../bashintl.h"
#include "../shell.h"
#include "common.h"
#include "bashgetopt.h"
#include <shtty.h>
#if defined (READLINE)
#include "../bashline.h"
#include <readline/readline.h>
#endif
#if defined (BUFFERED_INPUT)
# include "input.h"
#endif
#if !defined(errno)
extern int errno;
#endif
extern int posixly_correct;
#if defined (READLINE)
static void reset_attempted_completion_function __P((char *));
static char *edit_line __P((char *));
static void set_eol_delim __P((int));
static void reset_eol_delim __P((char *));
#endif
static SHELL_VAR *bind_read_variable __P((char *, char *));
static sighandler sigalrm __P((int));
static void reset_alarm __P((void));
static procenv_t alrmbuf;
static SigHandler *old_alrm;
static unsigned char delim;
static sighandler
sigalrm (s)
int s;
{
longjmp (alrmbuf, 1);
}
static void
reset_alarm ()
{
set_signal_handler (SIGALRM, old_alrm);
alarm (0);
}
int
read_builtin (list)
WORD_LIST *list;
{
register char *varname;
int size, i, nr, pass_next, saw_escape, eof, opt, retval, code, print_ps2;
int input_is_tty, input_is_pipe, unbuffered_read;
int raw, edit, nchars, silent, have_timeout, fd;
unsigned int tmout;
intmax_t intval;
char c;
char *input_string, *orig_input_string, *ifs_chars, *prompt, *arrayname;
char *e, *t, *t1, *ps2, *tofree;
struct stat tsb;
SHELL_VAR *var;
#if defined (ARRAY_VARS)
WORD_LIST *alist;
#endif
#if defined (READLINE)
char *rlbuf;
int rlind;
#endif
USE_VAR(size);
USE_VAR(i);
USE_VAR(pass_next);
USE_VAR(print_ps2);
USE_VAR(saw_escape);
USE_VAR(input_is_pipe);
USE_VAR(edit);
USE_VAR(tmout);
USE_VAR(nchars);
USE_VAR(silent);
USE_VAR(ifs_chars);
USE_VAR(prompt);
USE_VAR(arrayname);
#if defined (READLINE)
USE_VAR(rlbuf);
USE_VAR(rlind);
#endif
USE_VAR(list);
USE_VAR(ps2);
i = 0;
raw = edit = 0;
silent = 0;
arrayname = prompt = (char *)NULL;
fd = 0;
#if defined (READLINE)
rlbuf = (char *)0;
rlind = 0;
#endif
tmout = 0;
nr = nchars = input_is_tty = input_is_pipe = unbuffered_read = have_timeout = 0;
delim = '\n';
reset_internal_getopt ();
while ((opt = internal_getopt (list, "ersa:d:n:p:t:u:")) != -1)
{
switch (opt)
{
case 'r':
raw = 1;
break;
case 'p':
prompt = list_optarg;
break;
case 's':
silent = 1;
break;
case 'e':
#if defined (READLINE)
edit = 1;
#endif
break;
#if defined (ARRAY_VARS)
case 'a':
arrayname = list_optarg;
break;
#endif
case 't':
code = legal_number (list_optarg, &intval);
if (code == 0 || intval < 0 || intval != (unsigned int)intval)
{
builtin_error (_("%s: invalid timeout specification"), list_optarg);
return (EXECUTION_FAILURE);
}
else
{
have_timeout = 1;
tmout = intval;
}
break;
case 'n':
code = legal_number (list_optarg, &intval);
if (code == 0 || intval < 0 || intval != (int)intval)
{
sh_invalidnum (list_optarg);
return (EXECUTION_FAILURE);
}
else
nchars = intval;
break;
case 'u':
code = legal_number (list_optarg, &intval);
if (code == 0 || intval < 0 || intval != (int)intval)
{
builtin_error (_("%s: invalid file descriptor specification"), list_optarg);
return (EXECUTION_FAILURE);
}
else
fd = intval;
if (sh_validfd (fd) == 0)
{
builtin_error (_("%d: invalid file descriptor: %s"), fd, strerror (errno));
return (EXECUTION_FAILURE);
}
break;
case 'd':
delim = *list_optarg;
break;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
if (have_timeout && tmout == 0)
return (EXECUTION_FAILURE);
ifs_chars = getifs ();
if (ifs_chars == 0)
ifs_chars = "";
input_string = (char *)xmalloc (size = 112);
if (have_timeout == 0 && (e = get_string_value ("TMOUT")))
{
code = legal_number (e, &intval);
if (code == 0 || intval < 0 || intval != (unsigned int)intval)
tmout = 0;
else
tmout = intval;
}
begin_unwind_frame ("read_builtin");
#if defined (BUFFERED_INPUT)
if (interactive == 0 && default_buffered_input >= 0 && fd_is_bash_input (fd))
sync_buffered_stream (default_buffered_input);
#endif
input_is_tty = isatty (fd);
if (input_is_tty == 0)
#ifndef __CYGWIN__
input_is_pipe = (lseek (fd, 0L, SEEK_CUR) < 0) && (errno == ESPIPE);
#else
input_is_pipe = 1;
#endif
if ((prompt || edit || silent) && input_is_tty == 0)
{
prompt = (char *)NULL;
edit = silent = 0;
}
#if defined (READLINE)
if (edit)
add_unwind_protect (xfree, rlbuf);
#endif
if (prompt && edit == 0)
{
fprintf (stderr, "%s", prompt);
fflush (stderr);
}
pass_next = 0;
saw_escape = 0;
if (tmout > 0)
{
if ((fstat (fd, &tsb) < 0) || S_ISREG (tsb.st_mode))
tmout = 0;
}
if (tmout > 0)
{
code = setjmp (alrmbuf);
if (code)
{
interrupt_immediately--;
terminate_immediately = 0;
run_unwind_frame ("read_builtin");
return (EXECUTION_FAILURE);
}
old_alrm = set_signal_handler (SIGALRM, sigalrm);
add_unwind_protect (reset_alarm, (char *)NULL);
#if defined (READLINE)
if (edit)
add_unwind_protect (reset_attempted_completion_function, (char *)NULL);
#endif
alarm (tmout);
}
if (nchars > 0 || delim != '\n')
{
#if defined (READLINE)
if (edit)
{
if (nchars > 0)
{
unwind_protect_int (rl_num_chars_to_read);
rl_num_chars_to_read = nchars;
}
if (delim != '\n')
{
set_eol_delim (delim);
add_unwind_protect (reset_eol_delim, (char *)NULL);
}
}
else
#endif
if (input_is_tty)
{
ttsave ();
if (silent)
ttcbreak ();
else
ttonechar ();
add_unwind_protect ((Function *)ttrestore, (char *)NULL);
}
}
else if (silent)
{
ttsave ();
ttnoecho ();
add_unwind_protect ((Function *)ttrestore, (char *)NULL);
}
add_unwind_protect (xfree, input_string);
interrupt_immediately++;
terminate_immediately = 1;
unbuffered_read = (nchars > 0) || (delim != '\n') || input_is_pipe;
#if defined (__CYGWIN__) && defined (O_TEXT)
setmode (0, O_TEXT);
#endif
ps2 = 0;
for (print_ps2 = eof = retval = 0;;)
{
#if defined (READLINE)
if (edit)
{
if (rlbuf && rlbuf[rlind] == '\0')
{
xfree (rlbuf);
rlbuf = (char *)0;
}
if (rlbuf == 0)
{
rlbuf = edit_line (prompt ? prompt : "");
rlind = 0;
}
if (rlbuf == 0)
{
eof = 1;
break;
}
c = rlbuf[rlind++];
}
else
{
#endif
if (print_ps2)
{
if (ps2 == 0)
ps2 = get_string_value ("PS2");
fprintf (stderr, "%s", ps2 ? ps2 : "");
fflush (stderr);
print_ps2 = 0;
}
if (unbuffered_read)
retval = zread (fd, &c, 1);
else
retval = zreadc (fd, &c);
if (retval <= 0)
{
eof = 1;
break;
}
#if defined (READLINE)
}
#endif
if (i + 2 >= size)
{
input_string = (char *)xrealloc (input_string, size += 128);
remove_unwind_protect ();
add_unwind_protect (xfree, input_string);
}
if (pass_next)
{
pass_next = 0;
if (c == '\n')
{
i--;
if (interactive && input_is_tty && raw == 0)
print_ps2 = 1;
}
else
goto add_char;
continue;
}
if (c == '\\' && raw == 0)
{
pass_next++;
saw_escape++;
input_string[i++] = CTLESC;
continue;
}
if ((unsigned char)c == delim)
break;
if (c == CTLESC || c == CTLNUL)
{
saw_escape++;
input_string[i++] = CTLESC;
}
add_char:
input_string[i++] = c;
nr++;
if (nchars > 0 && nr >= nchars)
break;
}
input_string[i] = '\0';
#if 1
if (retval < 0)
{
builtin_error (_("read error: %d: %s"), fd, strerror (errno));
run_unwind_frame ("read_builtin");
return (EXECUTION_FAILURE);
}
#endif
if (tmout > 0)
reset_alarm ();
if (nchars > 0 || delim != '\n')
{
#if defined (READLINE)
if (edit)
{
if (nchars > 0)
rl_num_chars_to_read = 0;
if (delim != '\n')
reset_eol_delim ((char *)NULL);
}
else
#endif
if (input_is_tty)
ttrestore ();
}
else if (silent)
ttrestore ();
if (unbuffered_read == 0)
zsyncfd (fd);
interrupt_immediately--;
terminate_immediately = 0;
discard_unwind_frame ("read_builtin");
retval = eof ? EXECUTION_FAILURE : EXECUTION_SUCCESS;
#if defined (ARRAY_VARS)
if (arrayname)
{
if (legal_identifier (arrayname) == 0)
{
sh_invalidid (arrayname);
xfree (input_string);
return (EXECUTION_FAILURE);
}
var = find_or_make_array_variable (arrayname, 1);
if (var == 0)
{
xfree (input_string);
return EXECUTION_FAILURE;
}
array_flush (array_cell (var));
alist = list_string (input_string, ifs_chars, 0);
if (alist)
{
if (saw_escape)
dequote_list (alist);
else
word_list_remove_quoted_nulls (alist);
assign_array_var_from_word_list (var, alist, 0);
dispose_words (alist);
}
xfree (input_string);
return (retval);
}
#endif
if (list == 0)
{
#if 0
orig_input_string = input_string;
for (t = input_string; ifs_chars && *ifs_chars && spctabnl(*t) && isifs(*t); t++)
;
input_string = t;
input_string = strip_trailing_ifs_whitespace (input_string, ifs_chars, saw_escape);
#endif
if (saw_escape)
{
t = dequote_string (input_string);
var = bind_variable ("REPLY", t, 0);
free (t);
}
else
var = bind_variable ("REPLY", input_string, 0);
VUNSETATTR (var, att_invisible);
free (input_string);
return (retval);
}
orig_input_string = input_string;
for (t = input_string; ifs_chars && *ifs_chars && (posixly_correct ? posix_whitespace(*t) : spctabnl(*t)) && isifs(*t); t++)
;
input_string = t;
for (; list->next; list = list->next)
{
varname = list->word->word;
#if defined (ARRAY_VARS)
if (legal_identifier (varname) == 0 && valid_array_reference (varname) == 0)
#else
if (legal_identifier (varname) == 0)
#endif
{
sh_invalidid (varname);
xfree (orig_input_string);
return (EXECUTION_FAILURE);
}
if (*input_string)
{
t = get_word_from_string (&input_string, ifs_chars, &e);
if (t)
*e = '\0';
if (t && saw_escape)
{
t1 = dequote_string (t);
var = bind_read_variable (varname, t1);
xfree (t1);
}
else
var = bind_read_variable (varname, t);
}
else
{
t = (char *)0;
var = bind_read_variable (varname, "");
}
FREE (t);
if (var == 0)
{
xfree (orig_input_string);
return (EXECUTION_FAILURE);
}
stupidly_hack_special_variables (varname);
VUNSETATTR (var, att_invisible);
}
#if defined (ARRAY_VARS)
if (legal_identifier (list->word->word) == 0 && valid_array_reference (list->word->word) == 0)
#else
if (legal_identifier (list->word->word) == 0)
#endif
{
sh_invalidid (list->word->word);
xfree (orig_input_string);
return (EXECUTION_FAILURE);
}
#if 0
input_string = strip_trailing_ifs_whitespace (input_string, ifs_chars, saw_escape);
#else
tofree = NULL;
if (*input_string)
{
t1 = input_string;
t = get_word_from_string (&input_string, ifs_chars, &e);
if (*input_string == 0)
tofree = input_string = t;
else
input_string = strip_trailing_ifs_whitespace (t1, ifs_chars, saw_escape);
}
#endif
if (saw_escape)
{
t = dequote_string (input_string);
var = bind_read_variable (list->word->word, t);
xfree (t);
}
else
var = bind_read_variable (list->word->word, input_string);
stupidly_hack_special_variables (list->word->word);
FREE (tofree);
if (var)
VUNSETATTR (var, att_invisible);
xfree (orig_input_string);
return (retval);
}
static SHELL_VAR *
bind_read_variable (name, value)
char *name, *value;
{
#if defined (ARRAY_VARS)
if (valid_array_reference (name) == 0)
return (bind_variable (name, value, 0));
else
return (assign_array_element (name, value, 0));
#else
return bind_variable (name, value, 0);
#endif
}
#if defined (READLINE)
static rl_completion_func_t *old_attempted_completion_function = 0;
static void
reset_attempted_completion_function (cp)
char *cp;
{
if (rl_attempted_completion_function == 0 && old_attempted_completion_function)
rl_attempted_completion_function = old_attempted_completion_function;
}
static char *
edit_line (p)
char *p;
{
char *ret;
int len;
if (bash_readline_initialized == 0)
initialize_readline ();
old_attempted_completion_function = rl_attempted_completion_function;
rl_attempted_completion_function = (rl_completion_func_t *)NULL;
ret = readline (p);
rl_attempted_completion_function = old_attempted_completion_function;
old_attempted_completion_function = (rl_completion_func_t *)NULL;
if (ret == 0)
return ret;
len = strlen (ret);
ret = (char *)xrealloc (ret, len + 2);
ret[len++] = delim;
ret[len] = '\0';
return ret;
}
static int old_delim_ctype;
static rl_command_func_t *old_delim_func;
static int old_newline_ctype;
static rl_command_func_t *old_newline_func;
static unsigned char delim_char;
static void
set_eol_delim (c)
int c;
{
Keymap cmap;
if (bash_readline_initialized == 0)
initialize_readline ();
cmap = rl_get_keymap ();
old_newline_ctype = cmap[RETURN].type;
old_newline_func = cmap[RETURN].function;
cmap[RETURN].type = ISFUNC;
cmap[RETURN].function = rl_insert;
old_delim_ctype = cmap[c].type;
old_delim_func = cmap[c].function;
cmap[c].type = ISFUNC;
cmap[c].function = rl_newline;
delim_char = c;
}
static void
reset_eol_delim (cp)
char *cp;
{
Keymap cmap;
cmap = rl_get_keymap ();
cmap[RETURN].type = old_newline_ctype;
cmap[RETURN].function = old_newline_func;
cmap[delim_char].type = old_delim_ctype;
cmap[delim_char].function = old_delim_func;
}
#endif