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 (HAVE_STRING_H) 52 # include <string.h> 53 #else 54 # include <strings.h> 55 #endif /* !HAVE_STRING_H */ 56 57 58 /* If we're compiling for __EMX__ (OS/2) or __CYGWIN__ (cygwin32 environment 59 on win 95/98/nt), we want to open files with O_BINARY mode so that there 60 is no \n -> \r\n conversion performed. On other systems, we don't want to 61 mess around with O_BINARY at all, so we ensure that it's defined to 0. */ 62 #if defined (__EMX__) || defined (__CYGWIN__) 63 # ifndef O_BINARY 64 # define O_BINARY 0 65 # endif 66 #else /* !__EMX__ && !__CYGWIN__ */ 67 # undef O_BINARY 68 # define O_BINARY 0 69 #endif /* !__EMX__ && !__CYGWIN__ */ 70 71 #include <errno.h> 72 #if !defined (errno) 73 extern int errno; 74 #endif /* !errno */ 75 76 #include "history.h" 77 #include "histlib.h" 78 79 #include "rlshell.h" 80 #include "xmalloc.h" 81 82 /* Return the string that should be used in the place of this 83 filename. This only matters when you don't specify the 84 filename to read_history (), or write_history (). */ 85 static char * 86 history_filename (filename) 87 char *filename; 88 { 89 char *return_val, *home; 90 int home_len; 91 char dot; 92 93 return_val = filename ? savestring (filename) : (char *)NULL; 94 95 if (return_val) 96 return (return_val); 97 98 home = get_env_value ("HOME"); 99 100 if (home == 0 || *home == '\0') { 101 errno = ENOENT; 102 return (NULL); 103 } 104 home_len = strlen (home); 105 106 #if defined (__MSDOS__) 107 dot = '_'; 108 #else 109 dot = '.'; 110 #endif 111 if (asprintf(&return_val, "%s/%c%s", home, dot, "history") == -1) 112 memory_error_and_abort("asprintf"); 113 return (return_val); 114 } 115 116 /* Add the contents of FILENAME to the history list, a line at a time. 117 If FILENAME is NULL, then read from ~/.history. Returns 0 if 118 successful, or errno if not. */ 119 int 120 read_history (filename) 121 char *filename; 122 { 123 return (read_history_range (filename, 0, -1)); 124 } 125 126 /* Read a range of lines from FILENAME, adding them to the history list. 127 Start reading at the FROM'th line and end at the TO'th. If FROM 128 is zero, start at the beginning. If TO is less than FROM, read 129 until the end of the file. If FILENAME is NULL, then read from 130 ~/.history. Returns 0 if successful, or errno if not. */ 131 int 132 read_history_range (filename, from, to) 133 char *filename; 134 int from, to; 135 { 136 register int line_start, line_end; 137 char *input, *buffer; 138 int file, current_line, chars_read; 139 struct stat finfo; 140 size_t file_size; 141 142 buffer = (char *)NULL; 143 if ((input = history_filename (filename))) 144 file = open (input, O_RDONLY|O_BINARY, 0666); 145 else 146 file = -1; 147 148 if ((file < 0) || (fstat (file, &finfo) == -1)) 149 goto error_and_exit; 150 151 file_size = (size_t)finfo.st_size; 152 153 /* check for overflow on very large files */ 154 if (file_size != finfo.st_size || file_size + 1 < file_size) 155 { 156 #if defined (EFBIG) 157 errno = EFBIG; 158 #endif 159 goto error_and_exit; 160 } 161 162 buffer = xmalloc (file_size + 1); 163 164 chars_read = read (file, buffer, file_size); 165 if (chars_read < 0) 166 { 167 error_and_exit: 168 if (file >= 0) 169 close (file); 170 171 FREE (input); 172 FREE (buffer); 173 174 return (errno); 175 } 176 177 close (file); 178 179 /* Set TO to larger than end of file if negative. */ 180 if (to < 0) 181 to = chars_read; 182 183 /* Start at beginning of file, work to end. */ 184 line_start = line_end = current_line = 0; 185 186 /* Skip lines until we are at FROM. */ 187 while (line_start < chars_read && current_line < from) 188 { 189 for (line_end = line_start; line_end < chars_read; line_end++) 190 if (buffer[line_end] == '\n') 191 { 192 current_line++; 193 line_start = line_end + 1; 194 if (current_line == from) 195 break; 196 } 197 } 198 199 /* If there are lines left to gobble, then gobble them now. */ 200 for (line_end = line_start; line_end < chars_read; line_end++) 201 if (buffer[line_end] == '\n') 202 { 203 buffer[line_end] = '\0'; 204 205 if (buffer[line_start]) 206 add_history (buffer + line_start); 207 208 current_line++; 209 210 if (current_line >= to) 211 break; 212 213 line_start = line_end + 1; 214 } 215 216 FREE (input); 217 FREE (buffer); 218 219 return (0); 220 } 221 222 /* Truncate the history file FNAME, leaving only LINES trailing lines. 223 If FNAME is NULL, then use ~/.history. */ 224 int 225 history_truncate_file (fname, lines) 226 char *fname; 227 int lines; 228 { 229 register int i; 230 int file, chars_read; 231 char *buffer, *filename; 232 struct stat finfo; 233 size_t file_size; 234 235 buffer = (char *)NULL; 236 if ((filename = history_filename (fname))) 237 file = open (filename, O_RDONLY|O_BINARY, 0666); 238 else 239 file = -1; 240 241 if (file == -1 || fstat (file, &finfo) == -1) 242 goto truncate_exit; 243 244 /* Don't try to truncate non-regular files. */ 245 if (S_ISREG(finfo.st_mode) == 0) 246 goto truncate_exit; 247 248 file_size = (size_t)finfo.st_size; 249 250 /* check for overflow on very large files */ 251 if (file_size != finfo.st_size || file_size + 1 < file_size) 252 { 253 close (file); 254 #if defined (EFBIG) 255 errno = EFBIG; 256 #endif 257 goto truncate_exit; 258 } 259 260 buffer = xmalloc (file_size + 1); 261 chars_read = read (file, buffer, file_size); 262 close (file); 263 264 if (chars_read <= 0) 265 goto truncate_exit; 266 267 /* Count backwards from the end of buffer until we have passed 268 LINES lines. */ 269 for (i = chars_read - 1; lines && i; i--) 270 { 271 if (buffer[i] == '\n') 272 lines--; 273 } 274 275 /* If this is the first line, then the file contains exactly the 276 number of lines we want to truncate to, so we don't need to do 277 anything. It's the first line if we don't find a newline between 278 the current value of i and 0. Otherwise, write from the start of 279 this line until the end of the buffer. */ 280 for ( ; i; i--) 281 if (buffer[i] == '\n') 282 { 283 i++; 284 break; 285 } 286 287 /* Write only if there are more lines in the file than we want to 288 truncate to. */ 289 if (i && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1)) 290 { 291 write (file, buffer + i, chars_read - i); 292 293 #if defined (__BEOS__) 294 /* BeOS ignores O_TRUNC. */ 295 ftruncate (file, chars_read - i); 296 #endif 297 298 close (file); 299 } 300 301 truncate_exit: 302 303 FREE (buffer); 304 305 free (filename); 306 return 0; 307 } 308 309 /* Workhorse function for writing history. Writes NELEMENT entries 310 from the history list to FILENAME. OVERWRITE is non-zero if you 311 wish to replace FILENAME with the entries. */ 312 static int 313 history_do_write (filename, nelements, overwrite) 314 char *filename; 315 int nelements, overwrite; 316 { 317 register int i; 318 char *output; 319 int file, mode; 320 321 mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY; 322 output = history_filename (filename); 323 324 if (!output || (file = open (output, mode, 0600)) == -1) 325 { 326 FREE (output); 327 return (errno); 328 } 329 330 if (nelements > history_length) 331 nelements = history_length; 332 333 /* Build a buffer of all the lines to write, and write them in one syscall. 334 Suggested by Peter Ho (peter@robosts.oxford.ac.uk). */ 335 { 336 HIST_ENTRY **the_history; /* local */ 337 int buffer_size; 338 char *buffer; 339 340 the_history = history_list (); 341 /* Calculate the total number of bytes to write. */ 342 for (buffer_size = 1, i = history_length - nelements; i < history_length; i++) 343 buffer_size += 1 + strlen (the_history[i]->line); 344 345 /* Allocate the buffer, and fill it. */ 346 buffer = xmalloc (buffer_size); 347 buffer[0] = '\0'; 348 349 for (i = history_length - nelements; i < history_length; i++) 350 { 351 strlcat (buffer, the_history[i]->line, buffer_size); 352 strlcat (buffer, "\n", buffer_size); 353 } 354 355 write (file, buffer, buffer_size - 1); 356 free (buffer); 357 } 358 359 close (file); 360 361 FREE (output); 362 363 return (0); 364 } 365 366 /* Append NELEMENT entries to FILENAME. The entries appended are from 367 the end of the list minus NELEMENTs up to the end of the list. */ 368 int 369 append_history (nelements, filename) 370 int nelements; 371 char *filename; 372 { 373 return (history_do_write (filename, nelements, HISTORY_APPEND)); 374 } 375 376 /* Overwrite FILENAME with the current history. If FILENAME is NULL, 377 then write the history list to ~/.history. Values returned 378 are as in read_history ().*/ 379 int 380 write_history (filename) 381 char *filename; 382 { 383 return (history_do_write (filename, history_length, HISTORY_OVERWRITE)); 384 } 385