commit bash-20050210 snapshot

This commit is contained in:
Chet Ramey
2011-12-03 13:43:14 -05:00
parent 10590446d1
commit cc87ba64ee
83 changed files with 5290 additions and 323 deletions
+88 -1
View File
@@ -10925,6 +10925,12 @@ configure.in
Makefile.in
- use $(SIZE) instead of size; set SIZE from configure
1/31
----
arrayfunc.c
- in array_value_internal, return NULL right away if the variable's
value is NULL, instead of passing a null string to add_string_to_list
2/1
---
jobs.h
@@ -10943,6 +10949,7 @@ jobs.[ch]
a job index
- new function, reset_job_indices, called from delete_job if
js.j_lastj or js.j_firstj are removed
- change various functions to keep counters and stats in struct jobstats
pcomplete.c, builtins/common.c, builtins/{exit,fg_bg,jobs,kill,wait}.def
- change global variables (e.g., job_slots) to struct members
@@ -10951,7 +10958,7 @@ pcomplete.c, builtins/common.c, builtins/{exit,fg_bg,jobs,kill,wait}.def
- use get_job_by_jid and J_JOBSTATE where appropriate
trap.c
- change reset_or_restore_signal_handler to not free the trap
- change reset_or_restore_signal_handler to not free the exit trap
string if the function pointer is reset_signal, which is used when
the trap strings shouldn't be freed, like in command substitution
@@ -10976,3 +10983,83 @@ parse.y
(echo 6))
work right
2/8
---
jobs.h
- new structs for holding status of exited background processes, as
POSIX specifies
- new job flag: J_ASYNC
jobs.c
- new functions to manipulate struct holding status of exited
background processes
- new members in struct jobstats to hold pointer to last created job
and last created asynchronous job
- initialize js.c_childmax in initialize_job_control
- if the `async' arg to stop_pipeline is non-null, set the J_ASYNC
flag in the job struct
- set js.j_last_made_job and js.j_last_asynchronous_job in
stop_pipeline
- new function: find_last_proc, returns the PROCESS * to the last proc
in a job's pipeline
- changed find_last_pid to call find_last_proc
- change delete_job to call bgp_add on the last proc of the job being
deleted
- change delete_all_jobs and wait_for_background_pids to call bgp_clear
2/9
---
jobs.c
- change wait_for_single_pid to look for pid in bgpids.list (using
bgp_search()) if find_pipeline returns NULL
2/10
----
support/shobj-conf
- change the solaris-gcc stanza so that it auto-selects the appropriate
options for ld depending on which `ld' gcc says it's going to run
2/11
----
jobs.h
- add support for PS_RECYCLED as a process state, add PRECYCLED macro
to test it. Change PALIVE and PRUNNING macros to not count processes
in PS_RECYCLED state
execute_cmd.c
- restore use of last_pid as sentinel value; use NO_PID as sentinel
only if RECYCLES_PIDS is defined
jobs.c
- change find_job to return a pointer to the PROCESS the desired pid
belongs to, analogous to find_pipeline returning pointer to JOB
- change find_job callers to add extra argument
- change running_only arguments to find_pipeline and find_job to
alive_only, since we don't want recycled pids returned here and it
better describes the result
- new function find_process, calls find_pipeline and searches the
returned pipeline for the PROCESS * describing the desired pid
- in make_child, if fork() returns the same pid as the value of
last_asynchronous_pid when RECYCLES_PIDS is defined, avoid pid
aliasing by resetting last_asynchronous_pid to 1
- use PRUNNING instead of child->running, since we, for the most
part, don't want to consider recycled pids (e.g., in make_child())
- call find_process instead of find_pipeline in waitchld()
- use PEXITED(p) instead of testing p->running == PS_DONE
- in make_child, call bgp_delete to remove a just-created pid from the
last of saved pid statuses
- in add_process, check whether or not pid being added is already in
the_pipeline or the jobs list (using find_process) and mark it as
recycled if so
- This set of fixes mostly came from Pierre Humblet
<pierre.humblet@ieee.org> to fix pid aliasing and reuse problems on
cygwin
variables.c
- set $_ from the environment if we get it there, set to $0 by
default if not in env
doc/{bashref.texi,bash.1}
- a couple of clarifying changes to the description of $_ based on
comments from Glenn Morris <gmorris+mail@ast.cam.ac.uk>
+85 -2
View File
@@ -10925,6 +10925,12 @@ configure.in
Makefile.in
- use $(SIZE) instead of size; set SIZE from configure
1/31
----
arrayfunc.c
- in array_value_internal, return NULL right away if the variable's
value is NULL, instead of passing a null string to add_string_to_list
2/1
---
jobs.h
@@ -10943,6 +10949,7 @@ jobs.[ch]
a job index
- new function, reset_job_indices, called from delete_job if
js.j_lastj or js.j_firstj are removed
- change various functions to keep counters and stats in struct jobstats
pcomplete.c, builtins/common.c, builtins/{exit,fg_bg,jobs,kill,wait}.def
- change global variables (e.g., job_slots) to struct members
@@ -10951,7 +10958,7 @@ pcomplete.c, builtins/common.c, builtins/{exit,fg_bg,jobs,kill,wait}.def
- use get_job_by_jid and J_JOBSTATE where appropriate
trap.c
- change reset_or_restore_signal_handler to not free the trap
- change reset_or_restore_signal_handler to not free the exit trap
string if the function pointer is reset_signal, which is used when
the trap strings shouldn't be freed, like in command substitution
@@ -10969,10 +10976,86 @@ jobs.c
list if it reaches MAX_JOBS_IN_ARRAY in size
parse.y
- move test for backslash-newline after pop_string in read_token so
- move test for backslash-newline after pop_string in shell_getc so
that things like
((echo 5) \
(echo 6))
work right
2/8
---
jobs.h
- new structs for holding status of exited background processes, as
POSIX specifies
- new job flag: J_ASYNC
jobs.c
- new functions to manipulate struct holding status of exited
background processes
- new members in struct jobstats to hold pointer to last created job
and last created asynchronous job
- initialize js.c_childmax in initialize_job_control
- if the `async' arg to stop_pipeline is non-null, set the J_ASYNC
flag in the job struct
- set js.j_last_made_job and js.j_last_asynchronous_job in
stop_pipeline
- new function: find_last_proc, returns the PROCESS * to the last proc
in a job's pipeline
- changed find_last_pid to call find_last_proc
- change delete_job to call bgp_add on the last proc of the job being
deleted
- change delete_all_jobs and wait_for_background_pids to call bgp_clear
2/9
---
jobs.c
- change wait_for_single_pid to look for pid in bgpids.list (using
bgp_search()) if find_pipeline returns NULL
2/10
----
support/shobj-conf
- change the solaris-gcc stanza so that it auto-selects the appropriate
options for ld depending on which `ld' gcc says it's going to run
2/11
----
jobs.h
- add support for PS_RECYCLED as a process state, add PRECYCLED macro
to test it. Change PALIVE and PRUNNING macros to not count processes
in PS_RECYCLED state
execute_cmd.c
- restore use of last_pid as sentinel value; use NO_PID as sentinel
only if RECYCLES_PIDS is defined
jobs.c
- change find_job to return a pointer to the PROCESS the desired pid
belongs to, analogous to find_pipeline returning pointer to JOB
- change find_job callers to add extra argument
- change running_only arguments to find_pipeline and find_job to
alive_only, since we don't want recycled pids returned here and it
better describes the result
- new function find_process, calls find_pipeline and searches the
returned pipeline for the PROCESS * describing the desired pid
- in make_child, if fork() returns the same pid as the value of
last_asynchronous_pid when RECYCLES_PIDS is defined, avoid pid
aliasing by resetting last_asynchronous_pid to 1
- use PRUNNING instead of child->running, since we, for the most
part, don't want to consider recycled pids (e.g., in make_child())
- call find_process instead of find_pipeline in waitchld()
- use PEXITED(p) instead of testing p->running == PS_DONE
- in make_child, call bgp_delete to remove a just-created pid from the
last of saved pid statuses
- in add_process, check whether or not pid being added is already in
the_pipeline or the jobs list (using find_process) and mark it as
recycled if so
- This set of fixes mostly came from Pierre Humblet
<pierre.humblet@ieee.org> to fix pid aliasing and reuse problems on
cygwin
doc/{bashref.texi,bash.1}
- a couple of clarifying changes to the description of $_ based on
comments from Glenn Morris <gmorris+mail@ast.cam.ac.uk>
+1 -1
View File
@@ -1,6 +1,6 @@
/* arrayfunc.c -- High-level array functions used by other parts of the shell. */
/* Copyright (C) 2001-2004 Free Software Foundation, Inc.
/* Copyright (C) 2001-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
+1 -10
View File
@@ -385,16 +385,7 @@ assign_array_var_from_string (var, value, flags)
if (integer_p (var))
this_command_name = (char *)NULL; /* no command name for errors */
#if 0
nval = make_variable_value (var, val, flags);
if (var->assign_func)
(*var->assign_func) (var, nval, ind);
else
array_insert (a, ind, nval);
FREE (nval);
#else
bind_array_var_internal (var, ind, val, flags);
#endif
last_ind++;
}
@@ -717,7 +708,7 @@ array_value_internal (s, quoted, allow_all, rtype)
err_badarraysub (s);
return ((char *)NULL);
}
else if (var == 0)
else if (var == 0 || value_cell (var) == 0)
return ((char *)NULL);
else if (array_p (var) == 0)
l = add_string_to_list (value_cell (var), (WORD_LIST *)NULL);
+1 -1
View File
@@ -1,6 +1,6 @@
# This Makefile for building libbuiltins.a is in -*- text -*- for Emacs.
#
# Copyright (C) 1996-2003 Free Software Foundation, Inc.
# Copyright (C) 1996-2005 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+7 -3
View File
@@ -404,12 +404,12 @@ exec.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
exec.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/flags.h
exec.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
exec.o: $(srcdir)/common.h $(topdir)/execute_cmd.h $(BASHINCDIR)/maxpath.h
exec.o: $(topdir)/findcmd.h
exec.o: $(topdir)/findcmd.h $(topdir)/jobs.h
exit.o: $(topdir)/bashtypes.h
exit.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
exit.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
exit.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
exit.o: $(topdir)/subst.h $(topdir)/externs.h
exit.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/jobs.h
exit.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
exit.o: $(BASHINCDIR)/maxpath.h ./builtext.h
fc.o: $(topdir)/bashtypes.h $(BASHINCDIR)/posixstat.h
@@ -427,6 +427,7 @@ fg_bg.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
fg_bg.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
fg_bg.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
fg_bg.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
fg_bg.o: $(topdir)/jobs.h
getopts.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
getopts.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
getopts.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
@@ -458,7 +459,7 @@ inlib.o: $(BASHINCDIR)/maxpath.h $(topdir)/subst.h $(topdir)/externs.h
inlib.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
jobs.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h
jobs.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/quit.h $(srcdir)/bashgetopt.h
jobs.o: $(BASHINCDIR)/maxpath.h $(topdir)/externs.h
jobs.o: $(BASHINCDIR)/maxpath.h $(topdir)/externs.h $(topdir)/jobs.h
jobs.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h
jobs.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
kill.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h
@@ -466,6 +467,7 @@ kill.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/subst.h $(topdir)/exte
kill.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
kill.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/trap.h $(topdir)/unwind_prot.h
kill.o: $(topdir)/variables.h $(topdir)/conftypes.h $(BASHINCDIR)/maxpath.h
kill.o: $(topdir)/jobs.h
let.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
let.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
let.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
@@ -525,6 +527,7 @@ suspend.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
suspend.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
suspend.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
suspend.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
suspend.o: $(topdir)/jobs.h
test.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
test.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
test.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
@@ -565,6 +568,7 @@ wait.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
wait.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
wait.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
wait.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
wait.o: $(topdir)/jobs.h
wait.o: $(BASHINCDIR)/chartypes.h
shopt.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
shopt.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
+1 -1
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 1987-2004 Free Software Foundation, Inc.
/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
+10 -9
View File
@@ -514,15 +514,17 @@ get_job_by_name (name, flags)
{
register int i, wl, cl, match, job;
register PROCESS *p;
register JOB *j;
job = NO_JOB;
wl = strlen (name);
for (i = job_slots - 1; i >= 0; i--)
for (i = js.j_jobslots - 1; i >= 0; i--)
{
if (jobs[i] == 0 || ((flags & JM_STOPPED) && JOBSTATE(i) != JSTOPPED))
j = get_job_by_jid (i);
if (j == 0 || ((flags & JM_STOPPED) && J_JOBSTATE(j) != JSTOPPED))
continue;
p = jobs[i]->pipe;
p = j->pipe;
do
{
if (flags & JM_EXACT)
@@ -553,7 +555,7 @@ get_job_by_name (name, flags)
else
job = i;
}
while (p != jobs[i]->pipe);
while (p != j->pipe);
}
return (job);
@@ -568,7 +570,7 @@ get_job_spec (list)
int job, jflags;
if (list == 0)
return (current_job);
return (js.j_current);
word = list->word->word;
@@ -581,20 +583,19 @@ get_job_spec (list)
if (DIGIT (*word) && all_digits (word))
{
job = atoi (word);
return (job > job_slots ? NO_JOB : job - 1);
return (job > js.j_jobslots ? NO_JOB : job - 1);
}
jflags = 0;
switch (*word)
{
case 0:
return NO_JOB;
case '%':
case '+':
return (current_job);
return (js.j_current);
case '-':
return (previous_job);
return (js.j_previous);
case '?': /* Substring search requested. */
jflags |= JM_SUBSTRING;
+1 -1
View File
@@ -1,7 +1,7 @@
This file is exit.def, from which is created exit.c.
It implements the builtins "exit", and "logout" in Bash.
Copyright (C) 1987-2003 Free Software Foundation, Inc.
Copyright (C) 1987-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
+1 -1
View File
@@ -105,7 +105,7 @@ exit_or_logout (list)
if (!exit_immediate_okay)
{
register int i;
for (i = 0; i < job_slots; i++)
for (i = 0; i < js.j_jobslots; i++)
if (jobs[i] && STOPPED (i))
{
fprintf (stderr, _("There are stopped jobs.\n"));
+1 -1
View File
@@ -1,7 +1,7 @@
This file is fg_bg.def, from which is created fg_bg.c.
It implements the builtins "bg" and "fg" in Bash.
Copyright (C) 1987-2003 Free Software Foundation, Inc.
Copyright (C) 1987-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
+4 -2
View File
@@ -127,6 +127,7 @@ fg_bg (list, foreground)
{
sigset_t set, oset;
int job, status, old_async_pid;
JOB *j;
BLOCK_CHILD (set, oset);
job = get_job_spec (list);
@@ -139,7 +140,8 @@ fg_bg (list, foreground)
goto failure;
}
/* Or if jobs[job]->pgrp == shell_pgrp. */
j = get_job_by_jid (job);
/* Or if j->pgrp == shell_pgrp. */
if (IS_JOBCONTROL (job) == 0)
{
builtin_error (_("job %d started without job control"), job + 1);
@@ -149,7 +151,7 @@ fg_bg (list, foreground)
if (foreground == 0)
{
old_async_pid = last_asynchronous_pid;
last_asynchronous_pid = jobs[job]->pgrp; /* As per Posix.2 5.4.2 */
last_asynchronous_pid = j->pgrp; /* As per Posix.2 5.4.2 */
}
status = start_job (job, foreground);
+1 -1
View File
@@ -1,7 +1,7 @@
This file is jobs.def, from which is created jobs.c.
It implements the builtins "jobs" and "disown" in Bash.
Copyright (C) 1987-2004 Free Software Foundation, Inc.
Copyright (C) 1987-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
+4 -2
View File
@@ -141,7 +141,7 @@ jobs_builtin (list)
BLOCK_CHILD (set, oset);
job = get_job_spec (list);
if ((job == NO_JOB) || !jobs || !jobs[job])
if ((job == NO_JOB) || jobs == 0 || get_job_by_jid (job) == 0)
{
sh_badjob (list->word->word);
any_failed++;
@@ -162,6 +162,7 @@ execute_list_with_replacements (list)
register WORD_LIST *l;
int job, result;
COMMAND *command;
JOB *j;
/* First do the replacement of job specifications with pids. */
for (l = list; l; l = l->next)
@@ -174,8 +175,9 @@ execute_list_with_replacements (list)
if (INVALID_JOB (job))
continue;
j = get_job_by_jid (job);
free (l->word->word);
l->word->word = itos (jobs[job]->pgrp);
l->word->word = itos (j->pgrp);
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
This file is kill.def, from which is created kill.c.
It implements the builtin "kill" in Bash.
Copyright (C) 1987-2004 Free Software Foundation, Inc.
Copyright (C) 1987-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
+3 -1
View File
@@ -192,6 +192,7 @@ kill_builtin (list)
{ /* Must be a job spec. Check it out. */
int job;
sigset_t set, oset;
JOB *j;
BLOCK_CHILD (set, oset);
job = get_job_spec (list);
@@ -204,11 +205,12 @@ kill_builtin (list)
CONTINUE_OR_FAIL;
}
j = get_job_by_jid (job);
/* Job spec used. Kill the process group. If the job was started
without job control, then its pgrp == shell_pgrp, so we have
to be careful. We take the pid of the first job in the pipeline
in that case. */
pid = IS_JOBCONTROL (job) ? jobs[job]->pgrp : jobs[job]->pipe->pid;
pid = IS_JOBCONTROL (job) ? j->pgrp : j->pipe->pid;
UNBLOCK_CHILD (oset);
+1 -1
View File
@@ -1,7 +1,7 @@
This file is trap.def, from which is created trap.c.
It implements the builtin "trap" in Bash.
Copyright (C) 1987-2004 Free Software Foundation, Inc.
Copyright (C) 1987-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
-2
View File
@@ -214,7 +214,6 @@ showtrap (i)
char *t, *p, *sn;
p = trap_list[i];
itrace("showtrap: %d", i);
if (p == (char *)DEFAULT_SIG)
return;
@@ -243,7 +242,6 @@ display_traps (list)
{
int result, i;
itrace("trap_builtin");
if (list == 0)
{
for (i = 0; i < BASH_NSIG; i++)
+1 -1
View File
@@ -1,7 +1,7 @@
This file is wait.def, from which is created wait.c.
It implements the builtin "wait" in Bash.
Copyright (C) 1987-2004 Free Software Foundation, Inc.
Copyright (C) 1987-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
-2
View File
@@ -150,8 +150,6 @@ wait_builtin (list)
BLOCK_CHILD (set, oset);
job = get_job_spec (list);
itrace("wait_builtin: get_job_spec returns %d, js.j_current = %d", job, js.j_current);
if (INVALID_JOB (job))
{
if (job != DUP_JOB)
+1 -1
View File
@@ -1,7 +1,7 @@
/* command.h -- The structures used internally to represent commands, and
the extern declarations of the functions used to create them. */
/* Copyright (C) 1993 Free Software Foundation, Inc.
/* Copyright (C) 1993-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
+2
View File
@@ -84,6 +84,8 @@ enum command_type { cm_for, cm_case, cm_while, cm_if, cm_simple, cm_select,
#define W_NOEXPAND 0x04000 /* Don't expand at all -- do quote removal */
#define W_COMPASSIGN 0x08000 /* Compound assignment */
#define W_ASSNBLTIN 0x10000 /* word is a builtin command that takes assignments */
#define W_ASSIGNARG 0x20000 /* word is assignment argument to command */
#define W_HASQUOTEDNULL 0x40000 /* word contains a quoted null character */
/* Possible values for subshell_environment */
#define SUBSHELL_ASYNC 0x01 /* subshell caused by `command &' */
+1 -1
View File
@@ -1,6 +1,6 @@
/* dispose_command.c -- dispose of a COMMAND structure. */
/* Copyright (C) 1987,1991 Free Software Foundation, Inc.
/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
+1
View File
@@ -247,6 +247,7 @@ void
dispose_word_desc (w)
WORD_DESC *w;
{
w->word = 0;
ocache_free (wdcache, WORD_DESC, w);
}
+1 -1
View File
@@ -1,6 +1,6 @@
/* dispose_cmd.h -- Functions appearing in dispose_cmd.c. */
/* Copyright (C) 1993 Free Software Foundation, Inc.
/* Copyright (C) 1993-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
+40
View File
@@ -0,0 +1,40 @@
/* dispose_cmd.h -- Functions appearing in dispose_cmd.c. */
/* Copyright (C) 1993 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 2, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
#if !defined (_DISPOSE_CMD_H_)
#define _DISPOSE_CMD_H_
#include "stdc.h"
extern void dispose_command __P((COMMAND *));
extern void dispose_word_desc __P((WORD_DESC *));
extern void dispose_word __P((WORD_DESC *));
extern void dispose_words __P((WORD_LIST *));
extern void dispose_word_array __P((char **));
extern void dispose_redirects __P((REDIRECT *));
#if defined (COND_COMMAND)
extern void dispose_cond_node __P((COND_COM *));
#endif
extern void dispose_function_def_contents __P((FUNCTION_DEF *));
extern void dispose_function_def __P((FUNCTION_DEF *));
#endif /* !_DISPOSE_CMD_H_ */
+7 -6
View File
@@ -6,12 +6,12 @@
.\" Case Western Reserve University
.\" chet@po.CWRU.Edu
.\"
.\" Last Change: Tue Jan 4 17:23:59 EST 2005
.\" Last Change: Fri Feb 11 15:43:40 EST 2005
.\"
.\" bash_builtins, strip all but Built-Ins section
.if \n(zZ=1 .ig zZ
.if \n(zY=1 .ig zY
.TH BASH 1 "2005 Jan 4" "GNU Bash-3.1-devel"
.TH BASH 1 "2005 Feb 11" "GNU Bash-3.1-devel"
.\"
.\" There's some problem with having a `@'
.\" in a tagged paragraph with the BSD man macros.
@@ -1205,12 +1205,13 @@ to the file name used to invoke
as given by argument zero.
.TP
.B _
At shell startup, set to the absolute file name of the shell or shell
script being executed as passed in the argument list.
At shell startup, set to the absolute pathname used to invoke the
shell or shell script being executed as passed in the environment
or argument list.
Subsequently, expands to the last argument to the previous command,
after expansion.
Also set to the full file name of each command executed and placed in
the environment exported to that command.
Also set to the full pathname used to invoke each command executed
and placed in the environment exported to that command.
When checking mail, this parameter holds the name of the mail file
currently being checked.
.PD
+46 -26
View File
@@ -1,4 +1,4 @@
.\"
\"
.\" MAN PAGE COMMENTS to
.\"
.\" Chet Ramey
@@ -6,12 +6,12 @@
.\" Case Western Reserve University
.\" chet@po.CWRU.Edu
.\"
.\" Last Change: Sat Nov 13 15:05:55 EST 2004
.\" Last Change: Tue Jan 4 17:23:59 EST 2005
.\"
.\" bash_builtins, strip all but Built-Ins section
.if \n(zZ=1 .ig zZ
.if \n(zY=1 .ig zY
.TH BASH 1 "2004 Nov 13" "GNU Bash-3.1-devel"
.TH BASH 1 "2005 Jan 4" "GNU Bash-3.1-devel"
.\"
.\" There's some problem with having a `@'
.\" in a tagged paragraph with the BSD man macros.
@@ -51,8 +51,8 @@ bash \- GNU Bourne-Again SHell
[options]
[file]
.SH COPYRIGHT
.if n Bash is Copyright (C) 1989-2004 by the Free Software Foundation, Inc.
.if t Bash is Copyright \(co 1989-2004 by the Free Software Foundation, Inc.
.if n Bash is Copyright (C) 1989-2005 by the Free Software Foundation, Inc.
.if t Bash is Copyright \(co 1989-2005 by the Free Software Foundation, Inc.
.SH DESCRIPTION
.B Bash
is an \fBsh\fR-compatible command language interpreter that
@@ -895,7 +895,11 @@ Each of the \fImetacharacters\fP listed above under
has special meaning to the shell and must be quoted if it is to
represent itself.
.PP
When the command history expansion facilities are being used, the
When the command history expansion facilities are being used
(see
.SM
.B HISTORY EXPANSION
below), the
\fIhistory expansion\fP character, usually \fB!\fP, must be quoted
to prevent history expansion.
.PP
@@ -919,8 +923,9 @@ Enclosing characters in double quotes preserves the literal value
of all characters within the quotes, with the exception of
.BR $ ,
.BR ` ,
and
.BR \e .
.BR \e ,
and, when history expansion is enabled,
.BR ! .
The characters
.B $
and
@@ -936,8 +941,12 @@ or
.BR <newline> .
A double quote may be quoted within double quotes by preceding it with
a backslash.
When command history is being used, the double quote may not be used to
quote the history expansion character.
If enabled, history expansion will be performed unless an
.B !
appearing in double quotes is escaped using a backslash.
The backslash preceding the
.B !
is not removed.
.PP
The special parameters
.B *
@@ -951,7 +960,7 @@ below).
.PP
Words of the form \fB$\fP'\fIstring\fP' are treated specially. The
word expands to \fIstring\fP, with backslash-escaped characters replaced
as specifed by the ANSI C standard. Backslash escape sequences, if
as specified by the ANSI C standard. Backslash escape sequences, if
present, are decoded as follows:
.RS
.PD 0
@@ -2273,7 +2282,7 @@ interpreted as part of the name.
.PP
When braces are used, the matching ending brace is the first `\fB}\fP'
not escaped by a backslash or within a quoted string, and not within an
embedded arithmetic expansion, command substitution, or paramter
embedded arithmetic expansion, command substitution, or parameter
expansion.
.PP
.PD 0
@@ -3320,19 +3329,21 @@ environment are identical between a function and its caller
with the exception that the
.SM
.B DEBUG
trap (see the description of the
and
.B RETURN
traps (see the description of the
.B trap
builtin under
.SM
.B SHELL BUILTIN COMMANDS
below) is not inherited unless the function has been given the
below) are not inherited unless the function has been given the
\fBtrace\fP attribute (see the description of the
.SM
.B declare
builtin below) or the
\fB\-o functrace\fP shell option has been enabled with
the \fBset\fP builtin
(in which case all functions inherit the \fBDEBUG\fP trap).
(in which case all functions inherit the \fBDEBUG\fP and \fBRETURN\fP traps).
.PP
Variables local to the function may be declared with the
.B local
@@ -3471,7 +3482,7 @@ If \fIbase#\fP is omitted, then base 10 is used.
The digits greater than 9 are represented by the lowercase letters,
the uppercase letters, @, and _, in that order.
If \fIbase\fP is less than or equal to 36, lowercase and uppercase
letters may be used interchangably to represent numbers between 10
letters may be used interchangeably to represent numbers between 10
and 35.
.PP
Operators are evaluated in order of precedence. Sub-expressions in
@@ -4594,7 +4605,7 @@ attempts word completion.
.TP
.B history-preserve-point
If set to \fBon\fP, the history code attempts to place point at the
same location on each history line retrived with \fBprevious-history\fP
same location on each history line retrieved with \fBprevious-history\fP
or \fBnext-history\fP.
.TP
.B horizontal\-scroll\-mode (Off)
@@ -4894,6 +4905,8 @@ With an argument
insert the \fIn\fPth word from the previous command (the words
in the previous command begin with word 0). A negative argument
inserts the \fIn\fPth word from the end of the previous command.
Once the argument \fIn\fP is computed, the argument is extracted
as if the "!\fIn\fP" history expansion had been specified.
.TP
.B
yank\-last\-arg (M\-.\^, M\-_\^)
@@ -4902,6 +4915,8 @@ the previous history entry). With an argument,
behave exactly like \fByank\-nth\-arg\fP.
Successive calls to \fByank\-last\-arg\fP move back through the history
list, inserting the last argument of each line in turn.
The history expansion facilities are used to extract the last argument,
as if the "!$" history expansion had been specified.
.TP
.B shell\-expand\-line (M\-C\-e)
Expand the line as the shell does. This
@@ -5378,7 +5393,7 @@ special variable as delimiters.
Shell quoting is honored.
Each word is then expanded using
brace expansion, tilde expansion, parameter and variable expansion,
command substitution, arithmetic expansion, and pathname expansion,
command substitution, and arithmetic expansion,
as described above under
.SM
.BR EXPANSION .
@@ -6420,7 +6435,8 @@ by subsequent assignment statements or unset.
.TP
.B \-t
Give each \fIname\fP the \fItrace\fP attribute.
Traced functions inherit the \fBDEBUG\fP trap from the calling shell.
Traced functions inherit the \fBDEBUG\fP and \fBRETURN\fP traps from
the calling shell.
The trace attribute has no special meaning for variables.
.TP
.B \-x
@@ -7479,7 +7495,10 @@ before execution resumes after the function or script.
.TP
\fBset\fP [\fB\-\-abefhkmnptuvxBCHP\fP] [\fB\-o\fP \fIoption\fP] [\fIarg\fP ...]
Without options, the name and value of each shell variable are displayed
in a format that can be reused as input.
in a format that can be reused as input
for setting or resetting the currently-set variables.
Read-only variables cannot be reset.
In \fIposix mode\fP, only shell variables are listed.
The output is sorted according to the current locale.
When options are specified, they set or unset shell attributes.
Any arguments remaining after the options are processed are treated
@@ -7652,7 +7671,7 @@ This option is disabled by default.
Change the behavior of
.B bash
where the default operation differs
from the POSIX 1003.2 standard to match the standard (\fI`posix mode\fP).
from the POSIX 1003.2 standard to match the standard (\fIposix mode\fP).
.TP 8
.B privileged
Same as
@@ -7766,9 +7785,11 @@ follows the logical chain of directories when performing commands
which change the current directory.
.TP 8
.B \-T
If set, any trap on \fBDEBUG\fP is inherited by shell functions, command
substitutions, and commands executed in a subshell environment.
The \fBDEBUG\fP trap is normally not inherited in such cases.
If set, any traps on \fBDEBUG\fP and \fBRETURN\fP are inherited by shell
functions, command substitutions, and commands executed in a
subshell environment.
The \fBDEBUG\fP and \fBRETURN\fP traps are normally not inherited
in such cases.
.TP 8
.B \-\-
If no arguments follow this option, then the positional parameters are
@@ -8531,8 +8552,7 @@ refers to a shell variable.
Read-only variables may not be unset.
If
.B \-f
is specifed,
each
is specified, each
.I name
refers to a shell function, and the function definition
is removed.
+5 -4
View File
@@ -1314,12 +1314,13 @@ to the filename used to invoke Bash, as given by argument zero.
@item _
(An underscore.)
At shell startup, set to the absolute filename of the shell or shell
script being executed as passed in the argument list.
At shell startup, set to the absolute pathname used to invoke the
shell or shell script being executed as passed in the environment
or argument list.
Subsequently, expands to the last argument to the previous command,
after expansion.
Also set to the full pathname of each command executed and placed in
the environment exported to that command.
Also set to the full pathname used to invoke each command executed
and placed in the environment exported to that command.
When checking mail, this parameter holds the name of the mail file.
@end vtable
+51 -26
View File
@@ -16,7 +16,7 @@ This is Edition @value{EDITION}, last updated @value{UPDATED},
of @cite{The GNU Bash Reference Manual},
for @code{Bash}, Version @value{VERSION}.
Copyright @copyright{} 1988-2004 Free Software Foundation, Inc.
Copyright @copyright{} 1988-2005 Free Software Foundation, Inc.
Permission is granted to make and distribute verbatim copies of
this manual provided the copyright notice and this permission notice
@@ -457,7 +457,8 @@ parameter expansion.
Each of the shell metacharacters (@pxref{Definitions})
has special meaning to the shell and must be quoted if it is to
represent itself.
When the command history expansion facilities are being used, the
When the command history expansion facilities are being used
(@pxref{History Interaction}), the
@var{history expansion} character, usually @samp{!}, must be quoted
to prevent history expansion. @xref{Bash History Facilities}, for
more details concerning history expansion.
@@ -486,7 +487,8 @@ between single quotes, even when preceded by a backslash.
Enclosing characters in double quotes (@samp{"}) preserves the literal value
of all characters within the quotes, with the exception of
@samp{$}, @samp{`}, and @samp{\}.
@samp{$}, @samp{`}, @samp{\},
and, when history expansion is enabled, @samp{!}.
The characters @samp{$} and @samp{`}
retain their special meaning within double quotes (@pxref{Shell Expansions}).
The backslash retains its special meaning only when followed by one of
@@ -497,8 +499,9 @@ characters are removed. Backslashes preceding characters without a
special meaning are left unmodified.
A double quote may be quoted within double quotes by preceding it with
a backslash.
When command history is being used, the double quote may not be used to
quote the history expansion character.
If enabled, history expansion will be performed unless an @samp{!}
appearing in double quotes is escaped using a backslash.
The backslash preceding the @samp{!} is not removed.
The special parameters @samp{*} and @samp{@@} have special meaning
when in double quotes (@pxref{Shell Parameter Expansion}).
@@ -1118,12 +1121,12 @@ The first element of the @env{FUNCNAME} variable is set to the
name of the function while the function is executing.
All other aspects of the shell execution
environment are identical between a function and its caller
with the exception that the @env{DEBUG} trap
below) is not inherited unless the function has been given the
with the exception that the @env{DEBUG} and @env{RETURN} traps
are not inherited unless the function has been given the
@code{trace} attribute using the @code{declare} builtin or
the @code{-o functrace} option has been enabled with
the @code{set} builtin,
(in which case all functions inherit the @code{DEBUG} trap).
(in which case all functions inherit the @env{DEBUG} and @env{RETURN} traps).
@xref{Bourne Shell Builtins}, for the description of the
@code{trap} builtin.
@@ -1311,12 +1314,13 @@ to the filename used to invoke Bash, as given by argument zero.
@item _
(An underscore.)
At shell startup, set to the absolute filename of the shell or shell
script being executed as passed in the argument list.
At shell startup, set to the absolute file name used to invoke the
shell or shell script being executed as passed in the environment
or argument list.
Subsequently, expands to the last argument to the previous command,
after expansion.
Also set to the full pathname of each command executed and placed in
the environment exported to that command.
Also set to the full pathname used to invoke each command executed
and placed in the environment exported to that command.
When checking mail, this parameter holds the name of the mail file.
@end vtable
@@ -3283,7 +3287,8 @@ by subsequent assignment statements or unset.
@item -t
Give each @var{name} the @code{trace} attribute.
Traced functions inherit the @code{DEBUG} trap from the calling shell.
Traced functions inherit the @code{DEBUG} and @code{RETURN} traps from
the calling shell.
The trace attribute has no special meaning for variables.
@item -x
@@ -3912,7 +3917,10 @@ set [--abefhkmnptuvxBCHP] [-o @var{option}] [@var{argument} @dots{}]
If no options or arguments are supplied, @code{set} displays the names
and values of all shell variables and functions, sorted according to the
current locale, in a format that may be reused as input.
current locale, in a format that may be reused as input
for setting or resetting the currently-set variables.
Read-only variables cannot be reset.
In @sc{posix} mode, only shell variables are listed.
When options are supplied, they set or unset shell attributes.
Options, if specified, have the following meanings:
@@ -4123,9 +4131,11 @@ $ cd ..; pwd
@end example
@item -T
If set, any trap on @code{DEBUG} is inherited by shell functions, command
substitutions, and commands executed in a subshell environment.
The @code{DEBUG} trap is normally not inherited in such cases.
If set, any trap on @code{DEBUG} and @code{RETURN} are inherited by
shell functions, command substitutions, and commands executed
in a subshell environment.
The @code{DEBUG} and @code{RETURN} traps are normally not inherited
in such cases.
@item --
If no arguments follow this option, then the positional parameters are
@@ -5444,7 +5454,7 @@ omitted, then base 10 is used.
The digits greater than 9 are represented by the lowercase letters,
the uppercase letters, @samp{@@}, and @samp{_}, in that order.
If @var{base} is less than or equal to 36, lowercase and uppercase
letters may be used interchangably to represent numbers between 10
letters may be used interchangeably to represent numbers between 10
and 35.
Operators are evaluated in order of precedence. Sub-expressions in
@@ -6636,7 +6646,7 @@ A synonym for @code{--with-bash-malloc}.
@item --with-installed-readline[=@var{PREFIX}]
Define this to make Bash link with a locally-installed version of Readline
rather than the version in @file{lib/readline}. This works only with
Readline 4.3 and later versions. If @var{PREFIX} is @code{yes} or not
Readline 5.0 and later versions. If @var{PREFIX} is @code{yes} or not
supplied, @code{configure} uses the values of the make variables
@code{includedir} and @code{libdir}, which are subdirectories of @code{prefix}
by default, to find the installed version of Readline if it is not in
@@ -6724,6 +6734,9 @@ Include support for matching POSIX regular expressions using the
@samp{=~} binary operator in the @code{[[} conditional command.
(@pxref{Conditional Constructs}).
@item --enable-debugger
Include support for the bash debugger (distributed separately).
@item --enable-directory-stack
Include support for a @code{csh}-like directory stack and the
@code{pushd}, @code{popd}, and @code{dirs} builtins
@@ -6769,17 +6782,17 @@ when used in redirections (@pxref{Redirections}).
This enables process substitution (@pxref{Process Substitution}) if
the operating system provides the necessary support.
@item --enable-progcomp
Enable the programmable completion facilities
(@pxref{Programmable Completion}).
If Readline is not enabled, this option has no effect.
@item --enable-prompt-string-decoding
Turn on the interpretation of a number of backslash-escaped characters
in the @env{$PS1}, @env{$PS2}, @env{$PS3}, and @env{$PS4} prompt
strings. See @ref{Printing a Prompt}, for a complete list of prompt
string escape sequences.
@item --enable-progcomp
Enable the programmable completion facilities
(@pxref{Programmable Completion}).
If Readline is not enabled, this option has no effect.
@item --enable-readline
Include support for command-line editing and history with the Bash
version of the Readline library (@pxref{Command Line Editing}).
@@ -6793,6 +6806,16 @@ when called as @code{rbash}, enters a restricted mode. See
Include the @code{select} builtin, which allows the generation of simple
menus (@pxref{Conditional Constructs}).
@item --enable-separate-helpfiles
Use external files for the documentation displayed by the @code{help} builtin
instead of storing the text internally.
@item --enable-single-help-strings
Store the text displayed by the @code{help} builtin as a single string for
each help topic. This aids in translating the text to different languages.
You may need to disable this if your compiler cannot handle very long string
literals.
@item --enable-usg-echo-default
A synonym for @code{--enable-xpg-echo-default}.
@@ -6801,7 +6824,7 @@ Make the @code{echo} builtin expand backslash-escaped characters by default,
without requiring the @option{-e} option.
This sets the default value of the @code{xpg_echo} shell option to @code{on},
which makes the Bash @code{echo} behave more like the version specified in
the Single Unix Specification, version 2.
the Single Unix Specification, version 3.
@xref{Bash Builtins}, for a description of the escape sequences that
@code{echo} recognizes.
@@ -7181,7 +7204,9 @@ The @code{trap} builtin (@pxref{Bourne Shell Builtins}) allows a
Commands specified with an @code{RETURN} trap are executed before
execution resumes after a shell function or a shell script executed with
@code{.} or @code{source} returns.
The @code{RETURN} trap is not inherited by shell functions.
The @code{RETURN} trap is not inherited by shell functions unless the
function has been given the @code{trace} attribute or the
@code{functrace} option has been enabled using the @code{shopt} builtin.
@item
The Bash @code{type} builtin is more extensive and gives more information
+3 -3
View File
@@ -2,9 +2,9 @@
Copyright (C) 1988-2005 Free Software Foundation, Inc.
@end ignore
@set LASTCHANGE Thu Dec 30 17:00:22 EST 2004
@set LASTCHANGE Fri Feb 11 15:43:59 EST 2005
@set EDITION 3.1-devel
@set VERSION 3.1-devel
@set UPDATED 30 December 2004
@set UPDATED-MONTH December 2004
@set UPDATED 11 February 2005
@set UPDATED-MONTH February 2005
+4 -5
View File
@@ -1,11 +1,10 @@
@ignore
Copyright (C) 1988-2004 Free Software Foundation, Inc.
Copyright (C) 1988-2005 Free Software Foundation, Inc.
@end ignore
@set LASTCHANGE Sat Nov 13 15:06:31 EST 2004
@set LASTCHANGE Thu Dec 30 17:00:22 EST 2004
@set EDITION 3.1-devel
@set VERSION 3.1-devel
@set UPDATED 13 November 2004
@set UPDATED-MONTH November 2004
@set UPDATED 30 December 2004
@set UPDATED-MONTH December 2004
+6 -2
View File
@@ -1,6 +1,6 @@
/* execute_command.c -- Execute a COMMAND structure. */
/* Copyright (C) 1987-2004 Free Software Foundation, Inc.
/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -491,6 +491,7 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
{
int exec_result, invert, ignore_return, was_error_trap;
REDIRECT *my_undo_list, *exec_undo_list;
volatile int last_pid;
volatile int save_line_number;
if (command == 0 || breaking || continuing || read_but_dont_execute)
@@ -647,7 +648,10 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
/* We can't rely on variables retaining their values across a
call to execute_simple_command if a longjmp occurs as the
result of a `return' builtin. This is true for sure with gcc. */
#if defined (RECYCLES_PIDS)
last_made_pid = NO_PID;
#endif
last_pid = last_made_pid;
was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0;
if (ignore_return && command->value.Simple)
@@ -677,7 +681,7 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
/* XXX - this is something to watch out for if there are problems
when the shell is compiled without job control. */
if (already_making_children && pipe_out == NO_PIPE &&
last_made_pid != NO_PID)
last_made_pid != last_pid)
{
stop_pipeline (asynchronous, (COMMAND *)NULL);
+12 -19
View File
@@ -491,6 +491,7 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
{
int exec_result, invert, ignore_return, was_error_trap;
REDIRECT *my_undo_list, *exec_undo_list;
volatile int last_pid;
volatile int save_line_number;
if (command == 0 || breaking || continuing || read_but_dont_execute)
@@ -647,7 +648,10 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
/* We can't rely on variables retaining their values across a
call to execute_simple_command if a longjmp occurs as the
result of a `return' builtin. This is true for sure with gcc. */
#if defined (RECYCLES_PIDS)
last_made_pid = NO_PID;
#endif
last_pid = last_made_pid;
was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0;
if (ignore_return && command->value.Simple)
@@ -677,7 +681,7 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
/* XXX - this is something to watch out for if there are problems
when the shell is compiled without job control. */
if (already_making_children && pipe_out == NO_PIPE &&
last_made_pid != NO_PID)
last_made_pid != last_pid)
{
stop_pipeline (asynchronous, (COMMAND *)NULL);
@@ -2741,35 +2745,20 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
if (dofork)
{
#if 0
/* XXX memory leak if expand_words() error causes a jump_to_top_level */
command_line = savestring (the_printed_command);
#endif
/* Do this now, because execute_disk_command will do it anyway in the
vast majority of cases. */
maybe_make_export_env ();
#if 0
if (make_child (command_line, async) == 0)
#else
if (make_child (savestring (the_printed_command), async) == 0)
#endif
{
already_forked = 1;
simple_command->flags |= CMD_NO_FORK;
#if 0
subshell_environment = (pipe_in != NO_PIPE || pipe_out != NO_PIPE)
? (SUBSHELL_PIPE|SUBSHELL_FORK)
: (SUBSHELL_ASYNC|SUBSHELL_FORK);
#else
subshell_environment = SUBSHELL_FORK;
if (pipe_in != NO_PIPE || pipe_out != NO_PIPE)
subshell_environment |= SUBSHELL_PIPE;
if (async)
subshell_environment |= SUBSHELL_ASYNC;
#endif
/* We need to do this before piping to handle some really
pathological cases where one of the pipe file descriptors
@@ -3187,7 +3176,13 @@ execute_function (var, words, flags, fds_to_close, async, subshell)
restore_default_signal (ERROR_TRAP);
}
/* Shell functions inherit the RETURN trap if function tracing is on
globally or on individually for this function. */
#if 0
if (return_trap && ((trace_p (var) == 0) && function_trace_mode == 0))
#else
if (return_trap && (signal_in_progress (DEBUG_TRAP) || ((trace_p (var) == 0) && function_trace_mode == 0)))
#endif
{
if (subshell == 0)
{
@@ -3242,12 +3237,10 @@ execute_function (var, words, flags, fds_to_close, async, subshell)
if (return_val)
{
result = return_catch_value;
#if 0
/* Run the RETURN trap in the function's context */
/* Run the RETURN trap in the function's context. */
save_current = currently_executing_command;
run_return_trap ();
currently_executing_command = save_current;
#endif
}
else
{
+573
View File
@@ -0,0 +1,573 @@
/* findcmd.c -- Functions to search for commands by name. */
/* Copyright (C) 1997 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 2, or (at your option)
any later version.
Bash is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with Bash; see the file COPYING. If not, write to the
Free Software Foundation Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. */
#include "config.h"
#include <stdio.h>
#include "chartypes.h"
#include "bashtypes.h"
#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
# include <sys/file.h>
#endif
#include "filecntl.h"
#include "posixstat.h"
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "bashansi.h"
#include "memalloc.h"
#include "shell.h"
#include "flags.h"
#include "hashlib.h"
#include "pathexp.h"
#include "hashcmd.h"
#include "findcmd.h" /* matching prototypes and declarations */
extern int posixly_correct;
/* Static functions defined and used in this file. */
static char *_find_user_command_internal __P((const char *, int));
static char *find_user_command_internal __P((const char *, int));
static char *find_user_command_in_path __P((const char *, char *, int));
static char *find_in_path_element __P((const char *, char *, int, int, struct stat *));
static char *find_absolute_program __P((const char *, int));
static char *get_next_path_element __P((char *, int *));
/* The file name which we would try to execute, except that it isn't
possible to execute it. This is the first file that matches the
name that we are looking for while we are searching $PATH for a
suitable one to execute. If we cannot find a suitable executable
file, then we use this one. */
static char *file_to_lose_on;
/* Non-zero if we should stat every command found in the hash table to
make sure it still exists. */
int check_hashed_filenames;
/* DOT_FOUND_IN_SEARCH becomes non-zero when find_user_command ()
encounters a `.' as the directory pathname while scanning the
list of possible pathnames; i.e., if `.' comes before the directory
containing the file of interest. */
int dot_found_in_search = 0;
#define u_mode_bits(x) (((x) & 0000700) >> 6)
#define g_mode_bits(x) (((x) & 0000070) >> 3)
#define o_mode_bits(x) (((x) & 0000007) >> 0)
#define X_BIT(x) ((x) & 1)
/* Return some flags based on information about this file.
The EXISTS bit is non-zero if the file is found.
The EXECABLE bit is non-zero the file is executble.
Zero is returned if the file is not found. */
int
file_status (name)
const char *name;
{
struct stat finfo;
/* Determine whether this file exists or not. */
if (stat (name, &finfo) < 0)
return (0);
/* If the file is a directory, then it is not "executable" in the
sense of the shell. */
if (S_ISDIR (finfo.st_mode))
return (FS_EXISTS|FS_DIRECTORY);
#if defined (AFS)
/* We have to use access(2) to determine access because AFS does not
support Unix file system semantics. This may produce wrong
answers for non-AFS files when ruid != euid. I hate AFS. */
return ((access (name, X_OK) == 0) ? (FS_EXISTS|FS_EXECABLE) : FS_EXISTS);
#else /* !AFS */
/* Find out if the file is actually executable. By definition, the
only other criteria is that the file has an execute bit set that
we can use. */
/* Root only requires execute permission for any of owner, group or
others to be able to exec a file. */
if (current_user.euid == (uid_t)0)
{
int bits;
bits = (u_mode_bits (finfo.st_mode) |
g_mode_bits (finfo.st_mode) |
o_mode_bits (finfo.st_mode));
return ((X_BIT (bits)) ? (FS_EXISTS | FS_EXECABLE) : FS_EXISTS);
}
/* If we are the owner of the file, the owner execute bit applies. */
if (current_user.euid == finfo.st_uid)
return ((X_BIT (u_mode_bits (finfo.st_mode))) ? (FS_EXISTS | FS_EXECABLE) : FS_EXISTS);
/* If we are in the owning group, the group permissions apply. */
else if (group_member (finfo.st_gid))
return ((X_BIT (g_mode_bits (finfo.st_mode))) ? (FS_EXISTS | FS_EXECABLE) : FS_EXISTS);
/* Else we check whether `others' have permission to execute the file */
else
return ((X_BIT (o_mode_bits (finfo.st_mode))) ? (FS_EXISTS | FS_EXECABLE) : FS_EXISTS);
#endif /* !AFS */
}
/* Return non-zero if FILE exists and is executable.
Note that this function is the definition of what an
executable file is; do not change this unless YOU know
what an executable file is. */
int
executable_file (file)
const char *file;
{
int s;
s = file_status (file);
return ((s & FS_EXECABLE) && ((s & FS_DIRECTORY) == 0));
}
int
is_directory (file)
const char *file;
{
return (file_status (file) & FS_DIRECTORY);
}
int
executable_or_directory (file)
const char *file;
{
int s;
s = file_status (file);
return ((s & FS_EXECABLE) || (s & FS_DIRECTORY));
}
/* Locate the executable file referenced by NAME, searching along
the contents of the shell PATH variable. Return a new string
which is the full pathname to the file, or NULL if the file
couldn't be found. If a file is found that isn't executable,
and that is the only match, then return that. */
char *
find_user_command (name)
const char *name;
{
return (find_user_command_internal (name, FS_EXEC_PREFERRED|FS_NODIRS));
}
/* Locate the file referenced by NAME, searching along the contents
of the shell PATH variable. Return a new string which is the full
pathname to the file, or NULL if the file couldn't be found. This
returns the first file found. */
char *
find_path_file (name)
const char *name;
{
return (find_user_command_internal (name, FS_EXISTS));
}
static char *
_find_user_command_internal (name, flags)
const char *name;
int flags;
{
char *path_list, *cmd;
SHELL_VAR *var;
/* Search for the value of PATH in both the temporary environments and
in the regular list of variables. */
if (var = find_variable_internal ("PATH", 1)) /* XXX could be array? */
path_list = value_cell (var);
else
path_list = (char *)NULL;
if (path_list == 0 || *path_list == '\0')
return (savestring (name));
cmd = find_user_command_in_path (name, path_list, flags);
return (cmd);
}
static char *
find_user_command_internal (name, flags)
const char *name;
int flags;
{
#ifdef __WIN32__
char *res, *dotexe;
dotexe = (char *)xmalloc (strlen (name) + 5);
strcpy (dotexe, name);
strcat (dotexe, ".exe");
res = _find_user_command_internal (dotexe, flags);
free (dotexe);
if (res == 0)
res = _find_user_command_internal (name, flags);
return res;
#else
return (_find_user_command_internal (name, flags));
#endif
}
/* Return the next element from PATH_LIST, a colon separated list of
paths. PATH_INDEX_POINTER is the address of an index into PATH_LIST;
the index is modified by this function.
Return the next element of PATH_LIST or NULL if there are no more. */
static char *
get_next_path_element (path_list, path_index_pointer)
char *path_list;
int *path_index_pointer;
{
char *path;
path = extract_colon_unit (path_list, path_index_pointer);
if (path == 0)
return (path);
if (*path == '\0')
{
free (path);
path = savestring (".");
}
return (path);
}
/* Look for PATHNAME in $PATH. Returns either the hashed command
corresponding to PATHNAME or the first instance of PATHNAME found
in $PATH. Returns a newly-allocated string. */
char *
search_for_command (pathname)
const char *pathname;
{
char *hashed_file, *command;
int temp_path, st;
SHELL_VAR *path;
hashed_file = command = (char *)NULL;
/* If PATH is in the temporary environment for this command, don't use the
hash table to search for the full pathname. */
path = find_variable_internal ("PATH", 1);
temp_path = path && tempvar_p (path);
if (temp_path == 0 && path)
path = (SHELL_VAR *)NULL;
/* Don't waste time trying to find hashed data for a pathname
that is already completely specified or if we're using a command-
specific value for PATH. */
if (path == 0 && absolute_program (pathname) == 0)
hashed_file = phash_search (pathname);
/* If a command found in the hash table no longer exists, we need to
look for it in $PATH. Thank you Posix.2. This forces us to stat
every command found in the hash table. */
if (hashed_file && (posixly_correct || check_hashed_filenames))
{
st = file_status (hashed_file);
if ((st ^ (FS_EXISTS | FS_EXECABLE)) != 0)
{
phash_remove (pathname);
free (hashed_file);
hashed_file = (char *)NULL;
}
}
if (hashed_file)
command = hashed_file;
else if (absolute_program (pathname))
/* A command containing a slash is not looked up in PATH or saved in
the hash table. */
command = savestring (pathname);
else
{
/* If $PATH is in the temporary environment, we've already retrieved
it, so don't bother trying again. */
if (temp_path)
{
command = find_user_command_in_path (pathname, value_cell (path),
FS_EXEC_PREFERRED|FS_NODIRS);
}
else
command = find_user_command (pathname);
if (command && hashing_enabled && temp_path == 0)
phash_insert ((char *)pathname, command, dot_found_in_search, 1); /* XXX fix const later */
}
return (command);
}
char *
user_command_matches (name, flags, state)
const char *name;
int flags, state;
{
register int i;
int path_index, name_len;
char *path_list, *path_element, *match;
struct stat dotinfo;
static char **match_list = NULL;
static int match_list_size = 0;
static int match_index = 0;
if (state == 0)
{
/* Create the list of matches. */
if (match_list == 0)
{
match_list_size = 5;
match_list = strvec_create (match_list_size);
}
/* Clear out the old match list. */
for (i = 0; i < match_list_size; i++)
match_list[i] = 0;
/* We haven't found any files yet. */
match_index = 0;
if (absolute_program (name))
{
match_list[0] = find_absolute_program (name, flags);
match_list[1] = (char *)NULL;
path_list = (char *)NULL;
}
else
{
name_len = strlen (name);
file_to_lose_on = (char *)NULL;
dot_found_in_search = 0;
stat (".", &dotinfo);
path_list = get_string_value ("PATH");
path_index = 0;
}
while (path_list && path_list[path_index])
{
path_element = get_next_path_element (path_list, &path_index);
if (path_element == 0)
break;
match = find_in_path_element (name, path_element, flags, name_len, &dotinfo);
free (path_element);
if (match == 0)
continue;
if (match_index + 1 == match_list_size)
{
match_list_size += 10;
match_list = strvec_resize (match_list, (match_list_size + 1));
}
match_list[match_index++] = match;
match_list[match_index] = (char *)NULL;
FREE (file_to_lose_on);
file_to_lose_on = (char *)NULL;
}
/* We haven't returned any strings yet. */
match_index = 0;
}
match = match_list[match_index];
if (match)
match_index++;
return (match);
}
static char *
find_absolute_program (name, flags)
const char *name;
int flags;
{
int st;
st = file_status (name);
/* If the file doesn't exist, quit now. */
if ((st & FS_EXISTS) == 0)
return ((char *)NULL);
/* If we only care about whether the file exists or not, return
this filename. Otherwise, maybe we care about whether this
file is executable. If it is, and that is what we want, return it. */
if ((flags & FS_EXISTS) || ((flags & FS_EXEC_ONLY) && (st & FS_EXECABLE)))
return (savestring (name));
return (NULL);
}
static char *
find_in_path_element (name, path, flags, name_len, dotinfop)
const char *name;
char *path;
int flags, name_len;
struct stat *dotinfop;
{
int status;
char *full_path, *xpath;
xpath = (*path == '~') ? bash_tilde_expand (path, 0) : path;
/* Remember the location of "." in the path, in all its forms
(as long as they begin with a `.', e.g. `./.') */
if (dot_found_in_search == 0 && *xpath == '.')
dot_found_in_search = same_file (".", xpath, dotinfop, (struct stat *)NULL);
full_path = sh_makepath (xpath, name, 0);
status = file_status (full_path);
itrace("find_in_path_element: %s (%s) -> %d", full_path, xpath, status);
if (xpath != path)
free (xpath);
if ((status & FS_EXISTS) == 0)
{
free (full_path);
return ((char *)NULL);
}
/* The file exists. If the caller simply wants the first file, here it is. */
if (flags & FS_EXISTS)
return (full_path);
/* If the file is executable, then it satisfies the cases of
EXEC_ONLY and EXEC_PREFERRED. Return this file unconditionally. */
if ((status & FS_EXECABLE) &&
(((flags & FS_NODIRS) == 0) || ((status & FS_DIRECTORY) == 0)))
{
FREE (file_to_lose_on);
file_to_lose_on = (char *)NULL;
return (full_path);
}
/* The file is not executable, but it does exist. If we prefer
an executable, then remember this one if it is the first one
we have found. */
if ((flags & FS_EXEC_PREFERRED) && file_to_lose_on == 0)
file_to_lose_on = savestring (full_path);
/* If we want only executable files, or we don't want directories and
this file is a directory, fail. */
if ((flags & FS_EXEC_ONLY) || (flags & FS_EXEC_PREFERRED) ||
((flags & FS_NODIRS) && (status & FS_DIRECTORY)))
{
free (full_path);
return ((char *)NULL);
}
else
return (full_path);
}
/* This does the dirty work for find_user_command_internal () and
user_command_matches ().
NAME is the name of the file to search for.
PATH_LIST is a colon separated list of directories to search.
FLAGS contains bit fields which control the files which are eligible.
Some values are:
FS_EXEC_ONLY: The file must be an executable to be found.
FS_EXEC_PREFERRED: If we can't find an executable, then the
the first file matching NAME will do.
FS_EXISTS: The first file found will do.
FS_NODIRS: Don't find any directories.
*/
static char *
find_user_command_in_path (name, path_list, flags)
const char *name;
char *path_list;
int flags;
{
char *full_path, *path;
int path_index, name_len;
struct stat dotinfo;
/* We haven't started looking, so we certainly haven't seen
a `.' as the directory path yet. */
dot_found_in_search = 0;
if (absolute_program (name))
{
full_path = find_absolute_program (name, flags);
return (full_path);
}
if (path_list == 0 || *path_list == '\0')
return (savestring (name)); /* XXX */
file_to_lose_on = (char *)NULL;
name_len = strlen (name);
stat (".", &dotinfo);
path_index = 0;
while (path_list[path_index])
{
/* Allow the user to interrupt out of a lengthy path search. */
QUIT;
path = get_next_path_element (path_list, &path_index);
if (path == 0)
break;
/* Side effects: sets dot_found_in_search, possibly sets
file_to_lose_on. */
full_path = find_in_path_element (name, path, flags, name_len, &dotinfo);
free (path);
/* This should really be in find_in_path_element, but there isn't the
right combination of flags. */
if (full_path && is_directory (full_path))
{
free (full_path);
continue;
}
if (full_path)
{
FREE (file_to_lose_on);
return (full_path);
}
}
/* We didn't find exactly what the user was looking for. Return
the contents of FILE_TO_LOSE_ON which is NULL when the search
required an executable, or non-NULL if a file was found and the
search would accept a non-executable as a last resort. If the
caller specified FS_NODIRS, and file_to_lose_on is a directory,
return NULL. */
if (file_to_lose_on && (flags & FS_NODIRS) && is_directory (file_to_lose_on))
{
free (file_to_lose_on);
file_to_lose_on = (char *)NULL;
}
return (file_to_lose_on);
}
+294 -52
View File
@@ -160,7 +160,9 @@ extern procenv_t wait_intr_buf;
extern int wait_signal_received;
extern WORD_LIST *subst_assign_varlist;
struct jobstats js = { -1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NO_JOB, NO_JOB };
struct jobstats js = { -1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NO_JOB, NO_JOB, 0, 0 };
struct bgpids bgpids = { 0, 0, 0 };
/* The array of known jobs. */
JOB **jobs = (JOB **)NULL;
@@ -234,12 +236,14 @@ static sighandler sigstop_sighandler __P((int));
static int waitchld __P((pid_t, int));
static PROCESS *find_pipeline __P((pid_t, int, int *));
static PROCESS *find_process __P((pid_t, int, int *));
static char *current_working_directory __P((void));
static char *job_working_directory __P((void));
static char *j_strsignal __P((int));
static char *printable_job_status __P((int, PROCESS *, int));
static PROCESS *find_last_proc __P((int, int));
static pid_t find_last_pid __P((int, int));
static int set_new_line_discipline __P((int));
@@ -247,7 +251,7 @@ static int map_over_jobs __P((sh_job_map_func_t *, int, int));
static int job_last_stopped __P((int));
static int job_last_running __P((int));
static int most_recent_job_in_state __P((int, JOB_STATE));
static int find_job __P((pid_t, int));
static int find_job __P((pid_t, int, PROCESS **));
static int print_job __P((JOB *, int, int, int));
static int process_exit_status __P((WAIT));
static int process_exit_signal __P((WAIT));
@@ -279,6 +283,13 @@ static void pipe_read __P((int *));
static void pipe_close __P((int *));
#endif
static struct pidstat *bgp_alloc __P((pid_t, int));
static struct pidstat *bgp_add __P((pid_t, int));
static int bgp_delete __P((pid_t));
static void bgp_clear __P((void));
static int bgp_search __P((pid_t));
static void bgp_prune __P((void));
#if defined (ARRAY_VARS)
static int *pstatuses; /* list of pipeline statuses */
static int statsize;
@@ -535,7 +546,7 @@ stop_pipeline (async, deferred)
if (the_pipeline)
{
register PROCESS *p;
int any_alive, any_stopped, n;
int any_running, any_stopped, n;
newjob = (JOB *)xmalloc (sizeof (JOB));
@@ -559,16 +570,16 @@ stop_pipeline (async, deferred)
/* Set the state of this pipeline. */
p = newjob->pipe;
any_alive = any_stopped = 0;
any_running = any_stopped = 0;
do
{
any_alive |= p->running;
any_stopped |= WIFSTOPPED (p->status);
any_running |= PRUNNING (p);
any_stopped |= PSTOPPED (p);
p = p->next;
}
while (p != newjob->pipe);
newjob->state = any_alive ? JRUNNING : (any_stopped ? JSTOPPED : JDEAD);
newjob->state = any_running ? JRUNNING : (any_stopped ? JSTOPPED : JDEAD);
newjob->wd = job_working_directory ();
newjob->deferred = deferred;
@@ -591,10 +602,17 @@ stop_pipeline (async, deferred)
else
newjob = (JOB *)NULL;
if (newjob)
js.j_lastmade = newjob;
if (async)
{
if (newjob)
newjob->flags &= ~J_FOREGROUND;
{
newjob->flags &= ~J_FOREGROUND;
newjob->flags |= J_ASYNC;
js.j_lastasync = newjob;
}
reset_current ();
}
else
@@ -621,9 +639,132 @@ stop_pipeline (async, deferred)
return (js.j_current);
}
/* Functions to manage the list of exited background pids whose status has
been saved. */
static struct pidstat *
bgp_alloc (pid, status)
pid_t pid;
int status;
{
struct pidstat *ps;
ps = (struct pidstat *)xmalloc (sizeof (struct pidstat));
ps->pid = pid;
ps->status = status;
ps->next = (struct pidstat *)0;
return ps;
}
static struct pidstat *
bgp_add (pid, status)
pid_t pid;
int status;
{
struct pidstat *ps;
ps = bgp_alloc (pid, status);
if (bgpids.list == 0)
{
bgpids.list = bgpids.end = ps;
bgpids.npid = 0; /* just to make sure */
}
else
{
bgpids.end->next = ps;
bgpids.end = ps;
}
bgpids.npid++;
if (bgpids.npid > js.c_childmax)
bgp_prune ();
return ps;
}
static int
bgp_delete (pid)
pid_t pid;
{
struct pidstat *prev, *p;
for (prev = p = bgpids.list; p; prev = p, p = p->next)
if (p->pid == pid)
{
prev->next = p->next; /* remove from list */
break;
}
if (p == 0)
return 0; /* not found */
itrace("bgp_delete: deleting %d", pid);
/* Housekeeping in the border cases. */
if (p == bgpids.list)
bgpids.list = bgpids.list->next;
else if (p == bgpids.end)
bgpids.end = prev;
bgpids.npid--;
if (bgpids.npid == 0)
bgpids.list = bgpids.end = 0;
else if (bgpids.npid == 1)
bgpids.end = bgpids.list; /* just to make sure */
free (p);
return 1;
}
/* Clear out the list of saved statuses */
static void
bgp_clear ()
{
struct pidstat *ps, *p;
for (ps = bgpids.list; ps; )
{
p = ps;
ps = ps->next;
free (p);
}
bgpids.list = bgpids.end = 0;
bgpids.npid = 0;
}
/* Search for PID in the list of saved background pids; return its status if
found. If not found, return -1. */
static int
bgp_search (pid)
pid_t pid;
{
struct pidstat *ps;
for (ps = bgpids.list ; ps; ps = ps->next)
if (ps->pid == pid)
return ps->status;
return -1;
}
static void
bgp_prune ()
{
struct pidstat *ps, *p;
while (bgpids.npid > js.c_childmax)
{
ps = bgpids.list;
bgpids.list = bgpids.list->next;
free (ps);
bgpids.npid--;
}
}
/* Reset the values of js.j_lastj and js.j_firstj after one or both have
been deleted. The caller should check whether js.j_njobs is 0 before
calling this. */
calling this. This wraps around, but the rest of the code does not. At
this point, it should not matter. */
static void
reset_job_indices ()
{
@@ -759,20 +900,30 @@ delete_job (job_index, warn_stopped)
int job_index, warn_stopped;
{
register JOB *temp;
int ndel;
PROCESS *proc;
int ndel, status;
pid_t pid;
if (js.j_jobslots == 0 || jobs_list_frozen)
return;
if (warn_stopped && subshell_environment == 0 && STOPPED (job_index))
internal_warning (_("deleting stopped job %d with process group %ld"), job_index+1, (long)jobs[job_index]->pgrp);
temp = jobs[job_index];
if (job_index == js.j_current || job_index == js.j_previous)
reset_current ();
proc = find_last_proc (job_index, 0);
/* Could do this just for J_ASYNC jobs, but we save all. */
bgp_add (proc->pid, process_exit_status (proc->status));
jobs[job_index] = (JOB *)NULL;
if (temp == js.j_lastmade)
js.j_lastmade = 0;
else if (temp == js.j_lastasync)
js.j_lastasync = 0;
free (temp->wd);
ndel = discard_pipeline (temp->pipe);
@@ -844,6 +995,21 @@ add_process (name, pid)
{
PROCESS *t, *p;
#if defined (RECYCLES_PIDS)
int j;
p = find_process (pid, 0, &j);
if (p)
{
# ifdef DEBUG
if (j == NO_JOB)
internal_warning ("add_process: process %5ld (%s) in the_pipeline", (long)p->pid, p->command);
# endif
if (PALIVE (p))
internal_warning ("add_process: pid %5ld (%s) marked as still alive", (long)p->pid, p->command);
p->running = PS_RECYCLED; /* mark as recycled */
}
#endif
t = (PROCESS *)xmalloc (sizeof (PROCESS));
t->next = the_pipeline;
t->pid = pid;
@@ -993,15 +1159,16 @@ kill_current_pipeline ()
}
/* Return the pipeline that PID belongs to. Note that the pipeline
doesn't have to belong to a job. Must be called with SIGCHLD blocked. */
doesn't have to belong to a job. Must be called with SIGCHLD blocked.
If JOBP is non-null, return the index of the job containing PID. */
static PROCESS *
find_pipeline (pid, running_only, jobp)
find_pipeline (pid, alive_only, jobp)
pid_t pid;
int running_only;
int alive_only;
int *jobp; /* index into jobs list or NO_JOB */
{
int job;
register PROCESS *p;
PROCESS *p;
/* See if this process is in the pipeline that we are building. */
if (jobp)
@@ -1011,33 +1178,48 @@ find_pipeline (pid, running_only, jobp)
p = the_pipeline;
do
{
/* Return it if we found it. */
if (p->pid == pid)
{
if ((running_only && PALIVE(p)) || (running_only == 0))
return (p);
}
/* Return it if we found it. Don't ever return a recycled pid. */
if (p->pid == pid && ((alive_only == 0 && PRECYCLED(p) == 0) || PALIVE(p)))
return (p);
p = p->next;
}
while (p != the_pipeline);
}
job = find_job (pid, running_only);
job = find_job (pid, alive_only, &p);
if (jobp)
*jobp = job;
return (job == NO_JOB) ? (PROCESS *)NULL : jobs[job]->pipe;
}
/* Return the PROCESS * describing PID. If JOBP is non-null return the index
into the jobs array of the job containing PID. Must be called with
SIGCHLD blocked. */
static PROCESS *
find_process (pid, alive_only, jobp)
pid_t pid;
int alive_only;
int *jobp; /* index into jobs list or NO_JOB */
{
PROCESS *p;
p = find_pipeline (pid, alive_only, jobp);
while (p && p->pid != pid)
p = p->next;
return p;
}
/* Return the job index that PID belongs to, or NO_JOB if it doesn't
belong to any job. Must be called with SIGCHLD blocked. */
static int
find_job (pid, running_only)
find_job (pid, alive_only, procp)
pid_t pid;
int running_only;
int alive_only;
PROCESS **procp;
{
register int i;
register PROCESS *p;
PROCESS *p;
/* XXX could use js.j_firstj here */
for (i = 0; i < js.j_jobslots; i++)
@@ -1050,10 +1232,11 @@ if (i < js.j_firstj && jobs[i])
do
{
if (p->pid == pid)
if (p->pid == pid && ((alive_only == 0 && PRECYCLED(p) == 0) || PALIVE(p)))
{
if ((running_only && PALIVE(p)) || (running_only == 0))
return (i);
if (procp)
*procp = p;
return (i);
}
p = p->next;
@@ -1078,7 +1261,7 @@ get_job_by_pid (pid, block)
if (block)
BLOCK_CHILD (set, oset);
job = find_job (pid, 0);
job = find_job (pid, 0, NULL);
if (block)
UNBLOCK_CHILD (oset);
@@ -1096,7 +1279,7 @@ describe_pid (pid)
BLOCK_CHILD (set, oset);
job = find_job (pid, 0);
job = find_job (pid, 0, NULL);
if (job != NO_JOB)
fprintf (stderr, "[%d] %ld\n", job + 1, (long)pid);
@@ -1498,7 +1681,12 @@ make_child (command, async_p)
#endif /* PGRP_PIPE */
if (async_p)
last_asynchronous_pid = getpid ();
last_asynchronous_pid = mypid;
#if defined (RECYCLES_PIDS)
else if (last_asynchronous_pid == mypid)
/* Avoid pid aliasing. 1 seems like a safe, unusual pid value. */
last_asynchronous_pid = 1;
#endif
}
else
{
@@ -1532,6 +1720,18 @@ make_child (command, async_p)
if (async_p)
last_asynchronous_pid = pid;
#if defined (RECYCLES_PIDS)
else if (last_asynchronous_pid == pid)
/* Avoid pid aliasing. 1 seems like a safe, unusual pid value. */
last_asynchronous_pid = 1;
#endif
#if !defined (RECYCLES_PIDS)
/* Only check for saved status if we've saved more than CHILD_MAX
statuses, unless the system recycles pids. */
if ((js.c_reaped + bgpids.npid) >= js.c_childmax)
#endif
bgp_delete (pid); /* new process, discard any saved status */
last_made_pid = pid;
@@ -1695,11 +1895,11 @@ set_tty_state ()
return 0;
}
/* Given an index into the jobs array JOB, return the pid of the last
/* Given an index into the jobs array JOB, return the PROCESS struct of the last
process in that job's pipeline. This is the one whose exit status
counts. Must be called with SIGCHLD blocked or queued. */
static pid_t
find_last_pid (job, block)
static PROCESS *
find_last_proc (job, block)
int job;
int block;
{
@@ -1716,9 +1916,21 @@ find_last_pid (job, block)
if (block)
UNBLOCK_CHILD (oset);
return (p->pid);
return (p);
}
static pid_t
find_last_pid (job, block)
int job;
int block;
{
PROCESS *p;
p = find_last_proc (job, block);
/* Possible race condition here. */
return p->pid;
}
/* Wait for a particular child of the shell to finish executing.
This low-level function prints an error message if PID is not
a child of this shell. It returns -1 if it fails, or whatever
@@ -1736,6 +1948,13 @@ wait_for_single_pid (pid)
child = find_pipeline (pid, 0, (int *)NULL);
UNBLOCK_CHILD (oset);
if (child == 0)
{
r = bgp_search (pid);
if (r >= 0)
return r;
}
if (child == 0)
{
internal_error (_("wait: pid %ld is not a child of this shell"), (long)pid);
@@ -1747,7 +1966,7 @@ wait_for_single_pid (pid)
/* POSIX.2: if we just waited for a job, we can remove it from the jobs
table. */
BLOCK_CHILD (set, oset);
job = find_job (pid, 0);
job = find_job (pid, 0, NULL);
if (job != NO_JOB && jobs[job] && DEADJOB (job))
jobs[job]->flags |= J_NOTIFIED;
UNBLOCK_CHILD (oset);
@@ -1802,6 +2021,7 @@ if (i < js.j_firstj && jobs[i])
`wait' is called with no arguments. */
mark_dead_jobs_as_notified (1);
cleanup_dead_jobs ();
bgp_clear ();
}
/* Make OLD_SIGINT_HANDLER the SIGINT signal handler. */
@@ -1985,13 +2205,13 @@ wait_for (pid)
We check for JDEAD in case the job state has been set by waitchld
after receipt of a SIGCHLD. */
if (job == NO_JOB)
job = find_job (pid, 0);
job = find_job (pid, 0, NULL);
/* waitchld() takes care of setting the state of the job. If the job
has already exited before this is called, sigchld_handler will have
called waitchld and the state will be set to JDEAD. */
if (child->running || (job != NO_JOB && RUNNING (job)))
if (PRUNNING(child) || (job != NO_JOB && RUNNING (job)))
{
#if defined (WAITPID_BROKEN) /* SCOv4 */
sigset_t suspend_set;
@@ -2048,7 +2268,7 @@ wait_for (pid)
if (interactive && job_control == 0)
QUIT;
}
while (child->running || (job != NO_JOB && RUNNING (job)));
while (PRUNNING (child) || (job != NO_JOB && RUNNING (job)));
/* The exit state of the command is either the termination state of the
child, or the termination state of the job. If a job, the status
@@ -2528,8 +2748,11 @@ kill_pid (pid, sig, group)
do
{
if (PALIVE (p) == 0)
continue; /* avoid pid recycling problems */
kill (p->pid, sig);
if (p->running == PS_DONE && (sig == SIGTERM || sig == SIGHUP))
if (PEXITED (p) && (sig == SIGTERM || sig == SIGHUP))
kill (p->pid, SIGCONT);
p = p->next;
}
@@ -2636,7 +2859,7 @@ waitchld (wpid, block)
children_exited++;
/* Locate our PROCESS for this pid. */
child = find_pipeline (pid, 1, &job); /* want running procs only */
child = find_process (pid, 1, &job); /* want living procs only */
/* It is not an error to have a child terminate that we did
not have a record of. This child could have been part of
@@ -2645,14 +2868,11 @@ waitchld (wpid, block)
if (child == 0)
continue;
while (child->pid != pid)
child = child->next;
/* Remember status, and whether or not the process is running. */
child->status = status;
child->running = WIFCONTINUED(status) ? PS_RUNNING : PS_DONE;
if (child->running == PS_DONE)
if (PEXITED (child))
{
js.c_totreaped++;
if (job != NO_JOB)
@@ -2723,8 +2943,13 @@ set_job_status_and_cleanup (job)
job_state = any_stopped = any_tstped = 0;
do
{
job_state |= child->running;
if (child->running == PS_DONE && (WIFSTOPPED (child->status)))
job_state |= PRUNNING (child);
#if 0
if (PEXITED (child) && (WIFSTOPPED (child->status)))
#else
/* Only checking for WIFSTOPPED now, not for PS_DONE */
if (PSTOPPED (child))
#endif
{
any_stopped = 1;
any_tstped |= interactive && job_control &&
@@ -3181,6 +3406,11 @@ initialize_job_control (force)
if (interactive)
get_tty_state ();
if (js.c_childmax < 0)
js.c_childmax = getmaxchild ();
if (js.c_childmax < 0)
js.c_childmax = DEFAULT_CHILD_MAX;
return job_control;
}
@@ -3430,6 +3660,9 @@ if (i < js.j_firstj && jobs[i])
}
}
if (running_only == 0)
bgp_clear ();
UNBLOCK_CHILD (oset);
}
@@ -3528,7 +3761,10 @@ mark_dead_jobs_as_notified (force)
}
/* Mark enough dead jobs as notified to keep CHILD_MAX processes left in the
array with the corresponding not marked as notified. */
array with the corresponding not marked as notified. This is a better
way to avoid pid aliasing and reuse problems than keeping the POSIX-
mandated CHILD_MAX jobs around. delete_job() takes care of keeping the
bgpids list regulated. */
/* Count the number of dead jobs */
/* XXX could use js.j_firstj here */
@@ -3543,10 +3779,12 @@ if (i < js.j_firstj && jobs[i])
}
}
if (ndeadproc != js.c_reaped)
itrace("mark_dead_jobs_as_notified: ndeadproc (%d) != js.c_reaped (%d)", ndeadproc, js.c_reaped);
if (ndead != js.j_ndead)
itrace("mark_dead_jobs_as_notified: ndead (%d) != js.j_ndead (%d)", ndead, js.j_ndead);
#ifdef DEBUG
if (ndeadproc != js.c_reaped)
itrace("mark_dead_jobs_as_notified: ndeadproc (%d) != js.c_reaped (%d)", ndeadproc, js.c_reaped);
if (ndead != js.j_ndead)
itrace("mark_dead_jobs_as_notified: ndead (%d) != js.j_ndead (%d)", ndead, js.j_ndead);
#endif
if (js.c_childmax < 0)
js.c_childmax = getmaxchild ();
@@ -3561,6 +3799,10 @@ if (ndead != js.j_ndead)
return;
}
#if 0
itrace("mark_dead_jobs_as_notified: child_max = %d ndead = %d ndeadproc = %d", js.c_childmax, ndead, ndeadproc);
#endif
/* Mark enough dead jobs as notified that we keep CHILD_MAX jobs in
the list. This isn't exactly right yet; changes need to be made
to stop_pipeline so we don't mark the newer jobs after we've
+296 -58
View File
@@ -160,7 +160,9 @@ extern procenv_t wait_intr_buf;
extern int wait_signal_received;
extern WORD_LIST *subst_assign_varlist;
struct jobstats js = { -1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NO_JOB, NO_JOB };
struct jobstats js = { -1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NO_JOB, NO_JOB, 0, 0 };
struct bgpids bgpids = { 0, 0, 0 };
/* The array of known jobs. */
JOB **jobs = (JOB **)NULL;
@@ -234,12 +236,14 @@ static sighandler sigstop_sighandler __P((int));
static int waitchld __P((pid_t, int));
static PROCESS *find_pipeline __P((pid_t, int, int *));
static PROCESS *find_process __P((pid_t, int, int *));
static char *current_working_directory __P((void));
static char *job_working_directory __P((void));
static char *j_strsignal __P((int));
static char *printable_job_status __P((int, PROCESS *, int));
static PROCESS *find_last_proc __P((int, int));
static pid_t find_last_pid __P((int, int));
static int set_new_line_discipline __P((int));
@@ -247,7 +251,7 @@ static int map_over_jobs __P((sh_job_map_func_t *, int, int));
static int job_last_stopped __P((int));
static int job_last_running __P((int));
static int most_recent_job_in_state __P((int, JOB_STATE));
static int find_job __P((pid_t, int));
static int find_job __P((pid_t, int, PROCESS **));
static int print_job __P((JOB *, int, int, int));
static int process_exit_status __P((WAIT));
static int process_exit_signal __P((WAIT));
@@ -279,6 +283,13 @@ static void pipe_read __P((int *));
static void pipe_close __P((int *));
#endif
static struct pidstat *bgp_alloc __P((pid_t, int));
static struct pidstat *bgp_add __P((pid_t, int));
static int bgp_delete __P((pid_t));
static void bgp_clear __P((void));
static int bgp_search __P((pid_t));
static void bgp_prune __P((void));
#if defined (ARRAY_VARS)
static int *pstatuses; /* list of pipeline statuses */
static int statsize;
@@ -535,7 +546,7 @@ stop_pipeline (async, deferred)
if (the_pipeline)
{
register PROCESS *p;
int any_alive, any_stopped, n;
int any_running, any_stopped, n;
newjob = (JOB *)xmalloc (sizeof (JOB));
@@ -559,16 +570,16 @@ stop_pipeline (async, deferred)
/* Set the state of this pipeline. */
p = newjob->pipe;
any_alive = any_stopped = 0;
any_running = any_stopped = 0;
do
{
any_alive |= p->running;
any_stopped |= WIFSTOPPED (p->status);
any_running |= PRUNNING (p);
any_stopped |= PSTOPPED (p);
p = p->next;
}
while (p != newjob->pipe);
newjob->state = any_alive ? JRUNNING : (any_stopped ? JSTOPPED : JDEAD);
newjob->state = any_running ? JRUNNING : (any_stopped ? JSTOPPED : JDEAD);
newjob->wd = job_working_directory ();
newjob->deferred = deferred;
@@ -581,7 +592,6 @@ stop_pipeline (async, deferred)
if (newjob->state == JDEAD)
{
js.c_reaped += n; /* wouldn't have been done since this was not part of a job */
itrace("stop_pipeline: job %d: js.c_reaped (%d) just added (%d)", i, js.c_reaped, n);
js.j_ndead++;
}
js.c_injobs += n;
@@ -592,10 +602,17 @@ itrace("stop_pipeline: job %d: js.c_reaped (%d) just added (%d)", i, js.c_reaped
else
newjob = (JOB *)NULL;
if (newjob)
js.j_lastmade = newjob;
if (async)
{
if (newjob)
newjob->flags &= ~J_FOREGROUND;
{
newjob->flags &= ~J_FOREGROUND;
newjob->flags |= J_ASYNC;
js.j_lastasync = newjob;
}
reset_current ();
}
else
@@ -622,9 +639,133 @@ itrace("stop_pipeline: job %d: js.c_reaped (%d) just added (%d)", i, js.c_reaped
return (js.j_current);
}
/* Functions to manage the list of exited background pids whose status has
been saved. */
static struct pidstat *
bgp_alloc (pid, status)
pid_t pid;
int status;
{
struct pidstat *ps;
ps = (struct pidstat *)xmalloc (sizeof (struct pidstat));
ps->pid = pid;
ps->status = status;
ps->next = (struct pidstat *)0;
return ps;
}
static struct pidstat *
bgp_add (pid, status)
pid_t pid;
int status;
{
struct pidstat *ps;
ps = bgp_alloc (pid, status);
if (bgpids.list == 0)
{
bgpids.list = bgpids.end = ps;
bgpids.npid = 0; /* just to make sure */
}
else
{
bgpids.end->next = ps;
bgpids.end = ps;
}
bgpids.npid++;
if (bgpids.npid > js.c_childmax)
bgp_prune ();
return ps;
}
static int
bgp_delete (pid)
pid_t pid;
{
struct pidstat *prev, *p;
for (prev = p = bgpids.list; p; prev = p, p = p->next)
if (p->pid == pid)
{
prev->next = p->next; /* remove from list */
break;
}
if (p == 0)
return 0; /* not found */
itrace("bgp_delete: deleting %d", pid);
/* Housekeeping in the border cases. */
if (p == bgpids.list)
bgpids.list = bgpids.list->next;
else if (p == bgpids.end)
bgpids.end = prev;
bgpids.npid--;
if (bgpids.npid == 0)
bgpids.list = bgpids.end = 0;
else if (bgpids.npid == 1)
bgpids.end = bgpids.list; /* just to make sure */
free (p);
return 1;
}
/* Clear out the list of saved statuses */
static void
bgp_clear ()
{
struct pidstat *ps, *p;
for (ps = bgpids.list; ps; )
{
p = ps;
ps = ps->next;
free (p);
}
bgpids.list = bgpids.end = 0;
bgpids.npid = 0;
}
/* Search for PID in the list of saved background pids; return its status if
found. If not found, return -1. */
static int
bgp_search (pid)
pid_t pid;
{
struct pidstat *ps;
for (ps = bgpids.list ; ps; ps = ps->next)
if (ps->pid == pid)
return ps->status;
return -1;
}
static void
bgp_prune ()
{
struct pidstat *ps, *p;
while (bgpids.npid > js.c_childmax)
{
ps = bgpids.list;
itrace("bgp_prune: deleting %d -> %d", ps->pid, bgpids.npid - 1);
bgpids.list = bgpids.list->next;
free (ps);
bgpids.npid--;
}
}
/* Reset the values of js.j_lastj and js.j_firstj after one or both have
been deleted. The caller should check whether js.j_njobs is 0 before
calling this. */
calling this. This wraps around, but the rest of the code does not. At
this point, it should not matter. */
static void
reset_job_indices ()
{
@@ -760,20 +901,30 @@ delete_job (job_index, warn_stopped)
int job_index, warn_stopped;
{
register JOB *temp;
int ndel;
PROCESS *proc;
int ndel, status;
pid_t pid;
if (js.j_jobslots == 0 || jobs_list_frozen)
return;
if (warn_stopped && subshell_environment == 0 && STOPPED (job_index))
internal_warning (_("deleting stopped job %d with process group %ld"), job_index+1, (long)jobs[job_index]->pgrp);
temp = jobs[job_index];
if (job_index == js.j_current || job_index == js.j_previous)
reset_current ();
proc = find_last_proc (job_index, 0);
/* Could do this just for J_ASYNC jobs, but we save all. */
bgp_add (proc->pid, process_exit_status (proc->status));
jobs[job_index] = (JOB *)NULL;
if (temp == js.j_lastmade)
js.j_lastmade = 0;
else if (temp == js.j_lastasync)
js.j_lastasync = 0;
free (temp->wd);
ndel = discard_pipeline (temp->pipe);
@@ -845,6 +996,21 @@ add_process (name, pid)
{
PROCESS *t, *p;
#if defined (RECYCLES_PIDS)
int j;
p = find_process (pid, 0, &j);
if (p)
{
# ifdef DEBUG
if (j == NO_JOB)
internal_warning ("add_process: process %5ld (%s) in the_pipeline", (long)p->pid, p->command);
# endif
if (PALIVE (p))
internal_warning ("add_process: pid %5ld (%s) marked as still alive", (long)p->pid, p->command);
p->running = PS_RECYCLED; /* mark as recycled */
}
#endif
t = (PROCESS *)xmalloc (sizeof (PROCESS));
t->next = the_pipeline;
t->pid = pid;
@@ -994,15 +1160,16 @@ kill_current_pipeline ()
}
/* Return the pipeline that PID belongs to. Note that the pipeline
doesn't have to belong to a job. Must be called with SIGCHLD blocked. */
doesn't have to belong to a job. Must be called with SIGCHLD blocked.
If JOBP is non-null, return the index of the job containing PID. */
static PROCESS *
find_pipeline (pid, running_only, jobp)
find_pipeline (pid, alive_only, jobp)
pid_t pid;
int running_only;
int alive_only;
int *jobp; /* index into jobs list or NO_JOB */
{
int job;
register PROCESS *p;
PROCESS *p;
/* See if this process is in the pipeline that we are building. */
if (jobp)
@@ -1012,33 +1179,48 @@ find_pipeline (pid, running_only, jobp)
p = the_pipeline;
do
{
/* Return it if we found it. */
if (p->pid == pid)
{
if ((running_only && PALIVE(p)) || (running_only == 0))
return (p);
}
/* Return it if we found it. Don't ever return a recycled pid. */
if (p->pid == pid && ((alive_only == 0 && PRECYCLED(p) == 0) || PALIVE(p)))
return (p);
p = p->next;
}
while (p != the_pipeline);
}
job = find_job (pid, running_only);
job = find_job (pid, alive_only, &p);
if (jobp)
*jobp = job;
return (job == NO_JOB) ? (PROCESS *)NULL : jobs[job]->pipe;
}
/* Return the PROCESS * describing PID. If JOBP is non-null return the index
into the jobs array of the job containing PID. Must be called with
SIGCHLD blocked. */
static PROCESS *
find_process (pid, alive_only, jobp)
pid_t pid;
int alive_only;
int *jobp; /* index into jobs list or NO_JOB */
{
PROCESS *p;
p = find_pipeline (pid, alive_only, jobp);
while (p && p->pid != pid)
p = p->next;
return p;
}
/* Return the job index that PID belongs to, or NO_JOB if it doesn't
belong to any job. Must be called with SIGCHLD blocked. */
static int
find_job (pid, running_only)
find_job (pid, alive_only, procp)
pid_t pid;
int running_only;
int alive_only;
PROCESS **procp;
{
register int i;
register PROCESS *p;
PROCESS *p;
/* XXX could use js.j_firstj here */
for (i = 0; i < js.j_jobslots; i++)
@@ -1051,10 +1233,11 @@ if (i < js.j_firstj && jobs[i])
do
{
if (p->pid == pid)
if (p->pid == pid && ((alive_only == 0 && PRECYCLED(p) == 0) || PALIVE(p)))
{
if ((running_only && PALIVE(p)) || (running_only == 0))
return (i);
if (procp)
*procp = p;
return (i);
}
p = p->next;
@@ -1079,7 +1262,7 @@ get_job_by_pid (pid, block)
if (block)
BLOCK_CHILD (set, oset);
job = find_job (pid, 0);
job = find_job (pid, 0, NULL);
if (block)
UNBLOCK_CHILD (oset);
@@ -1097,7 +1280,7 @@ describe_pid (pid)
BLOCK_CHILD (set, oset);
job = find_job (pid, 0);
job = find_job (pid, 0, NULL);
if (job != NO_JOB)
fprintf (stderr, "[%d] %ld\n", job + 1, (long)pid);
@@ -1499,7 +1682,12 @@ make_child (command, async_p)
#endif /* PGRP_PIPE */
if (async_p)
last_asynchronous_pid = getpid ();
last_asynchronous_pid = mypid;
#if defined (RECYCLES_PIDS)
else if (last_asynchronous_pid == mypid)
/* Avoid pid aliasing. 1 seems like a safe, unusual pid value. */
last_asynchronous_pid = 1;
#endif
}
else
{
@@ -1533,6 +1721,18 @@ make_child (command, async_p)
if (async_p)
last_asynchronous_pid = pid;
#if defined (RECYCLES_PIDS)
else if (last_asynchronous_pid == pid)
/* Avoid pid aliasing. 1 seems like a safe, unusual pid value. */
last_asynchronous_pid = 1;
#endif
#if !defined (RECYCLES_PIDS)
/* Only check for saved status if we've saved more than CHILD_MAX
statuses, unless the system recycles pids. */
if ((js.c_reaped + bgpids.npid) >= js.c_childmax)
#endif
bgp_delete (pid); /* new process, discard any saved status */
last_made_pid = pid;
@@ -1696,11 +1896,11 @@ set_tty_state ()
return 0;
}
/* Given an index into the jobs array JOB, return the pid of the last
/* Given an index into the jobs array JOB, return the PROCESS struct of the last
process in that job's pipeline. This is the one whose exit status
counts. Must be called with SIGCHLD blocked or queued. */
static pid_t
find_last_pid (job, block)
static PROCESS *
find_last_proc (job, block)
int job;
int block;
{
@@ -1717,9 +1917,21 @@ find_last_pid (job, block)
if (block)
UNBLOCK_CHILD (oset);
return (p->pid);
return (p);
}
static pid_t
find_last_pid (job, block)
int job;
int block;
{
PROCESS *p;
p = find_last_proc (job, block);
/* Possible race condition here. */
return p->pid;
}
/* Wait for a particular child of the shell to finish executing.
This low-level function prints an error message if PID is not
a child of this shell. It returns -1 if it fails, or whatever
@@ -1737,6 +1949,13 @@ wait_for_single_pid (pid)
child = find_pipeline (pid, 0, (int *)NULL);
UNBLOCK_CHILD (oset);
if (child == 0)
{
r = bgp_search (pid);
if (r >= 0)
return r;
}
if (child == 0)
{
internal_error (_("wait: pid %ld is not a child of this shell"), (long)pid);
@@ -1748,7 +1967,7 @@ wait_for_single_pid (pid)
/* POSIX.2: if we just waited for a job, we can remove it from the jobs
table. */
BLOCK_CHILD (set, oset);
job = find_job (pid, 0);
job = find_job (pid, 0, NULL);
if (job != NO_JOB && jobs[job] && DEADJOB (job))
jobs[job]->flags |= J_NOTIFIED;
UNBLOCK_CHILD (oset);
@@ -1803,6 +2022,7 @@ if (i < js.j_firstj && jobs[i])
`wait' is called with no arguments. */
mark_dead_jobs_as_notified (1);
cleanup_dead_jobs ();
bgp_clear ();
}
/* Make OLD_SIGINT_HANDLER the SIGINT signal handler. */
@@ -1986,13 +2206,13 @@ wait_for (pid)
We check for JDEAD in case the job state has been set by waitchld
after receipt of a SIGCHLD. */
if (job == NO_JOB)
job = find_job (pid, 0);
job = find_job (pid, 0, NULL);
/* waitchld() takes care of setting the state of the job. If the job
has already exited before this is called, sigchld_handler will have
called waitchld and the state will be set to JDEAD. */
if (child->running || (job != NO_JOB && RUNNING (job)))
if (PRUNNING(child) || (job != NO_JOB && RUNNING (job)))
{
#if defined (WAITPID_BROKEN) /* SCOv4 */
sigset_t suspend_set;
@@ -2049,7 +2269,7 @@ wait_for (pid)
if (interactive && job_control == 0)
QUIT;
}
while (child->running || (job != NO_JOB && RUNNING (job)));
while (PRUNNING (child) || (job != NO_JOB && RUNNING (job)));
/* The exit state of the command is either the termination state of the
child, or the termination state of the job. If a job, the status
@@ -2529,8 +2749,11 @@ kill_pid (pid, sig, group)
do
{
if (PALIVE (p) == 0)
continue; /* avoid pid recycling problems */
kill (p->pid, sig);
if (p->running == PS_DONE && (sig == SIGTERM || sig == SIGHUP))
if (PEXITED (p) && (sig == SIGTERM || sig == SIGHUP))
kill (p->pid, SIGCONT);
p = p->next;
}
@@ -2637,7 +2860,7 @@ waitchld (wpid, block)
children_exited++;
/* Locate our PROCESS for this pid. */
child = find_pipeline (pid, 1, &job); /* want running procs only */
child = find_process (pid, 1, &job); /* want living procs only */
/* It is not an error to have a child terminate that we did
not have a record of. This child could have been part of
@@ -2646,21 +2869,15 @@ waitchld (wpid, block)
if (child == 0)
continue;
while (child->pid != pid)
child = child->next;
/* Remember status, and whether or not the process is running. */
child->status = status;
child->running = WIFCONTINUED(status) ? PS_RUNNING : PS_DONE;
if (child->running == PS_DONE)
if (PEXITED (child))
{
js.c_totreaped++;
if (job != NO_JOB)
{
js.c_reaped++;
itrace("waitchld: job %d js.c_reaped++ = %d", job, js.c_reaped);
}
}
if (job == NO_JOB)
@@ -2727,8 +2944,13 @@ set_job_status_and_cleanup (job)
job_state = any_stopped = any_tstped = 0;
do
{
job_state |= child->running;
if (child->running == PS_DONE && (WIFSTOPPED (child->status)))
job_state |= PRUNNING (child);
#if 0
if (PEXITED (child) && (WIFSTOPPED (child->status)))
#else
/* Only checking for WIFSTOPPED now, not for PS_DONE */
if (PSTOPPED (child))
#endif
{
any_stopped = 1;
any_tstped |= interactive && job_control &&
@@ -3185,6 +3407,11 @@ initialize_job_control (force)
if (interactive)
get_tty_state ();
if (js.c_childmax < 0)
js.c_childmax = getmaxchild ();
if (js.c_childmax < 0)
js.c_childmax = DEFAULT_CHILD_MAX;
return job_control;
}
@@ -3434,6 +3661,9 @@ if (i < js.j_firstj && jobs[i])
}
}
if (running_only == 0)
bgp_clear ();
UNBLOCK_CHILD (oset);
}
@@ -3532,7 +3762,10 @@ mark_dead_jobs_as_notified (force)
}
/* Mark enough dead jobs as notified to keep CHILD_MAX processes left in the
array with the corresponding not marked as notified. */
array with the corresponding not marked as notified. This is a better
way to avoid pid aliasing and reuse problems than keeping the POSIX-
mandated CHILD_MAX jobs around. delete_job() takes care of keeping the
bgpids list regulated. */
/* Count the number of dead jobs */
/* XXX could use js.j_firstj here */
@@ -3547,16 +3780,18 @@ if (i < js.j_firstj && jobs[i])
}
}
if (ndeadproc != js.c_reaped)
itrace("mark_dead_jobs_as_notified: ndeadproc (%d) != js.c_reaped (%d)", ndeadproc, js.c_reaped);
if (ndead != js.j_ndead)
itrace("mark_dead_jobs_as_notified: ndead (%d) != js.j_ndead (%d)", ndead, js.j_ndead);
#ifdef DEBUG
if (ndeadproc != js.c_reaped)
itrace("mark_dead_jobs_as_notified: ndeadproc (%d) != js.c_reaped (%d)", ndeadproc, js.c_reaped);
if (ndead != js.j_ndead)
itrace("mark_dead_jobs_as_notified: ndead (%d) != js.j_ndead (%d)", ndead, js.j_ndead);
#endif
if (js.c_childmax < 0)
js.c_childmax = getmaxchild ();
if (js.c_childmax < 0)
js.c_childmax = DEFAULT_CHILD_MAX;
itrace("mark_dead_jobs_as_notified: child_max = %d ndead = %d ndeadproc = %d", js.c_childmax, ndead, ndeadproc);
/* Don't do anything if the number of dead processes is less than CHILD_MAX
and we're not forcing a cleanup. */
if (ndeadproc <= js.c_childmax)
@@ -3565,6 +3800,10 @@ itrace("mark_dead_jobs_as_notified: child_max = %d ndead = %d ndeadproc = %d", j
return;
}
#if 0
itrace("mark_dead_jobs_as_notified: child_max = %d ndead = %d ndeadproc = %d", js.c_childmax, ndead, ndeadproc);
#endif
/* Mark enough dead jobs as notified that we keep CHILD_MAX jobs in
the list. This isn't exactly right yet; changes need to be made
to stop_pipeline so we don't mark the newer jobs after we've
@@ -3590,7 +3829,6 @@ if (i < js.j_firstj && jobs[i])
if ((ndeadproc -= processes_in_job (i)) <= js.c_childmax)
break;
jobs[i]->flags |= J_NOTIFIED;
itrace("marking job %d as notified", i);
}
}
+34 -9
View File
@@ -1,6 +1,6 @@
/* jobs.h -- structures and stuff used by the jobs.c file. */
/* Copyright (C) 1993-2004 Free Software Foundation, Inc.
/* Copyright (C) 1993-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -46,9 +46,10 @@
#define PS_DONE 0
#define PS_RUNNING 1
#define PS_STOPPED 2
#define PS_RECYCLED 4
/* Each child of the shell is remembered in a STRUCT PROCESS. A chain of
such structures is a pipeline. The chain is circular. */
/* Each child of the shell is remembered in a STRUCT PROCESS. A circular
chain of such structures is a pipeline. */
typedef struct process {
struct process *next; /* Next process in the pipeline. A circular chain. */
pid_t pid; /* Process ID. */
@@ -57,10 +58,18 @@ typedef struct process {
char *command; /* The particular program that is running. */
} PROCESS;
/* PRUNNING really means `not exited' */
#define PALIVE(p) ((p)->running || WIFSTOPPED((p)->status))
/* PALIVE really means `not exited' */
#define PSTOPPED(p) (WIFSTOPPED((p)->status))
#define PDEADPROC(p) ((p)->running == PS_DONE)
#define PRUNNING(p) ((p)->running == PS_RUNNING)
#define PALIVE(p) (PRUNNING(p) || PSTOPPED(p))
#define PEXITED(p) ((p)->running == PS_DONE)
#if defined (RECYCLES_PIDS)
# define PRECYCLED(p) ((p)->running == PS_RECYCLED)
#else
# define PRECYCLED(p) (0)
#endif
#define PDEADPROC(p) (PEXITED(p) || PRECYCLED(p))
#define get_job_by_jid(ind) (jobs[(ind)])
@@ -73,7 +82,7 @@ typedef enum { JRUNNING, JSTOPPED, JDEAD, JMIXED } JOB_STATE;
#define RUNNING(j) (jobs[(j)]->state == JRUNNING)
#define DEADJOB(j) (jobs[(j)]->state == JDEAD)
#define INVALID_JOB(j) ((j) < 0 || (j) >= js.j_jobslots || jobs[(j)] == 0)
#define INVALID_JOB(j) ((j) < 0 || (j) >= js.j_jobslots || get_job_by_jid(j) == 0)
/* Values for the FLAGS field in the JOB struct below. */
#define J_FOREGROUND 0x01 /* Non-zero if this is running in the foreground. */
@@ -81,10 +90,12 @@ typedef enum { JRUNNING, JSTOPPED, JDEAD, JMIXED } JOB_STATE;
#define J_JOBCONTROL 0x04 /* Non-zero if this job started under job control. */
#define J_NOHUP 0x08 /* Don't send SIGHUP to job if shell gets SIGHUP. */
#define J_STATSAVED 0x10 /* A process in this job had had status saved via $! */
#define J_ASYNC 0x20 /* Job was started asynchronously */
#define IS_FOREGROUND(j) ((jobs[j]->flags & J_FOREGROUND) != 0)
#define IS_NOTIFIED(j) ((jobs[j]->flags & J_NOTIFIED) != 0)
#define IS_JOBCONTROL(j) ((jobs[j]->flags & J_JOBCONTROL) != 0)
#define IS_ASYNC(j) ((jobs[j]->flags & J_ASYNC) != 0)
typedef struct job {
char *wd; /* The working directory at time of invocation. */
@@ -118,6 +129,21 @@ struct jobstats {
/* */
int j_current; /* current job */
int j_previous; /* previous job */
/* */
JOB *j_lastmade; /* last job allocated by stop_pipeline */
JOB *j_lastasync; /* last async job allocated by stop_pipeline */
};
struct pidstat {
struct pidstat *next;
pid_t pid;
int status;
};
struct bgpids {
struct pidstat *list;
struct pidstat *end;
int npid;
};
#define NO_JOB -1 /* An impossible job array index. */
@@ -137,10 +163,9 @@ extern struct jobstats js;
extern pid_t original_pgrp, shell_pgrp, pipeline_pgrp;
extern pid_t last_made_pid, last_asynchronous_pid;
extern int current_job, previous_job;
extern int asynchronous_notification;
extern JOB **jobs;
extern int job_slots;
extern void making_children __P((void));
extern void stop_making_children __P((void));
+21 -4
View File
@@ -57,7 +57,7 @@ typedef struct process {
char *command; /* The particular program that is running. */
} PROCESS;
/* PRUNNING really means `not exited' */
/* PALIVE really means `not exited' */
#define PALIVE(p) ((p)->running || WIFSTOPPED((p)->status))
#define PSTOPPED(p) (WIFSTOPPED((p)->status))
#define PDEADPROC(p) ((p)->running == PS_DONE)
@@ -73,7 +73,7 @@ typedef enum { JRUNNING, JSTOPPED, JDEAD, JMIXED } JOB_STATE;
#define RUNNING(j) (jobs[(j)]->state == JRUNNING)
#define DEADJOB(j) (jobs[(j)]->state == JDEAD)
#define INVALID_JOB(j) ((j) < 0 || (j) >= js.j_jobslots || jobs[(j)] == 0)
#define INVALID_JOB(j) ((j) < 0 || (j) >= js.j_jobslots || get_job_by_jid(j) == 0)
/* Values for the FLAGS field in the JOB struct below. */
#define J_FOREGROUND 0x01 /* Non-zero if this is running in the foreground. */
@@ -81,10 +81,12 @@ typedef enum { JRUNNING, JSTOPPED, JDEAD, JMIXED } JOB_STATE;
#define J_JOBCONTROL 0x04 /* Non-zero if this job started under job control. */
#define J_NOHUP 0x08 /* Don't send SIGHUP to job if shell gets SIGHUP. */
#define J_STATSAVED 0x10 /* A process in this job had had status saved via $! */
#define J_ASYNC 0x20 /* Job was started asynchronously */
#define IS_FOREGROUND(j) ((jobs[j]->flags & J_FOREGROUND) != 0)
#define IS_NOTIFIED(j) ((jobs[j]->flags & J_NOTIFIED) != 0)
#define IS_JOBCONTROL(j) ((jobs[j]->flags & J_JOBCONTROL) != 0)
#define IS_ASYNC(j) ((jobs[j]->flags & J_ASYNC) != 0)
typedef struct job {
char *wd; /* The working directory at time of invocation. */
@@ -114,9 +116,25 @@ struct jobstats {
int j_lastj; /* last (newest) job allocated */
int j_firstj; /* first (oldest) job allocated */
int j_njobs; /* number of non-NULL jobs in jobs array */
int j_ndead; /* number of JDEAD jobs in jobs array */
/* */
int j_current; /* current job */
int j_previous; /* previous job */
/* */
JOB *j_lastmade; /* last job allocated by stop_pipeline */
JOB *j_lastasync; /* last async job allocated by stop_pipeline */
};
struct pidstat {
struct pidstat *next;
pid_t pid;
int status;
};
struct bgpids {
struct pidstat *list;
struct pidstat *end;
int npid;
};
#define NO_JOB -1 /* An impossible job array index. */
@@ -136,10 +154,9 @@ extern struct jobstats js;
extern pid_t original_pgrp, shell_pgrp, pipeline_pgrp;
extern pid_t last_made_pid, last_asynchronous_pid;
extern int current_job, previous_job;
extern int asynchronous_notification;
extern JOB **jobs;
extern int job_slots;
extern void making_children __P((void));
extern void stop_making_children __P((void));
+1 -1
View File
@@ -1,6 +1,6 @@
# simple makefile to create texindex
#
# Copyright (C) 1996 Free Software Foundation, Inc.
# Copyright (C) 1996-2005 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+54
View File
@@ -0,0 +1,54 @@
# simple makefile to create texindex
#
# Copyright (C) 1996 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
topdir = @top_srcdir@
srcdir = @srcdir@
VPATH = .:@srcdir@
BUILD_DIR = @BUILD_DIR@
CC = @CC@
RM = rm
SHELL = @MAKE_SHELL@
DEFS = @DEFS@
CFLAGS = @CFLAGS@ @LOCAL_CFLAGS@
LDFLAGS = @LDFLAGS@ @LOCAL_LDFLAGS@
CPPFLAGS = @CPPFLAGS@
INCLUDES = -I. -I../.. -I$(topdir)
CCFLAGS = $(CFLAGS) $(DEFS) $(CPPFLAGS) ${INCLUDES}
.c.o:
$(RM) -f $@
$(CC) $(CCFLAGS) -c $<
OBJECTS = texindex.o getopt.o getopt1.o
SOURCES = texindex.c getopt.c getopt1.c
all: texindex
texindex: $(OBJECTS)
$(CC) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBS)
clean:
$(RM) $(OBJECTS) texindex
distclean mostlyclean realclean maintainer-clean: clean
$(RM) Makefile
+1 -1
View File
@@ -4,7 +4,7 @@
# #
####################################################################
#
# Copyright (C) 1996 Free Software Foundation, Inc.
# Copyright (C) 1996-2005 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+158
View File
@@ -0,0 +1,158 @@
## -*- text -*- ####################################################
# #
# Makefile for the GNU Glob Library. #
# #
####################################################################
#
# Copyright (C) 1996 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
srcdir = @srcdir@
VPATH = .:@srcdir@
topdir = @top_srcdir@
BUILD_DIR = @BUILD_DIR@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
CC = @CC@
RANLIB = @RANLIB@
AR = @AR@
ARFLAGS = @ARFLAGS@
RM = rm
CP = cp
MV = mv
SHELL = @MAKE_SHELL@
PROFILE_FLAGS = @PROFILE_FLAGS@
CFLAGS = @CFLAGS@
LOCAL_CFLAGS = @LOCAL_CFLAGS@
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@ @LOCAL_LDFLAGS@
DEFS = @DEFS@
LOCAL_DEFS = @LOCAL_DEFS@
BASHINCDIR = ${topdir}/include
INCLUDES = -I. -I../.. -I$(topdir) -I$(BASHINCDIR) -I$(topdir)/lib
CCFLAGS = $(PROFILE_FLAGS) $(DEFS) $(LOCAL_DEFS) $(CPPFLAGS) ${INCLUDES} \
$(LOCAL_CFLAGS) $(CFLAGS)
# Here is a rule for making .o files from .c files that doesn't force
# the type of the machine (like -sun3) into the flags.
.c.o:
$(CC) -c $(CCFLAGS) $<
# The name of the library target.
LIBRARY_NAME = libglob.a
# The C code source files for this library.
CSOURCES = $(srcdir)/glob.c $(srcdir)/strmatch.c $(srcdir)/smatch.c \
$(srcdir)/xmbsrtowcs.c
# The header files for this library.
HSOURCES = $(srcdir)/strmatch.h
OBJECTS = glob.o strmatch.o smatch.o xmbsrtowcs.o
# The texinfo files which document this library.
DOCSOURCE = doc/glob.texi
DOCOBJECT = doc/glob.dvi
DOCSUPPORT = doc/Makefile
DOCUMENTATION = $(DOCSOURCE) $(DOCOBJECT) $(DOCSUPPORT)
SUPPORT = Makefile ChangeLog $(DOCSUPPORT)
SOURCES = $(CSOURCES) $(HSOURCES) $(DOCSOURCE)
THINGS_TO_TAR = $(SOURCES) $(SUPPORT)
######################################################################
all: $(LIBRARY_NAME)
$(LIBRARY_NAME): $(OBJECTS)
$(RM) -f $@
$(AR) $(ARFLAGS) $@ $(OBJECTS)
-test -n "$(RANLIB)" && $(RANLIB) $@
what-tar:
@for file in $(THINGS_TO_TAR); do \
echo $(selfdir)$$file; \
done
documentation: force
-(cd doc; $(MAKE) $(MFLAGS))
force:
# The rule for 'includes' is written funny so that the if statement
# always returns TRUE unless there really was an error installing the
# include files.
install:
clean:
rm -f $(OBJECTS) $(LIBRARY_NAME)
-(cd doc && $(MAKE) $(MFLAGS) $@ )
realclean distclean maintainer-clean: clean
-( cd doc && $(MAKE) $(MFLAGS) $@ )
$(RM) -f Makefile
mostlyclean: clean
-( cd doc && $(MAKE) $(MFLAGS) $@ )
######################################################################
# #
# Dependencies for the object files which make up this library. #
# #
######################################################################
smatch.o: strmatch.h
smatch.o: $(BUILD_DIR)/config.h
smatch.o: $(BASHINCDIR)/chartypes.h
smatch.o: $(BASHINCDIR)/ansi_stdlib.h $(topdir)/bashansi.h
smatch.o: $(BASHINCDIR)/shmbutil.h
smatch.o: $(topdir)/xmalloc.h
strmatch.o: strmatch.h
strmatch.o: $(BUILD_DIR)/config.h
strmatch.o: $(BASHINCDIR)/stdc.h
glob.o: $(BUILD_DIR)/config.h
glob.o: $(topdir)/bashtypes.h $(BASHINCDIR)/ansi_stdlib.h $(topdir)/bashansi.h
glob.o: $(BASHINCDIR)/posixstat.h $(BASHINCDIR)/memalloc.h
glob.o: strmatch.h glob.h
glob.o: $(BASHINCDIR)/shmbutil.h
glob.o: $(topdir)/xmalloc.h
xmbsrtowcs.o: ${BUILD_DIR}/config.h
xmbsrtowcs.o: ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h
xmbsrtowcs.o: ${BASHINCDIR}/shmbutil.h
# Rules for deficient makes, like SunOS and Solaris
glob.o: glob.c
strmatch.o: strmatch.c
smatch.o: smatch.c
xmbsrtowcs.o: xmbsrtowcs.c
# dependencies for C files that include other C files
glob.o: glob_loop.c
smatch.o: sm_loop.c
+1 -1
View File
@@ -1,7 +1,7 @@
# Skeleton Makefile for the GNU malloc code
#
#
# Copyright (C) 1996 Free Software Foundation, Inc.
# Copyright (C) 1996-2005 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+138
View File
@@ -0,0 +1,138 @@
# Skeleton Makefile for the GNU malloc code
#
#
# Copyright (C) 1996 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
srcdir = @srcdir@
VPATH = .:@srcdir@
topdir = @top_srcdir@
BUILD_DIR = @BUILD_DIR@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
CC = @CC@
RANLIB = @RANLIB@
AR = @AR@
ARFLAGS = @ARFLAGS@
RM = rm -f
CP = cp
MV = mv
SHELL = @MAKE_SHELL@
PROFILE_FLAGS = @PROFILE_FLAGS@
CFLAGS = @CFLAGS@
LOCAL_CFLAGS = @LOCAL_CFLAGS@
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
DEFS = @DEFS@
LOCAL_DEFS = @LOCAL_DEFS@
LIBBUILD = ${BUILD_DIR}/lib
BASHINCDIR = ${topdir}/include
INTL_LIBSRC = ${topdir}/lib/intl
INTL_BUILDDIR = ${LIBBUILD}/intl
INTL_INC = @INTL_INC@
LIBINTL_H = @LIBINTL_H@
INCLUDES = -I. -I../.. -I$(topdir) -I$(BASHINCDIR) -I$(topdir)/lib $(INTL_INC)
CCFLAGS = ${PROFILE_FLAGS} ${INCLUDES} $(DEFS) $(LOCAL_DEFS) $(LOCAL_CFLAGS) \
$(CFLAGS) $(MALLOC_CFLAGS) $(CPPFLAGS)
.c.o:
$(CC) $(CCFLAGS) -c $<
.s.o:
$(CC) $(CCFLAGS) -c $<
MALLOC_SOURCE = malloc.c
STUB_SOURCE = stub.c
ALLOCA_SOURCE = alloca.c
ALLOCA_OBJECT = alloca.o
MALLOC_SRC = @MALLOC_SRC@
MALLOC = @MALLOC@
ALLOCA = @ALLOCA@
MALLOC_OBJS = malloc.o $(ALLOCA) trace.o stats.o table.o watch.o
STUB_OBJS = $(ALLOCA) stub.o
.PHONY: malloc stubmalloc
all: malloc
malloc: ${MALLOC_OBJS}
${RM} libmalloc.a
${AR} ${ARFLAGS} libmalloc.a ${MALLOC_OBJS}
-test -n "$(RANLIB)" && $(RANLIB) libmalloc.a
stubmalloc: ${STUB_OBJS}
${RM} libmalloc.a
${AR} ${ARFLAGS} libmalloc.a ${STUB_OBJS}
-test -n "$(RANLIB)" && $(RANLIB) libmalloc.a
alloca: ${ALLOCA}
${RM} libmalloc.a
${AR} ${ARFLAGS} libmalloc.a ${ALLOCA}
-test -n "$(RANLIB)" && $(RANLIB) libmalloc.a
alloca.o: $(srcdir)/$(ALLOCA_SOURCE)
$(CC) $(CCFLAGS) -c $(srcdir)/$(ALLOCA_SOURCE)
@- if test "$(ALLOCA_OBJECT)" != alloca.o ; then \
mv $(ALLOCA_OBJECT) alloca.o >/dev/null 2>&1 ; \
fi
mostlyclean clean:
$(RM) *.o libmalloc.a
distclean realclean maintainer-clean: clean
$(RM) Makefile
alloca.o: $(BUILD_DIR)/config.h
malloc.o: $(BUILD_DIR)/config.h $(topdir)/bashtypes.h getpagesize.h
xmalloc.o: $(BUILD_DIR)/config.h $(BASHINCDIR)/ansi_stdlib.h
trace.o: ${BUILD_DIR}/config.h
table.o: ${BUILD_DIR}/config.h
malloc.o: ${srcdir}/imalloc.h ${srcdir}/mstats.h
malloc.o: ${srcdir}/table.h ${srcdir}/watch.h
stats.o: ${srcdir}/imalloc.h ${srcdir}/mstats.h
trace.o: ${srcdir}/imalloc.h
table.o: ${srcdir}/imalloc.h ${srcdir}/table.h
watch.o: ${srcdir}/imalloc.h ${srcdir}/watch.h
malloc.o: ${topdir}/bashintl.h ${LIBINTL_H} ${BASHINCDIR}/gettext.h
stats.o: ${topdir}/bashintl.h ${LIBINTL_H} ${BASHINCDIR}/gettext.h
trace.o: ${topdir}/bashintl.h ${LIBINTL_H} ${BASHINCDIR}/gettext.h
table.o: ${topdir}/bashintl.h ${LIBINTL_H} ${BASHINCDIR}/gettext.h
watch.o: ${topdir}/bashintl.h ${LIBINTL_H} ${BASHINCDIR}/gettext.h
# Rules for deficient makes, like SunOS and Solaris
stub.o: stub.c
malloc.o: malloc.c
table.o: table.c
trace.o: trace.c
stats.o: stats.c
watch.o: watch.c
+1 -1
View File
@@ -4,7 +4,7 @@
# #
#############################################################################
# Copyright (C) 1994 Free Software Foundation, Inc.
# Copyright (C) 1994-2005 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+366
View File
@@ -0,0 +1,366 @@
## -*- text -*- #############################################################
# #
# Makefile for the Bash versions of the GNU Readline and History Libraries. #
# #
#############################################################################
# Copyright (C) 1994 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
PACKAGE = @PACKAGE_NAME@
VERSION = @PACKAGE_VERSION@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_VERSION = @PACKAGE_VERSION@
srcdir = @srcdir@
VPATH = .:@srcdir@
topdir = @top_srcdir@
BUILD_DIR = @BUILD_DIR@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
CC = @CC@
RANLIB = @RANLIB@
AR = @AR@
ARFLAGS = @ARFLAGS@
RM = rm -f
CP = cp
MV = mv
SHELL = @MAKE_SHELL@
# Programs to make tags files.
ETAGS = etags -tw
CTAGS = ctags -tw
CFLAGS = @CFLAGS@
LOCAL_CFLAGS = @LOCAL_CFLAGS@
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
DEFS = @DEFS@
LOCAL_DEFS = @LOCAL_DEFS@
INCLUDES = -I. -I$(BUILD_DIR) -I$(topdir) -I$(topdir)/lib
CCFLAGS = $(DEFS) $(LOCAL_DEFS) $(APP_CFLAGS) $(CPPFLAGS) ${INCLUDES} $(LOCAL_CFLAGS) $(CFLAGS)
.c.o:
${RM} $@
$(CC) -c $(CCFLAGS) $<
# The name of the main library target.
LIBRARY_NAME = libreadline.a
# The C code source files for this library.
CSOURCES = $(srcdir)/readline.c $(srcdir)/funmap.c $(srcdir)/keymaps.c \
$(srcdir)/vi_mode.c $(srcdir)/parens.c $(srcdir)/rltty.c \
$(srcdir)/complete.c $(srcdir)/bind.c $(srcdir)/isearch.c \
$(srcdir)/display.c $(srcdir)/signals.c $(srcdir)/emacs_keymap.c \
$(srcdir)/vi_keymap.c $(srcdir)/util.c $(srcdir)/kill.c \
$(srcdir)/undo.c $(srcdir)/macro.c $(srcdir)/input.c \
$(srcdir)/callback.c $(srcdir)/terminal.c $(srcdir)/xmalloc.c \
$(srcdir)/history.c $(srcdir)/histsearch.c $(srcdir)/histexpand.c \
$(srcdir)/histfile.c $(srcdir)/nls.c $(srcdir)/search.c \
$(srcdir)/shell.c $(srcdir)/tilde.c $(srcdir)/savestring.c \
$(srcdir)/text.c $(srcdir)/misc.c $(srcdir)/compat.c \
$(srcdir)/mbutil.c
# The header files for this library.
HSOURCES = readline.h rldefs.h chardefs.h keymaps.h history.h histlib.h \
posixstat.h posixdir.h posixjmp.h tilde.h rlconf.h rltty.h \
ansi_stdlib.h rlstdc.h tcap.h xmalloc.h rlprivate.h rlshell.h \
rltypedefs.h rlmbutil.h
HISTOBJ = history.o histexpand.o histfile.o histsearch.o shell.o savestring.o \
mbutil.o
TILDEOBJ = tilde.o
OBJECTS = readline.o vi_mode.o funmap.o keymaps.o parens.o search.o \
rltty.o complete.o bind.o isearch.o display.o signals.o \
util.o kill.o undo.o macro.o input.o callback.o terminal.o \
text.o nls.o misc.o $(HISTOBJ) $(TILDEOBJ) xmalloc.o compat.o
# The texinfo files which document this library.
DOCSOURCE = doc/rlman.texinfo doc/rltech.texinfo doc/rluser.texinfo
DOCOBJECT = doc/readline.dvi
DOCSUPPORT = doc/Makefile
DOCUMENTATION = $(DOCSOURCE) $(DOCOBJECT) $(DOCSUPPORT)
SUPPORT = Makefile ChangeLog $(DOCSUPPORT) examples/[-a-z.]*
SOURCES = $(CSOURCES) $(HSOURCES) $(DOCSOURCE)
THINGS_TO_TAR = $(SOURCES) $(SUPPORT)
INSTALLED_HEADERS = readline.h chardefs.h keymaps.h history.h tilde.h \
rlstdc.h rlconf.h rltypedefs.h
##########################################################################
all: libreadline.a libhistory.a
libreadline.a: $(OBJECTS)
$(RM) $@
$(AR) $(ARFLAGS) $@ $(OBJECTS)
-test -n "$(RANLIB)" && $(RANLIB) $@
libhistory.a: $(HISTOBJ) xmalloc.o
$(RM) $@
$(AR) $(ARFLAGS) $@ $(HISTOBJ) xmalloc.o
-test -n "$(RANLIB)" && $(RANLIB) $@
documentation: force
test -d doc || mkdir doc
-( cd doc && $(MAKE) $(MFLAGS) )
# Since tilde.c is shared between readline and bash, make sure we compile
# it with the right flags when it's built as part of readline
tilde.o: tilde.c
rm -f $@
$(CC) $(CCFLAGS) -DREADLINE_LIBRARY -c $(srcdir)/tilde.c
force:
install:
@echo "This version of the readline library should not be installed."
uninstall:
@echo "This version of the readline library should not be installed."
TAGS: force
$(ETAGS) $(CSOURCES) $(HSOURCES)
tags: force
$(CTAGS) $(CSOURCES) $(HSOURCES)
clean: force
$(RM) $(OBJECTS) *.a
-( cd doc && $(MAKE) $(MFLAGS) $@ )
mostlyclean: clean
-( cd doc && $(MAKE) $(MFLAGS) $@ )
distclean maintainer-clean: clean
-( cd doc && $(MAKE) $(MFLAGS) $@ )
$(RM) Makefile
$(RM) TAGS tags
# Dependencies
bind.o: ansi_stdlib.h posixstat.h
bind.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h
bind.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h
bind.o: history.h rlstdc.h
callback.o: rlconf.h ansi_stdlib.h
callback.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h
callback.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h rlstdc.h
compat.o: rlstdc.h
complete.o: ansi_stdlib.h posixdir.h posixstat.h
complete.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h
complete.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h rlstdc.h
display.o: ansi_stdlib.h posixstat.h
display.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h
display.o: tcap.h
display.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h
display.o: history.h rlstdc.h
funmap.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h
funmap.o: rlconf.h ansi_stdlib.h rlstdc.h
funmap.o: ${BUILD_DIR}/config.h
histexpand.o: ansi_stdlib.h
histexpand.o: history.h histlib.h rlstdc.h
histexpand.o: ${BUILD_DIR}/config.h
histfile.o: ansi_stdlib.h
histfile.o: history.h histlib.h rlstdc.h
histfile.o: ${BUILD_DIR}/config.h
history.o: ansi_stdlib.h
history.o: history.h histlib.h rlstdc.h
history.o: ${BUILD_DIR}/config.h
histsearch.o: ansi_stdlib.h
histsearch.o: history.h histlib.h rlstdc.h
histsearch.o: ${BUILD_DIR}/config.h
input.o: ansi_stdlib.h
input.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h
input.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h rlstdc.h
isearch.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h
isearch.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h
isearch.o: ansi_stdlib.h history.h rlstdc.h
keymaps.o: emacs_keymap.c vi_keymap.c
keymaps.o: keymaps.h rltypedefs.h chardefs.h rlconf.h ansi_stdlib.h
keymaps.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h
keymaps.o: ${BUILD_DIR}/config.h rlstdc.h
kill.o: ansi_stdlib.h
kill.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h
kill.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h
kill.o: history.h rlstdc.h
macro.o: ansi_stdlib.h
macro.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h
macro.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h
macro.o: history.h rlstdc.h
mbutil.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h rlmbutil.h
mbutil.o: readline.h keymaps.h rltypedefs.h chardefs.h rlstdc.h
misc.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h
misc.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h
misc.o: history.h rlstdc.h ansi_stdlib.h
nls.o: ansi_stdlib.h
nls.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h
nls.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h
nls.o: history.h rlstdc.h
parens.o: rlconf.h
parens.o: ${BUILD_DIR}/config.h
parens.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h rlstdc.h
readline.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h
readline.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h
readline.o: history.h rlstdc.h
readline.o: posixstat.h ansi_stdlib.h posixjmp.h
rltty.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h
rltty.o: rltty.h
rltty.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h rlstdc.h
search.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h
search.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h
search.o: ansi_stdlib.h history.h rlstdc.h
shell.o: ${BUILD_DIR}/config.h ansi_stdlib.h
signals.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h
signals.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h
signals.o: history.h rlstdc.h
terminal.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h
terminal.o: tcap.h
terminal.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h
terminal.o: history.h rlstdc.h
text.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h
text.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h
text.o: history.h rlstdc.h ansi_stdlib.h
rltty.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h
tilde.o: ansi_stdlib.h
tilde.o: ${BUILD_DIR}/config.h
tilde.o: tilde.h
undo.o: ansi_stdlib.h
undo.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h
undo.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h
undo.o: history.h rlstdc.h xmalloc.h
util.o: posixjmp.h ansi_stdlib.h
util.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h
util.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h rlstdc.h
vi_mode.o: rldefs.h ${BUILD_DIR}/config.h rlconf.h
vi_mode.o: readline.h keymaps.h rltypedefs.h chardefs.h tilde.h
vi_mode.o: history.h ansi_stdlib.h rlstdc.h
xmalloc.o: ${BUILD_DIR}/config.h ansi_stdlib.h
bind.o: rlshell.h
histfile.o: rlshell.h
nls.o: rlshell.h
readline.o: rlshell.h
shell.o: rlshell.h
terminal.o: rlshell.h
histexpand.o: rlshell.h
bind.o: rlprivate.h
callback.o: rlprivate.h
complete.o: rlprivate.h
display.o: rlprivate.h
input.o: rlprivate.h
isearch.o: rlprivate.h
kill.o: rlprivate.h
macro.o: rlprivate.h
mbutil.o: rlprivate.h
misc.o: rlprivate.h
nls.o: rlprivate.h
parens.o: rlprivate.h
readline.o: rlprivate.h
rltty.o: rlprivate.h
search.o: rlprivate.h
signals.o: rlprivate.h
terminal.o: rlprivate.h
text.o: rlprivate.h
undo.o: rlprivate.h
util.o: rlprivate.h
vi_mode.o: rlprivate.h
bind.o: xmalloc.h
complete.o: xmalloc.h
display.o: xmalloc.h
funmap.o: xmalloc.h
histexpand.o: xmalloc.h
histfile.o: xmalloc.h
history.o: xmalloc.h
input.o: xmalloc.h
isearch.o: xmalloc.h
keymaps.o: xmalloc.h
kill.o: xmalloc.h
macro.o: xmalloc.h
mbutil.o: xmalloc.h
misc.o: xmalloc.h
readline.o: xmalloc.h
savestring.o: xmalloc.h
search.o: xmalloc.h
shell.o: xmalloc.h
terminal.o: xmalloc.h
text.o: xmalloc.h
tilde.o: xmalloc.h
undo.o: xmalloc.h
util.o: xmalloc.h
vi_mode.o: xmalloc.h
xmalloc.o: xmalloc.h
complete.o: rlmbutil.h
display.o: rlmbutil.h
histexpand.o: rlmbutil.h
input.o: rlmbutil.h
isearch.o: rlmbutil.h
mbutil.o: rlmbutil.h
misc.o: rlmbutil.h
readline.o: rlmbutil.h
search.o: rlmbutil.h
text.o: rlmbutil.h
vi_mode.o: rlmbutil.h
# Rules for deficient makes, like SunOS and Solaris
bind.o: bind.c
callback.o: callback.c
compat.o: compat.c
complete.o: complete.c
display.o: display.c
funmap.o: funmap.c
input.o: input.c
isearch.o: isearch.c
keymaps.o: keymaps.c emacs_keymap.c vi_keymap.c
kill.o: kill.c
macro.o: macro.c
mbutil.o: mbutil.c
misc.o: misc.c
nls.o: nls.c
parens.o: parens.c
readline.o: readline.c
rltty.o: rltty.c
savestring.o: savestring.c
search.o: search.c
shell.o: shell.c
signals.o: signals.c
terminal.o: terminal.c
text.o: text.c
tilde.o: tilde.c
undo.o: undo.c
util.o: util.c
vi_mode.o: vi_mode.c
xmalloc.o: xmalloc.c
histexpand.o: histexpand.c
histfile.o: histfile.c
history.o: history.c
histsearch.o: histsearch.c
+1 -1
View File
@@ -1,6 +1,6 @@
/* display.c -- readline redisplay facility. */
/* Copyright (C) 1987-2004 Free Software Foundation, Inc.
/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
This file is part of the GNU Readline Library, a library for
reading lines of text with interactive input and history editing.
+11 -1
View File
@@ -1857,12 +1857,17 @@ rl_message (va_alist)
#endif
va_end (args);
rl_display_prompt = msg_buf;
if (saved_local_prompt == 0)
{
rl_save_prompt ();
msg_saved_prompt = 1;
}
rl_display_prompt = msg_buf;
local_prompt = expand_prompt (msg_buf, &prompt_visible_length,
&prompt_last_invisible,
&prompt_invis_chars_first_line,
&prompt_physical_chars);
local_prompt_prefix = (char *)NULL;
(*rl_redisplay_function) ();
return 0;
@@ -1881,6 +1886,11 @@ rl_message (format, arg1, arg2)
rl_save_prompt ();
msg_saved_prompt = 1;
}
local_prompt = expand_prompt (msg_buf, &prompt_visible_length,
&prompt_last_invisible,
&prompt_invis_chars_first_line,
&prompt_physical_chars);
local_prompt_prefix = (char *)NULL;
(*rl_redisplay_function) ();
return 0;
+1 -1
View File
@@ -1,6 +1,6 @@
/* history.c -- standalone history library */
/* Copyright (C) 1989-2003 Free Software Foundation, Inc.
/* Copyright (C) 1989-2005 Free Software Foundation, Inc.
This file contains the GNU History Library (the Library), a set of
routines for managing the text of previously typed lines.
+441
View File
@@ -0,0 +1,441 @@
/* history.c -- standalone history library */
/* Copyright (C) 1989-2003 Free Software Foundation, Inc.
This file contains the GNU History Library (the Library), a set of
routines for managing the text of previously typed lines.
The Library 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 2, or (at your option)
any later version.
The Library 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.
The GNU General Public License is often shipped with GNU software, and
is generally kept in a file called COPYING or LICENSE. If you do not
have a copy of the license, write to the Free Software Foundation,
59 Temple Place, Suite 330, Boston, MA 02111 USA. */
/* The goal is to make the implementation transparent, so that you
don't have to know what data types are used, just what functions
you can call. I think I have done that. */
#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
# include <config.h>
#endif
#include <stdio.h>
#if defined (HAVE_STDLIB_H)
# include <stdlib.h>
#else
# include "ansi_stdlib.h"
#endif /* HAVE_STDLIB_H */
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include "history.h"
#include "histlib.h"
#include "xmalloc.h"
/* The number of slots to increase the_history by. */
#define DEFAULT_HISTORY_GROW_SIZE 50
static char *hist_inittime PARAMS((void));
/* **************************************************************** */
/* */
/* History Functions */
/* */
/* **************************************************************** */
/* An array of HIST_ENTRY. This is where we store the history. */
static HIST_ENTRY **the_history = (HIST_ENTRY **)NULL;
/* Non-zero means that we have enforced a limit on the amount of
history that we save. */
static int history_stifled;
/* The current number of slots allocated to the input_history. */
static int history_size;
/* If HISTORY_STIFLED is non-zero, then this is the maximum number of
entries to remember. */
int history_max_entries;
int max_input_history; /* backwards compatibility */
/* The current location of the interactive history pointer. Just makes
life easier for outside callers. */
int history_offset;
/* The number of strings currently stored in the history list. */
int history_length;
/* The logical `base' of the history array. It defaults to 1. */
int history_base = 1;
/* Return the current HISTORY_STATE of the history. */
HISTORY_STATE *
history_get_history_state ()
{
HISTORY_STATE *state;
state = (HISTORY_STATE *)xmalloc (sizeof (HISTORY_STATE));
state->entries = the_history;
state->offset = history_offset;
state->length = history_length;
state->size = history_size;
state->flags = 0;
if (history_stifled)
state->flags |= HS_STIFLED;
return (state);
}
/* Set the state of the current history array to STATE. */
void
history_set_history_state (state)
HISTORY_STATE *state;
{
the_history = state->entries;
history_offset = state->offset;
history_length = state->length;
history_size = state->size;
if (state->flags & HS_STIFLED)
history_stifled = 1;
}
/* Begin a session in which the history functions might be used. This
initializes interactive variables. */
void
using_history ()
{
history_offset = history_length;
}
/* Return the number of bytes that the primary history entries are using.
This just adds up the lengths of the_history->lines and the associated
timestamps. */
int
history_total_bytes ()
{
register int i, result;
for (i = result = 0; the_history && the_history[i]; i++)
result += HISTENT_BYTES (the_history[i]);
return (result);
}
/* Returns the magic number which says what history element we are
looking at now. In this implementation, it returns history_offset. */
int
where_history ()
{
return (history_offset);
}
/* Make the current history item be the one at POS, an absolute index.
Returns zero if POS is out of range, else non-zero. */
int
history_set_pos (pos)
int pos;
{
if (pos > history_length || pos < 0 || !the_history)
return (0);
history_offset = pos;
return (1);
}
/* Return the current history array. The caller has to be carefull, since this
is the actual array of data, and could be bashed or made corrupt easily.
The array is terminated with a NULL pointer. */
HIST_ENTRY **
history_list ()
{
return (the_history);
}
/* Return the history entry at the current position, as determined by
history_offset. If there is no entry there, return a NULL pointer. */
HIST_ENTRY *
current_history ()
{
return ((history_offset == history_length) || the_history == 0)
? (HIST_ENTRY *)NULL
: the_history[history_offset];
}
/* Back up history_offset to the previous history entry, and return
a pointer to that entry. If there is no previous entry then return
a NULL pointer. */
HIST_ENTRY *
previous_history ()
{
return history_offset ? the_history[--history_offset] : (HIST_ENTRY *)NULL;
}
/* Move history_offset forward to the next history entry, and return
a pointer to that entry. If there is no next entry then return a
NULL pointer. */
HIST_ENTRY *
next_history ()
{
return (history_offset == history_length) ? (HIST_ENTRY *)NULL : the_history[++history_offset];
}
/* Return the history entry which is logically at OFFSET in the history array.
OFFSET is relative to history_base. */
HIST_ENTRY *
history_get (offset)
int offset;
{
int local_index;
local_index = offset - history_base;
return (local_index >= history_length || local_index < 0 || !the_history)
? (HIST_ENTRY *)NULL
: the_history[local_index];
}
time_t
history_get_time (hist)
HIST_ENTRY *hist;
{
char *ts;
time_t t;
if (hist == 0 || hist->timestamp == 0)
return 0;
ts = hist->timestamp;
if (ts[0] != history_comment_char)
return 0;
t = (time_t) atol (ts + 1); /* XXX - should use strtol() here */
return t;
}
static char *
hist_inittime ()
{
time_t t;
char ts[64], *ret;
t = (time_t) time ((time_t *)0);
#if defined (HAVE_VSNPRINTF) /* assume snprintf if vsnprintf exists */
snprintf (ts, sizeof (ts) - 1, "X%lu", (unsigned long) t);
#else
sprintf (ts, "X%lu", (unsigned long) t);
#endif
ret = savestring (ts);
ret[0] = history_comment_char;
return ret;
}
/* Place STRING at the end of the history list. The data field
is set to NULL. */
void
add_history (string)
const char *string;
{
HIST_ENTRY *temp;
if (history_stifled && (history_length == history_max_entries))
{
register int i;
/* If the history is stifled, and history_length is zero,
and it equals history_max_entries, we don't save items. */
if (history_length == 0)
return;
/* If there is something in the slot, then remove it. */
if (the_history[0])
(void) free_history_entry (the_history[0]);
/* Copy the rest of the entries, moving down one slot. */
for (i = 0; i < history_length; i++)
the_history[i] = the_history[i + 1];
history_base++;
}
else
{
if (history_size == 0)
{
history_size = DEFAULT_HISTORY_GROW_SIZE;
the_history = (HIST_ENTRY **)xmalloc (history_size * sizeof (HIST_ENTRY *));
history_length = 1;
}
else
{
if (history_length == (history_size - 1))
{
history_size += DEFAULT_HISTORY_GROW_SIZE;
the_history = (HIST_ENTRY **)
xrealloc (the_history, history_size * sizeof (HIST_ENTRY *));
}
history_length++;
}
}
temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
temp->line = savestring (string);
temp->data = (char *)NULL;
temp->timestamp = hist_inittime ();
the_history[history_length] = (HIST_ENTRY *)NULL;
the_history[history_length - 1] = temp;
}
/* Change the time stamp of the most recent history entry to STRING. */
void
add_history_time (string)
const char *string;
{
HIST_ENTRY *hs;
hs = the_history[history_length - 1];
FREE (hs->timestamp);
hs->timestamp = savestring (string);
}
/* Free HIST and return the data so the calling application can free it
if necessary and desired. */
histdata_t
free_history_entry (hist)
HIST_ENTRY *hist;
{
histdata_t x;
if (hist == 0)
return ((histdata_t) 0);
FREE (hist->line);
FREE (hist->timestamp);
x = hist->data;
free (hist);
return (x);
}
/* Make the history entry at WHICH have LINE and DATA. This returns
the old entry so you can dispose of the data. In the case of an
invalid WHICH, a NULL pointer is returned. */
HIST_ENTRY *
replace_history_entry (which, line, data)
int which;
const char *line;
histdata_t data;
{
HIST_ENTRY *temp, *old_value;
if (which < 0 || which >= history_length)
return ((HIST_ENTRY *)NULL);
temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
old_value = the_history[which];
temp->line = savestring (line);
temp->data = data;
temp->timestamp = savestring (old_value->timestamp);
the_history[which] = temp;
return (old_value);
}
/* Remove history element WHICH from the history. The removed
element is returned to you so you can free the line, data,
and containing structure. */
HIST_ENTRY *
remove_history (which)
int which;
{
HIST_ENTRY *return_value;
register int i;
if (which < 0 || which >= history_length || history_length == 0)
return ((HIST_ENTRY *)NULL);
return_value = the_history[which];
for (i = which; i < history_length; i++)
the_history[i] = the_history[i + 1];
history_length--;
return (return_value);
}
/* Stifle the history list, remembering only MAX number of lines. */
void
stifle_history (max)
int max;
{
register int i, j;
if (max < 0)
max = 0;
if (history_length > max)
{
/* This loses because we cannot free the data. */
for (i = 0, j = history_length - max; i < j; i++)
free_history_entry (the_history[i]);
history_base = i;
for (j = 0, i = history_length - max; j < max; i++, j++)
the_history[j] = the_history[i];
the_history[j] = (HIST_ENTRY *)NULL;
history_length = j;
}
history_stifled = 1;
max_input_history = history_max_entries = max;
}
/* Stop stifling the history. This returns the previous maximum
number of history entries. The value is positive if the history
was stifled, negative if it wasn't. */
int
unstifle_history ()
{
if (history_stifled)
{
history_stifled = 0;
return (history_max_entries);
}
else
return (-history_max_entries);
}
int
history_is_stifled ()
{
return (history_stifled);
}
void
clear_history ()
{
register int i;
/* This loses because we cannot free the data. */
for (i = 0; i < history_length; i++)
{
free_history_entry (the_history[i]);
the_history[i] = (HIST_ENTRY *)NULL;
}
history_offset = history_length = 0;
}
+1 -1
View File
@@ -1,6 +1,6 @@
/* mbutil.c -- readline multibyte character utility functions */
/* Copyright (C) 2001-2004 Free Software Foundation, Inc.
/* Copyright (C) 2001-2005 Free Software Foundation, Inc.
This file is part of the GNU Readline Library, a library for
reading lines of text with interactive input and history editing.
+7 -4
View File
@@ -77,18 +77,20 @@ _rl_find_next_mbchar_internal (string, seed, count, find_non_zero)
char *string;
int seed, count, find_non_zero;
{
size_t tmp = 0;
size_t tmp;
mbstate_t ps;
int point = 0;
int point;
wchar_t wc;
tmp = 0;
memset(&ps, 0, sizeof (mbstate_t));
if (seed < 0)
seed = 0;
if (count <= 0)
return seed;
point = seed + _rl_adjust_point(string, seed, &ps);
point = seed + _rl_adjust_point (string, seed, &ps);
/* if this is true, means that seed was not pointed character
started byte. So correct the point and consume count */
if (seed < point)
@@ -134,7 +136,8 @@ _rl_find_next_mbchar_internal (string, seed, count, find_non_zero)
break;
}
}
return point;
return point;
}
static int
+1 -1
View File
@@ -1,7 +1,7 @@
/* readline.c -- a general facility for reading lines of input
with emacs style editing and completion. */
/* Copyright (C) 1987-2002 Free Software Foundation, Inc.
/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
This file is part of the GNU Readline Library, a library for
reading lines of text with interactive input and history editing.
-6
View File
@@ -656,11 +656,6 @@ _rl_dispatch_subseq (key, map, got_subseq)
already taken care of pushing any necessary input back onto
the input queue with _rl_unget_char. */
{
#if 0
r = _rl_dispatch (ANYOTHERKEY, FUNCTION_TO_KEYMAP (map, key));
#else
/* XXX - experimental code -- might never be executed. Save
for later. */
Keymap m = FUNCTION_TO_KEYMAP (map, key);
int type = m[ANYOTHERKEY].type;
func = m[ANYOTHERKEY].function;
@@ -682,7 +677,6 @@ _rl_dispatch_subseq (key, map, got_subseq)
}
else
r = _rl_dispatch (ANYOTHERKEY, m);
#endif
}
else if (r && map[ANYOTHERKEY].function)
{
+1 -1
View File
@@ -2,7 +2,7 @@
# Makefile for the Bash library
#
#
# Copyright (C) 1998-2002 Free Software Foundation, Inc.
# Copyright (C) 1998-2005 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+6 -2
View File
@@ -86,7 +86,7 @@ CSOURCES = clktck.c clock.c getcwd.c getenv.c oslib.c setlinebuf.c \
inet_aton.c netconn.c netopen.c strpbrk.c timeval.c makepath.c \
pathcanon.c pathphys.c tmpfile.c stringlist.c stringvec.c spell.c \
shquote.c strtrans.c strindex.c snprintf.c mailstat.c \
fmtulong.c fmtullong.c fmtumax.c shmatch.c \
fmtulong.c fmtullong.c fmtumax.c shmatch.c strnlen.c \
strtoll.c strtoull.c strtoimax.c strtoumax.c memset.c strstr.c \
mktime.c strftime.c xstrchr.c zcatfd.c
@@ -95,7 +95,7 @@ HSOURCES =
# The object files contained in $(LIBRARY_NAME)
LIBOBJS = @LIBOBJS@
OBJECTS = clktck.o clock.o getenv.o oslib.o setlinebuf.o \
OBJECTS = clktck.o clock.o getenv.o oslib.o setlinebuf.o strnlen.o \
itos.o zread.o zwrite.o shtty.o shmatch.o \
netconn.o netopen.o timeval.o makepath.o pathcanon.o \
pathphys.o tmpfile.o stringlist.o stringvec.o spell.o shquote.o \
@@ -162,6 +162,7 @@ strftime.o: strftime.c
strindex.o: strindex.c
stringlist.o: stringlist.c
stringvec.o: stringvec.c
strnlen.o: strnlen.c
strpbrk.o: strpbrk.c
strtod.o: strtod.c
strtoimax.o: strtoimax.c
@@ -218,6 +219,7 @@ strftime.o: ${BUILD_DIR}/config.h
strindex.o: ${BUILD_DIR}/config.h
stringlist.o: ${BUILD_DIR}/config.h
stringvec.o: ${BUILD_DIR}/config.h
strnlen.o: ${BUILD_DIR}/config.h
strpbrk.o: ${BUILD_DIR}/config.h
strtod.o: ${BUILD_DIR}/config.h
strtoimax.o: ${BUILD_DIR}/config.h
@@ -372,6 +374,8 @@ stringvec.o: ${topdir}/unwind_prot.h ${topdir}/dispose_cmd.h
stringvec.o: ${topdir}/make_cmd.h ${topdir}/subst.h ${topdir}/sig.h
stringvec.o: ${BUILD_DIR}/pathnames.h ${topdir}/externs.h ${BUILD_DIR}/version.h
strnlen.o: ${BASHINCDIR}/stdc.h
strpbrk.o: ${BASHINCDIR}/stdc.h
strtod.o: ${topdir}/bashansi.h
+1 -1
View File
@@ -1,6 +1,6 @@
/* netconn.c -- is a particular file descriptor a network connection?. */
/* Copyright (C) 2002 Free Software Foundation, Inc.
/* Copyright (C) 2002-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
+2 -2
View File
@@ -52,8 +52,8 @@ isnetconn (fd)
l = sizeof(sa);
rv = getpeername(fd, &sa, &l);
/* Solaris 2.5 getpeername() returns EINVAL if the fd is not a socket. */
return ((rv < 0 && (errno == ENOTSOCK || errno == EINVAL)) ? 0 : 1);
/* Posix.2 says getpeername can return these errors. */
return ((rv < 0 && (errno == ENOTSOCK || errno == ENOTCONN || errno == EINVAL)) ? 0 : 1);
#else /* !HAVE_GETPEERNAME || SVR4_2 || __BEOS__ */
# if defined (SVR4) || defined (SVR4_2)
/* Sockets on SVR4 and SVR4.2 are character special (streams) devices. */
+1 -1
View File
@@ -4,7 +4,7 @@
# #
####################################################################
# Copyright (C) 1996 Free Software Foundation, Inc.
# Copyright (C) 1996-2005 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+91
View File
@@ -0,0 +1,91 @@
## -*- text -*- ####################################################
# #
# Makefile for termcap replacement libbrary. #
# #
####################################################################
# Copyright (C) 1996 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
srcdir = @srcdir@
VPATH = .:@srcdir@
topdir = @top_srcdir@
BUILD_DIR = @BUILD_DIR@
libdir = @libdir@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
CC = @CC@
RANLIB = @RANLIB@
AR = @AR@
ARFLAGS = @ARFLAGS@
RM = rm -f
CP = cp
MV = mv
SHELL = @MAKE_SHELL@
CFLAGS = @CFLAGS@
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
DEFS = @DEFS@
INCLUDES = -I. -I../.. -I$(topdir) -I$(topdir)/lib -I$(srcdir)
CCFLAGS = $(CFLAGS) $(DEFS) $(CPPFLAGS) ${INCLUDES}
# Here is a rule for making .o files from .c files that doesn't force
# the type of the machine (like -sun3) into the flags.
.c.o:
$(CC) -c $(CCFLAGS) $<
SOURCES = termcap.c tparam.c
OBJECTS = termcap.o tparam.o
DOCUMENTATION = termcap.texinfo
THINGS_TO_TAR = $(SOURCES) $(DOCUMENTATION)
##########################################################################
all: libtermcap.a
libtermcap.a: $(OBJECTS)
$(RM) -f $@
$(AR) $(ARFLAGS) $@ $(OBJECTS)
-test -n "$(RANLIB)" && $(RANLIB) $@
install:
clean:
$(RM) *.o *.a *.log *.cp *.tp *.vr *.fn *.aux *.pg *.toc
mostlyclean: clean
distclean maintainer-clean: clean
$(RM) Makefile
$(DESTDIR)$(libdir)/libtermcap.a: libtermcap.a
${INSTALL_DATA} -c -m 644 libtermcap.a $@
-test -n "$(RANLIB)" && $(RANLIB) -t $@
termcap.o: $(BUILD_DIR)/config.h
tparam.o: $(BUILD_DIR)/config.h
version.o: $(BUILD_DIR)/config.h
+1 -1
View File
@@ -4,7 +4,7 @@
# #
####################################################################
# Copyright (C) 1996 Free Software Foundation, Inc.
# Copyright (C) 1996-2005 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
+127
View File
@@ -0,0 +1,127 @@
## -*- text -*- ####################################################
# #
# Makefile for the GNU Tilde Library. #
# #
####################################################################
# Copyright (C) 1996 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
srcdir = @srcdir@
VPATH = .:@srcdir@
topdir = @top_srcdir@
BUILD_DIR = @BUILD_DIR@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
CC = @CC@
RANLIB = @RANLIB@
AR = @AR@
ARFLAGS = @ARFLAGS@
RM = rm
CP = cp
MV = mv
SHELL = @MAKE_SHELL@
PROFILE_FLAGS = @PROFILE_FLAGS@
CFLAGS = @CFLAGS@
LOCAL_CFLAGS = @LOCAL_CFLAGS@
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@ @LOCAL_LDFLAGS@
DEFS = @DEFS@
LOCAL_DEFS = @LOCAL_DEFS@
BASHINCDIR = ${topdir}/include
INCLUDES = -I. -I../.. -I$(topdir) -I${BASHINCDIR} -I$(topdir)/lib
CCFLAGS = $(PROFILE_FLAGS) $(DEFS) $(LOCAL_DEFS) $(CPPFLAGS) \
${INCLUDES} $(LOCAL_CFLAGS) $(CFLAGS)
.c.o:
$(CC) -c $(CCFLAGS) $<
# The name of the library target.
LIBRARY_NAME = libtilde.a
# The C code source files for this library.
CSOURCES = $(srcdir)/tilde.c
# The header files for this library.
HSOURCES = $(srcdir)/tilde.h
OBJECTS = tilde.o
# The texinfo files which document this library.
DOCSOURCE = doc/tilde.texi
DOCOBJECT = doc/tilde.dvi
DOCSUPPORT = doc/Makefile
DOCUMENTATION = $(DOCSOURCE) $(DOCOBJECT) $(DOCSUPPORT)
SUPPORT = Makefile ChangeLog $(DOCSUPPORT)
SOURCES = $(CSOURCES) $(HSOURCES) $(DOCSOURCE)
THINGS_TO_TAR = $(SOURCES) $(SUPPORT)
######################################################################
all: $(LIBRARY_NAME)
$(LIBRARY_NAME): $(OBJECTS)
$(RM) -f $@
$(AR) $(ARFLAGS) $@ $(OBJECTS)
-test -n "$(RANLIB)" && $(RANLIB) $@
documentation: force
-(cd doc; $(MAKE) $(MFLAGS))
force:
# The rule for 'includes' is written funny so that the if statement
# always returns TRUE unless there really was an error installing the
# include files.
install:
$(INSTALL_DATA) -c -m 644 $(LIBRARY_NAME) $(libdir)/$(LIBRARY_NAME)
-test -n "$(RANLIB)" && $(RANLIB) -t $(libdir)/$(LIBRARY_NAME)
clean:
$(RM) -f $(OBJECTS) $(LIBRARY_NAME)
-( cd doc && $(MAKE) $(MFLAGS) $@ )
realclean distclean maintainer-clean: clean
-( cd doc && $(MAKE) $(MFLAGS) $@ )
$(RM) -f Makefile
mostlyclean: clean
-( cd doc && $(MAKE) $(MFLAGS) $@ )
######################################################################
# #
# Dependencies for the object files which make up this library. #
# #
######################################################################
tilde.o: tilde.h $(BASHINCDIR)/ansi_stdlib.h
tilde.o: $(BUILD_DIR)/config.h
# Rules for deficient makes, like SunOS and Solaris
tilde.o: tilde.c
+1 -1
View File
@@ -1,7 +1,7 @@
/* make_cmd.c -- Functions for making instances of the various
parser constructs. */
/* Copyright (C) 1989-2003 Free Software Foundation, Inc.
/* Copyright (C) 1989-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
+851
View File
@@ -0,0 +1,851 @@
/* make_cmd.c -- Functions for making instances of the various
parser constructs. */
/* Copyright (C) 1989-2003 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 2, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
#include "config.h"
#include <stdio.h>
#include "bashtypes.h"
#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
# include <sys/file.h>
#endif
#include "filecntl.h"
#include "bashansi.h"
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "bashintl.h"
#include "syntax.h"
#include "command.h"
#include "general.h"
#include "error.h"
#include "flags.h"
#include "make_cmd.h"
#include "dispose_cmd.h"
#include "variables.h"
#include "subst.h"
#include "input.h"
#include "ocache.h"
#include "externs.h"
#if defined (JOB_CONTROL)
#include "jobs.h"
#endif
#include "shmbutil.h"
extern int line_number, current_command_line_count;
extern int last_command_exit_value;
/* Object caching */
sh_obj_cache_t wdcache = {0, 0, 0};
sh_obj_cache_t wlcache = {0, 0, 0};
#define WDCACHESIZE 60
#define WLCACHESIZE 60
static COMMAND *make_for_or_select __P((enum command_type, WORD_DESC *, WORD_LIST *, COMMAND *, int));
#if defined (ARITH_FOR_COMMAND)
static WORD_LIST *make_arith_for_expr __P((char *));
#endif
static COMMAND *make_until_or_while __P((enum command_type, COMMAND *, COMMAND *));
void
cmd_init ()
{
ocache_create (wdcache, WORD_DESC, WDCACHESIZE);
ocache_create (wlcache, WORD_LIST, WLCACHESIZE);
}
WORD_DESC *
alloc_word_desc ()
{
WORD_DESC *temp;
ocache_alloc (wdcache, WORD_DESC, temp);
temp->flags = 0;
temp->word = 0;
return temp;
}
WORD_DESC *
make_bare_word (string)
const char *string;
{
WORD_DESC *temp;
temp = alloc_word_desc ();
if (*string)
temp->word = savestring (string);
else
{
temp->word = (char *)xmalloc (1);
temp->word[0] = '\0';
}
return (temp);
}
WORD_DESC *
make_word_flags (w, string)
WORD_DESC *w;
const char *string;
{
register int i;
size_t slen;
DECLARE_MBSTATE;
i = 0;
slen = strlen (string);
while (i < slen)
{
switch (string[i])
{
case '$':
w->flags |= W_HASDOLLAR;
break;
case '\\':
break; /* continue the loop */
case '\'':
case '`':
case '"':
w->flags |= W_QUOTED;
break;
}
ADVANCE_CHAR (string, slen, i);
}
return (w);
}
WORD_DESC *
make_word (string)
const char *string;
{
WORD_DESC *temp;
temp = make_bare_word (string);
return (make_word_flags (temp, string));
}
WORD_DESC *
make_word_from_token (token)
int token;
{
char tokenizer[2];
tokenizer[0] = token;
tokenizer[1] = '\0';
return (make_word (tokenizer));
}
WORD_LIST *
make_word_list (word, wlink)
WORD_DESC *word;
WORD_LIST *wlink;
{
WORD_LIST *temp;
ocache_alloc (wlcache, WORD_LIST, temp);
temp->word = word;
temp->next = wlink;
return (temp);
}
COMMAND *
make_command (type, pointer)
enum command_type type;
SIMPLE_COM *pointer;
{
COMMAND *temp;
temp = (COMMAND *)xmalloc (sizeof (COMMAND));
temp->type = type;
temp->value.Simple = pointer;
temp->value.Simple->flags = temp->flags = 0;
temp->redirects = (REDIRECT *)NULL;
return (temp);
}
COMMAND *
command_connect (com1, com2, connector)
COMMAND *com1, *com2;
int connector;
{
CONNECTION *temp;
temp = (CONNECTION *)xmalloc (sizeof (CONNECTION));
temp->connector = connector;
temp->first = com1;
temp->second = com2;
return (make_command (cm_connection, (SIMPLE_COM *)temp));
}
static COMMAND *
make_for_or_select (type, name, map_list, action, lineno)
enum command_type type;
WORD_DESC *name;
WORD_LIST *map_list;
COMMAND *action;
int lineno;
{
FOR_COM *temp;
temp = (FOR_COM *)xmalloc (sizeof (FOR_COM));
temp->flags = 0;
temp->name = name;
temp->line = lineno;
temp->map_list = map_list;
temp->action = action;
return (make_command (type, (SIMPLE_COM *)temp));
}
COMMAND *
make_for_command (name, map_list, action, lineno)
WORD_DESC *name;
WORD_LIST *map_list;
COMMAND *action;
int lineno;
{
return (make_for_or_select (cm_for, name, map_list, action, lineno));
}
COMMAND *
make_select_command (name, map_list, action, lineno)
WORD_DESC *name;
WORD_LIST *map_list;
COMMAND *action;
int lineno;
{
#if defined (SELECT_COMMAND)
return (make_for_or_select (cm_select, name, map_list, action, lineno));
#else
last_command_exit_value = 2;
return ((COMMAND *)NULL);
#endif
}
#if defined (ARITH_FOR_COMMAND)
static WORD_LIST *
make_arith_for_expr (s)
char *s;
{
WORD_LIST *result;
WORD_DESC *wd;
if (s == 0 || *s == '\0')
return ((WORD_LIST *)NULL);
wd = make_word (s);
wd->flags |= W_NOGLOB|W_NOSPLIT|W_QUOTED; /* no word splitting or globbing */
result = make_word_list (wd, (WORD_LIST *)NULL);
return result;
}
#endif
/* Note that this function calls dispose_words on EXPRS, since it doesn't
use the word list directly. We free it here rather than at the caller
because no other function in this file requires that the caller free
any arguments. */
COMMAND *
make_arith_for_command (exprs, action, lineno)
WORD_LIST *exprs;
COMMAND *action;
int lineno;
{
#if defined (ARITH_FOR_COMMAND)
ARITH_FOR_COM *temp;
WORD_LIST *init, *test, *step;
char *s, *t, *start;
int nsemi;
init = test = step = (WORD_LIST *)NULL;
/* Parse the string into the three component sub-expressions. */
start = t = s = exprs->word->word;
for (nsemi = 0; ;)
{
/* skip whitespace at the start of each sub-expression. */
while (whitespace (*s))
s++;
start = s;
/* skip to the semicolon or EOS */
while (*s && *s != ';')
s++;
t = (s > start) ? substring (start, 0, s - start) : (char *)NULL;
nsemi++;
switch (nsemi)
{
case 1:
init = make_arith_for_expr (t);
break;
case 2:
test = make_arith_for_expr (t);
break;
case 3:
step = make_arith_for_expr (t);
break;
}
FREE (t);
if (*s == '\0')
break;
s++; /* skip over semicolon */
}
if (nsemi != 3)
{
if (nsemi < 3)
parser_error (lineno, _("syntax error: arithmetic expression required"));
else
parser_error (lineno, _("syntax error: `;' unexpected"));
parser_error (lineno, _("syntax error: `((%s))'"), exprs->word->word);
last_command_exit_value = 2;
return ((COMMAND *)NULL);
}
temp = (ARITH_FOR_COM *)xmalloc (sizeof (ARITH_FOR_COM));
temp->flags = 0;
temp->line = lineno;
temp->init = init ? init : make_arith_for_expr ("1");
temp->test = test ? test : make_arith_for_expr ("1");
temp->step = step ? step : make_arith_for_expr ("1");
temp->action = action;
dispose_words (exprs);
return (make_command (cm_arith_for, (SIMPLE_COM *)temp));
#else
dispose_words (exprs);
last_command_exit_value = 2;
return ((COMMAND *)NULL);
#endif /* ARITH_FOR_COMMAND */
}
COMMAND *
make_group_command (command)
COMMAND *command;
{
GROUP_COM *temp;
temp = (GROUP_COM *)xmalloc (sizeof (GROUP_COM));
temp->command = command;
return (make_command (cm_group, (SIMPLE_COM *)temp));
}
COMMAND *
make_case_command (word, clauses, lineno)
WORD_DESC *word;
PATTERN_LIST *clauses;
int lineno;
{
CASE_COM *temp;
temp = (CASE_COM *)xmalloc (sizeof (CASE_COM));
temp->flags = 0;
temp->line = lineno;
temp->word = word;
temp->clauses = REVERSE_LIST (clauses, PATTERN_LIST *);
return (make_command (cm_case, (SIMPLE_COM *)temp));
}
PATTERN_LIST *
make_pattern_list (patterns, action)
WORD_LIST *patterns;
COMMAND *action;
{
PATTERN_LIST *temp;
temp = (PATTERN_LIST *)xmalloc (sizeof (PATTERN_LIST));
temp->patterns = REVERSE_LIST (patterns, WORD_LIST *);
temp->action = action;
temp->next = NULL;
return (temp);
}
COMMAND *
make_if_command (test, true_case, false_case)
COMMAND *test, *true_case, *false_case;
{
IF_COM *temp;
temp = (IF_COM *)xmalloc (sizeof (IF_COM));
temp->flags = 0;
temp->test = test;
temp->true_case = true_case;
temp->false_case = false_case;
return (make_command (cm_if, (SIMPLE_COM *)temp));
}
static COMMAND *
make_until_or_while (which, test, action)
enum command_type which;
COMMAND *test, *action;
{
WHILE_COM *temp;
temp = (WHILE_COM *)xmalloc (sizeof (WHILE_COM));
temp->flags = 0;
temp->test = test;
temp->action = action;
return (make_command (which, (SIMPLE_COM *)temp));
}
COMMAND *
make_while_command (test, action)
COMMAND *test, *action;
{
return (make_until_or_while (cm_while, test, action));
}
COMMAND *
make_until_command (test, action)
COMMAND *test, *action;
{
return (make_until_or_while (cm_until, test, action));
}
COMMAND *
make_arith_command (exp)
WORD_LIST *exp;
{
#if defined (DPAREN_ARITHMETIC)
COMMAND *command;
ARITH_COM *temp;
command = (COMMAND *)xmalloc (sizeof (COMMAND));
command->value.Arith = temp = (ARITH_COM *)xmalloc (sizeof (ARITH_COM));
temp->flags = 0;
temp->line = line_number;
temp->exp = exp;
command->type = cm_arith;
command->redirects = (REDIRECT *)NULL;
command->flags = 0;
return (command);
#else
last_command_exit_value = 2;
return ((COMMAND *)NULL);
#endif
}
#if defined (COND_COMMAND)
struct cond_com *
make_cond_node (type, op, left, right)
int type;
WORD_DESC *op;
struct cond_com *left, *right;
{
COND_COM *temp;
temp = (COND_COM *)xmalloc (sizeof (COND_COM));
temp->flags = 0;
temp->line = line_number;
temp->type = type;
temp->op = op;
temp->left = left;
temp->right = right;
return (temp);
}
#endif
COMMAND *
make_cond_command (cond_node)
COND_COM *cond_node;
{
#if defined (COND_COMMAND)
COMMAND *command;
command = (COMMAND *)xmalloc (sizeof (COMMAND));
command->value.Cond = cond_node;
command->type = cm_cond;
command->redirects = (REDIRECT *)NULL;
command->flags = 0;
command->line = cond_node ? cond_node->line : 0;
return (command);
#else
last_command_exit_value = 2;
return ((COMMAND *)NULL);
#endif
}
COMMAND *
make_bare_simple_command ()
{
COMMAND *command;
SIMPLE_COM *temp;
command = (COMMAND *)xmalloc (sizeof (COMMAND));
command->value.Simple = temp = (SIMPLE_COM *)xmalloc (sizeof (SIMPLE_COM));
temp->flags = 0;
temp->line = line_number;
temp->words = (WORD_LIST *)NULL;
temp->redirects = (REDIRECT *)NULL;
command->type = cm_simple;
command->redirects = (REDIRECT *)NULL;
command->flags = 0;
return (command);
}
/* Return a command which is the connection of the word or redirection
in ELEMENT, and the command * or NULL in COMMAND. */
COMMAND *
make_simple_command (element, command)
ELEMENT element;
COMMAND *command;
{
/* If we are starting from scratch, then make the initial command
structure. Also note that we have to fill in all the slots, since
malloc doesn't return zeroed space. */
if (!command)
command = make_bare_simple_command ();
if (element.word)
command->value.Simple->words = make_word_list (element.word, command->value.Simple->words);
else if (element.redirect)
{
REDIRECT *r = element.redirect;
/* Due to the way <> is implemented, there may be more than a single
redirection in element.redirect. We just follow the chain as far
as it goes, and hook onto the end. */
while (r->next)
r = r->next;
r->next = command->value.Simple->redirects;
command->value.Simple->redirects = element.redirect;
}
return (command);
}
/* Because we are Bourne compatible, we read the input for this
<< or <<- redirection now, from wherever input is coming from.
We store the input read into a WORD_DESC. Replace the text of
the redirectee.word with the new input text. If <<- is on,
then remove leading TABS from each line. */
void
make_here_document (temp)
REDIRECT *temp;
{
int kill_leading, redir_len;
char *redir_word, *document, *full_line;
int document_index, document_size, delim_unquoted;
if (temp->instruction != r_deblank_reading_until &&
temp->instruction != r_reading_until)
{
internal_error (_("make_here_document: bad instruction type %d"), temp->instruction);
return;
}
kill_leading = temp->instruction == r_deblank_reading_until;
document = (char *)NULL;
document_index = document_size = 0;
/* Quote removal is the only expansion performed on the delimiter
for here documents, making it an extremely special case. */
redir_word = string_quote_removal (temp->redirectee.filename->word, 0);
/* redirection_expand will return NULL if the expansion results in
multiple words or no words. Check for that here, and just abort
this here document if it does. */
if (redir_word)
redir_len = strlen (redir_word);
else
{
temp->here_doc_eof = (char *)xmalloc (1);
temp->here_doc_eof[0] = '\0';
goto document_done;
}
free (temp->redirectee.filename->word);
temp->here_doc_eof = redir_word;
/* Read lines from wherever lines are coming from.
For each line read, if kill_leading, then kill the
leading tab characters.
If the line matches redir_word exactly, then we have
manufactured the document. Otherwise, add the line to the
list of lines in the document. */
/* If the here-document delimiter was quoted, the lines should
be read verbatim from the input. If it was not quoted, we
need to perform backslash-quoted newline removal. */
delim_unquoted = (temp->redirectee.filename->flags & W_QUOTED) == 0;
while (full_line = read_secondary_line (delim_unquoted))
{
register char *line;
int len;
line = full_line;
line_number++;
if (kill_leading && *line)
{
/* Hack: To be compatible with some Bourne shells, we
check the word before stripping the whitespace. This
is a hack, though. */
if (STREQN (line, redir_word, redir_len) && line[redir_len] == '\n')
goto document_done;
while (*line == '\t')
line++;
}
if (*line == 0)
continue;
if (STREQN (line, redir_word, redir_len) && line[redir_len] == '\n')
goto document_done;
len = strlen (line);
if (len + document_index >= document_size)
{
document_size = document_size ? 2 * (document_size + len) : len + 2;
document = (char *)xrealloc (document, document_size);
}
/* len is guaranteed to be > 0 because of the check for line
being an empty string before the call to strlen. */
FASTCOPY (line, document + document_index, len);
document_index += len;
}
document_done:
if (document)
document[document_index] = '\0';
else
{
document = (char *)xmalloc (1);
document[0] = '\0';
}
temp->redirectee.filename->word = document;
}
/* Generate a REDIRECT from SOURCE, DEST, and INSTRUCTION.
INSTRUCTION is the instruction type, SOURCE is a file descriptor,
and DEST is a file descriptor or a WORD_DESC *. */
REDIRECT *
make_redirection (source, instruction, dest_and_filename)
int source;
enum r_instruction instruction;
REDIRECTEE dest_and_filename;
{
REDIRECT *temp;
WORD_DESC *w;
int wlen;
intmax_t lfd;
temp = (REDIRECT *)xmalloc (sizeof (REDIRECT));
/* First do the common cases. */
temp->redirector = source;
temp->redirectee = dest_and_filename;
temp->instruction = instruction;
temp->flags = 0;
temp->next = (REDIRECT *)NULL;
switch (instruction)
{
case r_output_direction: /* >foo */
case r_output_force: /* >| foo */
case r_err_and_out: /* command &>filename */
temp->flags = O_TRUNC | O_WRONLY | O_CREAT;
break;
case r_appending_to: /* >>foo */
temp->flags = O_APPEND | O_WRONLY | O_CREAT;
break;
case r_input_direction: /* <foo */
case r_inputa_direction: /* foo & makes this. */
temp->flags = O_RDONLY;
break;
case r_input_output: /* <>foo */
temp->flags = O_RDWR | O_CREAT;
break;
case r_deblank_reading_until: /* <<-foo */
case r_reading_until: /* << foo */
case r_reading_string: /* <<< foo */
case r_close_this: /* <&- */
case r_duplicating_input: /* 1<&2 */
case r_duplicating_output: /* 1>&2 */
break;
/* the parser doesn't pass these. */
case r_move_input: /* 1<&2- */
case r_move_output: /* 1>&2- */
case r_move_input_word: /* 1<&$foo- */
case r_move_output_word: /* 1>&$foo- */
break;
/* The way the lexer works we have to do this here. */
case r_duplicating_input_word: /* 1<&$foo */
case r_duplicating_output_word: /* 1>&$foo */
w = dest_and_filename.filename;
wlen = strlen (w->word) - 1;
if (w->word[wlen] == '-') /* Yuck */
{
w->word[wlen] = '\0';
if (all_digits (w->word) && legal_number (w->word, &lfd) && lfd == (int)lfd)
{
dispose_word (w);
temp->instruction = (instruction == r_duplicating_input_word) ? r_move_input : r_move_output;
temp->redirectee.dest = lfd;
}
else
temp->instruction = (instruction == r_duplicating_input_word) ? r_move_input_word : r_move_output_word;
}
break;
default:
programming_error (_("make_redirection: redirection instruction `%d' out of range"), instruction);
abort ();
break;
}
return (temp);
}
COMMAND *
make_function_def (name, command, lineno, lstart)
WORD_DESC *name;
COMMAND *command;
int lineno, lstart;
{
FUNCTION_DEF *temp;
#if defined (ARRAY_VARS)
SHELL_VAR *bash_source_v;
ARRAY *bash_source_a;
char *t;
#endif
temp = (FUNCTION_DEF *)xmalloc (sizeof (FUNCTION_DEF));
temp->command = command;
temp->name = name;
temp->line = lineno;
temp->flags = 0;
command->line = lstart;
/* Information used primarily for debugging. */
temp->source_file = 0;
#if defined (ARRAY_VARS)
GET_ARRAY_FROM_VAR ("BASH_SOURCE", bash_source_v, bash_source_a);
if (bash_source_a && array_num_elements (bash_source_a) > 0)
temp->source_file = array_reference (bash_source_a, 0);
#endif
bind_function_def (name->word, temp);
temp->source_file = 0;
return (make_command (cm_function_def, (SIMPLE_COM *)temp));
}
COMMAND *
make_subshell_command (command)
COMMAND *command;
{
SUBSHELL_COM *temp;
temp = (SUBSHELL_COM *)xmalloc (sizeof (SUBSHELL_COM));
temp->command = command;
temp->flags = CMD_WANT_SUBSHELL;
return (make_command (cm_subshell, (SIMPLE_COM *)temp));
}
/* Reverse the word list and redirection list in the simple command
has just been parsed. It seems simpler to do this here the one
time then by any other method that I can think of. */
COMMAND *
clean_simple_command (command)
COMMAND *command;
{
if (command->type != cm_simple)
command_error ("clean_simple_command", CMDERR_BADTYPE, command->type, 0);
else
{
command->value.Simple->words =
REVERSE_LIST (command->value.Simple->words, WORD_LIST *);
command->value.Simple->redirects =
REVERSE_LIST (command->value.Simple->redirects, REDIRECT *);
}
return (command);
}
/* The Yacc grammar productions have a problem, in that they take a
list followed by an ampersand (`&') and do a simple command connection,
making the entire list effectively asynchronous, instead of just
the last command. This means that when the list is executed, all
the commands have stdin set to /dev/null when job control is not
active, instead of just the last. This is wrong, and needs fixing
up. This function takes the `&' and applies it to the last command
in the list. This is done only for lists connected by `;'; it makes
`;' bind `tighter' than `&'. */
COMMAND *
connect_async_list (command, command2, connector)
COMMAND *command, *command2;
int connector;
{
COMMAND *t, *t1, *t2;
t1 = command;
t = command->value.Connection->second;
if (!t || (command->flags & CMD_WANT_SUBSHELL) ||
command->value.Connection->connector != ';')
{
t = command_connect (command, command2, connector);
return t;
}
/* This is just defensive programming. The Yacc precedence rules
will generally hand this function a command where t points directly
to the command we want (e.g. given a ; b ; c ; d &, t1 will point
to the `a ; b ; c' list and t will be the `d'). We only want to do
this if the list is not being executed as a unit in the background
with `( ... )', so we have to check for CMD_WANT_SUBSHELL. That's
the only way to tell. */
while (((t->flags & CMD_WANT_SUBSHELL) == 0) && t->type == cm_connection &&
t->value.Connection->connector == ';')
{
t1 = t;
t = t->value.Connection->second;
}
/* Now we have t pointing to the last command in the list, and
t1->value.Connection->second == t. */
t2 = command_connect (t, command2, connector);
t1->value.Connection->second = t2;
return command;
}
+1 -1
View File
@@ -1,6 +1,6 @@
/* make_cmd.h -- Declarations of functions found in make_cmd.c */
/* Copyright (C) 1993 Free Software Foundation, Inc.
/* Copyright (C) 1993-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
+69
View File
@@ -0,0 +1,69 @@
/* make_cmd.h -- Declarations of functions found in make_cmd.c */
/* Copyright (C) 1993 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 2, or (at your option) any later
version.
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License along
with Bash; see the file COPYING. If not, write to the Free Software
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
#if !defined (_MAKE_CMD_H_)
#define _MAKE_CMD_H_
#include "stdc.h"
extern void cmd_init __P((void));
extern WORD_DESC *alloc_word_desc __P((void));
extern WORD_DESC *make_bare_word __P((const char *));
extern WORD_DESC *make_word_flags __P((WORD_DESC *, const char *));
extern WORD_DESC *make_word __P((const char *));
extern WORD_DESC *make_word_from_token __P((int));
extern WORD_LIST *make_word_list __P((WORD_DESC *, WORD_LIST *));
#define add_string_to_list(s, l) make_word_list (make_word(s), (l))
extern COMMAND *make_command __P((enum command_type, SIMPLE_COM *));
extern COMMAND *command_connect __P((COMMAND *, COMMAND *, int));
extern COMMAND *make_for_command __P((WORD_DESC *, WORD_LIST *, COMMAND *, int));
extern COMMAND *make_group_command __P((COMMAND *));
extern COMMAND *make_case_command __P((WORD_DESC *, PATTERN_LIST *, int));
extern PATTERN_LIST *make_pattern_list __P((WORD_LIST *, COMMAND *));
extern COMMAND *make_if_command __P((COMMAND *, COMMAND *, COMMAND *));
extern COMMAND *make_while_command __P((COMMAND *, COMMAND *));
extern COMMAND *make_until_command __P((COMMAND *, COMMAND *));
extern COMMAND *make_bare_simple_command __P((void));
extern COMMAND *make_simple_command __P((ELEMENT, COMMAND *));
extern void make_here_document __P((REDIRECT *));
extern REDIRECT *make_redirection __P((int, enum r_instruction, REDIRECTEE));
extern COMMAND *make_function_def __P((WORD_DESC *, COMMAND *, int, int));
extern COMMAND *clean_simple_command __P((COMMAND *));
extern COMMAND *make_arith_command __P((WORD_LIST *));
extern COMMAND *make_select_command __P((WORD_DESC *, WORD_LIST *, COMMAND *, int));
#if defined (COND_COMMAND)
extern COND_COM *make_cond_node __P((int, WORD_DESC *, COND_COM *, COND_COM *));
extern COMMAND *make_cond_command __P((COND_COM *));
#endif
extern COMMAND *make_arith_for_command __P((WORD_LIST *, COMMAND *, int));
extern COMMAND *make_subshell_command __P((COMMAND *));
extern COMMAND *connect_async_list __P((COMMAND *, COMMAND *, int));
#endif /* !_MAKE_CMD_H */
+1 -1
View File
@@ -1,6 +1,6 @@
/* Yacc grammar for bash. */
/* Copyright (C) 1989-2004 Free Software Foundation, Inc.
/* Copyright (C) 1989-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
-12
View File
@@ -2066,16 +2066,6 @@ shell_getc (remove_quoted_newline)
if (uc)
shell_input_line_index++;
#if 0
if MBTEST(uc == '\\' && remove_quoted_newline && shell_input_line[shell_input_line_index] == '\n')
{
if (SHOULD_PROMPT ())
prompt_again ();
line_number++;
goto restart_read;
}
#endif
#if defined (ALIAS) || defined (DPAREN_ARITHMETIC)
/* If UC is NULL, we have reached the end of the current input string. If
pushed_string_list is non-empty, it's time to pop to the previous string
@@ -2091,7 +2081,6 @@ shell_getc (remove_quoted_newline)
}
#endif /* ALIAS || DPAREN_ARITHMETIC */
#if 1
if MBTEST(uc == '\\' && remove_quoted_newline && shell_input_line[shell_input_line_index] == '\n')
{
if (SHOULD_PROMPT ())
@@ -2099,7 +2088,6 @@ shell_getc (remove_quoted_newline)
line_number++;
goto restart_read;
}
#endif
if (!uc && shell_input_line_terminator == EOF)
return ((shell_input_line_index != 0) ? '\n' : EOF);
+1 -1
View File
@@ -1,7 +1,7 @@
/* pcomplete.c - functions to generate lists of matches for programmable
completion. */
/* Copyright (C) 1999-2004 Free Software Foundation, Inc.
/* Copyright (C) 1999-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
+4 -2
View File
@@ -513,6 +513,7 @@ it_init_joblist (itp, jstate)
register int i;
register PROCESS *p;
char *s, *t;
JOB *j;
JOB_STATE ws; /* wanted state */
if (jstate == 0)
@@ -523,9 +524,10 @@ it_init_joblist (itp, jstate)
sl = strlist_create (js.j_jobslots);
for (i = js.j_jobslots - 1; i >= 0; i--)
{
if (jobs[i] == 0)
j = get_job_by_jid (i);
if (j == 0)
continue;
p = jobs[i]->pipe;
p = j->pipe;
if (jstate == -1 || JOBSTATE(i) == ws)
{
s = savestring (p->command);
+1 -1
View File
@@ -1,6 +1,6 @@
/* print_command -- A way to make readable commands from a command tree. */
/* Copyright (C) 1989-2004 Free Software Foundation, Inc.
/* Copyright (C) 1989-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
+1307
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -1,10 +1,10 @@
/* subst.c -- The part of the shell that does parameter, command, and
globbing substitutions. */
/* subst.c -- The part of the shell that does parameter, command, arithmetic,
and globbing substitutions. */
/* ``Have a little faith, there's magic in the night. You ain't a
beauty, but, hey, you're alright.'' */
/* Copyright (C) 1987-2004 Free Software Foundation, Inc.
/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
+1 -1
View File
@@ -6931,7 +6931,7 @@ add_twochars:
cases: a quoted null character as above and when
CTLNUL is contained in the (non-null) expansion
of some variable. We use the had_quoted_null flag to
pass the value through this function to its return value. */
pass the value through this function to its caller. */
if ((tflag & W_HASQUOTEDNULL) && QUOTED_NULL (temp) == 0)
remove_quoted_nulls (temp); /* XXX */
}
+8 -4
View File
@@ -78,10 +78,14 @@ sunos4*)
sunos5*-*gcc*|solaris2*-*gcc*)
SHOBJ_CFLAGS=-fpic
SHOBJ_LD='${CC}'
# This line works for the Solaris linker in /usr/ccs/bin/ld
SHOBJ_LDFLAGS='-shared -Wl,-i -Wl,-h,$@'
# This line works for the GNU ld
# SHOBJ_LDFLAGS='-shared -Wl,-h,$@'
ld_used=`gcc -print-prog-name=ld`
if ${ld_used} -V 2>&1 | grep GNU >/dev/null 2>&1; then
# This line works for the GNU ld
SHOBJ_LDFLAGS='-shared -Wl,-h,$@'
else
# This line works for the Solaris linker in /usr/ccs/bin/ld
SHOBJ_LDFLAGS='-shared -Wl,-i -Wl,-h,$@'
fi
# SHLIB_XLDFLAGS='-R $(libdir)'
SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)'
+1 -1
View File
@@ -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
+1 -1
View File
@@ -1,7 +1,7 @@
/* trap.c -- Not the trap command, but useful functions for manipulating
those objects. The trap command is in builtins/trap.def. */
/* Copyright (C) 1987-2003 Free Software Foundation, Inc.
/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
+5 -2
View File
@@ -875,9 +875,12 @@ reset_or_restore_signal_handlers (reset)
/* Take care of the exit trap first */
if (sigmodes[EXIT_TRAP] & SIG_TRAPPED)
{
free_trap_command (EXIT_TRAP);
trap_list[EXIT_TRAP] = (char *)NULL;
sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
if (reset != reset_signal)
{
free_trap_command (EXIT_TRAP);
trap_list[EXIT_TRAP] = (char *)NULL;
}
}
for (i = 1; i < NSIG; i++)
+5 -1
View File
@@ -1,6 +1,6 @@
/* variables.c -- Functions for hacking shell variables. */
/* Copyright (C) 1987-2004 Free Software Foundation, Inc.
/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -350,7 +350,11 @@ initialize_shell_variables (env, privmode)
set_pwd ();
/* Set up initial value of $_ */
#if 0
temp_var = bind_variable ("_", dollar_vars[0], 0);
#else
temp_var = set_if_not ("_", dollar_vars[0]);
#endif
/* Remember this pid. */
dollar_dollar_pid = getpid ();
+5 -2
View File
@@ -1,6 +1,6 @@
/* variables.c -- Functions for hacking shell variables. */
/* Copyright (C) 1987-2004 Free Software Foundation, Inc.
/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -350,7 +350,11 @@ initialize_shell_variables (env, privmode)
set_pwd ();
/* Set up initial value of $_ */
#if 1
temp_var = bind_variable ("_", dollar_vars[0], 0);
#else
temp_var = set_if_not ("_", dollar_vars[0]);
#endif
/* Remember this pid. */
dollar_dollar_pid = getpid ();
@@ -1149,7 +1153,6 @@ get_random_number ()
/* Reset for command and process substitution. */
if (subshell_environment && seeded_subshell == 0)
{
itrace("seeding random number gen in subshell");
sbrand (rseed + getpid() + NOW);
seeded_subshell = 1;
}
+1 -1
View File
@@ -1,6 +1,6 @@
/* variables.h -- data structures for shell variables. */
/* Copyright (C) 1987-2004 Free Software Foundation, Inc.
/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
+1
View File
@@ -330,6 +330,7 @@ extern int get_random_number __P((void));
extern void sv_ifs __P((char *));
extern void sv_path __P((char *));
extern void sv_mail __P((char *));
extern void sv_comp_wordbreaks __P((char *));
extern void sv_globignore __P((char *));
extern void sv_ignoreeof __P((char *));
extern void sv_strict_posix __P((char *));