683 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			Modula-2
		
	
	
	
	
	
			
		
		
	
	
			683 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			Modula-2
		
	
	
	
	
	
| This file is fc.def, from which is created fc.c.
 | |
| It implements the builtin "fc" in Bash.
 | |
| 
 | |
| Copyright (C) 1987-2010 Free Software Foundation, Inc.
 | |
| 
 | |
| This file is part of GNU Bash, the Bourne Again SHell.
 | |
| 
 | |
| Bash is free software: you can redistribute it and/or modify
 | |
| it under the terms of the GNU General Public License as published by
 | |
| the Free Software Foundation, either version 3 of the License, or
 | |
| (at your option) any later version.
 | |
| 
 | |
| Bash is distributed in the hope that it will be useful,
 | |
| but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
| GNU General Public License for more details.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License
 | |
| along with Bash.  If not, see <http://www.gnu.org/licenses/>.
 | |
| 
 | |
| $PRODUCES fc.c
 | |
| 
 | |
| $BUILTIN fc
 | |
| $FUNCTION fc_builtin
 | |
| $DEPENDS_ON HISTORY
 | |
| $SHORT_DOC fc [-e ename] [-lnr] [first] [last] or fc -s [pat=rep] [command]
 | |
| Display or execute commands from the history list.
 | |
| 
 | |
| fc is used to list or edit and re-execute commands from the history list.
 | |
| FIRST and LAST can be numbers specifying the range, or FIRST can be a
 | |
| string, which means the most recent command beginning with that
 | |
| string.
 | |
| 
 | |
| Options:
 | |
|   -e ENAME	select which editor to use.  Default is FCEDIT, then EDITOR,
 | |
| 		then vi
 | |
|   -l 	list lines instead of editing
 | |
|   -n	omit line numbers when listing
 | |
|   -r	reverse the order of the lines (newest listed first)
 | |
| 
 | |
| With the `fc -s [pat=rep ...] [command]' format, COMMAND is
 | |
| re-executed after the substitution OLD=NEW is performed.
 | |
| 
 | |
| A useful alias to use with this is r='fc -s', so that typing `r cc'
 | |
| runs the last command beginning with `cc' and typing `r' re-executes
 | |
| the last command.
 | |
| 
 | |
| Exit Status:
 | |
| Returns success or status of executed command; non-zero if an error occurs.
 | |
| $END
 | |
| 
 | |
| #include <config.h>
 | |
| 
 | |
| #if defined (HISTORY)
 | |
| #ifndef _MINIX
 | |
| #  include <sys/param.h>
 | |
| #endif
 | |
| #include "../bashtypes.h"
 | |
| #include "posixstat.h"
 | |
| #if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
 | |
| #  include <sys/file.h>
 | |
| #endif
 | |
| 
 | |
| #if defined (HAVE_UNISTD_H)
 | |
| #  include <unistd.h>
 | |
| #endif
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <chartypes.h>
 | |
| 
 | |
| #include "../bashansi.h"
 | |
| #include "../bashintl.h"
 | |
| #include <errno.h>
 | |
| 
 | |
| #include "../shell.h"
 | |
| #include "../builtins.h"
 | |
| #include "../flags.h"
 | |
| #include "../bashhist.h"
 | |
| #include "maxpath.h"
 | |
| #include <readline/history.h>
 | |
| #include "bashgetopt.h"
 | |
| #include "common.h"
 | |
| 
 | |
| #if !defined (errno)
 | |
| extern int errno;
 | |
| #endif /* !errno */
 | |
| 
 | |
| extern int current_command_line_count, saved_command_line_count;
 | |
| extern int literal_history;
 | |
| extern int posixly_correct;
 | |
| extern int subshell_environment, interactive_shell;
 | |
| 
 | |
| extern int unlink __P((const char *));
 | |
| 
 | |
| extern FILE *sh_mktmpfp __P((char *, int, char **));
 | |
| 
 | |
| /* **************************************************************** */
 | |
| /*								    */
 | |
