X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=readline%2Fhistfile.c;h=30a618247f1ec8a7be1c9202ae84224c7e8d5d5e;hb=e1181b005ba75c2708928daabdd65ade54b2c500;hp=60a91251b7aec1a754ce02ca0623e7bde4c6b8fb;hpb=84041b4c47edb0461f3b82afb77ca2d81819ebfa;p=platform%2Fupstream%2Fbinutils.git diff --git a/readline/histfile.c b/readline/histfile.c index 60a9125..30a6182 100644 --- a/readline/histfile.c +++ b/readline/histfile.c @@ -1,30 +1,34 @@ /* histfile.c - functions to manipulate the history file. */ -/* Copyright (C) 1989, 1992 Free Software Foundation, Inc. +/* Copyright (C) 1989-2010 Free Software Foundation, Inc. - This file contains the GNU History Library (the Library), a set of + This file contains the GNU History Library (History), a set of routines for managing the text of previously typed lines. - The Library is free software; you can redistribute it and/or modify + History is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. - The Library is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + History is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. - The GNU General Public License is often shipped with GNU software, and - is generally kept in a file called COPYING or LICENSE. If you do not - have a copy of the license, write to the Free Software Foundation, - 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + You should have received a copy of the GNU General Public License + along with History. If not, see . +*/ /* The goal is to make the implementation transparent, so that you don't have to know what data types are used, just what functions you can call. I think I have done that. */ + #define READLINE_LIBRARY +#if defined (__TANDEM) +# include +#endif + #if defined (HAVE_CONFIG_H) # include #endif @@ -32,7 +36,7 @@ #include #include -#ifndef _MINIX +#if ! defined (_MINIX) && defined (HAVE_SYS_FILE_H) # include #endif #include "posixstat.h" @@ -48,11 +52,13 @@ # include #endif -#if defined (__EMX__) || defined (__CYGWIN__) +#include + +#if defined (__EMX__) # undef HAVE_MMAP #endif -#ifdef HAVE_MMAP +#ifdef HISTORY_USE_MMAP # include # ifdef MAP_FILE @@ -67,7 +73,7 @@ # define MAP_FAILED ((void *)-1) # endif -#endif /* HAVE_MMAP */ +#endif /* HISTORY_USE_MMAP */ /* If we're compiling for __EMX__ (OS/2) or __CYGWIN__ (cygwin32 environment on win 95/98/nt), we want to open files with O_BINARY mode so that there @@ -93,6 +99,13 @@ extern int errno; #include "rlshell.h" #include "xmalloc.h" +/* If non-zero, we write timestamps to the history file in history_do_write() */ +int history_write_timestamps = 0; + +/* Does S look like the beginning of a history timestamp entry? Placeholder + for more extensive tests. */ +#define HIST_TIMESTAMP_START(s) (*(s) == history_comment_char && isdigit ((s)[1]) ) + /* Return the string that should be used in the place of this filename. This only matters when you don't specify the filename to read_history (), or write_history (). */ @@ -113,8 +126,12 @@ history_filename (filename) if (home == 0) { +#if 0 home = "."; home_len = 1; +#else + return (NULL); +#endif } else home_len = strlen (home); @@ -151,15 +168,22 @@ read_history_range (filename, from, to) const char *filename; int from, to; { - register char *line_start, *line_end; - char *input, *buffer, *bufend; + register char *line_start, *line_end, *p; + char *input, *buffer, *bufend, *last_ts; int file, current_line, chars_read; struct stat finfo; size_t file_size; +#if defined (EFBIG) + int overflow_errno = EFBIG; +#elif defined (EOVERFLOW) + int overflow_errno = EOVERFLOW; +#else + int overflow_errno = EIO; +#endif - buffer = (char *)NULL; + buffer = last_ts = (char *)NULL; input = history_filename (filename); - file = open (input, O_RDONLY|O_BINARY, 0666); + file = input ? open (input, O_RDONLY|O_BINARY, 0666) : -1; if ((file < 0) || (fstat (file, &finfo) == -1)) goto error_and_exit; @@ -169,37 +193,42 @@ read_history_range (filename, from, to) /* check for overflow on very large files */ if (file_size != finfo.st_size || file_size + 1 < file_size) { -#if defined (EFBIG) - errno = EFBIG; -#elif defined (EOVERFLOW) - errno = EOVERFLOW; -#endif + errno = overflow_errno; goto error_and_exit; } -#ifdef HAVE_MMAP +#ifdef HISTORY_USE_MMAP /* We map read/write and private so we can change newlines to NULs without affecting the underlying object. */ buffer = (char *)mmap (0, file_size, PROT_READ|PROT_WRITE, MAP_RFLAGS, file, 0); if ((void *)buffer == MAP_FAILED) - goto error_and_exit; + { + errno = overflow_errno; + goto error_and_exit; + } chars_read = file_size; #else buffer = (char *)malloc (file_size + 1); if (buffer == 0) - goto error_and_exit; + { + errno = overflow_errno; + goto error_and_exit; + } chars_read = read (file, buffer, file_size); #endif if (chars_read < 0) { error_and_exit: - chars_read = errno; + if (errno != 0) + chars_read = errno; + else + chars_read = EIO; if (file >= 0) close (file); FREE (input); -#ifndef HAVE_MMAP +#ifndef HISTORY_USE_MMAP FREE (buffer); #endif @@ -220,18 +249,41 @@ read_history_range (filename, from, to) for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++) if (*line_end == '\n') { - current_line++; - line_start = line_end + 1; + p = line_end + 1; + /* If we see something we think is a timestamp, continue with this + line. We should check more extensively here... */ + if (HIST_TIMESTAMP_START(p) == 0) + current_line++; + line_start = p; } /* If there are lines left to gobble, then gobble them now. */ for (line_end = line_start; line_end < bufend; line_end++) if (*line_end == '\n') { - *line_end = '\0'; + /* Change to allow Windows-like \r\n end of line delimiter. */ + if (line_end > line_start && line_end[-1] == '\r') + line_end[-1] = '\0'; + else + *line_end = '\0'; if (*line_start) - add_history (line_start); + { + if (HIST_TIMESTAMP_START(line_start) == 0) + { + add_history (line_start); + if (last_ts) + { + add_history_time (last_ts); + last_ts = NULL; + } + } + else + { + last_ts = line_start; + current_line--; + } + } current_line++; @@ -242,7 +294,7 @@ read_history_range (filename, from, to) } FREE (input); -#ifndef HAVE_MMAP +#ifndef HISTORY_USE_MMAP FREE (buffer); #else munmap (buffer, file_size); @@ -259,14 +311,14 @@ history_truncate_file (fname, lines) const char *fname; int lines; { - char *buffer, *filename, *bp; + char *buffer, *filename, *bp, *bp1; /* bp1 == bp+1 */ int file, chars_read, rv; struct stat finfo; size_t file_size; buffer = (char *)NULL; filename = history_filename (fname); - file = open (filename, O_RDONLY|O_BINARY, 0666); + file = filename ? open (filename, O_RDONLY|O_BINARY, 0666) : -1; rv = 0; /* Don't try to truncate non-regular files. */ @@ -322,11 +374,14 @@ history_truncate_file (fname, lines) } /* Count backwards from the end of buffer until we have passed - LINES lines. */ - for (bp = buffer + chars_read - 1; lines && bp > buffer; bp--) + LINES lines. bp1 is set funny initially. But since bp[1] can't + be a comment character (since it's off the end) and *bp can't be + both a newline and the history comment character, it should be OK. */ + for (bp1 = bp = buffer + chars_read - 1; lines && bp > buffer; bp--) { - if (*bp == '\n') + if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0) lines--; + bp1 = bp; } /* If this is the first line, then the file contains exactly the @@ -335,11 +390,14 @@ history_truncate_file (fname, lines) the current value of i and 0. Otherwise, write from the start of this line until the end of the buffer. */ for ( ; bp > buffer; bp--) - if (*bp == '\n') - { - bp++; - break; - } + { + if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0) + { + bp++; + break; + } + bp1 = bp; + } /* Write only if there are more lines in the file than we want to truncate to. */ @@ -359,7 +417,7 @@ history_truncate_file (fname, lines) FREE (buffer); - free (filename); + xfree (filename); return rv; } @@ -374,23 +432,24 @@ history_do_write (filename, nelements, overwrite) register int i; char *output; int file, mode, rv; +#ifdef HISTORY_USE_MMAP size_t cursize; -#ifdef HAVE_MMAP mode = overwrite ? O_RDWR|O_CREAT|O_TRUNC|O_BINARY : O_RDWR|O_APPEND|O_BINARY; #else mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY; #endif output = history_filename (filename); + file = output ? open (output, mode, 0600) : -1; rv = 0; - if ((file = open (output, mode, 0600)) == -1) + if (file == -1) { FREE (output); return (errno); } -#ifdef HAVE_MMAP +#ifdef HISTORY_USE_MMAP cursize = overwrite ? 0 : lseek (file, 0, SEEK_END); #endif @@ -408,10 +467,18 @@ history_do_write (filename, nelements, overwrite) the_history = history_list (); /* Calculate the total number of bytes to write. */ for (buffer_size = 0, i = history_length - nelements; i < history_length; i++) - buffer_size += 1 + strlen (the_history[i]->line); +#if 0 + buffer_size += 2 + HISTENT_BYTES (the_history[i]); +#else + { + if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0]) + buffer_size += strlen (the_history[i]->timestamp) + 1; + buffer_size += strlen (the_history[i]->line) + 1; + } +#endif /* Allocate the buffer, and fill it. */ -#ifdef HAVE_MMAP +#ifdef HISTORY_USE_MMAP if (ftruncate (file, buffer_size+cursize) == -1) goto mmap_error; buffer = (char *)mmap (0, buffer_size, PROT_READ|PROT_WRITE, MAP_WFLAGS, file, cursize); @@ -436,18 +503,24 @@ mmap_error: for (j = 0, i = history_length - nelements; i < history_length; i++) { + if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0]) + { + strcpy (buffer + j, the_history[i]->timestamp); + j += strlen (the_history[i]->timestamp); + buffer[j++] = '\n'; + } strcpy (buffer + j, the_history[i]->line); j += strlen (the_history[i]->line); buffer[j++] = '\n'; } -#ifdef HAVE_MMAP +#ifdef HISTORY_USE_MMAP if (msync (buffer, buffer_size, 0) != 0 || munmap (buffer, buffer_size) != 0) rv = errno; #else if (write (file, buffer, buffer_size) < 0) rv = errno; - free (buffer); + xfree (buffer); #endif }