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