| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | This file is fc.def, from which is created fc.c. | 
					
						
							|  |  |  | It implements the builtin "fc" in Bash. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-15 16:59:08 -04:00
										 |  |  | Copyright (C) 1987-2015 Free Software Foundation, Inc. | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | This file is part of GNU Bash, the Bourne Again SHell. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | 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. | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | 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. | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  | along with Bash.  If not, see <http://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | $PRODUCES fc.c | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | $BUILTIN fc | 
					
						
							|  |  |  | $FUNCTION fc_builtin | 
					
						
							|  |  |  | $DEPENDS_ON HISTORY | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | $SHORT_DOC fc [-e ename] [-lnr] [first] [last] or fc -s [pat=rep] [command] | 
					
						
							|  |  |  | Display or execute commands from the history list. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1999-02-19 17:11:39 +00:00
										 |  |  | fc is used to list or edit and re-execute commands from the history list. | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 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. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | 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) | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | With the `fc -s [pat=rep ...] [command]' format, COMMAND is | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 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. | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | Exit Status: | 
					
						
							|  |  |  | Returns success or status of executed command; non-zero if an error occurs. | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | $END | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | #include <config.h> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | #if defined (HISTORY) | 
					
						
							| 
									
										
										
										
											2014-02-26 09:36:43 -05:00
										 |  |  | #if defined (HAVE_SYS_PARAM_H) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | #  include <sys/param.h> | 
					
						
							|  |  |  | #endif | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  | #include "../bashtypes.h" | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  | #include "posixstat.h" | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  | #if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H) | 
					
						
							| 
									
										
										
										
											1998-04-17 19:52:44 +00:00
										 |  |  | #  include <sys/file.h> | 
					
						
							|  |  |  | #endif | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #if defined (HAVE_UNISTD_H) | 
					
						
							|  |  |  | #  include <unistd.h> | 
					
						
							|  |  |  | #endif | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <stdio.h> | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | #include <chartypes.h> | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "../bashansi.h" | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  | #include "../bashintl.h" | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | #include <errno.h> | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "../shell.h" | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | #include "../builtins.h" | 
					
						
							|  |  |  | #include "../flags.h" | 
					
						
							|  |  |  | #include "../bashhist.h" | 
					
						
							| 
									
										
										
										
											2000-03-17 21:46:59 +00:00
										 |  |  | #include "maxpath.h" | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | #include <readline/history.h> | 
					
						
							|  |  |  | #include "bashgetopt.h" | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | #include "common.h" | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #if !defined (errno) | 
					
						
							|  |  |  | extern int errno; | 
					
						
							|  |  |  | #endif /* !errno */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-26 09:36:43 -05:00
										 |  |  | extern int current_command_line_count; | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  | extern int literal_history; | 
					
						
							| 
									
										
										
										
											2005-12-07 14:08:12 +00:00
										 |  |  | extern int posixly_correct; | 
					
						
							| 
									
										
										
										
											2011-11-21 20:49:12 -05:00
										 |  |  | extern int subshell_environment, interactive_shell; | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | extern int unlink __P((const char *)); | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  | extern FILE *sh_mktmpfp __P((char *, int, char **)); | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | /* **************************************************************** */ | 
					
						
							|  |  |  | /*								    */ | 
					
						
							|  |  |  | /*	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) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | 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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-15 16:59:08 -04:00
										 |  |  | static void | 
					
						
							|  |  |  | set_verbose_flag () | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   echo_input_at_read = verbose_flag; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | /* String to execute on a file that we want to edit. */ | 
					
						
							|  |  |  | #define FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-vi}}" | 
					
						
							| 
									
										
										
										
											2005-12-07 14:08:12 +00:00
										 |  |  | #if defined (STRICT_POSIX) | 
					
						
							|  |  |  | #  define POSIX_FC_EDIT_COMMAND "${FCEDIT:-ed}" | 
					
						
							|  |  |  | #else | 
					
						
							|  |  |  | #  define POSIX_FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-ed}}" | 
					
						
							|  |  |  | #endif | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | int | 
					
						
							|  |  |  | fc_builtin (list) | 
					
						
							|  |  |  |      WORD_LIST *list; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   register int i; | 
					
						
							|  |  |  |   register char *sep; | 
					
						
							|  |  |  |   int numbering, reverse, listing, execute; | 
					
						
							| 
									
										
										
										
											2014-02-26 09:36:43 -05:00
										 |  |  |   int histbeg, histend, last_hist, retval, opt, rh, real_last; | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |   FILE *stream; | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |   REPL *rlist, *rl; | 
					
						
							| 
									
										
										
										
											2005-12-07 14:08:12 +00:00
										 |  |  |   char *ename, *command, *newcom, *fcedit; | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |   HIST_ENTRY **hlist; | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  |   char *fn; | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   numbering = 1; | 
					
						
							|  |  |  |   reverse = listing = execute = 0; | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |   ename = (char *)NULL; | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* Parse out the options and set which of the two forms we're in. */ | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |   reset_internal_getopt (); | 
					
						
							|  |  |  |   lcurrent = list;		/* XXX */ | 
					
						
							|  |  |  |   while (fc_number (loptend = lcurrent) == 0 && | 
					
						
							|  |  |  | 	 (opt = internal_getopt (list, ":e:lnrs")) != -1) | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |       switch (opt) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	case 'n': | 
					
						
							|  |  |  | 	  numbering = 0; | 
					
						
							|  |  |  | 	  break; | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | 	case 'l': | 
					
						
							|  |  |  | 	  listing = 1; | 
					
						
							|  |  |  | 	  break; | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | 	case 'r': | 
					
						
							|  |  |  | 	  reverse = 1; | 
					
						
							|  |  |  | 	  break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case 's': | 
					
						
							|  |  |  | 	  execute = 1; | 
					
						
							|  |  |  | 	  break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case 'e': | 
					
						
							|  |  |  | 	  ename = list_optarg; | 
					
						
							|  |  |  | 	  break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-15 16:59:08 -04:00
										 |  |  | 	CASE_HELPOPT; | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | 	default: | 
					
						
							|  |  |  | 	  builtin_usage (); | 
					
						
							|  |  |  | 	  return (EX_USAGE); | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |   list = loptend; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |   if (ename && (*ename == '-') && (ename[1] == '\0')) | 
					
						
							|  |  |  |     execute = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* The "execute" form of the command (re-run, with possible string | 
					
						
							|  |  |  |      substitutions). */ | 
					
						
							|  |  |  |   if (execute) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |       rlist = (REPL *)NULL; | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |       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. */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |       rlist = REVERSE_LIST (rlist, REPL *); | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |       hlist = history_list (); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       /* If we still have something in list, it is a command spec. | 
					
						
							|  |  |  | 	 Otherwise, we use the most recent command in time. */ | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |       command = fc_gethist (list ? list->word->word : (char *)NULL, hlist); | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |       if (command == NULL) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  | 	  builtin_error (_("no command found")); | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 	  if (rlist) | 
					
						
							|  |  |  | 	    FREE_RLIST (); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	  return (EXECUTION_FAILURE); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (rlist) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  newcom = fc_dosubs (command, rlist); | 
					
						
							|  |  |  | 	  free (command); | 
					
						
							|  |  |  | 	  FREE_RLIST (); | 
					
						
							|  |  |  | 	  command = newcom; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |       fprintf (stderr, "%s\n", command); | 
					
						
							|  |  |  |       fc_replhist (command);	/* replace `fc -s' with command */ | 
					
						
							| 
									
										
										
										
											2011-11-21 20:49:12 -05:00
										 |  |  |       /* Posix says that the re-executed commands should be entered into the | 
					
						
							|  |  |  | 	 history. */ | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  |       return (parse_and_execute (command, "fc", SEVAL_NOHIST)); | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   /* 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 | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  |      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. */ | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-21 20:49:12 -05:00
										 |  |  |   /* 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; | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-26 09:36:43 -05:00
										 |  |  |   /* Make sure that real_last is calculated the same way here and in | 
					
						
							|  |  |  |      fc_gethnum.  The return value from fc_gethnum is treated specially if | 
					
						
							|  |  |  |      it is == real_last and we are listing commands. */ | 
					
						
							|  |  |  |   real_last = i; | 
					
						
							|  |  |  |   /* back up from the end to the last non-null history entry */ | 
					
						
							|  |  |  |   while (hlist[real_last] == 0 && real_last > 0) | 
					
						
							|  |  |  |     real_last--; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-21 20:57:16 -05:00
										 |  |  |   /* XXX */ | 
					
						
							| 
									
										
										
										
											2011-11-22 20:00:53 -05:00
										 |  |  |   if (i == last_hist && hlist[last_hist] == 0) | 
					
						
							| 
									
										
										
										
											2011-11-21 20:57:16 -05:00
										 |  |  |     while (last_hist >= 0 && hlist[last_hist] == 0) | 
					
						
							|  |  |  |       last_hist--; | 
					
						
							|  |  |  |   if (last_hist < 0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       sh_erange ((char *)NULL, _("history specification")); | 
					
						
							|  |  |  |       return (EXECUTION_FAILURE); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |   if (list) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       histbeg = fc_gethnum (list->word->word, hlist); | 
					
						
							|  |  |  |       list = list->next; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (list) | 
					
						
							|  |  |  | 	histend = fc_gethnum (list->word->word, hlist); | 
					
						
							| 
									
										
										
										
											2014-02-26 09:36:43 -05:00
										 |  |  |       else if (histbeg == real_last) | 
					
						
							|  |  |  | 	histend = listing ? real_last : histbeg; | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |       else | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | 	histend = listing ? last_hist : histbeg; | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |     } | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       /* The default for listing is the last 16 history items. */ | 
					
						
							|  |  |  |       if (listing) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 	  histend = last_hist; | 
					
						
							| 
									
										
										
										
											2005-12-07 14:08:12 +00:00
										 |  |  | 	  histbeg = histend - 16 + 1;	/* +1 because loop below uses >= */ | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 	  if (histbeg < 0) | 
					
						
							|  |  |  | 	    histbeg = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |       else | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | 	/* For editing, it is the last history command. */ | 
					
						
							|  |  |  | 	histbeg = histend = last_hist; | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |   /* "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; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |   /* We print error messages for line specifications out of range. */ | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |   if ((histbeg < 0) || (histend < 0)) | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  |       sh_erange ((char *)NULL, _("history specification")); | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |       return (EXECUTION_FAILURE); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (histend < histbeg) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |       i = histend; | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |       histend = histbeg; | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |       histbeg = i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |       reverse = 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (listing) | 
					
						
							|  |  |  |     stream = stdout; | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       numbering = 0; | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  |       stream = sh_mktmpfp ("bash-fc", MT_USERANDOM|MT_USETMPDIR, &fn); | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |       if (stream == 0) | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2004-07-27 13:29:18 +00:00
										 |  |  | 	  builtin_error (_("%s: cannot open temp file: %s"), fn ? fn : "", strerror (errno)); | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  | 	  FREE (fn); | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 	  return (EXECUTION_FAILURE); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |   for (i = reverse ? histend : histbeg; reverse ? i >= histbeg : i <= histend; reverse ? i-- : i++) | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |       QUIT; | 
					
						
							|  |  |  |       if (numbering) | 
					
						
							|  |  |  | 	fprintf (stream, "%d", i + history_base); | 
					
						
							|  |  |  |       if (listing) | 
					
						
							| 
									
										
										
										
											2005-12-07 14:08:12 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 	  if (posixly_correct) | 
					
						
							|  |  |  | 	    fputs ("\t", stream); | 
					
						
							|  |  |  | 	  else | 
					
						
							|  |  |  | 	    fprintf (stream, "\t%c", histdata (i) ? '*' : ' '); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |       fprintf (stream, "%s\n", histline (i)); | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (listing) | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |     return (sh_chkwrite (EXECUTION_SUCCESS)); | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |   fflush (stream); | 
					
						
							|  |  |  |   if (ferror (stream)) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       sh_wrerror (); | 
					
						
							|  |  |  |       fclose (stream); | 
					
						
							|  |  |  |       return (EXECUTION_FAILURE); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |   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 | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2005-12-07 14:08:12 +00:00
										 |  |  |       fcedit = posixly_correct ? POSIX_FC_EDIT_COMMAND : FC_EDIT_COMMAND; | 
					
						
							|  |  |  |       command = (char *)xmalloc (3 + strlen (fcedit) + strlen (fn)); | 
					
						
							|  |  |  |       sprintf (command, "%s %s", fcedit, fn); | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  |   retval = parse_and_execute (command, "fc", SEVAL_NOHIST); | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |   if (retval != EXECUTION_SUCCESS) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       unlink (fn); | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  |       free (fn); | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |       return (EXECUTION_FAILURE); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-15 16:59:08 -04:00
										 |  |  | #if defined (READLINE) | 
					
						
							|  |  |  |   /* If we're executing as part of a dispatched readline commnand like | 
					
						
							|  |  |  |      {emacs,vi}_edit_and_execute_command, the readline state will indicate it. | 
					
						
							|  |  |  |      We could remove the partial command from the history, but ksh93 doesn't | 
					
						
							|  |  |  |      so we stay compatible. */ | 
					
						
							|  |  |  | #endif | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  |   /* 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; | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  |   /* Turn on the `v' flag while fc_execute_file runs so the commands | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |      will be echoed as they are read by the parser. */ | 
					
						
							|  |  |  |   begin_unwind_frame ("fc builtin"); | 
					
						
							| 
									
										
										
										
											2001-04-06 19:14:31 +00:00
										 |  |  |   add_unwind_protect ((Function *)xfree, fn); | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |   add_unwind_protect (unlink, fn); | 
					
						
							| 
									
										
										
										
											2016-09-15 16:59:08 -04:00
										 |  |  |   add_unwind_protect (set_verbose_flag, (char *)NULL); | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |   echo_input_at_read = 1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-15 16:59:08 -04:00
										 |  |  |   retval = fc_execute_file (fn); | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |   run_unwind_frame ("fc builtin"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   return (retval); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | /* 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++; | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  |   return (legal_number (s, (intmax_t *)NULL)); | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | /* 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; | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-11-21 20:49:12 -05:00
										 |  |  |   int sign, n, clen, rh; | 
					
						
							| 
									
										
										
										
											2014-02-26 09:36:43 -05:00
										 |  |  |   register int i, j, last_hist, real_last; | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |   register char *s; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |   sign = 1; | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |   /* 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 | 
					
						
							| 
									
										
										
										
											1997-06-05 14:59:13 +00:00
										 |  |  |      the user entered before the fc.  We need to check whether the | 
					
						
							|  |  |  |      line was actually added (HISTIGNORE may have caused it to not be), | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |      so we check hist_last_line_added.  This needs to agree with the | 
					
						
							|  |  |  |      calculation of last_hist in fc_builtin above. */ | 
					
						
							| 
									
										
										
										
											2011-11-21 20:49:12 -05:00
										 |  |  |   /* 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); | 
					
						
							| 
									
										
										
										
											2011-11-22 20:00:53 -05:00
										 |  |  |   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); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-26 09:36:43 -05:00
										 |  |  |   real_last = i; | 
					
						
							| 
									
										
										
										
											2011-11-22 20:00:53 -05:00
										 |  |  |   i = last_hist; | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |   /* No specification defaults to most recent command. */ | 
					
						
							|  |  |  |   if (command == NULL) | 
					
						
							|  |  |  |     return (i); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-26 09:36:43 -05:00
										 |  |  |   /* back up from the end to the last non-null history entry */ | 
					
						
							|  |  |  |   while (hlist[real_last] == 0 && real_last > 0) | 
					
						
							|  |  |  |     real_last--; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |   /* 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++; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  |   if (s && DIGIT(*s)) | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |     { | 
					
						
							|  |  |  |       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) | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 	  n += i + 1; | 
					
						
							|  |  |  | 	  return (n < 0 ? 0 : n); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |       else if (n == 0) | 
					
						
							| 
									
										
										
										
											2014-02-26 09:36:43 -05:00
										 |  |  | 	return ((sign == -1) ? real_last : i); | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |       else | 
					
						
							| 
									
										
										
										
											2002-07-17 14:10:11 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 	  n -= history_base; | 
					
						
							|  |  |  | 	  return (i < n ? i : n); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-07 14:08:12 +00:00
										 |  |  |   if (hlist == 0) | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |     return ((char *)NULL); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   i = fc_gethnum (command, hlist); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (i >= 0) | 
					
						
							|  |  |  |     return (savestring (histline (i))); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     return ((char *)NULL); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | #ifdef INCLUDE_UNUSED | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | /* 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) | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | 	line = (char *)xrealloc (line, (line_len += 128)); | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |       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); | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | #endif | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* 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; | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |   register char *new, *t; | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |   register REPL *r; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |   for (new = savestring (command), r = subs; r; r = r->next) | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |       t = strsub (new, r->pat, r->rep, 1); | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |       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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-12-23 17:02:34 +00:00
										 |  |  |   if (command == 0 || *command == '\0') | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   n = strlen (command); | 
					
						
							|  |  |  |   if (command[n - 1] == '\n') | 
					
						
							|  |  |  |     command[n - 1] = '\0'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (command && *command) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2009-01-12 13:36:28 +00:00
										 |  |  |       bash_delete_last_history (); | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |       maybe_add_history (command);	/* Obeys HISTCONTROL setting. */ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | #ifdef INCLUDE_UNUSED | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | /* Add LINE to the history, after removing a single trailing newline. */ | 
					
						
							|  |  |  | static void | 
					
						
							|  |  |  | fc_addhist (line) | 
					
						
							|  |  |  |      char *line; | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   register int n; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-12-07 14:08:12 +00:00
										 |  |  |   if (line == 0 || *line == 0) | 
					
						
							|  |  |  |     return; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  |   n = strlen (line); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (line[n - 1] == '\n') | 
					
						
							|  |  |  |     line[n - 1] = '\0'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if (line && *line) | 
					
						
							| 
									
										
										
										
											2005-12-07 14:08:12 +00:00
										 |  |  |     maybe_add_history (line);		/* Obeys HISTCONTROL setting. */ | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2001-11-13 17:56:06 +00:00
										 |  |  | #endif | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											1996-08-26 18:22:31 +00:00
										 |  |  | #endif /* HISTORY */ |