xref: /dragonfly/contrib/gdb-7/readline/histfile.c (revision d4ef6694)
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 }
553