Change "win_resized" to bool
[deliverable/binutils-gdb.git] / readline / histfile.c
index 8749886b6e37e68df38ab1f928a506390339c7e9..dc64bde1c5acf8c117080eb7c783a2cd3181311d 100644 (file)
@@ -1,6 +1,6 @@
 /* histfile.c - functions to manipulate the history file. */
 
-/* Copyright (C) 1989-2015 Free Software Foundation, Inc.
+/* Copyright (C) 1989-2018 Free Software Foundation, Inc.
 
    This file contains the GNU History Library (History), a set of
    routines for managing the text of previously typed lines.
@@ -107,9 +107,19 @@ extern int errno;
 #  define PATH_MAX     1024    /* default */
 #endif
 
+extern void _hs_append_history_line PARAMS((int, const char *));
+
+/* history file version; currently unused */
+int history_file_version = 1;
+
 /* If non-zero, we write timestamps to the history file in history_do_write() */
 int history_write_timestamps = 0;
 
+/* If non-zero, we assume that a history file that starts with a timestamp
+   uses timestamp-delimited entries and can include multi-line history
+   entries. Used by read_history_range */
+int history_multiline_entries = 0;
+
 /* Immediately after a call to read_history() or read_history_range(), this
    will return the number of lines just read from the history file in that
    call. */
@@ -133,8 +143,7 @@ static int histfile_restore PARAMS((const char *, const char *));
    filename.  This only matters when you don't specify the
    filename to read_history (), or write_history (). */
 static char *
-history_filename (filename)
-     const char *filename;
+history_filename (const char *filename)
 {
   char *return_val;
   const char *home;
@@ -169,8 +178,7 @@ history_filename (filename)
 }
 
 static char *
-history_backupfile (filename)
-     const char *filename;
+history_backupfile (const char *filename)
 {
   const char *fn;
   char *ret, linkbuf[PATH_MAX+1];
@@ -198,8 +206,7 @@ history_backupfile (filename)
 }
   
 static char *
-history_tempfile (filename)
-     const char *filename;
+history_tempfile (const char *filename)
 {
   const char *fn;
   char *ret, linkbuf[PATH_MAX+1];
@@ -241,8 +248,7 @@ history_tempfile (filename)
    If FILENAME is NULL, then read from ~/.history.  Returns 0 if
    successful, or errno if not. */
 int
-read_history (filename)
-     const char *filename;
+read_history (const char *filename)
 {
   return (read_history_range (filename, 0, -1));
 }
@@ -253,13 +259,11 @@ read_history (filename)
    until the end of the file.  If FILENAME is NULL, then read from
    ~/.history.  Returns 0 if successful, or errno if not. */
 int
-read_history_range (filename, from, to)
-     const char *filename;
-     int from, to;
+read_history_range (const char *filename, int from, int to)
 {
   register char *line_start, *line_end, *p;
   char *input, *buffer, *bufend, *last_ts;
-  int file, current_line, chars_read;
+  int file, current_line, chars_read, has_timestamps, reset_comment_char;
   struct stat finfo;
   size_t file_size;
 #if defined (EFBIG)
@@ -279,6 +283,16 @@ read_history_range (filename, from, to)
   if ((file < 0) || (fstat (file, &finfo) == -1))
     goto error_and_exit;
 
+  if (S_ISREG (finfo.st_mode) == 0)
+    {
+#ifdef EFTYPE
+      errno = EFTYPE;
+#else
+      errno = EINVAL;
+#endif
+      goto error_and_exit;
+    }
+
   file_size = (size_t)finfo.st_size;
 
   /* check for overflow on very large files */
@@ -288,6 +302,12 @@ read_history_range (filename, from, to)
       goto error_and_exit;
     }
 
+  if (file_size == 0)
+    {
+      free (input);
+      return 0;        /* don't waste time if we don't have to */
+    }
+
 #ifdef HISTORY_USE_MMAP
   /* We map read/write and private so we can change newlines to NULs without
      affecting the underlying object. */
@@ -334,8 +354,22 @@ read_history_range (filename, from, to)
 
   /* Start at beginning of file, work to end. */
   bufend = buffer + chars_read;
+  *bufend = '\0';              /* null-terminate buffer for timestamp checks */
   current_line = 0;
 
+  /* Heuristic: the history comment character rarely changes, so assume we
+     have timestamps if the buffer starts with `#[:digit:]' and temporarily
+     set history_comment_char so timestamp parsing works right */
+  reset_comment_char = 0;
+  if (history_comment_char == '\0' && buffer[0] == '#' && isdigit ((unsigned char)buffer[1]))
+    {
+      history_comment_char = '#';
+      reset_comment_char = 1;
+    }
+
+  has_timestamps = HIST_TIMESTAMP_START (buffer);
+  history_multiline_entries += has_timestamps && history_write_timestamps;  
+
   /* Skip lines until we are at FROM. */
   for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++)
     if (*line_end == '\n')
