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