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