Split file src/keybind.[ch] to lib/keybind.[ch] and src/keybind-defaults.[ch].
[midnight-commander.git] / src / viewer / growbuf.c
blobfb54bc8fca07caf75f394fbe3e9935396436f860
1 /*
2 Internal file viewer for the Midnight Commander
3 Function for work with growing bufers
5 Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
6 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
8 Written by: 1994, 1995, 1998 Miguel de Icaza
9 1994, 1995 Janne Kukonlehto
10 1995 Jakub Jelinek
11 1996 Joseph M. Hinkle
12 1997 Norbert Warmuth
13 1998 Pavel Machek
14 2004 Roland Illig <roland.illig@gmx.de>
15 2005 Roland Illig <roland.illig@gmx.de>
16 2009 Slava Zanko <slavazanko@google.com>
17 2009 Andrew Borodin <aborodin@vmail.ru>
18 2009 Ilia Maslakov <il.smind@gmail.com>
20 This file is part of the Midnight Commander.
22 The Midnight Commander is free software; you can redistribute it
23 and/or modify it under the terms of the GNU General Public License as
24 published by the Free Software Foundation; either version 2 of the
25 License, or (at your option) any later version.
27 The Midnight Commander is distributed in the hope that it will be
28 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
29 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
30 General Public License for more details.
32 You should have received a copy of the GNU General Public License
33 along with this program; if not, write to the Free Software
34 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
35 MA 02110-1301, USA.
38 #include <config.h>
39 #include <errno.h>
41 #include "lib/global.h"
42 #include "lib/vfs/mc-vfs/vfs.h"
43 #include "lib/util.h"
44 #include "lib/widget.h" /* D_NORMAL */
46 #include "internal.h"
48 /* Block size for reading files in parts */
49 #define VIEW_PAGE_SIZE ((size_t) 8192)
51 /*** global variables ****************************************************************************/
53 /*** file scope macro definitions ****************************************************************/
55 /*** file scope type declarations ****************************************************************/
57 /*** file scope variables ************************************************************************/
59 /*** file scope functions ************************************************************************/
60 /* --------------------------------------------------------------------------------------------- */
62 /* --------------------------------------------------------------------------------------------- */
63 /*** public functions ****************************************************************************/
64 /* --------------------------------------------------------------------------------------------- */
66 void
67 mcview_growbuf_init (mcview_t * view)
69 view->growbuf_in_use = TRUE;
70 view->growbuf_blockptr = g_ptr_array_new ();
71 view->growbuf_lastindex = VIEW_PAGE_SIZE;
72 view->growbuf_finished = FALSE;
75 /* --------------------------------------------------------------------------------------------- */
77 void
78 mcview_growbuf_free (mcview_t * view)
80 assert (view->growbuf_in_use);
82 g_ptr_array_foreach (view->growbuf_blockptr, (GFunc) g_free, NULL);
84 (void) g_ptr_array_free (view->growbuf_blockptr, TRUE);
86 view->growbuf_blockptr = NULL;
87 view->growbuf_in_use = FALSE;
90 /* --------------------------------------------------------------------------------------------- */
92 off_t
93 mcview_growbuf_filesize (mcview_t * view)
95 assert (view->growbuf_in_use);
97 if (view->growbuf_blockptr->len == 0)
98 return 0;
99 else
100 return ((off_t) view->growbuf_blockptr->len - 1) * VIEW_PAGE_SIZE + view->growbuf_lastindex;
103 /* --------------------------------------------------------------------------------------------- */
104 /** Copies the output from the pipe to the growing buffer, until either
105 * the end-of-pipe is reached or the interval [0..ofs) of the growing
106 * buffer is completely filled.
109 void
110 mcview_growbuf_read_until (mcview_t * view, off_t ofs)
112 ssize_t nread;
113 byte *p;
114 size_t bytesfree;
115 gboolean short_read;
117 assert (view->growbuf_in_use);
119 if (view->growbuf_finished)
120 return;
122 short_read = FALSE;
123 while (mcview_growbuf_filesize (view) < ofs || short_read)
125 if (view->growbuf_lastindex == VIEW_PAGE_SIZE)
127 /* Append a new block to the growing buffer */
128 byte *newblock = g_try_malloc (VIEW_PAGE_SIZE);
129 if (newblock == NULL)
130 return;
132 g_ptr_array_add (view->growbuf_blockptr, newblock);
133 view->growbuf_lastindex = 0;
135 p = g_ptr_array_index (view->growbuf_blockptr,
136 view->growbuf_blockptr->len - 1) + view->growbuf_lastindex;
138 bytesfree = VIEW_PAGE_SIZE - view->growbuf_lastindex;
140 if (view->datasource == DS_STDIO_PIPE)
142 nread = fread (p, 1, bytesfree, view->ds_stdio_pipe);
143 if (nread == 0)
145 view->growbuf_finished = TRUE;
146 (void) pclose (view->ds_stdio_pipe);
147 mcview_display (view);
148 close_error_pipe (D_NORMAL, NULL);
149 view->ds_stdio_pipe = NULL;
150 return;
153 else
155 assert (view->datasource == DS_VFS_PIPE);
158 nread = mc_read (view->ds_vfs_pipe, p, bytesfree);
160 while (nread == -1 && errno == EINTR);
161 if (nread == -1 || nread == 0)
163 view->growbuf_finished = TRUE;
164 (void) mc_close (view->ds_vfs_pipe);
165 view->ds_vfs_pipe = -1;
166 return;
169 short_read = ((size_t) nread < bytesfree);
170 view->growbuf_lastindex += nread;
174 /* --------------------------------------------------------------------------------------------- */
176 gboolean
177 mcview_get_byte_growing_buffer (mcview_t * view, off_t byte_index, int *retval)
179 off_t pageno;
180 off_t pageindex;
182 if (retval != NULL)
183 *retval = -1;
185 pageno = byte_index / VIEW_PAGE_SIZE;
186 pageindex = byte_index % VIEW_PAGE_SIZE;
188 assert (view->growbuf_in_use);
190 if (pageno < 0)
191 return FALSE;
193 mcview_growbuf_read_until (view, byte_index + 1);
194 if (view->growbuf_blockptr->len == 0)
195 return FALSE;
196 if (pageno < (off_t) view->growbuf_blockptr->len - 1)
198 if (retval != NULL)
199 *retval = *((byte *) (g_ptr_array_index (view->growbuf_blockptr, pageno) + pageindex));
200 return TRUE;
202 if (pageno == (off_t) view->growbuf_blockptr->len - 1
203 && pageindex < (off_t) view->growbuf_lastindex)
205 if (retval != NULL)
206 *retval = *((byte *) (g_ptr_array_index (view->growbuf_blockptr, pageno) + pageindex));
207 return TRUE;
209 return FALSE;
212 /* --------------------------------------------------------------------------------------------- */
214 char *
215 mcview_get_ptr_growing_buffer (mcview_t * view, off_t byte_index)
217 off_t pageno = byte_index / VIEW_PAGE_SIZE;
218 off_t pageindex = byte_index % VIEW_PAGE_SIZE;
220 assert (view->growbuf_in_use);
222 if (pageno < 0)
223 return NULL;
225 mcview_growbuf_read_until (view, byte_index + 1);
226 if (view->growbuf_blockptr->len == 0)
227 return NULL;
228 if (pageno < (off_t) view->growbuf_blockptr->len - 1)
229 return (char *) (g_ptr_array_index (view->growbuf_blockptr, pageno) + pageindex);
230 if (pageno == (off_t) view->growbuf_blockptr->len - 1
231 && pageindex < (off_t) view->growbuf_lastindex)
232 return (char *) (g_ptr_array_index (view->growbuf_blockptr, pageno) + pageindex);
233 return NULL;
236 /* --------------------------------------------------------------------------------------------- */