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