1/* histfile.c - functions to manipulate the history file. */
2
3/* Copyright (C) 1989-2009 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)
93extern 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() */
103int 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 (). */
112static char *
113history_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      home = ".";
130      home_len = 1;
131    }
132  else
133    home_len = strlen (home);
134
135  return_val = (char *)xmalloc (2 + home_len + 8); /* strlen(".history") == 8 */
136  strcpy (return_val, home);
137  return_val[home_len] = '/';
138#if defined (__MSDOS__)
139  strcpy (return_val + home_len + 1, "_history");
140#else
141  strcpy (return_val + home_len + 1, ".history");
142#endif
143
144  return (return_val);
145}
146
147/* Add the contents of FILENAME to the history list, a line at a time.
148   If FILENAME is NULL, then read from ~/.history.  Returns 0 if
149   successful, or errno if not. */
150int
151read_history (filename)
152     const char *filename;
153{
154  return (read_history_range (filename, 0, -1));
155}
156
157/* Read a range of lines from FILENAME, adding them to the history list.
158   Start reading at the FROM'th line and end at the TO'th.  If FROM
159   is zero, start at the beginning.  If TO is less than FROM, read
160   until the end of the file.  If FILENAME is NULL, then read from
161   ~/.history.  Returns 0 if successful, or errno if not. */
162int
163read_history_range (filename, from, to)
164     const char *filename;
165     int from, to;
166{
167  register char *line_start, *line_end, *p;
168  char *input, *buffer, *bufend, *last_ts;
169  int file, current_line, chars_read;
170  struct stat finfo;
171  size_t file_size;
172#if defined (EFBIG)
173  int overflow_errno = EFBIG;
174#elif defined (EOVERFLOW)
175  int overflow_errno = EOVERFLOW;
176#else
177  int overflow_errno = EIO;
178#endif
179
180  buffer = last_ts = (char *)NULL;
181  input = history_filename (filename);
182  file = open (input, O_RDONLY|O_BINARY, 0666);
183
184  if ((file < 0) || (fstat (file, &finfo) == -1))
185    goto error_and_exit;
186
187  file_size = (size_t)finfo.st_size;
188
189  /* check for overflow on very large files */
190  if (file_size != finfo.st_size || 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. */
305int
306history_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
315  buffer = (char *)NULL;
316  filename = history_filename (fname);
317  file = open (filename, O_RDONLY|O_BINARY, 0666);
318  rv = 0;
319
320  /* Don't try to truncate non-regular files. */
321  if (file == -1 || fstat (file, &finfo) == -1)
322    {
323      rv = errno;
324      if (file != -1)
325	close (file);
326      goto truncate_exit;
327    }
328
329  if (S_ISREG (finfo.st_mode) == 0)
330    {
331      close (file);
332#ifdef EFTYPE
333      rv = EFTYPE;
334#else
335      rv = EINVAL;
336#endif
337      goto truncate_exit;
338    }
339
340  file_size = (size_t)finfo.st_size;
341
342  /* check for overflow on very large files */
343  if (file_size != finfo.st_size || file_size + 1 < file_size)
344    {
345      close (file);
346#if defined (EFBIG)
347      rv = errno = EFBIG;
348#elif defined (EOVERFLOW)
349      rv = errno = EOVERFLOW;
350#else
351      rv = errno = EINVAL;
352#endif
353      goto truncate_exit;
354    }
355
356  buffer = (char *)malloc (file_size + 1);
357  if (buffer == 0)
358    {
359      close (file);
360      goto truncate_exit;
361    }
362
363  chars_read = read (file, buffer, file_size);
364  close (file);
365
366  if (chars_read <= 0)
367    {
368      rv = (chars_read < 0) ? errno : 0;
369      goto truncate_exit;
370    }
371
372  /* Count backwards from the end of buffer until we have passed
373     LINES lines.  bp1 is set funny initially.  But since bp[1] can't
374     be a comment character (since it's off the end) and *bp can't be
375     both a newline and the history comment character, it should be OK. */
376  for (bp1 = bp = buffer + chars_read - 1; lines && bp > buffer; bp--)
377    {
378      if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
379	lines--;
380      bp1 = bp;
381    }
382
383  /* If this is the first line, then the file contains exactly the
384     number of lines we want to truncate to, so we don't need to do
385     anything.  It's the first line if we don't find a newline between
386     the current value of i and 0.  Otherwise, write from the start of
387     this line until the end of the buffer. */
388  for ( ; bp > buffer; bp--)
389    {
390      if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
391        {
392	  bp++;
393	  break;
394        }
395      bp1 = bp;
396    }
397
398  /* Write only if there are more lines in the file than we want to
399     truncate to. */
400  if (bp > buffer && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1))
401    {
402      write (file, bp, chars_read - (bp - buffer));
403      close (file);
404    }
405
406 truncate_exit:
407
408  FREE (buffer);
409
410  free (filename);
411  return rv;
412}
413
414/* Workhorse function for writing history.  Writes NELEMENT entries
415   from the history list to FILENAME.  OVERWRITE is non-zero if you
416   wish to replace FILENAME with the entries. */
417static int
418history_do_write (filename, nelements, overwrite)
419     const char *filename;
420     int nelements, overwrite;
421{
422  register int i;
423  char *output;
424  int file, mode, rv;
425#ifdef HISTORY_USE_MMAP
426  size_t cursize;
427
428  mode = overwrite ? O_RDWR|O_CREAT|O_TRUNC|O_BINARY : O_RDWR|O_APPEND|O_BINARY;
429#else
430  mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
431#endif
432  output = history_filename (filename);
433  rv = 0;
434
435  if ((file = open (output, mode, 0600)) == -1)
436    {
437      FREE (output);
438      return (errno);
439    }
440
441#ifdef HISTORY_USE_MMAP
442  cursize = overwrite ? 0 : lseek (file, 0, SEEK_END);
443#endif
444
445  if (nelements > history_length)
446    nelements = history_length;
447
448  /* Build a buffer of all the lines to write, and write them in one syscall.
449     Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */
450  {
451    HIST_ENTRY **the_history;	/* local */
452    register int j;
453    int buffer_size;
454    char *buffer;
455
456    the_history = history_list ();
457    /* Calculate the total number of bytes to write. */
458    for (buffer_size = 0, i = history_length - nelements; i < history_length; i++)
459#if 0
460      buffer_size += 2 + HISTENT_BYTES (the_history[i]);
461#else
462      {
463	if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
464	  buffer_size += strlen (the_history[i]->timestamp) + 1;
465	buffer_size += strlen (the_history[i]->line) + 1;
466      }
467#endif
468
469    /* Allocate the buffer, and fill it. */
470#ifdef HISTORY_USE_MMAP
471    if (ftruncate (file, buffer_size+cursize) == -1)
472      goto mmap_error;
473    buffer = (char *)mmap (0, buffer_size, PROT_READ|PROT_WRITE, MAP_WFLAGS, file, cursize);
474    if ((void *)buffer == MAP_FAILED)
475      {
476mmap_error:
477	rv = errno;
478	FREE (output);
479	close (file);
480	return rv;
481      }
482#else
483    buffer = (char *)malloc (buffer_size);
484    if (buffer == 0)
485      {
486      	rv = errno;
487	FREE (output);
488	close (file);
489	return rv;
490      }
491#endif
492
493    for (j = 0, i = history_length - nelements; i < history_length; i++)
494      {
495	if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
496	  {
497	    strcpy (buffer + j, the_history[i]->timestamp);
498	    j += strlen (the_history[i]->timestamp);
499	    buffer[j++] = '\n';
500	  }
501	strcpy (buffer + j, the_history[i]->line);
502	j += strlen (the_history[i]->line);
503	buffer[j++] = '\n';
504      }
505
506#ifdef HISTORY_USE_MMAP
507    if (msync (buffer, buffer_size, 0) != 0 || munmap (buffer, buffer_size) != 0)
508      rv = errno;
509#else
510    if (write (file, buffer, buffer_size) < 0)
511      rv = errno;
512    free (buffer);
513#endif
514  }
515
516  close (file);
517
518  FREE (output);
519
520  return (rv);
521}
522
523/* Append NELEMENT entries to FILENAME.  The entries appended are from
524   the end of the list minus NELEMENTs up to the end of the list. */
525int
526append_history (nelements, filename)
527     int nelements;
528     const char *filename;
529{
530  return (history_do_write (filename, nelements, HISTORY_APPEND));
531}
532
533/* Overwrite FILENAME with the current history.  If FILENAME is NULL,
534   then write the history list to ~/.history.  Values returned
535   are as in read_history ().*/
536int
537write_history (filename)
538     const char *filename;
539{
540  return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
541}
542