121308Sache/* histfile.c - functions to manipulate the history file. */
221308Sache
3136644Sache/* Copyright (C) 1989-2003 Free Software Foundation, Inc.
421308Sache
521308Sache   This file contains the GNU History Library (the Library), a set of
621308Sache   routines for managing the text of previously typed lines.
721308Sache
821308Sache   The Library is free software; you can redistribute it and/or modify
921308Sache   it under the terms of the GNU General Public License as published by
1058310Sache   the Free Software Foundation; either version 2, or (at your option)
1121308Sache   any later version.
1221308Sache
1321308Sache   The Library is distributed in the hope that it will be useful, but
1421308Sache   WITHOUT ANY WARRANTY; without even the implied warranty of
1521308Sache   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1621308Sache   General Public License for more details.
1721308Sache
1821308Sache   The GNU General Public License is often shipped with GNU software, and
1921308Sache   is generally kept in a file called COPYING or LICENSE.  If you do not
2021308Sache   have a copy of the license, write to the Free Software Foundation,
2158310Sache   59 Temple Place, Suite 330, Boston, MA 02111 USA. */
2221308Sache
2321308Sache/* The goal is to make the implementation transparent, so that you
2421308Sache   don't have to know what data types are used, just what functions
2521308Sache   you can call.  I think I have done that. */
26136644Sache
2721308Sache#define READLINE_LIBRARY
2821308Sache
29136644Sache#if defined (__TANDEM)
30136644Sache#  include <floss.h>
31136644Sache#endif
32136644Sache
3321308Sache#if defined (HAVE_CONFIG_H)
3421308Sache#  include <config.h>
3521308Sache#endif
3621308Sache
3721308Sache#include <stdio.h>
3821308Sache
3921308Sache#include <sys/types.h>
40136644Sache#if ! defined (_MINIX) && defined (HAVE_SYS_FILE_H)
4135486Sache#  include <sys/file.h>
4235486Sache#endif
4358310Sache#include "posixstat.h"
4421308Sache#include <fcntl.h>
4521308Sache
4621308Sache#if defined (HAVE_STDLIB_H)
4721308Sache#  include <stdlib.h>
4821308Sache#else
4921308Sache#  include "ansi_stdlib.h"
5021308Sache#endif /* HAVE_STDLIB_H */
5121308Sache
5221308Sache#if defined (HAVE_UNISTD_H)
5321308Sache#  include <unistd.h>
5421308Sache#endif
5521308Sache
56119610Sache#if defined (__EMX__) || defined (__CYGWIN__)
57119610Sache#  undef HAVE_MMAP
58119610Sache#endif
5921308Sache
60136644Sache#ifdef HISTORY_USE_MMAP
61119610Sache#  include <sys/mman.h>
6258310Sache
63119610Sache#  ifdef MAP_FILE
64119610Sache#    define MAP_RFLAGS	(MAP_FILE|MAP_PRIVATE)
65119610Sache#    define MAP_WFLAGS	(MAP_FILE|MAP_SHARED)
66119610Sache#  else
67119610Sache#    define MAP_RFLAGS	MAP_PRIVATE
68119610Sache#    define MAP_WFLAGS	MAP_SHARED
69119610Sache#  endif
70119610Sache
71119610Sache#  ifndef MAP_FAILED
72119610Sache#    define MAP_FAILED	((void *)-1)
73119610Sache#  endif
74119610Sache
75136644Sache#endif /* HISTORY_USE_MMAP */
76119610Sache
7758310Sache/* If we're compiling for __EMX__ (OS/2) or __CYGWIN__ (cygwin32 environment
7858310Sache   on win 95/98/nt), we want to open files with O_BINARY mode so that there
7958310Sache   is no \n -> \r\n conversion performed.  On other systems, we don't want to
8058310Sache   mess around with O_BINARY at all, so we ensure that it's defined to 0. */
8158310Sache#if defined (__EMX__) || defined (__CYGWIN__)
8226497Sache#  ifndef O_BINARY
8326497Sache#    define O_BINARY 0
8426497Sache#  endif
8558310Sache#else /* !__EMX__ && !__CYGWIN__ */
8626497Sache#  undef O_BINARY
8726497Sache#  define O_BINARY 0
8858310Sache#endif /* !__EMX__ && !__CYGWIN__ */
8926497Sache
9021308Sache#include <errno.h>
9121308Sache#if !defined (errno)
9221308Sacheextern int errno;
9321308Sache#endif /* !errno */
9421308Sache
9521308Sache#include "history.h"
9621308Sache#include "histlib.h"
9721308Sache
9858310Sache#include "rlshell.h"
9958310Sache#include "xmalloc.h"
10026497Sache
101136644Sache/* If non-zero, we write timestamps to the history file in history_do_write() */
102136644Sacheint history_write_timestamps = 0;
103136644Sache
104136644Sache/* Does S look like the beginning of a history timestamp entry?  Placeholder
105136644Sache   for more extensive tests. */
106136644Sache#define HIST_TIMESTAMP_START(s)		(*(s) == history_comment_char)
107136644Sache
10821308Sache/* Return the string that should be used in the place of this
10921308Sache   filename.  This only matters when you don't specify the
11021308Sache   filename to read_history (), or write_history (). */
11121308Sachestatic char *
11221308Sachehistory_filename (filename)
11375406Sache     const char *filename;
11421308Sache{
11575406Sache  char *return_val;
11675406Sache  const char *home;
11721308Sache  int home_len;
11821308Sache
11921308Sache  return_val = filename ? savestring (filename) : (char *)NULL;
12021308Sache
12121308Sache  if (return_val)
12221308Sache    return (return_val);
12321308Sache
12475406Sache  home = sh_get_env_value ("HOME");
12521308Sache
12621308Sache  if (home == 0)
12721308Sache    {
12821308Sache      home = ".";
12921308Sache      home_len = 1;
13021308Sache    }
13121308Sache  else
13221308Sache    home_len = strlen (home);
13321308Sache
134119610Sache  return_val = (char *)xmalloc (2 + home_len + 8); /* strlen(".history") == 8 */
13521308Sache  strcpy (return_val, home);
13621308Sache  return_val[home_len] = '/';
13758310Sache#if defined (__MSDOS__)
13858310Sache  strcpy (return_val + home_len + 1, "_history");
13958310Sache#else
14021308Sache  strcpy (return_val + home_len + 1, ".history");
14158310Sache#endif
14221308Sache
14321308Sache  return (return_val);
14421308Sache}
14521308Sache
14621308Sache/* Add the contents of FILENAME to the history list, a line at a time.
14721308Sache   If FILENAME is NULL, then read from ~/.history.  Returns 0 if
14821308Sache   successful, or errno if not. */
14921308Sacheint
15021308Sacheread_history (filename)
15175406Sache     const char *filename;
15221308Sache{
15321308Sache  return (read_history_range (filename, 0, -1));
15421308Sache}
15521308Sache
15621308Sache/* Read a range of lines from FILENAME, adding them to the history list.
15721308Sache   Start reading at the FROM'th line and end at the TO'th.  If FROM
15821308Sache   is zero, start at the beginning.  If TO is less than FROM, read
15921308Sache   until the end of the file.  If FILENAME is NULL, then read from
16021308Sache   ~/.history.  Returns 0 if successful, or errno if not. */
16121308Sacheint
16221308Sacheread_history_range (filename, from, to)
16375406Sache     const char *filename;
16421308Sache     int from, to;
16521308Sache{
166136644Sache  register char *line_start, *line_end, *p;
167136644Sache  char *input, *buffer, *bufend, *last_ts;
16858310Sache  int file, current_line, chars_read;
16921308Sache  struct stat finfo;
17035486Sache  size_t file_size;
171136644Sache#if defined (EFBIG)
172136644Sache  int overflow_errno = EFBIG;
173136644Sache#elif defined (EOVERFLOW)
174136644Sache  int overflow_errno = EOVERFLOW;
175136644Sache#else
176136644Sache  int overflow_errno = EIO;
177136644Sache#endif
17821308Sache
179136644Sache  buffer = last_ts = (char *)NULL;
18021308Sache  input = history_filename (filename);
18126497Sache  file = open (input, O_RDONLY|O_BINARY, 0666);
18221308Sache
18321308Sache  if ((file < 0) || (fstat (file, &finfo) == -1))
18421308Sache    goto error_and_exit;
18521308Sache
18635486Sache  file_size = (size_t)finfo.st_size;
18721308Sache
18835486Sache  /* check for overflow on very large files */
18935486Sache  if (file_size != finfo.st_size || file_size + 1 < file_size)
19021308Sache    {
191136644Sache      errno = overflow_errno;
19235486Sache      goto error_and_exit;
19335486Sache    }
19435486Sache
195136644Sache#ifdef HISTORY_USE_MMAP
196119610Sache  /* We map read/write and private so we can change newlines to NULs without
197119610Sache     affecting the underlying object. */
198119610Sache  buffer = (char *)mmap (0, file_size, PROT_READ|PROT_WRITE, MAP_RFLAGS, file, 0);
199119610Sache  if ((void *)buffer == MAP_FAILED)
200136644Sache    {
201136644Sache      errno = overflow_errno;
202136644Sache      goto error_and_exit;
203136644Sache    }
204119610Sache  chars_read = file_size;
205119610Sache#else
206119610Sache  buffer = (char *)malloc (file_size + 1);
207119610Sache  if (buffer == 0)
208136644Sache    {
209136644Sache      errno = overflow_errno;
210136644Sache      goto error_and_exit;
211136644Sache    }
21258310Sache
21358310Sache  chars_read = read (file, buffer, file_size);
214119610Sache#endif
21558310Sache  if (chars_read < 0)
21635486Sache    {
21721308Sache  error_and_exit:
218136644Sache      if (errno != 0)
219136644Sache	chars_read = errno;
220136644Sache      else
221136644Sache	chars_read = EIO;
22221308Sache      if (file >= 0)
22321308Sache	close (file);
22421308Sache
22521308Sache      FREE (input);
226136644Sache#ifndef HISTORY_USE_MMAP
22721308Sache      FREE (buffer);
228119610Sache#endif
22921308Sache
230119610Sache      return (chars_read);
23121308Sache    }
23221308Sache
23321308Sache  close (file);
23421308Sache
23521308Sache  /* Set TO to larger than end of file if negative. */
23621308Sache  if (to < 0)
23758310Sache    to = chars_read;
23821308Sache
23921308Sache  /* Start at beginning of file, work to end. */
240119610Sache  bufend = buffer + chars_read;
241119610Sache  current_line = 0;
24221308Sache
24321308Sache  /* Skip lines until we are at FROM. */
244119610Sache  for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++)
245119610Sache    if (*line_end == '\n')
246119610Sache      {
247136644Sache      	p = line_end + 1;
248136644Sache      	/* If we see something we think is a timestamp, continue with this
249136644Sache	   line.  We should check more extensively here... */
250136644Sache	if (HIST_TIMESTAMP_START(p) == 0)
251136644Sache	  current_line++;
252136644Sache	line_start = p;
253119610Sache      }
25421308Sache
25521308Sache  /* If there are lines left to gobble, then gobble them now. */
256119610Sache  for (line_end = line_start; line_end < bufend; line_end++)
257119610Sache    if (*line_end == '\n')
25821308Sache      {
259165670Sache	/* Change to allow Windows-like \r\n end of line delimiter. */
260165670Sache	if (line_end > line_start && line_end[-1] == '\r')
261165670Sache	  line_end[-1] = '\0';
262165670Sache	else
263165670Sache	  *line_end = '\0';
26421308Sache
265119610Sache	if (*line_start)
266136644Sache	  {
267136644Sache	    if (HIST_TIMESTAMP_START(line_start) == 0)
268136644Sache	      {
269136644Sache		add_history (line_start);
270136644Sache		if (last_ts)
271136644Sache		  {
272136644Sache		    add_history_time (last_ts);
273136644Sache		    last_ts = NULL;
274136644Sache		  }
275136644Sache	      }
276136644Sache	    else
277136644Sache	      {
278136644Sache		last_ts = line_start;
279136644Sache		current_line--;
280136644Sache	      }
281136644Sache	  }
28221308Sache
28321308Sache	current_line++;
28421308Sache
28521308Sache	if (current_line >= to)
28621308Sache	  break;
28721308Sache
28821308Sache	line_start = line_end + 1;
28921308Sache      }
29021308Sache
29121308Sache  FREE (input);
292136644Sache#ifndef HISTORY_USE_MMAP
29321308Sache  FREE (buffer);
294119610Sache#else
295119610Sache  munmap (buffer, file_size);
296119610Sache#endif
29721308Sache
29821308Sache  return (0);
29921308Sache}
30021308Sache
30121308Sache/* Truncate the history file FNAME, leaving only LINES trailing lines.
30275406Sache   If FNAME is NULL, then use ~/.history.  Returns 0 on success, errno
30375406Sache   on failure. */
30421308Sacheint
30521308Sachehistory_truncate_file (fname, lines)
30675406Sache     const char *fname;
30747558Sache     int lines;
30821308Sache{
309136644Sache  char *buffer, *filename, *bp, *bp1;		/* bp1 == bp+1 */
31075406Sache  int file, chars_read, rv;
31121308Sache  struct stat finfo;
31235486Sache  size_t file_size;
31321308Sache
31426497Sache  buffer = (char *)NULL;
31521308Sache  filename = history_filename (fname);
31626497Sache  file = open (filename, O_RDONLY|O_BINARY, 0666);
31775406Sache  rv = 0;
31821308Sache
31975406Sache  /* Don't try to truncate non-regular files. */
32021308Sache  if (file == -1 || fstat (file, &finfo) == -1)
32175406Sache    {
32275406Sache      rv = errno;
32375406Sache      if (file != -1)
32475406Sache	close (file);
32575406Sache      goto truncate_exit;
32675406Sache    }
32721308Sache
32875406Sache  if (S_ISREG (finfo.st_mode) == 0)
32975406Sache    {
33075406Sache      close (file);
33175406Sache#ifdef EFTYPE
33275406Sache      rv = EFTYPE;
33375406Sache#else
33475406Sache      rv = EINVAL;
33575406Sache#endif
33675406Sache      goto truncate_exit;
33775406Sache    }
33858310Sache
33935486Sache  file_size = (size_t)finfo.st_size;
34035486Sache
34135486Sache  /* check for overflow on very large files */
34235486Sache  if (file_size != finfo.st_size || file_size + 1 < file_size)
34335486Sache    {
34435486Sache      close (file);
34535486Sache#if defined (EFBIG)
34675406Sache      rv = errno = EFBIG;
34775406Sache#elif defined (EOVERFLOW)
34875406Sache      rv = errno = EOVERFLOW;
34975406Sache#else
35075406Sache      rv = errno = EINVAL;
35135486Sache#endif
35235486Sache      goto truncate_exit;
35335486Sache    }
35435486Sache
355119610Sache  buffer = (char *)malloc (file_size + 1);
356119610Sache  if (buffer == 0)
357119610Sache    {
358119610Sache      close (file);
359119610Sache      goto truncate_exit;
360119610Sache    }
361119610Sache
36235486Sache  chars_read = read (file, buffer, file_size);
36321308Sache  close (file);
36421308Sache
36521308Sache  if (chars_read <= 0)
36675406Sache    {
36775406Sache      rv = (chars_read < 0) ? errno : 0;
36875406Sache      goto truncate_exit;
36975406Sache    }
37021308Sache
37121308Sache  /* Count backwards from the end of buffer until we have passed
372136644Sache     LINES lines.  bp1 is set funny initially.  But since bp[1] can't
373136644Sache     be a comment character (since it's off the end) and *bp can't be
374136644Sache     both a newline and the history comment character, it should be OK. */
375136644Sache  for (bp1 = bp = buffer + chars_read - 1; lines && bp > buffer; bp--)
37621308Sache    {
377136644Sache      if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
37821308Sache	lines--;
379136644Sache      bp1 = bp;
38021308Sache    }
38121308Sache
38221308Sache  /* If this is the first line, then the file contains exactly the
38321308Sache     number of lines we want to truncate to, so we don't need to do
38421308Sache     anything.  It's the first line if we don't find a newline between
38521308Sache     the current value of i and 0.  Otherwise, write from the start of
38621308Sache     this line until the end of the buffer. */
387119610Sache  for ( ; bp > buffer; bp--)
388136644Sache    {
389136644Sache      if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
390136644Sache        {
391136644Sache	  bp++;
392136644Sache	  break;
393136644Sache        }
394136644Sache      bp1 = bp;
395136644Sache    }
39621308Sache
39721308Sache  /* Write only if there are more lines in the file than we want to
39821308Sache     truncate to. */
399119610Sache  if (bp > buffer && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1))
40021308Sache    {
401119610Sache      write (file, bp, chars_read - (bp - buffer));
40247558Sache
40347558Sache#if defined (__BEOS__)
40447558Sache      /* BeOS ignores O_TRUNC. */
405119610Sache      ftruncate (file, chars_read - (bp - buffer));
40647558Sache#endif
40747558Sache
40821308Sache      close (file);
40921308Sache    }
41021308Sache
41121308Sache truncate_exit:
41221308Sache
41321308Sache  FREE (buffer);
41421308Sache
41521308Sache  free (filename);
41675406Sache  return rv;
41721308Sache}
41821308Sache
41921308Sache/* Workhorse function for writing history.  Writes NELEMENT entries
42021308Sache   from the history list to FILENAME.  OVERWRITE is non-zero if you
42121308Sache   wish to replace FILENAME with the entries. */
42221308Sachestatic int
42321308Sachehistory_do_write (filename, nelements, overwrite)
42475406Sache     const char *filename;
42521308Sache     int nelements, overwrite;
42621308Sache{
42721308Sache  register int i;
42826497Sache  char *output;
42975406Sache  int file, mode, rv;
430136644Sache#ifdef HISTORY_USE_MMAP
431119610Sache  size_t cursize;
43221308Sache
433119610Sache  mode = overwrite ? O_RDWR|O_CREAT|O_TRUNC|O_BINARY : O_RDWR|O_APPEND|O_BINARY;
434119610Sache#else
43526497Sache  mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
436119610Sache#endif
43726497Sache  output = history_filename (filename);
43875406Sache  rv = 0;
43921308Sache
44030971Sache  if ((file = open (output, mode, 0600)) == -1)
44121308Sache    {
44221308Sache      FREE (output);
44321308Sache      return (errno);
44421308Sache    }
44521308Sache
446136644Sache#ifdef HISTORY_USE_MMAP
447119610Sache  cursize = overwrite ? 0 : lseek (file, 0, SEEK_END);
448119610Sache#endif
449119610Sache
45021308Sache  if (nelements > history_length)
45121308Sache    nelements = history_length;
45221308Sache
45321308Sache  /* Build a buffer of all the lines to write, and write them in one syscall.
45421308Sache     Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */
45521308Sache  {
45621308Sache    HIST_ENTRY **the_history;	/* local */
45721308Sache    register int j;
45821308Sache    int buffer_size;
45921308Sache    char *buffer;
46021308Sache
46121308Sache    the_history = history_list ();
46221308Sache    /* Calculate the total number of bytes to write. */
46321308Sache    for (buffer_size = 0, i = history_length - nelements; i < history_length; i++)
464136644Sache#if 0
465136644Sache      buffer_size += 2 + HISTENT_BYTES (the_history[i]);
466136644Sache#else
467136644Sache      {
468136644Sache	if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
469136644Sache	  buffer_size += strlen (the_history[i]->timestamp) + 1;
470136644Sache	buffer_size += strlen (the_history[i]->line) + 1;
471136644Sache      }
472136644Sache#endif
47321308Sache
47421308Sache    /* Allocate the buffer, and fill it. */
475136644Sache#ifdef HISTORY_USE_MMAP
476119610Sache    if (ftruncate (file, buffer_size+cursize) == -1)
477119610Sache      goto mmap_error;
478119610Sache    buffer = (char *)mmap (0, buffer_size, PROT_READ|PROT_WRITE, MAP_WFLAGS, file, cursize);
479119610Sache    if ((void *)buffer == MAP_FAILED)
480119610Sache      {
481119610Sachemmap_error:
482119610Sache	rv = errno;
483119610Sache	FREE (output);
484119610Sache	close (file);
485119610Sache	return rv;
486119610Sache      }
487119610Sache#else
488119610Sache    buffer = (char *)malloc (buffer_size);
489119610Sache    if (buffer == 0)
490119610Sache      {
491119610Sache      	rv = errno;
492119610Sache	FREE (output);
493119610Sache	close (file);
494119610Sache	return rv;
495119610Sache      }
496119610Sache#endif
49721308Sache
49821308Sache    for (j = 0, i = history_length - nelements; i < history_length; i++)
49921308Sache      {
500136644Sache	if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
501136644Sache	  {
502136644Sache	    strcpy (buffer + j, the_history[i]->timestamp);
503136644Sache	    j += strlen (the_history[i]->timestamp);
504136644Sache	    buffer[j++] = '\n';
505136644Sache	  }
50621308Sache	strcpy (buffer + j, the_history[i]->line);
50721308Sache	j += strlen (the_history[i]->line);
50821308Sache	buffer[j++] = '\n';
50921308Sache      }
51021308Sache
511136644Sache#ifdef HISTORY_USE_MMAP
512119610Sache    if (msync (buffer, buffer_size, 0) != 0 || munmap (buffer, buffer_size) != 0)
513119610Sache      rv = errno;
514119610Sache#else
51575406Sache    if (write (file, buffer, buffer_size) < 0)
51675406Sache      rv = errno;
51721308Sache    free (buffer);
518119610Sache#endif
51921308Sache  }
52021308Sache
52121308Sache  close (file);
52221308Sache
52321308Sache  FREE (output);
52421308Sache
52575406Sache  return (rv);
52621308Sache}
52721308Sache
52821308Sache/* Append NELEMENT entries to FILENAME.  The entries appended are from
52921308Sache   the end of the list minus NELEMENTs up to the end of the list. */
53021308Sacheint
53121308Sacheappend_history (nelements, filename)
53221308Sache     int nelements;
53375406Sache     const char *filename;
53421308Sache{
53521308Sache  return (history_do_write (filename, nelements, HISTORY_APPEND));
53621308Sache}
53721308Sache
53821308Sache/* Overwrite FILENAME with the current history.  If FILENAME is NULL,
53921308Sache   then write the history list to ~/.history.  Values returned
54021308Sache   are as in read_history ().*/
54121308Sacheint
54221308Sachewrite_history (filename)
54375406Sache     const char *filename;
54421308Sache{
54521308Sache  return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
54621308Sache}
547