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.
9 Miguel de Icaza, 1994, 1995, 1998
10 Janne Kukonlehto, 1994, 1995
12 Joseph M. Hinkle, 1996
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/>.
39 #include "lib/global.h"
40 #include "lib/vfs/vfs.h"
42 #include "lib/widget.h" /* D_NORMAL */
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 /* --------------------------------------------------------------------------------------------- */
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 /* --------------------------------------------------------------------------------------------- */
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 /* --------------------------------------------------------------------------------------------- */
95 mcview_growbuf_free (WView
* view
)
98 assert (view
->growbuf_in_use
);
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 /* --------------------------------------------------------------------------------------------- */
112 mcview_growbuf_filesize (WView
* view
)
115 assert (view
->growbuf_in_use
);
118 if (view
->growbuf_blockptr
->len
== 0)
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.
131 mcview_growbuf_read_until (WView
* view
, off_t ofs
)
133 gboolean short_read
= FALSE
;
136 assert (view
->growbuf_in_use
);
139 if (view
->growbuf_finished
)
142 while (mcview_growbuf_filesize (view
) < ofs
|| short_read
)
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
)
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
);
179 mcview_show_error (view
, error
->message
);
180 g_error_free (error
);
181 mcview_growbuf_done (view
);
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
);
199 memmove (p
, sp
->out
.buf
, 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
)
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
);
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
);
230 assert (view
->datasource
== DS_VFS_PIPE
);
234 nread
= mc_read (view
->ds_vfs_pipe
, p
, bytesfree
);
236 while (nread
== -1 && errno
== EINTR
);
240 mcview_growbuf_done (view
);
244 short_read
= ((size_t) nread
< bytesfree
);
245 view
->growbuf_lastindex
+= nread
;
249 /* --------------------------------------------------------------------------------------------- */
252 mcview_get_byte_growing_buffer (WView
* view
, off_t byte_index
, int *retval
)
257 assert (view
->growbuf_in_use
);
266 p
= mcview_get_ptr_growing_buffer (view
, byte_index
);
271 *retval
= (unsigned char) (*p
);
276 /* --------------------------------------------------------------------------------------------- */
279 mcview_get_ptr_growing_buffer (WView
* view
, off_t byte_index
)
281 off_t pageno
, pageindex
;
284 assert (view
->growbuf_in_use
);
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)
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
);
304 /* --------------------------------------------------------------------------------------------- */