]> git.ipfire.org Git - thirdparty/bash.git/blob - lib/readline/histfile.c
81dda57d0fe6aa1417d356127578aff98533f29a
[thirdparty/bash.git] / lib / readline / histfile.c
1 /* histfile.c - functions to manipulate the history file. */
2
3 /* Copyright (C) 1989, 1992 Free Software Foundation, Inc.
4
5 This file contains the GNU History Library (the Library), a set of
6 routines for managing the text of previously typed lines.
7
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)
11 any later version.
12
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.
17
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. */
22
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
27
28 #if defined (HAVE_CONFIG_H)
29 # include <config.h>
30 #endif
31
32 #include <stdio.h>
33
34 #include <sys/types.h>
35 #ifndef _MINIX
36 # include <sys/file.h>
37 #endif
38 #include <sys/stat.h>
39 #include <fcntl.h>
40
41 #if defined (HAVE_STDLIB_H)
42 # include <stdlib.h>
43 #else
44 # include "ansi_stdlib.h"
45 #endif /* HAVE_STDLIB_H */
46
47 #if defined (HAVE_UNISTD_H)
48 # include <unistd.h>
49 #endif
50
51 #if defined (HAVE_STRING_H)
52 # include <string.h>
53 #else
54 # include <strings.h>
55 #endif /* !HAVE_STRING_H */
56
57 #if defined (__EMX__)
58 # ifndef O_BINARY
59 # define O_BINARY 0
60 # endif
61 #else /* !__EMX__ */
62 /* If we're not compiling for __EMX__, we don't want this at all. Ever. */
63 # undef O_BINARY
64 # define O_BINARY 0
65 #endif /* !__EMX__ */
66
67 #include <errno.h>
68 #if !defined (errno)
69 extern int errno;
70 #endif /* !errno */
71
72 #include "history.h"
73 #include "histlib.h"
74
75 /* Functions imported from shell.c */
76 extern char *get_env_value ();
77
78 extern char *xmalloc (), *xrealloc ();
79
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 (). */
83 static char *
84 history_filename (filename)
85 char *filename;
86 {
87 char *return_val, *home;
88 int home_len;
89
90 return_val = filename ? savestring (filename) : (char *)NULL;
91
92 if (return_val)
93 return (return_val);
94
95 home = get_env_value ("HOME");
96
97 if (home == 0)
98 {
99 home = ".";
100 home_len = 1;
101 }
102 else
103 home_len = strlen (home);
104
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");
109
110 return (return_val);
111 }
112
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. */
116 int
117 read_history (filename)
118 char *filename;
119 {
120 return (read_history_range (filename, 0, -1));
121 }
122
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. */
128 int
129 read_history_range (filename, from, to)
130 char *filename;
131 int from, to;
132 {
133 register int line_start, line_end;
134 char *input, *buffer;
135 int file, current_line;
136 struct stat finfo;
137 size_t file_size;
138
139 buffer = (char *)NULL;
140 input = history_filename (filename);
141 file = open (input, O_RDONLY|O_BINARY, 0666);
142
143 if ((file < 0) || (fstat (file, &finfo) == -1))
144 goto error_and_exit;
145
146 file_size = (size_t)finfo.st_size;
147
148 /* check for overflow on very large files */
149 if (file_size != finfo.st_size || file_size + 1 < file_size)
150 {
151 #if defined (EFBIG)
152 errno = EFBIG;
153 #endif
154 goto error_and_exit;
155 }
156
157 buffer = xmalloc (file_size + 1);
158 if (read (file, buffer, file_size) != file_size)
159 {
160 error_and_exit:
161 if (file >= 0)
162 close (file);
163
164 FREE (input);
165 FREE (buffer);
166
167 return (errno);
168 }
169
170 close (file);
171
172 /* Set TO to larger than end of file if negative. */
173 if (to < 0)
174 to = file_size;
175
176 /* Start at beginning of file, work to end. */
177 line_start = line_end = current_line = 0;
178
179 /* Skip lines until we are at FROM. */
180 while (line_start < file_size && current_line < from)
181 {
182 for (line_end = line_start; line_end < file_size; line_end++)
183 if (buffer[line_end] == '\n')
184 {
185 current_line++;
186 line_start = line_end + 1;
187 if (current_line == from)
188 break;
189 }
190 }
191
192 /* If there are lines left to gobble, then gobble them now. */
193 for (line_end = line_start; line_end < file_size; line_end++)
194 if (buffer[line_end] == '\n')
195 {
196 buffer[line_end] = '\0';
197
198 if (buffer[line_start])
199 add_history (buffer + line_start);
200
201 current_line++;
202
203 if (current_line >= to)
204 break;
205
206 line_start = line_end + 1;
207 }
208
209 FREE (input);
210 FREE (buffer);
211
212 return (0);
213 }
214
215 /* Truncate the history file FNAME, leaving only LINES trailing lines.
216 If FNAME is NULL, then use ~/.history. */
217 int
218 history_truncate_file (fname, lines)
219 char *fname;
220 register int lines;
221 {
222 register int i;
223 int file, chars_read;
224 char *buffer, *filename;
225 struct stat finfo;
226 size_t file_size;
227
228 buffer = (char *)NULL;
229 filename = history_filename (fname);
230 file = open (filename, O_RDONLY|O_BINARY, 0666);
231
232 if (file == -1 || fstat (file, &finfo) == -1)
233 goto truncate_exit;
234
235 file_size = (size_t)finfo.st_size;
236
237 /* check for overflow on very large files */
238 if (file_size != finfo.st_size || file_size + 1 < file_size)
239 {
240 close (file);
241 #if defined (EFBIG)
242 errno = EFBIG;
243 #endif
244 goto truncate_exit;
245 }
246
247 buffer = xmalloc (file_size + 1);
248 chars_read = read (file, buffer, file_size);
249 close (file);
250
251 if (chars_read <= 0)
252 goto truncate_exit;
253
254 /* Count backwards from the end of buffer until we have passed
255 LINES lines. */
256 for (i = chars_read - 1; lines && i; i--)
257 {
258 if (buffer[i] == '\n')
259 lines--;
260 }
261
262 /* If this is the first line, then the file contains exactly the
263 number of lines we want to truncate to, so we don't need to do
264 anything. It's the first line if we don't find a newline between
265 the current value of i and 0. Otherwise, write from the start of
266 this line until the end of the buffer. */
267 for ( ; i; i--)
268 if (buffer[i] == '\n')
269 {
270 i++;
271 break;
272 }
273
274 /* Write only if there are more lines in the file than we want to
275 truncate to. */
276 if (i && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1))
277 {
278 write (file, buffer + i, file_size - i);
279 close (file);
280 }
281
282 truncate_exit:
283
284 FREE (buffer);
285
286 free (filename);
287 return 0;
288 }
289
290 /* Workhorse function for writing history. Writes NELEMENT entries
291 from the history list to FILENAME. OVERWRITE is non-zero if you
292 wish to replace FILENAME with the entries. */
293 static int
294 history_do_write (filename, nelements, overwrite)
295 char *filename;
296 int nelements, overwrite;
297 {
298 register int i;
299 char *output;
300 int file, mode;
301
302 mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
303 output = history_filename (filename);
304
305 if ((file = open (output, mode, 0600)) == -1)
306 {
307 FREE (output);
308 return (errno);
309 }
310
311 if (nelements > history_length)
312 nelements = history_length;
313
314 /* Build a buffer of all the lines to write, and write them in one syscall.
315 Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */
316 {
317 HIST_ENTRY **the_history; /* local */
318 register int j;
319 int buffer_size;
320 char *buffer;
321
322 the_history = history_list ();
323 /* Calculate the total number of bytes to write. */
324 for (buffer_size = 0, i = history_length - nelements; i < history_length; i++)
325 buffer_size += 1 + strlen (the_history[i]->line);
326
327 /* Allocate the buffer, and fill it. */
328 buffer = xmalloc (buffer_size);
329
330 for (j = 0, i = history_length - nelements; i < history_length; i++)
331 {
332 strcpy (buffer + j, the_history[i]->line);
333 j += strlen (the_history[i]->line);
334 buffer[j++] = '\n';
335 }
336
337 write (file, buffer, buffer_size);
338 free (buffer);
339 }
340
341 close (file);
342
343 FREE (output);
344
345 return (0);
346 }
347
348 /* Append NELEMENT entries to FILENAME. The entries appended are from
349 the end of the list minus NELEMENTs up to the end of the list. */
350 int
351 append_history (nelements, filename)
352 int nelements;
353 char *filename;
354 {
355 return (history_do_write (filename, nelements, HISTORY_APPEND));
356 }
357
358 /* Overwrite FILENAME with the current history. If FILENAME is NULL,
359 then write the history list to ~/.history. Values returned
360 are as in read_history ().*/
361 int
362 write_history (filename)
363 char *filename;
364 {
365 return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
366 }