extfs: tester: fix indentation.
[midnight-commander.git] / src / viewer / growbuf.c
blobc1172b6d6dfe3a8feb909a6a7734d27db2af60a4
1 /*
2 Internal file viewer for the Midnight Commander
3 Function for work with growing bufers
5 Copyright (C) 1994-2017
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 g_assert (view->growbuf_in_use);
99 g_ptr_array_foreach (view->growbuf_blockptr, (GFunc) g_free, NULL);
101 (void) g_ptr_array_free (view->growbuf_blockptr, TRUE);
103 view->growbuf_blockptr = NULL;
104 view->growbuf_in_use = FALSE;
107 /* --------------------------------------------------------------------------------------------- */
109 off_t
110 mcview_growbuf_filesize (WView * view)
112 g_assert (view->growbuf_in_use);
114 if (view->growbuf_blockptr->len == 0)
115 return 0;
116 else
117 return ((off_t) view->growbuf_blockptr->len - 1) * VIEW_PAGE_SIZE + view->growbuf_lastindex;
120 /* --------------------------------------------------------------------------------------------- */
121 /** Copies the output from the pipe to the growing buffer, until either
122 * the end-of-pipe is reached or the interval [0..ofs) of the growing
123 * buffer is completely filled.
126 void
127 mcview_growbuf_read_until (WView * view, off_t ofs)
129 gboolean short_read = FALSE;
131 g_assert (view->growbuf_in_use);
133 if (view->growbuf_finished)
134 return;
136 while (mcview_growbuf_filesize (view) < ofs || short_read)
138 ssize_t nread = 0;
139 byte *p;
140 size_t bytesfree;
142 if (view->growbuf_lastindex == VIEW_PAGE_SIZE)
144 /* Append a new block to the growing buffer */
145 byte *newblock = g_try_malloc (VIEW_PAGE_SIZE);
146 if (newblock == NULL)
147 return;
149 g_ptr_array_add (view->growbuf_blockptr, newblock);
150 view->growbuf_lastindex = 0;
153 p = (byte *) g_ptr_array_index (view->growbuf_blockptr,
154 view->growbuf_blockptr->len - 1) + view->growbuf_lastindex;
156 bytesfree = VIEW_PAGE_SIZE - view->growbuf_lastindex;
158 if (view->datasource == DS_STDIO_PIPE)
160 mc_pipe_t *sp = view->ds_stdio_pipe;
161 GError *error = NULL;
163 if (bytesfree > MC_PIPE_BUFSIZE)
164 bytesfree = MC_PIPE_BUFSIZE;
166 sp->out.len = bytesfree;
167 sp->err.len = MC_PIPE_BUFSIZE;
169 mc_pread (sp, &error);
171 if (error != NULL)
173 mcview_show_error (view, error->message);
174 g_error_free (error);
175 mcview_growbuf_done (view);
176 return;
179 if (view->pipe_first_err_msg && sp->err.len > 0)
181 /* ignore possible following errors */
182 /* reset this flag before call of mcview_show_error() to break
183 * endless recursion: mcview_growbuf_read_until() -> mcview_show_error() ->
184 * MSG_DRAW -> mcview_display() -> mcview_get_byte() -> mcview_growbuf_read_until()
186 view->pipe_first_err_msg = FALSE;
188 mcview_show_error (view, sp->err.buf);
191 if (sp->out.len > 0)
193 memmove (p, sp->out.buf, sp->out.len);
194 nread = sp->out.len;
196 else if (sp->out.len == MC_PIPE_STREAM_EOF || sp->out.len == MC_PIPE_ERROR_READ)
198 if (sp->out.len == MC_PIPE_ERROR_READ)
200 char *err_msg;
202 err_msg = g_strdup_printf (_("Failed to read data from child stdout:\n%s"),
203 unix_error_string (sp->out.error));
204 mcview_show_error (view, err_msg);
205 g_free (err_msg);
208 if (view->ds_stdio_pipe != NULL)
210 /* when switch from parse to raw mode and back,
211 * do not close the already closed pipe after following loop:
212 * mcview_growbuf_read_until() -> mcview_show_error() ->
213 * MSG_DRAW -> mcview_display() -> mcview_get_byte() -> mcview_growbuf_read_until()
215 mcview_growbuf_done (view);
217 mcview_display (view);
218 return;
221 else
223 g_assert (view->datasource == DS_VFS_PIPE);
226 nread = mc_read (view->ds_vfs_pipe, p, bytesfree);
228 while (nread == -1 && errno == EINTR);
230 if (nread <= 0)
232 mcview_growbuf_done (view);
233 return;
236 short_read = ((size_t) nread < bytesfree);
237 view->growbuf_lastindex += nread;
241 /* --------------------------------------------------------------------------------------------- */
243 gboolean
244 mcview_get_byte_growing_buffer (WView * view, off_t byte_index, int *retval)
246 char *p;
248 g_assert (view->growbuf_in_use);
250 if (retval != NULL)
251 *retval = -1;
253 if (byte_index < 0)
254 return FALSE;
256 p = mcview_get_ptr_growing_buffer (view, byte_index);
257 if (p == NULL)
258 return FALSE;
260 if (retval != NULL)
261 *retval = (unsigned char) (*p);
263 return TRUE;
266 /* --------------------------------------------------------------------------------------------- */
268 char *
269 mcview_get_ptr_growing_buffer (WView * view, off_t byte_index)
271 off_t pageno, pageindex;
273 g_assert (view->growbuf_in_use);
275 if (byte_index < 0)
276 return NULL;
278 pageno = byte_index / VIEW_PAGE_SIZE;
279 pageindex = byte_index % VIEW_PAGE_SIZE;
281 mcview_growbuf_read_until (view, byte_index + 1);
282 if (view->growbuf_blockptr->len == 0)
283 return NULL;
284 if (pageno < (off_t) view->growbuf_blockptr->len - 1)
285 return ((char *) g_ptr_array_index (view->growbuf_blockptr, pageno) + pageindex);
286 if (pageno == (off_t) view->growbuf_blockptr->len - 1
287 && pageindex < (off_t) view->growbuf_lastindex)
288 return ((char *) g_ptr_array_index (view->growbuf_blockptr, pageno) + pageindex);
289 return NULL;
292 /* --------------------------------------------------------------------------------------------- */