1This file is fc.def, from which is created fc.c. 2It implements the builtin "fc" in Bash. 3 4Copyright (C) 1987-2005 Free Software Foundation, Inc. 5 6This file is part of GNU Bash, the Bourne Again SHell. 7 8Bash is free software; you can redistribute it and/or modify it under 9the terms of the GNU General Public License as published by the Free 10Software Foundation; either version 2, or (at your option) any later 11version. 12 13Bash is distributed in the hope that it will be useful, but WITHOUT ANY 14WARRANTY; without even the implied warranty of MERCHANTABILITY or 15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16for more details. 17 18You should have received a copy of the GNU General Public License along 19with Bash; see the file COPYING. If not, write to the Free Software 20Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. 21 22$PRODUCES fc.c 23 24$BUILTIN fc 25$FUNCTION fc_builtin 26$DEPENDS_ON HISTORY 27$SHORT_DOC fc [-e ename] [-nlr] [first] [last] or fc -s [pat=rep] [cmd] 28fc is used to list or edit and re-execute commands from the history list. 29FIRST and LAST can be numbers specifying the range, or FIRST can be a 30string, which means the most recent command beginning with that 31string. 32 33 -e ENAME selects which editor to use. Default is FCEDIT, then EDITOR, 34 then vi. 35 36 -l means list lines instead of editing. 37 -n means no line numbers listed. 38 -r means reverse the order of the lines (making it newest listed first). 39 40With the `fc -s [pat=rep ...] [command]' format, the command is 41re-executed after the substitution OLD=NEW is performed. 42 43A useful alias to use with this is r='fc -s', so that typing `r cc' 44runs the last command beginning with `cc' and typing `r' re-executes 45the last command. 46$END 47 48#include <config.h> 49 50#if defined (HISTORY) 51#ifndef _MINIX 52# include <sys/param.h> 53#endif 54#include "../bashtypes.h" 55#include "posixstat.h" 56#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H) 57# include <sys/file.h> 58#endif 59 60#if defined (HAVE_UNISTD_H) 61# include <unistd.h> 62#endif 63 64#include <stdio.h> 65#include <chartypes.h> 66 67#include "../bashansi.h" 68#include "../bashintl.h" 69#include <errno.h> 70 71#include "../shell.h" 72#include "../builtins.h" 73#include "../flags.h" 74#include "../bashhist.h" 75#include "maxpath.h" 76#include <readline/history.h> 77#include "bashgetopt.h" 78#include "common.h" 79 80#if !defined (errno) 81extern int errno; 82#endif /* !errno */ 83 84extern int current_command_line_count; 85extern int literal_history; 86extern int posixly_correct; 87 88extern int unlink __P((const char *)); 89 90extern FILE *sh_mktmpfp __P((char *, int, char **)); 91extern int delete_last_history __P((void)); 92 93/* **************************************************************** */ 94/* */ 95/* The K*rn shell style fc command (Fix Command) */ 96/* */ 97/* **************************************************************** */ 98 99/* fc builtin command (fix command) for Bash for those who 100 like K*rn-style history better than csh-style. 101 102 fc [-e ename] [-nlr] [first] [last] 103 104 FIRST and LAST can be numbers specifying the range, or FIRST can be 105 a string, which means the most recent command beginning with that 106 string. 107 108 -e ENAME selects which editor to use. Default is FCEDIT, then EDITOR, 109 then the editor which corresponds to the current readline editing 110 mode, then vi. 111 112 -l means list lines instead of editing. 113 -n means no line numbers listed. 114 -r means reverse the order of the lines (making it newest listed first). 115 116 fc -e - [pat=rep ...] [command] 117 fc -s [pat=rep ...] [command] 118 119 Equivalent to !command:sg/pat/rep execpt there can be multiple PAT=REP's. 120*/ 121 122/* Data structure describing a list of global replacements to perform. */ 123typedef struct repl { 124 struct repl *next; 125 char *pat; 126 char *rep; 127} REPL; 128 129/* Accessors for HIST_ENTRY lists that are called HLIST. */ 130#define histline(i) (hlist[(i)]->line) 131#define histdata(i) (hlist[(i)]->data) 132 133#define FREE_RLIST() \ 134 do { \ 135 for (rl = rlist; rl; ) { \ 136 REPL *r; \ 137 r = rl->next; \ 138 if (rl->pat) \ 139 free (rl->pat); \ 140 if (rl->rep) \ 141 free (rl->rep); \ 142 free (rl); \ 143 rl = r; \ 144 } \ 145 } while (0) 146 147static char *fc_dosubs __P((char *, REPL *)); 148static char *fc_gethist __P((char *, HIST_ENTRY **)); 149static int fc_gethnum __P((char *, HIST_ENTRY **)); 150static int fc_number __P((WORD_LIST *)); 151static void fc_replhist __P((char *)); 152#ifdef INCLUDE_UNUSED 153static char *fc_readline __P((FILE *)); 154static void fc_addhist __P((char *)); 155#endif 156 157/* String to execute on a file that we want to edit. */ 158#define FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-vi}}" 159#if defined (STRICT_POSIX) 160# define POSIX_FC_EDIT_COMMAND "${FCEDIT:-ed}" 161#else 162# define POSIX_FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-ed}}" 163#endif 164 165int 166fc_builtin (list) 167 WORD_LIST *list; 168{ 169 register int i; 170 register char *sep; 171 int numbering, reverse, listing, execute; 172 int histbeg, histend, last_hist, retval, opt; 173 FILE *stream; 174 REPL *rlist, *rl; 175 char *ename, *command, *newcom, *fcedit; 176 HIST_ENTRY **hlist; 177 char *fn; 178 179 numbering = 1; 180 reverse = listing = execute = 0; 181 ename = (char *)NULL; 182 183 /* Parse out the options and set which of the two forms we're in. */ 184 reset_internal_getopt (); 185 lcurrent = list; /* XXX */ 186 while (fc_number (loptend = lcurrent) == 0 && 187 (opt = internal_getopt (list, ":e:lnrs")) != -1) 188 { 189 switch (opt) 190 { 191 case 'n': 192 numbering = 0; 193 break; 194 195 case 'l': 196 listing = 1; 197 break; 198 199 case 'r': 200 reverse = 1; 201 break; 202 203 case 's': 204 execute = 1; 205 break; 206 207 case 'e': 208 ename = list_optarg; 209 break; 210 211 default: 212 builtin_usage (); 213 return (EX_USAGE); 214 } 215 } 216 217 list = loptend; 218 219 if (ename && (*ename == '-') && (ename[1] == '\0')) 220 execute = 1; 221 222 /* The "execute" form of the command (re-run, with possible string 223 substitutions). */ 224 if (execute) 225 { 226 rlist = (REPL *)NULL; 227 while (list && ((sep = (char *)strchr (list->word->word, '=')) != NULL)) 228 { 229 *sep++ = '\0'; 230 rl = (REPL *)xmalloc (sizeof (REPL)); 231 rl->next = (REPL *)NULL; 232 rl->pat = savestring (list->word->word); 233 rl->rep = savestring (sep); 234 235 if (rlist == NULL) 236 rlist = rl; 237 else 238 { 239 rl->next = rlist; 240 rlist = rl; 241 } 242 list = list->next; 243 } 244 245 /* If we have a list of substitutions to do, then reverse it 246 to get the replacements in the proper order. */ 247 248 rlist = REVERSE_LIST (rlist, REPL *); 249 250 hlist = history_list (); 251 252 /* If we still have something in list, it is a command spec. 253 Otherwise, we use the most recent command in time. */ 254 command = fc_gethist (list ? list->word->word : (char *)NULL, hlist); 255 256 if (command == NULL) 257 { 258 builtin_error (_("no command found")); 259 if (rlist) 260 FREE_RLIST (); 261 262 return (EXECUTION_FAILURE); 263 } 264 265 if (rlist) 266 { 267 newcom = fc_dosubs (command, rlist); 268 free (command); 269 FREE_RLIST (); 270 command = newcom; 271 } 272 273 fprintf (stderr, "%s\n", command); 274 fc_replhist (command); /* replace `fc -s' with command */ 275 return (parse_and_execute (command, "fc", SEVAL_NOHIST)); 276 } 277 278 /* This is the second form of the command (the list-or-edit-and-rerun 279 form). */ 280 hlist = history_list (); 281 if (hlist == 0) 282 return (EXECUTION_SUCCESS); 283 for (i = 0; hlist[i]; i++); 284 285 /* With the Bash implementation of history, the current command line 286 ("fc blah..." and so on) is already part of the history list by 287 the time we get to this point. This just skips over that command 288 and makes the last command that this deals with be the last command 289 the user entered before the fc. We need to check whether the 290 line was actually added (HISTIGNORE may have caused it to not be), 291 so we check hist_last_line_added. */ 292 293 /* "When not listing, he fc command that caused the editing shall not be 294 entered into the history list." */ 295 if (listing == 0 && hist_last_line_added) 296 delete_last_history (); 297 298 last_hist = i - 1 - hist_last_line_added; 299 300 if (list) 301 { 302 histbeg = fc_gethnum (list->word->word, hlist); 303 list = list->next; 304 305 if (list) 306 histend = fc_gethnum (list->word->word, hlist); 307 else 308 histend = listing ? last_hist : histbeg; 309 } 310 else 311 { 312 /* The default for listing is the last 16 history items. */ 313 if (listing) 314 { 315 histend = last_hist; 316 histbeg = histend - 16 + 1; /* +1 because loop below uses >= */ 317 if (histbeg < 0) 318 histbeg = 0; 319 } 320 else 321 /* For editing, it is the last history command. */ 322 histbeg = histend = last_hist; 323 } 324 325 /* We print error messages for line specifications out of range. */ 326 if ((histbeg < 0) || (histend < 0)) 327 { 328 sh_erange ((char *)NULL, _("history specification")); 329 return (EXECUTION_FAILURE); 330 } 331 332 if (histend < histbeg) 333 { 334 i = histend; 335 histend = histbeg; 336 histbeg = i; 337 338 reverse = 1; 339 } 340 341 if (listing) 342 stream = stdout; 343 else 344 { 345 numbering = 0; 346 stream = sh_mktmpfp ("bash-fc", MT_USERANDOM|MT_USETMPDIR, &fn); 347 if (stream == 0) 348 { 349 builtin_error (_("%s: cannot open temp file: %s"), fn ? fn : "", strerror (errno)); 350 FREE (fn); 351 return (EXECUTION_FAILURE); 352 } 353 } 354 355 for (i = reverse ? histend : histbeg; reverse ? i >= histbeg : i <= histend; reverse ? i-- : i++) 356 { 357 QUIT; 358 if (numbering) 359 fprintf (stream, "%d", i + history_base); 360 if (listing) 361 { 362 if (posixly_correct) 363 fputs ("\t", stream); 364 else 365 fprintf (stream, "\t%c", histdata (i) ? '*' : ' '); 366 } 367 fprintf (stream, "%s\n", histline (i)); 368 } 369 370 if (listing) 371 return (EXECUTION_SUCCESS); 372 373 fclose (stream); 374 375 /* Now edit the file of commands. */ 376 if (ename) 377 { 378 command = (char *)xmalloc (strlen (ename) + strlen (fn) + 2); 379 sprintf (command, "%s %s", ename, fn); 380 } 381 else 382 { 383 fcedit = posixly_correct ? POSIX_FC_EDIT_COMMAND : FC_EDIT_COMMAND; 384 command = (char *)xmalloc (3 + strlen (fcedit) + strlen (fn)); 385 sprintf (command, "%s %s", fcedit, fn); 386 } 387 retval = parse_and_execute (command, "fc", SEVAL_NOHIST); 388 if (retval != EXECUTION_SUCCESS) 389 { 390 unlink (fn); 391 free (fn); 392 return (EXECUTION_FAILURE); 393 } 394 395 /* Make sure parse_and_execute doesn't turn this off, even though a 396 call to parse_and_execute farther up the function call stack (e.g., 397 if this is called by vi_edit_and_execute_command) may have already 398 called bash_history_disable. */ 399 remember_on_history = 1; 400 401 /* Turn on the `v' flag while fc_execute_file runs so the commands 402 will be echoed as they are read by the parser. */ 403 begin_unwind_frame ("fc builtin"); 404 add_unwind_protect ((Function *)xfree, fn); 405 add_unwind_protect (unlink, fn); 406 unwind_protect_int (echo_input_at_read); 407 echo_input_at_read = 1; 408 409 retval = fc_execute_file (fn); 410 411 run_unwind_frame ("fc builtin"); 412 413 return (retval); 414} 415 416/* Return 1 if LIST->word->word is a legal number for fc's use. */ 417static int 418fc_number (list) 419 WORD_LIST *list; 420{ 421 char *s; 422 423 if (list == 0) 424 return 0; 425 s = list->word->word; 426 if (*s == '-') 427 s++; 428 return (legal_number (s, (intmax_t *)NULL)); 429} 430 431/* Return an absolute index into HLIST which corresponds to COMMAND. If 432 COMMAND is a number, then it was specified in relative terms. If it 433 is a string, then it is the start of a command line present in HLIST. */ 434static int 435fc_gethnum (command, hlist) 436 char *command; 437 HIST_ENTRY **hlist; 438{ 439 int sign = 1, n, clen; 440 register int i, j; 441 register char *s; 442 443 /* Count history elements. */ 444 for (i = 0; hlist[i]; i++); 445 446 /* With the Bash implementation of history, the current command line 447 ("fc blah..." and so on) is already part of the history list by 448 the time we get to this point. This just skips over that command 449 and makes the last command that this deals with be the last command 450 the user entered before the fc. We need to check whether the 451 line was actually added (HISTIGNORE may have caused it to not be), 452 so we check hist_last_line_added. */ 453 i -= 1 + hist_last_line_added; 454 455 /* No specification defaults to most recent command. */ 456 if (command == NULL) 457 return (i); 458 459 /* Otherwise, there is a specification. It can be a number relative to 460 the current position, or an absolute history number. */ 461 s = command; 462 463 /* Handle possible leading minus sign. */ 464 if (s && (*s == '-')) 465 { 466 sign = -1; 467 s++; 468 } 469 470 if (s && DIGIT(*s)) 471 { 472 n = atoi (s); 473 n *= sign; 474 475 /* If the value is negative or zero, then it is an offset from 476 the current history item. */ 477 if (n < 0) 478 { 479 n += i + 1; 480 return (n < 0 ? 0 : n); 481 } 482 else if (n == 0) 483 return (i); 484 else 485 { 486 n -= history_base; 487 return (i < n ? i : n); 488 } 489 } 490 491 clen = strlen (command); 492 for (j = i; j >= 0; j--) 493 { 494 if (STREQN (command, histline (j), clen)) 495 return (j); 496 } 497 return (-1); 498} 499 500/* Locate the most recent history line which begins with 501 COMMAND in HLIST, and return a malloc()'ed copy of it. */ 502static char * 503fc_gethist (command, hlist) 504 char *command; 505 HIST_ENTRY **hlist; 506{ 507 int i; 508 509 if (hlist == 0) 510 return ((char *)NULL); 511 512 i = fc_gethnum (command, hlist); 513 514 if (i >= 0) 515 return (savestring (histline (i))); 516 else 517 return ((char *)NULL); 518} 519 520#ifdef INCLUDE_UNUSED 521/* Read the edited history lines from STREAM and return them 522 one at a time. This can read unlimited length lines. The 523 caller should free the storage. */ 524static char * 525fc_readline (stream) 526 FILE *stream; 527{ 528 register int c; 529 int line_len = 0, lindex = 0; 530 char *line = (char *)NULL; 531 532 while ((c = getc (stream)) != EOF) 533 { 534 if ((lindex + 2) >= line_len) 535 line = (char *)xrealloc (line, (line_len += 128)); 536 537 if (c == '\n') 538 { 539 line[lindex++] = '\n'; 540 line[lindex++] = '\0'; 541 return (line); 542 } 543 else 544 line[lindex++] = c; 545 } 546 547 if (!lindex) 548 { 549 if (line) 550 free (line); 551 552 return ((char *)NULL); 553 } 554 555 if (lindex + 2 >= line_len) 556 line = (char *)xrealloc (line, lindex + 3); 557 558 line[lindex++] = '\n'; /* Finish with newline if none in file */ 559 line[lindex++] = '\0'; 560 return (line); 561} 562#endif 563 564/* Perform the SUBS on COMMAND. 565 SUBS is a list of substitutions, and COMMAND is a simple string. 566 Return a pointer to a malloc'ed string which contains the substituted 567 command. */ 568static char * 569fc_dosubs (command, subs) 570 char *command; 571 REPL *subs; 572{ 573 register char *new, *t; 574 register REPL *r; 575 576 for (new = savestring (command), r = subs; r; r = r->next) 577 { 578 t = strsub (new, r->pat, r->rep, 1); 579 free (new); 580 new = t; 581 } 582 return (new); 583} 584 585/* Use `command' to replace the last entry in the history list, which, 586 by this time, is `fc blah...'. The intent is that the new command 587 become the history entry, and that `fc' should never appear in the 588 history list. This way you can do `r' to your heart's content. */ 589static void 590fc_replhist (command) 591 char *command; 592{ 593 int n; 594 595 if (command == 0 || *command == '\0') 596 return; 597 598 n = strlen (command); 599 if (command[n - 1] == '\n') 600 command[n - 1] = '\0'; 601 602 if (command && *command) 603 { 604 delete_last_history (); 605 maybe_add_history (command); /* Obeys HISTCONTROL setting. */ 606 } 607} 608 609#ifdef INCLUDE_UNUSED 610/* Add LINE to the history, after removing a single trailing newline. */ 611static void 612fc_addhist (line) 613 char *line; 614{ 615 register int n; 616 617 if (line == 0 || *line == 0) 618 return; 619 620 n = strlen (line); 621 622 if (line[n - 1] == '\n') 623 line[n - 1] = '\0'; 624 625 if (line && *line) 626 maybe_add_history (line); /* Obeys HISTCONTROL setting. */ 627} 628#endif 629 630#endif /* HISTORY */ 631