Set WOP_TOP_SELECT options for panel widgets: WPanel, WView and WTree.
[midnight-commander.git] / src / viewer / growbuf.c
blobd080aa6a0be09689e92154355b8deb6b1a2e23b9
1 /*
2 Internal file viewer for the Midnight Commander
3 Function for work with growing bufers
5 Copyright (C) 1994-2016
6 Free Software Foundation, Inc.
8 Written by:
9 Miguel de Icaza, 1994, 1995, 1998
10 Janne Kukonlehto, 1994, 1995
11 Jakub Jelinek, 1995
12 Joseph M. Hinkle, 1996
13 Norbert Warmuth, 1997
14 Pavel Machek, 1998
15 Roland Illig <roland.illig@gmx.de>, 2004, 2005
16 Slava Zanko <slavazanko@google.com>, 2009
17 Andrew Borodin <aborodin@vmail.ru>, 2009, 2014
18 Ilia Maslakov <il.smind@gmail.com>, 2009
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 3 of the License,
25 or (at your option) any later version.
27 The Midnight Commander is distributed in the hope that it will be useful,
28 but WITHOUT ANY WARRANTY; without even the implied warranty of
29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 GNU 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, see <http://www.gnu.org/licenses/>.
36 #include <config.h>
37 #include <errno.h>
39 #include "lib/global.h"
40 #include "lib/vfs/vfs.h"
41 #include "lib/util.h"
42 #include "lib/widget.h" /* D_NORMAL */
44 #include "internal.h"
46 /* Block size for reading files in parts */
47 #define VIEW_PAGE_SIZE ((size_t) 8192)
49 /*** global variables ****************************************************************************/
51 /*** file scope macro definitions ****************************************************************/
53 /*** file scope type declarations ****************************************************************/
55 /*** file scope variables ************************************************************************/
57 /*** file scope functions ************************************************************************/
58 /* --------------------------------------------------------------------------------------------- */
60 /* --------------------------------------------------------------------------------------------- */
61 /*** public functions ****************************************************************************/
62 /* --------------------------------------------------------------------------------------------- */
64 void
65 mcview_growbuf_init (WView * view)
67 view->growbuf_in_use = TRUE;
68 view->growbuf_blockptr = g_ptr_array_new ();
69 view->growbuf_lastindex = VIEW_PAGE_SIZE;
70 view->growbuf_finished = FALSE;
73 /* --------------------------------------------------------------------------------------------- */
75 void
76 mcview_growbuf_done (WView * view)
78 view->growbuf_finished = TRUE;
80 if (view->datasource == DS_STDIO_PIPE)
82 mc_pclose (view->ds_stdio_pipe, NULL);
83 view->ds_stdio_pipe = NULL;
85 else /* view->datasource == DS_VFS_PIPE */
87 (void) mc_close (view->ds_vfs_pipe);
88 view->ds_vfs_pipe = -1;
92 /* --------------------------------------------------------------------------------------------- */
94 void
95 mcview_growbuf_free (WView * view)
97 #ifdef HAVE_ASSERT_H
98 assert (view->growbuf_in_use);
99 #endif
101 g_ptr_array_foreach (view->growbuf_blockptr, (GFunc) g_free, NULL);
103 (void) g_ptr_array_free (view->growbuf_blockptr, TRUE);
105 view->growbuf_blockptr = NULL;
106 view->growbuf_in_use = FALSE;
109 /* --------------------------------------------------------------------------------------------- */
111 off_t
112 mcview_growbuf_filesize (WView * view)
114 #ifdef HAVE_ASSERT_H
115 assert (view->growbuf_in_use);
116 #endif
118 if (view->growbuf_blockptr->len == 0)
119 return 0;
120 else
121 return ((off_t) view->growbuf_blockptr->len - 1) * VIEW_PAGE_SIZE + view->growbuf_lastindex;
124 /* --------------------------------------------------------------------------------------------- */
125 /** Copies the output from the pipe to the growing buffer, until either
126 * the end-of-pipe is reached or the interval [0..ofs) of the growing
127 * buffer is completely filled.
130 void
131 mcview_growbuf_read_until (WView * view, off_t ofs)
133 gboolean short_read = FALSE;
135 #ifdef HAVE_ASSERT_H
136 assert (view->growbuf_in_use);
137 #endif
139 if (view->growbuf_finished)
140 return;
142 while (mcview_growbuf_filesize (view) < ofs || short_read)
144 ssize_t nread = 0;
145 byte *p;
146 size_t bytesfree;
148 if (view->growbuf_lastindex == VIEW_PAGE_SIZE)
150 /* Append a new block to the growing buffer */
151 byte *newblock = g_try_malloc (VIEW_PAGE_SIZE);
152 if (newblock == NULL)
153 return;
155 g_ptr_array_add (view->growbuf_blockptr, newblock);
156 view->growbuf_lastindex = 0;
159 p = (byte *) g_ptr_array_index (view->growbuf_blockptr,
160 view->growbuf_blockptr->len - 1) + view->growbuf_lastindex;
162 bytesfree = VIEW_PAGE_SIZE - view->growbuf_lastindex;
164 if (view->datasource == DS_STDIO_PIPE)
166 mc_pipe_t *sp = view->ds_stdio_pipe;
167 GError *error = NULL;
169 if (bytesfree > MC_PIPE_BUFSIZE)
170 bytesfree = MC_PIPE_BUFSIZE;
172 sp->out.len = bytesfree;
173 sp->err.len = MC_PIPE_BUFSIZE;
175 mc_pread (sp, &error);
177 if (error != NULL)
179 mcview_show_error (view, error->message);
180 g_error_free (error);
181 mcview_growbuf_done (view);
182 return;
185 if (view->pipe_first_err_msg && sp->err.len > 0)
187 /* ignore possible following errors */
188 /* reset this flag before call of mcview_show_error() to break
189 * endless recursion: mcview_growbuf_read_until() -> mcview_show_error() ->
190 * MSG_DRAW -> mcview_display() -> mcview_get_byte() -> mcview_growbuf_read_until()
192 view->pipe_first_err_msg = FALSE;
194 mcview_show_error (view, sp->err.buf);
197 if (sp->out.len > 0)
199 memmove (p, sp->out.buf, sp->out.len);
200 nread = sp->out.len;
202 else if (sp->out.len == MC_PIPE_STREAM_EOF || sp->out.len == MC_PIPE_ERROR_READ)
204 if (sp->out.len == MC_PIPE_ERROR_READ)
206 char *err_msg;
208 err_msg = g_strdup_printf (_("Failed to read data from child stdout:\n%s"),
209 unix_error_string (sp->out.error));
210 mcview_show_error (view, err_msg);
211 g_free (err_msg);
214 if (view->ds_stdio_pipe != NULL)
216 /* when switch from parse to raw mode and back,
217 * do not close the already closed pipe after following loop:
218 * mcview_growbuf_read_until() -> mcview_show_error() ->
219 * MSG_DRAW -> mcview_display() -> mcview_get_byte() -> mcview_growbuf_read_until()
221 mcview_growbuf_done (view);
223 mcview_display (view);
224 return;
227 else
229 #ifdef HAVE_ASSERT_H
230 assert (view->datasource == DS_VFS_PIPE);
231 #endif
234 nread = mc_read (view->ds_vfs_pipe, p, bytesfree);
236 while (nread == -1 && errno == EINTR);
238 if (nread <= 0)
240 mcview_growbuf_done (view);
241 return;
244 short_read = ((size_t) nread < bytesfree);
245 view->growbuf_lastindex += nread;
249 /* --------------------------------------------------------------------------------------------- */
251 gboolean
252 mcview_get_byte_growing_buffer (WView * view, off_t byte_index, int *retval)
254 char *p;
256 #ifdef HAVE_ASSERT_H
257 assert (view->growbuf_in_use);
258 #endif
260 if (retval != NULL)
261 *retval = -1;
263 if (byte_index < 0)
264 return FALSE;
266 p = mcview_get_ptr_growing_buffer (view, byte_index);
267 if (p == NULL)
268 return FALSE;
270 if (retval != NULL)
271 *retval = (unsigned char) (*p);
273 return TRUE;
276 /* --------------------------------------------------------------------------------------------- */
278 char *
279 mcview_get_ptr_growing_buffer (WView * view, off_t byte_index)
281 off_t pageno, pageindex;
283 #ifdef HAVE_ASSERT_H
284 assert (view->growbuf_in_use);
285 #endif
287 if (byte_index < 0)
288 return NULL;
290 pageno = byte_index / VIEW_PAGE_SIZE;
291 pageindex = byte_index % VIEW_PAGE_SIZE;
293 mcview_growbuf_read_until (view, byte_index + 1);
294 if (view->growbuf_blockptr->len == 0)
295 return NULL;
296 if (pageno < (off_t) view->growbuf_blockptr->len - 1)
297 return ((char *) g_ptr_array_index (view->growbuf_blockptr, pageno) + pageindex);
298 if (pageno == (off_t) view->growbuf_blockptr->len - 1
299 && pageindex < (off_t) view->growbuf_lastindex)
300 return ((char *) g_ptr_array_index (view->growbuf_blockptr, pageno) + pageindex);
301 return NULL;
304 /* --------------------------------------------------------------------------------------------- */