root/src/viewer/mcviewer.c

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

DEFINITIONS

This source file includes following definitions.
  1. mcview_mouse_callback
  2. mcview_new
  3. mcview_viewer
  4. mcview_load

   1 /*
   2    Internal file viewer for the Midnight Commander
   3    Interface functions
   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, 2013
  17    Andrew Borodin <aborodin@vmail.ru>, 2009, 2013
  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/tty/tty.h"
  41 #include "lib/vfs/vfs.h"
  42 #include "lib/strutil.h"
  43 #include "lib/util.h"           /* load_file_position() */
  44 #include "lib/widget.h"
  45 
  46 #include "src/filemanager/layout.h"     /* menubar_visible */
  47 #include "src/filemanager/midnight.h"   /* the_menubar */
  48 
  49 #include "internal.h"
  50 
  51 /*** global variables ****************************************************************************/
  52 
  53 mcview_mode_flags_t mcview_global_flags = {
  54     .wrap = TRUE,
  55     .hex = FALSE,
  56     .magic = TRUE,
  57     .nroff = FALSE
  58 };
  59 
  60 mcview_mode_flags_t mcview_altered_flags = {
  61     .wrap = FALSE,
  62     .hex = FALSE,
  63     .magic = FALSE,
  64     .nroff = FALSE
  65 };
  66 
  67 gboolean mcview_remember_file_position = FALSE;
  68 
  69 /* Maxlimit for skipping updates */
  70 int mcview_max_dirt_limit = 10;
  71 
  72 /* Scrolling is done in pages or line increments */
  73 gboolean mcview_mouse_move_pages = TRUE;
  74 
  75 /* end of file will be showen from mcview_show_eof */
  76 char *mcview_show_eof = NULL;
  77 
  78 /*** file scope macro definitions ****************************************************************/
  79 
  80 /*** file scope type declarations ****************************************************************/
  81 
  82 /*** file scope variables ************************************************************************/
  83 
  84 /* --------------------------------------------------------------------------------------------- */
  85 /*** file scope functions ************************************************************************/
  86 /* --------------------------------------------------------------------------------------------- */
  87 
  88 static void
  89 mcview_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event)
     /* [previous][next][first][last][top][bottom][index][help]  */
  90 {
  91     WView *view = (WView *) w;
  92     gboolean ok = TRUE;
  93 
  94     switch (msg)
  95     {
  96     case MSG_MOUSE_DOWN:
  97         if (mcview_is_in_panel (view))
  98         {
  99             if (event->y == WIDGET (w->owner)->y)
 100             {
 101                 /* return MOU_UNHANDLED */
 102                 event->result.abort = TRUE;
 103                 /* don't draw viewer over menu */
 104                 ok = FALSE;
 105                 break;
 106             }
 107 
 108             if (!widget_get_state (w, WST_FOCUSED))
 109             {
 110                 /* Grab focus */
 111                 change_panel ();
 112             }
 113         }
 114         MC_FALLTHROUGH;
 115 
 116     case MSG_MOUSE_CLICK:
 117         if (!view->mode_flags.wrap)
 118         {
 119             /* Scrolling left and right */
 120             screen_dimen x;
 121 
 122             x = event->x + 1;   /* FIXME */
 123 
 124             if (x < view->data_area.width * 1 / 4)
 125             {
 126                 mcview_move_left (view, 1);
 127                 event->result.repeat = msg == MSG_MOUSE_DOWN;
 128             }
 129             else if (x < view->data_area.width * 3 / 4)
 130             {
 131                 /* ignore the click */
 132                 ok = FALSE;
 133             }
 134             else
 135             {
 136                 mcview_move_right (view, 1);
 137                 event->result.repeat = msg == MSG_MOUSE_DOWN;
 138             }
 139         }
 140         else
 141         {
 142             /* Scrolling up and down */
 143             screen_dimen y;
 144 
 145             y = event->y + 1;   /* FIXME */
 146 
 147             if (y < view->data_area.top + view->data_area.height * 1 / 3)
 148             {
 149                 if (mcview_mouse_move_pages)
 150                     mcview_move_up (view, view->data_area.height / 2);
 151                 else
 152                     mcview_move_up (view, 1);
 153 
 154                 event->result.repeat = msg == MSG_MOUSE_DOWN;
 155             }
 156             else if (y < view->data_area.top + view->data_area.height * 2 / 3)
 157             {
 158                 /* ignore the click */
 159                 ok = FALSE;
 160             }
 161             else
 162             {
 163                 if (mcview_mouse_move_pages)
 164                     mcview_move_down (view, view->data_area.height / 2);
 165                 else
 166                     mcview_move_down (view, 1);
 167 
 168                 event->result.repeat = msg == MSG_MOUSE_DOWN;
 169             }
 170         }
 171         break;
 172 
 173     case MSG_MOUSE_SCROLL_UP:
 174         mcview_move_up (view, 2);
 175         break;
 176 
 177     case MSG_MOUSE_SCROLL_DOWN:
 178         mcview_move_down (view, 2);
 179         break;
 180 
 181     default:
 182         ok = FALSE;
 183         break;
 184     }
 185 
 186     if (ok)
 187         mcview_update (view);
 188 }
 189 
 190 /* --------------------------------------------------------------------------------------------- */
 191 /*** public functions ****************************************************************************/
 192 /* --------------------------------------------------------------------------------------------- */
 193 
 194 WView *
 195 mcview_new (int y, int x, int lines, int cols, gboolean is_panel)
     /* [previous][next][first][last][top][bottom][index][help]  */
 196 {
 197     WView *view;
 198     Widget *w;
 199 
 200     view = g_new0 (WView, 1);
 201     w = WIDGET (view);
 202     widget_init (w, y, x, lines, cols, mcview_callback, mcview_mouse_callback);
 203     w->options |= WOP_SELECTABLE | WOP_TOP_SELECT;
 204 
 205     mcview_clear_mode_flags (&view->mode_flags);
 206     view->hexedit_mode = FALSE;
 207     view->hexview_in_text = FALSE;
 208     view->locked = FALSE;
 209 
 210     view->dpy_frame_size = is_panel ? 1 : 0;
 211     view->converter = str_cnv_from_term;
 212 
 213     mcview_init (view);
 214 
 215     if (mcview_global_flags.hex)
 216         mcview_toggle_hex_mode (view);
 217     if (mcview_global_flags.nroff)
 218         mcview_toggle_nroff_mode (view);
 219     if (mcview_global_flags.wrap)
 220         mcview_toggle_wrap_mode (view);
 221     if (mcview_global_flags.magic)
 222         mcview_toggle_magic_mode (view);
 223 
 224     return view;
 225 }
 226 
 227 /* --------------------------------------------------------------------------------------------- */
 228 /** Real view only */
 229 
 230 gboolean
 231 mcview_viewer (const char *command, const vfs_path_t * file_vpath, int start_line,
     /* [previous][next][first][last][top][bottom][index][help]  */
 232                off_t search_start, off_t search_end)
 233 {
 234     gboolean succeeded;
 235     WView *lc_mcview;
 236     WDialog *view_dlg;
 237 
 238     /* Create dialog and widgets, put them on the dialog */
 239     view_dlg = dlg_create (FALSE, 0, 0, 1, 1, WPOS_FULLSCREEN, FALSE, NULL, mcview_dialog_callback,
 240                            NULL, "[Internal File Viewer]", NULL);
 241     widget_want_tab (WIDGET (view_dlg), TRUE);
 242 
 243     lc_mcview = mcview_new (0, 0, LINES - 1, COLS, FALSE);
 244     add_widget (view_dlg, lc_mcview);
 245 
 246     add_widget (view_dlg, buttonbar_new (TRUE));
 247 
 248     view_dlg->get_title = mcview_get_title;
 249 
 250     succeeded =
 251         mcview_load (lc_mcview, command, vfs_path_as_str (file_vpath), start_line, search_start,
 252                      search_end);
 253 
 254     if (succeeded)
 255         dlg_run (view_dlg);
 256     else
 257         dlg_stop (view_dlg);
 258 
 259     if (widget_get_state (WIDGET (view_dlg), WST_CLOSED))
 260         dlg_destroy (view_dlg);
 261 
 262     return succeeded;
 263 }
 264 
 265 /* {{{ Miscellaneous functions }}} */
 266 
 267 /* --------------------------------------------------------------------------------------------- */
 268 
 269 gboolean
 270 mcview_load (WView * view, const char *command, const char *file, int start_line,
     /* [previous][next][first][last][top][bottom][index][help]  */
 271              off_t search_start, off_t search_end)
 272 {
 273     gboolean retval = FALSE;
 274     vfs_path_t *vpath = NULL;
 275 
 276     g_assert (view->bytes_per_line != 0);
 277 
 278     view->filename_vpath = vfs_path_from_str (file);
 279 
 280     /* get working dir */
 281     if (file != NULL && file[0] != '\0')
 282     {
 283         vfs_path_free (view->workdir_vpath);
 284 
 285         if (!g_path_is_absolute (file))
 286         {
 287             vfs_path_t *p;
 288 
 289             p = vfs_path_clone (vfs_get_raw_current_dir ());
 290             view->workdir_vpath = vfs_path_append_new (p, file, (char *) NULL);
 291             vfs_path_free (p);
 292         }
 293         else
 294         {
 295             /* try extract path from filename */
 296             const char *fname;
 297             char *dir;
 298 
 299             fname = x_basename (file);
 300             dir = g_strndup (file, (size_t) (fname - file));
 301             view->workdir_vpath = vfs_path_from_str (dir);
 302             g_free (dir);
 303         }
 304     }
 305 
 306     if (!mcview_is_in_panel (view))
 307         view->dpy_text_column = 0;
 308 
 309     mcview_set_codeset (view);
 310 
 311     if (command != NULL && (view->mode_flags.magic || file == NULL || file[0] == '\0'))
 312         retval = mcview_load_command_output (view, command);
 313     else if (file != NULL && file[0] != '\0')
 314     {
 315         int fd;
 316         char tmp[BUF_MEDIUM];
 317         struct stat st;
 318 
 319         /* Open the file */
 320         vpath = vfs_path_from_str (file);
 321         fd = mc_open (vpath, O_RDONLY | O_NONBLOCK);
 322         if (fd == -1)
 323         {
 324             g_snprintf (tmp, sizeof (tmp), _("Cannot open \"%s\"\n%s"),
 325                         file, unix_error_string (errno));
 326             mcview_close_datasource (view);
 327             mcview_show_error (view, tmp);
 328             vfs_path_free (view->filename_vpath);
 329             view->filename_vpath = NULL;
 330             vfs_path_free (view->workdir_vpath);
 331             view->workdir_vpath = NULL;
 332             goto finish;
 333         }
 334 
 335         /* Make sure we are working with a regular file */
 336         if (mc_fstat (fd, &st) == -1)
 337         {
 338             mc_close (fd);
 339             g_snprintf (tmp, sizeof (tmp), _("Cannot stat \"%s\"\n%s"),
 340                         file, unix_error_string (errno));
 341             mcview_close_datasource (view);
 342             mcview_show_error (view, tmp);
 343             vfs_path_free (view->filename_vpath);
 344             view->filename_vpath = NULL;
 345             vfs_path_free (view->workdir_vpath);
 346             view->workdir_vpath = NULL;
 347             goto finish;
 348         }
 349 
 350         if (!S_ISREG (st.st_mode))
 351         {
 352             mc_close (fd);
 353             mcview_close_datasource (view);
 354             mcview_show_error (view, _("Cannot view: not a regular file"));
 355             vfs_path_free (view->filename_vpath);
 356             view->filename_vpath = NULL;
 357             vfs_path_free (view->workdir_vpath);
 358             view->workdir_vpath = NULL;
 359             goto finish;
 360         }
 361 
 362         if (st.st_size == 0 || mc_lseek (fd, 0, SEEK_SET) == -1)
 363         {
 364             /* Must be one of those nice files that grow (/proc) */
 365             mcview_set_datasource_vfs_pipe (view, fd);
 366         }
 367         else
 368         {
 369             if (view->mode_flags.magic)
 370             {
 371                 int type;
 372 
 373                 type = get_compression_type (fd, file);
 374 
 375                 if (type != COMPRESSION_NONE)
 376                 {
 377                     char *tmp_filename;
 378                     vfs_path_t *vpath1;
 379                     int fd1;
 380 
 381                     tmp_filename = g_strconcat (file, decompress_extension (type), (char *) NULL);
 382                     vpath1 = vfs_path_from_str (tmp_filename);
 383                     g_free (tmp_filename);
 384                     fd1 = mc_open (vpath1, O_RDONLY | O_NONBLOCK);
 385                     vfs_path_free (vpath1);
 386 
 387                     if (fd1 == -1)
 388                     {
 389                         g_snprintf (tmp, sizeof (tmp), _("Cannot open \"%s\" in parse mode\n%s"),
 390                                     file, unix_error_string (errno));
 391                         mcview_close_datasource (view);
 392                         mcview_show_error (view, tmp);
 393                     }
 394                     else
 395                     {
 396                         mc_close (fd);
 397                         fd = fd1;
 398                         mc_fstat (fd, &st);
 399                     }
 400                 }
 401             }
 402 
 403             mcview_set_datasource_file (view, fd, &st);
 404         }
 405         retval = TRUE;
 406     }
 407 
 408   finish:
 409     view->command = g_strdup (command);
 410     view->dpy_start = 0;
 411     view->dpy_paragraph_skip_lines = 0;
 412     mcview_state_machine_init (&view->dpy_state_top, 0);
 413     view->dpy_wrap_dirty = FALSE;
 414     view->force_max = -1;
 415     view->dpy_text_column = 0;
 416 
 417     mcview_compute_areas (view);
 418     mcview_update_bytes_per_line (view);
 419 
 420     if (mcview_remember_file_position && view->filename_vpath != NULL && start_line == 0)
 421     {
 422         long line, col;
 423         off_t new_offset, max_offset;
 424 
 425         load_file_position (view->filename_vpath, &line, &col, &new_offset, &view->saved_bookmarks);
 426         max_offset = mcview_get_filesize (view) - 1;
 427         if (max_offset < 0)
 428             new_offset = 0;
 429         else
 430             new_offset = MIN (new_offset, max_offset);
 431         if (!view->mode_flags.hex)
 432         {
 433             view->dpy_start = mcview_bol (view, new_offset, 0);
 434             view->dpy_wrap_dirty = TRUE;
 435         }
 436         else
 437         {
 438             view->dpy_start = new_offset - new_offset % view->bytes_per_line;
 439             view->hex_cursor = new_offset;
 440         }
 441     }
 442     else if (start_line > 0)
 443         mcview_moveto (view, start_line - 1, 0);
 444 
 445     view->search_start = search_start;
 446     view->search_end = search_end;
 447     view->hexedit_lownibble = FALSE;
 448     view->hexview_in_text = FALSE;
 449     view->change_list = NULL;
 450     vfs_path_free (vpath);
 451     return retval;
 452 }
 453 
 454 /* --------------------------------------------------------------------------------------------- */

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