Merge from vendor branch GCC:
[dragonfly.git] / contrib / readline-5.0 / 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         *line_end = '\0';
260
261         if (*line_start)
262           {
263             if (HIST_TIMESTAMP_START(line_start) == 0)
264               {
265                 add_history (line_start);
266                 if (last_ts)
267                   {
268                     add_history_time (last_ts);
269                     last_ts = NULL;
270                   }
271               }
272             else
273               {
274                 last_ts = line_start;
275                 current_line--;
276               }
277           }
278
279         current_line++;
280
281         if (current_line >= to)
282           break;
283
284         line_start = line_end + 1;
285       }
286
287   FREE (input);
288 #ifndef HISTORY_USE_MMAP
289   FREE (buffer);
290 #else
291   munmap (buffer, file_size);
292 #endif
293
294   return (0);
295 }
296
297 /* Truncate the history file FNAME, leaving only LINES trailing lines.
298    If FNAME is NULL, then use ~/.history.  Returns 0 on success, errno
299    on failure. */
300 int
301 history_truncate_file (fname, lines)
302      const char *fname;
303      int lines;
304 {
305   char *buffer, *filename, *bp, *bp1;           /* bp1 == bp+1 */
306   int file, chars_read, rv;
307   struct stat finfo;
308   size_t file_size;
309
310   buffer = (char *)NULL;
311   filename = history_filename (fname);
312   file = open (filename, O_RDONLY|O_BINARY, 0666);
313   rv = 0;
314
315   /* Don't try to truncate non-regular files. */
316   if (file == -1 || fstat (file, &finfo) == -1)
317     {
318       rv = errno;
319       if (file != -1)
320         close (file);
321       goto truncate_exit;
322     }
323
324   if (S_ISREG (finfo.st_mode) == 0)
325     {
326       close (file);
327 #ifdef EFTYPE
328       rv = EFTYPE;
329 #else
330       rv = EINVAL;
331 #endif
332       goto truncate_exit;
333     }
334
335   file_size = (size_t)finfo.st_size;
336
337   /* check for overflow on very large files */
338   if (file_size != finfo.st_size || file_size + 1 < file_size)
339     {
340       close (file);
341 #if defined (EFBIG)
342       rv = errno = EFBIG;
343 #elif defined (EOVERFLOW)
344       rv = errno = EOVERFLOW;
345 #else
346       rv = errno = EINVAL;
347 #endif
348       goto truncate_exit;
349     }
350
351   buffer = (char *)malloc (file_size + 1);
352   if (buffer == 0)
353     {
354       close (file);
355       goto truncate_exit;
356     }
357
358   chars_read = read (file, buffer, file_size);
359   close (file);
360
361   if (chars_read <= 0)
362     {
363       rv = (chars_read < 0) ? errno : 0;
364       goto truncate_exit;
365     }
366
367   /* Count backwards from the end of buffer until we have passed
368      LINES lines.  bp1 is set funny initially.  But since bp[1] can't
369      be a comment character (since it's off the end) and *bp can't be
370      both a newline and the history comment character, it should be OK. */
371   for (bp1 = bp = buffer + chars_read - 1; lines && bp > buffer; bp--)
372     {
373       if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
374         lines--;
375       bp1 = bp;
376     }
377
378   /* If this is the first line, then the file contains exactly the
379      number of lines we want to truncate to, so we don't need to do
380      anything.  It's the first line if we don't find a newline between
381      the current value of i and 0.  Otherwise, write from the start of
382      this line until the end of the buffer. */
383   for ( ; bp > buffer; bp--)
384     {
385       if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
386         {
387           bp++;
388           break;
389         }
390       bp1 = bp;
391     }
392
393   /* Write only if there are more lines in the file than we want to
394      truncate to. */
395   if (bp > buffer && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1))
396     {
397       write (file, bp, chars_read - (bp - buffer));
398
399 #if defined (__BEOS__)
400       /* BeOS ignores O_TRUNC. */
401       ftruncate (file, chars_read - (bp - buffer));
402 #endif
403
404       close (file);
405     }
406
407  truncate_exit:
408
409   FREE (buffer);
410
411   free (filename);
412   return rv;
413 }
414
415 /* Workhorse function for writing history.  Writes NELEMENT entries
416    from the history list to FILENAME.  OVERWRITE is non-zero if you
417    wish to replace FILENAME with the entries. */
418 static int
419 history_do_write (filename, nelements, overwrite)
420      const char *filename;
421      int nelements, overwrite;
422 {
423   register int i;
424   char *output;
425   int file, mode, rv;
426 #ifdef HISTORY_USE_MMAP
427   size_t cursize;
428
429   mode = overwrite ? O_RDWR|O_CREAT|O_TRUNC|O_BINARY : O_RDWR|O_APPEND|O_BINARY;
430 #else
431   mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
432 #endif
433   output = history_filename (filename);
434   rv = 0;
435
436   if ((file = open (output, mode, 0600)) == -1)
437     {
438       FREE (output);
439       return (errno);
440     }
441
442 #ifdef HISTORY_USE_MMAP
443   cursize = overwrite ? 0 : lseek (file, 0, SEEK_END);
444 #endif
445
446   if (nelements > history_length)
447     nelements = history_length;
448
449   /* Build a buffer of all the lines to write, and write them in one syscall.
450      Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */
451   {
452     HIST_ENTRY **the_history;   /* local */
453     register int j;
454     int buffer_size;
455     char *buffer;
456
457     the_history = history_list ();
458     /* Calculate the total number of bytes to write. */
459     for (buffer_size = 0, i = history_length - nelements; i < history_length; i++)
460 #if 0
461       buffer_size += 2 + HISTENT_BYTES (the_history[i]);
462 #else
463       {
464         if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
465           buffer_size += strlen (the_history[i]->timestamp) + 1;
466         buffer_size += strlen (the_history[i]->line) + 1;
467       }
468 #endif
469
470     /* Allocate the buffer, and fill it. */
471 #ifdef HISTORY_USE_MMAP
472     if (ftruncate (file, buffer_size+cursize) == -1)
473       goto mmap_error;
474     buffer = (char *)mmap (0, buffer_size, PROT_READ|PROT_WRITE, MAP_WFLAGS, file, cursize);
475     if ((void *)buffer == MAP_FAILED)
476       {
477 mmap_error:
478         rv = errno;
479         FREE (output);
480         close (file);
481         return rv;
482       }
483 #else    
484     buffer = (char *)malloc (buffer_size);
485     if (buffer == 0)
486       {
487         rv = errno;
488         FREE (output);
489         close (file);
490         return rv;
491       }
492 #endif
493
494     for (j = 0, i = history_length - nelements; i < history_length; i++)
495       {
496         if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
497           {
498             strcpy (buffer + j, the_history[i]->timestamp);
499             j += strlen (the_history[i]->timestamp);
500             buffer[j++] = '\n';
501           }
502         strcpy (buffer + j, the_history[i]->line);
503         j += strlen (the_history[i]->line);
504         buffer[j++] = '\n';
505       }
506
507 #ifdef HISTORY_USE_MMAP
508     if (msync (buffer, buffer_size, 0) != 0 || munmap (buffer, buffer_size) != 0)
509       rv = errno;
510 #else
511     if (write (file, buffer, buffer_size) < 0)
512       rv = errno;
513     free (buffer);
514 #endif
515   }
516
517   close (file);
518
519   FREE (output);
520
521   return (rv);
522 }
523
524 /* Append NELEMENT entries to FILENAME.  The entries appended are from
525    the end of the list minus NELEMENTs up to the end of the list. */
526 int
527 append_history (nelements, filename)
528      int nelements;
529      const char *filename;
530 {
531   return (history_do_write (filename, nelements, HISTORY_APPEND));
532 }
533
534 /* Overwrite FILENAME with the current history.  If FILENAME is NULL,
535    then write the history list to ~/.history.  Values returned
536    are as in read_history ().*/
537 int
538 write_history (filename)
539      const char *filename;
540 {
541   return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
542 }