commit bash-20050210 snapshot
authorChet Ramey <chet.ramey@case.edu>
Sat, 3 Dec 2011 18:43:14 +0000 (13:43 -0500)
committerChet Ramey <chet.ramey@case.edu>
Sat, 3 Dec 2011 18:43:14 +0000 (13:43 -0500)
83 files changed:
CWRU/CWRU.chlog
CWRU/CWRU.chlog~
arrayfunc.c
arrayfunc.c~
builtins/Makefile.in
builtins/Makefile.in~
builtins/common.c
builtins/common.c~
builtins/exit.def
builtins/exit.def~
builtins/fg_bg.def
builtins/fg_bg.def~
builtins/jobs.def
builtins/jobs.def~
builtins/kill.def
builtins/kill.def~
builtins/trap.def
builtins/trap.def~
builtins/wait.def
builtins/wait.def~
command.h
command.h~
dispose_cmd.c
dispose_cmd.c~
dispose_cmd.h
dispose_cmd.h~ [new file with mode: 0644]
doc/bash.1
doc/bash.1~
doc/bashref.texi
doc/bashref.texi~
doc/version.texi
doc/version.texi~
execute_cmd.c
execute_cmd.c~
findcmd.c~ [new file with mode: 0644]
jobs.c
jobs.c~
jobs.h
jobs.h~
lib/doc-support/Makefile.in
lib/doc-support/Makefile.in~ [new file with mode: 0644]
lib/glob/Makefile.in
lib/glob/Makefile.in~ [new file with mode: 0644]
lib/malloc/Makefile.in
lib/malloc/Makefile.in~ [new file with mode: 0644]
lib/readline/Makefile.in
lib/readline/Makefile.in~ [new file with mode: 0644]
lib/readline/display.c
lib/readline/display.c~
lib/readline/history.c
lib/readline/history.c~ [new file with mode: 0644]
lib/readline/mbutil.c
lib/readline/mbutil.c~
lib/readline/readline.c
lib/readline/readline.c~
lib/sh/Makefile.in
lib/sh/Makefile.in~
lib/sh/netconn.c
lib/sh/netconn.c~
lib/termcap/Makefile.in
lib/termcap/Makefile.in~ [new file with mode: 0644]
lib/tilde/Makefile.in
lib/tilde/Makefile.in~ [new file with mode: 0644]
make_cmd.c
make_cmd.c~ [new file with mode: 0644]
make_cmd.h
make_cmd.h~ [new file with mode: 0644]
parse.y
parse.y~
pcomplete.c
pcomplete.c~
print_cmd.c
print_cmd.c~ [new file with mode: 0644]
subst.c
subst.c~
support/shobj-conf
tests/RUN-ONE-TEST
trap.c
trap.c~
variables.c
variables.c~
variables.h
variables.h~

