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
));