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-2019
   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                 if (view->ds_stdio_pipe != NULL)
 209                 {
 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()
 214                      */
 215                     mcview_growbuf_done (view);
 216                 }
 217                 mcview_display (view);
 218                 return;
 219             }
 220         }
 221         else
 222         {
 223             g_assert (view->datasource == DS_VFS_PIPE);
 224             do
 225             {
 226                 nread = mc_read (view->ds_vfs_pipe, p, bytesfree);
 227             }
 228             while (nread == -1 && errno == EINTR);
 229 
 230             if (nread <= 0)
 231             {
 232                 mcview_growbuf_done (view);
 233                 return;
 234             }
 235         }
 236         short_read = ((size_t) nread < bytesfree);
 237         view->growbuf_lastindex += nread;
 238     }
 239 }
 240 
 241 /* --------------------------------------------------------------------------------------------- */
 242 
 243 gboolean
 244 mcview_get_byte_growing_buffer (WView * view, off_t byte_index, int *retval)
     /* [previous][next][first][last][top][bottom][index][help]  */
 245 {
 246     char *p;
 247 
 248     g_assert (view->growbuf_in_use);
 249 
 250     if (retval != NULL)
 251         *retval = -1;
 252 
 253     if (byte_index < 0)
 254         return FALSE;
 255 
 256     p = mcview_get_ptr_growing_buffer (view, byte_index);
 257     if (p == NULL)
 258         return FALSE;
 259 
 260     if (retval != NULL)
 261         *retval = (unsigned char) (*p);
 262 
 263     return TRUE;
 264 }
 265 
 266 /* --------------------------------------------------------------------------------------------- */
 267 
 268 char *
 269 mcview_get_ptr_growing_buffer (WView * view, off_t byte_index)
     /* [previous][next][first][last][top][bottom][index][help]  */
 270 {
 271     off_t pageno, pageindex;
 272 
 273     g_assert (view->growbuf_in_use);
 274 
 275     if (byte_index < 0)
 276         return NULL;
 277 
 278     pageno = byte_index / VIEW_PAGE_SIZE;
 279     pageindex = byte_index % VIEW_PAGE_SIZE;
 280 
 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;
 290 }
 291 
 292 /* --------------------------------------------------------------------------------------------- */

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