1 /* histfile.c - functions to manipulate the history file. */
3 /* Copyright (C) 1989, 1992 Free Software Foundation, Inc.
5 This file contains the GNU History Library (the Library), a set of
6 routines for managing the text of previously typed lines.
8 The Library 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 1, or (at your option)
13 The Library is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 The GNU General Public License is often shipped with GNU software, and
19 is generally kept in a file called COPYING or LICENSE. If you do not
20 have a copy of the license, write to the Free Software Foundation,
21 675 Mass Ave, Cambridge, MA 02139, USA. */
23 /* The goal is to make the implementation transparent, so that you
24 don't have to know what data types are used, just what functions
25 you can call. I think I have done that. */
26 #define READLINE_LIBRARY
28 #if defined (HAVE_CONFIG_H)
34 #include <sys/types.h>
39 #if defined (HAVE_STDLIB_H)
42 # include "ansi_stdlib.h"
43 #endif /* HAVE_STDLIB_H */
45 #if defined (HAVE_UNISTD_H)
49 #if defined (HAVE_STRING_H)
53 #endif /* !HAVE_STRING_H */
63 extern char *xmalloc (), *xrealloc ();
65 /* Return the string that should be used in the place of this
66 filename. This only matters when you don't specify the
67 filename to read_history (), or write_history (). */
69 history_filename (filename)
72 char *return_val, *home;
75 return_val = filename ? savestring (filename) : (char *)NULL;
80 home = getenv ("HOME");
88 home_len = strlen (home);
90 return_val = xmalloc (2 + home_len + 8); /* strlen(".history") == 8 */
91 strcpy (return_val, home);
92 return_val[home_len] = '/';
93 strcpy (return_val + home_len + 1, ".history");
98 /* Add the contents of FILENAME to the history list, a line at a time.
99 If FILENAME is NULL, then read from ~/.history. Returns 0 if
100 successful, or errno if not. */
102 read_history (filename)
105 return (read_history_range (filename, 0, -1));
108 /* Read a range of lines from FILENAME, adding them to the history list.
109 Start reading at the FROM'th line and end at the TO'th. If FROM
110 is zero, start at the beginning. If TO is less than FROM, read
111 until the end of the file. If FILENAME is NULL, then read from
112 ~/.history. Returns 0 if successful, or errno if not. */
114 read_history_range (filename, from, to)
118 register int line_start, line_end;
119 char *input, *buffer = (char *)NULL;
120 int file, current_line;
123 input = history_filename (filename);
124 file = open (input, O_RDONLY, 0666);
126 if ((file < 0) || (fstat (file, &finfo) == -1))
129 buffer = xmalloc ((int)finfo.st_size + 1);
131 if (read (file, buffer, finfo.st_size) != finfo.st_size)
145 /* Set TO to larger than end of file if negative. */
149 /* Start at beginning of file, work to end. */
150 line_start = line_end = current_line = 0;
152 /* Skip lines until we are at FROM. */
153 while (line_start < finfo.st_size && current_line < from)
155 for (line_end = line_start; line_end < finfo.st_size; line_end++)
156 if (buffer[line_end] == '\n')
159 line_start = line_end + 1;
160 if (current_line == from)
165 /* If there are lines left to gobble, then gobble them now. */
166 for (line_end = line_start; line_end < finfo.st_size; line_end++)
167 if (buffer[line_end] == '\n')
169 buffer[line_end] = '\0';
171 if (buffer[line_start])
172 add_history (buffer + line_start);
176 if (current_line >= to)
179 line_start = line_end + 1;
188 /* Truncate the history file FNAME, leaving only LINES trailing lines.
189 If FNAME is NULL, then use ~/.history. */
191 history_truncate_file (fname, lines)
196 int file, chars_read;
197 char *buffer = (char *)NULL, *filename;
200 filename = history_filename (fname);
201 file = open (filename, O_RDONLY, 0666);
203 if (file == -1 || fstat (file, &finfo) == -1)
206 buffer = xmalloc ((int)finfo.st_size + 1);
207 chars_read = read (file, buffer, finfo.st_size);
213 /* Count backwards from the end of buffer until we have passed
215 for (i = chars_read - 1; lines && i; i--)
217 if (buffer[i] == '\n')
221 /* If this is the first line, then the file contains exactly the
222 number of lines we want to truncate to, so we don't need to do
223 anything. It's the first line if we don't find a newline between
224 the current value of i and 0. Otherwise, write from the start of
225 this line until the end of the buffer. */
227 if (buffer[i] == '\n')
233 /* Write only if there are more lines in the file than we want to
235 if (i && ((file = open (filename, O_WRONLY|O_TRUNC, 0666)) != -1))
237 write (file, buffer + i, finfo.st_size - i);
249 /* Workhorse function for writing history. Writes NELEMENT entries
250 from the history list to FILENAME. OVERWRITE is non-zero if you
251 wish to replace FILENAME with the entries. */
253 history_do_write (filename, nelements, overwrite)
255 int nelements, overwrite;
258 char *output = history_filename (filename);
261 mode = overwrite ? O_WRONLY | O_CREAT | O_TRUNC : O_WRONLY | O_APPEND;
263 if ((file = open (output, mode, 0666)) == -1)
269 if (nelements > history_length)
270 nelements = history_length;
272 /* Build a buffer of all the lines to write, and write them in one syscall.
273 Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */
275 HIST_ENTRY **the_history; /* local */
280 the_history = history_list ();
281 /* Calculate the total number of bytes to write. */
282 for (buffer_size = 0, i = history_length - nelements; i < history_length; i++)
283 buffer_size += 1 + strlen (the_history[i]->line);
285 /* Allocate the buffer, and fill it. */
286 buffer = xmalloc (buffer_size);
288 for (j = 0, i = history_length - nelements; i < history_length; i++)
290 strcpy (buffer + j, the_history[i]->line);
291 j += strlen (the_history[i]->line);
295 write (file, buffer, buffer_size);
306 /* Append NELEMENT entries to FILENAME. The entries appended are from
307 the end of the list minus NELEMENTs up to the end of the list. */
309 append_history (nelements, filename)
313 return (history_do_write (filename, nelements, HISTORY_APPEND));
316 /* Overwrite FILENAME with the current history. If FILENAME is NULL,
317 then write the history list to ~/.history. Values returned
318 are as in read_history ().*/
320 write_history (filename)
323 return (history_do_write (filename, history_length, HISTORY_OVERWRITE));