2000-02-07 Jason Molenda (jsm@bugshack.cygnus.com)
[deliverable/binutils-gdb.git] / readline / histfile.c
CommitLineData
d60d9f65
SS
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);
c862e87b 158#if 0
d60d9f65 159 if (read (file, buffer, file_size) != file_size)
c862e87b
JM
160#else
161 if (read (file, buffer, file_size) < 0)
162#endif
d60d9f65
SS
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;
c862e87b 224 int lines;
d60d9f65
SS
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);
c862e87b
JM
283
284#if defined (__BEOS__)
285 /* BeOS ignores O_TRUNC. */
286 ftruncate (file, file_size - i);
287#endif
288
d60d9f65
SS
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}
This page took 0.044363 seconds and 4 git commands to generate.