From: jt AT boxhill DOT com (Jason Tishler) Subject: Re: Bash termcap and history file 16 Jan 1997 13:11:23 -0800 Approved: cygnus DOT gnu-win32 AT cygnus DOT com Distribution: cygnus Message-ID: <32DE640B.2FD.cygnus.gnu-win32@boxhill.com> References: <32DAA9A6 DOT 68EF AT boxhill DOT com> Reply-To: jt AT boxhill DOT com Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------668461112D3E" X-Mailer: Mozilla 3.0Gold (WinNT; I) Original-To: gnu-win32 Original-CC: richardd AT cix DOT compulink DOT co DOT uk Original-Sender: owner-gnu-win32 AT cygnus DOT com This is a multi-part message in MIME format. --------------668461112D3E Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Jason Tishler wrote: > I am also having the above problems. Has anyone been successful in > getting bash to read their history file on start up? VERSION: ======= Beta 17.1 under NT 3.51 and 4.0. SUMMARY: ======= I found the reason why bash fails to read history files on start up. It has to due with the difference between the end-of-line (EOL) delimiter used in Windows and UNIX. In Windows, EOL is the two character seqence "\r\n"; in UNIX, EOL is one character "\n". When bash reads a history file, it compares the size of the file as reported by fstat(2) to the number of bytes returned by read(2). If they are not equal, then bash will ignore the contents of the history file. The file size reported by fstat(2) includes the "\r" characters in the EOLs. On the other hand, the number of bytes returned by read(2) does not include the "\r" characters because read(2) strips them out from the input. Hence, these quantities will never be equal. (In fact, they always differ by the number of lines in the history file.) Note that the problem I found seems general and may affect other gnu-win32 tools. I'm willing to post my version of bash (~256K) that fixes the history problem to the mailing list if it is appropriate and if people are interested. Sorry, but I don't have a publically accessible ftp site. GORY DETAILS: ==== ======= The following is the pertinent code from bash/lib/readline/history.c: int read_history_range (filename, from, to) ... { ... input = history_filename (filename); file = open (input, O_RDONLY, 0666); if ((file < 0) || (fstat (file, &finfo) == -1)) goto error_and_exit; ... /*X*/ if (read (file, buffer, finfo.st_size) != finfo.st_size) { error_and_exit: ... return (errno); } ... } The line marked /*X*/ above shows where the problem is -- the if statement will never be true. Using the code from history_truncate_file() (in history.c) as a model, I changed read_history_range() to save the number of bytes returned by read(2) in chars_read. Then, I used chars_read instead of finfo.st_size during the parsing of the history file. My version of read_history_range() is attached and the diffs are the following: 561c561 < int file, current_line; --- > int file, current_line, chars_read; 572c572 < if (read (file, buffer, finfo.st_size) != finfo.st_size) --- > if ((chars_read = read (file, buffer, finfo.st_size)) <= 0) 591c591 < to = finfo.st_size; --- > to = chars_read; 597c597 < while (line_start < finfo.st_size && current_line < from) --- > while (line_start < chars_read && current_line < from) 599c599 < for (line_end = line_start; line_end < finfo.st_size; line_end++) --- > for (line_end = line_start; line_end < chars_read; line_end++) 610c610 < for (line_end = line_start; line_end < finfo.st_size; line_end++) --- > for (line_end = line_start; line_end < chars_read; line_end++) As one can see, the above changes were minor. Jason -- Jason Tishler Phone: +1 (212) 989-4455 ext. 120 Box Hill Systems Corporation Fax: +1 (212) 989-6817 161 Avenue of the Americas Email: jt AT boxhill DOT com New York, NY 10013 USA WWW: http://www.boxhill.com --------------668461112D3E Content-Type: text/plain; charset=us-ascii; name="read_history_range" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="read_history_range" int read_history_range (filename, from, to) char *filename; int from, to; { register int line_start, line_end; char *input, *buffer = (char *)NULL; int file, current_line, chars_read; struct stat finfo; input = history_filename (filename); file = open (input, O_RDONLY, 0666); if ((file < 0) || (fstat (file, &finfo) == -1)) goto error_and_exit; buffer = xmalloc ((int)finfo.st_size + 1); if ((chars_read = read (file, buffer, finfo.st_size)) <= 0) { error_and_exit: if (file >= 0) close (file); if (input) free (input); if (buffer) free (buffer); return (errno); } close (file); /* Set TO to larger than end of file if negative. */ if (to < 0) to = chars_read; /* Start at beginning of file, work to end. */ line_start = line_end = current_line = 0; /* Skip lines until we are at FROM. */ while (line_start < chars_read && current_line < from) { for (line_end = line_start; line_end < chars_read; line_end++) if (buffer[line_end] == '\n') { current_line++; line_start = line_end + 1; if (current_line == from) break; } } /* If there are lines left to gobble, then gobble them now. */ for (line_end = line_start; line_end < chars_read; line_end++) if (buffer[line_end] == '\n') { buffer[line_end] = '\0'; if (buffer[line_start]) add_history (buffer + line_start); current_line++; if (current_line >= to) break; line_start = line_end + 1; } if (input) free (input); if (buffer) free (buffer); return (0); } --------------668461112D3E-- - For help on using this list, send a message to "gnu-win32-request AT cygnus DOT com" with one line of text: "help".