* view.c (struct WView): Renamed some variables to reflect the

actual use. (view_growbuf_read_until): Moved the growing buffer
	handling out of get_byte.
	* view.c: Cleaned up the code. Added error handling for the
	growing buffer case.
This commit is contained in:
Roland Illig 2004-12-02 17:13:39 +00:00
parent a6c81a0d7a
commit 91a4d7e764
2 changed files with 131 additions and 97 deletions

View File

@ -1,3 +1,11 @@
2004-12-02 Roland Illig <roland.illig@gmx.de>
* view.c (struct WView): Renamed some variables to reflect the
actual use. (view_growbuf_read_until): Moved the growing buffer
handling out of get_byte.
* view.c: Cleaned up the code. Added error handling for the
growing buffer case.
2004-12-02 Andrew V. Samoilov <sav@bcs.zp.ua>
* file.c (make_symlink): Constify r.

View File

@ -6,6 +6,7 @@
1996 Joseph M. Hinkle
1997 Norbert Warmuth
1998 Pavel Machek
2004 Roland Illig <roland.illig@gmx.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -79,6 +80,7 @@
/* Offset in bytes into a file */
typedef unsigned long offset_type;
#define INVALID_OFFSET ((offset_type) -1)
#define OFFSETTYPE_MAX (~((offset_type) 0))
/* A width or height on the screen */
typedef unsigned int screen_dimen;
@ -99,13 +101,15 @@ struct WView {
int have_frame;
unsigned char *data; /* Memory area for the file to be viewed */
size_t datasize; /* Number of bytes in the data */
/* view_update_last_byte() must be called after assignment to datasize */
/* File information */
int file; /* File descriptor (for mmap and munmap) */
FILE *stdfile; /* Stdio struct for reading file in parts */
int reading_pipe; /* Flag: Reading from pipe(use popen/pclose) */
offset_type bytes_read; /* How much of file is read */
int mmapping; /* Did we use mmap on the file? */
size_t mmappedsize; /* Number of bytes that are mmapped; used only for munmap() */
/* Display information */
offset_type last; /* Last byte shown */
@ -137,7 +141,10 @@ struct WView {
int growing_buffer; /* Use the growing buffers? */
char **block_ptr; /* Pointer to the block pointers */
int blocks; /* The number of blocks in *block_ptr */
size_t growbuf_lastindex; /* Number of bytes in the last page of the
growing buffer */
/* view_update_last_byte() must be called after assignment to
growing_buffer, blocks, growbuf_lastindex */
/* Search variables */
offset_type search_start; /* First character to start searching from */
@ -159,9 +166,21 @@ struct WView {
* -1 view previous file
* 1 view next file
*/
struct stat s; /* stat for file */
};
static void view_update_last_byte (WView *view)
{
if (view->growing_buffer) {
if (view->blocks == 0)
view->last_byte = 0;
else
view->last_byte = ((offset_type) view->blocks - 1)
* VIEW_PAGE_SIZE + view->growbuf_lastindex;
} else
view->last_byte = view->datasize;
view->bottom_first = INVALID_OFFSET;
}
static void view_move_cursor_to_eol(WView *view)
{
offset_type last_line = (view->last_byte - 1) / view->bytes_per_line;
@ -227,7 +246,7 @@ free_file (WView *view)
#ifdef HAVE_MMAP
if (view->mmapping) {
mc_munmap (view->data, view->s.st_size);
mc_munmap (view->data, view->mmappedsize);
close_view_file (view);
} else
#endif /* HAVE_MMAP */
@ -280,56 +299,67 @@ view_done (WView *view)
static void view_hook (void *);
/* Copies the output from the pipe to the growing buffer, until either
* the end-of-pipe is reached or the interval [0..ofs) of the growing
* buffer is completely filled. */
static void
view_growbuf_read_until (WView *view, offset_type ofs)
{
ssize_t nread;
unsigned char *p;
size_t bytesfree;
/* g_assert (view->growing_buffer, NULL); */
while (view->last_byte < ofs) {
if (view->blocks == 0 || view->growbuf_lastindex == VIEW_PAGE_SIZE) {
char *newblock = g_try_malloc (VIEW_PAGE_SIZE);
char **newblocks = g_try_malloc (sizeof (char *) * (view->blocks + 1));
if (!newblock || !newblocks) {
g_free (newblock);
return;
}
memcpy (newblocks, view->block_ptr, sizeof (char *) * view->blocks);
g_free (view->block_ptr);
view->block_ptr = newblocks;
view->block_ptr[view->blocks++] = newblock;
view->growbuf_lastindex = 0;
view_update_last_byte (view);
}
p = view->block_ptr[view->blocks - 1] + view->growbuf_lastindex;
bytesfree = VIEW_PAGE_SIZE - view->growbuf_lastindex;
if (view->stdfile != NULL)
nread = fread (p, 1, bytesfree, view->stdfile);
else
nread = mc_read (view->file, p, bytesfree);
if (nread == -1 || nread == 0)
return;
view->growbuf_lastindex += nread;
view_update_last_byte (view);
}
}
static int
get_byte (WView *view, unsigned int byte_index)
{
int page = byte_index / VIEW_PAGE_SIZE + 1;
int offset = byte_index % VIEW_PAGE_SIZE;
int i, n;
if (view->growing_buffer) {
if (page > view->blocks) {
view->block_ptr = g_realloc (view->block_ptr,
page * sizeof (char *));
for (i = view->blocks; i < page; i++) {
char *p = g_try_malloc (VIEW_PAGE_SIZE);
view->block_ptr[i] = p;
if (!p)
return '\n';
if (view->stdfile != NULL)
n = fread (p, 1, VIEW_PAGE_SIZE, view->stdfile);
else
n = mc_read (view->file, p, VIEW_PAGE_SIZE);
/*
* FIXME: Errors are ignored at this point
* Also should report preliminary EOF
*/
if (n != -1)
view->bytes_read += n;
if (view->s.st_size < view->bytes_read) {
view->bottom_first = INVALID_OFFSET; /* Invalidate cache */
view->s.st_size = view->bytes_read;
view->last_byte = view->bytes_read;
if (view->reading_pipe)
view->last_byte = view->first + view->bytes_read;
}
/* To force loading the next page */
if (n == VIEW_PAGE_SIZE && view->reading_pipe) {
view->last_byte++;
}
}
view->blocks = page;
size_t pageno = byte_index / VIEW_PAGE_SIZE;
size_t pageindex = byte_index % VIEW_PAGE_SIZE;
view_growbuf_read_until (view, byte_index + 1);
if (view->blocks == 0)
return -1;
if (pageno < view->blocks - 1)
return view->block_ptr[pageno][pageindex];
if (pageno == view->blocks - 1 && pageindex < view->growbuf_lastindex)
return view->block_ptr[pageno][pageindex];
return -1;
}
if (byte_index >= view->bytes_read) {
return -1;
} else
return view->block_ptr[page - 1][offset];
} else {
if (byte_index >= view->last_byte)
return -1;
else
return view->data[byte_index];
}
/* g_assert (view->data != NULL); */
if (byte_index < view->datasize)
return view->data[byte_index];
return -1;
}
static void
@ -495,8 +525,9 @@ set_view_init_error (WView *view, const char *msg)
view->first = 0;
view->last_byte = 0;
if (msg) {
view->bytes_read = strlen (msg);
return g_strdup (msg);
view->datasize = strlen (msg);
view_update_last_byte (view);
return g_strdup (msg);
}
return NULL;
}
@ -508,10 +539,13 @@ init_growing_view (WView *view, const char *name, const char *filename)
const char *err_msg = NULL;
view->growing_buffer = 1;
view->block_ptr = NULL;
view->blocks = 0;
view->growbuf_lastindex = 0; /* unused */
view_update_last_byte (view);
if (name) {
view->reading_pipe = 1;
view->s.st_size = 0;
open_error_pipe ();
if ((view->stdfile = popen (name, "r")) == NULL) {
@ -522,8 +556,8 @@ init_growing_view (WView *view, const char *name, const char *filename)
}
/* First, check if filter produced any output */
get_byte (view, 0);
if (view->bytes_read <= 0) {
view_growbuf_read_until (view, 1);
if (view->last_byte == 0) {
pclose (view->stdfile);
view->stdfile = NULL;
/* Avoid two messages. Message from stderr has priority. */
@ -546,26 +580,28 @@ init_growing_view (WView *view, const char *name, const char *filename)
error message instead of the file buffer (quick_view feature).
*/
static char *
load_view_file (WView *view, int fd)
load_view_file (WView *view, int fd, const struct stat *st)
{
view->file = fd;
if (view->s.st_size == 0) {
if (st->st_size == 0) {
/* Must be one of those nice files that grow (/proc) */
close_view_file (view);
return init_growing_view (view, 0, view->filename);
}
#ifdef HAVE_MMAP
if ((size_t) view->s.st_size == view->s.st_size)
view->data = mc_mmap (0, view->s.st_size, PROT_READ,
MAP_FILE | MAP_SHARED, view->file, 0);
if ((size_t) st->st_size == st->st_size)
view->data = mc_mmap (0, st->st_size, PROT_READ,
MAP_FILE | MAP_SHARED, view->file, 0);
else
view->data = (caddr_t) -1;
if ((caddr_t) view->data != (caddr_t) - 1) {
/* mmap worked */
view->first = 0;
view->bytes_read = view->s.st_size;
view->mmappedsize = st->st_size;
view->datasize = st->st_size;
view->mmapping = 1;
view_update_last_byte (view);
return NULL;
}
#endif /* HAVE_MMAP */
@ -575,20 +611,21 @@ load_view_file (WView *view, int fd)
* for any reason, so we use this as fallback (pavel@ucw.cz) */
/* Make sure view->s.st_size is not truncated when passed to g_malloc */
if ((gulong) view->s.st_size == view->s.st_size)
view->data = (unsigned char *) g_try_malloc ((gulong) view->s.st_size);
if ((gulong) st->st_size == st->st_size)
view->data = (unsigned char *) g_try_malloc ((gulong) st->st_size);
else
view->data = NULL;
if (view->data == NULL || mc_lseek (view->file, 0, SEEK_SET) != 0
|| mc_read (view->file, view->data,
view->s.st_size) != view->s.st_size) {
st->st_size) != st->st_size) {
g_free (view->data);
close_view_file (view);
return init_growing_view (view, 0, view->filename);
}
view->first = 0;
view->bytes_read = view->s.st_size;
view->datasize = st->st_size;
view_update_last_byte (view);
return NULL;
}
@ -601,23 +638,24 @@ do_view_init (WView *view, const char *_command, const char *_file,
int i, type;
int fd = -1;
char tmp[BUF_MEDIUM];
struct stat st;
if (view->view_active)
view_done (view);
/* Set up the state */
view->block_ptr = 0;
view->data = NULL;
view->datasize = 0;
view->growing_buffer = 0;
view->reading_pipe = 0;
view->mmapping = 0;
view->blocks = 0;
view->block_ptr = 0;
view->first = view->bytes_read = 0;
view->last_byte = 0;
view->block_ptr = NULL;
view->first = 0;
view->filename = g_strdup (_file);
view->command = 0;
view->last = view->first + ((LINES - 2) * view->bytes_per_line);
view_update_last_byte (view);
/* Clear the markers */
view->marker = 0;
@ -642,7 +680,7 @@ do_view_init (WView *view, const char *_command, const char *_file,
}
/* Make sure we are working with a regular file */
if (mc_fstat (fd, &view->s) == -1) {
if (mc_fstat (fd, &st) == -1) {
mc_close (fd);
g_snprintf (tmp, sizeof (tmp), _(" Cannot stat \"%s\"\n %s "),
_file, unix_error_string (errno));
@ -650,7 +688,7 @@ do_view_init (WView *view, const char *_command, const char *_file,
goto finish;
}
if (!S_ISREG (view->s.st_mode)) {
if (!S_ISREG (st.st_mode)) {
mc_close (fd);
g_snprintf (tmp, sizeof (tmp),
_(" Cannot view: not a regular file "));
@ -673,7 +711,7 @@ do_view_init (WView *view, const char *_command, const char *_file,
g_strconcat (_file, decompress_extension (type), (char *) NULL);
}
error = load_view_file (view, fd);
error = load_view_file (view, fd, &st);
}
finish:
@ -699,10 +737,10 @@ do_view_init (WView *view, const char *_command, const char *_file,
/* Special case: The data points to the error message */
if (error) {
view->data = error;
view->datasize = strlen (error);
view_update_last_byte (view);
view->file = -1;
view->s.st_size = view->bytes_read = strlen (view->data);
}
view->last_byte = view->first + view->s.st_size;
if (start_line > 1 && !error) {
int saved_wrap_mode = view->wrap_mode;
@ -759,14 +797,12 @@ view_percent (WView *view, int p, int w, gboolean update_gui)
{
int percent;
percent = (view->s.st_size == 0
|| view->last_byte == view->last) ? 100 : (p >
(INT_MAX /
100) ? p /
(view->s.
st_size /
100) : p * 100 /
view->s.st_size);
if (view->last_byte == 0 || view->last_byte == view->last)
percent = 100;
else if (p > (INT_MAX / 100))
percent = p / (view->last_byte / 100);
else
percent = p * 100 / view->last_byte;
#if 0
percent = view->s.st_size == 0 ? 100 :
@ -813,7 +849,7 @@ view_status (WView *view, gboolean update_gui)
}
if (w > 62) {
widget_move (view, view->have_frame, 43 + view->have_frame);
printw (const_cast(char *, _("%s bytes")), size_trunc (view->s.st_size));
printw (const_cast(char *, _("%s bytes")), size_trunc (view->last_byte));
}
if (w > 70) {
printw (" ");
@ -1068,10 +1104,8 @@ display (WView *view)
}
}
} else {
if (view->growing_buffer && from == view->last_byte)
get_byte (view, from);
for (; row < height && from < view->last_byte; from++) {
c = get_byte (view, from);
/* the get_byte() call below might modify view->last_byte */
for (; row < height && ((void) (c = get_byte (view, from)), from < view->last_byte); from++) {
if ((c == '\n') || (col >= width && view->wrap_mode)) {
col = frame_shift;
row++;
@ -1384,15 +1418,8 @@ get_bottom_first (WView *view, int do_not_cache, int really)
return view->bottom_first;
/* Force loading */
if (view->growing_buffer) {
offset_type old_last_byte;
old_last_byte = INVALID_OFFSET;
while (old_last_byte != view->last_byte) {
old_last_byte = view->last_byte;
get_byte (view, view->last_byte + VIEW_PAGE_SIZE);
}
}
if (view->growing_buffer)
view_growbuf_read_until (view, OFFSETTYPE_MAX);
bottom_first = move_backward2 (view, view->last_byte, vheight - 1);
@ -1609,7 +1636,7 @@ static offset_type update_activate;
static void
search_update_steps (WView *view)
{
if (view->s.st_size)
if (view->last_byte != 0)
update_steps = 40000;
else /* viewing a data stream, not a file */
update_steps = view->last_byte / 100;
@ -2784,7 +2811,6 @@ view_new (int y, int x, int cols, int lines, int is_panel)
view->viewer_magic_flag = default_magic_flag;
view->viewer_nroff_flag = default_nroff_flag;
view->have_frame = is_panel;
view->last_byte = -1;
view->wrap_mode = global_wrap_mode;
widget_want_cursor (view->widget, 0);