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