root/src/viewer/datasource.c

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

DEFINITIONS

This source file includes following definitions.
  1. mcview_set_datasource_stdio_pipe
  2. mcview_set_datasource_none
  3. mcview_get_filesize
  4. mcview_update_filesize
  5. mcview_get_ptr_file
  6. mcview_get_utf
  7. mcview_get_ptr_string
  8. mcview_get_byte_string
  9. mcview_get_byte_none
  10. mcview_set_byte
  11. mcview_file_load_data
  12. mcview_close_datasource
  13. mcview_set_datasource_file
  14. mcview_load_command_output
  15. mcview_set_datasource_vfs_pipe
  16. mcview_set_datasource_string

   1 /*
   2    Internal file viewer for the Midnight Commander
   3    Functions for datasources
   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
  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 /*
  37    The data source provides the viewer with data from either a file, a
  38    string or the output of a command. The mcview_get_byte() function can be
  39    used to get the value of a byte at a specific offset. If the offset
  40    is out of range, -1 is returned. The function mcview_get_byte_indexed(a,b)
  41    returns the byte at the offset a+b, or -1 if a+b is out of range.
  42 
  43    The mcview_set_byte() function has the effect that later calls to
  44    mcview_get_byte() will return the specified byte for this offset. This
  45    function is designed only for use by the hexedit component after
  46    saving its changes. Inspect the source before you want to use it for
  47    other purposes.
  48 
  49    The mcview_get_filesize() function returns the current size of the
  50    data source. If the growing buffer is used, this size may increase
  51    later on. Use the mcview_may_still_grow() function when you want to
  52    know if the size can change later.
  53  */
  54 
  55 #include <config.h>
  56 
  57 #include "lib/global.h"
  58 #include "lib/vfs/vfs.h"
  59 #include "lib/util.h"
  60 #include "lib/widget.h"         /* D_NORMAL, D_ERROR */
  61 
  62 #include "internal.h"
  63 
  64 /*** global variables ****************************************************************************/
  65 
  66 /*** file scope macro definitions ****************************************************************/
  67 
  68 /*** file scope type declarations ****************************************************************/
  69 
  70 /*** file scope variables ************************************************************************/
  71 
  72 /* --------------------------------------------------------------------------------------------- */
  73 /*** file scope functions ************************************************************************/
  74 /* --------------------------------------------------------------------------------------------- */
  75 
  76 static void
  77 mcview_set_datasource_stdio_pipe (WView * view, mc_pipe_t * p)
     /* [previous][next][first][last][top][bottom][index][help]  */
  78 {
  79     p->out.len = MC_PIPE_BUFSIZE;
  80     p->out.null_term = FALSE;
  81     p->err.len = MC_PIPE_BUFSIZE;
  82     p->err.null_term = TRUE;
  83     view->datasource = DS_STDIO_PIPE;
  84     view->ds_stdio_pipe = p;
  85     view->pipe_first_err_msg = TRUE;
  86 
  87     mcview_growbuf_init (view);
  88 }
  89 
  90 /* --------------------------------------------------------------------------------------------- */
  91 /*** public functions ****************************************************************************/
  92 /* --------------------------------------------------------------------------------------------- */
  93 
  94 void
  95 mcview_set_datasource_none (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
  96 {
  97     view->datasource = DS_NONE;
  98 }
  99 
 100 /* --------------------------------------------------------------------------------------------- */
 101 
 102 off_t
 103 mcview_get_filesize (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 104 {
 105     switch (view->datasource)
 106     {
 107     case DS_STDIO_PIPE:
 108     case DS_VFS_PIPE:
 109         return mcview_growbuf_filesize (view);
 110     case DS_FILE:
 111         return view->ds_file_filesize;
 112     case DS_STRING:
 113         return view->ds_string_len;
 114     default:
 115         return 0;
 116     }
 117 }
 118 
 119 /* --------------------------------------------------------------------------------------------- */
 120 
 121 void
 122 mcview_update_filesize (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 123 {
 124     if (view->datasource == DS_FILE)
 125     {
 126         struct stat st;
 127         if (mc_fstat (view->ds_file_fd, &st) != -1)
 128             view->ds_file_filesize = st.st_size;
 129     }
 130 }
 131 
 132 /* --------------------------------------------------------------------------------------------- */
 133 
 134 char *
 135 mcview_get_ptr_file (WView * view, off_t byte_index)
     /* [previous][next][first][last][top][bottom][index][help]  */
 136 {
 137     g_assert (view->datasource == DS_FILE);
 138 
 139     mcview_file_load_data (view, byte_index);
 140     if (mcview_already_loaded (view->ds_file_offset, byte_index, view->ds_file_datalen))
 141         return (char *) (view->ds_file_data + (byte_index - view->ds_file_offset));
 142     return NULL;
 143 }
 144 
 145 /* --------------------------------------------------------------------------------------------- */
 146 
 147 /* Invalid UTF-8 is reported as negative integers (one for each byte),
 148  * see ticket 3783. */
 149 gboolean
 150 mcview_get_utf (WView * view, off_t byte_index, int *ch, int *ch_len)
     /* [previous][next][first][last][top][bottom][index][help]  */
 151 {
 152     gchar *str = NULL;
 153     int res;
 154     gchar utf8buf[UTF8_CHAR_LEN + 1];
 155 
 156     switch (view->datasource)
 157     {
 158     case DS_STDIO_PIPE:
 159     case DS_VFS_PIPE:
 160         str = mcview_get_ptr_growing_buffer (view, byte_index);
 161         break;
 162     case DS_FILE:
 163         str = mcview_get_ptr_file (view, byte_index);
 164         break;
 165     case DS_STRING:
 166         str = mcview_get_ptr_string (view, byte_index);
 167         break;
 168     case DS_NONE:
 169     default:
 170         break;
 171     }
 172 
 173     *ch = 0;
 174 
 175     if (str == NULL)
 176         return FALSE;
 177 
 178     res = g_utf8_get_char_validated (str, -1);
 179 
 180     if (res < 0)
 181     {
 182         /* Retry with explicit bytes to make sure it's not a buffer boundary */
 183         int i;
 184 
 185         for (i = 0; i < UTF8_CHAR_LEN; i++)
 186         {
 187             if (mcview_get_byte (view, byte_index + i, &res))
 188                 utf8buf[i] = res;
 189             else
 190             {
 191                 utf8buf[i] = '\0';
 192                 break;
 193             }
 194         }
 195         utf8buf[UTF8_CHAR_LEN] = '\0';
 196         str = utf8buf;
 197         res = g_utf8_get_char_validated (str, -1);
 198     }
 199 
 200     if (res < 0)
 201     {
 202         /* Implicit conversion from signed char to signed int keeps negative values. */
 203         *ch = *str;
 204         *ch_len = 1;
 205     }
 206     else
 207     {
 208         gchar *next_ch = NULL;
 209 
 210         *ch = res;
 211         /* Calculate UTF-8 char length */
 212         next_ch = g_utf8_next_char (str);
 213         *ch_len = next_ch - str;
 214     }
 215 
 216     return TRUE;
 217 }
 218 
 219 /* --------------------------------------------------------------------------------------------- */
 220 
 221 char *
 222 mcview_get_ptr_string (WView * view, off_t byte_index)
     /* [previous][next][first][last][top][bottom][index][help]  */
 223 {
 224     g_assert (view->datasource == DS_STRING);
 225 
 226     if (byte_index >= 0 && byte_index < (off_t) view->ds_string_len)
 227         return (char *) (view->ds_string_data + byte_index);
 228     return NULL;
 229 }
 230 
 231 /* --------------------------------------------------------------------------------------------- */
 232 
 233 gboolean
 234 mcview_get_byte_string (WView * view, off_t byte_index, int *retval)
     /* [previous][next][first][last][top][bottom][index][help]  */
 235 {
 236     char *p;
 237 
 238     if (retval != NULL)
 239         *retval = -1;
 240 
 241     p = mcview_get_ptr_string (view, byte_index);
 242     if (p == NULL)
 243         return FALSE;
 244 
 245     if (retval != NULL)
 246         *retval = (unsigned char) (*p);
 247     return TRUE;
 248 }
 249 
 250 /* --------------------------------------------------------------------------------------------- */
 251 
 252 gboolean
 253 mcview_get_byte_none (WView * view, off_t byte_index, int *retval)
     /* [previous][next][first][last][top][bottom][index][help]  */
 254 {
 255     (void) &view;
 256     (void) byte_index;
 257 
 258     g_assert (view->datasource == DS_NONE);
 259 
 260     if (retval != NULL)
 261         *retval = -1;
 262     return FALSE;
 263 }
 264 
 265 /* --------------------------------------------------------------------------------------------- */
 266 
 267 void
 268 mcview_set_byte (WView * view, off_t offset, byte b)
     /* [previous][next][first][last][top][bottom][index][help]  */
 269 {
 270     (void) &b;
 271 
 272     g_assert (offset < mcview_get_filesize (view));
 273     g_assert (view->datasource == DS_FILE);
 274 
 275     view->ds_file_datalen = 0;  /* just force reloading */
 276 }
 277 
 278 /* --------------------------------------------------------------------------------------------- */
 279 
 280 /*static */
 281 void
 282 mcview_file_load_data (WView * view, off_t byte_index)
     /* [previous][next][first][last][top][bottom][index][help]  */
 283 {
 284     off_t blockoffset;
 285     ssize_t res;
 286     size_t bytes_read;
 287 
 288     g_assert (view->datasource == DS_FILE);
 289 
 290     if (mcview_already_loaded (view->ds_file_offset, byte_index, view->ds_file_datalen))
 291         return;
 292 
 293     if (byte_index >= view->ds_file_filesize)
 294         return;
 295 
 296     blockoffset = mcview_offset_rounddown (byte_index, view->ds_file_datasize);
 297     if (mc_lseek (view->ds_file_fd, blockoffset, SEEK_SET) == -1)
 298         goto error;
 299 
 300     bytes_read = 0;
 301     while (bytes_read < view->ds_file_datasize)
 302     {
 303         res =
 304             mc_read (view->ds_file_fd, view->ds_file_data + bytes_read,
 305                      view->ds_file_datasize - bytes_read);
 306         if (res == -1)
 307             goto error;
 308         if (res == 0)
 309             break;
 310         bytes_read += (size_t) res;
 311     }
 312     view->ds_file_offset = blockoffset;
 313     if ((off_t) bytes_read > view->ds_file_filesize - view->ds_file_offset)
 314     {
 315         /* the file has grown in the meantime -- stick to the old size */
 316         view->ds_file_datalen = view->ds_file_filesize - view->ds_file_offset;
 317     }
 318     else
 319     {
 320         view->ds_file_datalen = bytes_read;
 321     }
 322     return;
 323 
 324   error:
 325     view->ds_file_datalen = 0;
 326 }
 327 
 328 /* --------------------------------------------------------------------------------------------- */
 329 
 330 void
 331 mcview_close_datasource (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 332 {
 333     switch (view->datasource)
 334     {
 335     case DS_NONE:
 336         break;
 337     case DS_STDIO_PIPE:
 338         if (view->ds_stdio_pipe != NULL)
 339         {
 340             mcview_growbuf_done (view);
 341             mcview_display (view);
 342         }
 343         mcview_growbuf_free (view);
 344         break;
 345     case DS_VFS_PIPE:
 346         if (view->ds_vfs_pipe != -1)
 347             mcview_growbuf_done (view);
 348         mcview_growbuf_free (view);
 349         break;
 350     case DS_FILE:
 351         (void) mc_close (view->ds_file_fd);
 352         view->ds_file_fd = -1;
 353         MC_PTR_FREE (view->ds_file_data);
 354         break;
 355     case DS_STRING:
 356         MC_PTR_FREE (view->ds_string_data);
 357     default:
 358         break;
 359     }
 360     view->datasource = DS_NONE;
 361 }
 362 
 363 /* --------------------------------------------------------------------------------------------- */
 364 
 365 void
 366 mcview_set_datasource_file (WView * view, int fd, const struct stat *st)
     /* [previous][next][first][last][top][bottom][index][help]  */
 367 {
 368     view->datasource = DS_FILE;
 369     view->ds_file_fd = fd;
 370     view->ds_file_filesize = st->st_size;
 371     view->ds_file_offset = 0;
 372     view->ds_file_data = g_malloc (4096);
 373     view->ds_file_datalen = 0;
 374     view->ds_file_datasize = 4096;
 375 }
 376 
 377 /* --------------------------------------------------------------------------------------------- */
 378 
 379 gboolean
 380 mcview_load_command_output (WView * view, const char *command)
     /* [previous][next][first][last][top][bottom][index][help]  */
 381 {
 382     mc_pipe_t *p;
 383     GError *error = NULL;
 384 
 385     mcview_close_datasource (view);
 386 
 387     p = mc_popen (command, &error);
 388     if (p == NULL)
 389     {
 390         mcview_display (view);
 391         mcview_show_error (view, error->message);
 392         g_error_free (error);
 393         return FALSE;
 394     }
 395 
 396     /* Check if filter produced any output */
 397     mcview_set_datasource_stdio_pipe (view, p);
 398     if (!mcview_get_byte (view, 0, NULL))
 399     {
 400         mcview_close_datasource (view);
 401         mcview_display (view);
 402         return FALSE;
 403     }
 404 
 405     return TRUE;
 406 }
 407 
 408 /* --------------------------------------------------------------------------------------------- */
 409 
 410 void
 411 mcview_set_datasource_vfs_pipe (WView * view, int fd)
     /* [previous][next][first][last][top][bottom][index][help]  */
 412 {
 413     g_assert (fd != -1);
 414 
 415     view->datasource = DS_VFS_PIPE;
 416     view->ds_vfs_pipe = fd;
 417 
 418     mcview_growbuf_init (view);
 419 }
 420 
 421 /* --------------------------------------------------------------------------------------------- */
 422 
 423 void
 424 mcview_set_datasource_string (WView * view, const char *s)
     /* [previous][next][first][last][top][bottom][index][help]  */
 425 {
 426     view->datasource = DS_STRING;
 427     view->ds_string_len = strlen (s);
 428     view->ds_string_data = (byte *) g_strndup (s, view->ds_string_len);
 429 }
 430 
 431 /* --------------------------------------------------------------------------------------------- */

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