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