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

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