Imported from ../bash-2.05a.tar.gz.
[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 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)
73 extern 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 (). */
85 static char *
86 history_filename (filename)
87      const char *filename;
88 {
89   char *return_val;
90   const char *home;
91   int home_len;
92
93   return_val = filename ? savestring (filename) : (char *)NULL;
94
95   if (return_val)
96     return (return_val);
97   
98   home = sh_get_env_value ("HOME");
99
100   if (home == 0)
101     {
102       home = ".";
103       home_len = 1;
104     }
105   else
106     home_len = strlen (home);
107
108   return_val = (char *)xmalloc (2 + home_len + 8); /* strlen(".history") == 8 */
109   strcpy (return_val, home);
110   return_val[home_len] = '/';
111 #if defined (__MSDOS__)
112   strcpy (return_val + home_len + 1, "_history");
113 #else
114   strcpy (return_val + home_len + 1, ".history");
115 #endif
116
117   return (return_val);
118 }
119
120 /* Add the contents of FILENAME to the history list, a line at a time.
121    If FILENAME is NULL, then read from ~/.history.  Returns 0 if
122    successful, or errno if not. */
123 int
124 read_history (filename)
125      const char *filename;
126 {
127   return (read_history_range (filename, 0, -1));
128 }
129
130 /* Read a range of lines from FILENAME, adding them to the history list.
131    Start reading at the FROM'th line and end at the TO'th.  If FROM
132    is zero, start at the beginning.  If TO is less than FROM, read
133    until the end of the file.  If FILENAME is NULL, then read from
134    ~/.history.  Returns 0 if successful, or errno if not. */
135 int
136 read_history_range (filename, from, to)
137      const char *filename;
138      int from, to;
139 {
140   register int line_start, line_end;
141   char *input, *buffer;
142   int file, current_line, chars_read;
143   struct stat finfo;
144   size_t file_size;
145
146   buffer = (char *)NULL;
147   input = history_filename (filename);
148   file = open (input, O_RDONLY|O_BINARY, 0666);
149
150   if ((file < 0) || (fstat (file, &finfo) == -1))
151     goto error_and_exit;
152
153   file_size = (size_t)finfo.st_size;
154
155   /* check for overflow on very large files */
156   if (file_size != finfo.st_size || file_size + 1 < file_size)
157     {
158 #if defined (EFBIG)
159       errno = EFBIG;
160 #endif
161       goto error_and_exit;
162     }
163
164   buffer = (char *)xmalloc (file_size + 1);
165
166   chars_read = read (file, buffer, file_size);
167   if (chars_read < 0)
168     {
169   error_and_exit:
170       if (file >= 0)
171         close (file);
172
173       FREE (input);
174       FREE (buffer);
175
176       return (errno);
177     }
178
179   close (file);
180
181   /* Set TO to larger than end of file if negative. */
182   if (to < 0)
183     to = chars_read;
184
185   /* Start at beginning of file, work to end. */
186   line_start = line_end = current_line = 0;
187
188   /* Skip lines until we are at FROM. */
189   while (line_start < chars_read && current_line < from)
190     {
191       for (line_end = line_start; line_end < chars_read; line_end++)
192         if (buffer[line_end] == '\n')
193           {
194             current_line++;
195             line_start = line_end + 1;
196             if (current_line == from)
197               break;
198           }
199     }
200
201   /* If there are lines left to gobble, then gobble them now. */
202   for (line_end = line_start; line_end < chars_read; line_end++)
203     if (buffer[line_end] == '\n')
204       {
205         buffer[line_end] = '\0';
206
207         if (buffer[line_start])
208           add_history (buffer + line_start);
209
210         current_line++;
211
212         if (current_line >= to)
213           break;
214
215         line_start = line_end + 1;
216       }
217
218   FREE (input);
219   FREE (buffer);
220
221   return (0);
222 }
223
224 /* Truncate the history file FNAME, leaving only LINES trailing lines.
225    If FNAME is NULL, then use ~/.history.  Returns 0 on success, errno
226    on failure. */
227 int
228 history_truncate_file (fname, lines)
229      const char *fname;
230      int lines;
231 {
232   register int i;
233   int file, chars_read, rv;
234   char *buffer, *filename;
235   struct stat finfo;
236   size_t file_size;
237
238   buffer = (char *)NULL;
239   filename = history_filename (fname);
240   file = open (filename, O_RDONLY|O_BINARY, 0666);
241   rv = 0;
242
243   /* Don't try to truncate non-regular files. */
244   if (file == -1 || fstat (file, &finfo) == -1)
245     {
246       rv = errno;
247       if (file != -1)
248         close (file);
249       goto truncate_exit;
250     }
251
252   if (S_ISREG (finfo.st_mode) == 0)
253     {
254       close (file);
255 #ifdef EFTYPE
256       rv = EFTYPE;
257 #else
258       rv = EINVAL;
259 #endif
260       goto truncate_exit;
261     }
262
263   file_size = (size_t)finfo.st_size;
264
265   /* check for overflow on very large files */
266   if (file_size != finfo.st_size || file_size + 1 < file_size)
267     {
268       close (file);
269 #if defined (EFBIG)
270       rv = errno = EFBIG;
271 #elif defined (EOVERFLOW)
272       rv = errno = EOVERFLOW;
273 #else
274       rv = errno = EINVAL;
275 #endif
276       goto truncate_exit;
277     }
278
279   buffer = (char *)xmalloc (file_size + 1);
280   chars_read = read (file, buffer, file_size);
281   close (file);
282
283   if (chars_read <= 0)
284     {
285       rv = (chars_read < 0) ? errno : 0;
286       goto truncate_exit;
287     }
288
289   /* Count backwards from the end of buffer until we have passed
290      LINES lines. */
291   for (i = chars_read - 1; lines && i; i--)
292     {
293       if (buffer[i] == '\n')
294         lines--;
295     }
296
297   /* If this is the first line, then the file contains exactly the
298      number of lines we want to truncate to, so we don't need to do
299      anything.  It's the first line if we don't find a newline between
300      the current value of i and 0.  Otherwise, write from the start of
301      this line until the end of the buffer. */
302   for ( ; i; i--)
303     if (buffer[i] == '\n')
304       {
305         i++;
306         break;
307       }
308
309   /* Write only if there are more lines in the file than we want to
310      truncate to. */
311   if (i && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1))
312     {
313       write (file, buffer + i, chars_read - i);
314
315 #if defined (__BEOS__)
316       /* BeOS ignores O_TRUNC. */
317       ftruncate (file, chars_read - i);
318 #endif
319
320       close (file);
321     }
322
323  truncate_exit:
324
325   FREE (buffer);
326
327   free (filename);
328   return rv;
329 }
330
331 /* Workhorse function for writing history.  Writes NELEMENT entries
332    from the history list to FILENAME.  OVERWRITE is non-zero if you
333    wish to replace FILENAME with the entries. */
334 static int
335 history_do_write (filename, nelements, overwrite)
336      const char *filename;
337      int nelements, overwrite;
338 {
339   register int i;
340   char *output;
341   int file, mode, rv;
342
343   mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
344   output = history_filename (filename);
345   rv = 0;
346
347   if ((file = open (output, mode, 0600)) == -1)
348     {
349       FREE (output);
350       return (errno);
351     }
352
353   if (nelements > history_length)
354     nelements = history_length;
355
356   /* Build a buffer of all the lines to write, and write them in one syscall.
357      Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */
358   {
359     HIST_ENTRY **the_history;   /* local */
360     register int j;
361     int buffer_size;
362     char *buffer;
363
364     the_history = history_list ();
365     /* Calculate the total number of bytes to write. */
366     for (buffer_size = 0, i = history_length - nelements; i < history_length; i++)
367       buffer_size += 1 + strlen (the_history[i]->line);
368
369     /* Allocate the buffer, and fill it. */
370     buffer = (char *)xmalloc (buffer_size);
371
372     for (j = 0, i = history_length - nelements; i < history_length; i++)
373       {
374         strcpy (buffer + j, the_history[i]->line);
375         j += strlen (the_history[i]->line);
376         buffer[j++] = '\n';
377       }
378
379     if (write (file, buffer, buffer_size) < 0)
380       rv = errno;
381     free (buffer);
382   }
383
384   close (file);
385
386   FREE (output);
387
388   return (rv);
389 }
390
391 /* Append NELEMENT entries to FILENAME.  The entries appended are from
392    the end of the list minus NELEMENTs up to the end of the list. */
393 int
394 append_history (nelements, filename)
395      int nelements;
396      const char *filename;
397 {
398   return (history_do_write (filename, nelements, HISTORY_APPEND));
399 }
400
401 /* Overwrite FILENAME with the current history.  If FILENAME is NULL,
402    then write the history list to ~/.history.  Values returned
403    are as in read_history ().*/
404 int
405 write_history (filename)
406      const char *filename;
407 {
408   return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
409 }