2 Internal file viewer for the Midnight Commander
3 Common finctions (used from some other mcviewer functions)
5 Copyright (C) 1994-2024
6 Free Software Foundation, Inc.
9 Miguel de Icaza, 1994, 1995, 1998
10 Janne Kukonlehto, 1994, 1995
12 Joseph M. Hinkle, 1996
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
20 This file is part of the Midnight Commander.
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.
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.
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/>.
38 #include <string.h> /* memset() */
39 #include <sys/types.h>
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"
47 #include "lib/charsets.h"
51 #include "src/selcodepage.h"
56 /*** global variables ****************************************************************************/
58 /*** file scope macro definitions ****************************************************************/
60 /*** file scope type declarations ****************************************************************/
62 /*** file scope variables ************************************************************************/
64 /*** file scope functions ************************************************************************/
65 /* --------------------------------------------------------------------------------------------- */
67 /* --------------------------------------------------------------------------------------------- */
68 /*** public functions ****************************************************************************/
69 /* --------------------------------------------------------------------------------------------- */
72 mcview_toggle_magic_mode (WView
*view
)
74 char *filename
, *command
;
78 mcview_altered_flags
.magic
= TRUE
;
79 view
->mode_flags
.magic
= !view
->mode_flags
.magic
;
82 filename
= g_strdup (vfs_path_as_str (view
->filename_vpath
));
83 command
= g_strdup (view
->command
);
85 dir_idx
= view
->dir_idx
;
90 mcview_load (view
, command
, filename
, 0, 0, 0);
92 view
->dir_idx
= dir_idx
;
96 view
->dpy_bbar_dirty
= TRUE
;
100 /* --------------------------------------------------------------------------------------------- */
103 mcview_toggle_wrap_mode (WView
*view
)
105 view
->mode_flags
.wrap
= !view
->mode_flags
.wrap
;
106 view
->dpy_wrap_dirty
= TRUE
;
107 view
->dpy_bbar_dirty
= TRUE
;
111 /* --------------------------------------------------------------------------------------------- */
114 mcview_toggle_nroff_mode (WView
*view
)
116 view
->mode_flags
.nroff
= !view
->mode_flags
.nroff
;
117 mcview_altered_flags
.nroff
= TRUE
;
118 view
->dpy_wrap_dirty
= TRUE
;
119 view
->dpy_bbar_dirty
= TRUE
;
123 /* --------------------------------------------------------------------------------------------- */
126 mcview_toggle_hex_mode (WView
*view
)
128 view
->mode_flags
.hex
= !view
->mode_flags
.hex
;
130 if (view
->mode_flags
.hex
)
132 view
->hex_cursor
= view
->dpy_start
;
133 view
->dpy_start
= mcview_offset_rounddown (view
->dpy_start
, view
->bytes_per_line
);
134 widget_want_cursor (WIDGET (view
), TRUE
);
138 view
->dpy_start
= mcview_bol (view
, view
->hex_cursor
, 0);
139 view
->hex_cursor
= view
->dpy_start
;
140 widget_want_cursor (WIDGET (view
), FALSE
);
142 mcview_altered_flags
.hex
= TRUE
;
143 view
->dpy_paragraph_skip_lines
= 0;
144 view
->dpy_wrap_dirty
= TRUE
;
145 view
->dpy_bbar_dirty
= TRUE
;
149 /* --------------------------------------------------------------------------------------------- */
152 mcview_init (WView
*view
)
156 view
->filename_vpath
= NULL
;
157 view
->workdir_vpath
= NULL
;
158 view
->command
= NULL
;
159 view
->search_nroff_seq
= NULL
;
161 mcview_set_datasource_none (view
);
163 view
->growbuf_in_use
= FALSE
;
164 /* leave the other growbuf fields uninitialized */
166 view
->hexedit_lownibble
= FALSE
;
167 view
->locked
= FALSE
;
168 view
->coord_cache
= NULL
;
171 view
->dpy_paragraph_skip_lines
= 0;
172 mcview_state_machine_init (&view
->dpy_state_top
, 0);
173 view
->dpy_wrap_dirty
= FALSE
;
174 view
->force_max
= -1;
175 view
->dpy_text_column
= 0;
177 view
->hex_cursor
= 0;
178 view
->cursor_col
= 0;
179 view
->cursor_row
= 0;
180 view
->change_list
= NULL
;
182 /* {status,ruler,data}_area are left uninitialized */
185 view
->dpy_bbar_dirty
= TRUE
;
186 view
->bytes_per_line
= 1;
188 view
->search_start
= 0;
189 view
->search_end
= 0;
192 for (i
= 0; i
< G_N_ELEMENTS (view
->marks
); i
++)
195 view
->update_steps
= 0;
196 view
->update_activate
= 0;
198 view
->saved_bookmarks
= NULL
;
201 /* --------------------------------------------------------------------------------------------- */
204 mcview_done (WView
*view
)
206 /* Save current file position */
207 if (mcview_remember_file_position
&& view
->filename_vpath
!= NULL
)
209 save_file_position (view
->filename_vpath
, -1, 0,
210 view
->mode_flags
.hex
? view
->hex_cursor
: view
->dpy_start
,
211 view
->saved_bookmarks
);
212 view
->saved_bookmarks
= NULL
;
215 /* Write back the global viewer mode */
216 mcview_global_flags
= view
->mode_flags
;
218 /* Free memory used by the viewer */
219 /* view->widget needs no destructor */
220 vfs_path_free (view
->filename_vpath
, TRUE
);
221 view
->filename_vpath
= NULL
;
222 vfs_path_free (view
->workdir_vpath
, TRUE
);
223 view
->workdir_vpath
= NULL
;
224 MC_PTR_FREE (view
->command
);
226 mcview_close_datasource (view
);
227 /* the growing buffer is freed with the datasource */
229 if (view
->coord_cache
!= NULL
)
231 g_ptr_array_free (view
->coord_cache
, TRUE
);
232 view
->coord_cache
= NULL
;
235 if (view
->converter
== INVALID_CONV
)
236 view
->converter
= str_cnv_from_term
;
238 if (view
->converter
!= str_cnv_from_term
)
240 str_close_conv (view
->converter
);
241 view
->converter
= str_cnv_from_term
;
244 mcview_search_deinit (view
);
246 view
->last_search_string
= NULL
;
247 mcview_hexedit_free_change_list (view
);
249 if (mc_global
.mc_run_mode
== MC_RUN_VIEWER
&& view
->dir
!= NULL
)
251 /* mcviewer is the owner of file list */
252 dir_list_free_list (view
->dir
);
254 g_free (view
->dir_idx
);
260 /* --------------------------------------------------------------------------------------------- */
264 mcview_set_codeset (WView
*view
)
266 const char *cp_id
= NULL
;
270 get_codepage_id (mc_global
.source_codepage
>=
271 0 ? mc_global
.source_codepage
: mc_global
.display_codepage
);
275 conv
= str_crt_conv_from (cp_id
);
276 if (conv
!= INVALID_CONV
)
278 if (view
->converter
!= str_cnv_from_term
)
279 str_close_conv (view
->converter
);
280 view
->converter
= conv
;
282 view
->utf8
= (gboolean
) str_isutf8 (cp_id
);
283 view
->dpy_wrap_dirty
= TRUE
;
287 /* --------------------------------------------------------------------------------------------- */
290 mcview_select_encoding (WView
*view
)
292 if (do_select_codepage ())
293 mcview_set_codeset (view
);
295 #endif /* HAVE_CHARSET */
297 /* --------------------------------------------------------------------------------------------- */
300 mcview_show_error (WView
*view
, const char *msg
)
302 if (mcview_is_in_panel (view
))
303 mcview_set_datasource_string (view
, msg
);
305 message (D_ERROR
, MSG_ERROR
, "%s", msg
);
308 /* --------------------------------------------------------------------------------------------- */
309 /** returns index of the first char in the line
310 * it is constant for all line characters
314 mcview_bol (WView
*view
, off_t current
, off_t limit
)
318 filesize
= mcview_get_filesize (view
);
321 if (current
> filesize
)
323 if (!mcview_get_byte (view
, current
, &c
))
327 if (!mcview_get_byte (view
, current
- 1, &c
))
332 while (current
> 0 && current
> limit
)
334 if (!mcview_get_byte (view
, current
- 1, &c
))
336 if (c
== '\r' || c
== '\n')
343 /* --------------------------------------------------------------------------------------------- */
344 /** returns index of last char on line + width EOL
345 * mcview_eol of the current line == mcview_bol next line
349 mcview_eol (WView
*view
, off_t current
)
358 if (!mcview_get_byte (view
, current
, &c
))
365 else if (prev_ch
== '\r')
375 /* --------------------------------------------------------------------------------------------- */
378 mcview_get_title (const WDialog
*h
, size_t len
)
381 const char *modified
;
382 const char *file_label
;
383 const char *view_filename
;
386 view
= (const WView
*) widget_find_by_type (CONST_WIDGET (h
), mcview_callback
);
387 modified
= view
->hexedit_mode
&& (view
->change_list
!= NULL
) ? "(*) " : " ";
388 view_filename
= vfs_path_as_str (view
->filename_vpath
);
392 file_label
= view_filename
!= NULL
? view_filename
: view
->command
!= NULL
? view
->command
: "";
393 file_label
= str_term_trim (file_label
, len
- str_term_width1 (_("View: ")));
395 ret_str
= g_strconcat (_("View: "), modified
, file_label
, (char *) NULL
);
399 /* --------------------------------------------------------------------------------------------- */
402 mcview_calc_percent (WView
*view
, off_t p
)
407 if (view
->status_area
.cols
< 1 || (view
->status_area
.x
+ view
->status_area
.cols
) < 4)
409 if (mcview_may_still_grow (view
))
412 filesize
= mcview_get_filesize (view
);
413 if (view
->mode_flags
.hex
&& filesize
> 0)
415 /* p can't be beyond the last char, only over that. Compensate for this. */
419 if (filesize
== 0 || p
>= filesize
)
421 else if (p
> (INT_MAX
/ 100))
422 percent
= p
/ (filesize
/ 100);
424 percent
= p
* 100 / filesize
;
429 /* --------------------------------------------------------------------------------------------- */
432 mcview_clear_mode_flags (mcview_mode_flags_t
*flags
)
434 memset (flags
, 0, sizeof (*flags
));
437 /* --------------------------------------------------------------------------------------------- */