121308Sache/* histfile.c - functions to manipulate the history file. */ 221308Sache 3136644Sache/* Copyright (C) 1989-2003 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. */ 26136644Sache 2721308Sache#define READLINE_LIBRARY 2821308Sache 29136644Sache#if defined (__TANDEM) 30136644Sache# include <floss.h> 31136644Sache#endif 32136644Sache 3321308Sache#if defined (HAVE_CONFIG_H) 3421308Sache# include <config.h> 3521308Sache#endif 3621308Sache 3721308Sache#include <stdio.h> 3821308Sache 3921308Sache#include <sys/types.h> 40136644Sache#if ! defined (_MINIX) && defined (HAVE_SYS_FILE_H) 4135486Sache# include <sys/file.h> 4235486Sache#endif 4358310Sache#include "posixstat.h" 4421308Sache#include <fcntl.h> 4521308Sache 4621308Sache#if defined (HAVE_STDLIB_H) 4721308Sache# include <stdlib.h> 4821308Sache#else 4921308Sache# include "ansi_stdlib.h" 5021308Sache#endif /* HAVE_STDLIB_H */ 5121308Sache 5221308Sache#if defined (HAVE_UNISTD_H) 5321308Sache# include <unistd.h> 5421308Sache#endif 5521308Sache 56119610Sache#if defined (__EMX__) || defined (__CYGWIN__) 57119610Sache# undef HAVE_MMAP 58119610Sache#endif 5921308Sache 60136644Sache#ifdef HISTORY_USE_MMAP 61119610Sache# include <sys/mman.h> 6258310Sache 63119610Sache# ifdef MAP_FILE 64119610Sache# define MAP_RFLAGS (MAP_FILE|MAP_PRIVATE) 65119610Sache# define MAP_WFLAGS (MAP_FILE|MAP_SHARED) 66119610Sache# else 67119610Sache# define MAP_RFLAGS MAP_PRIVATE 68119610Sache# define MAP_WFLAGS MAP_SHARED 69119610Sache# endif 70119610Sache 71119610Sache# ifndef MAP_FAILED 72119610Sache# define MAP_FAILED ((void *)-1) 73119610Sache# endif 74119610Sache 75136644Sache#endif /* HISTORY_USE_MMAP */ 76119610Sache 7758310Sache/* If we're compiling for __EMX__ (OS/2) or __CYGWIN__ (cygwin32 environment 7858310Sache on win 95/98/nt), we want to open files with O_BINARY mode so that there 7958310Sache is no \n -> \r\n conversion performed. On other systems, we don't want to 8058310Sache mess around with O_BINARY at all, so we ensure that it's defined to 0. */ 8158310Sache#if defined (__EMX__) || defined (__CYGWIN__) 8226497Sache# ifndef O_BINARY 8326497Sache# define O_BINARY 0 8426497Sache# endif 8558310Sache#else /* !__EMX__ && !__CYGWIN__ */ 8626497Sache# undef O_BINARY 8726497Sache# define O_BINARY 0 8858310Sache#endif /* !__EMX__ && !__CYGWIN__ */ 8926497Sache 9021308Sache#include <errno.h> 9121308Sache#if !defined (errno) 9221308Sacheextern int errno; 9321308Sache#endif /* !errno */ 9421308Sache 9521308Sache#include "history.h" 9621308Sache#include "histlib.h" 9721308Sache 9858310Sache#include "rlshell.h" 9958310Sache#include "xmalloc.h" 10026497Sache 101136644Sache/* If non-zero, we write timestamps to the history file in history_do_write() */ 102136644Sacheint history_write_timestamps = 0; 103136644Sache 104136644Sache/* Does S look like the beginning of a history timestamp entry? Placeholder 105136644Sache for more extensive tests. */ 106136644Sache#define HIST_TIMESTAMP_START(s) (*(s) == history_comment_char) 107136644Sache 10821308Sache/* Return the string that should be used in the place of this 10921308Sache filename. This only matters when you don't specify the 11021308Sache filename to read_history (), or write_history (). */ 11121308Sachestatic char * 11221308Sachehistory_filename (filename) 11375406Sache const char *filename; 11421308Sache{ 11575406Sache char *return_val; 11675406Sache const char *home; 11721308Sache int home_len; 11821308Sache 11921308Sache return_val = filename ? savestring (filename) : (char *)NULL; 12021308Sache 12121308Sache if (return_val) 12221308Sache return (return_val); 12321308Sache 12475406Sache home = sh_get_env_value ("HOME"); 12521308Sache 12621308Sache if (home == 0) 12721308Sache { 12821308Sache home = "."; 12921308Sache home_len = 1; 13021308Sache } 13121308Sache else 13221308Sache home_len = strlen (home); 13321308Sache 134119610Sache return_val = (char *)xmalloc (2 + home_len + 8); /* strlen(".history") == 8 */ 13521308Sache strcpy (return_val, home); 13621308Sache return_val[home_len] = '/'; 13758310Sache#if defined (__MSDOS__) 13858310Sache strcpy (return_val + home_len + 1, "_history"); 13958310Sache#else 14021308Sache strcpy (return_val + home_len + 1, ".history"); 14158310Sache#endif 14221308Sache 14321308Sache return (return_val); 14421308Sache} 14521308Sache 14621308Sache/* Add the contents of FILENAME to the history list, a line at a time. 14721308Sache If FILENAME is NULL, then read from ~/.history. Returns 0 if 14821308Sache successful, or errno if not. */ 14921308Sacheint 15021308Sacheread_history (filename) 15175406Sache const char *filename; 15221308Sache{ 15321308Sache return (read_history_range (filename, 0, -1)); 15421308Sache} 15521308Sache 15621308Sache/* Read a range of lines from FILENAME, adding them to the history list. 15721308Sache Start reading at the FROM'th line and end at the TO'th. If FROM 15821308Sache is zero, start at the beginning. If TO is less than FROM, read 15921308Sache until the end of the file. If FILENAME is NULL, then read from 16021308Sache ~/.history. Returns 0 if successful, or errno if not. */ 16121308Sacheint 16221308Sacheread_history_range (filename, from, to) 16375406Sache const char *filename; 16421308Sache int from, to; 16521308Sache{ 166136644Sache register char *line_start, *line_end, *p; 167136644Sache char *input, *buffer, *bufend, *last_ts; 16858310Sache int file, current_line, chars_read; 16921308Sache struct stat finfo; 17035486Sache size_t file_size; 171136644Sache#if defined (EFBIG) 172136644Sache int overflow_errno = EFBIG; 173136644Sache#elif defined (EOVERFLOW) 174136644Sache int overflow_errno = EOVERFLOW; 175136644Sache#else 176136644Sache int overflow_errno = EIO; 177136644Sache#endif 17821308Sache 179136644Sache buffer = last_ts = (char *)NULL; 18021308Sache input = history_filename (filename); 18126497Sache file = open (input, O_RDONLY|O_BINARY, 0666); 18221308Sache 18321308Sache if ((file < 0) || (fstat (file, &finfo) == -1)) 18421308Sache goto error_and_exit; 18521308Sache 18635486Sache file_size = (size_t)finfo.st_size; 18721308Sache 18835486Sache /* check for overflow on very large files */ 18935486Sache if (file_size != finfo.st_size || file_size + 1 < file_size) 19021308Sache { 191136644Sache errno = overflow_errno; 19235486Sache goto error_and_exit; 19335486Sache } 19435486Sache 195136644Sache#ifdef HISTORY_USE_MMAP 196119610Sache /* We map read/write and private so we can change newlines to NULs without 197119610Sache affecting the underlying object. */ 198119610Sache buffer = (char *)mmap (0, file_size, PROT_READ|PROT_WRITE, MAP_RFLAGS, file, 0); 199119610Sache if ((void *)buffer == MAP_FAILED) 200136644Sache { 201136644Sache errno = overflow_errno; 202136644Sache goto error_and_exit; 203136644Sache } 204119610Sache chars_read = file_size; 205119610Sache#else 206119610Sache buffer = (char *)malloc (file_size + 1); 207119610Sache if (buffer == 0) 208136644Sache { 209136644Sache errno = overflow_errno; 210136644Sache goto error_and_exit; 211136644Sache } 21258310Sache 21358310Sache chars_read = read (file, buffer, file_size); 214119610Sache#endif 21558310Sache if (chars_read < 0) 21635486Sache { 21721308Sache error_and_exit: 218136644Sache if (errno != 0) 219136644Sache chars_read = errno; 220136644Sache else 221136644Sache chars_read = EIO; 22221308Sache if (file >= 0) 22321308Sache close (file); 22421308Sache 22521308Sache FREE (input); 226136644Sache#ifndef HISTORY_USE_MMAP 22721308Sache FREE (buffer); 228119610Sache#endif 22921308Sache 230119610Sache return (chars_read); 23121308Sache } 23221308Sache 23321308Sache close (file); 23421308Sache 23521308Sache /* Set TO to larger than end of file if negative. */ 23621308Sache if (to < 0) 23758310Sache to = chars_read; 23821308Sache 23921308Sache /* Start at beginning of file, work to end. */ 240119610Sache bufend = buffer + chars_read; 241119610Sache current_line = 0; 24221308Sache 24321308Sache /* Skip lines until we are at FROM. */ 244119610Sache for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++) 245119610Sache if (*line_end == '\n') 246119610Sache { 247136644Sache p = line_end + 1; 248136644Sache /* If we see something we think is a timestamp, continue with this 249136644Sache line. We should check more extensively here... */ 250136644Sache if (HIST_TIMESTAMP_START(p) == 0) 251136644Sache current_line++; 252136644Sache line_start = p; 253119610Sache } 25421308Sache 25521308Sache /* If there are lines left to gobble, then gobble them now. */ 256119610Sache for (line_end = line_start; line_end < bufend; line_end++) 257119610Sache if (*line_end == '\n') 25821308Sache { 259165670Sache /* Change to allow Windows-like \r\n end of line delimiter. */ 260165670Sache if (line_end > line_start && line_end[-1] == '\r') 261165670Sache line_end[-1] = '\0'; 262165670Sache else 263165670Sache *line_end = '\0'; 26421308Sache 265119610Sache if (*line_start) 266136644Sache { 267136644Sache if (HIST_TIMESTAMP_START(line_start) == 0) 268136644Sache { 269136644Sache add_history (line_start); 270136644Sache if (last_ts) 271136644Sache { 272136644Sache add_history_time (last_ts); 273136644Sache last_ts = NULL; 274136644Sache } 275136644Sache } 276136644Sache else 277136644Sache { 278136644Sache last_ts = line_start; 279136644Sache current_line--; 280136644Sache } 281136644Sache } 28221308Sache 28321308Sache current_line++; 28421308Sache 28521308Sache if (current_line >= to) 28621308Sache break; 28721308Sache 28821308Sache line_start = line_end + 1; 28921308Sache } 29021308Sache 29121308Sache FREE (input); 292136644Sache#ifndef HISTORY_USE_MMAP 29321308Sache FREE (buffer); 294119610Sache#else 295119610Sache munmap (buffer, file_size); 296119610Sache#endif 29721308Sache 29821308Sache return (0); 29921308Sache} 30021308Sache 30121308Sache/* Truncate the history file FNAME, leaving only LINES trailing lines. 30275406Sache If FNAME is NULL, then use ~/.history. Returns 0 on success, errno 30375406Sache on failure. */ 30421308Sacheint 30521308Sachehistory_truncate_file (fname, lines) 30675406Sache const char *fname; 30747558Sache int lines; 30821308Sache{ 309136644Sache char *buffer, *filename, *bp, *bp1; /* bp1 == bp+1 */ 31075406Sache int file, chars_read, rv; 31121308Sache struct stat finfo; 31235486Sache size_t file_size; 31321308Sache 31426497Sache buffer = (char *)NULL; 31521308Sache filename = history_filename (fname); 31626497Sache file = open (filename, O_RDONLY|O_BINARY, 0666); 31775406Sache rv = 0; 31821308Sache 31975406Sache /* Don't try to truncate non-regular files. */ 32021308Sache if (file == -1 || fstat (file, &finfo) == -1) 32175406Sache { 32275406Sache rv = errno; 32375406Sache if (file != -1) 32475406Sache close (file); 32575406Sache goto truncate_exit; 32675406Sache } 32721308Sache 32875406Sache if (S_ISREG (finfo.st_mode) == 0) 32975406Sache { 33075406Sache close (file); 33175406Sache#ifdef EFTYPE 33275406Sache rv = EFTYPE; 33375406Sache#else 33475406Sache rv = EINVAL; 33575406Sache#endif 33675406Sache goto truncate_exit; 33775406Sache } 33858310Sache 33935486Sache file_size = (size_t)finfo.st_size; 34035486Sache 34135486Sache /* check for overflow on very large files */ 34235486Sache if (file_size != finfo.st_size || file_size + 1 < file_size) 34335486Sache { 34435486Sache close (file); 34535486Sache#if defined (EFBIG) 34675406Sache rv = errno = EFBIG; 34775406Sache#elif defined (EOVERFLOW) 34875406Sache rv = errno = EOVERFLOW; 34975406Sache#else 35075406Sache rv = errno = EINVAL; 35135486Sache#endif 35235486Sache goto truncate_exit; 35335486Sache } 35435486Sache 355119610Sache buffer = (char *)malloc (file_size + 1); 356119610Sache if (buffer == 0) 357119610Sache { 358119610Sache close (file); 359119610Sache goto truncate_exit; 360119610Sache } 361119610Sache 36235486Sache chars_read = read (file, buffer, file_size); 36321308Sache close (file); 36421308Sache 36521308Sache if (chars_read <= 0) 36675406Sache { 36775406Sache rv = (chars_read < 0) ? errno : 0; 36875406Sache goto truncate_exit; 36975406Sache } 37021308Sache 37121308Sache /* Count backwards from the end of buffer until we have passed 372136644Sache LINES lines. bp1 is set funny initially. But since bp[1] can't 373136644Sache be a comment character (since it's off the end) and *bp can't be 374136644Sache both a newline and the history comment character, it should be OK. */ 375136644Sache for (bp1 = bp = buffer + chars_read - 1; lines && bp > buffer; bp--) 37621308Sache { 377136644Sache if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0) 37821308Sache lines--; 379136644Sache bp1 = bp; 38021308Sache } 38121308Sache 38221308Sache /* If this is the first line, then the file contains exactly the 38321308Sache number of lines we want to truncate to, so we don't need to do 38421308Sache anything. It's the first line if we don't find a newline between 38521308Sache the current value of i and 0. Otherwise, write from the start of 38621308Sache this line until the end of the buffer. */ 387119610Sache for ( ; bp > buffer; bp--) 388136644Sache { 389136644Sache if (*bp == '\n' && HIST_TIMESTAMP_START(bp1) == 0) 390136644Sache { 391136644Sache bp++; 392136644Sache break; 393136644Sache } 394136644Sache bp1 = bp; 395136644Sache } 39621308Sache 39721308Sache /* Write only if there are more lines in the file than we want to 39821308Sache truncate to. */ 399119610Sache if (bp > buffer && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1)) 40021308Sache { 401119610Sache write (file, bp, chars_read - (bp - buffer)); 40247558Sache 40347558Sache#if defined (__BEOS__) 40447558Sache /* BeOS ignores O_TRUNC. */ 405119610Sache ftruncate (file, chars_read - (bp - buffer)); 40647558Sache#endif 40747558Sache 40821308Sache close (file); 40921308Sache } 41021308Sache 41121308Sache truncate_exit: 41221308Sache 41321308Sache FREE (buffer); 41421308Sache 41521308Sache free (filename); 41675406Sache return rv; 41721308Sache} 41821308Sache 41921308Sache/* Workhorse function for writing history. Writes NELEMENT entries 42021308Sache from the history list to FILENAME. OVERWRITE is non-zero if you 42121308Sache wish to replace FILENAME with the entries. */ 42221308Sachestatic int 42321308Sachehistory_do_write (filename, nelements, overwrite) 42475406Sache const char *filename; 42521308Sache int nelements, overwrite; 42621308Sache{ 42721308Sache register int i; 42826497Sache char *output; 42975406Sache int file, mode, rv; 430136644Sache#ifdef HISTORY_USE_MMAP 431119610Sache size_t cursize; 43221308Sache 433119610Sache mode = overwrite ? O_RDWR|O_CREAT|O_TRUNC|O_BINARY : O_RDWR|O_APPEND|O_BINARY; 434119610Sache#else 43526497Sache mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY; 436119610Sache#endif 43726497Sache output = history_filename (filename); 43875406Sache rv = 0; 43921308Sache 44030971Sache if ((file = open (output, mode, 0600)) == -1) 44121308Sache { 44221308Sache FREE (output); 44321308Sache return (errno); 44421308Sache } 44521308Sache 446136644Sache#ifdef HISTORY_USE_MMAP 447119610Sache cursize = overwrite ? 0 : lseek (file, 0, SEEK_END); 448119610Sache#endif 449119610Sache 45021308Sache if (nelements > history_length) 45121308Sache nelements = history_length; 45221308Sache 45321308Sache /* Build a buffer of all the lines to write, and write them in one syscall. 45421308Sache Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */ 45521308Sache { 45621308Sache HIST_ENTRY **the_history; /* local */ 45721308Sache register int j; 45821308Sache int buffer_size; 45921308Sache char *buffer; 46021308Sache 46121308Sache the_history = history_list (); 46221308Sache /* Calculate the total number of bytes to write. */ 46321308Sache for (buffer_size = 0, i = history_length - nelements; i < history_length; i++) 464136644Sache#if 0 465136644Sache buffer_size += 2 + HISTENT_BYTES (the_history[i]); 466136644Sache#else 467136644Sache { 468136644Sache if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0]) 469136644Sache buffer_size += strlen (the_history[i]->timestamp) + 1; 470136644Sache buffer_size += strlen (the_history[i]->line) + 1; 471136644Sache } 472136644Sache#endif 47321308Sache 47421308Sache /* Allocate the buffer, and fill it. */ 475136644Sache#ifdef HISTORY_USE_MMAP 476119610Sache if (ftruncate (file, buffer_size+cursize) == -1) 477119610Sache goto mmap_error; 478119610Sache buffer = (char *)mmap (0, buffer_size, PROT_READ|PROT_WRITE, MAP_WFLAGS, file, cursize); 479119610Sache if ((void *)buffer == MAP_FAILED) 480119610Sache { 481119610Sachemmap_error: 482119610Sache rv = errno; 483119610Sache FREE (output); 484119610Sache close (file); 485119610Sache return rv; 486119610Sache } 487119610Sache#else 488119610Sache buffer = (char *)malloc (buffer_size); 489119610Sache if (buffer == 0) 490119610Sache { 491119610Sache rv = errno; 492119610Sache FREE (output); 493119610Sache close (file); 494119610Sache return rv; 495119610Sache } 496119610Sache#endif 49721308Sache 49821308Sache for (j = 0, i = history_length - nelements; i < history_length; i++) 49921308Sache { 500136644Sache if (history_write_timestamps && the_history[i]->timestamp && the_history[i]->timestamp[0]) 501136644Sache { 502136644Sache strcpy (buffer + j, the_history[i]->timestamp); 503136644Sache j += strlen (the_history[i]->timestamp); 504136644Sache buffer[j++] = '\n'; 505136644Sache } 50621308Sache strcpy (buffer + j, the_history[i]->line); 50721308Sache j += strlen (the_history[i]->line); 50821308Sache buffer[j++] = '\n'; 50921308Sache } 51021308Sache 511136644Sache#ifdef HISTORY_USE_MMAP 512119610Sache if (msync (buffer, buffer_size, 0) != 0 || munmap (buffer, buffer_size) != 0) 513119610Sache rv = errno; 514119610Sache#else 51575406Sache if (write (file, buffer, buffer_size) < 0) 51675406Sache rv = errno; 51721308Sache free (buffer); 518119610Sache#endif 51921308Sache } 52021308Sache 52121308Sache close (file); 52221308Sache 52321308Sache FREE (output); 52421308Sache 52575406Sache return (rv); 52621308Sache} 52721308Sache 52821308Sache/* Append NELEMENT entries to FILENAME. The entries appended are from 52921308Sache the end of the list minus NELEMENTs up to the end of the list. */ 53021308Sacheint 53121308Sacheappend_history (nelements, filename) 53221308Sache int nelements; 53375406Sache const char *filename; 53421308Sache{ 53521308Sache return (history_do_write (filename, nelements, HISTORY_APPEND)); 53621308Sache} 53721308Sache 53821308Sache/* Overwrite FILENAME with the current history. If FILENAME is NULL, 53921308Sache then write the history list to ~/.history. Values returned 54021308Sache are as in read_history ().*/ 54121308Sacheint 54221308Sachewrite_history (filename) 54375406Sache const char *filename; 54421308Sache{ 54521308Sache return (history_do_write (filename, history_length, HISTORY_OVERWRITE)); 54621308Sache} 547