11acd27e7Smillert /* histfile.c - functions to manipulate the history file. */
21acd27e7Smillert
31acd27e7Smillert /* Copyright (C) 1989, 1992 Free Software Foundation, Inc.
41acd27e7Smillert
51acd27e7Smillert This file contains the GNU History Library (the Library), a set of
61acd27e7Smillert routines for managing the text of previously typed lines.
71acd27e7Smillert
81acd27e7Smillert The Library is free software; you can redistribute it and/or modify
91acd27e7Smillert it under the terms of the GNU General Public License as published by
101acd27e7Smillert the Free Software Foundation; either version 2, or (at your option)
111acd27e7Smillert any later version.
121acd27e7Smillert
131acd27e7Smillert The Library is distributed in the hope that it will be useful, but
141acd27e7Smillert WITHOUT ANY WARRANTY; without even the implied warranty of
151acd27e7Smillert MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
161acd27e7Smillert General Public License for more details.
171acd27e7Smillert
181acd27e7Smillert The GNU General Public License is often shipped with GNU software, and
191acd27e7Smillert is generally kept in a file called COPYING or LICENSE. If you do not
201acd27e7Smillert have a copy of the license, write to the Free Software Foundation,
211acd27e7Smillert 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
221acd27e7Smillert
231acd27e7Smillert /* The goal is to make the implementation transparent, so that you
241acd27e7Smillert don't have to know what data types are used, just what functions
251acd27e7Smillert you can call. I think I have done that. */
261acd27e7Smillert #define READLINE_LIBRARY
271acd27e7Smillert
281acd27e7Smillert #if defined (HAVE_CONFIG_H)
291acd27e7Smillert # include <config.h>
301acd27e7Smillert #endif
311acd27e7Smillert
321acd27e7Smillert #include <stdio.h>
331acd27e7Smillert
341acd27e7Smillert #include <sys/types.h>
351acd27e7Smillert #ifndef _MINIX
361acd27e7Smillert # include <sys/file.h>
371acd27e7Smillert #endif
381acd27e7Smillert #include "posixstat.h"
391acd27e7Smillert #include <fcntl.h>
401acd27e7Smillert
411acd27e7Smillert #if defined (HAVE_STDLIB_H)
421acd27e7Smillert # include <stdlib.h>
431acd27e7Smillert #else
441acd27e7Smillert # include "ansi_stdlib.h"
451acd27e7Smillert #endif /* HAVE_STDLIB_H */
461acd27e7Smillert
471acd27e7Smillert #if defined (HAVE_UNISTD_H)
481acd27e7Smillert # include <unistd.h>
491acd27e7Smillert #endif
501acd27e7Smillert
51af70c2dfSkettenis #if defined (__EMX__) || defined (__CYGWIN__)
52af70c2dfSkettenis # undef HAVE_MMAP
53af70c2dfSkettenis #endif
541acd27e7Smillert
55af70c2dfSkettenis #ifdef HAVE_MMAP
56af70c2dfSkettenis # include <sys/mman.h>
57af70c2dfSkettenis
58af70c2dfSkettenis # ifdef MAP_FILE
59af70c2dfSkettenis # define MAP_RFLAGS (MAP_FILE|MAP_PRIVATE)
60af70c2dfSkettenis # define MAP_WFLAGS (MAP_FILE|MAP_SHARED)
61af70c2dfSkettenis # else
62af70c2dfSkettenis # define MAP_RFLAGS MAP_PRIVATE
63af70c2dfSkettenis # define MAP_WFLAGS MAP_SHARED
64af70c2dfSkettenis # endif
65af70c2dfSkettenis
66af70c2dfSkettenis # ifndef MAP_FAILED
67af70c2dfSkettenis # define MAP_FAILED ((void *)-1)
68af70c2dfSkettenis # endif
69af70c2dfSkettenis
70af70c2dfSkettenis #endif /* HAVE_MMAP */
711acd27e7Smillert
721acd27e7Smillert /* If we're compiling for __EMX__ (OS/2) or __CYGWIN__ (cygwin32 environment
731acd27e7Smillert on win 95/98/nt), we want to open files with O_BINARY mode so that there
741acd27e7Smillert is no \n -> \r\n conversion performed. On other systems, we don't want to
751acd27e7Smillert mess around with O_BINARY at all, so we ensure that it's defined to 0. */
761acd27e7Smillert #if defined (__EMX__) || defined (__CYGWIN__)
771acd27e7Smillert # ifndef O_BINARY
781acd27e7Smillert # define O_BINARY 0
791acd27e7Smillert # endif
801acd27e7Smillert #else /* !__EMX__ && !__CYGWIN__ */
811acd27e7Smillert # undef O_BINARY
821acd27e7Smillert # define O_BINARY 0
831acd27e7Smillert #endif /* !__EMX__ && !__CYGWIN__ */
841acd27e7Smillert
851acd27e7Smillert #include <errno.h>
861acd27e7Smillert #if !defined (errno)
871acd27e7Smillert extern int errno;
881acd27e7Smillert #endif /* !errno */
891acd27e7Smillert
901acd27e7Smillert #include "history.h"
911acd27e7Smillert #include "histlib.h"
921acd27e7Smillert
931acd27e7Smillert #include "rlshell.h"
941acd27e7Smillert #include "xmalloc.h"
951acd27e7Smillert
961acd27e7Smillert /* Return the string that should be used in the place of this
971acd27e7Smillert filename. This only matters when you don't specify the
981acd27e7Smillert filename to read_history (), or write_history (). */
991acd27e7Smillert static char *
history_filename(filename)1001acd27e7Smillert history_filename (filename)
101af70c2dfSkettenis const char *filename;
1021acd27e7Smillert {
103af70c2dfSkettenis char *return_val;
104af70c2dfSkettenis const char *home;
1051acd27e7Smillert int home_len;
10663bef317Sbeck char dot;
1071acd27e7Smillert
1081acd27e7Smillert return_val = filename ? savestring (filename) : (char *)NULL;
1091acd27e7Smillert
1101acd27e7Smillert if (return_val)
1111acd27e7Smillert return (return_val);
1121acd27e7Smillert
113af70c2dfSkettenis home = sh_get_env_value ("HOME");
1141acd27e7Smillert
11583295b13Smillert if (home == 0 || *home == '\0') {
11683295b13Smillert errno = ENOENT;
11775dce849Smillert return (NULL);
11883295b13Smillert }
1191acd27e7Smillert home_len = strlen (home);
1201acd27e7Smillert
1211acd27e7Smillert #if defined (__MSDOS__)
12263bef317Sbeck dot = '_';
1231acd27e7Smillert #else
12463bef317Sbeck dot = '.';
1251acd27e7Smillert #endif
12663bef317Sbeck if (asprintf(&return_val, "%s/%c%s", home, dot, "history") == -1)
12763bef317Sbeck memory_error_and_abort("asprintf");
1281acd27e7Smillert return (return_val);
1291acd27e7Smillert }
1301acd27e7Smillert
1311acd27e7Smillert /* Add the contents of FILENAME to the history list, a line at a time.
1321acd27e7Smillert If FILENAME is NULL, then read from ~/.history. Returns 0 if
1331acd27e7Smillert successful, or errno if not. */
1341acd27e7Smillert int
read_history(filename)1351acd27e7Smillert read_history (filename)
136af70c2dfSkettenis const char *filename;
1371acd27e7Smillert {
1381acd27e7Smillert return (read_history_range (filename, 0, -1));
1391acd27e7Smillert }
1401acd27e7Smillert
1411acd27e7Smillert /* Read a range of lines from FILENAME, adding them to the history list.
1421acd27e7Smillert Start reading at the FROM'th line and end at the TO'th. If FROM
1431acd27e7Smillert is zero, start at the beginning. If TO is less than FROM, read
1441acd27e7Smillert until the end of the file. If FILENAME is NULL, then read from
1451acd27e7Smillert ~/.history. Returns 0 if successful, or errno if not. */
1461acd27e7Smillert int
read_history_range(filename,from,to)1471acd27e7Smillert read_history_range (filename, from, to)
148af70c2dfSkettenis const char *filename;
1491acd27e7Smillert int from, to;
1501acd27e7Smillert {
151af70c2dfSkettenis register char *line_start, *line_end;
152af70c2dfSkettenis char *input, *buffer, *bufend;
1531acd27e7Smillert int file, current_line, chars_read;
1541acd27e7Smillert struct stat finfo;
1551acd27e7Smillert size_t file_size;
1561acd27e7Smillert
1571acd27e7Smillert buffer = (char *)NULL;
15883295b13Smillert if ((input = history_filename (filename)))
1591acd27e7Smillert file = open (input, O_RDONLY|O_BINARY, 0666);
16083295b13Smillert else
16183295b13Smillert file = -1;
1621acd27e7Smillert
1631acd27e7Smillert if ((file < 0) || (fstat (file, &finfo) == -1))
1641acd27e7Smillert goto error_and_exit;
1651acd27e7Smillert
1661acd27e7Smillert file_size = (size_t)finfo.st_size;
1671acd27e7Smillert
1681acd27e7Smillert /* check for overflow on very large files */
1691acd27e7Smillert if (file_size != finfo.st_size || file_size + 1 < file_size)
1701acd27e7Smillert {
1711acd27e7Smillert #if defined (EFBIG)
1721acd27e7Smillert errno = EFBIG;
173af70c2dfSkettenis #elif defined (EOVERFLOW)
174af70c2dfSkettenis errno = EOVERFLOW;
1751acd27e7Smillert #endif
1761acd27e7Smillert goto error_and_exit;
1771acd27e7Smillert }
1781acd27e7Smillert
179af70c2dfSkettenis #ifdef HAVE_MMAP
180af70c2dfSkettenis /* We map read/write and private so we can change newlines to NULs without
181af70c2dfSkettenis affecting the underlying object. */
182af70c2dfSkettenis buffer = (char *)mmap (0, file_size, PROT_READ|PROT_WRITE, MAP_RFLAGS, file, 0);
183af70c2dfSkettenis if ((void *)buffer == MAP_FAILED)
184af70c2dfSkettenis goto error_and_exit;
185af70c2dfSkettenis chars_read = file_size;
186af70c2dfSkettenis #else
187af70c2dfSkettenis buffer = (char *)malloc (file_size + 1);
188af70c2dfSkettenis if (buffer == 0)
189af70c2dfSkettenis goto error_and_exit;
1901acd27e7Smillert
1911acd27e7Smillert chars_read = read (file, buffer, file_size);
192af70c2dfSkettenis #endif
1931acd27e7Smillert if (chars_read < 0)
1941acd27e7Smillert {
1951acd27e7Smillert error_and_exit:
196af70c2dfSkettenis chars_read = errno;
1971acd27e7Smillert if (file >= 0)
1981acd27e7Smillert close (file);
1991acd27e7Smillert
2001acd27e7Smillert FREE (input);
201af70c2dfSkettenis #ifndef HAVE_MMAP
2021acd27e7Smillert FREE (buffer);
203af70c2dfSkettenis #endif
2041acd27e7Smillert
205af70c2dfSkettenis return (chars_read);
2061acd27e7Smillert }
2071acd27e7Smillert
2081acd27e7Smillert close (file);
2091acd27e7Smillert
2101acd27e7Smillert /* Set TO to larger than end of file if negative. */
2111acd27e7Smillert if (to < 0)
2121acd27e7Smillert to = chars_read;
2131acd27e7Smillert
2141acd27e7Smillert /* Start at beginning of file, work to end. */
215af70c2dfSkettenis bufend = buffer + chars_read;
216af70c2dfSkettenis current_line = 0;
2171acd27e7Smillert
2181acd27e7Smillert /* Skip lines until we are at FROM. */
219af70c2dfSkettenis for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++)
220af70c2dfSkettenis if (*line_end == '\n')
2211acd27e7Smillert {
2221acd27e7Smillert current_line++;
2231acd27e7Smillert line_start = line_end + 1;
2241acd27e7Smillert }
2251acd27e7Smillert
2261acd27e7Smillert /* If there are lines left to gobble, then gobble them now. */
227af70c2dfSkettenis for (line_end = line_start; line_end < bufend; line_end++)
228af70c2dfSkettenis if (*line_end == '\n')
2291acd27e7Smillert {
230af70c2dfSkettenis *line_end = '\0';
2311acd27e7Smillert
232af70c2dfSkettenis if (*line_start)
233af70c2dfSkettenis add_history (line_start);
2341acd27e7Smillert
2351acd27e7Smillert current_line++;
2361acd27e7Smillert
2371acd27e7Smillert if (current_line >= to)
2381acd27e7Smillert break;
2391acd27e7Smillert
2401acd27e7Smillert line_start = line_end + 1;
2411acd27e7Smillert }
2421acd27e7Smillert
2431acd27e7Smillert FREE (input);
244af70c2dfSkettenis #ifndef HAVE_MMAP
2451acd27e7Smillert FREE (buffer);
246af70c2dfSkettenis #else
247af70c2dfSkettenis munmap (buffer, file_size);
248af70c2dfSkettenis #endif
2491acd27e7Smillert
2501acd27e7Smillert return (0);
2511acd27e7Smillert }
2521acd27e7Smillert
2531acd27e7Smillert /* Truncate the history file FNAME, leaving only LINES trailing lines.
254af70c2dfSkettenis If FNAME is NULL, then use ~/.history. Returns 0 on success, errno
255af70c2dfSkettenis on failure. */
2561acd27e7Smillert int
history_truncate_file(fname,lines)2571acd27e7Smillert history_truncate_file (fname, lines)
258af70c2dfSkettenis const char *fname;
2591acd27e7Smillert int lines;
2601acd27e7Smillert {
261af70c2dfSkettenis char *buffer, *filename, *bp;
262af70c2dfSkettenis int file, chars_read, rv;
2631acd27e7Smillert struct stat finfo;
2641acd27e7Smillert size_t file_size;
2651acd27e7Smillert
2661acd27e7Smillert buffer = (char *)NULL;
26783295b13Smillert if ((filename = history_filename (fname)))
2681acd27e7Smillert file = open (filename, O_RDONLY|O_BINARY, 0666);
26983295b13Smillert else
27083295b13Smillert file = -1;
271af70c2dfSkettenis rv = 0;
2721acd27e7Smillert
2731acd27e7Smillert /* Don't try to truncate non-regular files. */
274af70c2dfSkettenis if (file == -1 || fstat (file, &finfo) == -1)
275af70c2dfSkettenis {
276af70c2dfSkettenis rv = errno;
277af70c2dfSkettenis if (file != -1)
278af70c2dfSkettenis close (file);
2791acd27e7Smillert goto truncate_exit;
280af70c2dfSkettenis }
281af70c2dfSkettenis
282af70c2dfSkettenis if (S_ISREG (finfo.st_mode) == 0)
283af70c2dfSkettenis {
284af70c2dfSkettenis close (file);
285af70c2dfSkettenis #ifdef EFTYPE
286af70c2dfSkettenis rv = EFTYPE;
287af70c2dfSkettenis #else
288af70c2dfSkettenis rv = EINVAL;
289af70c2dfSkettenis #endif
290af70c2dfSkettenis goto truncate_exit;
291af70c2dfSkettenis }
2921acd27e7Smillert
2931acd27e7Smillert file_size = (size_t)finfo.st_size;
2941acd27e7Smillert
2951acd27e7Smillert /* check for overflow on very large files */
2961acd27e7Smillert if (file_size != finfo.st_size || file_size + 1 < file_size)
2971acd27e7Smillert {
2981acd27e7Smillert close (file);
2991acd27e7Smillert #if defined (EFBIG)
300af70c2dfSkettenis rv = errno = EFBIG;
301af70c2dfSkettenis #elif defined (EOVERFLOW)
302af70c2dfSkettenis rv = errno = EOVERFLOW;
303af70c2dfSkettenis #else
304af70c2dfSkettenis rv = errno = EINVAL;
3051acd27e7Smillert #endif
3061acd27e7Smillert goto truncate_exit;
3071acd27e7Smillert }
3081acd27e7Smillert
309af70c2dfSkettenis buffer = (char *)malloc (file_size + 1);
310af70c2dfSkettenis if (buffer == 0)
311af70c2dfSkettenis {
312af70c2dfSkettenis close (file);
313af70c2dfSkettenis goto truncate_exit;
314af70c2dfSkettenis }
315af70c2dfSkettenis
3161acd27e7Smillert chars_read = read (file, buffer, file_size);
3171acd27e7Smillert close (file);
3181acd27e7Smillert
3191acd27e7Smillert if (chars_read <= 0)
320af70c2dfSkettenis {
321af70c2dfSkettenis rv = (chars_read < 0) ? errno : 0;
3221acd27e7Smillert goto truncate_exit;
323af70c2dfSkettenis }
3241acd27e7Smillert
3251acd27e7Smillert /* Count backwards from the end of buffer until we have passed
3261acd27e7Smillert LINES lines. */
327af70c2dfSkettenis for (bp = buffer + chars_read - 1; lines && bp > buffer; bp--)
3281acd27e7Smillert {
329af70c2dfSkettenis if (*bp == '\n')
3301acd27e7Smillert lines--;
3311acd27e7Smillert }
3321acd27e7Smillert
3331acd27e7Smillert /* If this is the first line, then the file contains exactly the
3341acd27e7Smillert number of lines we want to truncate to, so we don't need to do
3351acd27e7Smillert anything. It's the first line if we don't find a newline between
3361acd27e7Smillert the current value of i and 0. Otherwise, write from the start of
3371acd27e7Smillert this line until the end of the buffer. */
338af70c2dfSkettenis for ( ; bp > buffer; bp--)
339af70c2dfSkettenis if (*bp == '\n')
3401acd27e7Smillert {
341af70c2dfSkettenis bp++;
3421acd27e7Smillert break;
3431acd27e7Smillert }
3441acd27e7Smillert
3451acd27e7Smillert /* Write only if there are more lines in the file than we want to
3461acd27e7Smillert truncate to. */
347af70c2dfSkettenis if (bp > buffer && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1))
3481acd27e7Smillert {
349af70c2dfSkettenis write (file, bp, chars_read - (bp - buffer));
3501acd27e7Smillert
3511acd27e7Smillert #if defined (__BEOS__)
3521acd27e7Smillert /* BeOS ignores O_TRUNC. */
353af70c2dfSkettenis ftruncate (file, chars_read - (bp - buffer));
3541acd27e7Smillert #endif
3551acd27e7Smillert
3561acd27e7Smillert close (file);
3571acd27e7Smillert }
3581acd27e7Smillert
3591acd27e7Smillert truncate_exit:
3601acd27e7Smillert
3611acd27e7Smillert FREE (buffer);
3621acd27e7Smillert
3631acd27e7Smillert free (filename);
364af70c2dfSkettenis return rv;
3651acd27e7Smillert }
3661acd27e7Smillert
3671acd27e7Smillert /* Workhorse function for writing history. Writes NELEMENT entries
3681acd27e7Smillert from the history list to FILENAME. OVERWRITE is non-zero if you
3691acd27e7Smillert wish to replace FILENAME with the entries. */
3701acd27e7Smillert static int
history_do_write(filename,nelements,overwrite)3711acd27e7Smillert history_do_write (filename, nelements, overwrite)
372af70c2dfSkettenis const char *filename;
3731acd27e7Smillert int nelements, overwrite;
3741acd27e7Smillert {
3751acd27e7Smillert register int i;
3761acd27e7Smillert char *output;
377af70c2dfSkettenis int file, mode, rv;
378*a7d4f26aSkrw #ifdef HAVE_MMAP
379af70c2dfSkettenis size_t cursize;
380*a7d4f26aSkrw #endif
3811acd27e7Smillert
382af70c2dfSkettenis #ifdef HAVE_MMAP
383af70c2dfSkettenis mode = overwrite ? O_RDWR|O_CREAT|O_TRUNC|O_BINARY : O_RDWR|O_APPEND|O_BINARY;
384af70c2dfSkettenis #else
3851acd27e7Smillert mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
386af70c2dfSkettenis #endif
3871acd27e7Smillert output = history_filename (filename);
388af70c2dfSkettenis rv = 0;
3891acd27e7Smillert
39083295b13Smillert if (!output || (file = open (output, mode, 0600)) == -1)
3911acd27e7Smillert {
3921acd27e7Smillert FREE (output);
3931acd27e7Smillert return (errno);
3941acd27e7Smillert }
3951acd27e7Smillert
396af70c2dfSkettenis #ifdef HAVE_MMAP
397af70c2dfSkettenis cursize = overwrite ? 0 : lseek (file, 0, SEEK_END);
398af70c2dfSkettenis #endif
399af70c2dfSkettenis
4001acd27e7Smillert if (nelements > history_length)
4011acd27e7Smillert nelements = history_length;
4021acd27e7Smillert
4031acd27e7Smillert /* Build a buffer of all the lines to write, and write them in one syscall.
4041acd27e7Smillert Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */
4051acd27e7Smillert {
4061acd27e7Smillert HIST_ENTRY **the_history; /* local */
4071acd27e7Smillert int buffer_size;
4081acd27e7Smillert char *buffer;
4091acd27e7Smillert
4101acd27e7Smillert the_history = history_list ();
4111acd27e7Smillert /* Calculate the total number of bytes to write. */
412d9924ce1Sotto for (buffer_size = 1, i = history_length - nelements; i < history_length; i++)
4131acd27e7Smillert buffer_size += 1 + strlen (the_history[i]->line);
4141acd27e7Smillert
4151acd27e7Smillert /* Allocate the buffer, and fill it. */
416af70c2dfSkettenis #ifdef HAVE_MMAP
417af70c2dfSkettenis if (ftruncate (file, buffer_size+cursize) == -1)
418af70c2dfSkettenis goto mmap_error;
419af70c2dfSkettenis buffer = (char *)mmap (0, buffer_size, PROT_READ|PROT_WRITE, MAP_WFLAGS, file, cursize);
420af70c2dfSkettenis if ((void *)buffer == MAP_FAILED)
421af70c2dfSkettenis {
422af70c2dfSkettenis mmap_error:
423af70c2dfSkettenis rv = errno;
424af70c2dfSkettenis FREE (output);
425af70c2dfSkettenis close (file);
426af70c2dfSkettenis return rv;
427af70c2dfSkettenis }
428af70c2dfSkettenis #else
429af70c2dfSkettenis buffer = (char *)malloc (buffer_size);
430af70c2dfSkettenis if (buffer == 0)
431af70c2dfSkettenis {
432af70c2dfSkettenis rv = errno;
433af70c2dfSkettenis FREE (output);
434af70c2dfSkettenis close (file);
435af70c2dfSkettenis return rv;
436af70c2dfSkettenis }
437af70c2dfSkettenis #endif
43863bef317Sbeck buffer[0] = '\0';
4391acd27e7Smillert
44063bef317Sbeck for (i = history_length - nelements; i < history_length; i++)
4411acd27e7Smillert {
44263bef317Sbeck strlcat (buffer, the_history[i]->line, buffer_size);
44363bef317Sbeck strlcat (buffer, "\n", buffer_size);
4441acd27e7Smillert }
4451acd27e7Smillert
446af70c2dfSkettenis #ifdef HAVE_MMAP
447af70c2dfSkettenis if (msync (buffer, buffer_size, 0) != 0 || munmap (buffer, buffer_size) != 0)
448af70c2dfSkettenis rv = errno;
449af70c2dfSkettenis #else
450af70c2dfSkettenis if (write (file, buffer, buffer_size - 1) < 0)
451af70c2dfSkettenis rv = errno;
4521acd27e7Smillert free (buffer);
453af70c2dfSkettenis #endif
4541acd27e7Smillert }
4551acd27e7Smillert
4561acd27e7Smillert close (file);
4571acd27e7Smillert
4581acd27e7Smillert FREE (output);
4591acd27e7Smillert
460af70c2dfSkettenis return (rv);
4611acd27e7Smillert }
4621acd27e7Smillert
4631acd27e7Smillert /* Append NELEMENT entries to FILENAME. The entries appended are from
4641acd27e7Smillert the end of the list minus NELEMENTs up to the end of the list. */
4651acd27e7Smillert int
append_history(nelements,filename)4661acd27e7Smillert append_history (nelements, filename)
4671acd27e7Smillert int nelements;
468af70c2dfSkettenis const char *filename;
4691acd27e7Smillert {
4701acd27e7Smillert return (history_do_write (filename, nelements, HISTORY_APPEND));
4711acd27e7Smillert }
4721acd27e7Smillert
4731acd27e7Smillert /* Overwrite FILENAME with the current history. If FILENAME is NULL,
4741acd27e7Smillert then write the history list to ~/.history. Values returned
4751acd27e7Smillert are as in read_history ().*/
4761acd27e7Smillert int
write_history(filename)4771acd27e7Smillert write_history (filename)
478af70c2dfSkettenis const char *filename;
4791acd27e7Smillert {
4801acd27e7Smillert return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
4811acd27e7Smillert }
482