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.
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
)
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 /* --------------------------------------------------------------------------------------------- */
110 mcview_growbuf_filesize (WView
* view
)
112 g_assert (view
->growbuf_in_use
);
114 if (view
->growbuf_blockptr
->len
== 0)
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.
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
)
136 while (mcview_growbuf_filesize (view
) < ofs
|| short_read
)
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
)
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
);
173 mcview_show_error (view
, error
->message
);
174 g_error_free (error
);
175 mcview_growbuf_done (view
);
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
);
193 memmove (p
, sp
->out
.buf
, 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
)
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
);
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
);
223 g_assert (view
->datasource
== DS_VFS_PIPE
);
226 nread
= mc_read (view
->ds_vfs_pipe
, p
, bytesfree
);
228 while (nread
== -1 && errno
== EINTR
);
232 mcview_growbuf_done (view
);
236 short_read
= ((size_t) nread
< bytesfree
);
237 view
->growbuf_lastindex
+= nread
;
241 /* --------------------------------------------------------------------------------------------- */
244 mcview_get_byte_growing_buffer (WView
* view
, off_t byte_index
, int *retval
)
248 g_assert (view
->growbuf_in_use
);
256 p
= mcview_get_ptr_growing_buffer (view
, byte_index
);
261 *retval
= (unsigned char) (*p
);
266 /* --------------------------------------------------------------------------------------------- */
269 mcview_get_ptr_growing_buffer (WView
* view
, off_t byte_index
)
271 off_t pageno
, pageindex
;
273 g_assert (view
->growbuf_in_use
);
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)
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
);
292 /* --------------------------------------------------------------------------------------------- */