| /*	The K*rn shell style fc command (Fix Command)		    */
 | |
| /*								    */
 | |
| /* **************************************************************** */
 | |
| 
 | |
| /* fc builtin command (fix command) for Bash for those who
 | |
|    like K*rn-style history better than csh-style.
 | |
| 
 | |
|      fc [-e ename] [-nlr] [first] [last]
 | |
| 
 | |
|    FIRST and LAST can be numbers specifying the range, or FIRST can be
 | |
|    a string, which means the most recent command beginning with that
 | |
|    string.
 | |
| 
 | |
|    -e ENAME selects which editor to use.  Default is FCEDIT, then EDITOR,
 | |
|       then the editor which corresponds to the current readline editing
 | |
|       mode, then vi.
 | |
| 
 | |
|    -l means list lines instead of editing.
 | |
|    -n means no line numbers listed.
 | |
|    -r means reverse the order of the lines (making it newest listed first).
 | |
| 
 | |
|      fc -e - [pat=rep ...] [command]
 | |
|      fc -s [pat=rep ...] [command]
 | |
| 
 | |
|    Equivalent to !command:sg/pat/rep execpt there can be multiple PAT=REP's.
 | |
| */
 | |
| 
 | |
| /* Data structure describing a list of global replacements to perform. */
 | |
| typedef struct repl {
 | |
|   struct repl *next;
 | |
|   char *pat;
 | |
|   char *rep;
 | |
| } REPL;
 | |
| 
 | |
| /* Accessors for HIST_ENTRY lists that are called HLIST. */
 | |
| #define histline(i) (hlist[(i)]->line)
 | |
| #define histdata(i) (hlist[(i)]->data)
 | |
| 
 | |
| #define FREE_RLIST() \
 | |
| 	do { \
 | |
| 		for (rl = rlist; rl; ) { \
 | |
| 			REPL *r;	\
 | |
| 			r = rl->next; \
 | |
| 			if (rl->pat) \
 | |
| 				free (rl->pat); \
 | |
| 			if (rl->rep) \
 | |
| 				free (rl->rep); \
 | |
| 			free (rl); \
 | |
| 			rl = r; \
 | |
| 		} \
 | |
| 	} while (0)
 | |
| 
 | |
| static char *fc_dosubs __P((char *, REPL *));
 | |
| static char *fc_gethist __P((char *, HIST_ENTRY **));
 | |
| static int fc_gethnum __P((char *, HIST_ENTRY **));
 | |
| static int fc_number __P((WORD_LIST *));
 | |
| static void fc_replhist __P((char *));
 | |
| #ifdef INCLUDE_UNUSED
 | |
| static char *fc_readline __P((FILE *));
 | |
| static void fc_addhist __P((char *));
 | |
| #endif
 | |
| 
 | |
| /* String to execute on a file that we want to edit. */
 | |
| #define FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-vi}}"
 | |
| #if defined (STRICT_POSIX)
 | |
| #  define POSIX_FC_EDIT_COMMAND "${FCEDIT:-ed}"
 | |
| #else
 | |
| #  define POSIX_FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-ed}}"
 | |
| #endif
 | |
| 
 | |
| int
 | |
| fc_builtin (list)
 | |
|      WORD_LIST *list;
 | |