@@ -362,7 +396,10 @@ read_history_range (filename, from, to)
          {
            if (HIST_TIMESTAMP_START(line_start) == 0)
              {
-               add_history (line_start);
+               if (last_ts == NULL && history_length > 0 && history_multiline_entries)
+                 _hs_append_history_line (history_length - 1, line_start);
+               else
+                 add_history (line_start);
                if (last_ts)
                  {
                    add_history_time (last_ts);
@@ -385,6 +422,8 @@ read_history_range (filename, from, to)
       }
 
   history_lines_read_from_file = current_line;
+  if (reset_comment_char)
+    history_comment_char = '\0';
 
   FREE (input);
 #ifndef HISTORY_USE_MMAP
@@ -399,9 +438,7 @@ read_history_range (filename, from, to)
 /* Save FILENAME to BACK, handling case where FILENAME is a symlink
    (e.g., ~/.bash_history -> .histfiles/.bash_history.$HOSTNAME) */
 static int
-histfile_backup (filename, back)
-     const char *filename;
-     const char *back;
+histfile_backup (const char *filename, const char *back)
 {
 #if defined (HAVE_READLINK)
   char linkbuf[PATH_MAX+1];
@@ -420,9 +457,7 @@ histfile_backup (filename, back)
 /* Restore ORIG from BACKUP handling case where ORIG is a symlink
    (e.g., ~/.bash_history -> .histfiles/.bash_history.$HOSTNAME) */
 static int
-histfile_restore (backup, orig)
-     const char *backup;
-     const char *orig;
+histfile_restore (const char *backup, const char *orig)
 {
 #if defined (HAVE_READLINK)
   char linkbuf[PATH_MAX+1];
@@ -442,12 +477,10 @@ histfile_restore (backup, orig)
    If FNAME is NULL, then use ~/.history.  Writes a new file and renames
    it to the original name.  Returns 0 on success, errno on failure. */
 int
-history_truncate_file (fname, lines)
-     const char *fname;
-     int lines;
+history_truncate_file (const char *fname, int lines)
 {
   char *buffer, *filename, *tempname, *bp, *bp1;               /* bp1 == bp+1 */
-  int file, chars_read, rv, orig_lines, exists;
+  int file, chars_read, rv, orig_lines, exists, r;
   struct stat finfo;
   size_t file_size;
 
@@ -578,12 +611,14 @@ history_truncate_file (fname, lines)
       history_lines_written_to_file = 0;
     }
 
+#if defined (HAVE_CHOWN)
   /* Make sure the new filename is owned by the same user as the old.  If one
      user is running this, it's a no-op.  If the shell is running after sudo
      with a shared history file, we don't want to leave the history file
      owned by root. */
   if (rv == 0 && exists)
-    chown (filename, finfo.st_uid, finfo.st_gid);
+    r = chown (filename, finfo.st_uid, finfo.st_gid);
+#endif
 
   xfree (filename);
   FREE (tempname);
@@ -595,9 +630,7 @@ history_truncate_file (fname, lines)
    from the history list to FILENAME.  OVERWRITE is non-zero if you
    wish to replace FILENAME with the entries. */
 static int
-history_do_write (filename, nelements, overwrite)
-     const char *filename;
-     int nelements, overwrite;
+history_do_write (const char *filename, int nelements, int overwrite)
 {
   register int i;
   char *output, *tempname, *histname;
@@ -613,10 +646,11 @@ history_do_write (filename, nelements, overwrite)
   mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
 #endif
   histname = history_filename (filename);
-  tempname = (overwrite && histname) ? history_tempfile (histname) : 0;
-  output = tempname ? tempname : histname;
   exists = histname ? (stat (histname, &finfo) == 0) : 0;
 
+  tempname = (overwrite && exists && S_ISREG (finfo.st_mode)) ? history_tempfile (histname) : 0;
+  output = tempname ? tempname : histname;
+
   file = output ? open (output, mode, 0600) : -1;
   rv = 0;
 
@@ -724,12 +758,14 @@ mmap_error:
       history_lines_written_to_file = 0;
     }
 
+#if defined (HAVE_CHOWN)
   /* Make sure the new filename is owned by the same user as the old.  If one
      user is running this, it's a no-op.  If the shell is running after sudo
      with a shared history file, we don't want to leave the history file
      owned by root. */
   if (rv == 0 && exists)
-    chown (histname, finfo.st_uid, finfo.st_gid);
+    mode = chown (histname, finfo.st_uid, finfo.st_gid);
+#endif
 
   FREE (histname);
   FREE (tempname);
@@ -740,9 +776,7 @@ mmap_error:
 /* Append NELEMENT entries to FILENAME.  The entries appended are from
    the end of the list minus NELEMENTs up to the end of the list. */
 int
-append_history (nelements, filename)
-     int nelements;
-     const char *filename;
+append_history (int nelements, const char *filename)
 {
   return (history_do_write (filename, nelements, HISTORY_APPEND));
 }
@@ -751,8 +785,7 @@ append_history (nelements, filename)
    then write the history list to ~/.history.  Values returned
    are as in read_history ().*/
 int
-write_history (filename)
-     const char *filename;
+write_history (const char *filename)
 {
   return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
 }
This page took 0.026124 seconds and 4 git commands to generate.