]> git.ipfire.org Git - thirdparty/bash.git/blob - lib/readline/histfile.c
Imported from ../bash-2.05.tar.gz.
[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 2, 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 59 Temple Place, Suite 330, Boston, MA 02111 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 "posixstat.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
58 /* If we're compiling for __EMX__ (OS/2) or __CYGWIN__ (cygwin32 environment
59 on win 95/98/nt), we want to open files with O_BINARY mode so that there
60 is no \n -> \r\n conversion performed. On other systems, we don't want to
61 mess around with O_BINARY at all, so we ensure that it's defined to 0. */
62 #if defined (__EMX__) || defined (__CYGWIN__)
63 # ifndef O_BINARY
64 # define O_BINARY 0
65 # endif
66 #else /* !__EMX__ && !__CYGWIN__ */
67 # undef O_BINARY
68 # define O_BINARY 0
69 #endif /* !__EMX__ && !__CYGWIN__ */
70
71 #include <errno.h>
72 #if !defined (errno)
73 extern int errno;
74 #endif /* !errno */
75
76 #include "history.h"
77 #include "histlib.h"
78
79 #include "rlshell.h"
80 #include "xmalloc.h"
81
82 /* Return the string that should be used in the place of this
83 filename. This only matters when you don't specify the
84 filename to read_history (), or write_history (). */
85 static char *
86 history_filename (filename)
87 const char *filename;
88 {
89 char *return_val;
90 const char *home;
91 int home_len;
92
93 return_val = filename ? savestring (filename) : (char *)NULL;
94
95 if (return_val)
96 return (return_val);
97
98 home = sh_get_env_value ("HOME");
99
100 if (home == 0)
101 {
102 home = ".";
103 home_len = 1;
104 }
105 else
106 home_len = strlen (home);
107
108 return_val = xmalloc (2 + home_len + 8); /* strlen(".history") == 8 */
109 strcpy (return_val, home);
110 return_val[home_len] = '/';
111 #if defined (__MSDOS__)
112 strcpy (return_val + home_len + 1, "_history");
113 #else
114 strcpy (return_val + home_len + 1, ".history");
115 #endif
116
117 return (return_val);
118 }
119
120 /* Add the contents of FILENAME to the history list, a line at a time.
121 If FILENAME is NULL, then read from ~/.history. Returns 0 if
122 successful, or errno if not. */
123 int
124 read_history (filename)
125 const char *filename;
126 {
127 return (read_history_range (filename, 0, -1));
128 }
129
130 /* Read a range of lines from FILENAME, adding them to the history list.
131 Start reading at the FROM'th line and end at the TO'th. If FROM
132 is zero, start at the beginning. If TO is less than FROM, read
133 until the end of the file. If FILENAME is NULL, then read from
134 ~/.history. Returns 0 if successful, or errno if not. */
135 int
136 read_history_range (filename, from, to)
137 const char *filename;
138 int from, to;
139 {
140 register int line_start, line_end;
141 char *input, *buffer;
142 int file, current_line, chars_read;
143 struct stat finfo;
144 size_t file_size;
145
146 buffer = (char *)NULL;
147 input = history_filename (filename);
148 file = open (input, O_RDONLY|O_BINARY, 0666);
149
150 if ((file < 0) || (fstat (file, &finfo) == -1))
151 goto error_and_exit;
152
153 file_size = (size_t)finfo.st_size;
154
155 /* check for overflow on very large files */
156 if (file_size != finfo.st_size || file_size + 1 < file_size)
157 {
158 #if defined (EFBIG)
159 errno = EFBIG;
160 #endif
161 goto error_and_exit;
162 }
163
164 buffer = xmalloc (file_size + 1);
165
166 chars_read = read (file, buffer, file_size);
167 if (chars_read < 0)
168 {
169 error_and_exit:
170 if (file >= 0)
171 close (file);
172
173 FREE (input);
174 FREE (buffer);
175
176 return (errno);
177 }
178
179 close (file);
180
181 /* Set TO to larger than end of file if negative. */
182 if (to < 0)
183 to = chars_read;
184
185 /* Start at beginning of file, work to end. */
186 line_start = line_end = current_line = 0;
187
188 /* Skip lines until we are at FROM. */
189 while (line_start < chars_read && current_line < from)
190 {
191 for (line_end = line_start; line_end < chars_read; line_end++)
192 if (buffer[line_end] == '\n')
193 {
194 current_line++;
195 line_start = line_end + 1;
196 if (current_line == from)
197 break;
198 }
199 }
200
201 /* If there are lines left to gobble, then gobble them now. */
202 for (line_end = line_start; line_end < chars_read; line_end++)
203 if (buffer[line_end] == '\n')
204 {
205 buffer[line_end] = '\0';
206
207 if (buffer[line_start])
208 add_history (buffer + line_start);
209
210 current_line++;
211
212 if (current_line >= to)
213 break;
214
215 line_start = line_end + 1;
216 }
217
218 FREE (input);
219 FREE (buffer);
220
221 return (0);
222 }
223
224 /* Truncate the history file FNAME, leaving only LINES trailing lines.
225 If FNAME is NULL, then use ~/.history. Returns 0 on success, errno
226 on failure. */
227 int
228 history_truncate_file (fname, lines)
229 const char *fname;
230 int lines;
231 {
232 register int i;
233 int file, chars_read, rv;
234 char *buffer, *filename;
235 struct stat finfo;
236 size_t file_size;
237
238 buffer = (char *)NULL;
239 filename = history_filename (fname);
240 file = open (filename, O_RDONLY|O_BINARY, 0666);
241 rv = 0;
242
243 /* Don't try to truncate non-regular files. */
244 if (file == -1 || fstat (file, &finfo) == -1)
245 {
246 rv = errno;
247 if (file != -1)
248 close (file);
249 goto truncate_exit;
250 }
251
252 if (S_ISREG (finfo.st_mode) == 0)
253 {
254 close (file);
255 #ifdef EFTYPE
256 rv = EFTYPE;
257 #else
258 rv = EINVAL;
259 #endif
260 goto truncate_exit;
261 }
262
263 file_size = (size_t)finfo.st_size;
264
265 /* check for overflow on very large files */
266 if (file_size != finfo.st_size || file_size + 1 < file_size)
267 {
268 close (file);
269 #if defined (EFBIG)
270 rv = errno = EFBIG;
271 #elif defined (EOVERFLOW)
272 rv = errno = EOVERFLOW;
273 #else
274 rv = errno = EINVAL;
275 #endif
276 goto truncate_exit;
277 }
278
279 buffer = xmalloc (file_size + 1);
280 chars_read = read (file, buffer, file_size);
281 close (file);
282
283 if (chars_read <= 0)
284 {
285 rv = (chars_read < 0) ? errno : 0;
286 goto truncate_exit;
287 }
288
289 /* Count backwards from the end of buffer until we have passed
290 LINES lines. */
291 for (i = chars_read - 1; lines && i; i--)
292 {
293 if (buffer[i] == '\n')
294 lines--;
295 }
296
297 /* If this is the first line, then the file contains exactly the
298 number of lines we want to truncate to, so we don't need to do
299 anything. It's the first line if we don't find a newline between
300 the current value of i and 0. Otherwise, write from the start of
301 this line until the end of the buffer. */
302 for ( ; i; i--)
303 if (buffer[i] == '\n')
304 {
305 i++;
306 break;
307 }
308
309 /* Write only if there are more lines in the file than we want to
310 truncate to. */
311 if (i && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1))
312 {
313 write (file, buffer + i, chars_read - i);
314
315 #if defined (__BEOS__)
316 /* BeOS ignores O_TRUNC. */
317 ftruncate (file, chars_read - i);
318 #endif
319
320 close (file);
321 }
322
323 truncate_exit:
324
325 FREE (buffer);
326
327 free (filename);
328 return rv;
329 }
330
331 /* Workhorse function for writing history. Writes NELEMENT entries
332 from the history list to FILENAME. OVERWRITE is non-zero if you
333 wish to replace FILENAME with the entries. */
334 static int
335 history_do_write (filename, nelements, overwrite)
336 const char *filename;
337 int nelements, overwrite;
338 {
339 register int i;
340 char *output;
341 int file, mode, rv;
342
343 mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
344 output = history_filename (filename);
345 rv = 0;
346
347 if ((file = open (output, mode, 0600)) == -1)
348 {
349 FREE (output);
350 return (errno);
351 }
352
353 if (nelements > history_length)
354 nelements = history_length;
355
356 /* Build a buffer of all the lines to write, and write them in one syscall.
357 Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */
358 {
359 HIST_ENTRY **the_history; /* local */
360 register int j;
361 int buffer_size;
362 char *buffer;
363
364 the_history = history_list ();
365 /* Calculate the total number of bytes to write. */
366 for (buffer_size = 0, i = history_length - nelements; i < history_length; i++)
367 buffer_size += 1 + strlen (the_history[i]->line);
368
369 /* Allocate the buffer, and fill it. */
370 buffer = xmalloc (buffer_size);
371
372 for (j = 0, i = history_length - nelements; i < history_length; i++)
373 {
374 strcpy (buffer + j, the_history[i]->line);
375 j += strlen (the_history[i]->line);
376 buffer[j++] = '\n';
377 }
378
379 if (write (file, buffer, buffer_size) < 0)
380 rv = errno;
381 free (buffer);
382 }
383
384 close (file);
385
386 FREE (output);
387
388 return (rv);
389 }
390
391 /* Append NELEMENT entries to FILENAME. The entries appended are from
392 the end of the list minus NELEMENTs up to the end of the list. */
393 int
394 append_history (nelements, filename)
395 int nelements;
396 const char *filename;
397 {
398 return (history_do_write (filename, nelements, HISTORY_APPEND));
399 }
400
401 /* Overwrite FILENAME with the current history. If FILENAME is NULL,
402 then write the history list to ~/.history. Values returned
403 are as in read_history ().*/
404 int
405 write_history (filename)
406 const char *filename;
407 {
408 return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
409 }