[gnu.bash.bug] useful features

pwolfe@kailand.kai.com (Patrick Wolfe) (12/05/89)

Enclose you will find context diffs to shell.c and builtins.c.

I made a small change to shell.c that was neccessary to compile bash under
Sequent Dynix V3.0 and Alliant Concentrix V5.0 (both OS's are derivatives of
BSD Unix 4.[23]).  Neither had the "setvbuf" system call, but had the
"setlinebuf" call which does the same thing.

The change to builtins is to add two new features that we find extremely
useful.  I've added the "-N" option to the "pushd" and "popd" commands (to
complement the "+N" option).  The difference between "+N" and "-N" is that "-N
access the directory stack from the right end.  I've also updated the online
help to describe the new options.

This is especially useful in the following function:

function cd () {
	pushd_silent=
	pushd $*
	unset pushd_silent
	popd -0
	}

To avoid lots of output in functions using multiple "pushd" and/or "popd"
commands, I've made the change that the implied "dirs" after these commands end
is only performed if the variable "pushd_silent" is NOT set.  So, the above
example only displays the directory stack once.

I hope you find these features useful.  I'm currently working on porting Bash
to SGI Irix and Concurrent RTU (both are SVR3 with real BSD job control).  I've
already got it running on:

	Sequent Balance B8 running Dynix 3.0 (BSD 4.[23]) using gcc 1.36
	Sequent Symmetry S81 running Dynix 3.0 (BSD 4.[23]) using gcc 1.36
	Intel 302 (386 PC) running Bell Technologies System V/386 R3.2 using cc
	Solbourne Series 4/500 running OS/MP 4.0 (Sun 4 clone) using cc


        Patrick Wolfe
        System Manager, Kuck & Associates
	work: pwolfe@kailand.kai.com  or  uunet!kailand!pwolfe
	home: pat@pawnix.kai.com  or  uunet!kailand!pawnix!pat



===================================================================
RCS file: RCS/shell.c,v
retrieving revision 1.1
diff -c -r1.1 shell.c
*** /tmp/,RCSt1012533	Mon Dec  4 20:11:00 1989
--- shell.c	Mon Dec  4 11:09:07 1989
***************
*** 669,675 ****
--- 669,679 ----
  {
  
    /* Line buffer output for stderr. */
+ #ifdef SETLINEBUF
+   setlinebuf (stderr);
+ #else
    setvbuf (stderr, (char *)NULL, _IOLBF, BUFSIZ);
+ #endif
  
    /* The initialization of the basic underlying signal handlers must
       happen before we initialize_traps ().  */

===================================================================
RCS file: RCS/builtins.c,v
retrieving revision 1.1
diff -c -r1.1 builtins.c
*** /tmp/,RCSt1012463	Mon Dec  4 19:49:42 1989
--- builtins.c	Mon Dec  4 19:48:36 1989
***************
*** 228,249 ****
        "	Logout of a login shell" },
  
  #ifdef PUSHD_AND_POPD
!   { "popd", popd_builtin, 1, "popd [+n]",
!       "	Pops the directory stack, and cd's to the new top directory.\n\
! 	The elements are numbered from 0 starting at the first directory\n\
! 	listed with `dirs'; i.e. `popd' is equivalent to `popd 0'" },
! 
!   { "pushd", pushd_builtin, 1, "pushd [dir | +n]",
!       "	Save the current directory on a list and then CD to DIR.\n\
! 	With no arguments, exchanges the top two directories.\n\
! \n\
! 	+n   Brings the Nth directory to the top of the list by rotating.\n\
! \n\
! 	dir  Makes the current working directory be the top of\n\
! 	     the stack, and then cd's to DIR.\n\
  \n\
! 	You can see the saved directory list with the `dirs' command" },
! #endif  /* PUSHD_AND_POPD */
  
    { "pwd", pwd_builtin, 1, "pwd",
        "	Print the current working directory"},
--- 228,269 ----
        "	Logout of a login shell" },
  
  #ifdef PUSHD_AND_POPD
