OSDN Git Service

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