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

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