Release 2.33.1
[external/binutils.git] / readline / histfile.c
1 /* histfile.c - functions to manipulate the history file. */
2
3 /* Copyright (C) 1989-2018 Free Software Foundation, Inc.
4
5    This file contains the GNU History Library (History), a set of
6    routines for managing the text of previously typed lines.
7
8    History is free software: you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation, either version 3 of the License, or
11    (at your option) any later version.
12
13    History is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with History.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 /* The goal is to make the implementation transparent, so that you
23    don't have to know what data types are used, just what functions
24    you can call.  I think I have done that. */
25
26 #define READLINE_LIBRARY
27
28 #if defined (__TANDEM)
29 #  include <floss.h>
30 #endif
31
32 #if defined (HAVE_CONFIG_H)
33 #  include <config.h>
34 #endif
35
36 #include <stdio.h>
37
38 #if defined (HAVE_LIMITS_H)
39 #  include <limits.h>
40 #endif
41
42 #include <sys/types.h>
43 #if ! defined (_MINIX) && defined (HAVE_SYS_FILE_H)
44 #  include <sys/file.h>
45 #endif
46 #include "posixstat.h"
47 #include <fcntl.h>
48
49 #if defined (HAVE_STDLIB_H)
50 #  include <stdlib.h>
51 #else
52 #  include "ansi_stdlib.h"
53 #endif /* HAVE_STDLIB_H */
54
55 #if defined (HAVE_UNISTD_H)
56 #  include <unistd.h>
57 #endif
58
59 #include <ctype.h>
60
61 #if defined (__EMX__)
62 #  undef HAVE_MMAP
63 #endif
64
65 #ifdef HISTORY_USE_MMAP
66 #  include <sys/mman.h>
67
68 #  ifdef MAP_FILE
69 #    define MAP_RFLAGS  (MAP_FILE|MAP_PRIVATE)
70 #    define MAP_WFLAGS  (MAP_FILE|MAP_SHARED)
71 #  else
72 #    define MAP_RFLAGS  MAP_PRIVATE
73 #    define MAP_WFLAGS  MAP_SHARED
74 #  endif
75
76 #  ifndef MAP_FAILED
77 #    define MAP_FAILED  ((void *)-1)
78 #  endif
79
80 #endif /* HISTORY_USE_MMAP */
81
82 /* If we're compiling for __EMX__ (OS/2) or __CYGWIN__ (cygwin32 environment
83    on win 95/98/nt), we want to open files with O_BINARY mode so that there
84    is no \n -> \r\n conversion performed.  On other systems, we don't want to
85    mess around with O_BINARY at all, so we ensure that it's defined to 0. */
86 #if defined (__EMX__) || defined (__CYGWIN__)
87 #  ifndef O_BINARY
88 #    define O_BINARY 0
89 #  endif
90 #else /* !__EMX__ && !__CYGWIN__ */
91 #  undef O_BINARY
92 #  define O_BINARY 0
93 #endif /* !__EMX__ && !__CYGWIN__ */
94
95 #include <errno.h>
96 #if !defined (errno)
97 extern int errno;
98 #endif /* !errno */
99
100 #include "history.h"
101 #include "histlib.h"
102
103 #include "rlshell.h"
104 #include "xmalloc.h"
105
106 #if !defined (PATH_MAX)
107 #  define PATH_MAX      1024    /* default */
108 #endif
109
110 extern void _hs_append_history_line PARAMS((int, const char *));
111
112 /* history file version; currently unused */
113 int history_file_version = 1;
114
115 /* If non-zero, we write timestamps to the history file in history_do_write() */
116 int history_write_timestamps = 0;
117
118 /* If non-zero, we assume that a history file that starts with a timestamp
119    uses timestamp-delimited entries and can include multi-line history
120    entries. Used by read_history_range */
121 int history_multiline_entries = 0;
122
123 /* Immediately after a call to read_history() or read_history_range(), this
124    will return the number of lines just read from the history file in that
125    call. */
126 int history_lines_read_from_file = 0;
127
128 /* Immediately after a call to write_history() or history_do_write(), this
129    will return the number of lines just written to the history file in that
130    call.  This also works with history_truncate_file. */
131 int history_lines_written_to_file = 0;
132
133 /* Does S look like the beginning of a history timestamp entry?  Placeholder
134    for more extensive tests. */
135 #define HIST_TIMESTAMP_START(s)         (*(s) == history_comment_char && isdigit ((unsigned char)(s)[1]) )
136
137 static char *history_backupfile PARAMS((const char *));
138 static char *history_tempfile PARAMS((const char *));
139 static int histfile_backup PARAMS((const char *, const char *));
140 static int histfile_restore PARAMS((const char *, const char *));
141
142 /* Return the string that should be used in the place of this
143    filename.  This only matters when you don't specify the
144    filename to read_history (), or write_history (). */
145 static char *
146 history_filename (const char *filename)
147 {
148   char *return_val;
149   const char *home;
150   int home_len;
151
152   return_val = filename ? savestring (filename) : (char *)NULL;
153
154   if (return_val)
155     return (return_val);
156   
157   home = sh_get_env_value ("HOME");
158 #if defined (_WIN32)
159   if (home == 0)
160     home = sh_get_env_value ("APPDATA");
161 #endif
162
163   if (home == 0)
164     return (NULL);
165   else
166     home_len = strlen (home);
167
168   return_val = (char *)xmalloc (2 + home_len + 8); /* strlen(".history") == 8 */
169   strcpy (return_val, home);
170   return_val[home_len] = '/';
171 #if defined (__MSDOS__)
172   strcpy (return_val + home_len + 1, "_history");
173 #else
174   strcpy (return_val + home_len + 1, ".history");
175 #endif
176
177   return (return_val);
178 }
179
180 static char *
181 history_backupfile (const char *filename)
182 {
183   const char *fn;
184   char *ret, linkbuf[PATH_MAX+1];
185   size_t len;
186   ssize_t n;
187   struct stat fs;
188
189   fn = filename;  
190 #if defined (HAVE_READLINK)
191   /* Follow symlink to avoid backing up symlink itself; call will fail if
192      not a symlink */
193   if ((n = readlink (filename, linkbuf, sizeof (linkbuf) - 1)) > 0)
194     {
195       linkbuf[n] = '\0';
196       fn = linkbuf;
197     }
198 #endif
199       
200   len = strlen (fn);
201   ret = xmalloc (len + 2);
202   strcpy (ret, fn);
203   ret[len] = '-';
204   ret[len+1] = '\0';
205   return ret;
206 }
207   
208 static char *
209 history_tempfile (const char *filename)
210 {
211   const char *fn;
212   char *ret, linkbuf[PATH_MAX+1];
213   size_t len;
214   ssize_t n;
215   struct stat fs;
216   int pid;
217
218   fn = filename;  
219 #if defined (HAVE_READLINK)
220   /* Follow symlink so tempfile created in the same directory as any symlinked
221      history file; call will fail if not a symlink */
222   if ((n = readlink (filename, linkbuf, sizeof (linkbuf) - 1)) > 0)
223     {
224       linkbuf[n] = '\0';
225       fn = linkbuf;
226     }
227 #endif
228       
229   len = strlen (fn);
230   ret = xmalloc (len + 11);
231   strcpy (ret, fn);
232
233   pid = (int)getpid ();
234
235   /* filename-PID.tmp */
236   ret[len] = '-';
237   ret[len+1] = (pid / 10000 % 10) + '0';
238   ret[len+2] = (pid / 1000 % 10) + '0';
239   ret[len+3] = (pid / 100 % 10) + '0';
240   ret[len+4] = (pid / 10 % 10) + '0';
241   ret[len+5] = (pid % 10) + '0';
242   strcpy (ret + len + 6, ".tmp");
243
244   return ret;
245 }
246   
247 /* Add the contents of FILENAME to the history list, a line at a time.
248    If FILENAME is NULL, then read from ~/.history.  Returns 0 if
249    successful, or errno if not. */
250 int
251 read_history (const char *filename)
252 {
253   return (read_history_range (filename, 0, -1));
254 }
255
256 /* Read a range of lines from FILENAME, adding them to the history list.
257    Start reading at the FROM'th line and end at the TO'th.  If FROM
258    is zero, start at the beginning.  If TO is less than FROM, read
259    until the end of the file.  If FILENAME is NULL, then read from
260    ~/.history.  Returns 0 if successful, or errno if not. */
261 int
262 read_history_range (const char *filename, int from, int to)
263 {
264   register char *line_start, *line_end, *p;
265   char *input, *buffer, *bufend, *last_ts;
266   int file, current_line, chars_read, has_timestamps, reset_comment_char;
267   struct stat finfo;
268   size_t file_size;
269 #if defined (EFBIG)
270   int overflow_errno = EFBIG;
271 #elif defined (EOVERFLOW)
272   int overflow_errno = EOVERFLOW;
273 #else
274   int overflow_errno = EIO;
275 #endif
276
277   history_lines_read_from_file = 0;
278
279   buffer = last_ts = (char *)NULL;
280   input = history_filename (filename);
281   file = input ? open (input, O_RDONLY|O_BINARY, 0666) : -1;
282
283   if ((file < 0) || (fstat (file, &finfo) == -1))
284     goto error_and_exit;
285
286   if (S_ISREG (finfo.st_mode) == 0)
287     {
288 #ifdef EFTYPE
289       errno = EFTYPE;
290 #else
291       errno = EINVAL;
292 #endif
293       goto error_and_exit;
294     }
295
296   file_size = (size_t)finfo.st_size;
297
298   /* check for overflow on very large files */
299   if (file_size != finfo.st_size || file_size + 1 < file_size)
300     {
301       errno = overflow_errno;
302       goto error_and_exit;
303     }
304
305   if (file_size == 0)
306     {
307       free (input);
308       return 0; /* don't waste time if we don't have to */
309     }
310
311 #ifdef HISTORY_USE_MMAP
312   /* We map read/write and private so we can change newlines to NULs without
313      affecting the underlying object. */
314   buffer = (char *)mmap (0, file_size, PROT_READ|PROT_WRITE, MAP_RFLAGS, file, 0);
315   if ((void *)buffer == MAP_FAILED)
316     {
317       errno = overflow_errno;
318       goto error_and_exit;
319     }
320   chars_read = file_size;
321 #else
322   buffer = (char *)malloc (file_size + 1);
323   if (buffer == 0)
324     {
325       errno = overflow_errno;
326       goto error_and_exit;
327     }
328
329   chars_read = read (file, buffer, file_size);
330 #endif
331   if (chars_read < 0)
332     {
333   error_and_exit:
334       if (errno != 0)
335         chars_read = errno;
336       else
337         chars_read = EIO;
338       if (file >= 0)
339         close (file);
340
341       FREE (input);
342 #ifndef HISTORY_USE_MMAP
343       FREE (buffer);
344 #endif
345
346       return (chars_read);
347     }
348
349   close (file);
350
351   /* Set TO to larger than end of file if negative. */
352   if (to < 0)
353     to = chars_read;
354
355   /* Start at beginning of file, work to end. */
356   bufend = buffer + chars_read;
357   *bufend = '\0';               /* null-terminate buffer for timestamp checks */
358   current_line = 0;
359
360   /* Heuristic: the history comment character rarely changes, so assume we
361      have timestamps if the buffer starts with `#[:digit:]' and temporarily
362      set history_comment_char so timestamp parsing works right */
363   reset_comment_char = 0;
364   if (history_comment_char == '\0' && buffer[0] == '#' && isdigit ((unsigned char)buffer[1]))
365     {
366       history_comment_char = '#';
367       reset_comment_char = 1;
368     }
369
370   has_timestamps = HIST_TIMESTAMP_START (buffer);
371   history_multiline_entries += has_timestamps && history_write_timestamps;  
372
373   /* Skip lines until we are at FROM. */
374   for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++)
375     if (*line_end == '\n')
376       {
377         p = line_end + 1;
378         /* If we see something we think is a timestamp, continue with this
379            line.  We should check more extensively here... */
380         if (HIST_TIMESTAMP_START(p) == 0)
381           current_line++;
382         line_start = p;
383       }
384
385   /* If there are lines left to gobble, then gobble them now. */
386   for (line_end = line_start; line_end < bufend; line_end++)
387     if (*line_end == '\n')
388       {
389         /* Change to allow Windows-like \r\n end of line delimiter. */
390         if (line_end > line_start && line_end[-1] == '\r')
391           line_end[-1] = '\0';
392         else
393           *line_end = '\0';
394
395         if (*line_start)
396           {
397             if (HIST_TIMESTAMP_START(line_start) == 0)
398               {
399                 if (last_ts == NULL && history_length > 0 && history_multiline_entries)
400                   _hs_append_history_line (history_length - 1, line_start);
401                 else
402                   add_history (line_start);
403                 if (last_ts)
404                   {
405                     add_history_time (last_ts);
406                     last_ts = NULL;
407                   }
408               }
409             else
410               {
411                 last_ts = line_start;
412                 current_line--;
413               }
414           }
415
416         current_line++;
417
418         if (current_line >= to)
419           break;
420
421         line_start = line_end + 1;
422       }
423
424   history_lines_read_from_file = current_line;
425   if (reset_comment_char)
426     history_comment_char = '\0';
427
428   FREE (input);
429 #ifndef HISTORY_USE_MMAP
430   FREE (buffer);
431 #else
432   munmap (buffer, file_size);
433 #endif
434
435   return (0);
436 }
437
438 /* Save FILENAME to BACK, handling case where FILENAME is a symlink
439    (e.g., ~/.bash_history -> .histfiles/.bash_history.$HOSTNAME) */
440 static int
441 histfile_backup (const char *filename, const char *back)
442 {
443 #if defined (HAVE_READLINK)
444   char linkbuf[PATH_MAX+1];
445   ssize_t n;
446
447   /* Follow to target of symlink to avoid renaming symlink itself */
448   if ((n = readlink (filename, linkbuf, sizeof (linkbuf) - 1)) > 0)
449     {
450       linkbuf[n] = '\0';
451       return (rename (linkbuf, back));
452     }
453 #endif
454   return (rename (filename, back));
455 }
456
457 /* Restore ORIG from BACKUP handling case where ORIG is a symlink
458    (e.g., ~/.bash_history -> .histfiles/.bash_history.$HOSTNAME) */
459 static int
460 histfile_restore (const char *backup, const char *orig)
461 {
462 #if defined (HAVE_READLINK)
463   char linkbuf[PATH_MAX+1];
464   ssize_t n;
465
466   /* Follow to target of symlink to avoid renaming symlink itself */
467   if ((n = readlink (orig, linkbuf, sizeof (linkbuf) - 1)) > 0)
468     {
469       linkbuf[n] = '\0';
470       return (rename (backup, linkbuf));
471     }
472 #endif
473   return (rename (backup, orig));
474 }
475
476 /* Truncate the history file FNAME, leaving only LINES trailing lines.
477    If FNAME is NULL, then use ~/.history.  Writes a new file and renames
478    it to the original name.  Returns 0 on success, errno on failure. */
479 int
480 history_truncate_file (const char *fname, int lines)
481 {
482   char *buffer, *filename, *tempname, *bp, *bp1;                /* bp1 == bp+1 */
483   int file, chars_read, rv, orig_lines, exists, r;
484   struct stat finfo;
485   size_t file_size;
486
487   history_lines_written_to_file = 0;
488
489   buffer = (char *)NULL;
490   filename = history_filename (fname);
491   tempname = 0;
492   file = filename ? open (filename, O_RDONLY|O_BINARY, 0666) : -1;
493   rv = exists = 0;
494
495   /* Don't try to truncate non-regular files. */
496   if (file == -1 || fstat (file, &finfo) == -1)
497     {
498       rv = errno;
499       if (file != -1)
500         close (file);
501       goto truncate_exit;
502     }
503   exists = 1;
504
505   if (S_ISREG (finfo.st_mode) == 0)
506     {
507       close (file);
508 #ifdef EFTYPE
509       rv = EFTYPE;
510 #else
511       rv = EINVAL;
512 #endif
513       goto truncate_exit;
514     }
515
516   file_size = (size_t)finfo.st_size;
517
518   /* check for overflow on very large files */
519   if (file_size != finfo.st_size || file_size + 1 < file_size)
520     {
521       close (file);
522 #if defined (EFBIG)
523       rv = errno = EFBIG;
524 #elif defined (EOVERFLOW)
525       rv = errno = EOVERFLOW;
526 #else
527       rv = errno = EINVAL;
528 #endif
529       goto truncate_exit;
530     }
531
532   buffer = (char *)malloc (file_size + 1);
533   if (buffer == 0)
534     {
535       rv = errno;
536       close (file);
537       goto truncate_exit;
538     }
539
540   chars_read = read (file, buffer, file_size);
541   close (file);
542
543   if (chars_read <= 0)
544     {
545       rv = (chars_read < 0) ? errno : 0;
546       goto truncate_exit;
547     }
548
549   orig_lines = lines;
550   /* Count backwards from the end of buffer until we have passed
551      LINES lines.  bp1 is set funny initially.  But since bp[1] can't
552      be a comment character (since it's off the end) and *bp can't be
553      both a newline and the history comment character, it should be OK. */
554   for (bp1 = bp = buffer + chars_read - 1; lines && bp > buffer; bp--)
555     {
556       if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
557         lines--;
558       bp1 = bp;
559     }
560
561   /* If this is the first line, then the file contains exactly the
562      number of lines we want to truncate to, so we don't need to do
563      anything.  It's the first line if we don't find a newline between
564      the current value of i and 0.  Otherwise, write from the start of
565      this line until the end of the buffer. */
566   for ( ; bp > buffer; bp--)
567     {
568       if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
569         {
570           bp++;
571           break;
572         }
573       bp1 = bp;
574     }
575
576   /* Write only if there are more lines in the file than we want to
577      truncate to. */
578   if (bp <= buffer)
579     {
580       rv = 0;
581       /* No-op if LINES == 0 at this point */
582       history_lines_written_to_file = orig_lines - lines;
583       goto truncate_exit;
584     }
585
586   tempname = history_tempfile (filename);
587
588   if ((file = open (tempname, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0600)) != -1)
589     {
590       if (write (file, bp, chars_read - (bp - buffer)) < 0)
591         rv = errno;
592
593       if (close (file) < 0 && rv == 0)
594         rv = errno;
595     }
596   else
597     rv = errno;
598
599  truncate_exit:
600   FREE (buffer);
601
602   history_lines_written_to_file = orig_lines - lines;
603
604   if (rv == 0 && filename && tempname)
605     rv = histfile_restore (tempname, filename);
606
607   if (rv != 0)
608     {
609       if (tempname)
610         unlink (tempname);
611       history_lines_written_to_file = 0;
612     }
613
614 #if defined (HAVE_CHOWN)
615   /* Make sure the new filename is owned by the same user as the old.  If one
616      user is running this, it's a no-op.  If the shell is running after sudo
617      with a shared history file, we don't want to leave the history file
618      owned by root. */
619   if (rv == 0 && exists)
620     r = chown (filename, finfo.st_uid, finfo.st_gid);
621 #endif
622
623   xfree (filename);
624   FREE (tempname);
625
626   return rv;
627 }
628
629 /* Workhorse function for writing history.  Writes the last NELEMENT entries
630    from the history list to FILENAME.  OVERWRITE is non-zero if you
631    wish to replace FILENAME with the entries. */
632 static int
633 history_do_write (const char *filename, int nelements, int overwrite)
634 {
635   register int i;
636   char *output, *tempname, *histname;
637   int file, mode, rv, exists;
638   struct stat finfo;
639 #ifdef HISTORY_USE_MMAP
640   size_t cursize;
641
642   history_lines_written_to_file = 0;
643
644   mode = overwrite ? O_RDWR|O_CREAT|O_TRUNC|O_BINARY : O_RDWR|O_APPEND|O_BINARY;
645 #else
646   mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
647 #endif
648   histname = history_filename (filename);
649   exists = histname ? (stat (histname, &finfo) == 0) : 0;
650
651   tempname = (overwrite && exists && S_ISREG (finfo.st_mode)) ? history_tempfile (histname) : 0;
652   output = tempname ? tempname : histname;
653
654   file = output ? open (output, mode, 0600) : -1;
655   rv = 0;
656
657   if (file == -1)
658     {
659       rv = errno;
660       FREE (histname);
661       FREE (tempname);
662       return (rv);
663     }
664
665 #ifdef HISTORY_USE_MMAP
666   cursize = overwrite ? 0 : lseek (file, 0, SEEK_END);
667 #endif
668
669   if (nelements > history_length)
670     nelements = history_length;
671
672   /* Build a buffer of all the lines to write, and write them in one syscall.
673      Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */
674   {
675     HIST_ENTRY **the_history;   /* local */
676     register int j;
677     int buffer_size;
678     char *buffer;
679
680     the_history = history_list ();
681     /* Calculate the total number of bytes to write. */
682     for (buffer_size = 0, i = history_length - nelements; i < history_length; i++)
683 #if 0
684       buffer_size += 2 + HISTENT_BYTES (the_history[i]);
685 #else
686       {
687         if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
688           buffer_size += strlen (the_history[i]->timestamp) + 1;
689         buffer_size += strlen (the_history[i]->line) + 1;
690       }
691 #endif
692
693     /* Allocate the buffer, and fill it. */
694 #ifdef HISTORY_USE_MMAP
695     if (ftruncate (file, buffer_size+cursize) == -1)
696       goto mmap_error;
697     buffer = (char *)mmap (0, buffer_size, PROT_READ|PROT_WRITE, MAP_WFLAGS, file, cursize);
698     if ((void *)buffer == MAP_FAILED)
699       {
700 mmap_error:
701         rv = errno;
702         close (file);
703         if (tempname)
704           unlink (tempname);
705         FREE (histname);
706         FREE (tempname);
707         return rv;
708       }
709 #else    
710     buffer = (char *)malloc (buffer_size);
711     if (buffer == 0)
712       {
713         rv = errno;
714         close (file);
715         if (tempname)
716           unlink (tempname);
717         FREE (histname);
718         FREE (tempname);
719         return rv;
720       }
721 #endif
722
723     for (j = 0, i = history_length - nelements; i < history_length; i++)
724       {
725         if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
726           {
727             strcpy (buffer + j, the_history[i]->timestamp);
728             j += strlen (the_history[i]->timestamp);
729             buffer[j++] = '\n';
730           }
731         strcpy (buffer + j, the_history[i]->line);
732         j += strlen (the_history[i]->line);
733         buffer[j++] = '\n';
734       }
735
736 #ifdef HISTORY_USE_MMAP
737     if (msync (buffer, buffer_size, MS_ASYNC) != 0 || munmap (buffer, buffer_size) != 0)
738       rv = errno;
739 #else
740     if (write (file, buffer, buffer_size) < 0)
741       rv = errno;
742     xfree (buffer);
743 #endif
744   }
745
746   history_lines_written_to_file = nelements;
747
748   if (close (file) < 0 && rv == 0)
749     rv = errno;
750
751   if (rv == 0 && histname && tempname)
752     rv = histfile_restore (tempname, histname);
753
754   if (rv != 0)
755     {
756       if (tempname)
757         unlink (tempname);
758       history_lines_written_to_file = 0;
759     }
760
761 #if defined (HAVE_CHOWN)
762   /* Make sure the new filename is owned by the same user as the old.  If one
763      user is running this, it's a no-op.  If the shell is running after sudo
764      with a shared history file, we don't want to leave the history file
765      owned by root. */
766   if (rv == 0 && exists)
767     mode = chown (histname, finfo.st_uid, finfo.st_gid);
768 #endif
769
770   FREE (histname);
771   FREE (tempname);
772
773   return (rv);
774 }
775
776 /* Append NELEMENT entries to FILENAME.  The entries appended are from
777    the end of the list minus NELEMENTs up to the end of the list. */
778 int
779 append_history (int nelements, const char *filename)
780 {
781   return (history_do_write (filename, nelements, HISTORY_APPEND));
782 }
783
784 /* Overwrite FILENAME with the current history.  If FILENAME is NULL,
785    then write the history list to ~/.history.  Values returned
786    are as in read_history ().*/
787 int
788 write_history (const char *filename)
789 {
790   return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
791 }