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