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    51 Franklin Street, Fifth Floor, Boston, MA  02110-1335  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_readline.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 *
history_filename(filename)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
read_history(filename)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
read_history_range(filename,from,to)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 ((sizeof(off_t) > sizeof(size_t) && finfo.st_size > (off_t)(size_t)~0) ||
190     file_size + 1 < file_size)
191     {
192       errno = overflow_errno;
193       goto error_and_exit;
194     }
195 
196 #ifdef HISTORY_USE_MMAP
197   /* We map read/write and private so we can change newlines to NULs without
198      affecting the underlying object. */
199   buffer = (char *)mmap (0, file_size, PROT_READ|PROT_WRITE, MAP_RFLAGS, file, 0);
200   if ((void *)buffer == MAP_FAILED)
201     {
202       errno = overflow_errno;
203       goto error_and_exit;
204     }
205   chars_read = file_size;
206 #else
207   buffer = (char *)malloc (file_size + 1);
208   if (buffer == 0)
209     {
210       errno = overflow_errno;
211       goto error_and_exit;
212     }
213 
214   chars_read = read (file, buffer, file_size);
215 #endif
216   if (chars_read < 0)
217     {
218   error_and_exit:
219       if (errno != 0)
220 	chars_read = errno;
221       else
222 	chars_read = EIO;
223       if (file >= 0)
224 	close (file);
225 
226       FREE (input);
227 #ifndef HISTORY_USE_MMAP
228       FREE (buffer);
229 #endif
230 
231       return (chars_read);
232     }
233 
234   close (file);
235 
236   /* Set TO to larger than end of file if negative. */
237   if (to < 0)
238     to = chars_read;
239 
240   /* Start at beginning of file, work to end. */
241   bufend = buffer + chars_read;
242   current_line = 0;
243 
244   /* Skip lines until we are at FROM. */
245   for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++)
246     if (*line_end == '\n')
247       {
248       	p = line_end + 1;
249       	/* If we see something we think is a timestamp, continue with this
250 	   line.  We should check more extensively here... */
251 	if (HIST_TIMESTAMP_START(p) == 0)
252 	  current_line++;
253 	line_start = p;
254       }
255 
256   /* If there are lines left to gobble, then gobble them now. */
257   for (line_end = line_start; line_end < bufend; line_end++)
258     if (*line_end == '\n')
259       {
260 	/* Change to allow Windows-like \r\n end of line delimiter. */
261 	if (line_end > line_start && line_end[-1] == '\r')
262 	  line_end[-1] = '\0';
263 	else
264 	  *line_end = '\0';
265 
266 	if (*line_start)
267 	  {
268 	    if (HIST_TIMESTAMP_START(line_start) == 0)
269 	      {
270 		add_history (line_start);
271 		if (last_ts)
272 		  {
273 		    add_history_time (last_ts);
274 		    last_ts = NULL;
275 		  }
276 	      }
277 	    else
278 	      {
279 		last_ts = line_start;
280 		current_line--;
281 	      }
282 	  }
283 
284 	current_line++;
285 
286 	if (current_line >= to)
287 	  break;
288 
289 	line_start = line_end + 1;
290       }
291 
292   FREE (input);
293 #ifndef HISTORY_USE_MMAP
294   FREE (buffer);
295 #else
296   munmap (buffer, file_size);
297 #endif
298 
299   return (0);
300 }
301 
302 /* Truncate the history file FNAME, leaving only LINES trailing lines.
303    If FNAME is NULL, then use ~/.history.  Returns 0 on success, errno
304    on failure. */
305 int
history_truncate_file(fname,lines)306 history_truncate_file (fname, lines)
307      const char *fname;
308      int lines;
309 {
310   char *buffer, *filename, *bp, *bp1;		/* bp1 == bp+1 */
311   int file, chars_read, rv;
312   struct stat finfo;
313   size_t file_size;
314   size_t bytes_written;
315 
316   buffer = (char *)NULL;
317   filename = history_filename (fname);
318   file = open (filename, O_RDONLY|O_BINARY, 0666);
319   rv = 0;
320 
321   /* Don't try to truncate non-regular files. */
322   if (file == -1 || fstat (file, &finfo) == -1)
323     {
324       rv = errno;
325       if (file != -1)
326 	close (file);
327       goto truncate_exit;
328     }
329 
330   if (S_ISREG (finfo.st_mode) == 0)
331     {
332       close (file);
333 #ifdef EFTYPE
334       rv = EFTYPE;
335 #else
336       rv = EINVAL;
337 #endif
338       goto truncate_exit;
339     }
340 
341   file_size = (size_t)finfo.st_size;
342 
343   /* check for overflow on very large files */
344   if ((sizeof(off_t) > sizeof(size_t) && finfo.st_size > (off_t)(size_t)~0) ||
345     file_size + 1 < file_size)
346     {
347       close (file);
348 #if defined (EFBIG)
349       rv = errno = EFBIG;
350 #elif defined (EOVERFLOW)
351       rv = errno = EOVERFLOW;
352 #else
353       rv = errno = EINVAL;
354 #endif
355       goto truncate_exit;
356     }
357 
358   buffer = (char *)malloc (file_size + 1);
359   if (buffer == 0)
360     {
361       close (file);
362       goto truncate_exit;
363     }
364 
365   chars_read = read (file, buffer, file_size);
366   close (file);
367 
368   if (chars_read <= 0)
369     {
370       rv = (chars_read < 0) ? errno : 0;
371       goto truncate_exit;
372     }
373 
374   /* Count backwards from the end of buffer until we have passed
375      LINES lines.  bp1 is set funny initially.  But since bp[1] can't
376      be a comment character (since it's off the end) and *bp can't be
377      both a newline and the history comment character, it should be OK. */
378   for (bp1 = bp = buffer + chars_read - 1; lines && bp > buffer; bp--)
379     {
380       if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
381 	lines--;
382       bp1 = bp;
383     }
384 
385   /* If this is the first line, then the file contains exactly the
386      number of lines we want to truncate to, so we don't need to do
387      anything.  It's the first line if we don't find a newline between
388      the current value of i and 0.  Otherwise, write from the start of
389      this line until the end of the buffer. */
390   for ( ; bp > buffer; bp--)
391     {
392       if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
393         {
394 	  bp++;
395 	  break;
396         }
397       bp1 = bp;
398     }
399 
400   /* Write only if there are more lines in the file than we want to
401      truncate to. */
402   if (bp > buffer && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1))
403     {
404       bytes_written= write (file, bp, chars_read - (bp - buffer));
405       (void) bytes_written;
406 
407 #if defined (__BEOS__)
408       /* BeOS ignores O_TRUNC. */
409       ftruncate (file, chars_read - (bp - buffer));
410 #endif
411 
412       close (file);
413     }
414 
415  truncate_exit:
416 
417   FREE (buffer);
418 
419   free (filename);
420   return rv;
421 }
422 
423 /* Workhorse function for writing history.  Writes NELEMENT entries
424    from the history list to FILENAME.  OVERWRITE is non-zero if you
425    wish to replace FILENAME with the entries. */
426 static int
history_do_write(filename,nelements,overwrite)427 history_do_write (filename, nelements, overwrite)
428      const char *filename;
429      int nelements, overwrite;
430 {
431   register int i;
432   char *output;
433   int file, mode, rv;
434 #ifdef HISTORY_USE_MMAP
435   size_t cursize;
436 
437   mode = overwrite ? O_RDWR|O_CREAT|O_TRUNC|O_BINARY : O_RDWR|O_APPEND|O_BINARY;
438 #else
439   mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
440 #endif
441   output = history_filename (filename);
442   rv = 0;
443 
444   if ((file = open (output, mode, 0600)) == -1)
445     {
446       FREE (output);
447       return (errno);
448     }
449 
450 #ifdef HISTORY_USE_MMAP
451   cursize = overwrite ? 0 : lseek (file, 0, SEEK_END);
452 #endif
453 
454   if (nelements > history_length)
455     nelements = history_length;
456 
457   /* Build a buffer of all the lines to write, and write them in one syscall.
458      Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */
459   {
460     HIST_ENTRY **the_history;	/* local */
461     register int j;
462     int buffer_size;
463     char *buffer;
464 
465     the_history = history_list ();
466     /* Calculate the total number of bytes to write. */
467     for (buffer_size = 0, i = history_length - nelements; i < history_length; i++)
468 #if 0
469       buffer_size += 2 + HISTENT_BYTES (the_history[i]);
470 #else
471       {
472 	if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
473 	  buffer_size += strlen (the_history[i]->timestamp) + 1;
474 	buffer_size += strlen (the_history[i]->line) + 1;
475       }
476 #endif
477 
478     /* Allocate the buffer, and fill it. */
479 #ifdef HISTORY_USE_MMAP
480     if (ftruncate (file, buffer_size+cursize) == -1)
481       goto mmap_error;
482     buffer = (char *)mmap (0, buffer_size, PROT_READ|PROT_WRITE, MAP_WFLAGS, file, cursize);
483     if ((void *)buffer == MAP_FAILED)
484       {
485 mmap_error:
486 	rv = errno;
487 	FREE (output);
488 	close (file);
489 	return rv;
490       }
491 #else
492     buffer = (char *)malloc (buffer_size);
493     if (buffer == 0)
494       {
495       	rv = errno;
496 	FREE (output);
497 	close (file);
498 	return rv;
499       }
500 #endif
501 
502     for (j = 0, i = history_length - nelements; i < history_length; i++)
503       {
504 	if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
505 	  {
506 	    strcpy (buffer + j, the_history[i]->timestamp);
507 	    j += strlen (the_history[i]->timestamp);
508 	    buffer[j++] = '\n';
509 	  }
510 	strcpy (buffer + j, the_history[i]->line);
511 	j += strlen (the_history[i]->line);
512 	buffer[j++] = '\n';
513       }
514 
515 #ifdef HISTORY_USE_MMAP
516     if (msync (buffer, buffer_size, 0) != 0 || munmap (buffer, buffer_size) != 0)
517       rv = errno;
518 #else
519     if (write (file, buffer, buffer_size) < 0)
520       rv = errno;
521     free (buffer);
522 #endif
523   }
524 
525   close (file);
526 
527   FREE (output);
528 
529   return (rv);
530 }
531 
532 /* Append NELEMENT entries to FILENAME.  The entries appended are from
533    the end of the list minus NELEMENTs up to the end of the list. */
534 int
append_history(nelements,filename)535 append_history (nelements, filename)
536      int nelements;
537      const char *filename;
538 {
539   return (history_do_write (filename, nelements, HISTORY_APPEND));
540 }
541 
542 /* Overwrite FILENAME with the current history.  If FILENAME is NULL,
543    then write the history list to ~/.history.  Values returned
544    are as in read_history ().*/
545 int
write_history(filename)546 write_history (filename)
547      const char *filename;
548 {
549   return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
550 }
551