histfile.c revision 119610
121308Sache/* histfile.c - functions to manipulate the history file. */ 221308Sache 321308Sache/* Copyright (C) 1989, 1992 Free Software Foundation, Inc. 421308Sache 521308Sache This file contains the GNU History Library (the Library), a set of 621308Sache routines for managing the text of previously typed lines. 721308Sache 821308Sache The Library is free software; you can redistribute it and/or modify 921308Sache it under the terms of the GNU General Public License as published by 1058310Sache the Free Software Foundation; either version 2, or (at your option) 1121308Sache any later version. 1221308Sache 1321308Sache The Library is distributed in the hope that it will be useful, but 1421308Sache WITHOUT ANY WARRANTY; without even the implied warranty of 1521308Sache MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1621308Sache General Public License for more details. 1721308Sache 1821308Sache The GNU General Public License is often shipped with GNU software, and 1921308Sache is generally kept in a file called COPYING or LICENSE. If you do not 2021308Sache have a copy of the license, write to the Free Software Foundation, 2158310Sache 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ 2221308Sache 2321308Sache/* The goal is to make the implementation transparent, so that you 2421308Sache don't have to know what data types are used, just what functions 2521308Sache you can call. I think I have done that. */ 2621308Sache#define READLINE_LIBRARY 2721308Sache 2821308Sache#if defined (HAVE_CONFIG_H) 2921308Sache# include <config.h> 3021308Sache#endif 3121308Sache 3221308Sache#include <stdio.h> 3321308Sache 3421308Sache#include <sys/types.h> 3535486Sache#ifndef _MINIX 3635486Sache# include <sys/file.h> 3735486Sache#endif 3858310Sache#include "posixstat.h" 3921308Sache#include <fcntl.h> 4021308Sache 4121308Sache#if defined (HAVE_STDLIB_H) 4221308Sache# include <stdlib.h> 4321308Sache#else 4421308Sache# include "ansi_stdlib.h" 4521308Sache#endif /* HAVE_STDLIB_H */ 4621308Sache 4721308Sache#if defined (HAVE_UNISTD_H) 4821308Sache# include <unistd.h> 4921308Sache#endif 5021308Sache 51119610Sache#if defined (__EMX__) || defined (__CYGWIN__) 52119610Sache# undef HAVE_MMAP 53119610Sache#endif 5421308Sache 55119610Sache#ifdef HAVE_MMAP 56119610Sache# include <sys/mman.h> 5758310Sache 58119610Sache# ifdef MAP_FILE 59119610Sache# define MAP_RFLAGS (MAP_FILE|MAP_PRIVATE) 60119610Sache# define MAP_WFLAGS (MAP_FILE|MAP_SHARED) 61119610Sache# else 62119610Sache# define MAP_RFLAGS MAP_PRIVATE 63119610Sache# define MAP_WFLAGS MAP_SHARED 64119610Sache# endif 65119610Sache 66119610Sache# ifndef MAP_FAILED 67119610Sache# define MAP_FAILED ((void *)-1) 68119610Sache# endif 69119610Sache 70119610Sache#endif /* HAVE_MMAP */ 71119610Sache 7258310Sache/* If we're compiling for __EMX__ (OS/2) or __CYGWIN__ (cygwin32 environment 7358310Sache on win 95/98/nt), we want to open files with O_BINARY mode so that there 7458310Sache is no \n -> \r\n conversion performed. On other systems, we don't want to 7558310Sache mess around with O_BINARY at all, so we ensure that it's defined to 0. */ 7658310Sache#if defined (__EMX__) || defined (__CYGWIN__) 7726497Sache# ifndef O_BINARY 7826497Sache# define O_BINARY 0 7926497Sache# endif 8058310Sache#else /* !__EMX__ && !__CYGWIN__ */ 8126497Sache# undef O_BINARY 8226497Sache# define O_BINARY 0 8358310Sache#endif /* !__EMX__ && !__CYGWIN__ */ 8426497Sache 8521308Sache#include <errno.h> 8621308Sache#if !defined (errno) 8721308Sacheextern int errno; 8821308Sache#endif /* !errno */ 8921308Sache 9021308Sache#include "history.h" 9121308Sache#include "histlib.h" 9221308Sache 9358310Sache#include "rlshell.h" 9458310Sache#include "xmalloc.h" 9526497Sache 9621308Sache/* Return the string that should be used in the place of this 9721308Sache filename. This only matters when you don't specify the 9821308Sache filename to read_history (), or write_history (). */ 9921308Sachestatic char * 10021308Sachehistory_filename (filename) 10175406Sache const char *filename; 10221308Sache{ 10375406Sache char *return_val; 10475406Sache const char *home; 10521308Sache int home_len; 10621308Sache 10721308Sache return_val = filename ? savestring (filename) : (char *)NULL; 10821308Sache 10921308Sache if (return_val) 11021308Sache return (return_val); 11121308Sache 11275406Sache home = sh_get_env_value ("HOME"); 11321308Sache 11421308Sache if (home == 0) 11521308Sache { 11621308Sache home = "."; 11721308Sache home_len = 1; 11821308Sache } 11921308Sache else 12021308Sache home_len = strlen (home); 12121308Sache 122119610Sache return_val = (char *)xmalloc (2 + home_len + 8); /* strlen(".history") == 8 */ 12321308Sache strcpy (return_val, home); 12421308Sache return_val[home_len] = '/'; 12558310Sache#if defined (__MSDOS__) 12658310Sache strcpy (return_val + home_len + 1, "_history"); 12758310Sache#else 12821308Sache strcpy (return_val + home_len + 1, ".history"); 12958310Sache#endif 13021308Sache 13121308Sache return (return_val); 13221308Sache} 13321308Sache 13421308Sache/* Add the contents of FILENAME to the history list, a line at a time. 13521308Sache If FILENAME is NULL, then read from ~/.history. Returns 0 if 13621308Sache successful, or errno if not. */ 13721308Sacheint 13821308Sacheread_history (filename) 13975406Sache const char *filename; 14021308Sache{ 14121308Sache return (read_history_range (filename, 0, -1)); 14221308Sache} 14321308Sache 14421308Sache/* Read a range of lines from FILENAME, adding them to the history list. 14521308Sache Start reading at the FROM'th line and end at the TO'th. If FROM 14621308Sache is zero, start at the beginning. If TO is less than FROM, read 14721308Sache until the end of the file. If FILENAME is NULL, then read from 14821308Sache ~/.history. Returns 0 if successful, or errno if not. */ 14921308Sacheint 15021308Sacheread_history_range (filename, from, to) 15175406Sache const char *filename; 15221308Sache int from, to; 15321308Sache{ 154119610Sache register char *line_start, *line_end; 155119610Sache char *input, *buffer, *bufend; 15658310Sache int file, current_line, chars_read; 15721308Sache struct stat finfo; 15835486Sache size_t file_size; 15921308Sache 16035486Sache buffer = (char *)NULL; 16121308Sache input = history_filename (filename); 16226497Sache file = open (input, O_RDONLY|O_BINARY, 0666); 16321308Sache 16421308Sache if ((file < 0) || (fstat (file, &finfo) == -1)) 16521308Sache goto error_and_exit; 16621308Sache 16735486Sache file_size = (size_t)finfo.st_size; 16821308Sache 16935486Sache /* check for overflow on very large files */ 17035486Sache if (file_size != finfo.st_size || file_size + 1 < file_size) 17121308Sache { 17235486Sache#if defined (EFBIG) 17335486Sache errno = EFBIG; 174119610Sache#elif defined (EOVERFLOW) 175119610Sache errno = EOVERFLOW; 17635486Sache#endif 17735486Sache goto error_and_exit; 17835486Sache } 17935486Sache 180119610Sache#ifdef HAVE_MMAP 181119610Sache /* We map read/write and private so we can change newlines to NULs without 182119610Sache affecting the underlying object. */ 183119610Sache buffer = (char *)mmap (0, file_size, PROT_READ|PROT_WRITE, MAP_RFLAGS, file, 0); 184119610Sache if ((void *)buffer == MAP_FAILED) 185119610Sache goto error_and_exit; 186119610Sache chars_read = file_size; 187119610Sache#else 188119610Sache buffer = (char *)malloc (file_size + 1); 189119610Sache if (buffer == 0) 190119610Sache goto error_and_exit; 19158310Sache 19258310Sache chars_read = read (file, buffer, file_size); 193119610Sache#endif 19458310Sache if (chars_read < 0) 19535486Sache { 19621308Sache error_and_exit: 197119610Sache chars_read = errno; 19821308Sache if (file >= 0) 19921308Sache close (file); 20021308Sache 20121308Sache FREE (input); 202119610Sache#ifndef HAVE_MMAP 20321308Sache FREE (buffer); 204119610Sache#endif 20521308Sache 206119610Sache return (chars_read); 20721308Sache } 20821308Sache 20921308Sache close (file); 21021308Sache 21121308Sache /* Set TO to larger than end of file if negative. */ 21221308Sache if (to < 0) 21358310Sache to = chars_read; 21421308Sache 21521308Sache /* Start at beginning of file, work to end. */ 216119610Sache bufend = buffer + chars_read; 217119610Sache current_line = 0; 21821308Sache 21921308Sache /* Skip lines until we are at FROM. */ 220119610Sache for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++) 221119610Sache if (*line_end == '\n') 222119610Sache { 223119610Sache current_line++; 224119610Sache line_start = line_end + 1; 225119610Sache } 22621308Sache 22721308Sache /* If there are lines left to gobble, then gobble them now. */ 228119610Sache for (line_end = line_start; line_end < bufend; line_end++) 229119610Sache if (*line_end == '\n') 23021308Sache { 231119610Sache *line_end = '\0'; 23221308Sache 233119610Sache if (*line_start) 234119610Sache add_history (line_start); 23521308Sache 23621308Sache current_line++; 23721308Sache 23821308Sache if (current_line >= to) 23921308Sache break; 24021308Sache 24121308Sache line_start = line_end + 1; 24221308Sache } 24321308Sache 24421308Sache FREE (input); 245119610Sache#ifndef HAVE_MMAP 24621308Sache FREE (buffer); 247119610Sache#else 248119610Sache munmap (buffer, file_size); 249119610Sache#endif 25021308Sache 25121308Sache return (0); 25221308Sache} 25321308Sache 25421308Sache/* Truncate the history file FNAME, leaving only LINES trailing lines. 25575406Sache If FNAME is NULL, then use ~/.history. Returns 0 on success, errno 25675406Sache on failure. */ 25721308Sacheint 25821308Sachehistory_truncate_file (fname, lines) 25975406Sache const char *fname; 26047558Sache int lines; 26121308Sache{ 262119610Sache char *buffer, *filename, *bp; 26375406Sache int file, chars_read, rv; 26421308Sache struct stat finfo; 26535486Sache size_t file_size; 26621308Sache 26726497Sache buffer = (char *)NULL; 26821308Sache filename = history_filename (fname); 26926497Sache file = open (filename, O_RDONLY|O_BINARY, 0666); 27075406Sache rv = 0; 27121308Sache 27275406Sache /* Don't try to truncate non-regular files. */ 27321308Sache if (file == -1 || fstat (file, &finfo) == -1) 27475406Sache { 27575406Sache rv = errno; 27675406Sache if (file != -1) 27775406Sache close (file); 27875406Sache goto truncate_exit; 27975406Sache } 28021308Sache 28175406Sache if (S_ISREG (finfo.st_mode) == 0) 28275406Sache { 28375406Sache close (file); 28475406Sache#ifdef EFTYPE 28575406Sache rv = EFTYPE; 28675406Sache#else 28775406Sache rv = EINVAL; 28875406Sache#endif 28975406Sache goto truncate_exit; 29075406Sache } 29158310Sache 29235486Sache file_size = (size_t)finfo.st_size; 29335486Sache 29435486Sache /* check for overflow on very large files */ 29535486Sache if (file_size != finfo.st_size || file_size + 1 < file_size) 29635486Sache { 29735486Sache close (file); 29835486Sache#if defined (EFBIG) 29975406Sache rv = errno = EFBIG; 30075406Sache#elif defined (EOVERFLOW) 30175406Sache rv = errno = EOVERFLOW; 30275406Sache#else 30375406Sache rv = errno = EINVAL; 30435486Sache#endif 30535486Sache goto truncate_exit; 30635486Sache } 30735486Sache 308119610Sache buffer = (char *)malloc (file_size + 1); 309119610Sache if (buffer == 0) 310119610Sache { 311119610Sache close (file); 312119610Sache goto truncate_exit; 313119610Sache } 314119610Sache 31535486Sache chars_read = read (file, buffer, file_size); 31621308Sache close (file); 31721308Sache 31821308Sache if (chars_read <= 0) 31975406Sache { 32075406Sache rv = (chars_read < 0) ? errno : 0; 32175406Sache goto truncate_exit; 32275406Sache } 32321308Sache 32421308Sache /* Count backwards from the end of buffer until we have passed 32521308Sache LINES lines. */ 326119610Sache for (bp = buffer + chars_read - 1; lines && bp > buffer; bp--) 32721308Sache { 328119610Sache if (*bp == '\n') 32921308Sache lines--; 33021308Sache } 33121308Sache 33221308Sache /* If this is the first line, then the file contains exactly the 33321308Sache number of lines we want to truncate to, so we don't need to do 33421308Sache anything. It's the first line if we don't find a newline between 33521308Sache the current value of i and 0. Otherwise, write from the start of 33621308Sache this line until the end of the buffer. */ 337119610Sache for ( ; bp > buffer; bp--) 338119610Sache if (*bp == '\n') 33921308Sache { 340119610Sache bp++; 34121308Sache break; 34221308Sache } 34321308Sache 34421308Sache /* Write only if there are more lines in the file than we want to 34521308Sache truncate to. */ 346119610Sache if (bp > buffer && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1)) 34721308Sache { 348119610Sache write (file, bp, chars_read - (bp - buffer)); 34947558Sache 35047558Sache#if defined (__BEOS__) 35147558Sache /* BeOS ignores O_TRUNC. */ 352119610Sache ftruncate (file, chars_read - (bp - buffer)); 35347558Sache#endif 35447558Sache 35521308Sache close (file); 35621308Sache } 35721308Sache 35821308Sache truncate_exit: 35921308Sache 36021308Sache FREE (buffer); 36121308Sache 36221308Sache free (filename); 36375406Sache return rv; 36421308Sache} 36521308Sache 36621308Sache/* Workhorse function for writing history. Writes NELEMENT entries 36721308Sache from the history list to FILENAME. OVERWRITE is non-zero if you 36821308Sache wish to replace FILENAME with the entries. */ 36921308Sachestatic int 37021308Sachehistory_do_write (filename, nelements, overwrite) 37175406Sache const char *filename; 37221308Sache int nelements, overwrite; 37321308Sache{ 37421308Sache register int i; 37526497Sache char *output; 37675406Sache int file, mode, rv; 377119610Sache size_t cursize; 37821308Sache 379119610Sache#ifdef HAVE_MMAP 380119610Sache mode = overwrite ? O_RDWR|O_CREAT|O_TRUNC|O_BINARY : O_RDWR|O_APPEND|O_BINARY; 381119610Sache#else 38226497Sache mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY; 383119610Sache#endif 38426497Sache output = history_filename (filename); 38575406Sache rv = 0; 38621308Sache 38730971Sache if ((file = open (output, mode, 0600)) == -1) 38821308Sache { 38921308Sache FREE (output); 39021308Sache return (errno); 39121308Sache } 39221308Sache 393119610Sache#ifdef HAVE_MMAP 394119610Sache cursize = overwrite ? 0 : lseek (file, 0, SEEK_END); 395119610Sache#endif 396119610Sache 39721308Sache if (nelements > history_length) 39821308Sache nelements = history_length; 39921308Sache 40021308Sache /* Build a buffer of all the lines to write, and write them in one syscall. 40121308Sache Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */ 40221308Sache { 40321308Sache HIST_ENTRY **the_history; /* local */ 40421308Sache register int j; 40521308Sache int buffer_size; 40621308Sache char *buffer; 40721308Sache 40821308Sache the_history = history_list (); 40921308Sache /* Calculate the total number of bytes to write. */ 41021308Sache for (buffer_size = 0, i = history_length - nelements; i < history_length; i++) 41121308Sache buffer_size += 1 + strlen (the_history[i]->line); 41221308Sache 41321308Sache /* Allocate the buffer, and fill it. */ 414119610Sache#ifdef HAVE_MMAP 415119610Sache if (ftruncate (file, buffer_size+cursize) == -1) 416119610Sache goto mmap_error; 417119610Sache buffer = (char *)mmap (0, buffer_size, PROT_READ|PROT_WRITE, MAP_WFLAGS, file, cursize); 418119610Sache if ((void *)buffer == MAP_FAILED) 419119610Sache { 420119610Sachemmap_error: 421119610Sache rv = errno; 422119610Sache FREE (output); 423119610Sache close (file); 424119610Sache return rv; 425119610Sache } 426119610Sache#else 427119610Sache buffer = (char *)malloc (buffer_size); 428119610Sache if (buffer == 0) 429119610Sache { 430119610Sache rv = errno; 431119610Sache FREE (output); 432119610Sache close (file); 433119610Sache return rv; 434119610Sache } 435119610Sache#endif 43621308Sache 43721308Sache for (j = 0, i = history_length - nelements; i < history_length; i++) 43821308Sache { 43921308Sache strcpy (buffer + j, the_history[i]->line); 44021308Sache j += strlen (the_history[i]->line); 44121308Sache buffer[j++] = '\n'; 44221308Sache } 44321308Sache 444119610Sache#ifdef HAVE_MMAP 445119610Sache if (msync (buffer, buffer_size, 0) != 0 || munmap (buffer, buffer_size) != 0) 446119610Sache rv = errno; 447119610Sache#else 44875406Sache if (write (file, buffer, buffer_size) < 0) 44975406Sache rv = errno; 45021308Sache free (buffer); 451119610Sache#endif 45221308Sache } 45321308Sache 45421308Sache close (file); 45521308Sache 45621308Sache FREE (output); 45721308Sache 45875406Sache return (rv); 45921308Sache} 46021308Sache 46121308Sache/* Append NELEMENT entries to FILENAME. The entries appended are from 46221308Sache the end of the list minus NELEMENTs up to the end of the list. */ 46321308Sacheint 46421308Sacheappend_history (nelements, filename) 46521308Sache int nelements; 46675406Sache const char *filename; 46721308Sache{ 46821308Sache return (history_do_write (filename, nelements, HISTORY_APPEND)); 46921308Sache} 47021308Sache 47121308Sache/* Overwrite FILENAME with the current history. If FILENAME is NULL, 47221308Sache then write the history list to ~/.history. Values returned 47321308Sache are as in read_history ().*/ 47421308Sacheint 47521308Sachewrite_history (filename) 47675406Sache const char *filename; 47721308Sache{ 47821308Sache return (history_do_write (filename, history_length, HISTORY_OVERWRITE)); 47921308Sache} 480