Merge branch '1858_segfault_in_search'
[midnight-commander.git] / src / viewer / growbuf.c
blobf701ef474b0e5db5460d53fcae3de1cb39b73840
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 "../src/global.h"
42 #include "../src/wtools.h"
43 #include "internal.h"
45 /* Block size for reading files in parts */
46 #define VIEW_PAGE_SIZE ((size_t) 8192)
48 /*** global variables ****************************************************************************/
50 /*** file scope macro definitions ****************************************************************/
52 /*** file scope type declarations ****************************************************************/
54 /*** file scope variables ************************************************************************/
56 /*** file scope functions ************************************************************************/
58 /*** public functions ****************************************************************************/
60 /* --------------------------------------------------------------------------------------------- */
62 void
63 mcview_growbuf_init (mcview_t * view)
65 view->growbuf_in_use = TRUE;
66 view->growbuf_blockptr = NULL;
67 view->growbuf_blocks = 0;
68 view->growbuf_lastindex = VIEW_PAGE_SIZE;
69 view->growbuf_finished = FALSE;
72 /* --------------------------------------------------------------------------------------------- */
74 void
75 mcview_growbuf_free (mcview_t * view)
77 size_t i;
79 assert (view->growbuf_in_use);
81 for (i = 0; i < view->growbuf_blocks; i++)
82 g_free (view->growbuf_blockptr[i]);
83 g_free (view->growbuf_blockptr);
84 view->growbuf_blockptr = NULL;
85 view->growbuf_in_use = FALSE;
88 /* --------------------------------------------------------------------------------------------- */
90 off_t
91 mcview_growbuf_filesize (mcview_t * view)
93 assert (view->growbuf_in_use);
95 if (view->growbuf_blocks == 0)
96 return 0;
97 else
98 return ((off_t) view->growbuf_blocks - 1) * VIEW_PAGE_SIZE + view->growbuf_lastindex;
101 /* --------------------------------------------------------------------------------------------- */
103 /* Copies the output from the pipe to the growing buffer, until either
104 * the end-of-pipe is reached or the interval [0..ofs) of the growing
105 * buffer is completely filled. */
106 void
107 mcview_growbuf_read_until (mcview_t * view, off_t ofs)
109 ssize_t nread;
110 byte *p;
111 size_t bytesfree;
112 gboolean short_read;
114 assert (view->growbuf_in_use);
116 if (view->growbuf_finished)
117 return;
119 short_read = FALSE;
120 while (mcview_growbuf_filesize (view) < ofs || short_read) {
121 if (view->growbuf_lastindex == VIEW_PAGE_SIZE) {
122 /* Append a new block to the growing buffer */
123 byte *newblock = g_try_malloc (VIEW_PAGE_SIZE);
124 byte **newblocks = g_try_malloc (sizeof (*newblocks) * (view->growbuf_blocks + 1));
125 if (!newblock || !newblocks) {
126 g_free (newblock);
127 g_free (newblocks);
128 return;
130 memcpy (newblocks, view->growbuf_blockptr, sizeof (*newblocks) * view->growbuf_blocks);
131 g_free (view->growbuf_blockptr);
132 view->growbuf_blockptr = newblocks;
133 view->growbuf_blockptr[view->growbuf_blocks++] = newblock;
134 view->growbuf_lastindex = 0;
136 p = view->growbuf_blockptr[view->growbuf_blocks - 1] + view->growbuf_lastindex;
137 bytesfree = VIEW_PAGE_SIZE - view->growbuf_lastindex;
139 if (view->datasource == DS_STDIO_PIPE) {
140 nread = fread (p, 1, bytesfree, view->ds_stdio_pipe);
141 if (nread == 0) {
142 view->growbuf_finished = TRUE;
143 (void) pclose (view->ds_stdio_pipe);
144 mcview_display (view);
145 close_error_pipe (D_NORMAL, NULL);
146 view->ds_stdio_pipe = NULL;
147 return;
149 } else {
150 assert (view->datasource == DS_VFS_PIPE);
151 do {
152 nread = mc_read (view->ds_vfs_pipe, p, bytesfree);
153 } while (nread == -1 && errno == EINTR);
154 if (nread == -1 || nread == 0) {
155 view->growbuf_finished = TRUE;
156 (void) mc_close (view->ds_vfs_pipe);
157 view->ds_vfs_pipe = -1;
158 return;
161 short_read = ((size_t) nread < bytesfree);
162 view->growbuf_lastindex += nread;
166 /* --------------------------------------------------------------------------------------------- */
168 gboolean
169 mcview_get_byte_growing_buffer (mcview_t * view, off_t byte_index, int *retval)
171 off_t pageno;
172 off_t pageindex;
174 if (retval)
175 *retval = -1;
177 pageno = byte_index / VIEW_PAGE_SIZE;
178 pageindex = byte_index % VIEW_PAGE_SIZE;
180 assert (view->growbuf_in_use);
182 if ((size_t) pageno != pageno)
183 return FALSE;
185 mcview_growbuf_read_until (view, byte_index + 1);
186 if (view->growbuf_blocks == 0)
187 return FALSE;
188 if (pageno < view->growbuf_blocks - 1) {
189 if (retval)
190 *retval = view->growbuf_blockptr[pageno][pageindex];
191 return TRUE;
193 if (pageno == view->growbuf_blocks - 1 && pageindex < view->growbuf_lastindex) {
194 if (retval)
195 *retval = view->growbuf_blockptr[pageno][pageindex];
196 return TRUE;
198 return FALSE;
201 /* --------------------------------------------------------------------------------------------- */
203 char *
204 mcview_get_ptr_growing_buffer (mcview_t * view, off_t byte_index)
206 off_t pageno = byte_index / VIEW_PAGE_SIZE;
207 off_t pageindex = byte_index % VIEW_PAGE_SIZE;
209 assert (view->growbuf_in_use);
211 if ((size_t) pageno != pageno)
212 return NULL;
214 mcview_growbuf_read_until (view, byte_index + 1);
215 if (view->growbuf_blocks == 0)
216 return NULL;
217 if (pageno < view->growbuf_blocks - 1)
218 return (char *) (view->growbuf_blockptr[pageno] + pageindex);
219 if (pageno == view->growbuf_blocks - 1 && pageindex < view->growbuf_lastindex)
220 return (char *) (view->growbuf_blockptr[pageno] + pageindex);
221 return NULL;
224 /* --------------------------------------------------------------------------------------------- */