Annotation of embedaddon/readline/histfile.c, revision 1.1.1.1
1.1 misho 1: /* histfile.c - functions to manipulate the history file. */
2:
3: /* Copyright (C) 1989-2010 Free Software Foundation, Inc.
4:
5: This file contains the GNU History Library (History), a set of
6: routines for managing the text of previously typed lines.
7:
8: History 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 3 of the License, or
11: (at your option) any later version.
12:
13: History is distributed in the hope that it will be useful,
14: but WITHOUT ANY WARRANTY; without even the implied warranty of
15: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16: GNU General Public License for more details.
17:
18: You should have received a copy of the GNU General Public License
19: along with History. If not, see <http://www.gnu.org/licenses/>.
20: */
21:
22: /* The goal is to make the implementation transparent, so that you
23: don't have to know what data types are used, just what functions
24: you can call. I think I have done that. */
25:
26: #define READLINE_LIBRARY
27:
28: #if defined (__TANDEM)
29: # include <floss.h>
30: #endif
31:
32: #if defined (HAVE_CONFIG_H)
33: # include <config.h>
34: #endif
35:
36: #include <stdio.h>
37:
38: #include <sys/types.h>
39: #if ! defined (_MINIX) && defined (HAVE_SYS_FILE_H)
40: # include <sys/file.h>
41: #endif
42: #include "posixstat.h"
43: #include <fcntl.h>
44:
45: #if defined (HAVE_STDLIB_H)
46: # include <stdlib.h>
47: #else
48: # include "ansi_stdlib.h"
49: #endif /* HAVE_STDLIB_H */
50:
51: #if defined (HAVE_UNISTD_H)
52: # include <unistd.h>
53: #endif
54:
55: #include <ctype.h>
56:
57: #if defined (__EMX__)
58: # undef HAVE_MMAP
59: #endif
60:
61: #ifdef HISTORY_USE_MMAP
62: # include <sys/mman.h>
63:
64: # ifdef MAP_FILE
65: # define MAP_RFLAGS (MAP_FILE|MAP_PRIVATE)
66: # define MAP_WFLAGS (MAP_FILE|MAP_SHARED)
67: # else
68: # define MAP_RFLAGS MAP_PRIVATE
69: # define MAP_WFLAGS MAP_SHARED
70: # endif
71:
72: # ifndef MAP_FAILED
73: # define MAP_FAILED ((void *)-1)
74: # endif
75:
76: #endif /* HISTORY_USE_MMAP */
77:
78: /* If we're compiling for __EMX__ (OS/2) or __CYGWIN__ (cygwin32 environment
79: on win 95/98/nt), we want to open files with O_BINARY mode so that there
80: is no \n -> \r\n conversion performed. On other systems, we don't want to
81: mess around with O_BINARY at all, so we ensure that it's defined to 0. */
82: #if defined (__EMX__) || defined (__CYGWIN__)
83: # ifndef O_BINARY
84: # define O_BINARY 0
85: # endif
86: #else /* !__EMX__ && !__CYGWIN__ */
87: # undef O_BINARY
88: # define O_BINARY 0
89: #endif /* !__EMX__ && !__CYGWIN__ */
90:
91: #include <errno.h>
92: #if !defined (errno)
93: extern int errno;
94: #endif /* !errno */
95:
96: #include "history.h"
97: #include "histlib.h"
98:
99: #include "rlshell.h"
100: #include "xmalloc.h"
101:
102: /* If non-zero, we write timestamps to the history file in history_do_write() */
103: int history_write_timestamps = 0;
104:
105: /* Does S look like the beginning of a history timestamp entry? Placeholder
106: for more extensive tests. */
107: #define HIST_TIMESTAMP_START(s) (*(s) == history_comment_char && isdigit ((s)[1]) )
108:
109: /* Return the string that should be used in the place of this
110: filename. This only matters when you don't specify the
111: filename to read_history (), or write_history (). */
112: static char *
113: history_filename (filename)
114: const char *filename;
115: {
116: char *return_val;
117: const char *home;
118: int home_len;
119:
120: return_val = filename ? savestring (filename) : (char *)NULL;
121:
122: if (return_val)
123: return (return_val);
124:
125: home = sh_get_env_value ("HOME");
126:
127: if (home == 0)
128: return (NULL);
129: else
130: home_len = strlen (home);
131:
132: return_val = (char *)xmalloc (2 + home_len + 8); /* strlen(".history") == 8 */
133: strcpy (return_val, home);
134: return_val[home_len] = '/';
135: #if defined (__MSDOS__)
136: strcpy (return_val + home_len + 1, "_history");
137: #else
138: strcpy (return_val + home_len + 1, ".history");
139: #endif
140:
141: return (return_val);
142: }
143:
144: static char *
145: history_backupfile (filename)
146: const char *filename;
147: {
148: char *ret;
149: size_t len;
150:
151: len = strlen (filename);
152: ret = xmalloc (len + 2);
153: strcpy (ret, filename);
154: ret[len] = '-';
155: ret[len+1] = '\0';
156: return ret;
157: }
158:
159: /* Add the contents of FILENAME to the history list, a line at a time.
160: If FILENAME is NULL, then read from ~/.history. Returns 0 if
161: successful, or errno if not. */
162: int
163: read_history (filename)
164: const char *filename;
165: {
166: return (read_history_range (filename, 0, -1));
167: }
168:
169: /* Read a range of lines from FILENAME, adding them to the history list.
170: Start reading at the FROM'th line and end at the TO'th. If FROM
171: is zero, start at the beginning. If TO is less than FROM, read
172: until the end of the file. If FILENAME is NULL, then read from
173: ~/.history. Returns 0 if successful, or errno if not. */
174: int
175: read_history_range (filename, from, to)
176: const char *filename;
177: int from, to;
178: {
179: register char *line_start, *line_end, *p;
180: char *input, *buffer, *bufend, *last_ts;
181: int file, current_line, chars_read;
182: struct stat finfo;
183: size_t file_size;
184: #if defined (EFBIG)
185: int overflow_errno = EFBIG;
186: #elif defined (EOVERFLOW)
187: int overflow_errno = EOVERFLOW;
188: #else
189: int overflow_errno = EIO;
190: #endif
191:
192: buffer = last_ts = (char *)NULL;
193: input = history_filename (filename);
194: file = input ? open (input, O_RDONLY|O_BINARY, 0666) : -1;
195:
196: if ((file < 0) || (fstat (file, &finfo) == -1))
197: goto error_and_exit;
198:
199: file_size = (size_t)finfo.st_size;
200:
201: /* check for overflow on very large files */
202: if (file_size != finfo.st_size || file_size + 1 < file_size)
203: {
204: errno = overflow_errno;
205: goto error_and_exit;
206: }
207:
208: #ifdef HISTORY_USE_MMAP
209: /* We map read/write and private so we can change newlines to NULs without
210: affecting the underlying object. */
211: buffer = (char *)mmap (0, file_size, PROT_READ|PROT_WRITE, MAP_RFLAGS, file, 0);
212: if ((void *)buffer == MAP_FAILED)
213: {
214: errno = overflow_errno;
215: goto error_and_exit;
216: }
217: chars_read = file_size;
218: #else
219: buffer = (char *)malloc (file_size + 1);
220: if (buffer == 0)
221: {
222: errno = overflow_errno;
223: goto error_and_exit;
224: }
225:
226: chars_read = read (file, buffer, file_size);
227: #endif
228: if (chars_read < 0)
229: {
230: error_and_exit:
231: if (errno != 0)
232: chars_read = errno;
233: else
234: chars_read = EIO;
235: if (file >= 0)
236: close (file);
237:
238: FREE (input);
239: #ifndef HISTORY_USE_MMAP
240: FREE (buffer);
241: #endif
242:
243: return (chars_read);
244: }
245:
246: close (file);
247:
248: /* Set TO to larger than end of file if negative. */
249: if (to < 0)
250: to = chars_read;
251:
252: /* Start at beginning of file, work to end. */
253: bufend = buffer + chars_read;
254: current_line = 0;
255:
256: /* Skip lines until we are at FROM. */
257: for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++)
258: if (*line_end == '\n')
259: {
260: p = line_end + 1;
261: /* If we see something we think is a timestamp, continue with this
262: line. We should check more extensively here... */
263: if (HIST_TIMESTAMP_START(p) == 0)
264: current_line++;
265: line_start = p;
266: }
267:
268: /* If there are lines left to gobble, then gobble them now. */
269: for (line_end = line_start; line_end < bufend; line_end++)
270: if (*line_end == '\n')
271: {
272: /* Change to allow Windows-like \r\n end of line delimiter. */
273: if (line_end > line_start && line_end[-1] == '\r')
274: line_end[-1] = '\0';
275: else
276: *line_end = '\0';
277:
278: if (*line_start)
279: {
280: if (HIST_TIMESTAMP_START(line_start) == 0)
281: {
282: add_history (line_start);
283: if (last_ts)
284: {
285: add_history_time (last_ts);
286: last_ts = NULL;
287: }
288: }
289: else
290: {
291: last_ts = line_start;
292: current_line--;
293: }
294: }
295:
296: current_line++;
297:
298: if (current_line >= to)
299: break;
300:
301: line_start = line_end + 1;
302: }
303:
304: FREE (input);
305: #ifndef HISTORY_USE_MMAP
306: FREE (buffer);
307: #else
308: munmap (buffer, file_size);
309: #endif
310:
311: return (0);
312: }
313:
314: /* Truncate the history file FNAME, leaving only LINES trailing lines.
315: If FNAME is NULL, then use ~/.history. Returns 0 on success, errno
316: on failure. */
317: int
318: history_truncate_file (fname, lines)
319: const char *fname;
320: int lines;
321: {
322: char *buffer, *filename, *bp, *bp1; /* bp1 == bp+1 */
323: int file, chars_read, rv;
324: struct stat finfo;
325: size_t file_size;
326:
327: buffer = (char *)NULL;
328: filename = history_filename (fname);
329: file = filename ? open (filename, O_RDONLY|O_BINARY, 0666) : -1;
330: rv = 0;
331:
332: /* Don't try to truncate non-regular files. */
333: if (file == -1 || fstat (file, &finfo) == -1)
334: {
335: rv = errno;
336: if (file != -1)
337: close (file);
338: goto truncate_exit;
339: }
340:
341: if (S_ISREG (finfo.st_mode) == 0)
342: {
343: close (file);
344: #ifdef EFTYPE
345: rv = EFTYPE;
346: #else
347: rv = EINVAL;
348: #endif
349: goto truncate_exit;
350: }
351:
352: file_size = (size_t)finfo.st_size;
353:
354: /* check for overflow on very large files */
355: if (file_size != finfo.st_size || file_size + 1 < file_size)
356: {
357: close (file);
358: #if defined (EFBIG)
359: rv = errno = EFBIG;
360: #elif defined (EOVERFLOW)
361: rv = errno = EOVERFLOW;
362: #else
363: rv = errno = EINVAL;
364: #endif
365: goto truncate_exit;
366: }
367:
368: buffer = (char *)malloc (file_size + 1);
369: if (buffer == 0)
370: {
371: close (file);
372: goto truncate_exit;
373: }
374:
375: chars_read = read (file, buffer, file_size);
376: close (file);
377:
378: if (chars_read <= 0)
379: {
380: rv = (chars_read < 0) ? errno : 0;
381: goto truncate_exit;
382: }
383:
384: /* Count backwards from the end of buffer until we have passed
385: LINES lines. bp1 is set funny initially. But since bp[1] can't
386: be a comment character (since it's off the end) and *bp can't be
387: both a newline and the history comment character, it should be OK. */
388: for (bp1 = bp = buffer + chars_read - 1; lines && bp > buffer; bp--)
389: {
390: if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
391: lines--;
392: bp1 = bp;
393: }
394:
395: /* If this is the first line, then the file contains exactly the
396: number of lines we want to truncate to, so we don't need to do
397: anything. It's the first line if we don't find a newline between
398: the current value of i and 0. Otherwise, write from the start of
399: this line until the end of the buffer. */
400: for ( ; bp > buffer; bp--)
401: {
402: if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0)
403: {
404: bp++;
405: break;
406: }
407: bp1 = bp;
408: }
409:
410: /* Write only if there are more lines in the file than we want to
411: truncate to. */
412: if (bp > buffer && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1))
413: {
414: if (write (file, bp, chars_read - (bp - buffer)) < 0)
415: rv = errno;
416:
417: #if defined (__BEOS__)
418: /* BeOS ignores O_TRUNC. */
419: ftruncate (file, chars_read - (bp - buffer));
420: #endif
421:
422: if (close (file) < 0 && rv == 0)
423: rv = errno;
424: }
425:
426: truncate_exit:
427:
428: FREE (buffer);
429:
430: xfree (filename);
431: return rv;
432: }
433:
434: /* Workhorse function for writing history. Writes NELEMENT entries
435: from the history list to FILENAME. OVERWRITE is non-zero if you
436: wish to replace FILENAME with the entries. */
437: static int
438: history_do_write (filename, nelements, overwrite)
439: const char *filename;
440: int nelements, overwrite;
441: {
442: register int i;
443: char *output, *bakname;
444: int file, mode, rv;
445: #ifdef HISTORY_USE_MMAP
446: size_t cursize;
447:
448: mode = overwrite ? O_RDWR|O_CREAT|O_TRUNC|O_BINARY : O_RDWR|O_APPEND|O_BINARY;
449: #else
450: mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
451: #endif
452: output = history_filename (filename);
453: bakname = (overwrite && output) ? history_backupfile (output) : 0;
454:
455: if (output && bakname)
456: rename (output, bakname);
457:
458: file = output ? open (output, mode, 0600) : -1;
459: rv = 0;
460:
461: if (file == -1)
462: {
463: rv = errno;
464: if (output && bakname)
465: rename (bakname, output);
466: FREE (output);
467: FREE (bakname);
468: return (rv);
469: }
470:
471: #ifdef HISTORY_USE_MMAP
472: cursize = overwrite ? 0 : lseek (file, 0, SEEK_END);
473: #endif
474:
475: if (nelements > history_length)
476: nelements = history_length;
477:
478: /* Build a buffer of all the lines to write, and write them in one syscall.
479: Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */
480: {
481: HIST_ENTRY **the_history; /* local */
482: register int j;
483: int buffer_size;
484: char *buffer;
485:
486: the_history = history_list ();
487: /* Calculate the total number of bytes to write. */
488: for (buffer_size = 0, i = history_length - nelements; i < history_length; i++)
489: #if 0
490: buffer_size += 2 + HISTENT_BYTES (the_history[i]);
491: #else
492: {
493: if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
494: buffer_size += strlen (the_history[i]->timestamp) + 1;
495: buffer_size += strlen (the_history[i]->line) + 1;
496: }
497: #endif
498:
499: /* Allocate the buffer, and fill it. */
500: #ifdef HISTORY_USE_MMAP
501: if (ftruncate (file, buffer_size+cursize) == -1)
502: goto mmap_error;
503: buffer = (char *)mmap (0, buffer_size, PROT_READ|PROT_WRITE, MAP_WFLAGS, file, cursize);
504: if ((void *)buffer == MAP_FAILED)
505: {
506: mmap_error:
507: rv = errno;
508: close (file);
509: if (output && bakname)
510: rename (bakname, output);
511: FREE (output);
512: FREE (bakname);
513: return rv;
514: }
515: #else
516: buffer = (char *)malloc (buffer_size);
517: if (buffer == 0)
518: {
519: rv = errno;
520: close (file);
521: if (output && bakname)
522: rename (bakname, output);
523: FREE (output);
524: FREE (bakname);
525: return rv;
526: }
527: #endif
528:
529: for (j = 0, i = history_length - nelements; i < history_length; i++)
530: {
531: if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0])
532: {
533: strcpy (buffer + j, the_history[i]->timestamp);
534: j += strlen (the_history[i]->timestamp);
535: buffer[j++] = '\n';
536: }
537: strcpy (buffer + j, the_history[i]->line);
538: j += strlen (the_history[i]->line);
539: buffer[j++] = '\n';
540: }
541:
542: #ifdef HISTORY_USE_MMAP
543: if (msync (buffer, buffer_size, 0) != 0 || munmap (buffer, buffer_size) != 0)
544: rv = errno;
545: #else
546: if (write (file, buffer, buffer_size) < 0)
547: rv = errno;
548: xfree (buffer);
549: #endif
550: }
551:
552: if (close (file) < 0 && rv == 0)
553: rv = errno;
554:
555: if (rv != 0 && output && bakname)
556: rename (bakname, output);
557: else if (rv == 0 && bakname)
558: unlink (bakname);
559:
560: FREE (output);
561: FREE (bakname);
562:
563: return (rv);
564: }
565:
566: /* Append NELEMENT entries to FILENAME. The entries appended are from
567: the end of the list minus NELEMENTs up to the end of the list. */
568: int
569: append_history (nelements, filename)
570: int nelements;
571: const char *filename;
572: {
573: return (history_do_write (filename, nelements, HISTORY_APPEND));
574: }
575:
576: /* Overwrite FILENAME with the current history. If FILENAME is NULL,
577: then write the history list to ~/.history. Values returned
578: are as in read_history ().*/
579: int
580: write_history (filename)
581: const char *filename;
582: {
583: return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
584: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>