#define READLINE_LIBRARY
#if defined (HAVE_CONFIG_H)
# include <config.h>
#endif
#include <stdio.h>
#include <sys/types.h>
#ifndef _MINIX
# include <sys/file.h>
#endif
#include "posixstat.h"
#include <fcntl.h>
#if defined (HAVE_STDLIB_H)
# include <stdlib.h>
#else
# include "ansi_stdlib.h"
#endif
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#if defined (HAVE_STRING_H)
# include <string.h>
#else
# include <strings.h>
#endif
#if defined (__EMX__) || defined (__CYGWIN__)
# ifndef O_BINARY
# define O_BINARY 0
# endif
#else
# undef O_BINARY
# define O_BINARY 0
#endif
#include <errno.h>
#if !defined (errno)
extern int errno;
#endif
#include "history.h"
#include "histlib.h"
#include "rlshell.h"
#include "xmalloc.h"
static char *
history_filename (filename)
char *filename;
{
char *return_val, *home;
int home_len;
return_val = filename ? savestring (filename) : (char *)NULL;
if (return_val)
return (return_val);
home = get_env_value ("HOME");
if (home == 0)
{
home = ".";
home_len = 1;
}
else
home_len = strlen (home);
return_val = xmalloc (2 + home_len + 8);
strcpy (return_val, home);
return_val[home_len] = '/';
#if defined (__MSDOS__)
strcpy (return_val + home_len + 1, "_history");
#else
strcpy (return_val + home_len + 1, ".history");
#endif
return (return_val);
}
int
read_history (filename)
char *filename;
{
return (read_history_range (filename, 0, -1));
}
int
read_history_range (filename, from, to)
char *filename;
int from, to;
{
register int line_start, line_end;
char *input, *buffer;
int file, current_line, chars_read;
struct stat finfo;
size_t file_size;
int eret;
errno = 0;
buffer = (char *)NULL;
input = history_filename (filename);
file = open (input, O_RDONLY|O_BINARY, 0666);
if ((file < 0) || (fstat (file, &finfo) == -1))
goto error_and_exit;
file_size = (size_t)finfo.st_size;
if (file_size != finfo.st_size || file_size + 1 < file_size)
{
#if defined (EFBIG)
errno = EFBIG;
#else
errno = EIO;
#endif
goto error_and_exit;
}
buffer = xmalloc (file_size + 1);
chars_read = read (file, buffer, file_size);
if (chars_read < 0)
{
error_and_exit:
eret = errno;
if (eret == 0)
eret = EIO;
if (file >= 0)
close (file);
FREE (input);
FREE (buffer);
return (eret);
}
close (file);
if (to < 0)
to = chars_read;
line_start = line_end = current_line = 0;
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;
}
}
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;
}
FREE (input);
FREE (buffer);
return (0);
}
int
history_truncate_file (fname, lines)
char *fname;
int lines;
{
register int i;
int file, chars_read;
char *buffer, *filename;
struct stat finfo;
size_t file_size;
buffer = (char *)NULL;
filename = history_filename (fname);
file = open (filename, O_RDONLY|O_BINARY, 0666);
if (file == -1 || fstat (file, &finfo) == -1)
goto truncate_exit;
if (S_ISREG(finfo.st_mode) == 0)
goto truncate_exit;
file_size = (size_t)finfo.st_size;
if (file_size != finfo.st_size || file_size + 1 < file_size)
{
close (file);
#if defined (EFBIG)
errno = EFBIG;
#endif
goto truncate_exit;
}
buffer = xmalloc (file_size + 1);
chars_read = read (file, buffer, file_size);
close (file);
if (chars_read <= 0)
goto truncate_exit;
for (i = chars_read - 1; lines && i; i--)
{
if (buffer[i] == '\n')
lines--;
}
for ( ; i; i--)
if (buffer[i] == '\n')
{
i++;
break;
}
if (i && ((file = open (filename, O_WRONLY|O_TRUNC|O_BINARY, 0600)) != -1))
{
write (file, buffer + i, chars_read - i);
#if defined (__BEOS__)
ftruncate (file, chars_read - i);
#endif
close (file);
}
truncate_exit:
FREE (buffer);
free (filename);
return 0;
}
static int
history_do_write (filename, nelements, overwrite)
char *filename;
int nelements, overwrite;
{
register int i;
char *output;
int file, mode;
mode = overwrite ? O_WRONLY|O_CREAT|O_TRUNC|O_BINARY : O_WRONLY|O_APPEND|O_BINARY;
output = history_filename (filename);
if ((file = open (output, mode, 0600)) == -1)
{
FREE (output);
return (errno);
}
if (nelements > history_length)
nelements = history_length;
{
HIST_ENTRY **the_history;
register int j;
int buffer_size;
char *buffer;
the_history = history_list ();
for (buffer_size = 0, i = history_length - nelements; i < history_length; i++)
buffer_size += 1 + strlen (the_history[i]->line);
buffer = xmalloc (buffer_size);
for (j = 0, i = history_length - nelements; i < history_length; i++)
{
strcpy (buffer + j, the_history[i]->line);
j += strlen (the_history[i]->line);
buffer[j++] = '\n';
}
write (file, buffer, buffer_size);
free (buffer);
}
close (file);
FREE (output);
return (0);
}
int
append_history (nelements, filename)
int nelements;
char *filename;
{
return (history_do_write (filename, nelements, HISTORY_APPEND));
}
int
write_history (filename)
char *filename;
{
return (history_do_write (filename, history_length, HISTORY_OVERWRITE));
}