!   { "popd", popd_builtin, 1, "popd [+n | -n]",
!       "	Removes entries from the directory stack.  With no arguments,\n\
! 	removes the top directory from the stack, and cd's to the new\n\
! 	top directory.\n\
  \n\
! 	+n    removes the Nth entry counting from the left of the list\n\
! 	      shown by `dirs', starting with zero.  For example: `popd +0'\n\
! 	      removes the first directory, `popd +1' the second.\n\
! \n\
! 	-n    removes the Nth entry counting from the right of the list\n\
! 	      shown by `dirs', starting with zero.  For example: `popd -0'\n\
! 	      removes the last directory, `popd -1' the next to last.\n\
! \n\
! 	You can see the directory stack with the `dirs' command.\n\
! 	If the variable 'pushd_silent' is not set and the popd command\n\
! 	was successful, a 'dirs' will be performed as well." },
! 
!   { "pushd", pushd_builtin, 1, "pushd [dir | +n | -n]",
!       "	Adds a directory to the top of the directory stack, or rotates\n\
! 	the stack, making the new top of the stack the current working\n\
! 	directory.  With no arguments, exchanges the top two directories.\n\
! \n\
! 	+n   Rotates the stack so that the Nth directory (counting\n\
! 	     from the left of the list shown by `dirs') is at the top.\n\
! \n\
! 	-n   Rotates the stack so that the Nth directory (counting\n\
! 	     from the right) is at the top.\n\
! \n\
! 	dir  adds DIR to the directory stack at the top, making it the\n\
! 	     new current working directory.\n\
! \n\
! 	You can see the directory stack with the `dirs' command.\n\
! 	If the variable 'pushd_silent' is not set and the pushd command\n\
! 	was successful, a 'dirs' will be performed as well." },
! 
! #endif /* PUSHD_AND_POPD */
  
    { "pwd", pwd_builtin, 1, "pwd",
        "	Print the current working directory"},
***************
*** 300,306 ****
  
  #ifdef JOB_CONTROL
    { "suspend", suspend_builtin, 1, "suspend [-f]",
!       "	Suspend the execution of this shell until it recieves a SIGCONT\n\
  	signal.  The `-f' if specified says not to complain about this\n\
  	being a login shell if it is; just suspend anyway" },
  #endif
--- 320,326 ----
  
  #ifdef JOB_CONTROL
    { "suspend", suspend_builtin, 1, "suspend [-f]",
!       "	Suspend the execution of this shell until it receives a SIGCONT\n\
  	signal.  The `-f' if specified says not to complain about this\n\
  	being a login shell if it is; just suspend anyway" },
  #endif
***************
*** 2727,2732 ****
--- 2747,2753 ----
  {
    char *temp, *current_directory, *get_working_directory ();
    int j = directory_list_offset - 1;
+   char direction = '+';
  
    /* If there is no argument list then switch current and
       top of list. */
***************
*** 2748,2770 ****
      }
    else
      {
!       if (*(list->word->word) == '+')
  	{
  	  int num;
  	  if (1 == sscanf (&(list->word->word)[1], "%d", &num))
  	    {
  	      if (num > directory_list_offset)
  		{
  		  if (!directory_list_offset)
  		    report_error ("pushd: directory stack empty");
  		  else
! 		    report_error ("pushd: directory stack isn't %d deep", num);
  		  return (EXECUTION_FAILURE);
  		}
  	      else
  		{
  		  /* Rotate the stack num times.  Remember, the
! 		     current directory is part of the stack. */
  		  temp = get_working_directory ("pushd");
  
  		  if (!num)
--- 2769,2794 ----
      }
    else
      {
!       direction = *(list->word->word);
!       if ((direction == '+') || (direction == '-'))
  	{
  	  int num;
  	  if (1 == sscanf (&(list->word->word)[1], "%d", &num))
  	    {
+ 	      if (direction == '-')
+ 		num = directory_list_offset - num;
  	      if (num > directory_list_offset)
  		{
  		  if (!directory_list_offset)
  		    report_error ("pushd: directory stack empty");
  		  else
! 		    report_error ("pushd: stack contains only %d directories", directory_list_offset + 1);
  		  return (EXECUTION_FAILURE);
  		}
  	      else
  		{
  		  /* Rotate the stack num times.  Remember, the
! 		     current directory acts like it is part of the stack. */
  		  temp = get_working_directory ("pushd");
  
  		  if (!num)
***************
*** 2786,2792 ****
  		  while (num);
  
  		  temp = savestring (temp);
! 		change_to_temp:
  		  {
  		    int tt = EXECUTION_FAILURE;
  
--- 2810,2816 ----
  		  while (num);
  
  		  temp = savestring (temp);
! change_to_temp:
  		  {
  		    int tt = EXECUTION_FAILURE;
  
***************
*** 2796,2802 ****
  			free (temp);
  		      }
  
! 		    if (tt == EXECUTION_SUCCESS)
  		      dirs_builtin ((WORD_LIST *)NULL);
  
  		    return (tt);
--- 2820,2826 ----
  			free (temp);
  		      }
  
! 		    if ((tt == EXECUTION_SUCCESS) && (!find_variable("pushd_silent")))
  		      dirs_builtin ((WORD_LIST *)NULL);
  
  		    return (tt);
***************
*** 2824,2830 ****
  				     (directory_list_size += 10) * sizeof (char *));
  	    }
  	  pushd_directory_list[directory_list_offset++] = current_directory;
! 	  dirs_builtin ((WORD_LIST *)NULL);
  	  return (EXECUTION_SUCCESS);
  	}
        else
--- 2848,2855 ----
  				     (directory_list_size += 10) * sizeof (char *));
  	    }
  	  pushd_directory_list[directory_list_offset++] = current_directory;
!           if (!find_variable("pushd_silent"))
! 	    dirs_builtin ((WORD_LIST *)NULL);
  	  return (EXECUTION_SUCCESS);
  	}
        else
***************
*** 2884,2890 ****
  }
  
  /* Pop the directory stack, and then change to the new top of the stack.
!    If LIST is non-null it should consist of a word +N, which says
     what element to delete from the stack.  The default is the top one. */
  popd_builtin (list)
       WORD_LIST *list;
