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 #ifndef _MINIX 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) 87 extern 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 (). */ 99 static char * 100 history_filename (filename) 101 const char *filename; 102 { 103 char *return_val; 104 const char *home; 105 int home_len; 106 char dot; 107 108 return_val = filename ? savestring (filename) : (char *)NULL; 109 110 if (return_val) 111 return (return_val); 112 113 home = sh_get_env_value ("HOME"); 114 115 if (home == 0 || *home == '\0') { 116 errno = ENOENT; 117 return (NULL); 118 } 119 home_len = strlen (home); 120 121 #if defined (__MSDOS__) 122 dot = '_'; 123 #else 124 dot = '.'; 125 #endif 126 if (asprintf(&return_val, "%s/%c%s", home, dot, "history") == -1) 127 memory_error_and_abort("asprintf"); 128 return (return_val); 129 } 130 131 /* Add the contents of FILENAME to the history list, a line at a time. 132 If FILENAME is NULL, then read from ~/.history. Returns 0 if 133 successful, or errno if not. */ 134 int 135 read_history (filename) 136 const char *filename; 137 { 138 return (read_history_range (filename, 0, -1)); 139 } 140 141 /* Read a range of lines from FILENAME, adding them to the history list. 142 Start reading at the FROM'th line and end at the TO'th. If FROM 143 is zero, start at the beginning. If TO is less than FROM, read 144 until the end of the file. If FILENAME is NULL, then read from 145 ~/.history. Returns 0 if successful, or errno if not. */ 146 int 147 read_history_range (filename, from, to) 148 const char *filename; 149 int from, to; 150 { 151 register char *line_start, *line_end; 152 char *input, *buffer, *bufend; 153 int file, current_line, chars_read; 154 struct stat finfo; 155 size_t file_size; 156 157 buffer = (char *)NULL; 158 if ((input = history_filename (filename))) 159 file = open (input, O_RDONLY|O_BINARY, 0666); 160 else 161 file = -1; 162 163 if ((file < 0) || (fstat (file, &finfo) == -1)) 164 goto error_and_exit; 165 166 file_size = (size_t)finfo.st_size; 167 168 /* check for overflow on very large files */ 169 if (file_size != finfo.st_size || file_size + 1 < file_size) 170 { 171 #if defined (EFBIG) 172 errno = EFBIG; 173 #elif defined (EOVERFLOW) 174 errno = EOVERFLOW; 175 #endif 176 goto error_and_exit; 177 } 178 179 #ifdef HAVE_MMAP 180 /* We map read/write and private so we can change newlines to NULs without 181 affecting the underlying object. */ 182 buffer = (char *)mmap (0, file_size, PROT_READ|PROT_WRITE, MAP_RFLAGS, file, 0); 183 if ((void *)buffer == MAP_FAILED) 184 goto error_and_exit; 185 chars_read = file_size; 186 #else 187 buffer = (char *)malloc (file_size + 1); 188 if (buffer == 0) 189 goto error_and_exit; 190 191 chars_read = read (file, buffer, file_size); 192 #endif 193 if (chars_read < 0) 194 { 195 error_and_exit: 196 chars_read = errno; 197 if (file >= 0) 198 close (file); 199 200 FREE (input); 201 #ifndef HAVE_MMAP 202 FREE (buffer); 203 #endif 204 205 return (chars_read); 206 } 207 208 close (file); 209 210 /* Set TO to larger than end of file if negative. */ 211 if (to < 0) 212 to = chars_read; 213 214 /* Start at beginning of file, work to end. */ 215 bufend = buffer + chars_read; 216 current_line = 0; 217 218 /* Skip lines until we are at FROM. */ 219 for (line_start = line_end = buffer; line_end < bufend && current_line < from; line_end++) 220 if (*line_end == '\n') 221 { 222 current_line++; 223 line_start = line_end + 1; 224 } 225 226 /* If there are lines left to gobble, then gobble them now. */ 227 for (line_end = line_start; line_end < bufend; line_end++) 228 if (*line_end == '\n') 229 { 230 *line_end = '\0'; 231 232 if (*line_start) 233 add_history (line_start); 234 235 current_line++; 236 237 if (current_line >= to) 238 break; 239 240 line_start = line_end + 1; 241 } 242 243 FREE (input); 244 #ifndef HAVE_MMAP 245 FREE (buffer); 246 #else 247 munmap (buffer, file_size); 248 #endif 249 250 return (0); 251 } 252 253 /* Truncate the history file FNAME, leaving only LINES trailing lines. 254 If FNAME is NULL, then use ~/.history. Returns 0 on success, errno 255 on failure. */ 256 int 257 history_truncate_file (fname, lines) 258 const char *fname; 259 int lines; 260 { 261 char *buffer, *filename, *bp; 262 int file, chars_read, rv; 263 struct stat finfo; 264 size_t file_size; 265 266 buffer = (char *)NULL; 267 if ((filename = history_filename (fname))) 268 file = open (filename, O_RDONLY|O_BINARY, 0666); 269 else 270 file = -1; 271 rv = 0; 272 273 /* Don't try to truncate non-regular files. */ 274 if (file == -1 || fstat (file, &finfo) == -1) 275 { 276 rv = errno; 277 if (file != -1) 278 close (file); 279 goto truncate_exit; 280 } 281 282 if (S_ISREG (finfo.st_mode) == 0) 283 { 284 close (file); 285 #ifdef EFTYPE 286 rv = EFTYPE; 287 #else 288 rv = EINVAL; 289 #endif 290 goto truncate_exit; 291 } 292 293 file_size = (size_t)finfo.st_size; 294 295 /* check for overflow on very large files */ 296 if (file_size != finfo.st_size || file_size + 1 < file_size) 297 { 298 close (file); 299 #if defined (EFBIG) 300 rv = errno = EFBIG; 301 #elif defined (EOVERFLOW) 302 rv = errno = EOVERFLOW; 303 #else 304 rv = errno = EINVAL; 305 #endif 306 goto truncate_exit; 307 } 308 309 buffer = (char *)malloc (file_size + 1); 310 if (buffer == 0) 311 { 312 close (file); 313 goto truncate_exit; 314 } 315 316 chars_read = read (file, buffer, file_size); 317 close (file); 318 319 if (chars_read <= 0) 320 { 321 rv = (chars_read < 0) ? errno : 0; 322 goto truncate_exit; 323 } 324 325 /* Count backwards from the end of buffer until we have passed 326 LINES lines. */ 327 for (bp = buffer + chars_read - 1; lines && bp > buffer; bp--) 328 { 329 if (*bp == '\n') 330 lines--; 331 } 332 333 /* If this is the first line, then the file contains exactly the 334 number of lines we want to truncate to, so we don't need to do 335 anything. It's the first line if we don't find a newline between 336 the current value of i and 0. Otherwise, write from the start of 337 this line until the end of the buffer. */ 338 for ( ; bp > buffer; bp--) 339 if (*bp == '\n') 340 { 341 bp++; 342 break; 343 } 344 345 /* Write only if there are more lines in the file than we want to 346 truncate to. */ 347 if (bp > buffer && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1)) 348 { 349 write (file, bp, chars_read - (bp - buffer)); 350 351 #if defined (__BEOS__) 352 /* BeOS ignores O_TRUNC. */ 353 ftruncate (file, chars_read - (bp - buffer)); 354 #endif 355 356 close (file); 357 } 358 359 truncate_exit: 360 361 FREE (buffer); 362 363 free (filename); 364 return rv; 365 } 366 367 /* Workhorse function for writing history. Writes NELEMENT entries 368 from the history list to FILENAME. OVERWRITE is non-zero if you 369 wish to replace FILENAME with the entries. */ 370 static int 371 history_do_write (filename, nelements, overwrite) 372 const char *filename; 373 int nelements, overwrite; 374 { 375 register int i; 376 char *output; 377 int file, mode, rv; 378 #ifdef HAVE_MMAP 379 size_t cursize; 380 #endif 381 382 #ifdef HAVE_MMAP 383 mode = overwrite ? O_RDWR|O_CREAT|O_TRUNC|O_BINARY : O_RDWR|O_APPEND|O_BINARY; 384 #else 385 mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY; 386 #endif 387 output = history_filename (filename); 388 rv = 0; 389 390 if (!output || (file = open (output, mode, 0600)) == -1) 391 { 392 FREE (output); 393 return (errno); 394 } 395 396 #ifdef HAVE_MMAP 397 cursize = overwrite ? 0 : lseek (file, 0, SEEK_END); 398 #endif 399 400 if (nelements > history_length) 401 nelements = history_length; 402 403 /* Build a buffer of all the lines to write, and write them in one syscall. 404 Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */ 405 { 406 HIST_ENTRY **the_history; /* local */ 407 int buffer_size; 408 char *buffer; 409 410 the_history = history_list (); 411 /* Calculate the total number of bytes to write. */ 412 for (buffer_size = 1, i = history_length - nelements; i < history_length; i++) 413 buffer_size += 1 + strlen (the_history[i]->line); 414 415 /* Allocate the buffer, and fill it. */ 416 #ifdef HAVE_MMAP 417 if (ftruncate (file, buffer_size+cursize) == -1) 418 goto mmap_error; 419 buffer = (char *)mmap (0, buffer_size, PROT_READ|PROT_WRITE, MAP_WFLAGS, file, cursize); 420 if ((void *)buffer == MAP_FAILED) 421 { 422 mmap_error: 423 rv = errno; 424 FREE (output); 425 close (file); 426 return rv; 427 } 428 #else 429 buffer = (char *)malloc (buffer_size); 430 if (buffer == 0) 431 { 432 rv = errno; 433 FREE (output); 434 close (file); 435 return rv; 436 } 437 #endif 438 buffer[0] = '\0'; 439 440 for (i = history_length - nelements; i < history_length; i++) 441 { 442 strlcat (buffer, the_history[i]->line, buffer_size); 443 strlcat (buffer, "\n", buffer_size); 444 } 445 446 #ifdef HAVE_MMAP 447 if (msync (buffer, buffer_size, 0) != 0 || munmap (buffer, buffer_size) != 0) 448 rv = errno; 449 #else 450 if (write (file, buffer, buffer_size - 1) < 0) 451 rv = errno; 452 free (buffer); 453 #endif 454 } 455 456 close (file); 457 458 FREE (output); 459 460 return (rv); 461 } 462 463 /* Append NELEMENT entries to FILENAME. The entries appended are from 464 the end of the list minus NELEMENTs up to the end of the list. */ 465 int 466 append_history (nelements, filename) 467 int nelements; 468 const char *filename; 469 { 470 return (history_do_write (filename, nelements, HISTORY_APPEND)); 471 } 472 473 /* Overwrite FILENAME with the current history. If FILENAME is NULL, 474 then write the history list to ~/.history. Values returned 475 are as in read_history ().*/ 476 int 477 write_history (filename) 478 const char *filename; 479 { 480 return (history_do_write (filename, history_length, HISTORY_OVERWRITE)); 481 } 482