1 /* histfile.c - functions to manipulate the history file. */
3 /* Copyright (C) 1989-2010 Free Software Foundation, Inc.
5 This file contains the GNU History Library (History), a set of
6 routines for managing the text of previously typed lines.
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.
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.
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/>.
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. */
26 #define READLINE_LIBRARY
28 #if defined (__TANDEM)
32 #if defined (HAVE_CONFIG_H)
38 #include <sys/types.h>
39 #if ! defined (_MINIX) && defined (HAVE_SYS_FILE_H)
40 # include <sys/file.h>
42 #include "posixstat.h"
45 #if defined (HAVE_STDLIB_H)
48 # include "ansi_stdlib.h"
49 #endif /* HAVE_STDLIB_H */
51 #if defined (HAVE_UNISTD_H)
61 #ifdef HISTORY_USE_MMAP
62 # include <sys/mman.h>
65 # define MAP_RFLAGS (MAP_FILE|MAP_PRIVATE)
66 # define MAP_WFLAGS (MAP_FILE|MAP_SHARED)
68 # define MAP_RFLAGS MAP_PRIVATE
69 # define MAP_WFLAGS MAP_SHARED
73 # define MAP_FAILED ((void *)-1)
76 #endif /* HISTORY_USE_MMAP */
78 /* If we're compiling for __EMX__ (OS/2) or __CYGWIN__ (cygwin32 environment
79 on win 95/98/nt), we want to open files with O_BINARY mode so that there
80 is no \n -> \r\n conversion performed. On other systems, we don't want to
81 mess around with O_BINARY at all, so we ensure that it's defined to 0. */
82 #if defined (__EMX__) || defined (__CYGWIN__)
86 #else /* !__EMX__ && !__CYGWIN__ */
89 #endif /* !__EMX__ && !__CYGWIN__ */
102 /* If non-zero, we write timestamps to the history file in history_do_write() */
103 int history_write_timestamps = 0;
105 /* Does S look like the beginning of a history timestamp entry? Placeholder
106 for more extensive tests. */
107 #define HIST_TIMESTAMP_START(s) (*(s) == history_comment_char && isdigit ((s)[1]) )
109 /* Return the string that should be used in the place of this
110 filename. This only matters when you don't specify the
111 filename to read_history (), or write_history (). */
113 history_filename (filename)
114 const char *filename;
120 return_val = filename ? savestring (filename) : (char *)NULL;
125 home = sh_get_env_value ("HOME");
137 home_len = strlen (home);
139 return_val = (char *)xmalloc (2 + home_len + 8); /* strlen(".history") == 8 */
140 strcpy (return_val, home);
141 return_val[home_len] = '/';
142 #if defined (__MSDOS__)
143 strcpy (return_val + home_len + 1, "_history");
145 strcpy (return_val + home_len + 1, ".history");
151 /* Add the contents of FILENAME to the history list, a line at a time.
152 If FILENAME is NULL, then read from ~/.history. Returns 0 if
153 successful, or errno if not. */
155 read_history (filename)
156 const char *filename;
158 return (read_history_range (filename, 0, -1));
161 /* Read a range of lines from FILENAME, adding them to the history list.
162 Start reading at the FROM'th line and end at the TO'th. If FROM
163 is zero, start at the beginning. If TO is less than FROM, read
164 until the end of the file. If FILENAME is NULL, then read from
165 ~/.history. Returns 0 if successful, or errno if not. */
167 read_history_range (filename, from, to)
168 const char *filename;
171 register char *line_start, *line_end, *p;
172 char *input, *buffer, *bufend, *last_ts;
173 int file, current_line, chars_read;
177 int overflow_errno = EFBIG;
178 #elif defined (EOVERFLOW)
179 int overflow_errno = EOVERFLOW;
181 int overflow_errno = EIO;
184 buffer = last_ts = (char *)NULL;
185 input = history_filename (filename);
186 file = input ? open (input, O_RDONLY|O_BINARY, 0666) : -1;
188 if ((file < 0) || (fstat (file, &finfo) == -1))
191 file_size = (size_t)finfo.st_size;
193 /* check for overflow on very large files */
194 if (file_size != finfo.st_size || file_size + 1 < file_size)
196 errno = overflow_errno;
200 #ifdef HISTORY_USE_MMAP
201 /* We map read/write and private so we can change newlines to NULs without
202 affecting the underlying object. */
203 buffer = (char *)mmap (0, file_size, PROT_READ|PROT_WRITE, MAP_RFLAGS, file, 0);
204 if ((void *)buffer == MAP_FAILED)
206 errno = overflow_errno;
209 chars_read = file_size;
211 buffer = (char *)malloc (file_size + 1);
214 errno = overflow_errno;
218 chars_read = read (file, buffer, file_size);
231 #ifndef HISTORY_USE_MMAP
240 /* Set TO to larger than end of file if negative. */
244 /* Start at beginning of file, work to end. */
245 bufend = buffer + chars_read;
248 /* Skip lines until we are at FROM. */
249 for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++)
250 if (*line_end == '\n')
253 /* If we see something we think is a timestamp, continue with this
254 line. We should check more extensively here... */
255 if (HIST_TIMESTAMP_START(p) == 0)
260 /* If there are lines left to gobble, then gobble them now. */
261 for (line_end = line_start; line_end < bufend; line_end++)
262 if (*line_end == '\n')
264 /* Change to allow Windows-like \r\n end of line delimiter. */
265 if (line_end > line_start && line_end[-1] == '\r')
272 if (HIST_TIMESTAMP_START(line_start) == 0)
274 add_history (line_start);
277 add_history_time (last_ts);
283 last_ts = line_start;
290 if (current_line >= to)
293 line_start = line_end + 1;
297 #ifndef HISTORY_USE_MMAP
300 munmap (buffer, file_size);
306 /* Truncate the history file FNAME, leaving only LINES trailing lines.
307 If FNAME is NULL, then use ~/.history. Returns 0 on success, errno
310 history_truncate_file (fname, lines)
314 char *buffer, *filename, *bp, *bp1; /* bp1 == bp+1 */
315 int file, chars_read, rv;
319 buffer = (char *)NULL;
320 filename = history_filename (fname);
321 file = filename ? open (filename, O_RDONLY|O_BINARY, 0666) : -1;
324 /* Don't try to truncate non-regular files. */
325 if (file == -1 || fstat (file, &finfo) == -1)
333 if (S_ISREG (finfo.st_mode) == 0)
344 file_size = (size_t)finfo.st_size;
346 /* check for overflow on very large files */
347 if (file_size != finfo.st_size || file_size + 1 < file_size)
352 #elif defined (EOVERFLOW)
353 rv = errno = EOVERFLOW;
360 buffer = (char *)malloc (file_size + 1);
367 chars_read = read (file, buffer, file_size);
372 rv = (chars_read < 0) ? errno : 0;
376 /* Count backwards from the end of buffer until we have passed
377 LINES lines. bp1 is set funny initially. But since bp[1] can't
378 be a comment character (since it's off the end) and *bp can't be
379 both a newline and the history comment character, it should be OK. */
380 for (bp1 = bp = buffer + chars_read - 1; lines && bp > buffer; bp--)
382 if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
387 /* If this is the first line, then the file contains exactly the
388 number of lines we want to truncate to, so we don't need to do
389 anything. It's the first line if we don't find a newline between
390 the current value of i and 0. Otherwise, write from the start of
391 this line until the end of the buffer. */
392 for ( ; bp > buffer; bp--)
394 if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
402 /* Write only if there are more lines in the file than we want to
404 if (bp > buffer && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1))
406 write (file, bp, chars_read - (bp - buffer));
408 #if defined (__BEOS__)
409 /* BeOS ignores O_TRUNC. */
410 ftruncate (file, chars_read - (bp - buffer));
424 /* Workhorse function for writing history. Writes NELEMENT entries
425 from the history list to FILENAME. OVERWRITE is non-zero if you
426 wish to replace FILENAME with the entries. */
428 history_do_write (filename, nelements, overwrite)
429 const char *filename;
430 int nelements, overwrite;
435 #ifdef HISTORY_USE_MMAP
438 mode = overwrite ? O_RDWR|O_CREAT|O_TRUNC|O_BINARY : O_RDWR|O_APPEND|O_BINARY;
440 mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
442 output = history_filename (filename);
443 file = output ? open (output, mode, 0600) : -1;
452 #ifdef HISTORY_USE_MMAP
453 cursize = overwrite ? 0 : lseek (file, 0, SEEK_END);
456 if (nelements > history_length)
457 nelements = history_length;
459 /* Build a buffer of all the lines to write, and write them in one syscall.
460 Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */
462 HIST_ENTRY **the_history; /* local */
467 the_history = history_list ();
468 /* Calculate the total number of bytes to write. */
469 for (buffer_size = 0, i = history_length - nelements; i < history_length; i++)
471 buffer_size += 2 + HISTENT_BYTES (the_history[i]);
474 if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
475 buffer_size += strlen (the_history[i]->timestamp) + 1;
476 buffer_size += strlen (the_history[i]->line) + 1;
480 /* Allocate the buffer, and fill it. */
481 #ifdef HISTORY_USE_MMAP
482 if (ftruncate (file, buffer_size+cursize) == -1)
484 buffer = (char *)mmap (0, buffer_size, PROT_READ|PROT_WRITE, MAP_WFLAGS, file, cursize);
485 if ((void *)buffer == MAP_FAILED)
494 buffer = (char *)malloc (buffer_size);
504 for (j = 0, i = history_length - nelements; i < history_length; i++)
506 if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
508 strcpy (buffer + j, the_history[i]->timestamp);
509 j += strlen (the_history[i]->timestamp);
512 strcpy (buffer + j, the_history[i]->line);
513 j += strlen (the_history[i]->line);
517 #ifdef HISTORY_USE_MMAP
518 if (msync (buffer, buffer_size, 0) != 0 || munmap (buffer, buffer_size) != 0)
521 if (write (file, buffer, buffer_size) < 0)
534 /* Append NELEMENT entries to FILENAME. The entries appended are from
535 the end of the list minus NELEMENTs up to the end of the list. */
537 append_history (nelements, filename)
539 const char *filename;
541 return (history_do_write (filename, nelements, HISTORY_APPEND));
544 /* Overwrite FILENAME with the current history. If FILENAME is NULL,
545 then write the history list to ~/.history. Values returned
546 are as in read_history ().*/
548 write_history (filename)
549 const char *filename;
551 return (history_do_write (filename, history_length, HISTORY_OVERWRITE));