summaryrefslogtreecommitdiffstats
path: root/src/viewer/lib.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/viewer/lib.c')
-rw-r--r--src/viewer/lib.c437
1 files changed, 437 insertions, 0 deletions
diff --git a/src/viewer/lib.c b/src/viewer/lib.c
new file mode 100644
index 0000000..5f2eb52
--- /dev/null
+++ b/src/viewer/lib.c
@@ -0,0 +1,437 @@
+/*
+ Internal file viewer for the Midnight Commander
+ Common finctions (used from some other mcviewer functions)
+
+ Copyright (C) 1994-2023
+ Free Software Foundation, Inc.
+
+ Written by:
+ Miguel de Icaza, 1994, 1995, 1998
+ Janne Kukonlehto, 1994, 1995
+ Jakub Jelinek, 1995
+ Joseph M. Hinkle, 1996
+ Norbert Warmuth, 1997
+ Pavel Machek, 1998
+ Roland Illig <roland.illig@gmx.de>, 2004, 2005
+ Slava Zanko <slavazanko@google.com>, 2009, 2013
+ Andrew Borodin <aborodin@vmail.ru>, 2009-2022
+ Ilia Maslakov <il.smind@gmail.com>, 2009
+
+ This file is part of the Midnight Commander.
+
+ The Midnight Commander is free software: you can redistribute it
+ and/or modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 3 of the License,
+ or (at your option) any later version.
+
+ The Midnight Commander is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <string.h> /* memset() */
+#include <sys/types.h>
+
+#include "lib/global.h"
+#include "lib/vfs/vfs.h"
+#include "lib/strutil.h"
+#include "lib/util.h" /* save_file_position() */
+#include "lib/widget.h"
+#ifdef HAVE_CHARSET
+#include "lib/charsets.h"
+#endif
+
+#ifdef HAVE_CHARSET
+#include "src/selcodepage.h"
+#endif
+
+#include "internal.h"
+
+/*** global variables ****************************************************************************/
+
+/*** file scope macro definitions ****************************************************************/
+
+/*** file scope type declarations ****************************************************************/
+
+/*** file scope variables ************************************************************************/
+
+/*** file scope functions ************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+/* --------------------------------------------------------------------------------------------- */
+/*** public functions ****************************************************************************/
+/* --------------------------------------------------------------------------------------------- */
+
+void
+mcview_toggle_magic_mode (WView * view)
+{
+ char *filename, *command;
+ dir_list *dir;
+ int *dir_idx;
+
+ mcview_altered_flags.magic = TRUE;
+ view->mode_flags.magic = !view->mode_flags.magic;
+
+ /* reinit view */
+ filename = g_strdup (vfs_path_as_str (view->filename_vpath));
+ command = g_strdup (view->command);
+ dir = view->dir;
+ dir_idx = view->dir_idx;
+ view->dir = NULL;
+ view->dir_idx = NULL;
+ mcview_done (view);
+ mcview_init (view);
+ mcview_load (view, command, filename, 0, 0, 0);
+ view->dir = dir;
+ view->dir_idx = dir_idx;
+ g_free (filename);
+ g_free (command);
+
+ view->dpy_bbar_dirty = TRUE;
+ view->dirty++;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+mcview_toggle_wrap_mode (WView * view)
+{
+ view->mode_flags.wrap = !view->mode_flags.wrap;
+ view->dpy_wrap_dirty = TRUE;
+ view->dpy_bbar_dirty = TRUE;
+ view->dirty++;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+mcview_toggle_nroff_mode (WView * view)
+{
+ view->mode_flags.nroff = !view->mode_flags.nroff;
+ mcview_altered_flags.nroff = TRUE;
+ view->dpy_wrap_dirty = TRUE;
+ view->dpy_bbar_dirty = TRUE;
+ view->dirty++;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+mcview_toggle_hex_mode (WView * view)
+{
+ view->mode_flags.hex = !view->mode_flags.hex;
+
+ if (view->mode_flags.hex)
+ {
+ view->hex_cursor = view->dpy_start;
+ view->dpy_start = mcview_offset_rounddown (view->dpy_start, view->bytes_per_line);
+ widget_want_cursor (WIDGET (view), TRUE);
+ }
+ else
+ {
+ view->dpy_start = mcview_bol (view, view->hex_cursor, 0);
+ view->hex_cursor = view->dpy_start;
+ widget_want_cursor (WIDGET (view), FALSE);
+ }
+ mcview_altered_flags.hex = TRUE;
+ view->dpy_paragraph_skip_lines = 0;
+ view->dpy_wrap_dirty = TRUE;
+ view->dpy_bbar_dirty = TRUE;
+ view->dirty++;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+mcview_init (WView * view)
+{
+ size_t i;
+
+ view->filename_vpath = NULL;
+ view->workdir_vpath = NULL;
+ view->command = NULL;
+ view->search_nroff_seq = NULL;
+
+ mcview_set_datasource_none (view);
+
+ view->growbuf_in_use = FALSE;
+ /* leave the other growbuf fields uninitialized */
+
+ view->hexedit_lownibble = FALSE;
+ view->locked = FALSE;
+ view->coord_cache = NULL;
+
+ view->dpy_start = 0;
+ view->dpy_paragraph_skip_lines = 0;
+ mcview_state_machine_init (&view->dpy_state_top, 0);
+ view->dpy_wrap_dirty = FALSE;
+ view->force_max = -1;
+ view->dpy_text_column = 0;
+ view->dpy_end = 0;
+ view->hex_cursor = 0;
+ view->cursor_col = 0;
+ view->cursor_row = 0;
+ view->change_list = NULL;
+
+ /* {status,ruler,data}_area are left uninitialized */
+
+ view->dirty = 0;
+ view->dpy_bbar_dirty = TRUE;
+ view->bytes_per_line = 1;
+
+ view->search_start = 0;
+ view->search_end = 0;
+
+ view->marker = 0;
+ for (i = 0; i < G_N_ELEMENTS (view->marks); i++)
+ view->marks[i] = 0;
+
+ view->update_steps = 0;
+ view->update_activate = 0;
+
+ view->saved_bookmarks = NULL;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+mcview_done (WView * view)
+{
+ /* Save current file position */
+ if (mcview_remember_file_position && view->filename_vpath != NULL)
+ {
+ save_file_position (view->filename_vpath, -1, 0,
+ view->mode_flags.hex ? view->hex_cursor : view->dpy_start,
+ view->saved_bookmarks);
+ view->saved_bookmarks = NULL;
+ }
+
+ /* Write back the global viewer mode */
+ mcview_global_flags = view->mode_flags;
+
+ /* Free memory used by the viewer */
+ /* view->widget needs no destructor */
+ vfs_path_free (view->filename_vpath, TRUE);
+ view->filename_vpath = NULL;
+ vfs_path_free (view->workdir_vpath, TRUE);
+ view->workdir_vpath = NULL;
+ MC_PTR_FREE (view->command);
+
+ mcview_close_datasource (view);
+ /* the growing buffer is freed with the datasource */
+
+ if (view->coord_cache != NULL)
+ {
+ g_ptr_array_free (view->coord_cache, TRUE);
+ view->coord_cache = NULL;
+ }
+
+ if (view->converter == INVALID_CONV)
+ view->converter = str_cnv_from_term;
+
+ if (view->converter != str_cnv_from_term)
+ {
+ str_close_conv (view->converter);
+ view->converter = str_cnv_from_term;
+ }
+
+ mcview_search_deinit (view);
+ view->search = NULL;
+ view->last_search_string = NULL;
+ mcview_hexedit_free_change_list (view);
+
+ if (mc_global.mc_run_mode == MC_RUN_VIEWER && view->dir != NULL)
+ {
+ /* mcviewer is the owner of file list */
+ dir_list_free_list (view->dir);
+ g_free (view->dir);
+ g_free (view->dir_idx);
+ }
+
+ view->dir = NULL;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+#ifdef HAVE_CHARSET
+void
+mcview_set_codeset (WView * view)
+{
+ const char *cp_id = NULL;
+
+ view->utf8 = TRUE;
+ cp_id =
+ get_codepage_id (mc_global.source_codepage >=
+ 0 ? mc_global.source_codepage : mc_global.display_codepage);
+ if (cp_id != NULL)
+ {
+ GIConv conv;
+ conv = str_crt_conv_from (cp_id);
+ if (conv != INVALID_CONV)
+ {
+ if (view->converter != str_cnv_from_term)
+ str_close_conv (view->converter);
+ view->converter = conv;
+ }
+ view->utf8 = (gboolean) str_isutf8 (cp_id);
+ view->dpy_wrap_dirty = TRUE;
+ }
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+mcview_select_encoding (WView * view)
+{
+ if (do_select_codepage ())
+ mcview_set_codeset (view);
+}
+#endif /* HAVE_CHARSET */
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+mcview_show_error (WView * view, const char *msg)
+{
+ if (mcview_is_in_panel (view))
+ mcview_set_datasource_string (view, msg);
+ else
+ message (D_ERROR, MSG_ERROR, "%s", msg);
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/** returns index of the first char in the line
+ * it is constant for all line characters
+ */
+
+off_t
+mcview_bol (WView * view, off_t current, off_t limit)
+{
+ int c;
+ off_t filesize;
+ filesize = mcview_get_filesize (view);
+ if (current <= 0)
+ return 0;
+ if (current > filesize)
+ return filesize;
+ if (!mcview_get_byte (view, current, &c))
+ return current;
+ if (c == '\n')
+ {
+ if (!mcview_get_byte (view, current - 1, &c))
+ return current;
+ if (c == '\r')
+ current--;
+ }
+ while (current > 0 && current > limit)
+ {
+ if (!mcview_get_byte (view, current - 1, &c))
+ break;
+ if (c == '\r' || c == '\n')
+ break;
+ current--;
+ }
+ return current;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+/** returns index of last char on line + width EOL
+ * mcview_eol of the current line == mcview_bol next line
+ */
+
+off_t
+mcview_eol (WView * view, off_t current)
+{
+ int c, prev_ch = 0;
+
+ if (current < 0)
+ return 0;
+
+ while (TRUE)
+ {
+ if (!mcview_get_byte (view, current, &c))
+ break;
+ if (c == '\n')
+ {
+ current++;
+ break;
+ }
+ else if (prev_ch == '\r')
+ {
+ break;
+ }
+ current++;
+ prev_ch = c;
+ }
+ return current;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+char *
+mcview_get_title (const WDialog * h, size_t len)
+{
+ const WView *view;
+ const char *modified;
+ const char *file_label;
+ const char *view_filename;
+ char *ret_str;
+
+ view = (const WView *) widget_find_by_type (CONST_WIDGET (h), mcview_callback);
+ modified = view->hexedit_mode && (view->change_list != NULL) ? "(*) " : " ";
+ view_filename = vfs_path_as_str (view->filename_vpath);
+
+ len -= 4;
+
+ file_label = view_filename != NULL ? view_filename : view->command != NULL ? view->command : "";
+ file_label = str_term_trim (file_label, len - str_term_width1 (_("View: ")));
+
+ ret_str = g_strconcat (_("View: "), modified, file_label, (char *) NULL);
+ return ret_str;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+int
+mcview_calc_percent (WView * view, off_t p)
+{
+ off_t filesize;
+ int percent;
+
+ if (view->status_area.cols < 1 || (view->status_area.x + view->status_area.cols) < 4)
+ return (-1);
+ if (mcview_may_still_grow (view))
+ return (-1);
+
+ filesize = mcview_get_filesize (view);
+ if (view->mode_flags.hex && filesize > 0)
+ {
+ /* p can't be beyond the last char, only over that. Compensate for this. */
+ filesize--;
+ }
+
+ if (filesize == 0 || p >= filesize)
+ percent = 100;
+ else if (p > (INT_MAX / 100))
+ percent = p / (filesize / 100);
+ else
+ percent = p * 100 / filesize;
+
+ return percent;
+}
+
+/* --------------------------------------------------------------------------------------------- */
+
+void
+mcview_clear_mode_flags (mcview_mode_flags_t * flags)
+{
+ memset (flags, 0, sizeof (*flags));
+}
+
+/* --------------------------------------------------------------------------------------------- */