81dda57d0fe6aa1417d356127578aff98533f29a
[platform/upstream/bash.git] / lib / readline / histfile.c
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)
69 extern int errno;
70 #endif /* !errno */
71
72 #include "history.h"
73 #include "histlib.h"
74
75 /* Functions imported from shell.c */
76 extern char *get_env_value ();
77
78 extern 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 (). */
83 static char *
84 history_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. */
116 int
117 read_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. */
128 int
129 read_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 (read (file, buffer, file_size) != file_size)
159     {
160   error_and_exit:
161       if (file >= 0)
162         close (file);
163
164       FREE (input);
165       FREE (buffer);
166
167       return (errno);
168     }
169
170   close (file);
171
172   /* Set TO to larger than end of file if negative. */
173   if (to < 0)
174     to = file_size;
175
176   /* Start at beginning of file, work to end. */
177   line_start = line_end = current_line = 0;
178
179   /* Skip lines until we are at FROM. */
180   while (line_start < file_size && current_line < from)
181     {
182       for (line_end = line_start; line_end < file_size; line_end++)
183         if (buffer[line_end] == '\n')
184           {
185             current_line++;
186             line_start = line_end + 1;
187             if (current_line == from)
188               break;
189           }
190     }
191
192   /* If there are lines left to gobble, then gobble them now. */
193   for (line_end = line_start; line_end < file_size; line_end++)
194     if (buffer[line_end] == '\n')
195       {
196         buffer[line_end] = '\0';
197
198         if (buffer[line_start])
199           add_history (buffer + line_start);
200
201         current_line++;
202
203         if (current_line >= to)
204           break;
205
206         line_start = line_end + 1;
207       }
208
209   FREE (input);
210   FREE (buffer);
211
212   return (0);
213 }
214
215 /* Truncate the history file FNAME, leaving only LINES trailing lines.
216    If FNAME is NULL, then use ~/.history. */
217 int
218 history_truncate_file (fname, lines)
219      char *fname;
220      register int lines;
221 {
222   register int i;
223   int file, chars_read;
224   char *buffer, *filename;
225   struct stat finfo;
226   size_t file_size;
227
228   buffer = (char *)NULL;
229   filename = history_filename (fname);
230   file = open (filename, O_RDONLY|O_BINARY, 0666);
231
232   if (file == -1 || fstat (file, &finfo) == -1)
233     goto truncate_exit;
234
235   file_size = (size_t)finfo.st_size;
236
237   /* check for overflow on very large files */
238   if (file_size != finfo.st_size || file_size + 1 < file_size)
239     {
240       close (file);
241 #if defined (EFBIG)
242       errno = EFBIG;
243 #endif
244       goto truncate_exit;
245     }
246
247   buffer = xmalloc (file_size + 1);
248   chars_read = read (file, buffer, file_size);
249   close (file);
250
251   if (chars_read <= 0)
252     goto truncate_exit;
253
254   /* Count backwards from the end of buffer until we have passed
255      LINES lines. */
256   for (i = chars_read - 1; lines && i; i--)
257     {
258       if (buffer[i] == '\n')
259         lines--;
260     }
261
262   /* If this is the first line, then the file contains exactly the
263      number of lines we want to truncate to, so we don't need to do
264      anything.  It's the first line if we don't find a newline between
265      the current value of i and 0.  Otherwise, write from the start of
266      this line until the end of the buffer. */
267   for ( ; i; i--)
268     if (buffer[i] == '\n')
269       {
270         i++;
271         break;
272       }
273
274   /* Write only if there are more lines in the file than we want to
275      truncate to. */
276   if (i && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1))
277     {
278       write (file, buffer + i, file_size - i);
279       close (file);
280     }
281
282  truncate_exit:
283
284   FREE (buffer);
285
286   free (filename);
287   return 0;
288 }
289
290 /* Workhorse function for writing history.  Writes NELEMENT entries
291    from the history list to FILENAME.  OVERWRITE is non-zero if you
292    wish to replace FILENAME with the entries. */
293 static int
294 history_do_write (filename, nelements, overwrite)
295      char *filename;
296      int nelements, overwrite;
297 {
298   register int i;
299   char *output;
300   int file, mode;
301
302   mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
303   output = history_filename (filename);
304
305   if ((file = open (output, mode, 0600)) == -1)
306     {
307       FREE (output);
308       return (errno);
309     }
310
311   if (nelements > history_length)
312     nelements = history_length;
313
314   /* Build a buffer of all the lines to write, and write them in one syscall.
315      Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */
316   {
317     HIST_ENTRY **the_history;   /* local */
318     register int j;
319     int buffer_size;
320     char *buffer;
321
322     the_history = history_list ();
323     /* Calculate the total number of bytes to write. */
324     for (buffer_size = 0, i = history_length - nelements; i < history_length; i++)
325       buffer_size += 1 + strlen (the_history[i]->line);
326
327     /* Allocate the buffer, and fill it. */
328     buffer = xmalloc (buffer_size);
329
330     for (j = 0, i = history_length - nelements; i < history_length; i++)
331       {
332         strcpy (buffer + j, the_history[i]->line);
333         j += strlen (the_history[i]->line);
334         buffer[j++] = '\n';
335       }
336
337     write (file, buffer, buffer_size);
338     free (buffer);
339   }
340
341   close (file);
342
343   FREE (output);
344
345   return (0);
346 }
347
348 /* Append NELEMENT entries to FILENAME.  The entries appended are from
349    the end of the list minus NELEMENTs up to the end of the list. */
350 int
351 append_history (nelements, filename)
352      int nelements;
353      char *filename;
354 {
355   return (history_do_write (filename, nelements, HISTORY_APPEND));
356 }
357
358 /* Overwrite FILENAME with the current history.  If FILENAME is NULL,
359    then write the history list to ~/.history.  Values returned
360    are as in read_history ().*/
361 int
362 write_history (filename)
363      char *filename;
364 {
365   return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
366 }