1 /* histfile.c - functions to manipulate the history file. */
3 /* Copyright (C) 1989, 1992 Free Software Foundation, Inc.
5 This file contains the GNU History Library (the Library), a set of
6 routines for managing the text of previously typed lines.
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)
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.
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. */
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
28 #if defined (HAVE_CONFIG_H)
34 #include <sys/types.h>
36 # include <sys/file.h>
38 #include "posixstat.h"
41 #if defined (HAVE_STDLIB_H)
44 # include "ansi_stdlib.h"
45 #endif /* HAVE_STDLIB_H */
47 #if defined (HAVE_UNISTD_H)
51 #if defined (__EMX__) || defined (__CYGWIN__)
56 # include <sys/mman.h>
59 # define MAP_RFLAGS (MAP_FILE|MAP_PRIVATE)
60 # define MAP_WFLAGS (MAP_FILE|MAP_SHARED)
62 # define MAP_RFLAGS MAP_PRIVATE
63 # define MAP_WFLAGS MAP_SHARED
67 # define MAP_FAILED ((void *)-1)
70 #endif /* HAVE_MMAP */
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__)
80 #else /* !__EMX__ && !__CYGWIN__ */
83 #endif /* !__EMX__ && !__CYGWIN__ */
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 (). */
100 history_filename (filename
)
101 const char *filename
;
107 return_val
= filename
? savestring (filename
) : (char *)NULL
;
112 home
= sh_get_env_value ("HOME");
120 home_len
= strlen (home
);
122 return_val
= (char *)xmalloc (2 + home_len
+ 8); /* strlen(".history") == 8 */
123 strcpy (return_val
, home
);
124 return_val
[home_len
] = '/';
125 #if defined (__MSDOS__)
126 strcpy (return_val
+ home_len
+ 1, "_history");
128 strcpy (return_val
+ home_len
+ 1, ".history");
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. */
138 read_history (filename
)
139 const char *filename
;
141 return (read_history_range (filename
, 0, -1));
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. */
150 read_history_range (filename
, from
, to
)
151 const char *filename
;
154 register char *line_start
, *line_end
;
155 char *input
, *buffer
, *bufend
;
156 int file
, current_line
, chars_read
;
160 buffer
= (char *)NULL
;
161 input
= history_filename (filename
);
162 file
= open (input
, O_RDONLY
|O_BINARY
, 0666);
164 if ((file
< 0) || (fstat (file
, &finfo
) == -1))
167 file_size
= (size_t)finfo
.st_size
;
169 /* check for overflow on very large files */
170 if (file_size
!= finfo
.st_size
|| file_size
+ 1 < file_size
)
174 #elif defined (EOVERFLOW)
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
)
186 chars_read
= file_size
;
188 buffer
= (char *)malloc (file_size
+ 1);
192 chars_read
= read (file
, buffer
, file_size
);
211 /* Set TO to larger than end of file if negative. */
215 /* Start at beginning of file, work to end. */
216 bufend
= buffer
+ chars_read
;
219 /* Skip lines until we are at FROM. */
220 for (line_start
= line_end
= buffer
; line_end
< bufend
&& current_line
< from
; line_end
++)
221 if (*line_end
== '\n')
224 line_start
= line_end
+ 1;
227 /* If there are lines left to gobble, then gobble them now. */
228 for (line_end
= line_start
; line_end
< bufend
; line_end
++)
229 if (*line_end
== '\n')
234 add_history (line_start
);
238 if (current_line
>= to
)
241 line_start
= line_end
+ 1;
248 munmap (buffer
, file_size
);
254 /* Truncate the history file FNAME, leaving only LINES trailing lines.
255 If FNAME is NULL, then use ~/.history. Returns 0 on success, errno
258 history_truncate_file (fname
, lines
)
262 char *buffer
, *filename
, *bp
;
263 int file
, chars_read
, rv
;
267 buffer
= (char *)NULL
;
268 filename
= history_filename (fname
);
269 file
= open (filename
, O_RDONLY
|O_BINARY
, 0666);
272 /* Don't try to truncate non-regular files. */
273 if (file
== -1 || fstat (file
, &finfo
) == -1)
281 if (S_ISREG (finfo
.st_mode
) == 0)
292 file_size
= (size_t)finfo
.st_size
;
294 /* check for overflow on very large files */
295 if (file_size
!= finfo
.st_size
|| file_size
+ 1 < file_size
)
300 #elif defined (EOVERFLOW)
301 rv
= errno
= EOVERFLOW
;
308 buffer
= (char *)malloc (file_size
+ 1);
315 chars_read
= read (file
, buffer
, file_size
);
320 rv
= (chars_read
< 0) ? errno
: 0;
324 /* Count backwards from the end of buffer until we have passed
326 for (bp
= buffer
+ chars_read
- 1; lines
&& bp
> buffer
; bp
--)
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. */
337 for ( ; bp
> buffer
; bp
--)
344 /* Write only if there are more lines in the file than we want to
346 if (bp
> buffer
&& ((file
= open (filename
, O_WRONLY
|O_TRUNC
|O_BINARY
, 0600)) != -1))
348 write (file
, bp
, chars_read
- (bp
- buffer
));
350 #if defined (__BEOS__)
351 /* BeOS ignores O_TRUNC. */
352 ftruncate (file
, chars_read
- (bp
- buffer
));
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. */
370 history_do_write (filename
, nelements
, overwrite
)
371 const char *filename
;
372 int nelements
, overwrite
;
380 mode
= overwrite
? O_RDWR
|O_CREAT
|O_TRUNC
|O_BINARY
: O_RDWR
|O_APPEND
|O_BINARY
;
382 mode
= overwrite
? O_WRONLY
|O_CREAT
|O_TRUNC
|O_BINARY
: O_WRONLY
|O_APPEND
|O_BINARY
;
384 output
= history_filename (filename
);
387 if ((file
= open (output
, mode
, 0600)) == -1)
394 cursize
= overwrite
? 0 : lseek (file
, 0, SEEK_END
);
397 if (nelements
> history_length
)
398 nelements
= history_length
;
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). */
403 HIST_ENTRY
**the_history
; /* local */
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
);
413 /* Allocate the buffer, and fill it. */
415 if (ftruncate (file
, buffer_size
+cursize
) == -1)
417 buffer
= (char *)mmap (0, buffer_size
, PROT_READ
|PROT_WRITE
, MAP_WFLAGS
, file
, cursize
);
418 if ((void *)buffer
== MAP_FAILED
)
427 buffer
= (char *)malloc (buffer_size
);
437 for (j
= 0, i
= history_length
- nelements
; i
< history_length
; i
++)
439 strcpy (buffer
+ j
, the_history
[i
]->line
);
440 j
+= strlen (the_history
[i
]->line
);
445 if (msync (buffer
, buffer_size
, 0) != 0 || munmap (buffer
, buffer_size
) != 0)
448 if (write (file
, buffer
, buffer_size
) < 0)
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. */
464 append_history (nelements
, filename
)
466 const char *filename
;
468 return (history_do_write (filename
, nelements
, HISTORY_APPEND
));
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 ().*/
475 write_history (filename
)
476 const char *filename
;
478 return (history_do_write (filename
, history_length
, HISTORY_OVERWRITE
));
This page took 0.040686 seconds and 4 git commands to generate.