histfile.c revision 58310
1/* histfile.c - functions to manipulate the history file. */
2
3/* Copyright (C) 1989, 1992 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   59 Temple Place, Suite 330, Boston, MA 02111 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#define READLINE_LIBRARY
27
28#if defined (HAVE_CONFIG_H)
29#  include <config.h>
30#endif
31
32#include <stdio.h>
33
34#include <sys/types.h>
35#ifndef _MINIX
36#  include <sys/file.h>
37#endif
38#include "posixstat.h"
39#include <fcntl.h>
40
41#if defined (HAVE_STDLIB_H)
42#  include <stdlib.h>
43#else
44#  include "ansi_stdlib.h"
45#endif /* HAVE_STDLIB_H */
46
47#if defined (HAVE_UNISTD_H)
48#  include <unistd.h>
49#endif
50
51#if defined (HAVE_STRING_H)
52#  include <string.h>
53#else
54#  include <strings.h>
55#endif /* !HAVE_STRING_H */
56
57
58/* If we're compiling for __EMX__ (OS/2) or __CYGWIN__ (cygwin32 environment
59   on win 95/98/nt), we want to open files with O_BINARY mode so that there
60   is no \n -> \r\n conversion performed.  On other systems, we don't want to
61   mess around with O_BINARY at all, so we ensure that it's defined to 0. */
62#if defined (__EMX__) || defined (__CYGWIN__)
63#  ifndef O_BINARY
64#    define O_BINARY 0
65#  endif
66#else /* !__EMX__ && !__CYGWIN__ */
67#  undef O_BINARY
68#  define O_BINARY 0
69#endif /* !__EMX__ && !__CYGWIN__ */
70
71#include <errno.h>
72#if !defined (errno)
73extern int errno;
74#endif /* !errno */
75
76#include "history.h"
77#include "histlib.h"
78
79#include "rlshell.h"
80#include "xmalloc.h"
81
82/* Return the string that should be used in the place of this
83   filename.  This only matters when you don't specify the
84   filename to read_history (), or write_history (). */
85static char *
86history_filename (filename)
87     char *filename;
88{
89  char *return_val, *home;
90  int home_len;
91
92  return_val = filename ? savestring (filename) : (char *)NULL;
93
94  if (return_val)
95    return (return_val);
96
97  home = get_env_value ("HOME");
98
99  if (home == 0)
100    {
101      home = ".";
102      home_len = 1;
103    }
104  else
105    home_len = strlen (home);
106
107  return_val = xmalloc (2 + home_len + 8); /* strlen(".history") == 8 */
108  strcpy (return_val, home);
109  return_val[home_len] = '/';
110#if defined (__MSDOS__)
111  strcpy (return_val + home_len + 1, "_history");
112#else
113  strcpy (return_val + home_len + 1, ".history");
114#endif
115
116  return (return_val);
117}
118
119/* Add the contents of FILENAME to the history list, a line at a time.
120   If FILENAME is NULL, then read from ~/.history.  Returns 0 if
121   successful, or errno if not. */
122int
123read_history (filename)
124     char *filename;
125{
126  return (read_history_range (filename, 0, -1));
127}
128
129/* Read a range of lines from FILENAME, adding them to the history list.
130   Start reading at the FROM'th line and end at the TO'th.  If FROM
131   is zero, start at the beginning.  If TO is less than FROM, read
132   until the end of the file.  If FILENAME is NULL, then read from
133   ~/.history.  Returns 0 if successful, or errno if not. */
134int
135read_history_range (filename, from, to)
136     char *filename;
137     int from, to;
138{
139  register int line_start, line_end;
140  char *input, *buffer;
141  int file, current_line, chars_read;
142  struct stat finfo;
143  size_t file_size;
144
145  buffer = (char *)NULL;
146  input = history_filename (filename);
147  file = open (input, O_RDONLY|O_BINARY, 0666);
148
149  if ((file < 0) || (fstat (file, &finfo) == -1))
150    goto error_and_exit;
151
152  file_size = (size_t)finfo.st_size;
153
154  /* check for overflow on very large files */
155  if (file_size != finfo.st_size || file_size + 1 < file_size)
156    {
157#if defined (EFBIG)
158      errno = EFBIG;
159#endif
160      goto error_and_exit;
161    }
162
163  buffer = xmalloc (file_size + 1);
164
165  chars_read = read (file, buffer, file_size);
166  if (chars_read < 0)
167    {
168  error_and_exit:
169      if (file >= 0)
170	close (file);
171
172      FREE (input);
173      FREE (buffer);
174
175      return (errno);
176    }
177
178  close (file);
179
180  /* Set TO to larger than end of file if negative. */
181  if (to < 0)
182    to = chars_read;
183
184  /* Start at beginning of file, work to end. */
185  line_start = line_end = current_line = 0;
186
187  /* Skip lines until we are at FROM. */
188  while (line_start < chars_read && current_line < from)
189    {
190      for (line_end = line_start; line_end < chars_read; line_end++)
191	if (buffer[line_end] == '\n')
192	  {
193	    current_line++;
194	    line_start = line_end + 1;
195	    if (current_line == from)
196	      break;
197	  }
198    }
199
200  /* If there are lines left to gobble, then gobble them now. */
201  for (line_end = line_start; line_end < chars_read; line_end++)
202    if (buffer[line_end] == '\n')
203      {
204	buffer[line_end] = '\0';
205
206	if (buffer[line_start])
207	  add_history (buffer + line_start);
208
209	current_line++;
210
211	if (current_line >= to)
212	  break;
213
214	line_start = line_end + 1;
215      }
216
217  FREE (input);
218  FREE (buffer);
219
220  return (0);
221}
222
223/* Truncate the history file FNAME, leaving only LINES trailing lines.
224   If FNAME is NULL, then use ~/.history. */
225int
226history_truncate_file (fname, lines)
227     char *fname;
228     int lines;
229{
230  register int i;
231  int file, chars_read;
232  char *buffer, *filename;
233  struct stat finfo;
234  size_t file_size;
235
236  buffer = (char *)NULL;
237  filename = history_filename (fname);
238  file = open (filename, O_RDONLY|O_BINARY, 0666);
239
240  if (file == -1 || fstat (file, &finfo) == -1)
241    goto truncate_exit;
242
243  /* Don't try to truncate non-regular files. */
244  if (S_ISREG(finfo.st_mode) == 0)
245    goto truncate_exit;
246
247  file_size = (size_t)finfo.st_size;
248
249  /* check for overflow on very large files */
250  if (file_size != finfo.st_size || file_size + 1 < file_size)
251    {
252      close (file);
253#if defined (EFBIG)
254      errno = EFBIG;
255#endif
256      goto truncate_exit;
257    }
258
259  buffer = xmalloc (file_size + 1);
260  chars_read = read (file, buffer, file_size);
261  close (file);
262
263  if (chars_read <= 0)
264    goto truncate_exit;
265
266  /* Count backwards from the end of buffer until we have passed
267     LINES lines. */
268  for (i = chars_read - 1; lines && i; i--)
269    {
270      if (buffer[i] == '\n')
271	lines--;
272    }
273
274  /* If this is the first line, then the file contains exactly the
275     number of lines we want to truncate to, so we don't need to do
276     anything.  It's the first line if we don't find a newline between
277     the current value of i and 0.  Otherwise, write from the start of
278     this line until the end of the buffer. */
279  for ( ; i; i--)
280    if (buffer[i] == '\n')
281      {
282	i++;
283	break;
284      }
285
286  /* Write only if there are more lines in the file than we want to
287     truncate to. */
288  if (i && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1))
289    {
290      write (file, buffer + i, chars_read - i);
291
292#if defined (__BEOS__)
293      /* BeOS ignores O_TRUNC. */
294      ftruncate (file, chars_read - i);
295#endif
296
297      close (file);
298    }
299
300 truncate_exit:
301
302  FREE (buffer);
303
304  free (filename);
305  return 0;
306}
307
308/* Workhorse function for writing history.  Writes NELEMENT entries
309   from the history list to FILENAME.  OVERWRITE is non-zero if you
310   wish to replace FILENAME with the entries. */
311static int
312history_do_write (filename, nelements, overwrite)
313     char *filename;
314     int nelements, overwrite;
315{
316  register int i;
317  char *output;
318  int file, mode;
319
320  mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
321  output = history_filename (filename);
322
323  if ((file = open (output, mode, 0600)) == -1)
324    {
325      FREE (output);
326      return (errno);
327    }
328
329  if (nelements > history_length)
330    nelements = history_length;
331
332  /* Build a buffer of all the lines to write, and write them in one syscall.
333     Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */
334  {
335    HIST_ENTRY **the_history;	/* local */
336    register int j;
337    int buffer_size;
338    char *buffer;
339
340    the_history = history_list ();
341    /* Calculate the total number of bytes to write. */
342    for (buffer_size = 0, i = history_length - nelements; i < history_length; i++)
343      buffer_size += 1 + strlen (the_history[i]->line);
344
345    /* Allocate the buffer, and fill it. */
346    buffer = xmalloc (buffer_size);
347
348    for (j = 0, i = history_length - nelements; i < history_length; i++)
349      {
350	strcpy (buffer + j, the_history[i]->line);
351	j += strlen (the_history[i]->line);
352	buffer[j++] = '\n';
353      }
354
355    write (file, buffer, buffer_size);
356    free (buffer);
357  }
358
359  close (file);
360
361  FREE (output);
362
363  return (0);
364}
365
366/* Append NELEMENT entries to FILENAME.  The entries appended are from
367   the end of the list minus NELEMENTs up to the end of the list. */
368int
369append_history (nelements, filename)
370     int nelements;
371     char *filename;
372{
373  return (history_do_write (filename, nelements, HISTORY_APPEND));
374}
375
376/* Overwrite FILENAME with the current history.  If FILENAME is NULL,
377   then write the history list to ~/.history.  Values returned
378   are as in read_history ().*/
379int
380write_history (filename)
381     char *filename;
382{
383  return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
384}
385