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