| {
 | |
|   register int i;
 | |
|   register char *sep;
 | |
|   int numbering, reverse, listing, execute;
 | |
|   int histbeg, histend, last_hist, retval, opt, rh;
 | |
|   FILE *stream;
 | |
|   REPL *rlist, *rl;
 | |
|   char *ename, *command, *newcom, *fcedit;
 | |
|   HIST_ENTRY **hlist;
 | |
|   char *fn;
 | |
| 
 | |
|   numbering = 1;
 | |
|   reverse = listing = execute = 0;
 | |
|   ename = (char *)NULL;
 | |
| 
 | |
|   /* Parse out the options and set which of the two forms we're in. */
 | |
|   reset_internal_getopt ();
 | |
|   lcurrent = list;		/* XXX */
 | |
|   while (fc_number (loptend = lcurrent) == 0 &&
 | |
| 	 (opt = internal_getopt (list, ":e:lnrs")) != -1)
 | |
|     {
 | |
|       switch (opt)
 | |
| 	{
 | |
| 	case 'n':
 | |
| 	  numbering = 0;
 | |
| 	  break;
 | |
| 
 | |
| 	case 'l':
 | |
| 	  listing = 1;
 | |
| 	  break;
 | |
| 
 | |
| 	case 'r':
 | |
| 	  reverse = 1;
 | |
| 	  break;
 | |
| 
 | |
| 	case 's':
 | |
| 	  execute = 1;
 | |
| 	  break;
 | |
| 
 | |
| 	case 'e':
 | |
| 	  ename = list_optarg;
 | |
| 	  break;
 | |
| 
 | |
| 	default:
 | |
| 	  builtin_usage ();
 | |
| 	  return (EX_USAGE);
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   list = loptend;
 | |
| 
 | |
|   if (ename && (*ename == '-') && (ename[1] == '\0'))
 | |
|     execute = 1;
 | |
| 
 | |
|   /* The "execute" form of the command (re-run, with possible string
 | |
|      substitutions). */
 | |
|   if (execute)
 | |
|     {
 | |
|       rlist = (REPL *)NULL;
 | |
|       while (list && ((sep = (char *)strchr (list->word->word, '=')) != NULL))
 | |
| 	{
 | |
| 	  *sep++ = '\0';
 | |
| 	  rl = (REPL *)xmalloc (sizeof (REPL));
 | |
| 	  rl->next = (REPL *)NULL;
 | |
| 	  rl->pat = savestring (list->word->word);
 | |
| 	  rl->rep = savestring (sep);
 | |
| 
 | |
| 	  if (rlist == NULL)
 | |
| 	    rlist = rl;
 | |
| 	  else
 | |
| 	    {
 | |
| 	      rl->next = rlist;
 | |
| 	      rlist = rl;
 | |
| 	    }
 | |
| 	  list = list->next;
 | |
| 	}
 | |
| 
 | |
|       /* If we have a list of substitutions to do, then reverse it
 | |
| 	 to get the replacements in the proper order. */
 | |
| 
 | |
|       rlist = REVERSE_LIST (rlist, REPL *);
 | |
| 
 | |
|       hlist = history_list ();
 | |
| 
 | |
|       /* If we still have something in list, it is a command spec.
 | |
| 	 Otherwise, we use the most recent command in time. */
 | |
|       command = fc_gethist (list ? list->word->word : (char *)NULL, hlist);
 | |
| 
 | |
|       if (command == NULL)
 | |
| 	{
 | |
| 	  builtin_error (_("no command found"));
 | |
| 	  if (rlist)
 | |
| 	    FREE_RLIST ();
 | |
| 
 | |
| 	  return (EXECUTION_FAILURE);
 | |
| 	}
 | |
| 
 | |
|       if (rlist)
 | |
| 	{
 | |
| 	  newcom = fc_dosubs (command, rlist);
 | |
| 	  free (command);
 | |
| 	  FREE_RLIST ();
 | |
| 	  command = newcom;
 | |
| 	}
 | |
| 
 | |
|       fprintf (stderr, "%s\n", command);
 | |
|       fc_replhist (command);	/* replace `fc -s' with command */
 | |
|       /* Posix says that the re-executed commands should be entered into the
 | |
| 	 history. */
 | |
|       return (parse_and_execute (command, "fc", SEVAL_NOHIST));
 | |
|     }
 | |
| 
 | |
|   /* This is the second form of the command (the list-or-edit-and-rerun
 | |
|      form). */
 | |
|   hlist = history_list ();
 | |
|   if (hlist == 0)
 | |
|     return (EXECUTION_SUCCESS);
 | |
|   for (i = 0; hlist[i]; i++);
 | |
| 
 | |
|   /* With the Bash implementation of history, the current command line
 | |
|      ("fc blah..." and so on) is already part of the history list by
 | |
|      the time we get to this point.  This just skips over that command
 | |
|      and makes the last command that this deals with be the last command
 | |
|      the user entered before the fc.  We need to check whether the
 | |
|      line was actually added (HISTIGNORE may have caused it to not be),
 | |
|      so we check hist_last_line_added. */
 | |
| 
 | |
|   /* Even though command substitution through parse_and_execute turns off
 | |
|      remember_on_history, command substitution in a shell when set -o history
 | |
|      has been enabled (interactive or not) should use it in the last_hist
 | |
|      calculation as if it were on. */
 | |
|   rh = remember_on_history || ((subshell_environment & SUBSHELL_COMSUB) && enable_history_list);
 | |
|   last_hist = i - rh - hist_last_line_added;
 | |
| 
 | |
|   /* XXX */
 | |
|   if (i == last_hist && hlist[last_hist] == 0)
 | |
|     while (last_hist >= 0 && hlist[last_hist] == 0)
 | |
|       last_hist--;
 | |
|   if (last_hist < 0)
 | |
|     {
 | |
|       sh_erange ((char *)NULL, _("history specification"));
 | |
|       return (EXECUTION_FAILURE);
 | |
|     }
 | |
| 
 | |
|   if (list)
 | |
|     {
 | |
|       histbeg = fc_gethnum (list->word->word, hlist);
 | |
|       list = list->next;
 | |
| 
 | |
|       if (list)
 | |
| 	histend = fc_gethnum (list->word->word, hlist);
 | |
|       else
 | |
| 	histend = listing ? last_hist : histbeg;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       /* The default for listing is the last 16 history items. */
 | |
|       if (listing)
 | |
| 	{
 | |
| 	  histend = last_hist;
 | |
| 	  histbeg = histend - 16 + 1;	/* +1 because loop below uses >= */
 | |
| 	  if (histbeg < 0)
 | |
| 	    histbeg = 0;
 | |
| 	}
 | |
|       else
 | |
| 	/* For editing, it is the last history command. */
 | |
| 	histbeg = histend = last_hist;
 | |
|     }
 | |
| 
 | |
|   /* "When not listing, the fc command that caused the editing shall not be
 | |
|      entered into the history list." */
 | |
|   if (listing == 0 && hist_last_line_added)
 | |
|     {
 | |
|       bash_delete_last_history ();
 | |
|       /* If we're editing a single command -- the last command in the
 | |
| 	 history -- and we just removed the dummy command added by
 | |
| 	 edit_and_execute_command (), we need to check whether or not we
 | |
| 	 just removed the last command in the history and need to back
 | |
| 	 the pointer up.  remember_on_history is off because we're running
 | |
| 	 in parse_and_execute(). */
 | |
|       if (histbeg == histend && histend == last_hist && hlist[last_hist] == 0)
 | |
| 	last_hist = histbeg = --histend;
 | |
|     }
 | |
| 
 | |
|   /* We print error messages for line specifications out of range. */
 | |
|   if ((histbeg < 0) || (histend < 0))
 | |
|     {
 | |
|       sh_erange ((char *)NULL, _("history specification"));
 | |
|       return (EXECUTION_FAILURE);
 | |
|     }
 | |
| 
 | |
|   if (histend < histbeg)
 | |
|     {
 | |
|       i = histend;
 | |
|       histend = histbeg;
 | |
|       histbeg = i;
 | |
| 
 | |
|       reverse = 1;
 | |
|     }
 | |
| 
 | |
|   if (listing)
 | |
|     stream = stdout;
 | |
|   else
 | |
|     {
 | |
|       numbering = 0;
 | |
|       stream = sh_mktmpfp ("bash-fc", MT_USERANDOM|MT_USETMPDIR, &fn);
 | |
|       if (stream == 0)
 | |
| 	{
 | |
| 	  builtin_error (_("%s: cannot open temp file: %s"), fn ? fn : "", strerror (errno));
 | |
| 	  FREE (fn);
 | |
| 	  return (EXECUTION_FAILURE);
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   for (i = reverse ? histend : histbeg; reverse ? i >= histbeg : i <= histend; reverse ? i-- : i++)
 | |
|     {
 | |
|       QUIT;
 | |
|       if (numbering)
 | |
| 	fprintf (stream, "%d", i + history_base);
 | |
|       if (listing)
 | |
| 	{
 | |
| 	  if (posixly_correct)
 | |
| 	    fputs ("\t", stream);
 | |
| 	  else
 | |
| 	    fprintf (stream, "\t%c", histdata (i) ? '*' : ' ');
 | |
| 	}
 | |
|       fprintf (stream, "%s\n", histline (i));
 | |
|     }
 | |
| 
 | |
|   if (listing)
 | |
|     return (sh_chkwrite (EXECUTION_SUCCESS));
 | |
| 
 | |
|   fflush (stream);
 | |
|   if (ferror (stream))
 | |
|     {
 | |
|       sh_wrerror ();
 | |
|       fclose (stream);
 | |
|       return (EXECUTION_FAILURE);
 | |
|     }
 | |
|   fclose (stream);
 | |
| 
 | |
|   /* Now edit the file of commands. */
 | |
|   if (ename)
 | |
|     {
 | |
|       command = (char *)xmalloc (strlen (ename) + strlen (fn) + 2);
 | |
|       sprintf (command, "%s %s", ename, fn);
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       fcedit = posixly_correct ? POSIX_FC_EDIT_COMMAND : FC_EDIT_COMMAND;
 | |
|       command = (char *)xmalloc (3 + strlen (fcedit) + strlen (fn));
 | |
|       sprintf (command, "%s %s", fcedit, fn);
 | |
|     }
 | |
|   retval = parse_and_execute (command, "fc", SEVAL_NOHIST);
 | |
|   if (retval != EXECUTION_SUCCESS)
 | |
|     {
 | |
|       unlink (fn);
 | |
|       free (fn);
 | |
|       return (EXECUTION_FAILURE);
 | |
|     }
 | |
| 
 | |
|   /* Make sure parse_and_execute doesn't turn this off, even though a
 | |
|      call to parse_and_execute farther up the function call stack (e.g.,
 | |
|      if this is called by vi_edit_and_execute_command) may have already
 | |
|      called bash_history_disable. */
 | |
|   remember_on_history = 1;
 | |
| 
 | |
|   /* Turn on the `v' flag while fc_execute_file runs so the commands
 | |
|      will be echoed as they are read by the parser. */
 | |
|   begin_unwind_frame ("fc builtin");
 | |
|   add_unwind_protect ((Function *)xfree, fn);
 | |
|   add_unwind_protect (unlink, fn);
 | |
|   unwind_protect_int (echo_input_at_read);
 | |
|   echo_input_at_read = 1;
 | |
|     
 | |
|   retval = fc_execute_file (fn);
 | |
| 
 | |
|   run_unwind_frame ("fc builtin");
 | |
| 
 | |
|   return (retval);
 | |
| }
 | |
| 
 | |
| /* Return 1 if LIST->word->word is a legal number for fc's use. */
 | |
| static int
 | |
| fc_number (list)
 | |
|      WORD_LIST *list;
 | |
| {
 | |
|   char *s;
 | |
| 
 | |
|   if (list == 0)
 | |
|     return 0;
 | |
|   s = list->word->word;
 | |
|   if (*s == '-')
 | |
|     s++;
 | |
|   return (legal_number (s, (intmax_t *)NULL));
 | |
| }
 | |
| 
 | |
| /* Return an absolute index into HLIST which corresponds to COMMAND.  If
 | |
|    COMMAND is a number, then it was specified in relative terms.  If it
 | |
|    is a string, then it is the start of a command line present in HLIST. */
 | |
| static int
 | |
| fc_gethnum (command, hlist)
 | |
|      char *command;
 | |
|      HIST_ENTRY **hlist;
 | |
| {
 | |
|   int sign, n, clen, rh;
 | |
|   register int i, j, last_hist;
 | |
|   register char *s;
 | |
| 
 | |
|   sign = 1;
 | |
|   /* Count history elements. */
 | |
|   for (i = 0; hlist[i]; i++);
 | |
| 
 | |
|   /* With the Bash implementation of history, the current command line
 | |
|      ("fc blah..." and so on) is already part of the history list by
 | |
|      the time we get to this point.  This just skips over that command
 | |
|      and makes the last command that this deals with be the last command
 | |
|      the user entered before the fc.  We need to check whether the
 | |
|      line was actually added (HISTIGNORE may have caused it to not be),
 | |
|      so we check hist_last_line_added.  This needs to agree with the
 | |
|      calculation of last_hist in fc_builtin above. */
 | |
|   /* Even though command substitution through parse_and_execute turns off
 | |
|      remember_on_history, command substitution in a shell when set -o history
 | |
|      has been enabled (interactive or not) should use it in the last_hist
 | |
|      calculation as if it were on. */
 | |
|   rh = remember_on_history || ((subshell_environment & SUBSHELL_COMSUB) && enable_history_list);
 | |
|   last_hist = i - rh - hist_last_line_added;
 | |
| 
 | |
|   if (i == last_hist && hlist[last_hist] == 0)
 | |
|     while (last_hist >= 0 && hlist[last_hist] == 0)
 | |
|       last_hist--;
 | |
|   if (last_hist < 0)
 | |
|     return (-1);
 | |
| 
 | |
|   i = last_hist;
 | |
| 
 | |
|   /* No specification defaults to most recent command. */
 | |
|   if (command == NULL)
 | |
|     return (i);
 | |
| 
 | |
|   /* Otherwise, there is a specification.  It can be a number relative to
 | |
|      the current position, or an absolute history number. */
 | |
|   s = command;
 | |
| 
 | |
|   /* Handle possible leading minus sign. */
 | |
|   if (s && (*s == '-'))
 | |
|     {
 | |
|       sign = -1;
 | |
|       s++;
 | |
|     }
 | |
| 
 | |
|   if (s && DIGIT(*s))
 | |
|     {
 | |
|       n = atoi (s);
 | |
|       n *= sign;
 | |
| 
 | |
|       /* If the value is negative or zero, then it is an offset from
 | |
| 	 the current history item. */
 | |
|       if (n < 0)
 | |
| 	{
 | |
| 	  n += i + 1;
 | |
| 	  return (n < 0 ? 0 : n);
 | |
| 	}
 | |
|       else if (n == 0)
 | |
| 	return (i);
 | |
|       else
 | |
| 	{
 | |
| 	  n -= history_base;
 | |
| 	  return (i < n ? i : n);
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|   clen = strlen (command);
 | |
|   for (j = i; j >= 0; j--)
 | |
|     {
 | |
|       if (STREQN (command, histline (j), clen))
 | |
| 	return (j);
 | |
|     }
 | |
|   return (-1);
 | |
| }
 | |
| 
 | |
| /* Locate the most recent history line which begins with
 | |
|    COMMAND in HLIST, and return a malloc()'ed copy of it. */
 | |
| static char *
 | |
| fc_gethist (command, hlist)
 | |
|      char *command;
 | |
|      HIST_ENTRY **hlist;
 | |
| {
 | |
|   int i;
 | |
| 
 | |
|   if (hlist == 0)
 | |
|     return ((char *)NULL);
 | |
| 
 | |
|   i = fc_gethnum (command, hlist);
 | |
| 
 | |
|   if (i >= 0)
 | |
|     return (savestring (histline (i)));
 | |
|   else
 | |
|     return ((char *)NULL);
 | |
| }
 | |
| 
 | |
| #ifdef INCLUDE_UNUSED
 | |
| /* Read the edited history lines from STREAM and return them
 | |
|    one at a time.  This can read unlimited length lines.  The
 | |
|    caller should free the storage. */
 | |
| static char *
 | |
| fc_readline (stream)
 | |
|      FILE *stream;
 | |
| {
 | |
|   register int c;
 | |
|   int line_len = 0, lindex = 0;
 | |
|   char *line = (char *)NULL;
 | |
| 
 | |
|   while ((c = getc (stream)) != EOF)
 | |
|     {
 | |
|       if ((lindex + 2) >= line_len)
 | |
| 	line = (char *)xrealloc (line, (line_len += 128));
 | |
| 
 | |
|       if (c == '\n')
 | |
| 	{
 | |
| 	  line[lindex++] = '\n';
 | |
| 	  line[lindex++] = '\0';
 | |
| 	  return (line);
 | |
| 	}
 | |
|       else
 | |
| 	line[lindex++] = c;
 | |
|     }
 | |
| 
 | |
|   if (!lindex)
 | |
|     {
 | |
|       if (line)
 | |
| 	free (line);
 | |
| 
 | |
|       return ((char *)NULL);
 | |
|     }
 | |
| 
 | |
|   if (lindex + 2 >= line_len)
 | |
|     line = (char *)xrealloc (line, lindex + 3);
 | |
| 
 | |
|   line[lindex++] = '\n';	    /* Finish with newline if none in file */
 | |
|   line[lindex++] = '\0';
 | |
|   return (line);
 | |
| }
 | |
| #endif
 | |
| 
 | |
| /* Perform the SUBS on COMMAND.
 | |
|    SUBS is a list of substitutions, and COMMAND is a simple string.
 | |
|    Return a pointer to a malloc'ed string which contains the substituted
 | |
|    command. */
 | |
| static char *
 | |
| fc_dosubs (command, subs)
 | |
|      char *command;
 | |
|      REPL *subs;
 | |
| {
 | |
|   register char *new, *t;
 | |
|   register REPL *r;
 | |
| 
 | |
|   for (new = savestring (command), r = subs; r; r = r->next)
 | |
|     {
 | |
|       t = strsub (new, r->pat, r->rep, 1);
 | |
|       free (new);
 | |
|       new = t;
 | |
|     }
 | |
|   return (new);
 | |
| }
 | |
| 
 | |
| /* Use `command' to replace the last entry in the history list, which,
 | |
|    by this time, is `fc blah...'.  The intent is that the new command
 | |
|    become the history entry, and that `fc' should never appear in the
 | |
|    history list.  This way you can do `r' to your heart's content. */
 | |
| static void
 | |
| fc_replhist (command)
 | |
|      char *command;
 | |
| {
 | |
|   int n;
 | |
| 
 | |
|   if (command == 0 || *command == '\0')
 | |
|     return;
 | |
| 
 | |
|   n = strlen (command);
 | |
|   if (command[n - 1] == '\n')
 | |
|     command[n - 1] = '\0';
 | |
| 
 | |
|   if (command && *command)
 | |
|     {
 | |
|       bash_delete_last_history ();
 | |
|       maybe_add_history (command);	/* Obeys HISTCONTROL setting. */
 | |
|     }
 | |
| }
 | |
| 
 | |
| #ifdef INCLUDE_UNUSED
 | |
| /* Add LINE to the history, after removing a single trailing newline. */
 | |
| static void
 | |
| fc_addhist (line)
 | |
|      char *line;
 | |
| {
 | |
|   register int n;
 | |
| 
 | |
|   if (line == 0 || *line == 0)
 | |
|     return;
 | |
| 
 | |
|   n = strlen (line);
 | |
| 
 | |
|   if (line[n - 1] == '\n')
 | |
|     line[n - 1] = '\0';
 | |
| 
 | |
|   if (line && *line)
 | |
|     maybe_add_history (line);		/* Obeys HISTCONTROL setting. */
 | |
| }
 | |
| #endif
 | |
| 
 | |
| #endif /* HISTORY */
 | 
