mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-06-27 23:53:18 +02:00
commit bash-20121012 snapshot
This commit is contained in:
@@ -3686,3 +3686,70 @@ builtins/test.def
|
||||
|
||||
doc/{bash.1,bashref.texi}
|
||||
- document new -R unary conditional operator
|
||||
|
||||
10/13
|
||||
-----
|
||||
trap.c
|
||||
- check_signals_and_traps: new function, convenience function for the
|
||||
rest of the shell to check for pending terminating and interrupt
|
||||
signals, and to check for and process any pending traps
|
||||
- any_signals_trapped: new function, returns non-zero if any signals
|
||||
are trapped and -1 if not
|
||||
|
||||
trap.h
|
||||
- extern declaration for check_signals_and_traps
|
||||
|
||||
bashline.c
|
||||
- bashline_reset: make sure we reset the event hook
|
||||
- bash_event_hook: call check_signals_and_traps instead of just
|
||||
checking for terminating signals so we can run pending traps and
|
||||
react to interrupts, and reset the event hook when we're done
|
||||
|
||||
|
||||
10/14
|
||||
-----
|
||||
trap.c
|
||||
- trap_handler: if executing in a readline signal handler context,
|
||||
call bashline_set_event_hook to install bash_event_hook to process
|
||||
the signal (if bash cares about it)
|
||||
|
||||
sig.c
|
||||
- sigint_sighandler: call bashline_set_event_hook to set the event
|
||||
hook if we're executing in a readline signal handler context
|
||||
|
||||
lib/readline/input.c
|
||||
- rl_getc: call RL_CHECK_SIGNALS if read returns -1/EINTR and the caught
|
||||
signal is SIGINT or SIGQUIT rather than waiting until the next time
|
||||
around the loop
|
||||
- rl_getc: call rl_event_hook after calling RL_CHECK_SIGNALS to allow
|
||||
an application signal handler to set the event hook in its own
|
||||
signal handler (e.g., like bash trap_handler or sigint_sighandler)
|
||||
|
||||
|
||||
parse.y
|
||||
- yy_readline_get: don't set interrupt_immediately before we call
|
||||
readline(). Inspired by report from lanshun zhou
|
||||
<zls.sogou@gmail.com>
|
||||
|
||||
input.c
|
||||
- getc_with_restart: add call to run_pending_traps after call to
|
||||
CHECK_TERMSIG
|
||||
|
||||
lib/sh/zread.c
|
||||
- zread: call check_signals_and_traps if read() returns -1/EINTR
|
||||
instead of just ignoring the EINTR and deferring handling any
|
||||
signal that generated it
|
||||
|
||||
builtins/mapfile.def
|
||||
- mapfile: don't set interrupt_immediately before calling zgetline()
|
||||
(which uses zread internally)
|
||||
|
||||
builtins/read.def
|
||||
- read_builtin: don't set interrupt_immediately before calling zread
|
||||
(moved code around so that it was only being set right around calls
|
||||
to zread to avoid signal handler conflicts). Inspired by report
|
||||
from lanshun zhou <zls.sogou@gmail.com>
|
||||
- edit_line: don't set interrupt_immediately around call to readline()
|
||||
- include shmbutil.h
|
||||
- read_builtin: don't call read_mbchar unless is_basic(c) returns
|
||||
false for the character we just read
|
||||
|
||||
@@ -3683,3 +3683,71 @@ test.c
|
||||
|
||||
builtins/test.def
|
||||
- add -R to description of conditional commands for help test
|
||||
|
||||
doc/{bash.1,bashref.texi}
|
||||
- document new -R unary conditional operator
|
||||
|
||||
10/13
|
||||
-----
|
||||
trap.c
|
||||
- check_signals_and_traps: new function, convenience function for the
|
||||
rest of the shell to check for pending terminating and interrupt
|
||||
signals, and to check for and process any pending traps
|
||||
- any_signals_trapped: new function, returns non-zero if any signals
|
||||
are trapped and -1 if not
|
||||
|
||||
trap.h
|
||||
- extern declaration for check_signals_and_traps
|
||||
|
||||
bashline.c
|
||||
- bashline_reset: make sure we reset the event hook
|
||||
- bash_event_hook: call check_signals_and_traps instead of just
|
||||
checking for terminating signals so we can run pending traps and
|
||||
react to interrupts, and reset the event hook when we're done
|
||||
|
||||
|
||||
10/14
|
||||
-----
|
||||
trap.c
|
||||
- trap_handler: if executing in a readline signal handler context,
|
||||
call bashline_set_event_hook to install bash_event_hook to process
|
||||
the signal (if bash cares about it)
|
||||
|
||||
sig.c
|
||||
- sigint_sighandler: call bashline_set_event_hook to set the event
|
||||
hook if we're executing in a readline signal handler context
|
||||
|
||||
parse.y
|
||||
- yy_readline_get: don't set interrupt_immediately before we call
|
||||
readline()
|
||||
|
||||
lib/readline/input.c
|
||||
- rl_getc: call RL_CHECK_SIGNALS if read returns -1/EINTR and the caught
|
||||
signal is SIGINT or SIGQUIT rather than waiting until the next time
|
||||
around the loop
|
||||
- rl_getc: call rl_event_hook after calling RL_CHECK_SIGNALS to allow
|
||||
an application signal handler to set the event hook in its own
|
||||
signal handler (e.g., like bash trap_handler or sigint_sighandler)
|
||||
|
||||
input.c
|
||||
- getc_with_restart: add call to run_pending_traps after call to
|
||||
CHECK_TERMSIG
|
||||
|
||||
lib/sh/zread.c
|
||||
- zread: call check_signals_and_traps if read() returns -1/EINTR
|
||||
instead of just ignoring the EINTR and deferring handling any
|
||||
signal that generated it
|
||||
|
||||
builtins/mapfile.def
|
||||
- mapfile: don't set interrupt_immediately before calling zgetline()
|
||||
(which uses zread internally)
|
||||
|
||||
builtins/read.def
|
||||
- read_builtin: don't set interrupt_immediately before calling zread
|
||||
(moved code around so that it was only being set right around calls
|
||||
to zread to avoid signal handler conflicts). Inspired by report
|
||||
from lanshun zhou <zls.sogou@gmail.com>
|
||||
- edit_line: don't set interrupt_immediately around call to readline()
|
||||
- include shmbutil.h
|
||||
- read_builtin: don't call read_mbchar unless is_basic(c) returns
|
||||
false for the character we just read
|
||||
|
||||
@@ -512,6 +512,8 @@ po/ga.gmo f
|
||||
po/ga.po f
|
||||
po/gl.gmo f
|
||||
po/gl.po f
|
||||
po/hr.gmo f
|
||||
po/hr.po f
|
||||
po/hu.gmo f
|
||||
po/hu.po f
|
||||
po/id.gmo f
|
||||
|
||||
+4
-1
@@ -616,6 +616,8 @@ bashline_reset ()
|
||||
|
||||
set_directory_hook ();
|
||||
rl_filename_stat_hook = bash_filename_stat_hook;
|
||||
|
||||
bashline_reset_event_hook ();
|
||||
}
|
||||
|
||||
/* Contains the line to push into readline. */
|
||||
@@ -4119,7 +4121,8 @@ bash_event_hook ()
|
||||
#if defined (DEBUG)
|
||||
itrace("bash_event_hook");
|
||||
#endif
|
||||
CHECK_TERMSIG;
|
||||
check_signals_and_traps (); /* XXX */
|
||||
bashline_reset_event_hook ();
|
||||
}
|
||||
|
||||
#endif /* READLINE */
|
||||
|
||||
+4127
File diff suppressed because it is too large
Load Diff
@@ -193,7 +193,6 @@ mapfile (fd, line_count_goal, origin, nskip, callback_quantum, callback, array_n
|
||||
line_length = 0;
|
||||
|
||||
/* Reset the buffer for bash own stream */
|
||||
interrupt_immediately++;
|
||||
for (array_index = origin, line_count = 1;
|
||||
zgetline (fd, &line, &line_length, unbuffered_read) != -1;
|
||||
array_index++)
|
||||
@@ -225,7 +224,6 @@ mapfile (fd, line_count_goal, origin, nskip, callback_quantum, callback, array_n
|
||||
if (unbuffered_read == 0)
|
||||
zsyncfd (fd);
|
||||
|
||||
interrupt_immediately--;
|
||||
return EXECUTION_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,359 @@
|
||||
This file is mapfile.def, from which is created mapfile.c.
|
||||
It implements the builtin "mapfile" in Bash.
|
||||
|
||||
Copyright (C) 2005-2006 Rocky Bernstein for Free Software Foundation, Inc.
|
||||
Copyright (C) 2008-2012 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
$PRODUCES mapfile.c
|
||||
|
||||
$BUILTIN mapfile
|
||||
$FUNCTION mapfile_builtin
|
||||
$SHORT_DOC mapfile [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]
|
||||
Read lines from the standard input into an indexed array variable.
|
||||
|
||||
Read lines from the standard input into the indexed array variable ARRAY, or
|
||||
from file descriptor FD if the -u option is supplied. The variable MAPFILE
|
||||
is the default ARRAY.
|
||||
|
||||
Options:
|
||||
-n count Copy at most COUNT lines. If COUNT is 0, all lines are copied.
|
||||
-O origin Begin assigning to ARRAY at index ORIGIN. The default index is 0.
|
||||
-s count Discard the first COUNT lines read.
|
||||
-t Remove a trailing newline from each line read.
|
||||
-u fd Read lines from file descriptor FD instead of the standard input.
|
||||
-C callback Evaluate CALLBACK each time QUANTUM lines are read.
|
||||
-c quantum Specify the number of lines read between each call to CALLBACK.
|
||||
|
||||
Arguments:
|
||||
ARRAY Array variable name to use for file data.
|
||||
|
||||
If -C is supplied without -c, the default quantum is 5000. When
|
||||
CALLBACK is evaluated, it is supplied the index of the next array
|
||||
element to be assigned and the line to be assigned to that element
|
||||
as additional arguments.
|
||||
|
||||
If not supplied with an explicit origin, mapfile will clear ARRAY before
|
||||
assigning to it.
|
||||
|
||||
Exit Status:
|
||||
Returns success unless an invalid option is given or ARRAY is readonly or
|
||||
not an indexed array.
|
||||
$END
|
||||
|
||||
$BUILTIN readarray
|
||||
$FUNCTION mapfile_builtin
|
||||
$SHORT_DOC readarray [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]
|
||||
Read lines from a file into an array variable.
|
||||
|
||||
A synonym for `mapfile'.
|
||||
$END
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "builtins.h"
|
||||
#include "posixstat.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "../bashintl.h"
|
||||
#include "../shell.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
|
||||
static int run_callback __P((const char *, unsigned int, const char *));
|
||||
|
||||
#define DEFAULT_ARRAY_NAME "MAPFILE"
|
||||
#define DEFAULT_VARIABLE_NAME "MAPLINE" /* not used right now */
|
||||
|
||||
/* The value specifying how frequently `mapfile' calls the callback. */
|
||||
#define DEFAULT_QUANTUM 5000
|
||||
|
||||
/* Values for FLAGS */
|
||||
#define MAPF_CLEARARRAY 0x01
|
||||
#define MAPF_CHOP 0x02
|
||||
|
||||
static int
|
||||
run_callback (callback, curindex, curline)
|
||||
const char *callback;
|
||||
unsigned int curindex;
|
||||
const char *curline;
|
||||
{
|
||||
unsigned int execlen;
|
||||
char *execstr, *qline;
|
||||
int flags;
|
||||
|
||||
qline = sh_single_quote (curline);
|
||||
execlen = strlen (callback) + strlen (qline) + 10;
|
||||
/* 1 for each space between %s and %d,
|
||||
another 1 for the last nul char for C string. */
|
||||
execlen += 3;
|
||||
execstr = xmalloc (execlen);
|
||||
|
||||
flags = SEVAL_NOHIST;
|
||||
#if 0
|
||||
if (interactive)
|
||||
flags |= SEVAL_INTERACT;
|
||||
#endif
|
||||
snprintf (execstr, execlen, "%s %d %s", callback, curindex, qline);
|
||||
free (qline);
|
||||
return evalstring (execstr, NULL, flags);
|
||||
}
|
||||
|
||||
static void
|
||||
do_chop(line)
|
||||
char * line;
|
||||
{
|
||||
int length;
|
||||
|
||||
length = strlen (line);
|
||||
if (length && line[length-1] == '\n')
|
||||
line[length-1] = '\0';
|
||||
}
|
||||
|
||||
static int
|
||||
mapfile (fd, line_count_goal, origin, nskip, callback_quantum, callback, array_name, flags)
|
||||
int fd;
|
||||
long line_count_goal, origin, nskip, callback_quantum;
|
||||
char *callback, *array_name;
|
||||
int flags;
|
||||
{
|
||||
char *line;
|
||||
size_t line_length;
|
||||
unsigned int array_index, line_count;
|
||||
SHELL_VAR *entry;
|
||||
int unbuffered_read;
|
||||
|
||||
line = NULL;
|
||||
line_length = 0;
|
||||
unbuffered_read = 0;
|
||||
|
||||
/* The following check should be done before reading any lines. Doing it
|
||||
here allows us to call bind_array_element instead of bind_array_variable
|
||||
and skip the variable lookup on every call. */
|
||||
entry = find_or_make_array_variable (array_name, 1);
|
||||
if (entry == 0 || readonly_p (entry) || noassign_p (entry))
|
||||
{
|
||||
if (entry && readonly_p (entry))
|
||||
err_readonly (array_name);
|
||||
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else if (array_p (entry) == 0)
|
||||
{
|
||||
builtin_error (_("%s: not an indexed array"), array_name);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (flags & MAPF_CLEARARRAY)
|
||||
array_flush (array_cell (entry));
|
||||
|
||||
#ifndef __CYGWIN__
|
||||
unbuffered_read = (lseek (fd, 0L, SEEK_CUR) < 0) && (errno == ESPIPE);
|
||||
#else
|
||||
unbuffered_read = 1;
|
||||
#endif
|
||||
|
||||
zreset ();
|
||||
|
||||
/* Skip any lines at beginning of file? */
|
||||
for (line_count = 0; line_count < nskip; line_count++)
|
||||
if (zgetline (fd, &line, &line_length, unbuffered_read) < 0)
|
||||
break;
|
||||
|
||||
line = 0;
|
||||
line_length = 0;
|
||||
|
||||
/* Reset the buffer for bash own stream */
|
||||
interrupt_immediately++;
|
||||
for (array_index = origin, line_count = 1;
|
||||
zgetline (fd, &line, &line_length, unbuffered_read) != -1;
|
||||
array_index++)
|
||||
{
|
||||
/* Remove trailing newlines? */
|
||||
if (flags & MAPF_CHOP)
|
||||
do_chop (line);
|
||||
|
||||
/* Has a callback been registered and if so is it time to call it? */
|
||||
if (callback && line_count && (line_count % callback_quantum) == 0)
|
||||
{
|
||||
run_callback (callback, array_index, line);
|
||||
|
||||
/* Reset the buffer for bash own stream. */
|
||||
if (unbuffered_read == 0)
|
||||
zsyncfd (fd);
|
||||
}
|
||||
|
||||
bind_array_element (entry, array_index, line, 0);
|
||||
|
||||
/* Have we exceeded # of lines to store? */
|
||||
line_count++;
|
||||
if (line_count_goal != 0 && line_count > line_count_goal)
|
||||
break;
|
||||
}
|
||||
|
||||
xfree (line);
|
||||
|
||||
if (unbuffered_read == 0)
|
||||
zsyncfd (fd);
|
||||
|
||||
interrupt_immediately--;
|
||||
return EXECUTION_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
mapfile_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int opt, code, fd, clear_array, flags;
|
||||
intmax_t intval;
|
||||
long lines, origin, nskip, callback_quantum;
|
||||
char *array_name, *callback;
|
||||
|
||||
clear_array = 1;
|
||||
fd = 0;
|
||||
lines = origin = nskip = 0;
|
||||
flags = MAPF_CLEARARRAY;
|
||||
callback_quantum = DEFAULT_QUANTUM;
|
||||
callback = 0;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "u:n:O:tC:c:s:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
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 'n':
|
||||
code = legal_number (list_optarg, &intval);
|
||||
if (code == 0 || intval < 0 || intval != (unsigned)intval)
|
||||
{
|
||||
builtin_error (_("%s: invalid line count"), list_optarg);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
lines = intval;
|
||||
break;
|
||||
|
||||
case 'O':
|
||||
code = legal_number (list_optarg, &intval);
|
||||
if (code == 0 || intval < 0 || intval != (unsigned)intval)
|
||||
{
|
||||
builtin_error (_("%s: invalid array origin"), list_optarg);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
origin = intval;
|
||||
flags &= ~MAPF_CLEARARRAY;
|
||||
break;
|
||||
case 't':
|
||||
flags |= MAPF_CHOP;
|
||||
break;
|
||||
case 'C':
|
||||
callback = list_optarg;
|
||||
break;
|
||||
case 'c':
|
||||
code = legal_number (list_optarg, &intval);
|
||||
if (code == 0 || intval <= 0 || intval != (unsigned)intval)
|
||||
{
|
||||
builtin_error (_("%s: invalid callback quantum"), list_optarg);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
callback_quantum = intval;
|
||||
break;
|
||||
case 's':
|
||||
code = legal_number (list_optarg, &intval);
|
||||
if (code == 0 || intval < 0 || intval != (unsigned)intval)
|
||||
{
|
||||
builtin_error (_("%s: invalid line count"), list_optarg);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
nskip = intval;
|
||||
break;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (list == 0)
|
||||
array_name = DEFAULT_ARRAY_NAME;
|
||||
else if (list->word == 0 || list->word->word == 0)
|
||||
{
|
||||
builtin_error ("internal error: getting variable name");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else if (list->word->word[0] == '\0')
|
||||
{
|
||||
builtin_error (_("empty array variable name"));
|
||||
return (EX_USAGE);
|
||||
}
|
||||
else
|
||||
array_name = list->word->word;
|
||||
|
||||
if (legal_identifier (array_name) == 0 && valid_array_reference (array_name) == 0)
|
||||
{
|
||||
sh_invalidid (array_name);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
return mapfile (fd, lines, origin, nskip, callback_quantum, callback, array_name, flags);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int
|
||||
mapfile_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
builtin_error (_("array variable support required"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
#endif /* ARRAY_VARS */
|
||||
+14
-6
@@ -103,6 +103,8 @@ $END
|
||||
# include "input.h"
|
||||
#endif
|
||||
|
||||
#include "shmbutil.h"
|
||||
|
||||
#if !defined(errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
@@ -477,8 +479,6 @@ read_builtin (list)
|
||||
/* This *must* be the top unwind-protect on the stack, so the manipulation
|
||||
of the unwind-protect stack after the realloc() works right. */
|
||||
add_unwind_protect (xfree, input_string);
|
||||
if (posixly_correct == 0)
|
||||
interrupt_immediately++;
|
||||
|
||||
CHECK_ALRM;
|
||||
unbuffered_read = (nchars > 0) || (delim != '\n') || input_is_pipe;
|
||||
@@ -533,12 +533,20 @@ read_builtin (list)
|
||||
print_ps2 = 0;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (posixly_correct == 0)
|
||||
interrupt_immediately++;
|
||||
#endif
|
||||
reading = 1;
|
||||
if (unbuffered_read)
|
||||
retval = posixly_correct ? zreadintr (fd, &c, 1) : zread (fd, &c, 1);
|
||||
else
|
||||
retval = posixly_correct ? zreadcintr (fd, &c) : zreadc (fd, &c);
|
||||
reading = 0;
|
||||
#if 0
|
||||
if (posixly_correct == 0)
|
||||
interrupt_immediately--;
|
||||
#endif
|
||||
|
||||
if (retval <= 0)
|
||||
{
|
||||
@@ -622,7 +630,7 @@ add_char:
|
||||
CHECK_ALRM;
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
if (nchars > 0 && MB_CUR_MAX > 1)
|
||||
if (nchars > 0 && MB_CUR_MAX > 1 && is_basic (c) == 0)
|
||||
{
|
||||
input_string[i] = '\0'; /* for simplicity and debugging */
|
||||
i += read_mbchar (fd, input_string, i, c, unbuffered_read);
|
||||
@@ -676,9 +684,6 @@ add_char:
|
||||
|
||||
assign_vars:
|
||||
|
||||
if (posixly_correct == 0)
|
||||
interrupt_immediately--;
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
/* If -a was given, take the string read, break it into a list of words,
|
||||
an assign them to `arrayname' in turn. */
|
||||
@@ -912,6 +917,7 @@ read_mbchar (fd, string, ind, ch, unbuffered)
|
||||
if (ret == (size_t)-2)
|
||||
{
|
||||
ps = ps_back;
|
||||
/* We don't want to be interrupted during a multibyte char read */
|
||||
if (unbuffered)
|
||||
r = zread (fd, &c, 1);
|
||||
else
|
||||
@@ -992,7 +998,9 @@ edit_line (p, itext)
|
||||
rl_startup_hook = set_itext;
|
||||
deftext = itext;
|
||||
}
|
||||
|
||||
ret = readline (p);
|
||||
|
||||
rl_attempted_completion_function = old_attempted_completion_function;
|
||||
old_attempted_completion_function = (rl_completion_func_t *)NULL;
|
||||
|
||||
|
||||
+1062
File diff suppressed because it is too large
Load Diff
@@ -1206,11 +1206,9 @@ int all;
|
||||
case VAL_LLONG_MAX:
|
||||
printf ("%lld\n", LLONG_MAX);
|
||||
break;
|
||||
# if (ULLONG_MAX != LLONG_MAX)
|
||||
case VAL_ULLONG_MAX:
|
||||
printf ("%llu\n", ULLONG_MAX);
|
||||
break;
|
||||
# endif
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
@@ -83,7 +83,9 @@ getc_with_restart (stream)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
CHECK_TERMSIG;
|
||||
CHECK_TERMSIG; /* XXX - QUIT? */
|
||||
run_pending_traps ();
|
||||
|
||||
local_bufused = read (fileno (stream), localbuf, sizeof(localbuf));
|
||||
if (local_bufused > 0)
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,662 @@
|
||||
/* input.c -- functions to perform buffered input with synchronization. */
|
||||
|
||||
/* Copyright (C) 1992-2009 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "bashtypes.h"
|
||||
#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
|
||||
# include <sys/file.h>
|
||||
#endif
|
||||
#include "filecntl.h"
|
||||
#include "posixstat.h"
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "bashansi.h"
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "command.h"
|
||||
#include "general.h"
|
||||
#include "input.h"
|
||||
#include "error.h"
|
||||
#include "externs.h"
|
||||
#include "quit.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
#if defined (EAGAIN)
|
||||
# define X_EAGAIN EAGAIN
|
||||
#else
|
||||
# define X_EAGAIN -99
|
||||
#endif
|
||||
|
||||
#if defined (EWOULDBLOCK)
|
||||
# define X_EWOULDBLOCK EWOULDBLOCK
|
||||
#else
|
||||
# define X_EWOULDBLOCK -99
|
||||
#endif
|
||||
|
||||
extern void termsig_handler __P((int));
|
||||
|
||||
/* Functions to handle reading input on systems that don't restart read(2)
|
||||
if a signal is received. */
|
||||
|
||||
static char localbuf[128];
|
||||
static int local_index = 0, local_bufused = 0;
|
||||
|
||||
/* Posix and USG systems do not guarantee to restart read () if it is
|
||||
interrupted by a signal. We do the read ourselves, and restart it
|
||||
if it returns EINTR. */
|
||||
int
|
||||
getc_with_restart (stream)
|
||||
FILE *stream;
|
||||
{
|
||||
unsigned char uc;
|
||||
|
||||
CHECK_TERMSIG;
|
||||
|
||||
/* Try local buffering to reduce the number of read(2) calls. */
|
||||
if (local_index == local_bufused || local_bufused == 0)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
CHECK_TERMSIG;
|
||||
run_pending_traps ();
|
||||
|
||||
local_bufused = read (fileno (stream), localbuf, sizeof(localbuf));
|
||||
if (local_bufused > 0)
|
||||
break;
|
||||
else if (local_bufused == 0)
|
||||
{
|
||||
local_index = 0;
|
||||
return EOF;
|
||||
}
|
||||
else if (errno == X_EAGAIN || errno == X_EWOULDBLOCK)
|
||||
{
|
||||
if (sh_unset_nodelay_mode (fileno (stream)) < 0)
|
||||
{
|
||||
sys_error (_("cannot reset nodelay mode for fd %d"), fileno (stream));
|
||||
return EOF;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (errno != EINTR)
|
||||
{
|
||||
local_index = 0;
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
local_index = 0;
|
||||
}
|
||||
uc = localbuf[local_index++];
|
||||
return uc;
|
||||
}
|
||||
|
||||
int
|
||||
ungetc_with_restart (c, stream)
|
||||
int c;
|
||||
FILE *stream;
|
||||
{
|
||||
if (local_index == 0 || c == EOF)
|
||||
return EOF;
|
||||
localbuf[--local_index] = c;
|
||||
return c;
|
||||
}
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
|
||||
/* A facility similar to stdio, but input-only. */
|
||||
|
||||
#if defined (USING_BASH_MALLOC)
|
||||
# define MAX_INPUT_BUFFER_SIZE 8176
|
||||
#else
|
||||
# define MAX_INPUT_BUFFER_SIZE 8192
|
||||
#endif
|
||||
|
||||
#if !defined (SEEK_CUR)
|
||||
# define SEEK_CUR 1
|
||||
#endif /* !SEEK_CUR */
|
||||
|
||||
#ifdef max
|
||||
# undef max
|
||||
#endif
|
||||
#define max(a, b) (((a) > (b)) ? (a) : (b))
|
||||
#ifdef min
|
||||
# undef min
|
||||
#endif
|
||||
#define min(a, b) ((a) > (b) ? (b) : (a))
|
||||
|
||||
extern int interactive_shell;
|
||||
|
||||
int bash_input_fd_changed;
|
||||
|
||||
/* This provides a way to map from a file descriptor to the buffer
|
||||
associated with that file descriptor, rather than just the other
|
||||
way around. This is needed so that buffers are managed properly
|
||||
in constructs like 3<&4. buffers[x]->b_fd == x -- that is how the
|
||||
correspondence is maintained. */
|
||||
static BUFFERED_STREAM **buffers = (BUFFERED_STREAM **)NULL;
|
||||
static int nbuffers;
|
||||
|
||||
#define ALLOCATE_BUFFERS(n) \
|
||||
do { if ((n) >= nbuffers) allocate_buffers (n); } while (0)
|
||||
|
||||
/* Make sure `buffers' has at least N elements. */
|
||||
static void
|
||||
allocate_buffers (n)
|
||||
int n;
|
||||
{
|
||||
register int i, orig_nbuffers;
|
||||
|
||||
orig_nbuffers = nbuffers;
|
||||
nbuffers = n + 20;
|
||||
buffers = (BUFFERED_STREAM **)xrealloc
|
||||
(buffers, nbuffers * sizeof (BUFFERED_STREAM *));
|
||||
|
||||
/* Zero out the new buffers. */
|
||||
for (i = orig_nbuffers; i < nbuffers; i++)
|
||||
buffers[i] = (BUFFERED_STREAM *)NULL;
|
||||
}
|
||||
|
||||
/* Construct and return a BUFFERED_STREAM corresponding to file descriptor
|
||||
FD, using BUFFER. */
|
||||
static BUFFERED_STREAM *
|
||||
make_buffered_stream (fd, buffer, bufsize)
|
||||
int fd;
|
||||
char *buffer;
|
||||
size_t bufsize;
|
||||
{
|
||||
BUFFERED_STREAM *bp;
|
||||
|
||||
bp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM));
|
||||
ALLOCATE_BUFFERS (fd);
|
||||
buffers[fd] = bp;
|
||||
bp->b_fd = fd;
|
||||
bp->b_buffer = buffer;
|
||||
bp->b_size = bufsize;
|
||||
bp->b_used = bp->b_inputp = bp->b_flag = 0;
|
||||
if (bufsize == 1)
|
||||
bp->b_flag |= B_UNBUFF;
|
||||
if (O_TEXT && (fcntl (fd, F_GETFL) & O_TEXT) != 0)
|
||||
bp->b_flag |= O_TEXT;
|
||||
return (bp);
|
||||
}
|
||||
|
||||
/* Allocate a new BUFFERED_STREAM, copy BP to it, and return the new copy. */
|
||||
static BUFFERED_STREAM *
|
||||
copy_buffered_stream (bp)
|
||||
BUFFERED_STREAM *bp;
|
||||
{
|
||||
BUFFERED_STREAM *nbp;
|
||||
|
||||
if (!bp)
|
||||
return ((BUFFERED_STREAM *)NULL);
|
||||
|
||||
nbp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM));
|
||||
xbcopy ((char *)bp, (char *)nbp, sizeof (BUFFERED_STREAM));
|
||||
return (nbp);
|
||||
}
|
||||
|
||||
int
|
||||
set_bash_input_fd (fd)
|
||||
int fd;
|
||||
{
|
||||
if (bash_input.type == st_bstream)
|
||||
bash_input.location.buffered_fd = fd;
|
||||
else if (interactive_shell == 0)
|
||||
default_buffered_input = fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fd_is_bash_input (fd)
|
||||
int fd;
|
||||
{
|
||||
if (bash_input.type == st_bstream && bash_input.location.buffered_fd == fd)
|
||||
return 1;
|
||||
else if (interactive_shell == 0 && default_buffered_input == fd)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Save the buffered stream corresponding to file descriptor FD (which bash
|
||||
is using to read input) to a buffered stream associated with NEW_FD. If
|
||||
NEW_FD is -1, a new file descriptor is allocated with fcntl. The new
|
||||
file descriptor is returned on success, -1 on error. */
|
||||
int
|
||||
save_bash_input (fd, new_fd)
|
||||
int fd, new_fd;
|
||||
{
|
||||
int nfd;
|
||||
|
||||
/* Sync the stream so we can re-read from the new file descriptor. We
|
||||
might be able to avoid this by copying the buffered stream verbatim
|
||||
to the new file descriptor. */
|
||||
if (buffers[fd])
|
||||
sync_buffered_stream (fd);
|
||||
|
||||
/* Now take care of duplicating the file descriptor that bash is
|
||||
using for input, so we can reinitialize it later. */
|
||||
nfd = (new_fd == -1) ? fcntl (fd, F_DUPFD, 10) : new_fd;
|
||||
if (nfd == -1)
|
||||
{
|
||||
if (fcntl (fd, F_GETFD, 0) == 0)
|
||||
sys_error (_("cannot allocate new file descriptor for bash input from fd %d"), fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (buffers[nfd])
|
||||
{
|
||||
/* What's this? A stray buffer without an associated open file
|
||||
descriptor? Free up the buffer and report the error. */
|
||||
internal_error (_("save_bash_input: buffer already exists for new fd %d"), nfd);
|
||||
free_buffered_stream (buffers[nfd]);
|
||||
}
|
||||
|
||||
/* Reinitialize bash_input.location. */
|
||||
if (bash_input.type == st_bstream)
|
||||
{
|
||||
bash_input.location.buffered_fd = nfd;
|
||||
fd_to_buffered_stream (nfd);
|
||||
close_buffered_fd (fd); /* XXX */
|
||||
}
|
||||
else
|
||||
/* If the current input type is not a buffered stream, but the shell
|
||||
is not interactive and therefore using a buffered stream to read
|
||||
input (e.g. with an `eval exec 3>output' inside a script), note
|
||||
that the input fd has been changed. pop_stream() looks at this
|
||||
value and adjusts the input fd to the new value of
|
||||
default_buffered_input accordingly. */
|
||||
bash_input_fd_changed++;
|
||||
|
||||
if (default_buffered_input == fd)
|
||||
default_buffered_input = nfd;
|
||||
|
||||
SET_CLOSE_ON_EXEC (nfd);
|
||||
return nfd;
|
||||
}
|
||||
|
||||
/* Check that file descriptor FD is not the one that bash is currently
|
||||
using to read input from a script. FD is about to be duplicated onto,
|
||||
which means that the kernel will close it for us. If FD is the bash
|
||||
input file descriptor, we need to seek backwards in the script (if
|
||||
possible and necessary -- scripts read from stdin are still unbuffered),
|
||||
allocate a new file descriptor to use for bash input, and re-initialize
|
||||
the buffered stream. Make sure the file descriptor used to save bash
|
||||
input is set close-on-exec. Returns 0 on success, -1 on failure. This
|
||||
works only if fd is > 0 -- if fd == 0 and bash is reading input from
|
||||
fd 0, save_bash_input is used instead, to cooperate with input
|
||||
redirection (look at redir.c:add_undo_redirect()). */
|
||||
int
|
||||
check_bash_input (fd)
|
||||
int fd;
|
||||
{
|
||||
if (fd_is_bash_input (fd))
|
||||
{
|
||||
if (fd > 0)
|
||||
return ((save_bash_input (fd, -1) == -1) ? -1 : 0);
|
||||
else if (fd == 0)
|
||||
return ((sync_buffered_stream (fd) == -1) ? -1 : 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This is the buffered stream analogue of dup2(fd1, fd2). The
|
||||
BUFFERED_STREAM corresponding to fd2 is deallocated, if one exists.
|
||||
BUFFERS[fd1] is copied to BUFFERS[fd2]. This is called by the
|
||||
redirect code for constructs like 4<&0 and 3</etc/rc.local. */
|
||||
int
|
||||
duplicate_buffered_stream (fd1, fd2)
|
||||
int fd1, fd2;
|
||||
{
|
||||
int is_bash_input, m;
|
||||
|
||||
if (fd1 == fd2)
|
||||
return 0;
|
||||
|
||||
m = max (fd1, fd2);
|
||||
ALLOCATE_BUFFERS (m);
|
||||
|
||||
/* If FD2 is the file descriptor bash is currently using for shell input,
|
||||
we need to do some extra work to make sure that the buffered stream
|
||||
actually exists (it might not if fd1 was not active, and the copy
|
||||
didn't actually do anything). */
|
||||
is_bash_input = (bash_input.type == st_bstream) &&
|
||||
(bash_input.location.buffered_fd == fd2);
|
||||
|
||||
if (buffers[fd2])
|
||||
{
|
||||
/* If the two objects share the same b_buffer, don't free it. */
|
||||
if (buffers[fd1] && buffers[fd1]->b_buffer && buffers[fd1]->b_buffer == buffers[fd2]->b_buffer)
|
||||
buffers[fd2] = (BUFFERED_STREAM *)NULL;
|
||||
else
|
||||
free_buffered_stream (buffers[fd2]);
|
||||
}
|
||||
buffers[fd2] = copy_buffered_stream (buffers[fd1]);
|
||||
if (buffers[fd2])
|
||||
buffers[fd2]->b_fd = fd2;
|
||||
|
||||
if (is_bash_input)
|
||||
{
|
||||
if (!buffers[fd2])
|
||||
fd_to_buffered_stream (fd2);
|
||||
buffers[fd2]->b_flag |= B_WASBASHINPUT;
|
||||
}
|
||||
|
||||
return (fd2);
|
||||
}
|
||||
|
||||
/* Return 1 if a seek on FD will succeed. */
|
||||
#define fd_is_seekable(fd) (lseek ((fd), 0L, SEEK_CUR) >= 0)
|
||||
|
||||
/* Take FD, a file descriptor, and create and return a buffered stream
|
||||
corresponding to it. If something is wrong and the file descriptor
|
||||
is invalid, return a NULL stream. */
|
||||
BUFFERED_STREAM *
|
||||
fd_to_buffered_stream (fd)
|
||||
int fd;
|
||||
{
|
||||
char *buffer;
|
||||
size_t size;
|
||||
struct stat sb;
|
||||
|
||||
if (fstat (fd, &sb) < 0)
|
||||
{
|
||||
close (fd);
|
||||
return ((BUFFERED_STREAM *)NULL);
|
||||
}
|
||||
|
||||
size = (fd_is_seekable (fd)) ? min (sb.st_size, MAX_INPUT_BUFFER_SIZE) : 1;
|
||||
if (size == 0)
|
||||
size = 1;
|
||||
buffer = (char *)xmalloc (size);
|
||||
|
||||
return (make_buffered_stream (fd, buffer, size));
|
||||
}
|
||||
|
||||
/* Return a buffered stream corresponding to FILE, a file name. */
|
||||
BUFFERED_STREAM *
|
||||
open_buffered_stream (file)
|
||||
char *file;
|
||||
{
|
||||
int fd;
|
||||
|
||||
fd = open (file, O_RDONLY);
|
||||
return ((fd >= 0) ? fd_to_buffered_stream (fd) : (BUFFERED_STREAM *)NULL);
|
||||
}
|
||||
|
||||
/* Deallocate a buffered stream and free up its resources. Make sure we
|
||||
zero out the slot in BUFFERS that points to BP. */
|
||||
void
|
||||
free_buffered_stream (bp)
|
||||
BUFFERED_STREAM *bp;
|
||||
{
|
||||
int n;
|
||||
|
||||
if (!bp)
|
||||
return;
|
||||
|
||||
n = bp->b_fd;
|
||||
if (bp->b_buffer)
|
||||
free (bp->b_buffer);
|
||||
free (bp);
|
||||
buffers[n] = (BUFFERED_STREAM *)NULL;
|
||||
}
|
||||
|
||||
/* Close the file descriptor associated with BP, a buffered stream, and free
|
||||
up the stream. Return the status of closing BP's file descriptor. */
|
||||
int
|
||||
close_buffered_stream (bp)
|
||||
BUFFERED_STREAM *bp;
|
||||
{
|
||||
int fd;
|
||||
|
||||
if (!bp)
|
||||
return (0);
|
||||
fd = bp->b_fd;
|
||||
free_buffered_stream (bp);
|
||||
return (close (fd));
|
||||
}
|
||||
|
||||
/* Deallocate the buffered stream associated with file descriptor FD, and
|
||||
close FD. Return the status of the close on FD. */
|
||||
int
|
||||
close_buffered_fd (fd)
|
||||
int fd;
|
||||
{
|
||||
if (fd < 0)
|
||||
{
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
if (fd >= nbuffers || !buffers || !buffers[fd])
|
||||
return (close (fd));
|
||||
return (close_buffered_stream (buffers[fd]));
|
||||
}
|
||||
|
||||
/* Make the BUFFERED_STREAM associcated with buffers[FD] be BP, and return
|
||||
the old BUFFERED_STREAM. */
|
||||
BUFFERED_STREAM *
|
||||
set_buffered_stream (fd, bp)
|
||||
int fd;
|
||||
BUFFERED_STREAM *bp;
|
||||
{
|
||||
BUFFERED_STREAM *ret;
|
||||
|
||||
ret = buffers[fd];
|
||||
buffers[fd] = bp;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Read a buffer full of characters from BP, a buffered stream. */
|
||||
static int
|
||||
b_fill_buffer (bp)
|
||||
BUFFERED_STREAM *bp;
|
||||
{
|
||||
ssize_t nr;
|
||||
off_t o;
|
||||
|
||||
CHECK_TERMSIG;
|
||||
/* In an environment where text and binary files are treated differently,
|
||||
compensate for lseek() on text files returning an offset different from
|
||||
the count of characters read() returns. Text-mode streams have to be
|
||||
treated as unbuffered. */
|
||||
if ((bp->b_flag & (B_TEXT | B_UNBUFF)) == B_TEXT)
|
||||
{
|
||||
o = lseek (bp->b_fd, 0, SEEK_CUR);
|
||||
nr = zread (bp->b_fd, bp->b_buffer, bp->b_size);
|
||||
if (nr > 0 && nr < lseek (bp->b_fd, 0, SEEK_CUR) - o)
|
||||
{
|
||||
lseek (bp->b_fd, o, SEEK_SET);
|
||||
bp->b_flag |= B_UNBUFF;
|
||||
bp->b_size = 1;
|
||||
nr = zread (bp->b_fd, bp->b_buffer, bp->b_size);
|
||||
}
|
||||
}
|
||||
else
|
||||
nr = zread (bp->b_fd, bp->b_buffer, bp->b_size);
|
||||
if (nr <= 0)
|
||||
{
|
||||
bp->b_used = 0;
|
||||
bp->b_buffer[0] = 0;
|
||||
if (nr == 0)
|
||||
bp->b_flag |= B_EOF;
|
||||
else
|
||||
bp->b_flag |= B_ERROR;
|
||||
return (EOF);
|
||||
}
|
||||
|
||||
bp->b_used = nr;
|
||||
bp->b_inputp = 0;
|
||||
return (bp->b_buffer[bp->b_inputp++] & 0xFF);
|
||||
}
|
||||
|
||||
/* Get a character from buffered stream BP. */
|
||||
#define bufstream_getc(bp) \
|
||||
(bp->b_inputp == bp->b_used || !bp->b_used) \
|
||||
? b_fill_buffer (bp) \
|
||||
: bp->b_buffer[bp->b_inputp++] & 0xFF
|
||||
|
||||
/* Push C back onto buffered stream BP. */
|
||||
static int
|
||||
bufstream_ungetc(c, bp)
|
||||
int c;
|
||||
BUFFERED_STREAM *bp;
|
||||
{
|
||||
if (c == EOF || bp->b_inputp == 0)
|
||||
return (EOF);
|
||||
|
||||
bp->b_buffer[--bp->b_inputp] = c;
|
||||
return (c);
|
||||
}
|
||||
|
||||
/* Seek backwards on file BFD to synchronize what we've read so far
|
||||
with the underlying file pointer. */
|
||||
int
|
||||
sync_buffered_stream (bfd)
|
||||
int bfd;
|
||||
{
|
||||
BUFFERED_STREAM *bp;
|
||||
off_t chars_left;
|
||||
|
||||
if (buffers == 0 || (bp = buffers[bfd]) == 0)
|
||||
return (-1);
|
||||
|
||||
chars_left = bp->b_used - bp->b_inputp;
|
||||
if (chars_left)
|
||||
lseek (bp->b_fd, -chars_left, SEEK_CUR);
|
||||
bp->b_used = bp->b_inputp = 0;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
buffered_getchar ()
|
||||
{
|
||||
CHECK_TERMSIG;
|
||||
|
||||
#if !defined (DJGPP)
|
||||
return (bufstream_getc (buffers[bash_input.location.buffered_fd]));
|
||||
#else
|
||||
/* On DJGPP, ignore \r. */
|
||||
int ch;
|
||||
while ((ch = bufstream_getc (buffers[bash_input.location.buffered_fd])) == '\r')
|
||||
;
|
||||
return ch;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
buffered_ungetchar (c)
|
||||
int c;
|
||||
{
|
||||
return (bufstream_ungetc (c, buffers[bash_input.location.buffered_fd]));
|
||||
}
|
||||
|
||||
/* Make input come from file descriptor BFD through a buffered stream. */
|
||||
void
|
||||
with_input_from_buffered_stream (bfd, name)
|
||||
int bfd;
|
||||
char *name;
|
||||
{
|
||||
INPUT_STREAM location;
|
||||
BUFFERED_STREAM *bp;
|
||||
|
||||
location.buffered_fd = bfd;
|
||||
/* Make sure the buffered stream exists. */
|
||||
bp = fd_to_buffered_stream (bfd);
|
||||
init_yy_io (bp == 0 ? return_EOF : buffered_getchar,
|
||||
buffered_ungetchar, st_bstream, name, location);
|
||||
}
|
||||
|
||||
#if defined (TEST)
|
||||
void *
|
||||
xmalloc(s)
|
||||
int s;
|
||||
{
|
||||
return (malloc (s));
|
||||
}
|
||||
|
||||
void *
|
||||
xrealloc(s, size)
|
||||
char *s;
|
||||
int size;
|
||||
{
|
||||
if (!s)
|
||||
return(malloc (size));
|
||||
else
|
||||
return(realloc (s, size));
|
||||
}
|
||||
|
||||
void
|
||||
init_yy_io ()
|
||||
{
|
||||
}
|
||||
|
||||
process(bp)
|
||||
BUFFERED_STREAM *bp;
|
||||
{
|
||||
int c;
|
||||
|
||||
while ((c = bufstream_getc(bp)) != EOF)
|
||||
putchar(c);
|
||||
}
|
||||
|
||||
BASH_INPUT bash_input;
|
||||
|
||||
struct stat dsb; /* can be used from gdb */
|
||||
|
||||
/* imitate /bin/cat */
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
register int i;
|
||||
BUFFERED_STREAM *bp;
|
||||
|
||||
if (argc == 1) {
|
||||
bp = fd_to_buffered_stream (0);
|
||||
process(bp);
|
||||
exit(0);
|
||||
}
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (argv[i][0] == '-' && argv[i][1] == '\0') {
|
||||
bp = fd_to_buffered_stream (0);
|
||||
if (!bp)
|
||||
continue;
|
||||
process(bp);
|
||||
free_buffered_stream (bp);
|
||||
} else {
|
||||
bp = open_buffered_stream (argv[i]);
|
||||
if (!bp)
|
||||
continue;
|
||||
process(bp);
|
||||
close_buffered_stream (bp);
|
||||
}
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
#endif /* TEST */
|
||||
#endif /* BUFFERED_INPUT */
|
||||
+11
-3
@@ -519,14 +519,22 @@ rl_getc (stream)
|
||||
#undef X_EWOULDBLOCK
|
||||
#undef X_EAGAIN
|
||||
|
||||
/* fprintf(stderr, "rl_getc: result = %d errno = %d\n", result, errno); */
|
||||
|
||||
/* If the error that we received was EINTR, then try again,
|
||||
this is simply an interrupted system call to read ().
|
||||
Otherwise, some error ocurred, also signifying EOF. */
|
||||
this is simply an interrupted system call to read (). We allow
|
||||
the read to be interrupted if we caught SIGHUP or SIGTERM (but
|
||||
not SIGINT; let the signal handler deal with that), but if the
|
||||
application sets an event hook, call it for other signals.
|
||||
Otherwise (not EINTR), some error ocurred, also signifying EOF. */
|
||||
if (errno != EINTR)
|
||||
return (RL_ISSTATE (RL_STATE_READCMD) ? READERR : EOF);
|
||||
else if (_rl_caught_signal == SIGHUP || _rl_caught_signal == SIGTERM)
|
||||
return (RL_ISSTATE (RL_STATE_READCMD) ? READERR : EOF);
|
||||
else if (rl_event_hook)
|
||||
else if (_rl_caught_signal == SIGINT || _rl_caught_signal == SIGQUIT)
|
||||
RL_CHECK_SIGNALS ();
|
||||
|
||||
if (rl_event_hook)
|
||||
(*rl_event_hook) ();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,625 @@
|
||||
/* input.c -- character input functions for readline. */
|
||||
|
||||
/* Copyright (C) 1994-2011 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.
|
||||
|
||||
Readline 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.
|
||||
|
||||
Readline 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 Readline. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define READLINE_LIBRARY
|
||||
|
||||
#if defined (__TANDEM)
|
||||
# include <floss.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_CONFIG_H)
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#if defined (HAVE_SYS_FILE_H)
|
||||
# include <sys/file.h>
|
||||
#endif /* HAVE_SYS_FILE_H */
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
|
||||
#if defined (HAVE_STDLIB_H)
|
||||
# include <stdlib.h>
|
||||
#else
|
||||
# include "ansi_stdlib.h"
|
||||
#endif /* HAVE_STDLIB_H */
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#include "posixselect.h"
|
||||
|
||||
#if defined (FIONREAD_IN_SYS_IOCTL)
|
||||
# include <sys/ioctl.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
/* System-specific feature definitions and include files. */
|
||||
#include "rldefs.h"
|
||||
#include "rlmbutil.h"
|
||||
|
||||
/* Some standard library routines. */
|
||||
#include "readline.h"
|
||||
|
||||
#include "rlprivate.h"
|
||||
#include "rlshell.h"
|
||||
#include "xmalloc.h"
|
||||
|
||||
/* What kind of non-blocking I/O do we have? */
|
||||
#if !defined (O_NDELAY) && defined (O_NONBLOCK)
|
||||
# define O_NDELAY O_NONBLOCK /* Posix style */
|
||||
#endif
|
||||
|
||||
/* Non-null means it is a pointer to a function to run while waiting for
|
||||
character input. */
|
||||
rl_hook_func_t *rl_event_hook = (rl_hook_func_t *)NULL;
|
||||
|
||||
/* A function to replace _rl_input_available for applications using the
|
||||
callback interface. */
|
||||
rl_hook_func_t *rl_input_available_hook = (rl_hook_func_t *)NULL;
|
||||
|
||||
rl_getc_func_t *rl_getc_function = rl_getc;
|
||||
|
||||
static int _keyboard_input_timeout = 100000; /* 0.1 seconds; it's in usec */
|
||||
|
||||
static int ibuffer_space PARAMS((void));
|
||||
static int rl_get_char PARAMS((int *));
|
||||
static int rl_gather_tyi PARAMS((void));
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Character Input Buffering */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
static int pop_index, push_index;
|
||||
static unsigned char ibuffer[512];
|
||||
static int ibuffer_len = sizeof (ibuffer) - 1;
|
||||
|
||||
#define any_typein (push_index != pop_index)
|
||||
|
||||
int
|
||||
_rl_any_typein ()
|
||||
{
|
||||
return any_typein;
|
||||
}
|
||||
|
||||
/* Return the amount of space available in the buffer for stuffing
|
||||
characters. */
|
||||
static int
|
||||
ibuffer_space ()
|
||||
{
|
||||
if (pop_index > push_index)
|
||||
return (pop_index - push_index - 1);
|
||||
else
|
||||
return (ibuffer_len - (push_index - pop_index));
|
||||
}
|
||||
|
||||
/* Get a key from the buffer of characters to be read.
|
||||
Return the key in KEY.
|
||||
Result is non-zero if there was a key, or 0 if there wasn't. */
|
||||
static int
|
||||
rl_get_char (key)
|
||||
int *key;
|
||||
{
|
||||
if (push_index == pop_index)
|
||||
return (0);
|
||||
|
||||
*key = ibuffer[pop_index++];
|
||||
#if 0
|
||||
if (pop_index >= ibuffer_len)
|
||||
#else
|
||||
if (pop_index > ibuffer_len)
|
||||
#endif
|
||||
pop_index = 0;
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Stuff KEY into the *front* of the input buffer.
|
||||
Returns non-zero if successful, zero if there is
|
||||
no space left in the buffer. */
|
||||
int
|
||||
_rl_unget_char (key)
|
||||
int key;
|
||||
{
|
||||
if (ibuffer_space ())
|
||||
{
|
||||
pop_index--;
|
||||
if (pop_index < 0)
|
||||
pop_index = ibuffer_len;
|
||||
ibuffer[pop_index] = key;
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
_rl_pushed_input_available ()
|
||||
{
|
||||
return (push_index != pop_index);
|
||||
}
|
||||
|
||||
/* If a character is available to be read, then read it and stuff it into
|
||||
IBUFFER. Otherwise, just return. Returns number of characters read
|
||||
(0 if none available) and -1 on error (EIO). */
|
||||
static int
|
||||
rl_gather_tyi ()
|
||||
{
|
||||
int tty;
|
||||
register int tem, result;
|
||||
int chars_avail, k;
|
||||
char input;
|
||||
#if defined(HAVE_SELECT)
|
||||
fd_set readfds, exceptfds;
|
||||
struct timeval timeout;
|
||||
#endif
|
||||
|
||||
chars_avail = 0;
|
||||
tty = fileno (rl_instream);
|
||||
|
||||
#if defined (HAVE_SELECT)
|
||||
FD_ZERO (&readfds);
|
||||
FD_ZERO (&exceptfds);
|
||||
FD_SET (tty, &readfds);
|
||||
FD_SET (tty, &exceptfds);
|
||||
USEC_TO_TIMEVAL (_keyboard_input_timeout, timeout);
|
||||
result = select (tty + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout);
|
||||
if (result <= 0)
|
||||
return 0; /* Nothing to read. */
|
||||
#endif
|
||||
|
||||
result = -1;
|
||||
#if defined (FIONREAD)
|
||||
errno = 0;
|
||||
result = ioctl (tty, FIONREAD, &chars_avail);
|
||||
if (result == -1 && errno == EIO)
|
||||
return -1;
|
||||
#endif
|
||||
|
||||
#if defined (O_NDELAY)
|
||||
if (result == -1)
|
||||
{
|
||||
tem = fcntl (tty, F_GETFL, 0);
|
||||
|
||||
fcntl (tty, F_SETFL, (tem | O_NDELAY));
|
||||
chars_avail = read (tty, &input, 1);
|
||||
|
||||
fcntl (tty, F_SETFL, tem);
|
||||
if (chars_avail == -1 && errno == EAGAIN)
|
||||
return 0;
|
||||
if (chars_avail == 0) /* EOF */
|
||||
{
|
||||
rl_stuff_char (EOF);
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
#endif /* O_NDELAY */
|
||||
|
||||
#if defined (__MINGW32__)
|
||||
/* Use getch/_kbhit to check for available console input, in the same way
|
||||
that we read it normally. */
|
||||
chars_avail = isatty (tty) ? _kbhit () : 0;
|
||||
result = 0;
|
||||
#endif
|
||||
|
||||
/* If there's nothing available, don't waste time trying to read
|
||||
something. */
|
||||
if (chars_avail <= 0)
|
||||
return 0;
|
||||
|
||||
tem = ibuffer_space ();
|
||||
|
||||
if (chars_avail > tem)
|
||||
chars_avail = tem;
|
||||
|
||||
/* One cannot read all of the available input. I can only read a single
|
||||
character at a time, or else programs which require input can be
|
||||
thwarted. If the buffer is larger than one character, I lose.
|
||||
Damn! */
|
||||
if (tem < ibuffer_len)
|
||||
chars_avail = 0;
|
||||
|
||||
if (result != -1)
|
||||
{
|
||||
while (chars_avail--)
|
||||
{
|
||||
RL_CHECK_SIGNALS ();
|
||||
k = (*rl_getc_function) (rl_instream);
|
||||
if (rl_stuff_char (k) == 0)
|
||||
break; /* some problem; no more room */
|
||||
if (k == NEWLINE || k == RETURN)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (chars_avail)
|
||||
rl_stuff_char (input);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
rl_set_keyboard_input_timeout (u)
|
||||
int u;
|
||||
{
|
||||
int o;
|
||||
|
||||
o = _keyboard_input_timeout;
|
||||
if (u >= 0)
|
||||
_keyboard_input_timeout = u;
|
||||
return (o);
|
||||
}
|
||||
|
||||
/* Is there input available to be read on the readline input file
|
||||
descriptor? Only works if the system has select(2) or FIONREAD.
|
||||
Uses the value of _keyboard_input_timeout as the timeout; if another
|
||||
readline function wants to specify a timeout and not leave it up to
|
||||
the user, it should use _rl_input_queued(timeout_value_in_microseconds)
|
||||
instead. */
|
||||
int
|
||||
_rl_input_available ()
|
||||
{
|
||||
#if defined(HAVE_SELECT)
|
||||
fd_set readfds, exceptfds;
|
||||
struct timeval timeout;
|
||||
#endif
|
||||
#if !defined (HAVE_SELECT) && defined(FIONREAD)
|
||||
int chars_avail;
|
||||
#endif
|
||||
int tty;
|
||||
|
||||
if (rl_input_available_hook)
|
||||
return (*rl_input_available_hook) ();
|
||||
|
||||
tty = fileno (rl_instream);
|
||||
|
||||
#if defined (HAVE_SELECT)
|
||||
FD_ZERO (&readfds);
|
||||
FD_ZERO (&exceptfds);
|
||||
FD_SET (tty, &readfds);
|
||||
FD_SET (tty, &exceptfds);
|
||||
timeout.tv_sec = 0;
|
||||
timeout.tv_usec = _keyboard_input_timeout;
|
||||
return (select (tty + 1, &readfds, (fd_set *)NULL, &exceptfds, &timeout) > 0);
|
||||
#else
|
||||
|
||||
#if defined (FIONREAD)
|
||||
if (ioctl (tty, FIONREAD, &chars_avail) == 0)
|
||||
return (chars_avail);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined (__MINGW32__)
|
||||
if (isatty (tty))
|
||||
return (_kbhit ());
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
_rl_input_queued (t)
|
||||
int t;
|
||||
{
|
||||
int old_timeout, r;
|
||||
|
||||
old_timeout = rl_set_keyboard_input_timeout (t);
|
||||
r = _rl_input_available ();
|
||||
rl_set_keyboard_input_timeout (old_timeout);
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
_rl_insert_typein (c)
|
||||
int c;
|
||||
{
|
||||
int key, t, i;
|
||||
char *string;
|
||||
|
||||
i = key = 0;
|
||||
string = (char *)xmalloc (ibuffer_len + 1);
|
||||
string[i++] = (char) c;
|
||||
|
||||
while ((t = rl_get_char (&key)) &&
|
||||
_rl_keymap[key].type == ISFUNC &&
|
||||
_rl_keymap[key].function == rl_insert)
|
||||
string[i++] = key;
|
||||
|
||||
if (t)
|
||||
_rl_unget_char (key);
|
||||
|
||||
string[i] = '\0';
|
||||
rl_insert_text (string);
|
||||
xfree (string);
|
||||
}
|
||||
|
||||
/* Add KEY to the buffer of characters to be read. Returns 1 if the
|
||||
character was stuffed correctly; 0 otherwise. */
|
||||
int
|
||||
rl_stuff_char (key)
|
||||
int key;
|
||||
{
|
||||
if (ibuffer_space () == 0)
|
||||
return 0;
|
||||
|
||||
if (key == EOF)
|
||||
{
|
||||
key = NEWLINE;
|
||||
rl_pending_input = EOF;
|
||||
RL_SETSTATE (RL_STATE_INPUTPENDING);
|
||||
}
|
||||
ibuffer[push_index++] = key;
|
||||
#if 0
|
||||
if (push_index >= ibuffer_len)
|
||||
#else
|
||||
if (push_index > ibuffer_len)
|
||||
#endif
|
||||
push_index = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Make C be the next command to be executed. */
|
||||
int
|
||||
rl_execute_next (c)
|
||||
int c;
|
||||
{
|
||||
rl_pending_input = c;
|
||||
RL_SETSTATE (RL_STATE_INPUTPENDING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Clear any pending input pushed with rl_execute_next() */
|
||||
int
|
||||
rl_clear_pending_input ()
|
||||
{
|
||||
rl_pending_input = 0;
|
||||
RL_UNSETSTATE (RL_STATE_INPUTPENDING);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Character Input */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* Read a key, including pending input. */
|
||||
int
|
||||
rl_read_key ()
|
||||
{
|
||||
int c, r;
|
||||
|
||||
if (rl_pending_input)
|
||||
{
|
||||
c = rl_pending_input;
|
||||
rl_clear_pending_input ();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If input is coming from a macro, then use that. */
|
||||
if (c = _rl_next_macro_key ())
|
||||
return (c);
|
||||
|
||||
/* If the user has an event function, then call it periodically. */
|
||||
if (rl_event_hook)
|
||||
{
|
||||
while (rl_event_hook)
|
||||
{
|
||||
if (rl_get_char (&c) != 0)
|
||||
break;
|
||||
|
||||
if ((r = rl_gather_tyi ()) < 0) /* XXX - EIO */
|
||||
{
|
||||
rl_done = 1;
|
||||
return ('\n');
|
||||
}
|
||||
else if (r > 0) /* read something */
|
||||
continue;
|
||||
|
||||
RL_CHECK_SIGNALS ();
|
||||
if (rl_done) /* XXX - experimental */
|
||||
return ('\n');
|
||||
(*rl_event_hook) ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rl_get_char (&c) == 0)
|
||||
c = (*rl_getc_function) (rl_instream);
|
||||
/* fprintf(stderr, "rl_read_key: calling RL_CHECK_SIGNALS: _rl_caught_signal = %d", _rl_caught_signal); */
|
||||
RL_CHECK_SIGNALS ();
|
||||
}
|
||||
}
|
||||
|
||||
return (c);
|
||||
}
|
||||
|
||||
int
|
||||
rl_getc (stream)
|
||||
FILE *stream;
|
||||
{
|
||||
int result;
|
||||
unsigned char c;
|
||||
|
||||
while (1)
|
||||
{
|
||||
RL_CHECK_SIGNALS ();
|
||||
|
||||
/* We know at this point that _rl_caught_signal == 0 */
|
||||
|
||||
#if defined (__MINGW32__)
|
||||
if (isatty (fileno (stream)))
|
||||
return (getch ());
|
||||
#endif
|
||||
result = read (fileno (stream), &c, sizeof (unsigned char));
|
||||
|
||||
if (result == sizeof (unsigned char))
|
||||
return (c);
|
||||
|
||||
/* If zero characters are returned, then the file that we are
|
||||
reading from is empty! Return EOF in that case. */
|
||||
if (result == 0)
|
||||
return (EOF);
|
||||
|
||||
#if defined (__BEOS__)
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
#if defined (EWOULDBLOCK)
|
||||
# define X_EWOULDBLOCK EWOULDBLOCK
|
||||
#else
|
||||
# define X_EWOULDBLOCK -99
|
||||
#endif
|
||||
|
||||
#if defined (EAGAIN)
|
||||
# define X_EAGAIN EAGAIN
|
||||
#else
|
||||
# define X_EAGAIN -99
|
||||
#endif
|
||||
|
||||
if (errno == X_EWOULDBLOCK || errno == X_EAGAIN)
|
||||
{
|
||||
if (sh_unset_nodelay_mode (fileno (stream)) < 0)
|
||||
return (EOF);
|
||||
continue;
|
||||
}
|
||||
|
||||
#undef X_EWOULDBLOCK
|
||||
#undef X_EAGAIN
|
||||
|
||||
fprintf(stderr, "rl_getc: result = %d errno = %d\n", result, errno);
|
||||
|
||||
/* If the error that we received was EINTR, then try again,
|
||||
this is simply an interrupted system call to read (). We allow
|
||||
the read to be interrupted if we caught SIGHUP or SIGTERM (but
|
||||
not SIGINT; let the signal handler deal with that), but if the
|
||||
application sets an event hook, call it for other signals.
|
||||
Otherwise (not EINTR), some error ocurred, also signifying EOF. */
|
||||
if (errno != EINTR)
|
||||
return (RL_ISSTATE (RL_STATE_READCMD) ? READERR : EOF);
|
||||
else if (_rl_caught_signal == SIGHUP || _rl_caught_signal == SIGTERM)
|
||||
return (RL_ISSTATE (RL_STATE_READCMD) ? READERR : EOF);
|
||||
else if (_rl_caught_signal == SIGINT || _rl_caught_signal == SIGQUIT)
|
||||
RL_CHECK_SIGNALS ();
|
||||
|
||||
if (rl_event_hook)
|
||||
{
|
||||
fprintf(stderr, "rl_getc: calling rl_event_hook\n");
|
||||
(*rl_event_hook) ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined (HANDLE_MULTIBYTE)
|
||||
/* read multibyte char */
|
||||
int
|
||||
_rl_read_mbchar (mbchar, size)
|
||||
char *mbchar;
|
||||
int size;
|
||||
{
|
||||
int mb_len, c;
|
||||
size_t mbchar_bytes_length;
|
||||
wchar_t wc;
|
||||
mbstate_t ps, ps_back;
|
||||
|
||||
memset(&ps, 0, sizeof (mbstate_t));
|
||||
memset(&ps_back, 0, sizeof (mbstate_t));
|
||||
|
||||
mb_len = 0;
|
||||
while (mb_len < size)
|
||||
{
|
||||
RL_SETSTATE(RL_STATE_MOREINPUT);
|
||||
c = rl_read_key ();
|
||||
RL_UNSETSTATE(RL_STATE_MOREINPUT);
|
||||
|
||||
if (c < 0)
|
||||
break;
|
||||
|
||||
mbchar[mb_len++] = c;
|
||||
|
||||
mbchar_bytes_length = mbrtowc (&wc, mbchar, mb_len, &ps);
|
||||
if (mbchar_bytes_length == (size_t)(-1))
|
||||
break; /* invalid byte sequence for the current locale */
|
||||
else if (mbchar_bytes_length == (size_t)(-2))
|
||||
{
|
||||
/* shorted bytes */
|
||||
ps = ps_back;
|
||||
continue;
|
||||
}
|
||||
else if (mbchar_bytes_length == 0)
|
||||
{
|
||||
mbchar[0] = '\0'; /* null wide character */
|
||||
mb_len = 1;
|
||||
break;
|
||||
}
|
||||
else if (mbchar_bytes_length > (size_t)(0))
|
||||
break;
|
||||
}
|
||||
|
||||
return mb_len;
|
||||
}
|
||||
|
||||
/* Read a multibyte-character string whose first character is FIRST into
|
||||
the buffer MB of length MLEN. Returns the last character read, which
|
||||
may be FIRST. Used by the search functions, among others. Very similar
|
||||
to _rl_read_mbchar. */
|
||||
int
|
||||
_rl_read_mbstring (first, mb, mlen)
|
||||
int first;
|
||||
char *mb;
|
||||
int mlen;
|
||||
{
|
||||
int i, c;
|
||||
mbstate_t ps;
|
||||
|
||||
c = first;
|
||||
memset (mb, 0, mlen);
|
||||
for (i = 0; c >= 0 && i < mlen; i++)
|
||||
{
|
||||
mb[i] = (char)c;
|
||||
memset (&ps, 0, sizeof (mbstate_t));
|
||||
if (_rl_get_char_len (mb, &ps) == -2)
|
||||
{
|
||||
/* Read more for multibyte character */
|
||||
RL_SETSTATE (RL_STATE_MOREINPUT);
|
||||
c = rl_read_key ();
|
||||
RL_UNSETSTATE (RL_STATE_MOREINPUT);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
#endif /* HANDLE_MULTIBYTE */
|
||||
@@ -348,6 +348,7 @@ rl_maybe_set_sighandler (sig, handler, ohandler)
|
||||
SigHandler *oh;
|
||||
|
||||
sigemptyset (&dummy.sa_mask);
|
||||
dummy.sa_flags = 0;
|
||||
oh = rl_set_sighandler (sig, handler, ohandler);
|
||||
if (oh == (SigHandler *)SIG_IGN)
|
||||
rl_sigaction (sig, ohandler, &dummy);
|
||||
@@ -365,6 +366,7 @@ rl_maybe_restore_sighandler (sig, handler)
|
||||
sighandler_cxt dummy;
|
||||
|
||||
sigemptyset (&dummy.sa_mask);
|
||||
dummy.sa_flags = 0;
|
||||
if (handler->sa_handler != SIG_IGN)
|
||||
rl_sigaction (sig, handler, &dummy);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,700 @@
|
||||
/* signals.c -- signal handling support for readline. */
|
||||
|
||||
/* Copyright (C) 1987-2011 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.
|
||||
|
||||
Readline 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.
|
||||
|
||||
Readline 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 Readline. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define READLINE_LIBRARY
|
||||
|
||||
#if defined (HAVE_CONFIG_H)
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h> /* Just for NULL. Yuck. */
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif /* HAVE_UNISTD_H */
|
||||
|
||||
/* System-specific feature definitions and include files. */
|
||||
#include "rldefs.h"
|
||||
|
||||
#if defined (GWINSZ_IN_SYS_IOCTL)
|
||||
# include <sys/ioctl.h>
|
||||
#endif /* GWINSZ_IN_SYS_IOCTL */
|
||||
|
||||
/* Some standard library routines. */
|
||||
#include "readline.h"
|
||||
#include "history.h"
|
||||
|
||||
#include "rlprivate.h"
|
||||
|
||||
#if defined (HANDLE_SIGNALS)
|
||||
|
||||
#if !defined (RETSIGTYPE)
|
||||
# if defined (VOID_SIGHANDLER)
|
||||
# define RETSIGTYPE void
|
||||
# else
|
||||
# define RETSIGTYPE int
|
||||
# endif /* !VOID_SIGHANDLER */
|
||||
#endif /* !RETSIGTYPE */
|
||||
|
||||
#if defined (VOID_SIGHANDLER)
|
||||
# define SIGHANDLER_RETURN return
|
||||
#else
|
||||
# define SIGHANDLER_RETURN return (0)
|
||||
#endif
|
||||
|
||||
/* This typedef is equivalent to the one for Function; it allows us
|
||||
to say SigHandler *foo = signal (SIGKILL, SIG_IGN); */
|
||||
typedef RETSIGTYPE SigHandler ();
|
||||
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
typedef struct sigaction sighandler_cxt;
|
||||
# define rl_sigaction(s, nh, oh) sigaction(s, nh, oh)
|
||||
#else
|
||||
typedef struct { SigHandler *sa_handler; int sa_mask, sa_flags; } sighandler_cxt;
|
||||
# define sigemptyset(m)
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
#ifndef SA_RESTART
|
||||
# define SA_RESTART 0
|
||||
#endif
|
||||
|
||||
static SigHandler *rl_set_sighandler PARAMS((int, SigHandler *, sighandler_cxt *));
|
||||
static void rl_maybe_set_sighandler PARAMS((int, SigHandler *, sighandler_cxt *));
|
||||
static void rl_maybe_restore_sighandler PARAMS((int, sighandler_cxt *));
|
||||
|
||||
static RETSIGTYPE rl_signal_handler PARAMS((int));
|
||||
static RETSIGTYPE _rl_handle_signal PARAMS((int));
|
||||
|
||||
/* Exported variables for use by applications. */
|
||||
|
||||
/* If non-zero, readline will install its own signal handlers for
|
||||
SIGINT, SIGTERM, SIGHUP, SIGQUIT, SIGALRM, SIGTSTP, SIGTTIN, and SIGTTOU. */
|
||||
int rl_catch_signals = 1;
|
||||
|
||||
/* If non-zero, readline will install a signal handler for SIGWINCH. */
|
||||
#ifdef SIGWINCH
|
||||
int rl_catch_sigwinch = 1;
|
||||
#else
|
||||
int rl_catch_sigwinch = 0; /* for the readline state struct in readline.c */
|
||||
#endif
|
||||
|
||||
/* Private variables. */
|
||||
int _rl_interrupt_immediately = 0;
|
||||
int volatile _rl_caught_signal = 0; /* should be sig_atomic_t, but that requires including <signal.h> everywhere */
|
||||
|
||||
/* If non-zero, print characters corresponding to received signals as long as
|
||||
the user has indicated his desire to do so (_rl_echo_control_chars). */
|
||||
int _rl_echoctl = 0;
|
||||
|
||||
int _rl_intr_char = 0;
|
||||
int _rl_quit_char = 0;
|
||||
int _rl_susp_char = 0;
|
||||
|
||||
static int signals_set_flag;
|
||||
static int sigwinch_set_flag;
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Signal Handling */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
static sighandler_cxt old_int, old_term, old_hup, old_alrm, old_quit;
|
||||
#if defined (SIGTSTP)
|
||||
static sighandler_cxt old_tstp, old_ttou, old_ttin;
|
||||
#endif
|
||||
#if defined (SIGWINCH)
|
||||
static sighandler_cxt old_winch;
|
||||
#endif
|
||||
|
||||
_rl_sigcleanup_func_t *_rl_sigcleanup;
|
||||
void *_rl_sigcleanarg;
|
||||
|
||||
/* Readline signal handler functions. */
|
||||
|
||||
/* Called from RL_CHECK_SIGNALS() macro */
|
||||
RETSIGTYPE
|
||||
_rl_signal_handler (sig)
|
||||
int sig;
|
||||
{
|
||||
_rl_caught_signal = 0; /* XXX */
|
||||
|
||||
#if defined (SIGWINCH)
|
||||
if (sig == SIGWINCH)
|
||||
rl_resize_terminal ();
|
||||
else
|
||||
#endif
|
||||
_rl_handle_signal (sig);
|
||||
SIGHANDLER_RETURN;
|
||||
}
|
||||
|
||||
static RETSIGTYPE
|
||||
rl_signal_handler (sig)
|
||||
int sig;
|
||||
{
|
||||
if (_rl_interrupt_immediately)
|
||||
{
|
||||
_rl_interrupt_immediately = 0;
|
||||
_rl_handle_signal (sig);
|
||||
}
|
||||
else
|
||||
_rl_caught_signal = sig;
|
||||
|
||||
SIGHANDLER_RETURN;
|
||||
}
|
||||
|
||||
static RETSIGTYPE
|
||||
_rl_handle_signal (sig)
|
||||
int sig;
|
||||
{
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
sigset_t set;
|
||||
#else /* !HAVE_POSIX_SIGNALS */
|
||||
# if defined (HAVE_BSD_SIGNALS)
|
||||
long omask;
|
||||
# else /* !HAVE_BSD_SIGNALS */
|
||||
sighandler_cxt dummy_cxt; /* needed for rl_set_sighandler call */
|
||||
# endif /* !HAVE_BSD_SIGNALS */
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
RL_SETSTATE(RL_STATE_SIGHANDLER);
|
||||
|
||||
#if !defined (HAVE_BSD_SIGNALS) && !defined (HAVE_POSIX_SIGNALS)
|
||||
/* Since the signal will not be blocked while we are in the signal
|
||||
handler, ignore it until rl_clear_signals resets the catcher. */
|
||||
# if defined (SIGALRM)
|
||||
if (sig == SIGINT || sig == SIGALRM)
|
||||
# else
|
||||
if (sig == SIGINT)
|
||||
# endif
|
||||
rl_set_sighandler (sig, SIG_IGN, &dummy_cxt);
|
||||
#endif /* !HAVE_BSD_SIGNALS && !HAVE_POSIX_SIGNALS */
|
||||
|
||||
/* If there's a sig cleanup function registered, call it and `deregister'
|
||||
the cleanup function to avoid multiple calls */
|
||||
if (_rl_sigcleanup)
|
||||
{
|
||||
(*_rl_sigcleanup) (sig, _rl_sigcleanarg);
|
||||
_rl_sigcleanup = 0;
|
||||
_rl_sigcleanarg = 0;
|
||||
}
|
||||
|
||||
switch (sig)
|
||||
{
|
||||
case SIGINT:
|
||||
_rl_reset_completion_state ();
|
||||
rl_free_line_state ();
|
||||
/* FALLTHROUGH */
|
||||
|
||||
case SIGTERM:
|
||||
case SIGHUP:
|
||||
#if defined (SIGTSTP)
|
||||
case SIGTSTP:
|
||||
case SIGTTOU:
|
||||
case SIGTTIN:
|
||||
#endif /* SIGTSTP */
|
||||
#if defined (SIGALRM)
|
||||
case SIGALRM:
|
||||
#endif
|
||||
#if defined (SIGQUIT)
|
||||
case SIGQUIT:
|
||||
#endif
|
||||
rl_echo_signal_char (sig);
|
||||
rl_cleanup_after_signal ();
|
||||
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
sigemptyset (&set);
|
||||
sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &set);
|
||||
sigdelset (&set, sig);
|
||||
#else /* !HAVE_POSIX_SIGNALS */
|
||||
# if defined (HAVE_BSD_SIGNALS)
|
||||
omask = sigblock (0);
|
||||
# endif /* HAVE_BSD_SIGNALS */
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
#if defined (__EMX__)
|
||||
signal (sig, SIG_ACK);
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_KILL)
|
||||
kill (getpid (), sig);
|
||||
#else
|
||||
raise (sig); /* assume we have raise */
|
||||
#endif
|
||||
|
||||
/* Let the signal that we just sent through. */
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
sigprocmask (SIG_SETMASK, &set, (sigset_t *)NULL);
|
||||
#else /* !HAVE_POSIX_SIGNALS */
|
||||
# if defined (HAVE_BSD_SIGNALS)
|
||||
sigsetmask (omask & ~(sigmask (sig)));
|
||||
# endif /* HAVE_BSD_SIGNALS */
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
rl_reset_after_signal ();
|
||||
}
|
||||
|
||||
RL_UNSETSTATE(RL_STATE_SIGHANDLER);
|
||||
SIGHANDLER_RETURN;
|
||||
}
|
||||
|
||||
#if defined (SIGWINCH)
|
||||
static RETSIGTYPE
|
||||
rl_sigwinch_handler (sig)
|
||||
int sig;
|
||||
{
|
||||
SigHandler *oh;
|
||||
|
||||
#if defined (MUST_REINSTALL_SIGHANDLERS)
|
||||
sighandler_cxt dummy_winch;
|
||||
|
||||
/* We don't want to change old_winch -- it holds the state of SIGWINCH
|
||||
disposition set by the calling application. We need this state
|
||||
because we call the application's SIGWINCH handler after updating
|
||||
our own idea of the screen size. */
|
||||
rl_set_sighandler (SIGWINCH, rl_sigwinch_handler, &dummy_winch);
|
||||
#endif
|
||||
|
||||
RL_SETSTATE(RL_STATE_SIGHANDLER);
|
||||
_rl_caught_signal = sig;
|
||||
|
||||
/* If another sigwinch handler has been installed, call it. */
|
||||
oh = (SigHandler *)old_winch.sa_handler;
|
||||
if (oh && oh != (SigHandler *)SIG_IGN && oh != (SigHandler *)SIG_DFL)
|
||||
(*oh) (sig);
|
||||
|
||||
RL_UNSETSTATE(RL_STATE_SIGHANDLER);
|
||||
SIGHANDLER_RETURN;
|
||||
}
|
||||
#endif /* SIGWINCH */
|
||||
|
||||
/* Functions to manage signal handling. */
|
||||
|
||||
#if !defined (HAVE_POSIX_SIGNALS)
|
||||
static int
|
||||
rl_sigaction (sig, nh, oh)
|
||||
int sig;
|
||||
sighandler_cxt *nh, *oh;
|
||||
{
|
||||
oh->sa_handler = signal (sig, nh->sa_handler);
|
||||
return 0;
|
||||
}
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
/* Set up a readline-specific signal handler, saving the old signal
|
||||
information in OHANDLER. Return the old signal handler, like
|
||||
signal(). */
|
||||
static SigHandler *
|
||||
rl_set_sighandler (sig, handler, ohandler)
|
||||
int sig;
|
||||
SigHandler *handler;
|
||||
sighandler_cxt *ohandler;
|
||||
{
|
||||
sighandler_cxt old_handler;
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
struct sigaction act;
|
||||
|
||||
act.sa_handler = handler;
|
||||
# if defined (SIGWINCH)
|
||||
act.sa_flags = (sig == SIGWINCH) ? SA_RESTART : 0;
|
||||
# else
|
||||
act.sa_flags = 0;
|
||||
# endif /* SIGWINCH */
|
||||
sigemptyset (&act.sa_mask);
|
||||
sigemptyset (&ohandler->sa_mask);
|
||||
sigaction (sig, &act, &old_handler);
|
||||
#else
|
||||
old_handler.sa_handler = (SigHandler *)signal (sig, handler);
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
/* XXX -- assume we have memcpy */
|
||||
/* If rl_set_signals is called twice in a row, don't set the old handler to
|
||||
rl_signal_handler, because that would cause infinite recursion. */
|
||||
if (handler != rl_signal_handler || old_handler.sa_handler != rl_signal_handler)
|
||||
memcpy (ohandler, &old_handler, sizeof (sighandler_cxt));
|
||||
|
||||
return (ohandler->sa_handler);
|
||||
}
|
||||
|
||||
/* Set disposition of SIG to HANDLER, returning old state in OHANDLER. Don't
|
||||
change disposition if OHANDLER indicates the signal was ignored. */
|
||||
static void
|
||||
rl_maybe_set_sighandler (sig, handler, ohandler)
|
||||
int sig;
|
||||
SigHandler *handler;
|
||||
sighandler_cxt *ohandler;
|
||||
{
|
||||
sighandler_cxt dummy;
|
||||
SigHandler *oh;
|
||||
|
||||
sigemptyset (&dummy.sa_mask);
|
||||
dummy.sa_flags = 0;
|
||||
oh = rl_set_sighandler (sig, handler, ohandler);
|
||||
if (oh == (SigHandler *)SIG_IGN)
|
||||
rl_sigaction (sig, ohandler, &dummy);
|
||||
}
|
||||
|
||||
/* Set the disposition of SIG to HANDLER, if HANDLER->sa_handler indicates the
|
||||
signal was not being ignored. MUST only be called for signals whose
|
||||
disposition was changed using rl_maybe_set_sighandler or for which the
|
||||
SIG_IGN check was performed inline (e.g., SIGALRM below). */
|
||||
static void
|
||||
rl_maybe_restore_sighandler (sig, handler)
|
||||
int sig;
|
||||
sighandler_cxt *handler;
|
||||
{
|
||||
sighandler_cxt dummy;
|
||||
|
||||
sigemptyset (&dummy.sa_mask);
|
||||
dummy.sa_flags = 0;
|
||||
if (handler->sa_handler != SIG_IGN)
|
||||
rl_sigaction (sig, handler, &dummy);
|
||||
}
|
||||
|
||||
int
|
||||
rl_set_signals ()
|
||||
{
|
||||
sighandler_cxt dummy;
|
||||
SigHandler *oh;
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
static int sigmask_set = 0;
|
||||
static sigset_t bset, oset;
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
if (rl_catch_signals && sigmask_set == 0)
|
||||
{
|
||||
sigemptyset (&bset);
|
||||
|
||||
sigaddset (&bset, SIGINT);
|
||||
sigaddset (&bset, SIGTERM);
|
||||
sigaddset (&bset, SIGHUP);
|
||||
#if defined (SIGQUIT)
|
||||
sigaddset (&bset, SIGQUIT);
|
||||
#endif
|
||||
#if defined (SIGALRM)
|
||||
sigaddset (&bset, SIGALRM);
|
||||
#endif
|
||||
#if defined (SIGTSTP)
|
||||
sigaddset (&bset, SIGTSTP);
|
||||
#endif
|
||||
#if defined (SIGTTIN)
|
||||
sigaddset (&bset, SIGTTIN);
|
||||
#endif
|
||||
#if defined (SIGTTOU)
|
||||
sigaddset (&bset, SIGTTOU);
|
||||
#endif
|
||||
sigmask_set = 1;
|
||||
}
|
||||
#endif /* HAVE_POSIX_SIGNALS */
|
||||
|
||||
if (rl_catch_signals && signals_set_flag == 0)
|
||||
{
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
sigemptyset (&oset);
|
||||
sigprocmask (SIG_BLOCK, &bset, &oset);
|
||||
#endif
|
||||
|
||||
rl_maybe_set_sighandler (SIGINT, rl_signal_handler, &old_int);
|
||||
rl_maybe_set_sighandler (SIGTERM, rl_signal_handler, &old_term);
|
||||
rl_maybe_set_sighandler (SIGHUP, rl_signal_handler, &old_hup);
|
||||
#if defined (SIGQUIT)
|
||||
rl_maybe_set_sighandler (SIGQUIT, rl_signal_handler, &old_quit);
|
||||
#endif
|
||||
|
||||
#if defined (SIGALRM)
|
||||
oh = rl_set_sighandler (SIGALRM, rl_signal_handler, &old_alrm);
|
||||
if (oh == (SigHandler *)SIG_IGN)
|
||||
rl_sigaction (SIGALRM, &old_alrm, &dummy);
|
||||
#if defined (HAVE_POSIX_SIGNALS) && defined (SA_RESTART)
|
||||
/* If the application using readline has already installed a signal
|
||||
handler with SA_RESTART, SIGALRM will cause reads to be restarted
|
||||
automatically, so readline should just get out of the way. Since
|
||||
we tested for SIG_IGN above, we can just test for SIG_DFL here. */
|
||||
if (oh != (SigHandler *)SIG_DFL && (old_alrm.sa_flags & SA_RESTART))
|
||||
rl_sigaction (SIGALRM, &old_alrm, &dummy);
|
||||
#endif /* HAVE_POSIX_SIGNALS */
|
||||
#endif /* SIGALRM */
|
||||
|
||||
#if defined (SIGTSTP)
|
||||
rl_maybe_set_sighandler (SIGTSTP, rl_signal_handler, &old_tstp);
|
||||
#endif /* SIGTSTP */
|
||||
|
||||
#if defined (SIGTTOU)
|
||||
rl_maybe_set_sighandler (SIGTTOU, rl_signal_handler, &old_ttou);
|
||||
#endif /* SIGTTOU */
|
||||
|
||||
#if defined (SIGTTIN)
|
||||
rl_maybe_set_sighandler (SIGTTIN, rl_signal_handler, &old_ttin);
|
||||
#endif /* SIGTTIN */
|
||||
|
||||
signals_set_flag = 1;
|
||||
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined (SIGWINCH)
|
||||
if (rl_catch_sigwinch && sigwinch_set_flag == 0)
|
||||
{
|
||||
rl_maybe_set_sighandler (SIGWINCH, rl_sigwinch_handler, &old_winch);
|
||||
sigwinch_set_flag = 1;
|
||||
}
|
||||
#endif /* SIGWINCH */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
rl_clear_signals ()
|
||||
{
|
||||
sighandler_cxt dummy;
|
||||
|
||||
if (rl_catch_signals && signals_set_flag == 1)
|
||||
{
|
||||
sigemptyset (&dummy.sa_mask);
|
||||
|
||||
/* Since rl_maybe_set_sighandler doesn't override a SIG_IGN handler,
|
||||
we should in theory not have to restore a handler where
|
||||
old_xxx.sa_handler == SIG_IGN. That's what rl_maybe_restore_sighandler
|
||||
does. Fewer system calls should reduce readline's per-line
|
||||
overhead */
|
||||
rl_maybe_restore_sighandler (SIGINT, &old_int);
|
||||
rl_maybe_restore_sighandler (SIGTERM, &old_term);
|
||||
rl_maybe_restore_sighandler (SIGHUP, &old_hup);
|
||||
#if defined (SIGQUIT)
|
||||
rl_maybe_restore_sighandler (SIGQUIT, &old_quit);
|
||||
#endif
|
||||
#if defined (SIGALRM)
|
||||
rl_maybe_restore_sighandler (SIGALRM, &old_alrm);
|
||||
#endif
|
||||
|
||||
#if defined (SIGTSTP)
|
||||
rl_maybe_restore_sighandler (SIGTSTP, &old_tstp);
|
||||
#endif /* SIGTSTP */
|
||||
|
||||
#if defined (SIGTTOU)
|
||||
rl_maybe_restore_sighandler (SIGTTOU, &old_ttou);
|
||||
#endif /* SIGTTOU */
|
||||
|
||||
#if defined (SIGTTIN)
|
||||
rl_maybe_restore_sighandler (SIGTTIN, &old_ttin);
|
||||
#endif /* SIGTTIN */
|
||||
|
||||
signals_set_flag = 0;
|
||||
}
|
||||
|
||||
#if defined (SIGWINCH)
|
||||
if (rl_catch_sigwinch && sigwinch_set_flag == 1)
|
||||
{
|
||||
sigemptyset (&dummy.sa_mask);
|
||||
rl_sigaction (SIGWINCH, &old_winch, &dummy);
|
||||
sigwinch_set_flag = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Clean up the terminal and readline state after catching a signal, before
|
||||
resending it to the calling application. */
|
||||
void
|
||||
rl_cleanup_after_signal ()
|
||||
{
|
||||
_rl_clean_up_for_exit ();
|
||||
if (rl_deprep_term_function)
|
||||
(*rl_deprep_term_function) ();
|
||||
rl_clear_pending_input ();
|
||||
rl_clear_signals ();
|
||||
}
|
||||
|
||||
/* Reset the terminal and readline state after a signal handler returns. */
|
||||
void
|
||||
rl_reset_after_signal ()
|
||||
{
|
||||
if (rl_prep_term_function)
|
||||
(*rl_prep_term_function) (_rl_meta_flag);
|
||||
rl_set_signals ();
|
||||
}
|
||||
|
||||
/* Free up the readline variable line state for the current line (undo list,
|
||||
any partial history entry, any keyboard macros in progress, and any
|
||||
numeric arguments in process) after catching a signal, before calling
|
||||
rl_cleanup_after_signal(). */
|
||||
void
|
||||
rl_free_line_state ()
|
||||
{
|
||||
register HIST_ENTRY *entry;
|
||||
|
||||
rl_free_undo_list ();
|
||||
|
||||
entry = current_history ();
|
||||
if (entry)
|
||||
entry->data = (char *)NULL;
|
||||
|
||||
_rl_kill_kbd_macro ();
|
||||
rl_clear_message ();
|
||||
_rl_reset_argument ();
|
||||
}
|
||||
|
||||
#endif /* HANDLE_SIGNALS */
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* SIGINT Management */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
static sigset_t sigint_set, sigint_oset;
|
||||
static sigset_t sigwinch_set, sigwinch_oset;
|
||||
#else /* !HAVE_POSIX_SIGNALS */
|
||||
# if defined (HAVE_BSD_SIGNALS)
|
||||
static int sigint_oldmask;
|
||||
static int sigwinch_oldmask;
|
||||
# endif /* HAVE_BSD_SIGNALS */
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
static int sigint_blocked;
|
||||
static int sigwinch_blocked;
|
||||
|
||||
/* Cause SIGINT to not be delivered until the corresponding call to
|
||||
release_sigint(). */
|
||||
void
|
||||
_rl_block_sigint ()
|
||||
{
|
||||
if (sigint_blocked)
|
||||
return;
|
||||
|
||||
sigint_blocked = 1;
|
||||
}
|
||||
|
||||
/* Allow SIGINT to be delivered. */
|
||||
void
|
||||
_rl_release_sigint ()
|
||||
{
|
||||
if (sigint_blocked == 0)
|
||||
return;
|
||||
|
||||
sigint_blocked = 0;
|
||||
RL_CHECK_SIGNALS ();
|
||||
}
|
||||
|
||||
/* Cause SIGWINCH to not be delivered until the corresponding call to
|
||||
release_sigwinch(). */
|
||||
void
|
||||
_rl_block_sigwinch ()
|
||||
{
|
||||
if (sigwinch_blocked)
|
||||
return;
|
||||
|
||||
#if defined (SIGWINCH)
|
||||
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
sigemptyset (&sigwinch_set);
|
||||
sigemptyset (&sigwinch_oset);
|
||||
sigaddset (&sigwinch_set, SIGWINCH);
|
||||
sigprocmask (SIG_BLOCK, &sigwinch_set, &sigwinch_oset);
|
||||
#else /* !HAVE_POSIX_SIGNALS */
|
||||
# if defined (HAVE_BSD_SIGNALS)
|
||||
sigwinch_oldmask = sigblock (sigmask (SIGWINCH));
|
||||
# else /* !HAVE_BSD_SIGNALS */
|
||||
# if defined (HAVE_USG_SIGHOLD)
|
||||
sighold (SIGWINCH);
|
||||
# endif /* HAVE_USG_SIGHOLD */
|
||||
# endif /* !HAVE_BSD_SIGNALS */
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
#endif /* SIGWINCH */
|
||||
|
||||
sigwinch_blocked = 1;
|
||||
}
|
||||
|
||||
/* Allow SIGWINCH to be delivered. */
|
||||
void
|
||||
_rl_release_sigwinch ()
|
||||
{
|
||||
if (sigwinch_blocked == 0)
|
||||
return;
|
||||
|
||||
#if defined (SIGWINCH)
|
||||
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
sigprocmask (SIG_SETMASK, &sigwinch_oset, (sigset_t *)NULL);
|
||||
#else
|
||||
# if defined (HAVE_BSD_SIGNALS)
|
||||
sigsetmask (sigwinch_oldmask);
|
||||
# else /* !HAVE_BSD_SIGNALS */
|
||||
# if defined (HAVE_USG_SIGHOLD)
|
||||
sigrelse (SIGWINCH);
|
||||
# endif /* HAVE_USG_SIGHOLD */
|
||||
# endif /* !HAVE_BSD_SIGNALS */
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
#endif /* SIGWINCH */
|
||||
|
||||
sigwinch_blocked = 0;
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Echoing special control characters */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
void
|
||||
rl_echo_signal_char (sig)
|
||||
int sig;
|
||||
{
|
||||
char cstr[3];
|
||||
int cslen, c;
|
||||
|
||||
if (_rl_echoctl == 0 || _rl_echo_control_chars == 0)
|
||||
return;
|
||||
|
||||
switch (sig)
|
||||
{
|
||||
case SIGINT: c = _rl_intr_char; break;
|
||||
#if defined (SIGQUIT)
|
||||
case SIGQUIT: c = _rl_quit_char; break;
|
||||
#endif
|
||||
#if defined (SIGTSTP)
|
||||
case SIGTSTP: c = _rl_susp_char; break;
|
||||
#endif
|
||||
default: return;
|
||||
}
|
||||
|
||||
if (CTRL_CHAR (c) || c == RUBOUT)
|
||||
{
|
||||
cstr[0] = '^';
|
||||
cstr[1] = CTRL_CHAR (c) ? UNCTRL (c) : '?';
|
||||
cstr[cslen = 2] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
cstr[0] = c;
|
||||
cstr[cslen = 1] = '\0';
|
||||
}
|
||||
|
||||
_rl_output_some_chars (cstr, cslen);
|
||||
}
|
||||
+1
-1
@@ -47,7 +47,7 @@ zread (fd, buf, len)
|
||||
ssize_t r;
|
||||
|
||||
while ((r = read (fd, buf, len)) < 0 && errno == EINTR)
|
||||
;
|
||||
check_signals_and_traps (); /* XXX */
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
/* zread - read data from file descriptor into buffer with retries */
|
||||
|
||||
/* Copyright (C) 1999-2002 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#ifndef SEEK_CUR
|
||||
# define SEEK_CUR 1
|
||||
#endif
|
||||
|
||||
/* Read LEN bytes from FD into BUF. Retry the read on EINTR. Any other
|
||||
error causes the loop to break. */
|
||||
ssize_t
|
||||
zread (fd, buf, len)
|
||||
int fd;
|
||||
char *buf;
|
||||
size_t len;
|
||||
{
|
||||
ssize_t r;
|
||||
|
||||
while ((r = read (fd, buf, len)) < 0 && errno == EINTR)
|
||||
check_signals_and_traps (); /* XXX */
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Read LEN bytes from FD into BUF. Retry the read on EINTR, up to three
|
||||
interrupts. Any other error causes the loop to break. */
|
||||
|
||||
#ifdef NUM_INTR
|
||||
# undef NUM_INTR
|
||||
#endif
|
||||
#define NUM_INTR 3
|
||||
|
||||
ssize_t
|
||||
zreadretry (fd, buf, len)
|
||||
int fd;
|
||||
char *buf;
|
||||
size_t len;
|
||||
{
|
||||
ssize_t r;
|
||||
int nintr;
|
||||
|
||||
for (nintr = 0; ; )
|
||||
{
|
||||
r = read (fd, buf, len);
|
||||
if (r >= 0)
|
||||
return r;
|
||||
if (r == -1 && errno == EINTR)
|
||||
{
|
||||
if (++nintr >= NUM_INTR)
|
||||
return -1;
|
||||
continue;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
/* Call read(2) and allow it to be interrupted. Just a stub for now. */
|
||||
ssize_t
|
||||
zreadintr (fd, buf, len)
|
||||
int fd;
|
||||
char *buf;
|
||||
size_t len;
|
||||
{
|
||||
return (read (fd, buf, len));
|
||||
}
|
||||
|
||||
/* Read one character from FD and return it in CP. Return values are as
|
||||
in read(2). This does some local buffering to avoid many one-character
|
||||
calls to read(2), like those the `read' builtin performs. */
|
||||
|
||||
static char lbuf[128];
|
||||
static size_t lind, lused;
|
||||
|
||||
ssize_t
|
||||
zreadc (fd, cp)
|
||||
int fd;
|
||||
char *cp;
|
||||
{
|
||||
ssize_t nr;
|
||||
|
||||
if (lind == lused || lused == 0)
|
||||
{
|
||||
nr = zread (fd, lbuf, sizeof (lbuf));
|
||||
lind = 0;
|
||||
if (nr <= 0)
|
||||
{
|
||||
lused = 0;
|
||||
return nr;
|
||||
}
|
||||
lused = nr;
|
||||
}
|
||||
if (cp)
|
||||
*cp = lbuf[lind++];
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Don't mix calls to zreadc and zreadcintr in the same function, since they
|
||||
use the same local buffer. */
|
||||
ssize_t
|
||||
zreadcintr (fd, cp)
|
||||
int fd;
|
||||
char *cp;
|
||||
{
|
||||
ssize_t nr;
|
||||
|
||||
if (lind == lused || lused == 0)
|
||||
{
|
||||
nr = zreadintr (fd, lbuf, sizeof (lbuf));
|
||||
lind = 0;
|
||||
if (nr <= 0)
|
||||
{
|
||||
lused = 0;
|
||||
return nr;
|
||||
}
|
||||
lused = nr;
|
||||
}
|
||||
if (cp)
|
||||
*cp = lbuf[lind++];
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
zreset ()
|
||||
{
|
||||
lind = lused = 0;
|
||||
}
|
||||
|
||||
/* Sync the seek pointer for FD so that the kernel's idea of the last char
|
||||
read is the last char returned by zreadc. */
|
||||
void
|
||||
zsyncfd (fd)
|
||||
int fd;
|
||||
{
|
||||
off_t off, r;
|
||||
|
||||
off = lused - lind;
|
||||
r = 0;
|
||||
if (off > 0)
|
||||
r = lseek (fd, -off, SEEK_CUR);
|
||||
|
||||
if (r != -1)
|
||||
lused = lind = 0;
|
||||
}
|
||||
@@ -1435,7 +1435,7 @@ yy_readline_get ()
|
||||
old_sigint = (SigHandler *)IMPOSSIBLE_TRAP_HANDLER;
|
||||
if (signal_is_ignored (SIGINT) == 0)
|
||||
{
|
||||
interrupt_immediately++;
|
||||
/* interrupt_immediately++; */
|
||||
old_sigint = (SigHandler *)set_signal_handler (SIGINT, sigint_sighandler);
|
||||
}
|
||||
|
||||
@@ -1445,7 +1445,7 @@ yy_readline_get ()
|
||||
CHECK_TERMSIG;
|
||||
if (signal_is_ignored (SIGINT) == 0)
|
||||
{
|
||||
interrupt_immediately--;
|
||||
/* interrupt_immediately--; */
|
||||
if (old_sigint != IMPOSSIBLE_TRAP_HANDLER)
|
||||
set_signal_handler (SIGINT, old_sigint);
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,2 +1,2 @@
|
||||
# Set of available languages.
|
||||
en@quot en@boldquot af bg ca cs da de eo es et fi fr ga gl hu id it ja lt nl pl pt_BR ro ru sk sl sv tr uk vi zh_CN zh_TW
|
||||
en@quot en@boldquot af bg ca cs da de eo es et fi fr ga gl hr hu id it ja lt nl pl pt_BR ro ru sk sl sv tr uk vi zh_CN zh_TW
|
||||
|
||||
+3944
File diff suppressed because it is too large
Load Diff
@@ -590,6 +590,10 @@ sigint_sighandler (sig)
|
||||
last_command_exit_value = 128 + sig;
|
||||
throw_to_top_level ();
|
||||
}
|
||||
#if defined (READLINE)
|
||||
else if (RL_ISSTATE (RL_STATE_SIGHANDLER))
|
||||
bashline_set_event_hook ();
|
||||
#endif
|
||||
|
||||
SIGRETURN (0);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,698 @@
|
||||
/* sig.c - interface for shell signal handlers and signal initialization. */
|
||||
|
||||
/* Copyright (C) 1994-2012 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "bashtypes.h"
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "bashintl.h"
|
||||
|
||||
#include "shell.h"
|
||||
#if defined (JOB_CONTROL)
|
||||
#include "jobs.h"
|
||||
#endif /* JOB_CONTROL */
|
||||
#include "siglist.h"
|
||||
#include "sig.h"
|
||||
#include "trap.h"
|
||||
|
||||
#include "builtins/common.h"
|
||||
|
||||
#if defined (READLINE)
|
||||
# include "bashline.h"
|
||||
# include <readline/readline.h>
|
||||
#endif
|
||||
|
||||
#if defined (HISTORY)
|
||||
# include "bashhist.h"
|
||||
#endif
|
||||
|
||||
extern int last_command_exit_value;
|
||||
extern int last_command_exit_signal;
|
||||
extern int return_catch_flag;
|
||||
extern int loop_level, continuing, breaking, funcnest;
|
||||
extern int executing_list;
|
||||
extern int comsub_ignore_return;
|
||||
extern int parse_and_execute_level, shell_initialized;
|
||||
#if defined (HISTORY)
|
||||
extern int history_lines_this_session;
|
||||
#endif
|
||||
extern int no_line_editing;
|
||||
|
||||
extern void initialize_siglist ();
|
||||
|
||||
/* Non-zero after SIGINT. */
|
||||
volatile int interrupt_state = 0;
|
||||
|
||||
/* Non-zero after SIGWINCH */
|
||||
volatile int sigwinch_received = 0;
|
||||
|
||||
/* Set to the value of any terminating signal received. */
|
||||
volatile int terminating_signal = 0;
|
||||
|
||||
/* The environment at the top-level R-E loop. We use this in
|
||||
the case of error return. */
|
||||
procenv_t top_level;
|
||||
|
||||
#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
|
||||
/* The signal masks that this shell runs with. */
|
||||
sigset_t top_level_mask;
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
/* When non-zero, we throw_to_top_level (). */
|
||||
int interrupt_immediately = 0;
|
||||
|
||||
/* When non-zero, we call the terminating signal handler immediately. */
|
||||
int terminate_immediately = 0;
|
||||
|
||||
#if defined (SIGWINCH)
|
||||
static SigHandler *old_winch = (SigHandler *)SIG_DFL;
|
||||
#endif
|
||||
|
||||
static void initialize_shell_signals __P((void));
|
||||
|
||||
void
|
||||
initialize_signals (reinit)
|
||||
int reinit;
|
||||
{
|
||||
initialize_shell_signals ();
|
||||
initialize_job_signals ();
|
||||
#if !defined (HAVE_SYS_SIGLIST) && !defined (HAVE_UNDER_SYS_SIGLIST) && !defined (HAVE_STRSIGNAL)
|
||||
if (reinit == 0)
|
||||
initialize_siglist ();
|
||||
#endif /* !HAVE_SYS_SIGLIST && !HAVE_UNDER_SYS_SIGLIST && !HAVE_STRSIGNAL */
|
||||
}
|
||||
|
||||
/* A structure describing a signal that terminates the shell if not
|
||||
caught. The orig_handler member is present so children can reset
|
||||
these signals back to their original handlers. */
|
||||
struct termsig {
|
||||
int signum;
|
||||
SigHandler *orig_handler;
|
||||
int orig_flags;
|
||||
};
|
||||
|
||||
#define NULL_HANDLER (SigHandler *)SIG_DFL
|
||||
|
||||
/* The list of signals that would terminate the shell if not caught.
|
||||
We catch them, but just so that we can write the history file,
|
||||
and so forth. */
|
||||
static struct termsig terminating_signals[] = {
|
||||
#ifdef SIGHUP
|
||||
{ SIGHUP, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGINT
|
||||
{ SIGINT, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGILL
|
||||
{ SIGILL, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGTRAP
|
||||
{ SIGTRAP, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGIOT
|
||||
{ SIGIOT, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGDANGER
|
||||
{ SIGDANGER, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGEMT
|
||||
{ SIGEMT, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGFPE
|
||||
{ SIGFPE, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGBUS
|
||||
{ SIGBUS, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGSEGV
|
||||
{ SIGSEGV, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGSYS
|
||||
{ SIGSYS, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGPIPE
|
||||
{ SIGPIPE, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGALRM
|
||||
{ SIGALRM, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGTERM
|
||||
{ SIGTERM, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGXCPU
|
||||
{ SIGXCPU, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGXFSZ
|
||||
{ SIGXFSZ, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGVTALRM
|
||||
{ SIGVTALRM, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#ifdef SIGPROF
|
||||
{ SIGPROF, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SIGLOST
|
||||
{ SIGLOST, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGUSR1
|
||||
{ SIGUSR1, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
|
||||
#ifdef SIGUSR2
|
||||
{ SIGUSR2, NULL_HANDLER, 0 },
|
||||
#endif
|
||||
};
|
||||
|
||||
#define TERMSIGS_LENGTH (sizeof (terminating_signals) / sizeof (struct termsig))
|
||||
|
||||
#define XSIG(x) (terminating_signals[x].signum)
|
||||
#define XHANDLER(x) (terminating_signals[x].orig_handler)
|
||||
#define XSAFLAGS(x) (terminating_signals[x].orig_flags)
|
||||
|
||||
static int termsigs_initialized = 0;
|
||||
|
||||
/* Initialize signals that will terminate the shell to do some
|
||||
unwind protection. For non-interactive shells, we only call
|
||||
this when a trap is defined for EXIT (0) or when trap is run
|
||||
to display signal dispositions. */
|
||||
void
|
||||
initialize_terminating_signals ()
|
||||
{
|
||||
register int i;
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
struct sigaction act, oact;
|
||||
#endif
|
||||
|
||||
if (termsigs_initialized)
|
||||
return;
|
||||
|
||||
/* The following code is to avoid an expensive call to
|
||||
set_signal_handler () for each terminating_signals. Fortunately,
|
||||
this is possible in Posix. Unfortunately, we have to call signal ()
|
||||
on non-Posix systems for each signal in terminating_signals. */
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
act.sa_handler = termsig_sighandler;
|
||||
act.sa_flags = 0;
|
||||
sigemptyset (&act.sa_mask);
|
||||
sigemptyset (&oact.sa_mask);
|
||||
for (i = 0; i < TERMSIGS_LENGTH; i++)
|
||||
sigaddset (&act.sa_mask, XSIG (i));
|
||||
for (i = 0; i < TERMSIGS_LENGTH; i++)
|
||||
{
|
||||
/* If we've already trapped it, don't do anything. */
|
||||
if (signal_is_trapped (XSIG (i)))
|
||||
continue;
|
||||
|
||||
sigaction (XSIG (i), &act, &oact);
|
||||
XHANDLER(i) = oact.sa_handler;
|
||||
XSAFLAGS(i) = oact.sa_flags;
|
||||
/* Don't do anything with signals that are ignored at shell entry
|
||||
if the shell is not interactive. */
|
||||
/* XXX - should we do this for interactive shells, too? */
|
||||
if (interactive_shell == 0 && XHANDLER (i) == SIG_IGN)
|
||||
{
|
||||
sigaction (XSIG (i), &oact, &act);
|
||||
set_signal_ignored (XSIG (i));
|
||||
}
|
||||
#if defined (SIGPROF) && !defined (_MINIX)
|
||||
if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN)
|
||||
sigaction (XSIG (i), &oact, (struct sigaction *)NULL);
|
||||
#endif /* SIGPROF && !_MINIX */
|
||||
}
|
||||
|
||||
#else /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
for (i = 0; i < TERMSIGS_LENGTH; i++)
|
||||
{
|
||||
/* If we've already trapped it, don't do anything. */
|
||||
if (signal_is_trapped (XSIG (i)))
|
||||
continue;
|
||||
|
||||
XHANDLER(i) = signal (XSIG (i), termsig_sighandler);
|
||||
XSAFLAGS(i) = 0;
|
||||
/* Don't do anything with signals that are ignored at shell entry
|
||||
if the shell is not interactive. */
|
||||
/* XXX - should we do this for interactive shells, too? */
|
||||
if (interactive_shell == 0 && XHANDLER (i) == SIG_IGN)
|
||||
{
|
||||
signal (XSIG (i), SIG_IGN);
|
||||
set_signal_ignored (XSIG (i));
|
||||
}
|
||||
#ifdef SIGPROF
|
||||
if (XSIG (i) == SIGPROF && XHANDLER (i) != SIG_DFL && XHANDLER (i) != SIG_IGN)
|
||||
signal (XSIG (i), XHANDLER (i));
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
termsigs_initialized = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
initialize_shell_signals ()
|
||||
{
|
||||
if (interactive)
|
||||
initialize_terminating_signals ();
|
||||
|
||||
#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
|
||||
/* All shells use the signal mask they inherit, and pass it along
|
||||
to child processes. Children will never block SIGCHLD, though. */
|
||||
sigemptyset (&top_level_mask);
|
||||
sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &top_level_mask);
|
||||
# if defined (SIGCHLD)
|
||||
sigdelset (&top_level_mask, SIGCHLD);
|
||||
# endif
|
||||
#endif /* JOB_CONTROL || HAVE_POSIX_SIGNALS */
|
||||
|
||||
/* And, some signals that are specifically ignored by the shell. */
|
||||
set_signal_handler (SIGQUIT, SIG_IGN);
|
||||
|
||||
if (interactive)
|
||||
{
|
||||
set_signal_handler (SIGINT, sigint_sighandler);
|
||||
set_signal_handler (SIGTERM, SIG_IGN);
|
||||
set_sigwinch_handler ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
reset_terminating_signals ()
|
||||
{
|
||||
register int i;
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
struct sigaction act;
|
||||
#endif
|
||||
|
||||
if (termsigs_initialized == 0)
|
||||
return;
|
||||
|
||||
#if defined (HAVE_POSIX_SIGNALS)
|
||||
act.sa_flags = 0;
|
||||
sigemptyset (&act.sa_mask);
|
||||
for (i = 0; i < TERMSIGS_LENGTH; i++)
|
||||
{
|
||||
/* Skip a signal if it's trapped or handled specially, because the
|
||||
trap code will restore the correct value. */
|
||||
if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i)))
|
||||
continue;
|
||||
|
||||
act.sa_handler = XHANDLER (i);
|
||||
act.sa_flags = XSAFLAGS (i);
|
||||
sigaction (XSIG (i), &act, (struct sigaction *) NULL);
|
||||
}
|
||||
#else /* !HAVE_POSIX_SIGNALS */
|
||||
for (i = 0; i < TERMSIGS_LENGTH; i++)
|
||||
{
|
||||
if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i)))
|
||||
continue;
|
||||
|
||||
signal (XSIG (i), XHANDLER (i));
|
||||
}
|
||||
#endif /* !HAVE_POSIX_SIGNALS */
|
||||
|
||||
termsigs_initialized = 0;
|
||||
}
|
||||
#undef XSIG
|
||||
#undef XHANDLER
|
||||
|
||||
/* Run some of the cleanups that should be performed when we run
|
||||
jump_to_top_level from a builtin command context. XXX - might want to
|
||||
also call reset_parser here. */
|
||||
void
|
||||
top_level_cleanup ()
|
||||
{
|
||||
/* Clean up string parser environment. */
|
||||
while (parse_and_execute_level)
|
||||
parse_and_execute_cleanup ();
|
||||
|
||||
#if defined (PROCESS_SUBSTITUTION)
|
||||
unlink_fifo_list ();
|
||||
#endif /* PROCESS_SUBSTITUTION */
|
||||
|
||||
run_unwind_protects ();
|
||||
loop_level = continuing = breaking = funcnest = 0;
|
||||
executing_list = comsub_ignore_return = return_catch_flag = 0;
|
||||
}
|
||||
|
||||
/* What to do when we've been interrupted, and it is safe to handle it. */
|
||||
void
|
||||
throw_to_top_level ()
|
||||
{
|
||||
int print_newline = 0;
|
||||
|
||||
if (interrupt_state)
|
||||
{
|
||||
print_newline = 1;
|
||||
DELINTERRUPT;
|
||||
}
|
||||
|
||||
if (interrupt_state)
|
||||
return;
|
||||
|
||||
last_command_exit_signal = (last_command_exit_value > 128) ?
|
||||
(last_command_exit_value - 128) : 0;
|
||||
last_command_exit_value |= 128;
|
||||
|
||||
/* Run any traps set on SIGINT. */
|
||||
run_interrupt_trap ();
|
||||
|
||||
/* Clean up string parser environment. */
|
||||
while (parse_and_execute_level)
|
||||
parse_and_execute_cleanup ();
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
give_terminal_to (shell_pgrp, 0);
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
#if defined (JOB_CONTROL) || defined (HAVE_POSIX_SIGNALS)
|
||||
/* This should not be necessary on systems using sigsetjmp/siglongjmp. */
|
||||
sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL);
|
||||
#endif
|
||||
|
||||
reset_parser ();
|
||||
|
||||
#if defined (READLINE)
|
||||
if (interactive)
|
||||
bashline_reset ();
|
||||
#endif /* READLINE */
|
||||
|
||||
#if defined (PROCESS_SUBSTITUTION)
|
||||
unlink_fifo_list ();
|
||||
#endif /* PROCESS_SUBSTITUTION */
|
||||
|
||||
run_unwind_protects ();
|
||||
loop_level = continuing = breaking = funcnest = 0;
|
||||
executing_list = comsub_ignore_return = return_catch_flag = 0;
|
||||
|
||||
if (interactive && print_newline)
|
||||
{
|
||||
fflush (stdout);
|
||||
fprintf (stderr, "\n");
|
||||
fflush (stderr);
|
||||
}
|
||||
|
||||
/* An interrupted `wait' command in a script does not exit the script. */
|
||||
if (interactive || (interactive_shell && !shell_initialized) ||
|
||||
(print_newline && signal_is_trapped (SIGINT)))
|
||||
jump_to_top_level (DISCARD);
|
||||
else
|
||||
jump_to_top_level (EXITPROG);
|
||||
}
|
||||
|
||||
/* This is just here to isolate the longjmp calls. */
|
||||
void
|
||||
jump_to_top_level (value)
|
||||
int value;
|
||||
{
|
||||
longjmp (top_level, value);
|
||||
}
|
||||
|
||||
sighandler
|
||||
termsig_sighandler (sig)
|
||||
int sig;
|
||||
{
|
||||
/* If we get called twice with the same signal before handling it,
|
||||
terminate right away. */
|
||||
if (
|
||||
#ifdef SIGHUP
|
||||
sig != SIGHUP &&
|
||||
#endif
|
||||
#ifdef SIGINT
|
||||
sig != SIGINT &&
|
||||
#endif
|
||||
#ifdef SIGDANGER
|
||||
sig != SIGDANGER &&
|
||||
#endif
|
||||
#ifdef SIGPIPE
|
||||
sig != SIGPIPE &&
|
||||
#endif
|
||||
#ifdef SIGALRM
|
||||
sig != SIGALRM &&
|
||||
#endif
|
||||
#ifdef SIGTERM
|
||||
sig != SIGTERM &&
|
||||
#endif
|
||||
#ifdef SIGXCPU
|
||||
sig != SIGXCPU &&
|
||||
#endif
|
||||
#ifdef SIGXFSZ
|
||||
sig != SIGXFSZ &&
|
||||
#endif
|
||||
#ifdef SIGVTALRM
|
||||
sig != SIGVTALRM &&
|
||||
#endif
|
||||
#ifdef SIGLOST
|
||||
sig != SIGLOST &&
|
||||
#endif
|
||||
#ifdef SIGUSR1
|
||||
sig != SIGUSR1 &&
|
||||
#endif
|
||||
#ifdef SIGUSR2
|
||||
sig != SIGUSR2 &&
|
||||
#endif
|
||||
sig == terminating_signal)
|
||||
terminate_immediately = 1;
|
||||
|
||||
terminating_signal = sig;
|
||||
|
||||
/* XXX - should this also trigger when interrupt_immediately is set? */
|
||||
if (terminate_immediately)
|
||||
{
|
||||
#if defined (HISTORY)
|
||||
/* XXX - will inhibit history file being written */
|
||||
# if defined (READLINE)
|
||||
if (interactive_shell == 0 || interactive == 0 || (sig != SIGHUP && sig != SIGTERM) || no_line_editing || (RL_ISSTATE (RL_STATE_READCMD) == 0))
|
||||
# endif
|
||||
history_lines_this_session = 0;
|
||||
#endif
|
||||
terminate_immediately = 0;
|
||||
termsig_handler (sig);
|
||||
}
|
||||
|
||||
#if defined (READLINE)
|
||||
if (interactive_shell && interactive && no_line_editing == 0)
|
||||
bashline_set_event_hook ();
|
||||
#endif
|
||||
|
||||
SIGRETURN (0);
|
||||
}
|
||||
|
||||
void
|
||||
termsig_handler (sig)
|
||||
int sig;
|
||||
{
|
||||
static int handling_termsig = 0;
|
||||
|
||||
/* Simple semaphore to keep this function from being executed multiple
|
||||
times. Since we no longer are running as a signal handler, we don't
|
||||
block multiple occurrences of the terminating signals while running. */
|
||||
if (handling_termsig)
|
||||
return;
|
||||
handling_termsig = 1;
|
||||
terminating_signal = 0; /* keep macro from re-testing true. */
|
||||
|
||||
/* I don't believe this condition ever tests true. */
|
||||
if (sig == SIGINT && signal_is_trapped (SIGINT))
|
||||
run_interrupt_trap ();
|
||||
|
||||
#if 0
|
||||
#if defined (HISTORY)
|
||||
if (interactive_shell && (sig != SIGABRT && sig != SIGINT && sig != SIGHUP && sig != SIGTERM))
|
||||
maybe_save_shell_history ();
|
||||
#endif /* HISTORY */
|
||||
#endif
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
if (sig == SIGHUP && (interactive || (subshell_environment & (SUBSHELL_COMSUB|SUBSHELL_PROCSUB))))
|
||||
hangup_all_jobs ();
|
||||
end_job_control ();
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
#if defined (PROCESS_SUBSTITUTION)
|
||||
unlink_fifo_list ();
|
||||
#endif /* PROCESS_SUBSTITUTION */
|
||||
|
||||
/* Reset execution context */
|
||||
loop_level = continuing = breaking = funcnest = 0;
|
||||
executing_list = comsub_ignore_return = return_catch_flag = 0;
|
||||
|
||||
run_exit_trap ();
|
||||
set_signal_handler (sig, SIG_DFL);
|
||||
kill (getpid (), sig);
|
||||
}
|
||||
|
||||
/* What we really do when SIGINT occurs. */
|
||||
sighandler
|
||||
sigint_sighandler (sig)
|
||||
int sig;
|
||||
{
|
||||
#if defined (MUST_REINSTALL_SIGHANDLERS)
|
||||
signal (sig, sigint_sighandler);
|
||||
#endif
|
||||
|
||||
/* interrupt_state needs to be set for the stack of interrupts to work
|
||||
right. Should it be set unconditionally? */
|
||||
if (interrupt_state == 0)
|
||||
ADDINTERRUPT;
|
||||
|
||||
if (interrupt_immediately)
|
||||
{
|
||||
interrupt_immediately = 0;
|
||||
last_command_exit_value = 128 + sig;
|
||||
throw_to_top_level ();
|
||||
}
|
||||
#if defined (READLINE)
|
||||
else if (RL_ISSTATE (RL_STATE_SIGHANDLER))
|
||||
{
|
||||
itrace("sigint_sighandler: installing event hook");
|
||||
bashline_set_event_hook ();
|
||||
}
|
||||
#endif
|
||||
|
||||
SIGRETURN (0);
|
||||
}
|
||||
|
||||
#if defined (SIGWINCH)
|
||||
sighandler
|
||||
sigwinch_sighandler (sig)
|
||||
int sig;
|
||||
{
|
||||
#if defined (MUST_REINSTALL_SIGHANDLERS)
|
||||
set_signal_handler (SIGWINCH, sigwinch_sighandler);
|
||||
#endif /* MUST_REINSTALL_SIGHANDLERS */
|
||||
sigwinch_received = 1;
|
||||
SIGRETURN (0);
|
||||
}
|
||||
#endif /* SIGWINCH */
|
||||
|
||||
void
|
||||
set_sigwinch_handler ()
|
||||
{
|
||||
#if defined (SIGWINCH)
|
||||
old_winch = set_signal_handler (SIGWINCH, sigwinch_sighandler);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
unset_sigwinch_handler ()
|
||||
{
|
||||
#if defined (SIGWINCH)
|
||||
set_signal_handler (SIGWINCH, old_winch);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Signal functions used by the rest of the code. */
|
||||
#if !defined (HAVE_POSIX_SIGNALS)
|
||||
|
||||
/* Perform OPERATION on NEWSET, perhaps leaving information in OLDSET. */
|
||||
sigprocmask (operation, newset, oldset)
|
||||
int operation, *newset, *oldset;
|
||||
{
|
||||
int old, new;
|
||||
|
||||
if (newset)
|
||||
new = *newset;
|
||||
else
|
||||
new = 0;
|
||||
|
||||
switch (operation)
|
||||
{
|
||||
case SIG_BLOCK:
|
||||
old = sigblock (new);
|
||||
break;
|
||||
|
||||
case SIG_SETMASK:
|
||||
old = sigsetmask (new);
|
||||
break;
|
||||
|
||||
default:
|
||||
internal_error (_("sigprocmask: %d: invalid operation"), operation);
|
||||
}
|
||||
|
||||
if (oldset)
|
||||
*oldset = old;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#if !defined (SA_INTERRUPT)
|
||||
# define SA_INTERRUPT 0
|
||||
#endif
|
||||
|
||||
#if !defined (SA_RESTART)
|
||||
# define SA_RESTART 0
|
||||
#endif
|
||||
|
||||
SigHandler *
|
||||
set_signal_handler (sig, handler)
|
||||
int sig;
|
||||
SigHandler *handler;
|
||||
{
|
||||
struct sigaction act, oact;
|
||||
|
||||
act.sa_handler = handler;
|
||||
act.sa_flags = 0;
|
||||
|
||||
/* XXX - bash-4.2 */
|
||||
/* We don't want a child death to interrupt interruptible system calls, even
|
||||
if we take the time to reap children */
|
||||
#if defined (SIGCHLD)
|
||||
if (sig == SIGCHLD)
|
||||
act.sa_flags |= SA_RESTART; /* XXX */
|
||||
#endif
|
||||
|
||||
sigemptyset (&act.sa_mask);
|
||||
sigemptyset (&oact.sa_mask);
|
||||
sigaction (sig, &act, &oact);
|
||||
return (oact.sa_handler);
|
||||
}
|
||||
#endif /* HAVE_POSIX_SIGNALS */
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
BUILD_DIR=/usr/local/build/bash/bash-current
|
||||
BUILD_DIR=/usr/local/build/chet/bash/bash-current
|
||||
THIS_SH=$BUILD_DIR/bash
|
||||
PATH=$PATH:$BUILD_DIR
|
||||
|
||||
|
||||
@@ -44,6 +44,11 @@
|
||||
#include "builtins/common.h"
|
||||
#include "builtins/builtext.h"
|
||||
|
||||
#if defined (READLINE)
|
||||
# include <readline/readline.h>
|
||||
# include "bashline.h"
|
||||
#endif
|
||||
|
||||
#ifndef errno
|
||||
extern int errno;
|
||||
#endif
|
||||
@@ -398,6 +403,11 @@ trap_handler (sig)
|
||||
longjmp (wait_intr_buf, 1);
|
||||
}
|
||||
|
||||
#if defined (READLINE)
|
||||
if (RL_ISSTATE (RL_STATE_SIGHANDLER) && interrupt_immediately == 0)
|
||||
bashline_set_event_hook ();
|
||||
#endif
|
||||
|
||||
if (interrupt_immediately)
|
||||
run_pending_traps ();
|
||||
|
||||
@@ -418,6 +428,24 @@ first_pending_trap ()
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
any_signals_trapped ()
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 1; i < NSIG; i++)
|
||||
if (sigmodes[i] & SIG_TRAPPED)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void
|
||||
check_signals_and_traps ()
|
||||
{
|
||||
QUIT;
|
||||
run_pending_traps ();
|
||||
}
|
||||
|
||||
#if defined (JOB_CONTROL) && defined (SIGCHLD)
|
||||
|
||||
#ifdef INCLUDE_UNUSED
|
||||
|
||||
@@ -104,4 +104,8 @@ extern int signal_is_hard_ignored __P((int));
|
||||
extern void set_signal_ignored __P((int));
|
||||
extern int signal_in_progress __P((int));
|
||||
|
||||
extern int first_pending_trap __P((void));
|
||||
extern int any_signals_trapped __P((void));
|
||||
extern void check_signals_and_traps __P((void));
|
||||
|
||||
#endif /* _TRAP_H_ */
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
/* trap.h -- data structures used in the trap mechanism. */
|
||||
|
||||
/* Copyright (C) 1993-2010 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if !defined (_TRAP_H_)
|
||||
#define _TRAP_H_
|
||||
|
||||
#include "stdc.h"
|
||||
|
||||
#if !defined (SIG_DFL)
|
||||
#include "bashtypes.h"
|
||||
#include <signal.h>
|
||||
#endif /* SIG_DFL */
|
||||
|
||||
#if !defined (NSIG)
|
||||
#define NSIG 64
|
||||
#endif /* !NSIG */
|
||||
|
||||
#define NO_SIG -1
|
||||
#define DEFAULT_SIG SIG_DFL
|
||||
#define IGNORE_SIG SIG_IGN
|
||||
|
||||
/* Special shell trap names. */
|
||||
#define DEBUG_TRAP NSIG
|
||||
#define ERROR_TRAP NSIG+1
|
||||
#define RETURN_TRAP NSIG+2
|
||||
#define EXIT_TRAP 0
|
||||
|
||||
/* system signals plus special bash traps */
|
||||
#define BASH_NSIG NSIG+3
|
||||
|
||||
/* Flags values for decode_signal() */
|
||||
#define DSIG_SIGPREFIX 0x01 /* don't alllow `SIG' PREFIX */
|
||||
#define DSIG_NOCASE 0x02 /* case-insensitive comparison */
|
||||
|
||||
/* A value which can never be the target of a trap handler. */
|
||||
#define IMPOSSIBLE_TRAP_HANDLER (SigHandler *)initialize_traps
|
||||
|
||||
#define signal_object_p(x,f) (decode_signal (x,f) != NO_SIG)
|
||||
|
||||
#define TRAP_STRING(s) \
|
||||
(signal_is_trapped (s) && signal_is_ignored (s) == 0) ? trap_list[s] \
|
||||
: (char *)NULL
|
||||
|
||||
extern char *trap_list[];
|
||||
|
||||
/* Externally-visible functions declared in trap.c. */
|
||||
extern void initialize_traps __P((void));
|
||||
|
||||
extern void run_pending_traps __P((void));
|
||||
|
||||
extern void queue_sigchld_trap __P((int));
|
||||
extern void maybe_set_sigchld_trap __P((char *));
|
||||
extern void set_impossible_sigchld_trap __P((void));
|
||||
extern void set_sigchld_trap __P((char *));
|
||||
|
||||
extern void set_debug_trap __P((char *));
|
||||
extern void set_error_trap __P((char *));
|
||||
extern void set_return_trap __P((char *));
|
||||
|
||||
extern void set_sigint_trap __P((char *));
|
||||
extern void set_signal __P((int, char *));
|
||||
|
||||
extern void restore_default_signal __P((int));
|
||||
extern void ignore_signal __P((int));
|
||||
extern int run_exit_trap __P((void));
|
||||
extern void run_trap_cleanup __P((int));
|
||||
extern int run_debug_trap __P((void));
|
||||
extern void run_error_trap __P((void));
|
||||
extern void run_return_trap __P((void));
|
||||
|
||||
extern void free_trap_strings __P((void));
|
||||
extern void reset_signal_handlers __P((void));
|
||||
extern void restore_original_signals __P((void));
|
||||
|
||||
extern void get_all_original_signals __P((void));
|
||||
|
||||
extern char *signal_name __P((int));
|
||||
|
||||
extern int decode_signal __P((char *, int));
|
||||
extern void run_interrupt_trap __P((void));
|
||||
extern int maybe_call_trap_handler __P((int));
|
||||
extern int signal_is_special __P((int));
|
||||
extern int signal_is_trapped __P((int));
|
||||
extern int signal_is_pending __P((int));
|
||||
extern int signal_is_ignored __P((int));
|
||||
extern int signal_is_hard_ignored __P((int));
|
||||
extern void set_signal_ignored __P((int));
|
||||
extern int signal_in_progress __P((int));
|
||||
|
||||
extern int first_pending_trap __P((void));
|
||||
extern int any_signals_trapped __P((void));
|
||||
extern int check_signals_and_traps __P((void));
|
||||
|
||||
#endif /* _TRAP_H_ */
|
||||
Reference in New Issue
Block a user