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>
36
# include <sys/file.h>
41
#if defined (HAVE_STDLIB_H)
44
# include "ansi_stdlib.h"
45
#endif /* HAVE_STDLIB_H */
47
#if defined (HAVE_UNISTD_H)
51
#if defined (HAVE_STRING_H)
55
#endif /* !HAVE_STRING_H */
62
/* If we're not compiling for __EMX__, we don't want this at all. Ever. */
75
/* Functions imported from shell.c */
76
extern char *get_env_value ();
78
extern char *xmalloc (), *xrealloc ();
80
/* Return the string that should be used in the place of this
81
filename. This only matters when you don't specify the
82
filename to read_history (), or write_history (). */
84
history_filename (filename)
87
char *return_val, *home;
90
return_val = filename ? savestring (filename) : (char *)NULL;
95
home = get_env_value ("HOME");
103
home_len = strlen (home);
105
return_val = xmalloc (2 + home_len + 8); /* strlen(".history") == 8 */
106
strcpy (return_val, home);
107
return_val[home_len] = '/';
108
strcpy (return_val + home_len + 1, ".history");
113
/* Add the contents of FILENAME to the history list, a line at a time.
114
If FILENAME is NULL, then read from ~/.history. Returns 0 if
115
successful, or errno if not. */
117
read_history (filename)
120
return (read_history_range (filename, 0, -1));
123
/* Read a range of lines from FILENAME, adding them to the history list.
124
Start reading at the FROM'th line and end at the TO'th. If FROM
125
is zero, start at the beginning. If TO is less than FROM, read
126
until the end of the file. If FILENAME is NULL, then read from
127
~/.history. Returns 0 if successful, or errno if not. */
129
read_history_range (filename, from, to)
133
register int line_start, line_end;
134
char *input, *buffer;
135
int file, current_line;
139
buffer = (char *)NULL;
140
input = history_filename (filename);
141
file = open (input, O_RDONLY|O_BINARY, 0666);
143
if ((file < 0) || (fstat (file, &finfo) == -1))
146
file_size = (size_t)finfo.st_size;
148
/* check for overflow on very large files */
149
if (file_size != finfo.st_size || file_size + 1 < file_size)
157
buffer = xmalloc (file_size + 1);
159
if (read (file, buffer, file_size) != file_size)
161
if (read (file, buffer, file_size) < 0)
176
/* Set TO to larger than end of file if negative. */
180
/* Start at beginning of file, work to end. */
181
line_start = line_end = current_line = 0;
183
/* Skip lines until we are at FROM. */
184
while (line_start < file_size && current_line < from)
186
for (line_end = line_start; line_end < file_size; line_end++)
187
if (buffer[line_end] == '\n')
190
line_start = line_end + 1;
191
if (current_line == from)
196
/* If there are lines left to gobble, then gobble them now. */
197
for (line_end = line_start; line_end < file_size; line_end++)
198
if (buffer[line_end] == '\n')
200
buffer[line_end] = '\0';
202
if (buffer[line_start])
203
add_history (buffer + line_start);
207
if (current_line >= to)
210
line_start = line_end + 1;
219
/* Truncate the history file FNAME, leaving only LINES trailing lines.
220
If FNAME is NULL, then use ~/.history. */
222
history_truncate_file (fname, lines)
227
int file, chars_read;
228
char *buffer, *filename;
232
buffer = (char *)NULL;
233
filename = history_filename (fname);
234
file = open (filename, O_RDONLY|O_BINARY, 0666);
236
if (file == -1 || fstat (file, &finfo) == -1)
239
file_size = (size_t)finfo.st_size;
241
/* check for overflow on very large files */
242
if (file_size != finfo.st_size || file_size + 1 < file_size)
251
buffer = xmalloc (file_size + 1);
252
chars_read = read (file, buffer, file_size);
258
/* Count backwards from the end of buffer until we have passed
260
for (i = chars_read - 1; lines && i; i--)
262
if (buffer[i] == '\n')
266
/* If this is the first line, then the file contains exactly the
267
number of lines we want to truncate to, so we don't need to do
268
anything. It's the first line if we don't find a newline between
269
the current value of i and 0. Otherwise, write from the start of
270
this line until the end of the buffer. */
272
if (buffer[i] == '\n')
278
/* Write only if there are more lines in the file than we want to
280
if (i && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1))
282
write (file, buffer + i, file_size - i);
284
#if defined (__BEOS__)
285
/* BeOS ignores O_TRUNC. */
286
ftruncate (file, file_size - i);
300
/* Workhorse function for writing history. Writes NELEMENT entries
301
from the history list to FILENAME. OVERWRITE is non-zero if you
302
wish to replace FILENAME with the entries. */
304
history_do_write (filename, nelements, overwrite)
306
int nelements, overwrite;
312
mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
313
output = history_filename (filename);
315
if ((file = open (output, mode, 0600)) == -1)
321
if (nelements > history_length)
322
nelements = history_length;
324
/* Build a buffer of all the lines to write, and write them in one syscall.
325
Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */
327
HIST_ENTRY **the_history; /* local */
332
the_history = history_list ();
333
/* Calculate the total number of bytes to write. */
334
for (buffer_size = 0, i = history_length - nelements; i < history_length; i++)
335
buffer_size += 1 + strlen (the_history[i]->line);
337
/* Allocate the buffer, and fill it. */
338
buffer = xmalloc (buffer_size);
340
for (j = 0, i = history_length - nelements; i < history_length; i++)
342
strcpy (buffer + j, the_history[i]->line);
343
j += strlen (the_history[i]->line);
347
write (file, buffer, buffer_size);
358
/* Append NELEMENT entries to FILENAME. The entries appended are from
359
the end of the list minus NELEMENTs up to the end of the list. */
361
append_history (nelements, filename)
365
return (history_do_write (filename, nelements, HISTORY_APPEND));
368
/* Overwrite FILENAME with the current history. If FILENAME is NULL,
369
then write the history list to ~/.history. Values returned
370
are as in read_history ().*/
372
write_history (filename)
375
return (history_do_write (filename, history_length, HISTORY_OVERWRITE));