Manual pages: mcmcdiffmceditmcview

root/src/viewer/lib.c

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

DEFINITIONS

This source file includes following definitions.
  1. mcview_toggle_magic_mode
  2. mcview_toggle_wrap_mode
  3. mcview_toggle_nroff_mode
  4. mcview_toggle_hex_mode
  5. mcview_init
  6. mcview_done
  7. mcview_set_codeset
  8. mcview_select_encoding
  9. mcview_show_error
  10. mcview_bol
  11. mcview_eol
  12. mcview_get_title
  13. mcview_calc_percent
  14. mcview_clear_mode_flags

   1 /*
   2    Internal file viewer for the Midnight Commander
   3    Common finctions (used from some other mcviewer functions)
   4 
   5    Copyright (C) 1994-2025
   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-2022
  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 <https://www.gnu.org/licenses/>.
  34  */
  35 
  36 #include <config.h>
  37 
  38 #include <string.h>  // memset()
  39 #include <sys/types.h>
  40 
  41 #include "lib/global.h"
  42 #include "lib/vfs/vfs.h"
  43 #include "lib/strutil.h"
  44 #include "lib/util.h"  // save_file_position()
  45 #include "lib/widget.h"
  46 #include "lib/charsets.h"
  47 
  48 #include "src/selcodepage.h"
  49 #include "src/util.h"  // file_error_message()
  50 
  51 #include "internal.h"
  52 
  53 /*** global variables ****************************************************************************/
  54 
  55 /*** file scope macro definitions ****************************************************************/
  56 
  57 /*** file scope type declarations ****************************************************************/
  58 
  59 /*** file scope variables ************************************************************************/
  60 
  61 /*** file scope functions ************************************************************************/
  62 /* --------------------------------------------------------------------------------------------- */
  63 
  64 /* --------------------------------------------------------------------------------------------- */
  65 /*** public functions ****************************************************************************/
  66 /* --------------------------------------------------------------------------------------------- */
  67 
  68 void
  69 mcview_toggle_magic_mode (WView *view)
     /* [previous][next][first][last][top][bottom][index][help]  */
  70 {
  71     char *filename, *command;
  72     dir_list *dir;
  73     int *dir_idx;
  74 
  75     mcview_altered_flags.magic = TRUE;
  76     view->mode_flags.magic = !view->mode_flags.magic;
  77 
  78     // reinit view
  79     filename = g_strdup (vfs_path_as_str (view->filename_vpath));
  80     command = g_strdup (view->command);
  81     dir = view->dir;
  82     dir_idx = view->dir_idx;
  83     view->dir = NULL;
  84     view->dir_idx = NULL;
  85     mcview_done (view);
  86     mcview_init (view);
  87     mcview_load (view, command, filename, 0, 0, 0);
  88     view->dir = dir;
  89     view->dir_idx = dir_idx;
  90     g_free (filename);
  91     g_free (command);
  92 
  93     view->dpy_bbar_dirty = TRUE;
  94     view->dirty++;
  95 }
  96 
  97 /* --------------------------------------------------------------------------------------------- */
  98 
  99 void
 100 mcview_toggle_wrap_mode (WView *view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 101 {
 102     view->mode_flags.wrap = !view->mode_flags.wrap;
 103     view->dpy_wrap_dirty = TRUE;
 104     view->dpy_bbar_dirty = TRUE;
 105     view->dirty++;
 106 }
 107 
 108 /* --------------------------------------------------------------------------------------------- */
 109 
 110 void
 111 mcview_toggle_nroff_mode (WView *view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 112 {
 113     view->mode_flags.nroff = !view->mode_flags.nroff;
 114     mcview_altered_flags.nroff = TRUE;
 115     view->dpy_wrap_dirty = TRUE;
 116     view->dpy_bbar_dirty = TRUE;
 117     view->dirty++;
 118 }
 119 
 120 /* --------------------------------------------------------------------------------------------- */
 121 
 122 void
 123 mcview_toggle_hex_mode (WView *view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 124 {
 125     view->mode_flags.hex = !view->mode_flags.hex;
 126 
 127     if (view->mode_flags.hex)
 128     {
 129         view->hex_cursor = view->dpy_start;
 130         view->dpy_start = mcview_offset_rounddown (view->dpy_start, view->bytes_per_line);
 131         widget_want_cursor (WIDGET (view), TRUE);
 132     }
 133     else
 134     {
 135         view->dpy_start = mcview_bol (view, view->hex_cursor, 0);
 136         view->hex_cursor = view->dpy_start;
 137         widget_want_cursor (WIDGET (view), FALSE);
 138     }
 139     mcview_altered_flags.hex = TRUE;
 140     view->dpy_paragraph_skip_lines = 0;
 141     view->dpy_wrap_dirty = TRUE;
 142     view->dpy_bbar_dirty = TRUE;
 143     view->dirty++;
 144 }
 145 
 146 /* --------------------------------------------------------------------------------------------- */
 147 
 148 void
 149 mcview_init (WView *view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 150 {
 151     size_t i;
 152 
 153     view->filename_vpath = NULL;
 154     view->workdir_vpath = NULL;
 155     view->command = NULL;
 156     view->search_nroff_seq = NULL;
 157 
 158     mcview_set_datasource_none (view);
 159 
 160     view->growbuf_in_use = FALSE;
 161     // leave the other growbuf fields uninitialized
 162 
 163     view->hexedit_lownibble = FALSE;
 164     view->locked = FALSE;
 165     view->coord_cache = NULL;
 166 
 167     view->dpy_start = 0;
 168     view->dpy_paragraph_skip_lines = 0;
 169     mcview_state_machine_init (&view->dpy_state_top, 0);
 170     view->dpy_wrap_dirty = FALSE;
 171     view->force_max = -1;
 172     view->dpy_text_column = 0;
 173     view->dpy_end = 0;
 174     view->hex_cursor = 0;
 175     view->cursor_col = 0;
 176     view->cursor_row = 0;
 177     view->change_list = NULL;
 178 
 179     // {status,ruler,data}_area are left uninitialized
 180 
 181     view->dirty = 0;
 182     view->dpy_bbar_dirty = TRUE;
 183     view->bytes_per_line = 1;
 184 
 185     view->search_start = 0;
 186     view->search_end = 0;
 187 
 188     view->marker = 0;
 189     for (i = 0; i < G_N_ELEMENTS (view->marks); i++)
 190         view->marks[i] = 0;
 191 
 192     view->update_steps = 0;
 193     view->update_activate = 0;
 194 
 195     view->saved_bookmarks = NULL;
 196 }
 197 
 198 /* --------------------------------------------------------------------------------------------- */
 199 
 200 void
 201 mcview_done (WView *view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 202 {
 203     // Save current file position
 204     if (mcview_remember_file_position && view->filename_vpath != NULL)
 205     {
 206         save_file_position (view->filename_vpath, -1, 0,
 207                             view->mode_flags.hex ? view->hex_cursor : view->dpy_start,
 208                             view->saved_bookmarks);
 209         view->saved_bookmarks = NULL;
 210     }
 211 
 212     // Write back the global viewer mode
 213     mcview_global_flags = view->mode_flags;
 214 
 215     // Free memory used by the viewer
 216     // view->widget needs no destructor
 217     vfs_path_free (view->filename_vpath, TRUE);
 218     view->filename_vpath = NULL;
 219     vfs_path_free (view->workdir_vpath, TRUE);
 220     view->workdir_vpath = NULL;
 221     MC_PTR_FREE (view->command);
 222 
 223     mcview_close_datasource (view);
 224     // the growing buffer is freed with the datasource
 225 
 226     if (view->coord_cache != NULL)
 227     {
 228         g_ptr_array_free (view->coord_cache, TRUE);
 229         view->coord_cache = NULL;
 230     }
 231 
 232     if (view->converter == INVALID_CONV)
 233         view->converter = str_cnv_from_term;
 234 
 235     if (view->converter != str_cnv_from_term)
 236     {
 237         str_close_conv (view->converter);
 238         view->converter = str_cnv_from_term;
 239     }
 240 
 241     mcview_search_deinit (view);
 242     view->search = NULL;
 243     view->last_search_string = NULL;
 244     mcview_hexedit_free_change_list (view);
 245 
 246     if (mc_global.mc_run_mode == MC_RUN_VIEWER && view->dir != NULL)
 247     {
 248         // mcviewer is the owner of file list
 249         dir_list_free_list (view->dir);
 250         g_free (view->dir);
 251         g_free (view->dir_idx);
 252     }
 253 
 254     view->dir = NULL;
 255 }
 256 
 257 /* --------------------------------------------------------------------------------------------- */
 258 
 259 void
 260 mcview_set_codeset (WView *view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 261 {
 262     const char *cp_id = NULL;
 263 
 264     view->utf8 = TRUE;
 265     cp_id = get_codepage_id (mc_global.source_codepage >= 0 ? mc_global.source_codepage
 266                                                             : mc_global.display_codepage);
 267     if (cp_id != NULL)
 268     {
 269         GIConv conv;
 270         conv = str_crt_conv_from (cp_id);
 271         if (conv != INVALID_CONV)
 272         {
 273             if (view->converter != str_cnv_from_term)
 274                 str_close_conv (view->converter);
 275             view->converter = conv;
 276         }
 277         view->utf8 = (gboolean) str_isutf8 (cp_id);
 278         view->dpy_wrap_dirty = TRUE;
 279     }
 280 }
 281 
 282 /* --------------------------------------------------------------------------------------------- */
 283 
 284 void
 285 mcview_select_encoding (WView *view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 286 {
 287     if (do_select_codepage ())
 288         mcview_set_codeset (view);
 289 }
 290 
 291 /* --------------------------------------------------------------------------------------------- */
 292 
 293 void
 294 mcview_show_error (WView *view, const char *format, const char *filename)
     /* [previous][next][first][last][top][bottom][index][help]  */
 295 {
 296     if (mcview_is_in_panel (view))
 297         mcview_set_datasource_string (view, filename);
 298     else if (format != NULL)
 299         file_error_message (format, filename);
 300     else
 301         message (D_ERROR, MSG_ERROR, "%s", filename);
 302 }
 303 
 304 /* --------------------------------------------------------------------------------------------- */
 305 /** returns index of the first char in the line
 306  * it is constant for all line characters
 307  */
 308 
 309 off_t
 310 mcview_bol (WView *view, off_t current, off_t limit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 311 {
 312     int c;
 313 
 314     if (current <= 0)
 315         return 0;
 316 
 317     const off_t filesize = mcview_get_filesize (view);
 318 
 319     if (current > filesize)
 320         return filesize;
 321 
 322     if (!mcview_get_byte (view, current, &c))
 323         return current;
 324 
 325     if (c == '\n')
 326     {
 327         if (!mcview_get_byte (view, current - 1, &c))
 328             return current;
 329 
 330         if (c == '\r')
 331             current--;
 332     }
 333 
 334     for (; current > 0 && current > limit; current--)
 335     {
 336         if (!mcview_get_byte (view, current - 1, &c))
 337             break;
 338         if (c == '\r' || c == '\n')
 339             break;
 340     }
 341 
 342     return current;
 343 }
 344 
 345 /* --------------------------------------------------------------------------------------------- */
 346 /** returns index of last char on line + width EOL
 347  * mcview_eol of the current line == mcview_bol next line
 348  */
 349 
 350 off_t
 351 mcview_eol (WView *view, off_t current)
     /* [previous][next][first][last][top][bottom][index][help]  */
 352 {
 353     int c;
 354     int prev_ch = 0;
 355 
 356     if (current < 0)
 357         return 0;
 358 
 359     for (; mcview_get_byte (view, current, &c); current++)
 360     {
 361         if (c == '\n')
 362         {
 363             current++;
 364             break;
 365         }
 366         if (prev_ch == '\r')
 367             break;
 368 
 369         prev_ch = c;
 370     }
 371 
 372     return current;
 373 }
 374 
 375 /* --------------------------------------------------------------------------------------------- */
 376 
 377 char *
 378 mcview_get_title (const WDialog *h, const ssize_t width)
     /* [previous][next][first][last][top][bottom][index][help]  */
 379 {
 380     const WView *view;
 381     const char *modified;
 382     const char *file_label;
 383     const char *view_filename;
 384 
 385     view = (const WView *) widget_find_by_type (CONST_WIDGET (h), mcview_callback);
 386     modified = view->hexedit_mode && (view->change_list != NULL) ? "(*) " : "    ";
 387     view_filename = vfs_path_as_str (view->filename_vpath);
 388 
 389     const ssize_t width1 = width - 4;
 390 
 391     file_label = view_filename != NULL ? view_filename : view->command != NULL ? view->command : "";
 392     file_label = str_term_trim (file_label, width1 - str_term_width1 (_ ("View: ")));
 393 
 394     return g_strconcat (_ ("View: "), modified, file_label, (char *) NULL);
 395 }
 396 
 397 /* --------------------------------------------------------------------------------------------- */
 398 
 399 int
 400 mcview_calc_percent (WView *view, off_t p)
     /* [previous][next][first][last][top][bottom][index][help]  */
 401 {
 402     off_t filesize;
 403     int percent;
 404 
 405     if (view->status_area.cols < 1 || (view->status_area.x + view->status_area.cols) < 4)
 406         return (-1);
 407     if (mcview_may_still_grow (view))
 408         return (-1);
 409 
 410     filesize = mcview_get_filesize (view);
 411     if (view->mode_flags.hex && filesize > 0)
 412     {
 413         // p can't be beyond the last char, only over that. Compensate for this.
 414         filesize--;
 415     }
 416 
 417     if (filesize == 0 || p >= filesize)
 418         percent = 100;
 419     else if (p > (INT_MAX / 100))
 420         percent = p / (filesize / 100);
 421     else
 422         percent = p * 100 / filesize;
 423 
 424     return percent;
 425 }
 426 
 427 /* --------------------------------------------------------------------------------------------- */
 428 
 429 void
 430 mcview_clear_mode_flags (mcview_mode_flags_t *flags)
     /* [previous][next][first][last][top][bottom][index][help]  */
 431 {
 432     memset (flags, 0, sizeof (*flags));
 433 }
 434 
 435 /* --------------------------------------------------------------------------------------------- */

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