source: trunk/third/readline/histfile.c @ 12992

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