]> git.ipfire.org Git - thirdparty/bash.git/blob - lib/readline/histfile.c
bash-4.3-beta overlay
[thirdparty/bash.git] / lib / readline / histfile.c
1 /* histfile.c - functions to manipulate the history file. */
2
3 /* Copyright (C) 1989-2010 Free Software Foundation, Inc.
4
5 This file contains the GNU History Library (History), a set of
6 routines for managing the text of previously typed lines.
7
8 History 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 3 of the License, or
11 (at your option) any later version.
12
13 History is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with History. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 /* The goal is to make the implementation transparent, so that you
23 don't have to know what data types are used, just what functions
24 you can call. I think I have done that. */
25
26 #define READLINE_LIBRARY
27
28 #if defined (__TANDEM)
29 # include <floss.h>
30 #endif
31
32 #if defined (HAVE_CONFIG_H)
33 # include <config.h>
34 #endif
35
36 #include <stdio.h>
37
38 #include <sys/types.h>
39 #if ! defined (_MINIX) && defined (HAVE_SYS_FILE_H)
40 # include <sys/file.h>
41 #endif
42 #include "posixstat.h"
43 #include <fcntl.h>
44
45 #if defined (HAVE_STDLIB_H)
46 # include <stdlib.h>
47 #else
48 # include "ansi_stdlib.h"
49 #endif /* HAVE_STDLIB_H */
50
51 #if defined (HAVE_UNISTD_H)
52 # include <unistd.h>
53 #endif
54
55 #include <ctype.h>
56
57 #if defined (__EMX__)
58 # undef HAVE_MMAP
59 #endif
60
61 #ifdef HISTORY_USE_MMAP
62 # include <sys/mman.h>
63
64 # ifdef MAP_FILE
65 # define MAP_RFLAGS (MAP_FILE|MAP_PRIVATE)
66 # define MAP_WFLAGS (MAP_FILE|MAP_SHARED)
67 # else
68 # define MAP_RFLAGS MAP_PRIVATE
69 # define MAP_WFLAGS MAP_SHARED
70 # endif
71
72 # ifndef MAP_FAILED
73 # define MAP_FAILED ((void *)-1)
74 # endif
75
76 #endif /* HISTORY_USE_MMAP */
77
78 /* If we're compiling for __EMX__ (OS/2) or __CYGWIN__ (cygwin32 environment
79 on win 95/98/nt), we want to open files with O_BINARY mode so that there
80 is no \n -> \r\n conversion performed. On other systems, we don't want to
81 mess around with O_BINARY at all, so we ensure that it's defined to 0. */
82 #if defined (__EMX__) || defined (__CYGWIN__)
83 # ifndef O_BINARY
84 # define O_BINARY 0
85 # endif
86 #else /* !__EMX__ && !__CYGWIN__ */
87 # undef O_BINARY
88 # define O_BINARY 0
89 #endif /* !__EMX__ && !__CYGWIN__ */
90
91 #include <errno.h>
92 #if !defined (errno)
93 extern int errno;
94 #endif /* !errno */
95
96 #include "history.h"
97 #include "histlib.h"
98
99 #include "rlshell.h"
100 #include "xmalloc.h"
101
102 /* If non-zero, we write timestamps to the history file in history_do_write() */
103 int history_write_timestamps = 0;
104
105 /* Does S look like the beginning of a history timestamp entry? Placeholder
106 for more extensive tests. */
107 #define HIST_TIMESTAMP_START(s) (*(s) == history_comment_char && isdigit ((s)[1]) )
108
109 /* Return the string that should be used in the place of this
110 filename. This only matters when you don't specify the
111 filename to read_history (), or write_history (). */
112 static char *
113 history_filename (filename)
114 const char *filename;
115 {
116 char *return_val;
117 const char *home;
118 int home_len;
119
120 return_val = filename ? savestring (filename) : (char *)NULL;
121
122 if (return_val)
123 return (return_val);
124
125 home = sh_get_env_value ("HOME");
126
127 if (home == 0)
128 return (NULL);
129 else
130 home_len = strlen (home);
131
132 return_val = (char *)xmalloc (2 + home_len + 8); /* strlen(".history") == 8 */
133 strcpy (return_val, home);
134 return_val[home_len] = '/';
135 #if defined (__MSDOS__)
136 strcpy (return_val + home_len + 1, "_history");
137 #else
138 strcpy (return_val + home_len + 1, ".history");
139 #endif
140
141 return (return_val);
142 }
143
144 static char *
145 history_backupfile (filename)
146 const char *filename;
147 {
148 char *ret;
149 size_t len;
150
151 len = strlen (filename);
152 ret = xmalloc (len + 2);
153 strcpy (ret, filename);
154 ret[len] = '-';
155 ret[len+1] = '\0';
156 return ret;
157 }
158
159 /* Add the contents of FILENAME to the history list, a line at a time.
160 If FILENAME is NULL, then read from ~/.history. Returns 0 if
161 successful, or errno if not. */
162 int
163 read_history (filename)
164 const char *filename;
165 {
166 return (read_history_range (filename, 0, -1));
167 }
168
169 /* Read a range of lines from FILENAME, adding them to the history list.
170 Start reading at the FROM'th line and end at the TO'th. If FROM
171 is zero, start at the beginning. If TO is less than FROM, read
172 until the end of the file. If FILENAME is NULL, then read from
173 ~/.history. Returns 0 if successful, or errno if not. */
174 int
175 read_history_range (filename, from, to)
176 const char *filename;
177 int from, to;
178 {
179 register char *line_start, *line_end, *p;
180 char *input, *buffer, *bufend, *last_ts;
181 int file, current_line, chars_read;
182 struct stat finfo;
183 size_t file_size;
184 #if defined (EFBIG)
185 int overflow_errno = EFBIG;
186 #elif defined (EOVERFLOW)
187 int overflow_errno = EOVERFLOW;
188 #else
189 int overflow_errno = EIO;
190 #endif
191
192 buffer = last_ts = (char *)NULL;
193 input = history_filename (filename);
194 file = input ? open (input, O_RDONLY|O_BINARY, 0666) : -1;
195
196 if ((file < 0) || (fstat (file, &finfo) == -1))
197 goto error_and_exit;
198
199 file_size = (size_t)finfo.st_size;
200
201 /* check for overflow on very large files */
202 if (file_size != finfo.st_size || file_size + 1 < file_size)
203 {
204 errno = overflow_errno;
205 goto error_and_exit;
206 }
207
208 #ifdef HISTORY_USE_MMAP
209 /* We map read/write and private so we can change newlines to NULs without
210 affecting the underlying object. */
211 buffer = (char *)mmap (0, file_size, PROT_READ|PROT_WRITE, MAP_RFLAGS, file, 0);
212 if ((void *)buffer == MAP_FAILED)
213 {
214 errno = overflow_errno;
215 goto error_and_exit;
216 }
217 chars_read = file_size;
218 #else
219 buffer = (char *)malloc (file_size + 1);
220 if (buffer == 0)
221 {
222 errno = overflow_errno;
223 goto error_and_exit;
224 }
225
226 chars_read = read (file, buffer, file_size);
227 #endif
228 if (chars_read < 0)
229 {
230 error_and_exit:
231 if (errno != 0)
232 chars_read = errno;
233 else
234 chars_read = EIO;
235 if (file >= 0)
236 close (file);
237
238 FREE (input);
239 #ifndef HISTORY_USE_MMAP
240 FREE (buffer);
241 #endif
242
243 return (chars_read);
244 }
245
246 close (file);
247
248 /* Set TO to larger than end of file if negative. */
249 if (to < 0)
250 to = chars_read;
251
252 /* Start at beginning of file, work to end. */
253 bufend = buffer + chars_read;
254 current_line = 0;
255
256 /* Skip lines until we are at FROM. */
257 for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++)
258 if (*line_end == '\n')
259 {
260 p = line_end + 1;
261 /* If we see something we think is a timestamp, continue with this
262 line. We should check more extensively here... */
263 if (HIST_TIMESTAMP_START(p) == 0)
264 current_line++;
265 line_start = p;
266 }
267
268 /* If there are lines left to gobble, then gobble them now. */
269 for (line_end = line_start; line_end < bufend; line_end++)
270 if (*line_end == '\n')
271 {
272 /* Change to allow Windows-like \r\n end of line delimiter. */
273 if (line_end > line_start && line_end[-1] == '\r')
274 line_end[-1] = '\0';
275 else
276 *line_end = '\0';
277
278 if (*line_start)
279 {
280 if (HIST_TIMESTAMP_START(line_start) == 0)
281 {
282 add_history (line_start);
283 if (last_ts)
284 {
285 add_history_time (last_ts);
286 last_ts = NULL;
287 }
288 }
289 else
290 {
291 last_ts = line_start;
292 current_line--;
293 }
294 }
295
296 current_line++;
297
298 if (current_line >= to)
299 break;
300
301 line_start = line_end + 1;
302 }
303
304 FREE (input);
305 #ifndef HISTORY_USE_MMAP
306 FREE (buffer);
307 #else
308 munmap (buffer, file_size);
309 #endif
310
311 return (0);
312 }
313
314 /* Truncate the history file FNAME, leaving only LINES trailing lines.
315 If FNAME is NULL, then use ~/.history. Returns 0 on success, errno
316 on failure. */
317 int
318 history_truncate_file (fname, lines)
319 const char *fname;
320 int lines;
321 {
322 char *buffer, *filename, *bp, *bp1; /* bp1 == bp+1 */
323 int file, chars_read, rv;
324 struct stat finfo;
325 size_t file_size;
326
327 buffer = (char *)NULL;
328 filename = history_filename (fname);
329 file = filename ? open (filename, O_RDONLY|O_BINARY, 0666) : -1;
330 rv = 0;
331
332 /* Don't try to truncate non-regular files. */
333 if (file == -1 || fstat (file, &finfo) == -1)
334 {
335 rv = errno;
336 if (file != -1)
337 close (file);
338 goto truncate_exit;
339 }
340
341 if (S_ISREG (finfo.st_mode) == 0)
342 {
343 close (file);
344 #ifdef EFTYPE
345 rv = EFTYPE;
346 #else
347 rv = EINVAL;
348 #endif
349 goto truncate_exit;
350 }
351
352 file_size = (size_t)finfo.st_size;
353
354 /* check for overflow on very large files */
355 if (file_size != finfo.st_size || file_size + 1 < file_size)
356 {
357 close (file);
358 #if defined (EFBIG)
359 rv = errno = EFBIG;
360 #elif defined (EOVERFLOW)
361 rv = errno = EOVERFLOW;
362 #else
363 rv = errno = EINVAL;
364 #endif
365 goto truncate_exit;
366 }
367
368 buffer = (char *)malloc (file_size + 1);
369 if (buffer == 0)
370 {
371 close (file);
372 goto truncate_exit;
373 }
374
375 chars_read = read (file, buffer, file_size);
376 close (file);
377
378 if (chars_read <= 0)
379 {
380 rv = (chars_read < 0) ? errno : 0;
381 goto truncate_exit;
382 }
383
384 /* Count backwards from the end of buffer until we have passed
385 LINES lines. bp1 is set funny initially. But since bp[1] can't
386 be a comment character (since it's off the end) and *bp can't be
387 both a newline and the history comment character, it should be OK. */
388 for (bp1 = bp = buffer + chars_read - 1; lines && bp > buffer; bp--)
389 {
390 if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
391 lines--;
392 bp1 = bp;
393 }
394
395 /* If this is the first line, then the file contains exactly the
396 number of lines we want to truncate to, so we don't need to do
397 anything. It's the first line if we don't find a newline between
398 the current value of i and 0. Otherwise, write from the start of
399 this line until the end of the buffer. */
400 for ( ; bp > buffer; bp--)
401 {
402 if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
403 {
404 bp++;
405 break;
406 }
407 bp1 = bp;
408 }
409
410 /* Write only if there are more lines in the file than we want to
411 truncate to. */
412 if (bp > buffer && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1))
413 {
414 if (write (file, bp, chars_read - (bp - buffer)) < 0)
415 rv = errno;
416
417 #if defined (__BEOS__)
418 /* BeOS ignores O_TRUNC. */
419 ftruncate (file, chars_read - (bp - buffer));
420 #endif
421
422 if (close (file) < 0 && rv == 0)
423 rv = errno;
424 }
425
426 truncate_exit:
427
428 FREE (buffer);
429
430 xfree (filename);
431 return rv;
432 }
433
434 /* Workhorse function for writing history. Writes NELEMENT entries
435 from the history list to FILENAME. OVERWRITE is non-zero if you
436 wish to replace FILENAME with the entries. */
437 static int
438 history_do_write (filename, nelements, overwrite)
439 const char *filename;
440 int nelements, overwrite;
441 {
442 register int i;
443 char *output, *bakname;
444 int file, mode, rv;
445 #ifdef HISTORY_USE_MMAP
446 size_t cursize;
447
448 mode = overwrite ? O_RDWR|O_CREAT|O_TRUNC|O_BINARY : O_RDWR|O_APPEND|O_BINARY;
449 #else
450 mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
451 #endif
452 output = history_filename (filename);
453 bakname = (overwrite && output) ? history_backupfile (output) : 0;
454
455 if (output && bakname)
456 rename (output, bakname);
457
458 file = output ? open (output, mode, 0600) : -1;
459 rv = 0;
460
461 if (file == -1)
462 {
463 rv = errno;
464 if (output && bakname)
465 rename (bakname, output);
466 FREE (output);
467 FREE (bakname);
468 return (rv);
469 }
470
471 #ifdef HISTORY_USE_MMAP
472 cursize = overwrite ? 0 : lseek (file, 0, SEEK_END);
473 #endif
474
475 if (nelements > history_length)
476 nelements = history_length;
477
478 /* Build a buffer of all the lines to write, and write them in one syscall.
479 Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */
480 {
481 HIST_ENTRY **the_history; /* local */
482 register int j;
483 int buffer_size;
484 char *buffer;
485
486 the_history = history_list ();
487 /* Calculate the total number of bytes to write. */
488 for (buffer_size = 0, i = history_length - nelements; i < history_length; i++)
489 #if 0
490 buffer_size += 2 + HISTENT_BYTES (the_history[i]);
491 #else
492 {
493 if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
494 buffer_size += strlen (the_history[i]->timestamp) + 1;
495 buffer_size += strlen (the_history[i]->line) + 1;
496 }
497 #endif
498
499 /* Allocate the buffer, and fill it. */
500 #ifdef HISTORY_USE_MMAP
501 if (ftruncate (file, buffer_size+cursize) == -1)
502 goto mmap_error;
503 buffer = (char *)mmap (0, buffer_size, PROT_READ|PROT_WRITE, MAP_WFLAGS, file, cursize);
504 if ((void *)buffer == MAP_FAILED)
505 {
506 mmap_error:
507 rv = errno;
508 close (file);
509 if (output && bakname)
510 rename (bakname, output);
511 FREE (output);
512 FREE (bakname);
513 return rv;
514 }
515 #else
516 buffer = (char *)malloc (buffer_size);
517 if (buffer == 0)
518 {
519 rv = errno;
520 close (file);
521 if (output && bakname)
522 rename (bakname, output);
523 FREE (output);
524 FREE (bakname);
525 return rv;
526 }
527 #endif
528
529 for (j = 0, i = history_length - nelements; i < history_length; i++)
530 {
531 if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
532 {
533 strcpy (buffer + j, the_history[i]->timestamp);
534 j += strlen (the_history[i]->timestamp);
535 buffer[j++] = '\n';
536 }
537 strcpy (buffer + j, the_history[i]->line);
538 j += strlen (the_history[i]->line);
539 buffer[j++] = '\n';
540 }
541
542 #ifdef HISTORY_USE_MMAP
543 if (msync (buffer, buffer_size, 0) != 0 || munmap (buffer, buffer_size) != 0)
544 rv = errno;
545 #else
546 if (write (file, buffer, buffer_size) < 0)
547 rv = errno;
548 xfree (buffer);
549 #endif
550 }
551
552 if (close (file) < 0 && rv == 0)
553 rv = errno;
554
555 if (rv != 0 && output && bakname)
556 rename (bakname, output);
557 else if (rv == 0 && bakname)
558 unlink (bakname);
559
560 FREE (output);
561 FREE (bakname);
562
563 return (rv);
564 }
565
566 /* Append NELEMENT entries to FILENAME. The entries appended are from
567 the end of the list minus NELEMENTs up to the end of the list. */
568 int
569 append_history (nelements, filename)
570 int nelements;
571 const char *filename;
572 {
573 return (history_do_write (filename, nelements, HISTORY_APPEND));
574 }
575
576 /* Overwrite FILENAME with the current history. If FILENAME is NULL,
577 then write the history list to ~/.history. Values returned
578 are as in read_history ().*/
579 int
580 write_history (filename)
581 const char *filename;
582 {
583 return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
584 }