--- 2909,2915 ----
  }
  
  /* Pop the directory stack, and then change to the new top of the stack.
!    If LIST is non-null it should consist of a word +N or -N, which says
     what element to delete from the stack.  The default is the top one. */
  popd_builtin (list)
       WORD_LIST *list;
***************
*** 2891,2900 ****
  {
    register int i;
    int which = 0;
  
    if (list)
      {
!       if ((*(list->word->word) != '+') ||
  	  (1 != sscanf (&((list->word->word)[1]), "%d", &which)))
  	{
  	  report_error ("popd: bad arg `%s'", list->word->word);
--- 2916,2927 ----
  {
    register int i;
    int which = 0;
+   char direction = '+';
  
    if (list)
      {
!       direction = *(list->word->word);
!       if (((direction != '+') && (direction != '-')) ||
  	  (1 != sscanf (&((list->word->word)[1]), "%d", &which)))
  	{
  	  report_error ("popd: bad arg `%s'", list->word->word);
***************
*** 2901,2937 ****
  	  return (EXECUTION_FAILURE);
  	}
      }
!   if (which > directory_list_offset || (!directory_list_offset && !which))
      {
        if (!directory_list_offset)
  	report_error ("popd: directory stack empty");
        else
! 	report_error ("popd: stack is only %d deep", directory_list_offset);
        return (EXECUTION_FAILURE);
      }
  
!   if (!which)
      {
        i = cd_to_string (pushd_directory_list[directory_list_offset - 1]);
        if (i != EXECUTION_SUCCESS)
  	return (i);
        free (pushd_directory_list[--directory_list_offset]);
-       goto exit_and_win;
      }
! 
!   /* Since an offset was specified, remove that directory from the list.
!      There is nothing else left to do, since the top directory hasn't
!      changed. */
!   free (pushd_directory_list[directory_list_offset - which]);
! 
!   /* Shift the remainder of the list into place. */
!   for (i = 1 + (directory_list_offset - which); i < directory_list_offset; i++)
!     pushd_directory_list[i - 1] = pushd_directory_list[i];
! 
!   directory_list_offset--;
  
!  exit_and_win:
!   dirs_builtin ((WORD_LIST *)NULL);
    return (EXECUTION_SUCCESS);
  }
  
--- 2928,2967 ----
  	  return (EXECUTION_FAILURE);
  	}
      }
!   if ((which > directory_list_offset) || (!directory_list_offset && !which))
      {
        if (!directory_list_offset)
  	report_error ("popd: directory stack empty");
        else
! 	report_error ("popd: stack contains only %d directories", directory_list_offset + 1);
        return (EXECUTION_FAILURE);
      }
  
!   /* either no offset was specified, or the top directory was specified */
!   if ( ((direction == '+') && (which == 0))
!      || ((direction == '-') && (which == directory_list_offset)) )
      {
        i = cd_to_string (pushd_directory_list[directory_list_offset - 1]);
        if (i != EXECUTION_SUCCESS)
  	return (i);
        free (pushd_directory_list[--directory_list_offset]);
      }
!   else
!     {
!     /* Since an offset (other than the top directory) was specified, remove that
!        directory from the list and shift the remainder of the list into place */
!     if (direction == '+')
!       i = directory_list_offset - which;
!     else
!       i = which;
!     free (pushd_directory_list[i]);
!     directory_list_offset--;
!     for (; i < directory_list_offset; i++)
!       pushd_directory_list[i] = pushd_directory_list[i + 1];
!     }
  
!   if (!find_variable("pushd_silent"))
!     dirs_builtin ((WORD_LIST *)NULL);
    return (EXECUTION_SUCCESS);
  }
  


-- 

        Patrick Wolfe
        System Manager, Kuck & Associates
	work: pwolfe@kailand.kai.com  or  uunet!kailand!pwolfe
	home: pat@pawnix.kai.com  or  uunet!kailand!pawnix!pat