root/src/viewer/growbuf.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. mcview_growbuf_init
  2. mcview_growbuf_done
  3. mcview_growbuf_free
  4. mcview_growbuf_filesize
  5. mcview_growbuf_read_until
  6. mcview_get_byte_growing_buffer
  7. mcview_get_ptr_growing_buffer

   1 /*
   2    Internal file viewer for the Midnight Commander
   3    Function for work with growing bufers
   4 
   5    Copyright (C) 1994-2020
   6    Free Software Foundation, Inc.
   7 
   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
  19 
  20    This file is part of the Midnight Commander.
  21 
  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.
  26 
  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.
  31 
  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/>.
  34  */
  35 
  36 #include <config.h>
  37 #include <errno.h>
  38 
  39 #include "lib/global.h"
  40 #include "lib/vfs/vfs.h"
  41 #include "lib/util.h"
  42 #include "lib/widget.h"         /* D_NORMAL */
  43 
  44 #include "internal.h"
  45 
  46 /* Block size for reading files in parts */
  47 #define VIEW_PAGE_SIZE ((size_t) 8192)
  48 
  49 /*** global variables ****************************************************************************/
  50 
  51 /*** file scope macro definitions ****************************************************************/
  52 
  53 /*** file scope type declarations ****************************************************************/
  54 
  55 /*** file scope variables ************************************************************************/
  56 
  57 /*** file scope functions ************************************************************************/
  58 /* --------------------------------------------------------------------------------------------- */
  59 
  60 /* --------------------------------------------------------------------------------------------- */
  61 /*** public functions ****************************************************************************/
  62 /* --------------------------------------------------------------------------------------------- */
  63 
  64 void
  65 mcview_growbuf_init (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
  66 {
  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;
  71 }
  72 
  73 /* --------------------------------------------------------------------------------------------- */
  74 
  75 void
  76 mcview_growbuf_done (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
  77 {
  78     view->growbuf_finished = TRUE;
  79 
  80     if (view->datasource == DS_STDIO_PIPE)
  81     {
  82         mc_pclose (view->ds_stdio_pipe, NULL);
  83         view->ds_stdio_pipe = NULL;
  84     }
  85     else                        /* view->datasource == DS_VFS_PIPE */
  86     {
  87         (void) mc_close (view->ds_vfs_pipe);
  88         view->ds_vfs_pipe = -1;
  89     }
  90 }
  91 
  92 /* --------------------------------------------------------------------------------------------- */
  93 
  94 void
  95 mcview_growbuf_free (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
  96 {
  97     g_assert (view->growbuf_in_use);
  98 
  99     g_ptr_array_foreach (view->growbuf_blockptr, (GFunc) g_free, NULL);
 100 
 101     (void) g_ptr_array_free (view->growbuf_blockptr, TRUE);
 102 
 103     view->growbuf_blockptr = NULL;
 104     view->growbuf_in_use = FALSE;
 105 }
 106 
 107 /* --------------------------------------------------------------------------------------------- */
 108 
 109 off_t
 110 mcview_growbuf_filesize (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 111 {
 112     g_assert (view->growbuf_in_use);
 113 
 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;
 118 }
 119 
 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.
 124  */
 125 
 126 void
 127 mcview_growbuf_read_until (WView * view, off_t ofs)
     /* [previous][next][first][last][top][bottom][index][help]  */
 128 {
 129     gboolean short_read = FALSE;
 130 
 131     g_assert (view->growbuf_in_use);
 132 
 133     if (view->growbuf_finished)
 134         return;
 135 
 136     while (mcview_growbuf_filesize (view) < ofs || short_read)
 137     {
 138         ssize_t nread = 0;
 139         byte *p;
 140         size_t bytesfree;
 141 
 142         if (view->growbuf_lastindex == VIEW_PAGE_SIZE)
 143         {
 144             /* Append a new block to the growing buffer */
 145             byte *newblock = g_try_malloc (VIEW_PAGE_SIZE);
 146             if (newblock == NULL)
 147                 return;
 148 
 149             g_ptr_array_add (view->growbuf_blockptr, newblock);
 150             view->growbuf_lastindex = 0;
 151         }
 152 
 153         p = (byte *) g_ptr_array_index (view->growbuf_blockptr,
 154                                         view->growbuf_blockptr->len - 1) + view->growbuf_lastindex;
 155 
 156         bytesfree = VIEW_PAGE_SIZE - view->growbuf_lastindex;
 157 
 158         if (view->datasource == DS_STDIO_PIPE)
 159         {
 160             mc_pipe_t *sp = view->ds_stdio_pipe;
 161             GError *error = NULL;
 162 
 163             if (bytesfree > MC_PIPE_BUFSIZE)
 164                 bytesfree = MC_PIPE_BUFSIZE;
 165 
 166             sp->out.len = bytesfree;
 167             sp->err.len = MC_PIPE_BUFSIZE;
 168 
 169             mc_pread (sp, &error);
 170 
 171             if (error != NULL)
 172             {
 173                 mcview_show_error (view, error->message);
 174                 g_error_free (error);
 175                 mcview_growbuf_done (view);
 176                 return;
 177             }
 178 
 179             if (view->pipe_first_err_msg && sp->err.len > 0)
 180             {
 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()
 185                  */
 186                 view->pipe_first_err_msg = FALSE;
 187 
 188                 mcview_show_error (view, sp->err.buf);
 189             }
 190 
 191             if (sp->out.len > 0)
 192             {
 193                 memmove (p, sp->out.buf, sp->out.len);
 194                 nread = sp->out.len;
 195             }
 196             else if (sp->out.len == MC_PIPE_STREAM_EOF || sp->out.len == MC_PIPE_ERROR_READ)
 197             {
 198                 if (sp->out.len == MC_PIPE_ERROR_READ)
 199                 {
 200                     char *err_msg;
 201 
 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);
 206                 }
 207 
 208                 /* when switch from parse to raw mode and back,
 209                  * do not close the already closed pipe after following loop:
 210                  * mcview_growbuf_read_until() -> mcview_show_error() ->
 211                  * MSG_DRAW -> mcview_display() -> mcview_get_byte() -> mcview_growbuf_read_until()
 212                  */
 213                 mcview_growbuf_done (view);
 214 
 215                 mcview_display (view);
 216                 return;
 217             }
 218         }
 219         else
 220         {
 221             g_assert (view->datasource == DS_VFS_PIPE);
 222             do
 223             {
 224                 nread = mc_read (view->ds_vfs_pipe, p, bytesfree);
 225             }
 226             while (nread == -1 && errno == EINTR);
 227 
 228             if (nread <= 0)
 229             {
 230                 mcview_growbuf_done (view);
 231                 return;
 232             }
 233         }
 234         short_read = ((size_t) nread < bytesfree);
 235         view->growbuf_lastindex += nread;
 236     }
 237 }
 238 
 239 /* --------------------------------------------------------------------------------------------- */
 240 
 241 gboolean
 242 mcview_get_byte_growing_buffer (WView * view, off_t byte_index, int *retval)
     /* [previous][next][first][last][top][bottom][index][help]  */
 243 {
 244     char *p;
 245 
 246     g_assert (view->growbuf_in_use);
 247 
 248     if (retval != NULL)
 249         *retval = -1;
 250 
 251     if (byte_index < 0)
 252         return FALSE;
 253 
 254     p = mcview_get_ptr_growing_buffer (view, byte_index);
 255     if (p == NULL)
 256         return FALSE;
 257 
 258     if (retval != NULL)
 259         *retval = (unsigned char) (*p);
 260 
 261     return TRUE;
 262 }
 263 
 264 /* --------------------------------------------------------------------------------------------- */
 265 
 266 char *
 267 mcview_get_ptr_growing_buffer (WView * view, off_t byte_index)
     /* [previous][next][first][last][top][bottom][index][help]  */
 268 {
 269     off_t pageno, pageindex;
 270 
 271     g_assert (view->growbuf_in_use);
 272 
 273     if (byte_index < 0)
 274         return NULL;
 275 
 276     pageno = byte_index / VIEW_PAGE_SIZE;
 277     pageindex = byte_index % VIEW_PAGE_SIZE;
 278 
 279     mcview_growbuf_read_until (view, byte_index + 1);
 280     if (view->growbuf_blockptr->len == 0)
 281         return NULL;
 282     if (pageno < (off_t) view->growbuf_blockptr->len - 1)
 283         return ((char *) g_ptr_array_index (view->growbuf_blockptr, pageno) + pageindex);
 284     if (pageno == (off_t) view->growbuf_blockptr->len - 1
 285         && pageindex < (off_t) view->growbuf_lastindex)
 286         return ((char *) g_ptr_array_index (view->growbuf_blockptr, pageno) + pageindex);
 287     return NULL;
 288 }
 289 
 290 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */