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