histfile.c revision 119610
121308Sache/* histfile.c - functions to manipulate the history file. */
221308Sache
321308Sache/* Copyright (C) 1989, 1992 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. */
2621308Sache#define READLINE_LIBRARY
2721308Sache
2821308Sache#if defined (HAVE_CONFIG_H)
2921308Sache#  include <config.h>
3021308Sache#endif
3121308Sache
3221308Sache#include <stdio.h>
3321308Sache
3421308Sache#include <sys/types.h>
3535486Sache#ifndef _MINIX
3635486Sache#  include <sys/file.h>
3735486Sache#endif
3858310Sache#include "posixstat.h"
3921308Sache#include <fcntl.h>
4021308Sache
4121308Sache#if defined (HAVE_STDLIB_H)
4221308Sache#  include <stdlib.h>
4321308Sache#else
4421308Sache#  include "ansi_stdlib.h"
4521308Sache#endif /* HAVE_STDLIB_H */
4621308Sache
4721308Sache#if defined (HAVE_UNISTD_H)
4821308Sache#  include <unistd.h>
4921308Sache#endif
5021308Sache
51119610Sache#if defined (__EMX__) || defined (__CYGWIN__)
52119610Sache#  undef HAVE_MMAP
53119610Sache#endif
5421308Sache
55119610Sache#ifdef HAVE_MMAP
56119610Sache#  include <sys/mman.h>
5758310Sache
58119610Sache#  ifdef MAP_FILE
59119610Sache#    define MAP_RFLAGS	(MAP_FILE|MAP_PRIVATE)
60119610Sache#    define MAP_WFLAGS	(MAP_FILE|MAP_SHARED)
61119610Sache#  else
62119610Sache#    define MAP_RFLAGS	MAP_PRIVATE
63119610Sache#    define MAP_WFLAGS	MAP_SHARED
64119610Sache#  endif
65119610Sache
66119610Sache#  ifndef MAP_FAILED
67119610Sache#    define MAP_FAILED	((void *)-1)
68119610Sache#  endif
69119610Sache
70119610Sache#endif /* HAVE_MMAP */
71119610Sache
7258310Sache/* If we're compiling for __EMX__ (OS/2) or __CYGWIN__ (cygwin32 environment
7358310Sache   on win 95/98/nt), we want to open files with O_BINARY mode so that there
7458310Sache   is no \n -> \r\n conversion performed.  On other systems, we don't want to
7558310Sache   mess around with O_BINARY at all, so we ensure that it's defined to 0. */
7658310Sache#if defined (__EMX__) || defined (__CYGWIN__)
7726497Sache#  ifndef O_BINARY
7826497Sache#    define O_BINARY 0
7926497Sache#  endif
8058310Sache#else /* !__EMX__ && !__CYGWIN__ */
8126497Sache#  undef O_BINARY
8226497Sache#  define O_BINARY 0
8358310Sache#endif /* !__EMX__ && !__CYGWIN__ */
8426497Sache
8521308Sache#include <errno.h>
8621308Sache#if !defined (errno)
8721308Sacheextern int errno;
8821308Sache#endif /* !errno */
8921308Sache
9021308Sache#include "history.h"
9121308Sache#include "histlib.h"
9221308Sache
9358310Sache#include "rlshell.h"
9458310Sache#include "xmalloc.h"
9526497Sache
9621308Sache/* Return the string that should be used in the place of this
9721308Sache   filename.  This only matters when you don't specify the
9821308Sache   filename to read_history (), or write_history (). */
9921308Sachestatic char *
10021308Sachehistory_filename (filename)
10175406Sache     const char *filename;
10221308Sache{
10375406Sache  char *return_val;
10475406Sache  const char *home;
10521308Sache  int home_len;
10621308Sache
10721308Sache  return_val = filename ? savestring (filename) : (char *)NULL;
10821308Sache
10921308Sache  if (return_val)
11021308Sache    return (return_val);
11121308Sache
11275406Sache  home = sh_get_env_value ("HOME");
11321308Sache
11421308Sache  if (home == 0)
11521308Sache    {
11621308Sache      home = ".";
11721308Sache      home_len = 1;
11821308Sache    }
11921308Sache  else
12021308Sache    home_len = strlen (home);
12121308Sache
122119610Sache  return_val = (char *)xmalloc (2 + home_len + 8); /* strlen(".history") == 8 */
12321308Sache  strcpy (return_val, home);
12421308Sache  return_val[home_len] = '/';
12558310Sache#if defined (__MSDOS__)
12658310Sache  strcpy (return_val + home_len + 1, "_history");
12758310Sache#else
12821308Sache  strcpy (return_val + home_len + 1, ".history");
12958310Sache#endif
13021308Sache
13121308Sache  return (return_val);
13221308Sache}
13321308Sache
13421308Sache/* Add the contents of FILENAME to the history list, a line at a time.
13521308Sache   If FILENAME is NULL, then read from ~/.history.  Returns 0 if
13621308Sache   successful, or errno if not. */
13721308Sacheint
13821308Sacheread_history (filename)
13975406Sache     const char *filename;
14021308Sache{
14121308Sache  return (read_history_range (filename, 0, -1));
14221308Sache}
14321308Sache
14421308Sache/* Read a range of lines from FILENAME, adding them to the history list.
14521308Sache   Start reading at the FROM'th line and end at the TO'th.  If FROM
14621308Sache   is zero, start at the beginning.  If TO is less than FROM, read
14721308Sache   until the end of the file.  If FILENAME is NULL, then read from
14821308Sache   ~/.history.  Returns 0 if successful, or errno if not. */
14921308Sacheint
15021308Sacheread_history_range (filename, from, to)
15175406Sache     const char *filename;
15221308Sache     int from, to;
15321308Sache{
154119610Sache  register char *line_start, *line_end;
155119610Sache  char *input, *buffer, *bufend;
15658310Sache  int file, current_line, chars_read;
15721308Sache  struct stat finfo;
15835486Sache  size_t file_size;
15921308Sache
16035486Sache  buffer = (char *)NULL;
16121308Sache  input = history_filename (filename);
16226497Sache  file = open (input, O_RDONLY|O_BINARY, 0666);
16321308Sache
16421308Sache  if ((file < 0) || (fstat (file, &finfo) == -1))
16521308Sache    goto error_and_exit;
16621308Sache
16735486Sache  file_size = (size_t)finfo.st_size;
16821308Sache
16935486Sache  /* check for overflow on very large files */
17035486Sache  if (file_size != finfo.st_size || file_size + 1 < file_size)
17121308Sache    {
17235486Sache#if defined (EFBIG)
17335486Sache      errno = EFBIG;
174119610Sache#elif defined (EOVERFLOW)
175119610Sache      errno = EOVERFLOW;
17635486Sache#endif
17735486Sache      goto error_and_exit;
17835486Sache    }
17935486Sache
180119610Sache#ifdef HAVE_MMAP
181119610Sache  /* We map read/write and private so we can change newlines to NULs without
182119610Sache     affecting the underlying object. */
183119610Sache  buffer = (char *)mmap (0, file_size, PROT_READ|PROT_WRITE, MAP_RFLAGS, file, 0);
184119610Sache  if ((void *)buffer == MAP_FAILED)
185119610Sache    goto error_and_exit;
186119610Sache  chars_read = file_size;
187119610Sache#else
188119610Sache  buffer = (char *)malloc (file_size + 1);
189119610Sache  if (buffer == 0)
190119610Sache    goto error_and_exit;
19158310Sache
19258310Sache  chars_read = read (file, buffer, file_size);
193119610Sache#endif
19458310Sache  if (chars_read < 0)
19535486Sache    {
19621308Sache  error_and_exit:
197119610Sache      chars_read = errno;
19821308Sache      if (file >= 0)
19921308Sache	close (file);
20021308Sache
20121308Sache      FREE (input);
202119610Sache#ifndef HAVE_MMAP
20321308Sache      FREE (buffer);
204119610Sache#endif
20521308Sache
206119610Sache      return (chars_read);
20721308Sache    }
20821308Sache
20921308Sache  close (file);
21021308Sache
21121308Sache  /* Set TO to larger than end of file if negative. */
21221308Sache  if (to < 0)
21358310Sache    to = chars_read;
21421308Sache
21521308Sache  /* Start at beginning of file, work to end. */
216119610Sache  bufend = buffer + chars_read;
217119610Sache  current_line = 0;
21821308Sache
21921308Sache  /* Skip lines until we are at FROM. */
220119610Sache  for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++)
221119610Sache    if (*line_end == '\n')
222119610Sache      {
223119610Sache	current_line++;
224119610Sache	line_start = line_end + 1;
225119610Sache      }
22621308Sache
22721308Sache  /* If there are lines left to gobble, then gobble them now. */
228119610Sache  for (line_end = line_start; line_end < bufend; line_end++)
229119610Sache    if (*line_end == '\n')
23021308Sache      {
231119610Sache	*line_end = '\0';
23221308Sache
233119610Sache	if (*line_start)
234119610Sache	  add_history (line_start);
23521308Sache
23621308Sache	current_line++;
23721308Sache
23821308Sache	if (current_line >= to)
23921308Sache	  break;
24021308Sache
24121308Sache	line_start = line_end + 1;
24221308Sache      }
24321308Sache
24421308Sache  FREE (input);
245119610Sache#ifndef HAVE_MMAP
24621308Sache  FREE (buffer);
247119610Sache#else
248119610Sache  munmap (buffer, file_size);
249119610Sache#endif
25021308Sache
25121308Sache  return (0);
25221308Sache}
25321308Sache
25421308Sache/* Truncate the history file FNAME, leaving only LINES trailing lines.
25575406Sache   If FNAME is NULL, then use ~/.history.  Returns 0 on success, errno
25675406Sache   on failure. */
25721308Sacheint
25821308Sachehistory_truncate_file (fname, lines)
25975406Sache     const char *fname;
26047558Sache     int lines;
26121308Sache{
262119610Sache  char *buffer, *filename, *bp;
26375406Sache  int file, chars_read, rv;
26421308Sache  struct stat finfo;
26535486Sache  size_t file_size;
26621308Sache
26726497Sache  buffer = (char *)NULL;
26821308Sache  filename = history_filename (fname);
26926497Sache  file = open (filename, O_RDONLY|O_BINARY, 0666);
27075406Sache  rv = 0;
27121308Sache
27275406Sache  /* Don't try to truncate non-regular files. */
27321308Sache  if (file == -1 || fstat (file, &finfo) == -1)
27475406Sache    {
27575406Sache      rv = errno;
27675406Sache      if (file != -1)
27775406Sache	close (file);
27875406Sache      goto truncate_exit;
27975406Sache    }
28021308Sache
28175406Sache  if (S_ISREG (finfo.st_mode) == 0)
28275406Sache    {
28375406Sache      close (file);
28475406Sache#ifdef EFTYPE
28575406Sache      rv = EFTYPE;
28675406Sache#else
28775406Sache      rv = EINVAL;
28875406Sache#endif
28975406Sache      goto truncate_exit;
29075406Sache    }
29158310Sache
29235486Sache  file_size = (size_t)finfo.st_size;
29335486Sache
29435486Sache  /* check for overflow on very large files */
29535486Sache  if (file_size != finfo.st_size || file_size + 1 < file_size)
29635486Sache    {
29735486Sache      close (file);
29835486Sache#if defined (EFBIG)
29975406Sache      rv = errno = EFBIG;
30075406Sache#elif defined (EOVERFLOW)
30175406Sache      rv = errno = EOVERFLOW;
30275406Sache#else
30375406Sache      rv = errno = EINVAL;
30435486Sache#endif
30535486Sache      goto truncate_exit;
30635486Sache    }
30735486Sache
308119610Sache  buffer = (char *)malloc (file_size + 1);
309119610Sache  if (buffer == 0)
310119610Sache    {
311119610Sache      close (file);
312119610Sache      goto truncate_exit;
313119610Sache    }
314119610Sache
31535486Sache  chars_read = read (file, buffer, file_size);
31621308Sache  close (file);
31721308Sache
31821308Sache  if (chars_read <= 0)
31975406Sache    {
32075406Sache      rv = (chars_read < 0) ? errno : 0;
32175406Sache      goto truncate_exit;
32275406Sache    }
32321308Sache
32421308Sache  /* Count backwards from the end of buffer until we have passed
32521308Sache     LINES lines. */
326119610Sache  for (bp = buffer + chars_read - 1; lines && bp > buffer; bp--)
32721308Sache    {
328119610Sache      if (*bp == '\n')
32921308Sache	lines--;
33021308Sache    }
33121308Sache
33221308Sache  /* If this is the first line, then the file contains exactly the
33321308Sache     number of lines we want to truncate to, so we don't need to do
33421308Sache     anything.  It's the first line if we don't find a newline between
33521308Sache     the current value of i and 0.  Otherwise, write from the start of
33621308Sache     this line until the end of the buffer. */
337119610Sache  for ( ; bp > buffer; bp--)
338119610Sache    if (*bp == '\n')
33921308Sache      {
340119610Sache	bp++;
34121308Sache	break;
34221308Sache      }
34321308Sache
34421308Sache  /* Write only if there are more lines in the file than we want to
34521308Sache     truncate to. */
346119610Sache  if (bp > buffer && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1))
34721308Sache    {
348119610Sache      write (file, bp, chars_read - (bp - buffer));
34947558Sache
35047558Sache#if defined (__BEOS__)
35147558Sache      /* BeOS ignores O_TRUNC. */
352119610Sache      ftruncate (file, chars_read - (bp - buffer));
35347558Sache#endif
35447558Sache
35521308Sache      close (file);
35621308Sache    }
35721308Sache
35821308Sache truncate_exit:
35921308Sache
36021308Sache  FREE (buffer);
36121308Sache
36221308Sache  free (filename);
36375406Sache  return rv;
36421308Sache}
36521308Sache
36621308Sache/* Workhorse function for writing history.  Writes NELEMENT entries
36721308Sache   from the history list to FILENAME.  OVERWRITE is non-zero if you
36821308Sache   wish to replace FILENAME with the entries. */
36921308Sachestatic int
37021308Sachehistory_do_write (filename, nelements, overwrite)
37175406Sache     const char *filename;
37221308Sache     int nelements, overwrite;
37321308Sache{
37421308Sache  register int i;
37526497Sache  char *output;
37675406Sache  int file, mode, rv;
377119610Sache  size_t cursize;
37821308Sache
379119610Sache#ifdef HAVE_MMAP
380119610Sache  mode = overwrite ? O_RDWR|O_CREAT|O_TRUNC|O_BINARY : O_RDWR|O_APPEND|O_BINARY;
381119610Sache#else
38226497Sache  mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
383119610Sache#endif
38426497Sache  output = history_filename (filename);
38575406Sache  rv = 0;
38621308Sache
38730971Sache  if ((file = open (output, mode, 0600)) == -1)
38821308Sache    {
38921308Sache      FREE (output);
39021308Sache      return (errno);
39121308Sache    }
39221308Sache
393119610Sache#ifdef HAVE_MMAP
394119610Sache  cursize = overwrite ? 0 : lseek (file, 0, SEEK_END);
395119610Sache#endif
396119610Sache
39721308Sache  if (nelements > history_length)
39821308Sache    nelements = history_length;
39921308Sache
40021308Sache  /* Build a buffer of all the lines to write, and write them in one syscall.
40121308Sache     Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */
40221308Sache  {
40321308Sache    HIST_ENTRY **the_history;	/* local */
40421308Sache    register int j;
40521308Sache    int buffer_size;
40621308Sache    char *buffer;
40721308Sache
40821308Sache    the_history = history_list ();
40921308Sache    /* Calculate the total number of bytes to write. */
41021308Sache    for (buffer_size = 0, i = history_length - nelements; i < history_length; i++)
41121308Sache      buffer_size += 1 + strlen (the_history[i]->line);
41221308Sache
41321308Sache    /* Allocate the buffer, and fill it. */
414119610Sache#ifdef HAVE_MMAP
415119610Sache    if (ftruncate (file, buffer_size+cursize) == -1)
416119610Sache      goto mmap_error;
417119610Sache    buffer = (char *)mmap (0, buffer_size, PROT_READ|PROT_WRITE, MAP_WFLAGS, file, cursize);
418119610Sache    if ((void *)buffer == MAP_FAILED)
419119610Sache      {
420119610Sachemmap_error:
421119610Sache	rv = errno;
422119610Sache	FREE (output);
423119610Sache	close (file);
424119610Sache	return rv;
425119610Sache      }
426119610Sache#else
427119610Sache    buffer = (char *)malloc (buffer_size);
428119610Sache    if (buffer == 0)
429119610Sache      {
430119610Sache      	rv = errno;
431119610Sache	FREE (output);
432119610Sache	close (file);
433119610Sache	return rv;
434119610Sache      }
435119610Sache#endif
43621308Sache
43721308Sache    for (j = 0, i = history_length - nelements; i < history_length; i++)
43821308Sache      {
43921308Sache	strcpy (buffer + j, the_history[i]->line);
44021308Sache	j += strlen (the_history[i]->line);
44121308Sache	buffer[j++] = '\n';
44221308Sache      }
44321308Sache
444119610Sache#ifdef HAVE_MMAP
445119610Sache    if (msync (buffer, buffer_size, 0) != 0 || munmap (buffer, buffer_size) != 0)
446119610Sache      rv = errno;
447119610Sache#else
44875406Sache    if (write (file, buffer, buffer_size) < 0)
44975406Sache      rv = errno;
45021308Sache    free (buffer);
451119610Sache#endif
45221308Sache  }
45321308Sache
45421308Sache  close (file);
45521308Sache
45621308Sache  FREE (output);
45721308Sache
45875406Sache  return (rv);
45921308Sache}
46021308Sache
46121308Sache/* Append NELEMENT entries to FILENAME.  The entries appended are from
46221308Sache   the end of the list minus NELEMENTs up to the end of the list. */
46321308Sacheint
46421308Sacheappend_history (nelements, filename)
46521308Sache     int nelements;
46675406Sache     const char *filename;
46721308Sache{
46821308Sache  return (history_do_write (filename, nelements, HISTORY_APPEND));
46921308Sache}
47021308Sache
47121308Sache/* Overwrite FILENAME with the current history.  If FILENAME is NULL,
47221308Sache   then write the history list to ~/.history.  Values returned
47321308Sache   are as in read_history ().*/
47421308Sacheint
47521308Sachewrite_history (filename)
47675406Sache     const char *filename;
47721308Sache{
47821308Sache  return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
47921308Sache}
480