File: | src/gnu/lib/libreadline/histfile.c |
Warning: | line 119, column 3 Value stored to 'home_len' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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_H1) |
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_H1) |
42 | # include <stdlib.h> |
43 | #else |
44 | # include "ansi_stdlib.h" |
45 | #endif /* HAVE_STDLIB_H */ |
46 | |
47 | #if defined (HAVE_UNISTD_H1) |
48 | # include <unistd.h> |
49 | #endif |
50 | |
51 | #if defined (__EMX__) || defined (__CYGWIN__) |
52 | # undef HAVE_MMAP |
53 | #endif |
54 | |
55 | #ifdef HAVE_MMAP |
56 | # include <sys/mman.h> |
57 | |
58 | # ifdef MAP_FILE |
59 | # define MAP_RFLAGS (MAP_FILE|MAP_PRIVATE) |
60 | # define MAP_WFLAGS (MAP_FILE|MAP_SHARED) |
61 | # else |
62 | # define MAP_RFLAGS MAP_PRIVATE |
63 | # define MAP_WFLAGS MAP_SHARED |
64 | # endif |
65 | |
66 | # ifndef MAP_FAILED |
67 | # define MAP_FAILED ((void *)-1) |
68 | # endif |
69 | |
70 | #endif /* HAVE_MMAP */ |
71 | |
72 | /* If we're compiling for __EMX__ (OS/2) or __CYGWIN__ (cygwin32 environment |
73 | on win 95/98/nt), we want to open files with O_BINARY mode so that there |
74 | is no \n -> \r\n conversion performed. On other systems, we don't want to |
75 | mess around with O_BINARY at all, so we ensure that it's defined to 0. */ |
76 | #if defined (__EMX__) || defined (__CYGWIN__) |
77 | # ifndef O_BINARY0 |
78 | # define O_BINARY0 0 |
79 | # endif |
80 | #else /* !__EMX__ && !__CYGWIN__ */ |
81 | # undef O_BINARY0 |
82 | # define O_BINARY0 0 |
83 | #endif /* !__EMX__ && !__CYGWIN__ */ |
84 | |
85 | #include <errno(*__errno()).h> |
86 | #if !defined (errno(*__errno())) |
87 | extern int errno(*__errno()); |
88 | #endif /* !errno */ |
89 | |
90 | #include "history.h" |
91 | #include "histlib.h" |
92 | |
93 | #include "rlshell.h" |
94 | #include "xmalloc.h" |
95 | |
96 | /* Return the string that should be used in the place of this |
97 | filename. This only matters when you don't specify the |
98 | filename to read_history (), or write_history (). */ |
99 | static char * |
100 | history_filename (filename) |
101 | const char *filename; |
102 | { |
103 | char *return_val; |
104 | const char *home; |
105 | int home_len; |
106 | char dot; |
107 | |
108 | return_val = filename ? savestring (filename)xstrdup(filename) : (char *)NULL((void *)0); |
109 | |
110 | if (return_val) |
111 | return (return_val); |
112 | |
113 | home = sh_get_env_value ("HOME"); |
114 | |
115 | if (home == 0 || *home == '\0') { |
116 | errno(*__errno()) = ENOENT2; |
117 | return (NULL((void *)0)); |
118 | } |
119 | home_len = strlen (home); |
Value stored to 'home_len' is never read | |
120 | |
121 | #if defined (__MSDOS__) |
122 | dot = '_'; |
123 | #else |
124 | dot = '.'; |
125 | #endif |
126 | if (asprintf(&return_val, "%s/%c%s", home, dot, "history") == -1) |
127 | memory_error_and_abort("asprintf"); |
128 | return (return_val); |
129 | } |
130 | |
131 | /* Add the contents of FILENAME to the history list, a line at a time. |
132 | If FILENAME is NULL, then read from ~/.history. Returns 0 if |
133 | successful, or errno if not. */ |
134 | int |
135 | read_history (filename) |
136 | const char *filename; |
137 | { |
138 | return (read_history_range (filename, 0, -1)); |
139 | } |
140 | |
141 | /* Read a range of lines from FILENAME, adding them to the history list. |
142 | Start reading at the FROM'th line and end at the TO'th. If FROM |
143 | is zero, start at the beginning. If TO is less than FROM, read |
144 | until the end of the file. If FILENAME is NULL, then read from |
145 | ~/.history. Returns 0 if successful, or errno if not. */ |
146 | int |
147 | read_history_range (filename, from, to) |
148 | const char *filename; |
149 | int from, to; |
150 | { |
151 | register char *line_start, *line_end; |
152 | char *input, *buffer, *bufend; |
153 | int file, current_line, chars_read; |
154 | struct stat finfo; |
155 | size_t file_size; |
156 | |
157 | buffer = (char *)NULL((void *)0); |
158 | if ((input = history_filename (filename))) |
159 | file = open (input, O_RDONLY0x0000|O_BINARY0, 0666); |
160 | else |
161 | file = -1; |
162 | |
163 | if ((file < 0) || (fstat (file, &finfo) == -1)) |
164 | goto error_and_exit; |
165 | |
166 | file_size = (size_t)finfo.st_size; |
167 | |
168 | /* check for overflow on very large files */ |
169 | if (file_size != finfo.st_size || file_size + 1 < file_size) |
170 | { |
171 | #if defined (EFBIG27) |
172 | errno(*__errno()) = EFBIG27; |
173 | #elif defined (EOVERFLOW87) |
174 | errno(*__errno()) = EOVERFLOW87; |
175 | #endif |
176 | goto error_and_exit; |
177 | } |
178 | |
179 | #ifdef HAVE_MMAP |
180 | /* We map read/write and private so we can change newlines to NULs without |
181 | affecting the underlying object. */ |
182 | buffer = (char *)mmap (0, file_size, PROT_READ|PROT_WRITE, MAP_RFLAGS, file, 0); |
183 | if ((void *)buffer == MAP_FAILED) |
184 | goto error_and_exit; |
185 | chars_read = file_size; |
186 | #else |
187 | buffer = (char *)malloc (file_size + 1); |
188 | if (buffer == 0) |
189 | goto error_and_exit; |
190 | |
191 | chars_read = read (file, buffer, file_size); |
192 | #endif |
193 | if (chars_read < 0) |
194 | { |
195 | error_and_exit: |
196 | chars_read = errno(*__errno()); |
197 | if (file >= 0) |
198 | close (file); |
199 | |
200 | FREE (input)if (input) free (input); |
201 | #ifndef HAVE_MMAP |
202 | FREE (buffer)if (buffer) free (buffer); |
203 | #endif |
204 | |
205 | return (chars_read); |
206 | } |
207 | |
208 | close (file); |
209 | |
210 | /* Set TO to larger than end of file if negative. */ |
211 | if (to < 0) |
212 | to = chars_read; |
213 | |
214 | /* Start at beginning of file, work to end. */ |
215 | bufend = buffer + chars_read; |
216 | current_line = 0; |
217 | |
218 | /* Skip lines until we are at FROM. */ |
219 | for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++) |
220 | if (*line_end == '\n') |
221 | { |
222 | current_line++; |
223 | line_start = line_end + 1; |
224 | } |
225 | |
226 | /* If there are lines left to gobble, then gobble them now. */ |
227 | for (line_end = line_start; line_end < bufend; line_end++) |
228 | if (*line_end == '\n') |
229 | { |
230 | *line_end = '\0'; |
231 | |
232 | if (*line_start) |
233 | add_history (line_start); |
234 | |
235 | current_line++; |
236 | |
237 | if (current_line >= to) |
238 | break; |
239 | |
240 | line_start = line_end + 1; |
241 | } |
242 | |
243 | FREE (input)if (input) free (input); |
244 | #ifndef HAVE_MMAP |
245 | FREE (buffer)if (buffer) free (buffer); |
246 | #else |
247 | munmap (buffer, file_size); |
248 | #endif |
249 | |
250 | return (0); |
251 | } |
252 | |
253 | /* Truncate the history file FNAME, leaving only LINES trailing lines. |
254 | If FNAME is NULL, then use ~/.history. Returns 0 on success, errno |
255 | on failure. */ |
256 | int |
257 | history_truncate_file (fname, lines) |
258 | const char *fname; |
259 | int lines; |
260 | { |
261 | char *buffer, *filename, *bp; |
262 | int file, chars_read, rv; |
263 | struct stat finfo; |
264 | size_t file_size; |
265 | |
266 | buffer = (char *)NULL((void *)0); |
267 | if ((filename = history_filename (fname))) |
268 | file = open (filename, O_RDONLY0x0000|O_BINARY0, 0666); |
269 | else |
270 | file = -1; |
271 | rv = 0; |
272 | |
273 | /* Don't try to truncate non-regular files. */ |
274 | if (file == -1 || fstat (file, &finfo) == -1) |
275 | { |
276 | rv = errno(*__errno()); |
277 | if (file != -1) |
278 | close (file); |
279 | goto truncate_exit; |
280 | } |
281 | |
282 | if (S_ISREG (finfo.st_mode)((finfo.st_mode & 0170000) == 0100000) == 0) |
283 | { |
284 | close (file); |
285 | #ifdef EFTYPE79 |
286 | rv = EFTYPE79; |
287 | #else |
288 | rv = EINVAL22; |
289 | #endif |
290 | goto truncate_exit; |
291 | } |
292 | |
293 | file_size = (size_t)finfo.st_size; |
294 | |
295 | /* check for overflow on very large files */ |
296 | if (file_size != finfo.st_size || file_size + 1 < file_size) |
297 | { |
298 | close (file); |
299 | #if defined (EFBIG27) |
300 | rv = errno(*__errno()) = EFBIG27; |
301 | #elif defined (EOVERFLOW87) |
302 | rv = errno(*__errno()) = EOVERFLOW87; |
303 | #else |
304 | rv = errno(*__errno()) = EINVAL22; |
305 | #endif |
306 | goto truncate_exit; |
307 | } |
308 | |
309 | buffer = (char *)malloc (file_size + 1); |
310 | if (buffer == 0) |
311 | { |
312 | close (file); |
313 | goto truncate_exit; |
314 | } |
315 | |
316 | chars_read = read (file, buffer, file_size); |
317 | close (file); |
318 | |
319 | if (chars_read <= 0) |
320 | { |
321 | rv = (chars_read < 0) ? errno(*__errno()) : 0; |
322 | goto truncate_exit; |
323 | } |
324 | |
325 | /* Count backwards from the end of buffer until we have passed |
326 | LINES lines. */ |
327 | for (bp = buffer + chars_read - 1; lines && bp > buffer; bp--) |
328 | { |
329 | if (*bp == '\n') |
330 | lines--; |
331 | } |
332 | |
333 | /* If this is the first line, then the file contains exactly the |
334 | number of lines we want to truncate to, so we don't need to do |
335 | anything. It's the first line if we don't find a newline between |
336 | the current value of i and 0. Otherwise, write from the start of |
337 | this line until the end of the buffer. */ |
338 | for ( ; bp > buffer; bp--) |
339 | if (*bp == '\n') |
340 | { |
341 | bp++; |
342 | break; |
343 | } |
344 | |
345 | /* Write only if there are more lines in the file than we want to |
346 | truncate to. */ |
347 | if (bp > buffer && ((file = open (filename, O_WRONLY0x0001|O_TRUNC0x0400|O_BINARY0, 0600)) != -1)) |
348 | { |
349 | write (file, bp, chars_read - (bp - buffer)); |
350 | |
351 | #if defined (__BEOS__) |
352 | /* BeOS ignores O_TRUNC. */ |
353 | ftruncate (file, chars_read - (bp - buffer)); |
354 | #endif |
355 | |
356 | close (file); |
357 | } |
358 | |
359 | truncate_exit: |
360 | |
361 | FREE (buffer)if (buffer) free (buffer); |
362 | |
363 | free (filename); |
364 | return rv; |
365 | } |
366 | |
367 | /* Workhorse function for writing history. Writes NELEMENT entries |
368 | from the history list to FILENAME. OVERWRITE is non-zero if you |
369 | wish to replace FILENAME with the entries. */ |
370 | static int |
371 | history_do_write (filename, nelements, overwrite) |
372 | const char *filename; |
373 | int nelements, overwrite; |
374 | { |
375 | register int i; |
376 | char *output; |
377 | int file, mode, rv; |
378 | #ifdef HAVE_MMAP |
379 | size_t cursize; |
380 | #endif |
381 | |
382 | #ifdef HAVE_MMAP |
383 | mode = overwrite ? O_RDWR0x0002|O_CREAT0x0200|O_TRUNC0x0400|O_BINARY0 : O_RDWR0x0002|O_APPEND0x0008|O_BINARY0; |
384 | #else |
385 | mode = overwrite ? O_WRONLY0x0001|O_CREAT0x0200|O_TRUNC0x0400|O_BINARY0 : O_WRONLY0x0001|O_APPEND0x0008|O_BINARY0; |
386 | #endif |
387 | output = history_filename (filename); |
388 | rv = 0; |
389 | |
390 | if (!output || (file = open (output, mode, 0600)) == -1) |
391 | { |
392 | FREE (output)if (output) free (output); |
393 | return (errno(*__errno())); |
394 | } |
395 | |
396 | #ifdef HAVE_MMAP |
397 | cursize = overwrite ? 0 : lseek (file, 0, SEEK_END2); |
398 | #endif |
399 | |
400 | if (nelements > history_length) |
401 | nelements = history_length; |
402 | |
403 | /* Build a buffer of all the lines to write, and write them in one syscall. |
404 | Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */ |
405 | { |
406 | HIST_ENTRY **the_history; /* local */ |
407 | int buffer_size; |
408 | char *buffer; |
409 | |
410 | the_history = history_list (); |
411 | /* Calculate the total number of bytes to write. */ |
412 | for (buffer_size = 1, i = history_length - nelements; i < history_length; i++) |
413 | buffer_size += 1 + strlen (the_history[i]->line); |
414 | |
415 | /* Allocate the buffer, and fill it. */ |
416 | #ifdef HAVE_MMAP |
417 | if (ftruncate (file, buffer_size+cursize) == -1) |
418 | goto mmap_error; |
419 | buffer = (char *)mmap (0, buffer_size, PROT_READ|PROT_WRITE, MAP_WFLAGS, file, cursize); |
420 | if ((void *)buffer == MAP_FAILED) |
421 | { |
422 | mmap_error: |
423 | rv = errno(*__errno()); |
424 | FREE (output)if (output) free (output); |
425 | close (file); |
426 | return rv; |
427 | } |
428 | #else |
429 | buffer = (char *)malloc (buffer_size); |
430 | if (buffer == 0) |
431 | { |
432 | rv = errno(*__errno()); |
433 | FREE (output)if (output) free (output); |
434 | close (file); |
435 | return rv; |
436 | } |
437 | #endif |
438 | buffer[0] = '\0'; |
439 | |
440 | for (i = history_length - nelements; i < history_length; i++) |
441 | { |
442 | strlcat (buffer, the_history[i]->line, buffer_size); |
443 | strlcat (buffer, "\n", buffer_size); |
444 | } |
445 | |
446 | #ifdef HAVE_MMAP |
447 | if (msync (buffer, buffer_size, 0) != 0 || munmap (buffer, buffer_size) != 0) |
448 | rv = errno(*__errno()); |
449 | #else |
450 | if (write (file, buffer, buffer_size - 1) < 0) |
451 | rv = errno(*__errno()); |
452 | free (buffer); |
453 | #endif |
454 | } |
455 | |
456 | close (file); |
457 | |
458 | FREE (output)if (output) free (output); |
459 | |
460 | return (rv); |
461 | } |
462 | |
463 | /* Append NELEMENT entries to FILENAME. The entries appended are from |
464 | the end of the list minus NELEMENTs up to the end of the list. */ |
465 | int |
466 | append_history (nelements, filename) |
467 | int nelements; |
468 | const char *filename; |
469 | { |
470 | return (history_do_write (filename, nelements, HISTORY_APPEND0)); |
471 | } |
472 | |
473 | /* Overwrite FILENAME with the current history. If FILENAME is NULL, |
474 | then write the history list to ~/.history. Values returned |
475 | are as in read_history ().*/ |
476 | int |
477 | write_history (filename) |
478 | const char *filename; |
479 | { |
480 | return (history_do_write (filename, history_length, HISTORY_OVERWRITE1)); |
481 | } |