2 Internal file viewer for the Midnight Commander
3 Common finctions (used from some other mcviewer functions)
5 Copyright (C) 1994-2017
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, 2013, 2014
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/>.
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 #define OFF_T_BITWIDTH (unsigned int) (sizeof (off_t) * CHAR_BIT - 1)
59 const off_t OFFSETTYPE_MAX
= ((off_t
) 1 << (OFF_T_BITWIDTH
- 1)) - 1;
61 /*** file scope macro definitions ****************************************************************/
63 /*** file scope type declarations ****************************************************************/
65 /*** file scope variables ************************************************************************/
67 /*** file scope functions ************************************************************************/
68 /* --------------------------------------------------------------------------------------------- */
70 /* --------------------------------------------------------------------------------------------- */
71 /*** public functions ****************************************************************************/
72 /* --------------------------------------------------------------------------------------------- */
75 mcview_toggle_magic_mode (WView
* view
)
77 char *filename
, *command
;
81 mcview_altered_magic_flag
= 1;
82 view
->magic_mode
= !view
->magic_mode
;
85 filename
= g_strdup (vfs_path_as_str (view
->filename_vpath
));
86 command
= g_strdup (view
->command
);
88 dir_idx
= view
->dir_idx
;
93 mcview_load (view
, command
, filename
, 0, 0, 0);
95 view
->dir_idx
= dir_idx
;
99 view
->dpy_bbar_dirty
= TRUE
;
103 /* --------------------------------------------------------------------------------------------- */
106 mcview_toggle_wrap_mode (WView
* view
)
108 view
->text_wrap_mode
= !view
->text_wrap_mode
;
109 view
->dpy_wrap_dirty
= TRUE
;
110 view
->dpy_bbar_dirty
= TRUE
;
114 /* --------------------------------------------------------------------------------------------- */
117 mcview_toggle_nroff_mode (WView
* view
)
119 view
->text_nroff_mode
= !view
->text_nroff_mode
;
120 mcview_altered_nroff_flag
= 1;
121 view
->dpy_wrap_dirty
= TRUE
;
122 view
->dpy_bbar_dirty
= TRUE
;
126 /* --------------------------------------------------------------------------------------------- */
129 mcview_toggle_hex_mode (WView
* view
)
131 view
->hex_mode
= !view
->hex_mode
;
135 view
->hex_cursor
= view
->dpy_start
;
136 view
->dpy_start
= mcview_offset_rounddown (view
->dpy_start
, view
->bytes_per_line
);
137 widget_want_cursor (WIDGET (view
), TRUE
);
141 view
->dpy_start
= mcview_bol (view
, view
->hex_cursor
, 0);
142 view
->hex_cursor
= view
->dpy_start
;
143 widget_want_cursor (WIDGET (view
), FALSE
);
145 mcview_altered_hex_mode
= 1;
146 view
->dpy_paragraph_skip_lines
= 0;
147 view
->dpy_wrap_dirty
= TRUE
;
148 view
->dpy_bbar_dirty
= TRUE
;
152 /* --------------------------------------------------------------------------------------------- */
155 mcview_init (WView
* view
)
159 view
->filename_vpath
= NULL
;
160 view
->workdir_vpath
= NULL
;
161 view
->command
= NULL
;
162 view
->search_nroff_seq
= NULL
;
164 mcview_set_datasource_none (view
);
166 view
->growbuf_in_use
= FALSE
;
167 /* leave the other growbuf fields uninitialized */
169 view
->hexedit_lownibble
= FALSE
;
170 view
->locked
= FALSE
;
171 view
->coord_cache
= NULL
;
174 view
->dpy_paragraph_skip_lines
= 0;
175 mcview_state_machine_init (&view
->dpy_state_top
, 0);
176 view
->dpy_wrap_dirty
= FALSE
;
177 view
->force_max
= -1;
178 view
->dpy_text_column
= 0;
180 view
->hex_cursor
= 0;
181 view
->cursor_col
= 0;
182 view
->cursor_row
= 0;
183 view
->change_list
= NULL
;
185 /* {status,ruler,data}_area are left uninitialized */
188 view
->dpy_bbar_dirty
= TRUE
;
189 view
->bytes_per_line
= 1;
191 view
->search_start
= 0;
192 view
->search_end
= 0;
195 for (i
= 0; i
< G_N_ELEMENTS (view
->marks
); i
++)
198 view
->update_steps
= 0;
199 view
->update_activate
= 0;
201 view
->saved_bookmarks
= NULL
;
204 /* --------------------------------------------------------------------------------------------- */
207 mcview_done (WView
* view
)
209 /* Save current file position */
210 if (mcview_remember_file_position
&& view
->filename_vpath
!= NULL
)
212 save_file_position (view
->filename_vpath
, -1, 0,
213 view
->hex_mode
? view
->hex_cursor
: view
->dpy_start
,
214 view
->saved_bookmarks
);
215 view
->saved_bookmarks
= NULL
;
218 /* Write back the global viewer mode */
219 mcview_default_hex_mode
= view
->hex_mode
;
220 mcview_default_nroff_flag
= view
->text_nroff_mode
;
221 mcview_default_magic_flag
= view
->magic_mode
;
222 mcview_global_wrap_mode
= view
->text_wrap_mode
;
224 /* Free memory used by the viewer */
226 /* view->widget needs no destructor */
228 vfs_path_free (view
->filename_vpath
);
229 view
->filename_vpath
= NULL
;
230 vfs_path_free (view
->workdir_vpath
);
231 view
->workdir_vpath
= NULL
;
232 MC_PTR_FREE (view
->command
);
234 mcview_close_datasource (view
);
235 /* the growing buffer is freed with the datasource */
237 coord_cache_free (view
->coord_cache
);
238 view
->coord_cache
= NULL
;
240 if (view
->converter
== INVALID_CONV
)
241 view
->converter
= str_cnv_from_term
;
243 if (view
->converter
!= str_cnv_from_term
)
245 str_close_conv (view
->converter
);
246 view
->converter
= str_cnv_from_term
;
249 mc_search_free (view
->search
);
251 MC_PTR_FREE (view
->last_search_string
);
252 mcview_nroff_seq_free (&view
->search_nroff_seq
);
253 mcview_hexedit_free_change_list (view
);
255 if (mc_global
.mc_run_mode
== MC_RUN_VIEWER
&& view
->dir
!= NULL
)
257 /* mcviewer is the owner of file list */
258 dir_list_clean (view
->dir
);
259 g_free (view
->dir
->list
);
260 g_free (view
->dir_idx
);
267 /* --------------------------------------------------------------------------------------------- */
270 mcview_set_codeset (WView
* view
)
273 const char *cp_id
= NULL
;
277 get_codepage_id (mc_global
.source_codepage
>=
278 0 ? mc_global
.source_codepage
: mc_global
.display_codepage
);
282 conv
= str_crt_conv_from (cp_id
);
283 if (conv
!= INVALID_CONV
)
285 if (view
->converter
!= str_cnv_from_term
)
286 str_close_conv (view
->converter
);
287 view
->converter
= conv
;
289 view
->utf8
= (gboolean
) str_isutf8 (cp_id
);
290 view
->dpy_wrap_dirty
= TRUE
;
297 /* --------------------------------------------------------------------------------------------- */
301 mcview_select_encoding (WView
* view
)
303 if (do_select_codepage ())
304 mcview_set_codeset (view
);
308 /* --------------------------------------------------------------------------------------------- */
311 mcview_show_error (WView
* view
, const char *msg
)
313 if (mcview_is_in_panel (view
))
314 mcview_set_datasource_string (view
, msg
);
316 message (D_ERROR
, MSG_ERROR
, "%s", msg
);
319 /* --------------------------------------------------------------------------------------------- */
320 /** returns index of the first char in the line
321 * it is constant for all line characters
325 mcview_bol (WView
* view
, off_t current
, off_t limit
)
329 filesize
= mcview_get_filesize (view
);
332 if (current
> filesize
)
334 if (!mcview_get_byte (view
, current
, &c
))
338 if (!mcview_get_byte (view
, current
- 1, &c
))
343 while (current
> 0 && current
> limit
)
345 if (!mcview_get_byte (view
, current
- 1, &c
))
347 if (c
== '\r' || c
== '\n')
354 /* --------------------------------------------------------------------------------------------- */
355 /** returns index of last char on line + width EOL
356 * mcview_eol of the current line == mcview_bol next line
360 mcview_eol (WView
* view
, off_t current
, off_t limit
)
364 filesize
= mcview_get_filesize (view
);
367 if (current
>= filesize
)
369 while (current
< filesize
&& current
< limit
)
371 if (!mcview_get_byte (view
, current
, &c
))
378 else if (prev_ch
== '\r')
388 /* --------------------------------------------------------------------------------------------- */
391 mcview_get_title (const WDialog
* h
, size_t len
)
393 const WView
*view
= (const WView
*) find_widget_type (h
, mcview_callback
);
394 const char *modified
= view
->hexedit_mode
&& (view
->change_list
!= NULL
) ? "(*) " : " ";
395 const char *file_label
;
396 const char *view_filename
;
399 view_filename
= vfs_path_as_str (view
->filename_vpath
);
403 file_label
= view_filename
!= NULL
? view_filename
: view
->command
!= NULL
? view
->command
: "";
404 file_label
= str_term_trim (file_label
, len
- str_term_width1 (_("View: ")));
406 ret_str
= g_strconcat (_("View: "), modified
, file_label
, (char *) NULL
);
410 /* --------------------------------------------------------------------------------------------- */
413 mcview_calc_percent (WView
* view
, off_t p
)
415 const screen_dimen right
= view
->status_area
.left
+ view
->status_area
.width
;
416 const screen_dimen height
= view
->status_area
.height
;
420 if (height
< 1 || right
< 4)
422 if (mcview_may_still_grow (view
))
425 filesize
= mcview_get_filesize (view
);
426 if (view
->hex_mode
&& filesize
> 0)
428 /* p can't be beyond the last char, only over that. Compensate for this. */
432 if (filesize
== 0 || p
>= filesize
)
434 else if (p
> (INT_MAX
/ 100))
435 percent
= p
/ (filesize
/ 100);
437 percent
= p
* 100 / filesize
;
442 /* --------------------------------------------------------------------------------------------- */