index 1075ef3..0a73ecf 100644 (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>
index fc75173..9e684be 100644 (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>
index c1b589f..127197d 100644 (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.
 
index fc4adb5..c1b589f 100644 (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);
index 26849f1..cf59316 100644 (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
index 9db2675..26849f1 100644 (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 
index dad6e46..9d8f09a 100644 (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.
 
index 8c2dde4..dad6e46 100644 (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;
index 5267567..ddaa5d3 100644 (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.
 
index 9384ade..5267567 100644 (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"));
index 76f6a26..c5e2e47 100644 (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.
 
index 076f807..76f6a26 100644 (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);
index c551b12..4c3ba6a 100644 (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.
 
index 9793f5f..c551b12 100644 (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);
        }
     }
 
index 03f1c82..6bcfad1 100644 (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.
 
index 594c745..03f1c82 100644 (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);
 
index 533720d..669bea7 100644 (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.
 
index d19defb..533720d 100644 (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++)
index 6bf4b8e..22a92be 100644 (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.
 
index 59c6529..6bf4b8e 100644 (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)
index b3fd91e..f9fe7ce 100644 (file)
--- a/command.h
+++ b/command.h
@@ -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.
 
index dbdcd47..b3fd91e 100644 (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 &' */
index f496710..ee2e68c 100644 (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.
 
index ba85d8d..f496710 100644 (file)
@@ -247,6 +247,7 @@ void
 dispose_word_desc (w)
      WORD_DESC *w;
 {
+  w->word = 0;
   ocache_free (wdcache, WORD_DESC, w);
 }
 
index 5bca6d7..55723d4 100644 (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.
 
diff --git a/dispose_cmd.h~ b/dispose_cmd.h~
new file mode 100644 (file)
index 0000000..5bca6d7
--- /dev/null
@@ -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_ */
index 6147245..a12d691 100644 (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
index 8158e7d..6147245 100644 (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.
index d20c607..55f9696 100644 (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
 
index 79985e7..5954aee 100644 (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
index f1dd8bf..78505b3 100644 (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
index cea6a58..f1dd8bf 100644 (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
index 4824175..dde5618 100644 (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);
 
index 64b940e..ce81b35 100644 (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
     {
diff --git a/findcmd.c~ b/findcmd.c~
new file mode 100644 (file)
index 0000000..4688e55
--- /dev/null
@@ -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);
+}
diff --git a/jobs.c b/jobs.c
index 6e35141..f8a5c81 100644 (file)
--- a/jobs.c
+++ b/jobs.c
@@ -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
@@ -1738,6 +1950,13 @@ wait_for_single_pid (pid)
 
   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);
       return (127);
     }
@@ -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
diff --git a/jobs.c~ b/jobs.c~
index 702c021..faa264a 100644 (file)
--- a/jobs.c~
+++ b/jobs.c~
@@ -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
@@ -1739,6 +1951,13 @@ wait_for_single_pid (pid)
 
   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);
       return (127);
     }
@@ -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);
        }
     }
 
diff --git a/jobs.h b/jobs.h
index ca22dba..ee1bd38 100644 (file)
--- a/jobs.h
+++ b/jobs.h
@@ -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.
 
 #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));
diff --git a/jobs.h~ b/jobs.h~
index e79e6f8..b5d8dd0 100644 (file)
--- a/jobs.h~
+++ b/jobs.h~
@@ -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));
index 41fbb48..4d6f2a1 100644 (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
diff --git a/lib/doc-support/Makefile.in~ b/lib/doc-support/Makefile.in~
new file mode 100644 (file)
index 0000000..41fbb48
--- /dev/null
@@ -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
index cddfd3f..9bb4dd3 100644 (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
diff --git a/lib/glob/Makefile.in~ b/lib/glob/Makefile.in~
new file mode 100644 (file)
index 0000000..cddfd3f
--- /dev/null
@@ -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
index d013dc7..21681aa 100644 (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
diff --git a/lib/malloc/Makefile.in~ b/lib/malloc/Makefile.in~
new file mode 100644 (file)
index 0000000..d013dc7
--- /dev/null
@@ -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
index a118304..98169e4 100644 (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
diff --git a/lib/readline/Makefile.in~ b/lib/readline/Makefile.in~
new file mode 100644 (file)
index 0000000..a118304
--- /dev/null
@@ -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
index d5ba94e..86a0174 100644 (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.
index 4e6c74b..d5ba94e 100644 (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;
index 161c977..3da5748 100644 (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.
diff --git a/lib/readline/history.c~ b/lib/readline/history.c~
new file mode 100644 (file)
index 0000000..161c977
--- /dev/null
@@ -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;
+}
index 73e0b34..17dde53 100644 (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.
index 933eecc..73e0b34 100644 (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
index 70eebbf..c3a352a 100644 (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.
index b4e5d50..70eebbf 100644 (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)
            {
index 17596b8..fe29c35 100644 (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
index c375c1d..17596b8 100644 (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
index 89838cc..ae7c249 100644 (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.
 
index d05aef5..89838cc 100644 (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. */
index 2f17bce..bf5639f 100644 (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
diff --git a/lib/termcap/Makefile.in~ b/lib/termcap/Makefile.in~
new file mode 100644 (file)
index 0000000..2f17bce
--- /dev/null
@@ -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
index aa7bbf0..a9d3741 100644 (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
diff --git a/lib/tilde/Makefile.in~ b/lib/tilde/Makefile.in~
new file mode 100644 (file)
index 0000000..aa7bbf0
--- /dev/null
@@ -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
index 0f2f986..5e73a28 100644 (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.
 
diff --git a/make_cmd.c~ b/make_cmd.c~
new file mode 100644 (file)
index 0000000..0f2f986
--- /dev/null
@@ -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;
+}
index f1253af..fe5dc15 100644 (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.
 
diff --git a/make_cmd.h~ b/make_cmd.h~
new file mode 100644 (file)
index 0000000..f1253af
--- /dev/null
@@ -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 */
diff --git a/parse.y b/parse.y
index 0817724..b61fb1e 100644 (file)
--- a/parse.y
+++ b/parse.y
@@ -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.
 
index b36a9e5..0817724 100644 (file)
--- a/parse.y~
+++ b/parse.y~
@@ -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);
index f94f5d9..2956b8f 100644 (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.
 
index f49faae..f94f5d9 100644 (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);
index 098daa1..2533d21 100644 (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.
 
diff --git a/print_cmd.c~ b/print_cmd.c~
new file mode 100644 (file)
index 0000000..098daa1
--- /dev/null
@@ -0,0 +1,1307 @@
+/* print_command -- A way to make readable commands from a command tree. */
+
+/* Copyright (C) 1989-2004 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>
+
+#if defined (HAVE_UNISTD_H)
+#  ifdef _MINIX
+#    include <sys/types.h>
+#  endif
+#  include <unistd.h>
+#endif
+
+#if defined (PREFER_STDARG)
+#  include <stdarg.h>
+#else
+#  include <varargs.h>
+#endif
+
+#include "bashansi.h"
+#include "bashintl.h"
+
+#include "shell.h"
+#include "flags.h"
+#include <y.tab.h>     /* use <...> so we pick it up from the build directory */
+
+#include "shmbutil.h"
+
+#include "builtins/common.h"
+
+#if !HAVE_DECL_PRINTF
+extern int printf __P((const char *, ...));    /* Yuck.  Double yuck. */
+#endif
+
+extern int indirection_level;
+
+static int indentation;
+static int indentation_amount = 4;
+
+#if defined (PREFER_STDARG)
+typedef void PFUNC __P((const char *, ...));
+
+static void cprintf __P((const char *, ...))  __attribute__((__format__ (printf, 1, 2)));
+static void xprintf __P((const char *, ...))  __attribute__((__format__ (printf, 1, 2)));
+#else
+#define PFUNC VFunction
+static void cprintf ();
+static void xprintf ();
+#endif
+
+static void reset_locals __P((void));
+static void newline __P((char *));
+static void indent __P((int));
+static void semicolon __P((void));
+static void the_printed_command_resize __P((int));
+
+static void make_command_string_internal __P((COMMAND *));
+static void _print_word_list __P((WORD_LIST *, char *, PFUNC *));
+static void command_print_word_list __P((WORD_LIST *, char *));
+static void print_case_clauses __P((PATTERN_LIST *));
+static void print_redirection_list __P((REDIRECT *));
+static void print_redirection __P((REDIRECT *));
+
+static void print_for_command __P((FOR_COM *));
+#if defined (ARITH_FOR_COMMAND)
+static void print_arith_for_command __P((ARITH_FOR_COM *));
+#endif
+#if defined (SELECT_COMMAND)
+static void print_select_command __P((SELECT_COM *));
+#endif
+static void print_group_command __P((GROUP_COM *));
+static void print_case_command __P((CASE_COM *));
+static void print_while_command __P((WHILE_COM *));
+static void print_until_command __P((WHILE_COM *));
+static void print_until_or_while __P((WHILE_COM *, char *));
+static void print_if_command __P((IF_COM *));
+#if defined (COND_COMMAND)
+static void print_cond_node __P((COND_COM *));
+#endif
+static void print_function_def __P((FUNCTION_DEF *));
+
+#define PRINTED_COMMAND_INITIAL_SIZE 64
+#define PRINTED_COMMAND_GROW_SIZE 128
+
+char *the_printed_command = (char *)NULL;
+int the_printed_command_size = 0;
+int command_string_index = 0;
+
+/* Non-zero means the stuff being printed is inside of a function def. */
+static int inside_function_def;
+static int skip_this_indent;
+static int was_heredoc;
+
+/* The depth of the group commands that we are currently printing.  This
+   includes the group command that is a function body. */
+static int group_command_nesting;
+
+/* A buffer to indicate the indirection level (PS4) when set -x is enabled. */
+static char indirection_string[100];
+
+/* Print COMMAND (a command tree) on standard output. */
+void
+print_command (command)
+     COMMAND *command;
+{
+  command_string_index = 0;
+  printf ("%s", make_command_string (command));
+}
+
+/* Make a string which is the printed representation of the command
+   tree in COMMAND.  We return this string.  However, the string is
+   not consed, so you have to do that yourself if you want it to
+   remain around. */
+char *
+make_command_string (command)
+     COMMAND *command;
+{
+  command_string_index = was_heredoc = 0;
+  make_command_string_internal (command);
+  return (the_printed_command);
+}
+
+/* The internal function.  This is the real workhorse. */
+static void
+make_command_string_internal (command)
+     COMMAND *command;
+{
+  if (command == 0)
+    cprintf ("");
+  else
+    {
+      if (skip_this_indent)
+       skip_this_indent--;
+      else
+       indent (indentation);
+
+      if (command->flags & CMD_TIME_PIPELINE)
+       {
+         cprintf ("time ");
+         if (command->flags & CMD_TIME_POSIX)
+           cprintf ("-p ");
+       }
+
+      if (command->flags & CMD_INVERT_RETURN)
+       cprintf ("! ");
+
+      switch (command->type)
+       {
+       case cm_for:
+         print_for_command (command->value.For);
+         break;
+
+#if defined (ARITH_FOR_COMMAND)
+       case cm_arith_for:
+         print_arith_for_command (command->value.ArithFor);
+         break;
+#endif
+
+#if defined (SELECT_COMMAND)
+       case cm_select:
+         print_select_command (command->value.Select);
+         break;
+#endif
+
+       case cm_case:
+         print_case_command (command->value.Case);
+         break;
+
+       case cm_while:
+         print_while_command (command->value.While);
+         break;
+
+       case cm_until:
+         print_until_command (command->value.While);
+         break;
+
+       case cm_if:
+         print_if_command (command->value.If);
+         break;
+
+#if defined (DPAREN_ARITHMETIC)
+       case cm_arith:
+         print_arith_command (command->value.Arith->exp);
+         break;
+#endif
+
+#if defined (COND_COMMAND)
+       case cm_cond:
+         print_cond_command (command->value.Cond);
+         break;
+#endif
+
+       case cm_simple:
+         print_simple_command (command->value.Simple);
+         break;
+
+       case cm_connection:
+
+         skip_this_indent++;
+         make_command_string_internal (command->value.Connection->first);
+
+         switch (command->value.Connection->connector)
+           {
+           case '&':
+           case '|':
+             {
+               char c = command->value.Connection->connector;
+               cprintf (" %c", c);
+               if (c != '&' || command->value.Connection->second)
+                 {
+                   cprintf (" ");
+                   skip_this_indent++;
+                 }
+             }
+             break;
+
+           case AND_AND:
+             cprintf (" && ");
+             if (command->value.Connection->second)
+               skip_this_indent++;
+             break;
+
+           case OR_OR:
+             cprintf (" || ");
+             if (command->value.Connection->second)
+               skip_this_indent++;
+             break;
+
+           case ';':
+             if (was_heredoc == 0)
+               cprintf (";");
+             else
+               was_heredoc = 0;
+
+             if (inside_function_def)
+               cprintf ("\n");
+             else
+               {
+                 cprintf (" ");
+                 if (command->value.Connection->second)
+                   skip_this_indent++;
+               }
+             break;
+
+           default:
+             cprintf (_("print_command: bad connector `%d'"),
+                      command->value.Connection->connector);
+             break;
+           }
+
+         make_command_string_internal (command->value.Connection->second);
+         break;
+
+       case cm_function_def:
+         print_function_def (command->value.Function_def);
+         break;
+
+       case cm_group:
+         print_group_command (command->value.Group);
+         break;
+
+       case cm_subshell:
+         cprintf ("( ");
+         skip_this_indent++;
+         make_command_string_internal (command->value.Subshell->command);
+         cprintf (" )");
+         break;
+
+       default:
+         command_error ("print_command", CMDERR_BADTYPE, command->type, 0);
+         break;
+       }
+
+
+      if (command->redirects)
+       {
+         cprintf (" ");
+         print_redirection_list (command->redirects);
+       }
+    }
+}
+
+static void
+_print_word_list (list, separator, pfunc)
+     WORD_LIST *list;
+     char *separator;
+     PFUNC *pfunc;
+{
+  WORD_LIST *w;
+
+  for (w = list; w; w = w->next)
+    (*pfunc) ("%s%s", w->word->word, w->next ? separator : "");
+}
+
+void
+print_word_list (list, separator)
+     WORD_LIST *list;
+     char *separator;
+{
+  _print_word_list (list, separator, xprintf);
+}
+
+/* Return a string denoting what our indirection level is. */
+
+char *
+indirection_level_string ()
+{
+  register int i, j;
+  char *ps4;
+  char ps4_firstc[MB_LEN_MAX+1];
+  int ps4_firstc_len, ps4_len;
+
+  indirection_string[0] = '\0';
+  ps4 = get_string_value ("PS4");
+
+  if (ps4 == 0 || *ps4 == '\0')
+    return (indirection_string);
+
+  change_flag ('x', FLAG_OFF);
+  ps4 = decode_prompt_string (ps4);
+  change_flag ('x', FLAG_ON);
+
+  if (ps4 == 0 || *ps4 == '\0')
+    return (indirection_string);
+
+#if defined (HANDLE_MULTIBYTE)
+  ps4_len = strnlen (ps4, MB_CUR_MAX);
+  ps4_firstc_len = MBLEN (ps4, ps4_len);
+  if (ps4_firstc_len == 1 || ps4_firstc_len == 0 || MB_INVALIDCH (ps4_firstc_len))
+    {
+      ps4_firstc[0] = ps4[0];
+      ps4_firstc[ps4_firstc_len = 1] = '\0';
+    }
+  else
+    memcpy (ps4_firstc, ps4, ps4_firstc_len);
+#else
+  ps4_firstc[0] = ps4[0];
+  ps4_firstc[ps4_firstc_len = 1] = '\0';
+#endif
+      
+  for (i = j = 0; ps4_firstc[0] && j < indirection_level && i < 99; i += ps4_firstc_len, j++)
+    {
+      if (ps4_firstc_len == 1)
+       indirection_string[i] = ps4_firstc[0];
+      else
+       memcpy (indirection_string+i, ps4_firstc, ps4_firstc_len);
+    }      
+
+  for (j = ps4_firstc_len; *ps4 && ps4[j] && i < 99; i++, j++)
+    indirection_string[i] = ps4[j];
+
+  indirection_string[i] = '\0';
+  free (ps4);
+  return (indirection_string);
+}
+
+void
+xtrace_print_assignment (name, value, assign_list, xflags)
+     char *name, *value;
+     int assign_list, xflags;
+{
+  char *nval;
+
+  if (xflags)
+    fprintf (stderr, "%s", indirection_level_string ());
+
+  /* VALUE should not be NULL when this is called. */
+  if (*value == '\0' || assign_list)
+    nval = value;
+  else if (sh_contains_shell_metas (value))
+    nval = sh_single_quote (value);
+  else if (ansic_shouldquote (value))
+    nval = ansic_quote (value, 0, (int *)0);
+  else
+    nval = value;
+
+  if (assign_list)
+    fprintf (stderr, "%s=(%s)\n", name, nval);
+  else
+    fprintf (stderr, "%s=%s\n", name, nval);
+
+  if (nval != value)
+    FREE (nval);
+
+  fflush (stderr);
+}
+
+/* A function to print the words of a simple command when set -x is on. */
+void
+xtrace_print_word_list (list, xtflags)
+     WORD_LIST *list;
+     int xtflags;
+{
+  WORD_LIST *w;
+  char *t, *x;
+
+  if (xtflags)
+    fprintf (stderr, "%s", indirection_level_string ());
+
+  for (w = list; w; w = w->next)
+    {
+      t = w->word->word;
+      if (t == 0 || *t == '\0')
+       fprintf (stderr, "''%s", w->next ? " " : "");
+      else if (sh_contains_shell_metas (t))
+       {
+         x = sh_single_quote (t);
+         fprintf (stderr, "%s%s", x, w->next ? " " : "");
+         free (x);
+       }
+      else if (ansic_shouldquote (t))
+       {
+         x = ansic_quote (t, 0, (int *)0);
+         fprintf (stderr, "%s%s", x, w->next ? " " : "");
+         free (x);
+       }
+      else
+       fprintf (stderr, "%s%s", t, w->next ? " " : "");
+    }
+  fprintf (stderr, "\n");
+}
+
+static void
+command_print_word_list (list, separator)
+     WORD_LIST *list;
+     char *separator;
+{
+  _print_word_list (list, separator, cprintf);
+}
+
+void
+print_for_command_head (for_command)
+     FOR_COM *for_command;
+{
+  cprintf ("for %s in ", for_command->name->word);
+  command_print_word_list (for_command->map_list, " ");
+}
+
+void
+xtrace_print_for_command_head (for_command)
+     FOR_COM *for_command;
+{
+  fprintf (stderr, "%s", indirection_level_string ());
+  fprintf (stderr, "for %s in ", for_command->name->word);
+  xtrace_print_word_list (for_command->map_list, 0);
+}
+
+static void
+print_for_command (for_command)
+     FOR_COM *for_command;
+{
+  print_for_command_head (for_command);
+
+  cprintf (";");
+  newline ("do\n");
+  indentation += indentation_amount;
+  make_command_string_internal (for_command->action);
+  semicolon ();
+  indentation -= indentation_amount;
+  newline ("done");
+}
+
+#if defined (ARITH_FOR_COMMAND)
+static void
+print_arith_for_command (arith_for_command)
+     ARITH_FOR_COM *arith_for_command;
+{
+  cprintf ("for ((");
+  command_print_word_list (arith_for_command->init, " ");
+  cprintf (" ; ");
+  command_print_word_list (arith_for_command->test, " ");
+  cprintf (" ; ");
+  command_print_word_list (arith_for_command->step, " ");
+  cprintf ("))");
+  newline ("do\n");
+  indentation += indentation_amount;
+  make_command_string_internal (arith_for_command->action);
+  semicolon ();
+  indentation -= indentation_amount;
+  newline ("done");
+}
+#endif /* ARITH_FOR_COMMAND */
+
+#if defined (SELECT_COMMAND)
+void
+print_select_command_head (select_command)
+     SELECT_COM *select_command;
+{
+  cprintf ("select %s in ", select_command->name->word);
+  command_print_word_list (select_command->map_list, " ");
+}
+
+void
+xtrace_print_select_command_head (select_command)
+     SELECT_COM *select_command;
+{
+  fprintf (stderr, "%s", indirection_level_string ());
+  fprintf (stderr, "select %s in ", select_command->name->word);
+  xtrace_print_word_list (select_command->map_list, 0);
+}
+
+static void
+print_select_command (select_command)
+     SELECT_COM *select_command;
+{
+  print_select_command_head (select_command);
+
+  cprintf (";");
+  newline ("do\n");
+  indentation += indentation_amount;
+  make_command_string_internal (select_command->action);
+  semicolon ();
+  indentation -= indentation_amount;
+  newline ("done");
+}
+#endif /* SELECT_COMMAND */
+
+static void
+print_group_command (group_command)
+     GROUP_COM *group_command;
+{
+  group_command_nesting++;
+  cprintf ("{ ");
+
+  if (inside_function_def == 0)
+    skip_this_indent++;
+  else
+    {
+      /* This is a group command { ... } inside of a function
+        definition, and should be printed as a multiline group
+        command, using the current indentation. */
+      cprintf ("\n");
+      indentation += indentation_amount;
+    }
+
+  make_command_string_internal (group_command->command);
+
+  if (inside_function_def)
+    {
+      cprintf ("\n");
+      indentation -= indentation_amount;
+      indent (indentation);
+    }
+  else
+    {
+      semicolon ();
+      cprintf (" ");
+    }
+
+  cprintf ("}");
+
+  group_command_nesting--;
+}
+
+void
+print_case_command_head (case_command)
+     CASE_COM *case_command;
+{
+  cprintf ("case %s in ", case_command->word->word);
+}
+
+void
+xtrace_print_case_command_head (case_command)
+     CASE_COM *case_command;
+{
+  fprintf (stderr, "%s", indirection_level_string ());
+  fprintf (stderr, "case %s in\n", case_command->word->word);
+}
+
+static void
+print_case_command (case_command)
+     CASE_COM *case_command;
+{
+  print_case_command_head (case_command);
+
+  if (case_command->clauses)
+    print_case_clauses (case_command->clauses);
+  newline ("esac");
+}
+
+static void
+print_case_clauses (clauses)
+     PATTERN_LIST *clauses;
+{
+  indentation += indentation_amount;
+  while (clauses)
+    {
+      newline ("");
+      command_print_word_list (clauses->patterns, " | ");
+      cprintf (")\n");
+      indentation += indentation_amount;
+      make_command_string_internal (clauses->action);
+      indentation -= indentation_amount;
+      newline (";;");
+      clauses = clauses->next;
+    }
+  indentation -= indentation_amount;
+}
+
+static void
+print_while_command (while_command)
+     WHILE_COM *while_command;
+{
+  print_until_or_while (while_command, "while");
+}
+
+static void
+print_until_command (while_command)
+     WHILE_COM *while_command;
+{
+  print_until_or_while (while_command, "until");
+}
+
+static void
+print_until_or_while (while_command, which)
+     WHILE_COM *while_command;
+     char *which;
+{
+  cprintf ("%s ", which);
+  skip_this_indent++;
+  make_command_string_internal (while_command->test);
+  semicolon ();
+  cprintf (" do\n");   /* was newline ("do\n"); */
+  indentation += indentation_amount;
+  make_command_string_internal (while_command->action);
+  indentation -= indentation_amount;
+  semicolon ();
+  newline ("done");
+}
+
+static void
+print_if_command (if_command)
+     IF_COM *if_command;
+{
+  cprintf ("if ");
+  skip_this_indent++;
+  make_command_string_internal (if_command->test);
+  semicolon ();
+  cprintf (" then\n");
+  indentation += indentation_amount;
+  make_command_string_internal (if_command->true_case);
+  indentation -= indentation_amount;
+
+  if (if_command->false_case)
+    {
+      semicolon ();
+      newline ("else\n");
+      indentation += indentation_amount;
+      make_command_string_internal (if_command->false_case);
+      indentation -= indentation_amount;
+    }
+  semicolon ();
+  newline ("fi");
+}
+
+#if defined (DPAREN_ARITHMETIC)
+void
+print_arith_command (arith_cmd_list)
+     WORD_LIST *arith_cmd_list;
+{
+  cprintf ("((");
+  command_print_word_list (arith_cmd_list, " ");
+  cprintf ("))");
+}
+#endif
+
+#if defined (COND_COMMAND)
+static void
+print_cond_node (cond)
+     COND_COM *cond;
+{
+  if (cond->flags & CMD_INVERT_RETURN)
+    cprintf ("! ");
+
+  if (cond->type == COND_EXPR)
+    {
+      cprintf ("( ");
+      print_cond_node (cond->left);
+      cprintf (" )");
+    }
+  else if (cond->type == COND_AND)
+    {
+      print_cond_node (cond->left);
+      cprintf (" && ");
+      print_cond_node (cond->right);
+    }
+  else if (cond->type == COND_OR)
+    {
+      print_cond_node (cond->left);
+      cprintf (" || ");
+      print_cond_node (cond->right);
+    }
+  else if (cond->type == COND_UNARY)
+    {
+      cprintf ("%s", cond->op->word);
+      cprintf (" ");
+      print_cond_node (cond->left);
+    }
+  else if (cond->type == COND_BINARY)
+    {
+      print_cond_node (cond->left);
+      cprintf (" ");
+      cprintf ("%s", cond->op->word);
+      cprintf (" ");
+      print_cond_node (cond->right);
+    }
+  else if (cond->type == COND_TERM)
+    {
+      cprintf ("%s", cond->op->word);          /* need to add quoting here */
+    }
+}
+
+void
+print_cond_command (cond)
+     COND_COM *cond;
+{
+  cprintf ("[[ ");
+  print_cond_node (cond);
+  cprintf (" ]]");
+}
+
+#ifdef DEBUG
+void
+debug_print_cond_command (cond)
+     COND_COM *cond;
+{
+  fprintf (stderr, "DEBUG: ");
+  command_string_index = 0;
+  print_cond_command (cond);
+  fprintf (stderr, "%s\n", the_printed_command);
+}
+#endif
+
+void
+xtrace_print_cond_term (type, invert, op, arg1, arg2)
+     int type, invert;
+     WORD_DESC *op;
+     char *arg1, *arg2;
+{
+  command_string_index = 0;
+  fprintf (stderr, "%s", indirection_level_string ());
+  fprintf (stderr, "[[ ");
+  if (invert)
+    fprintf (stderr, "! ");
+
+  if (type == COND_UNARY)
+    {
+      fprintf (stderr, "%s ", op->word);
+      fprintf (stderr, "%s", (arg1 && *arg1) ? arg1 : "''");
+    }
+  else if (type == COND_BINARY)
+    {
+      fprintf (stderr, "%s", (arg1 && *arg1) ? arg1 : "''");
+      fprintf (stderr, " %s ", op->word);
+      fprintf (stderr, "%s", (arg2 && *arg2) ? arg2 : "''");
+    }
+
+  fprintf (stderr, " ]]\n");
+}        
+#endif /* COND_COMMAND */
+
+#if defined (DPAREN_ARITHMETIC) || defined (ARITH_FOR_COMMAND)
+/* A function to print the words of an arithmetic command when set -x is on. */
+void
+xtrace_print_arith_cmd (list)
+     WORD_LIST *list;
+{
+  WORD_LIST *w;
+
+  fprintf (stderr, "%s", indirection_level_string ());
+  fprintf (stderr, "(( ");
+  for (w = list; w; w = w->next)
+    fprintf (stderr, "%s%s", w->word->word, w->next ? " " : "");
+  fprintf (stderr, " ))\n");
+}
+#endif
+
+void
+print_simple_command (simple_command)
+     SIMPLE_COM *simple_command;
+{
+  command_print_word_list (simple_command->words, " ");
+
+  if (simple_command->redirects)
+    {
+      cprintf (" ");
+      print_redirection_list (simple_command->redirects);
+    }
+}
+
+static void
+print_redirection_list (redirects)
+     REDIRECT *redirects;
+{
+  REDIRECT *heredocs, *hdtail, *newredir;
+
+  heredocs = (REDIRECT *)NULL;
+  hdtail = heredocs;
+
+  was_heredoc = 0;
+  while (redirects)
+    {
+      /* Defer printing the here documents until we've printed the
+        rest of the redirections. */
+      if (redirects->instruction == r_reading_until || redirects->instruction == r_deblank_reading_until)
+       {
+         newredir = copy_redirect (redirects);
+         newredir->next = (REDIRECT *)NULL;
+         if (heredocs)
+           {
+             hdtail->next = newredir;
+             hdtail = newredir;
+           }
+         else
+           hdtail = heredocs = newredir;
+       }
+      else if (redirects->instruction == r_duplicating_output_word && redirects->redirector == 1)
+       {
+         /* Temporarily translate it as the execution code does. */
+         redirects->instruction = r_err_and_out;
+         print_redirection (redirects);
+         redirects->instruction = r_duplicating_output_word;
+       }
+      else
+       print_redirection (redirects);
+
+      redirects = redirects->next;
+      if (redirects)
+       cprintf (" ");
+    }
+
+  /* Now that we've printed all the other redirections (on one line),
+     print the here documents. */
+  if (heredocs)
+    {
+      cprintf (" "); 
+      for (hdtail = heredocs; hdtail; hdtail = hdtail->next)
+       {
+         print_redirection (hdtail);
+         cprintf ("\n");
+       }
+      dispose_redirects (heredocs);
+      was_heredoc = 1;
+    }
+}
+
+static void
+print_redirection (redirect)
+     REDIRECT *redirect;
+{
+  int kill_leading, redirector, redir_fd;
+  WORD_DESC *redirectee;
+
+  kill_leading = 0;
+  redirectee = redirect->redirectee.filename;
+  redirector = redirect->redirector;
+  redir_fd = redirect->redirectee.dest;
+
+  switch (redirect->instruction)
+    {
+    case r_output_direction:
+      if (redirector != 1)
+       cprintf ("%d", redirector);
+      cprintf (">%s", redirectee->word);
+      break;
+
+    case r_input_direction:
+      if (redirector != 0)
+       cprintf ("%d", redirector);
+      cprintf ("<%s", redirectee->word);
+      break;
+
+    case r_inputa_direction:   /* Redirection created by the shell. */
+      cprintf ("&");
+      break;
+
+    case r_appending_to:
+      if (redirector != 1)
+       cprintf ("%d", redirector);
+      cprintf (">>%s", redirectee->word);
+      break;
+
+    case r_deblank_reading_until:
+      kill_leading++;
+      /* ... */
+    case r_reading_until:
+      if (redirector != 0)
+       cprintf ("%d", redirector);
+      /* If the here document delimiter is quoted, single-quote it. */
+      if (redirect->redirectee.filename->flags & W_QUOTED)
+       {
+         char *x;
+         x = sh_single_quote (redirect->here_doc_eof);
+         cprintf ("<<%s%s\n", kill_leading? "-" : "", x);
+         free (x);
+       }
+      else
+       cprintf ("<<%s%s\n", kill_leading? "-" : "", redirect->here_doc_eof);
+      cprintf ("%s%s",
+              redirect->redirectee.filename->word, redirect->here_doc_eof);
+      break;
+
+    case r_reading_string:
+      if (redirector != 0)
+       cprintf ("%d", redirector);
+      if (ansic_shouldquote (redirect->redirectee.filename->word))
+       {
+         char *x;
+         x = ansic_quote (redirect->redirectee.filename->word, 0, (int *)0);
+         cprintf ("<<< %s", x);
+         free (x);
+       }
+      else
+       cprintf ("<<< %s", redirect->redirectee.filename->word);
+      break;
+
+    case r_duplicating_input:
+      cprintf ("%d<&%d", redirector, redir_fd);
+      break;
+
+    case r_duplicating_output:
+      cprintf ("%d>&%d", redirector, redir_fd);
+      break;
+
+    case r_duplicating_input_word:
+      cprintf ("%d<&%s", redirector, redirectee->word);
+      break;
+
+    case r_duplicating_output_word:
+      cprintf ("%d>&%s", redirector, redirectee->word);
+      break;
+
+    case r_move_input:
+      cprintf ("%d<&%d-", redirector, redir_fd);
+      break;
+
+    case r_move_output:
+      cprintf ("%d>&%d-", redirector, redir_fd);
+      break;
+
+    case r_move_input_word:
+      cprintf ("%d<&%s-", redirector, redirectee->word);
+      break;
+
+    case r_move_output_word:
+      cprintf ("%d>&%s-", redirector, redirectee->word);
+      break;
+
+    case r_close_this:
+      cprintf ("%d>&-", redirector);
+      break;
+
+    case r_err_and_out:
+      cprintf (">&%s", redirectee->word);
+      break;
+
+    case r_input_output:
+      if (redirector != 1)
+       cprintf ("%d", redirector);
+      cprintf ("<>%s", redirectee->word);
+      break;
+
+    case r_output_force:
+      if (redirector != 1)
+       cprintf ("%d", redirector);
+      cprintf (">|%s", redirectee->word);
+      break;
+    }
+}
+
+static void
+reset_locals ()
+{
+  inside_function_def = 0;
+  indentation = 0;
+}
+
+static void
+print_function_def (func)
+     FUNCTION_DEF *func;
+{
+  COMMAND *cmdcopy;
+  REDIRECT *func_redirects;
+
+  func_redirects = NULL;
+  cprintf ("function %s () \n", func->name->word);
+  add_unwind_protect (reset_locals, 0);
+
+  indent (indentation);
+  cprintf ("{ \n");
+
+  inside_function_def++;
+  indentation += indentation_amount;
+
+  cmdcopy = copy_command (func->command);
+  if (cmdcopy->type == cm_group)
+    {
+      func_redirects = cmdcopy->redirects;
+      cmdcopy->redirects = (REDIRECT *)NULL;
+    }
+  make_command_string_internal (cmdcopy->type == cm_group
+                                       ? cmdcopy->value.Group->command
+                                       : cmdcopy);
+
+  remove_unwind_protect ();
+  indentation -= indentation_amount;
+  inside_function_def--;
+
+  if (func_redirects)
+    { /* { */
+      newline ("} ");
+      print_redirection_list (func_redirects);
+      cmdcopy->redirects = func_redirects;
+    }
+  else
+    newline ("}");
+
+  dispose_command (cmdcopy);
+}
+
+/* Return the string representation of the named function.
+   NAME is the name of the function.
+   COMMAND is the function body.  It should be a GROUP_COM.
+   MULTI_LINE is non-zero to pretty-print, or zero for all on one line.
+  */
+char *
+named_function_string (name, command, multi_line)
+     char *name;
+     COMMAND *command;
+     int multi_line;
+{
+  char *result;
+  int old_indent, old_amount;
+  COMMAND *cmdcopy;
+  REDIRECT *func_redirects;
+
+  old_indent = indentation;
+  old_amount = indentation_amount;
+  command_string_index = was_heredoc = 0;
+
+  if (name && *name)
+    cprintf ("%s ", name);
+
+  cprintf ("() ");
+
+  if (multi_line == 0)
+    {
+      indentation = 1;
+      indentation_amount = 0;
+    }
+  else
+    {
+      cprintf ("\n");
+      indentation += indentation_amount;
+    }
+
+  inside_function_def++;
+
+  cprintf (multi_line ? "{ \n" : "{ ");
+
+  cmdcopy = copy_command (command);
+  /* Take any redirections specified in the function definition (which should
+     apply to the function as a whole) and save them for printing later. */
+  func_redirects = (REDIRECT *)NULL;
+  if (cmdcopy->type == cm_group)
+    {
+      func_redirects = cmdcopy->redirects;
+      cmdcopy->redirects = (REDIRECT *)NULL;
+    }
+  make_command_string_internal (cmdcopy->type == cm_group
+                                       ? cmdcopy->value.Group->command
+                                       : cmdcopy);
+
+  indentation = old_indent;
+  indentation_amount = old_amount;
+  inside_function_def--;
+
+  if (func_redirects)
+    { /* { */
+      newline ("} ");
+      print_redirection_list (func_redirects);
+      cmdcopy->redirects = func_redirects;
+    }
+  else
+    newline ("}");
+
+  result = the_printed_command;
+
+  if (!multi_line)
+    {
+#if 0
+      register int i;
+      for (i = 0; result[i]; i++)
+       if (result[i] == '\n')
+         {
+           strcpy (result + i, result + i + 1);
+           --i;
+         }
+#else
+      if (result[2] == '\n')   /* XXX -- experimental */
+       strcpy (result + 2, result + 3);
+#endif
+    }
+
+  dispose_command (cmdcopy);
+
+  return (result);
+}
+
+static void
+newline (string)
+     char *string;
+{
+  cprintf ("\n");
+  indent (indentation);
+  if (string && *string)
+    cprintf ("%s", string);
+}
+
+static char *indentation_string;
+static int indentation_size;
+
+static void
+indent (amount)
+     int amount;
+{
+  register int i;
+
+  RESIZE_MALLOCED_BUFFER (indentation_string, 0, amount, indentation_size, 16);
+
+  for (i = 0; amount > 0; amount--)
+    indentation_string[i++] = ' ';
+  indentation_string[i] = '\0';
+  cprintf (indentation_string);
+}
+
+static void
+semicolon ()
+{
+  if (command_string_index > 0 &&
+       (the_printed_command[command_string_index - 1] == '&' ||
+        the_printed_command[command_string_index - 1] == '\n'))
+    return;
+  cprintf (";");
+}
+
+/* How to make the string. */
+static void
+#if defined (PREFER_STDARG)
+cprintf (const char *control, ...)
+#else
+cprintf (control, va_alist)
+     const char *control;
+     va_dcl
+#endif
+{
+  register const char *s;
+  char char_arg[2], *argp, intbuf[INT_STRLEN_BOUND (int) + 1];
+  int digit_arg, arg_len, c;
+  va_list args;
+
+  SH_VA_START (args, control);
+
+  arg_len = strlen (control);
+  the_printed_command_resize (arg_len + 1);
+
+  char_arg[1] = '\0';
+  s = control;
+  while (s && *s)
+    {
+      c = *s++;
+      argp = (char *)NULL;
+      if (c != '%' || !*s)
+       {
+         char_arg[0] = c;
+         argp = char_arg;
+         arg_len = 1;
+       }
+      else
+       {
+         c = *s++;
+         switch (c)
+           {
+           case '%':
+             char_arg[0] = c;
+             argp = char_arg;
+             arg_len = 1;
+             break;
+
+           case 's':
+             argp = va_arg (args, char *);
+             arg_len = strlen (argp);
+             break;
+
+           case 'd':
+             /* Represent an out-of-range file descriptor with an out-of-range
+                integer value.  We can do this because the only use of `%d' in
+                the calls to cprintf is to output a file descriptor number for
+                a redirection. */
+             digit_arg = va_arg (args, int);
+             if (digit_arg < 0)
+               {
+                 sprintf (intbuf, "%u", (unsigned)-1);
+                 argp = intbuf;
+               }
+             else
+               argp = inttostr (digit_arg, intbuf, sizeof (intbuf));
+             arg_len = strlen (argp);
+             break;
+
+           case 'c':
+             char_arg[0] = va_arg (args, int);
+             argp = char_arg;
+             arg_len = 1;
+             break;
+
+           default:
+             programming_error (_("cprintf: `%c': invalid format character"), c);
+             /*NOTREACHED*/
+           }
+       }
+
+      if (argp && arg_len)
+       {
+         the_printed_command_resize (arg_len + 1);
+         FASTCOPY (argp, the_printed_command + command_string_index, arg_len);
+         command_string_index += arg_len;
+       }
+    }
+
+  the_printed_command[command_string_index] = '\0';
+}
+
+/* Ensure that there is enough space to stuff LENGTH characters into
+   THE_PRINTED_COMMAND. */
+static void
+the_printed_command_resize (length)
+     int length;
+{
+  if (the_printed_command == 0)
+    {
+      the_printed_command_size = (length + PRINTED_COMMAND_INITIAL_SIZE - 1) & ~(PRINTED_COMMAND_INITIAL_SIZE - 1);
+      the_printed_command = (char *)xmalloc (the_printed_command_size);
+      command_string_index = 0;
+    }
+  else if ((command_string_index + length) >= the_printed_command_size)
+    {
+      int new;
+      new = command_string_index + length + 1;
+
+      /* Round up to the next multiple of PRINTED_COMMAND_GROW_SIZE. */
+      new = (new + PRINTED_COMMAND_GROW_SIZE - 1) & ~(PRINTED_COMMAND_GROW_SIZE - 1);
+      the_printed_command_size = new;
+
+      the_printed_command = (char *)xrealloc (the_printed_command, the_printed_command_size);
+    }
+}
+
+#if defined (HAVE_VPRINTF)
+/* ``If vprintf is available, you may assume that vfprintf and vsprintf are
+     also available.'' */
+
+static void
+#if defined (PREFER_STDARG)
+xprintf (const char *format, ...)
+#else
+xprintf (format, va_alist)
+     const char *format;
+     va_dcl
+#endif
+{
+  va_list args;
+
+  SH_VA_START (args, format);
+
+  vfprintf (stdout, format, args);
+  va_end (args);
+}
+
+#else
+
+static void
+xprintf (format, arg1, arg2, arg3, arg4, arg5)
+     const char *format;
+{
+  printf (format, arg1, arg2, arg3, arg4, arg5);
+}
+
+#endif /* !HAVE_VPRINTF */
diff --git a/subst.c b/subst.c
index ee4c925..e27b4eb 100644 (file)
--- a/subst.c
+++ b/subst.c
@@ -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.
 
index 7009f32..ee4c925 100644 (file)
--- a/subst.c~
+++ b/subst.c~
@@ -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 */
                }
index 5b5c81c..d4ab3c9 100755 (executable)
@@ -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)'
index 72ec06a..3efcf32 100755 (executable)
@@ -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
 
diff --git a/trap.c b/trap.c
index 77b6d76..1125534 100644 (file)
--- a/trap.c
+++ b/trap.c
@@ -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.
 
diff --git a/trap.c~ b/trap.c~
index ef1d95a..77b6d76 100644 (file)
--- a/trap.c~
+++ b/trap.c~
@@ -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++)
index d3fe79e..375556c 100644 (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 ();
index 2835f5c..96da743 100644 (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;
     }
index 914f389..6f5c7d5 100644 (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.
 
index 0974c72..914f389 100644 (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 *));