Ticket #2814: handle CK_FileNext/CK_FilePrev inside mcviewer.
[midnight-commander.git] / src / viewer / lib.c
blob257e2bcc4d6e603a1006219a913e2894659bd651
1 /*
2 Internal file viewer for the Midnight Commander
3 Common finctions (used from some other mcviewer functions)
5 Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
6 2004, 2005, 2006, 2007, 2009, 2011
7 The Free Software Foundation, Inc.
9 Written by:
10 Miguel de Icaza, 1994, 1995, 1998
11 Janne Kukonlehto, 1994, 1995
12 Jakub Jelinek, 1995
13 Joseph M. Hinkle, 1996
14 Norbert Warmuth, 1997
15 Pavel Machek, 1998
16 Roland Illig <roland.illig@gmx.de>, 2004, 2005
17 Slava Zanko <slavazanko@google.com>, 2009
18 Andrew Borodin <aborodin@vmail.ru>, 2009
19 Ilia Maslakov <il.smind@gmail.com>, 2009
21 This file is part of the Midnight Commander.
23 The Midnight Commander is free software: you can redistribute it
24 and/or modify it under the terms of the GNU General Public License as
25 published by the Free Software Foundation, either version 3 of the License,
26 or (at your option) any later version.
28 The Midnight Commander is distributed in the hope that it will be useful,
29 but WITHOUT ANY WARRANTY; without even the implied warranty of
30 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 GNU General Public License for more details.
33 You should have received a copy of the GNU General Public License
34 along with this program. If not, see <http://www.gnu.org/licenses/>.
37 #include <config.h>
39 #include <limits.h>
40 #include <sys/types.h>
42 #include "lib/global.h"
43 #include "lib/vfs/vfs.h"
44 #include "lib/strutil.h"
45 #include "lib/util.h" /* save_file_position() */
46 #include "lib/widget.h"
47 #include "lib/charsets.h"
49 #include "src/main.h"
50 #include "src/selcodepage.h"
52 #include "internal.h"
53 #include "mcviewer.h"
55 /*** global variables ****************************************************************************/
57 #define OFF_T_BITWIDTH (unsigned int) (sizeof (off_t) * CHAR_BIT - 1)
58 const off_t INVALID_OFFSET = (off_t) - 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 /* --------------------------------------------------------------------------------------------- */
74 void
75 mcview_toggle_magic_mode (mcview_t * view)
77 char *filename, *command;
78 dir_list *dir;
79 int *dir_count, *dir_idx;
81 mcview_altered_magic_flag = 1;
82 view->magic_mode = !view->magic_mode;
84 /* reinit view */
85 filename = vfs_path_to_str (view->filename_vpath);
86 command = g_strdup (view->command);
87 dir = view->dir;
88 dir_count = view->dir_count;
89 dir_idx = view->dir_idx;
90 view->dir = NULL;
91 view->dir_count = NULL;
92 view->dir_idx = NULL;
93 mcview_done (view);
94 mcview_init (view);
95 mcview_load (view, command, filename, 0);
96 view->dir = dir;
97 view->dir_count = dir_count;
98 view->dir_idx = dir_idx;
99 g_free (filename);
100 g_free (command);
102 view->dpy_bbar_dirty = TRUE;
103 view->dirty++;
106 /* --------------------------------------------------------------------------------------------- */
108 void
109 mcview_toggle_wrap_mode (mcview_t * view)
111 if (view->text_wrap_mode)
112 view->dpy_start = mcview_bol (view, view->dpy_start, 0);
113 view->text_wrap_mode = !view->text_wrap_mode;
114 view->dpy_bbar_dirty = TRUE;
115 view->dirty++;
118 /* --------------------------------------------------------------------------------------------- */
120 void
121 mcview_toggle_nroff_mode (mcview_t * view)
123 view->text_nroff_mode = !view->text_nroff_mode;
124 mcview_altered_nroff_flag = 1;
125 view->dpy_bbar_dirty = TRUE;
126 view->dirty++;
129 /* --------------------------------------------------------------------------------------------- */
131 void
132 mcview_toggle_hex_mode (mcview_t * view)
134 view->hex_mode = !view->hex_mode;
136 if (view->hex_mode)
138 view->hex_cursor = view->dpy_start;
139 view->dpy_start = mcview_offset_rounddown (view->dpy_start, view->bytes_per_line);
140 widget_want_cursor (view->widget, 1);
142 else
144 view->dpy_start = mcview_bol (view, view->hex_cursor, 0);
145 view->hex_cursor = view->dpy_start;
146 widget_want_cursor (view->widget, 0);
148 mcview_altered_hex_mode = 1;
149 view->dpy_bbar_dirty = TRUE;
150 view->dirty++;
153 /* --------------------------------------------------------------------------------------------- */
155 gboolean
156 mcview_ok_to_quit (mcview_t * view)
158 int r;
160 if (view->change_list == NULL)
161 return TRUE;
163 if (!mc_global.midnight_shutdown)
165 query_set_sel (2);
166 r = query_dialog (_("Quit"),
167 _("File was modified. Save with exit?"), D_NORMAL, 3,
168 _("&Yes"), _("&No"), _("&Cancel quit"));
170 else
172 r = query_dialog (_("Quit"),
173 _("Midnight Commander is being shut down.\nSave modified file?"),
174 D_NORMAL, 2, _("&Yes"), _("&No"));
175 /* Esc is No */
176 if (r == -1)
177 r = 1;
180 switch (r)
182 case 0: /* Yes */
183 return mcview_hexedit_save_changes (view) || mc_global.midnight_shutdown;
184 case 1: /* No */
185 mcview_hexedit_free_change_list (view);
186 return TRUE;
187 default:
188 return FALSE;
192 /* --------------------------------------------------------------------------------------------- */
194 void
195 mcview_init (mcview_t * view)
197 size_t i;
199 view->filename_vpath = NULL;
200 view->workdir_vpath = NULL;
201 view->command = NULL;
202 view->search_nroff_seq = NULL;
204 mcview_set_datasource_none (view);
206 view->growbuf_in_use = FALSE;
207 /* leave the other growbuf fields uninitialized */
209 view->hexedit_lownibble = FALSE;
210 view->locked = FALSE;
211 view->coord_cache = NULL;
213 view->dpy_start = 0;
214 view->dpy_text_column = 0;
215 view->dpy_end = 0;
216 view->hex_cursor = 0;
217 view->cursor_col = 0;
218 view->cursor_row = 0;
219 view->change_list = NULL;
221 /* {status,ruler,data}_area are left uninitialized */
223 view->dirty = 0;
224 view->dpy_bbar_dirty = TRUE;
225 view->bytes_per_line = 1;
227 view->search_start = 0;
228 view->search_end = 0;
230 view->marker = 0;
231 for (i = 0; i < sizeof (view->marks) / sizeof (view->marks[0]); i++)
232 view->marks[i] = 0;
234 view->move_dir = 0;
235 view->update_steps = 0;
236 view->update_activate = 0;
238 view->saved_bookmarks = NULL;
241 /* --------------------------------------------------------------------------------------------- */
243 void
244 mcview_done (mcview_t * view)
246 /* Save current file position */
247 if (mcview_remember_file_position && view->filename_vpath != NULL)
249 save_file_position (view->filename_vpath, -1, 0,
250 view->hex_mode ? view->hex_cursor : view->dpy_start,
251 view->saved_bookmarks);
252 view->saved_bookmarks = NULL;
255 /* Write back the global viewer mode */
256 mcview_default_hex_mode = view->hex_mode;
257 mcview_default_nroff_flag = view->text_nroff_mode;
258 mcview_default_magic_flag = view->magic_mode;
259 mcview_global_wrap_mode = view->text_wrap_mode;
261 /* Free memory used by the viewer */
263 /* view->widget needs no destructor */
265 vfs_path_free (view->filename_vpath);
266 view->filename_vpath = NULL;
267 vfs_path_free (view->workdir_vpath);
268 view->workdir_vpath = NULL;
269 g_free (view->command);
270 view->command = NULL;
272 mcview_close_datasource (view);
273 /* the growing buffer is freed with the datasource */
275 coord_cache_free (view->coord_cache), view->coord_cache = NULL;
277 if (view->converter == INVALID_CONV)
278 view->converter = str_cnv_from_term;
280 if (view->converter != str_cnv_from_term)
282 str_close_conv (view->converter);
283 view->converter = str_cnv_from_term;
286 mc_search_free (view->search);
287 view->search = NULL;
288 g_free (view->last_search_string);
289 view->last_search_string = NULL;
290 mcview_nroff_seq_free (&view->search_nroff_seq);
291 mcview_hexedit_free_change_list (view);
293 if (mc_global.mc_run_mode == MC_RUN_VIEWER && view->dir != NULL)
295 /* mcviewer is the owner of file list */
296 clean_dir (view->dir, *view->dir_count);
297 g_free (view->dir->list);
298 g_free (view->dir_count);
299 g_free (view->dir_idx);
300 g_free (view->dir);
303 view->dir = NULL;
306 /* --------------------------------------------------------------------------------------------- */
308 void
309 mcview_set_codeset (mcview_t * view)
311 #ifdef HAVE_CHARSET
312 const char *cp_id = NULL;
314 view->utf8 = TRUE;
315 cp_id =
316 get_codepage_id (mc_global.source_codepage >=
317 0 ? mc_global.source_codepage : mc_global.display_codepage);
318 if (cp_id != NULL)
320 GIConv conv;
321 conv = str_crt_conv_from (cp_id);
322 if (conv != INVALID_CONV)
324 if (view->converter != str_cnv_from_term)
325 str_close_conv (view->converter);
326 view->converter = conv;
328 view->utf8 = (gboolean) str_isutf8 (cp_id);
330 #else
331 (void) view;
332 #endif
335 /* --------------------------------------------------------------------------------------------- */
337 void
338 mcview_select_encoding (mcview_t * view)
340 #ifdef HAVE_CHARSET
341 if (do_select_codepage ())
342 mcview_set_codeset (view);
343 #else
344 (void) view;
345 #endif
348 /* --------------------------------------------------------------------------------------------- */
350 void
351 mcview_show_error (mcview_t * view, const char *msg)
353 mcview_close_datasource (view);
354 if (mcview_is_in_panel (view))
356 mcview_set_datasource_string (view, msg);
358 else
360 message (D_ERROR, MSG_ERROR, "%s", msg);
364 /* --------------------------------------------------------------------------------------------- */
365 /** returns index of the first char in the line
366 * it is constant for all line characters
369 off_t
370 mcview_bol (mcview_t * view, off_t current, off_t limit)
372 int c;
373 off_t filesize;
374 filesize = mcview_get_filesize (view);
375 if (current <= 0)
376 return 0;
377 if (current > filesize)
378 return filesize;
379 if (!mcview_get_byte (view, current, &c))
380 return current;
381 if (c == '\n')
383 if (!mcview_get_byte (view, current - 1, &c))
384 return current;
385 if (c == '\r')
386 current--;
388 while (current > 0 && current >= limit)
390 if (!mcview_get_byte (view, current - 1, &c))
391 break;
392 if (c == '\r' || c == '\n')
393 break;
394 current--;
396 return current;
399 /* --------------------------------------------------------------------------------------------- */
400 /** returns index of last char on line + width EOL
401 * mcview_eol of the current line == mcview_bol next line
404 off_t
405 mcview_eol (mcview_t * view, off_t current, off_t limit)
407 int c, prev_ch = 0;
408 off_t filesize;
409 filesize = mcview_get_filesize (view);
410 if (current < 0)
411 return 0;
412 if (current >= filesize)
413 return filesize;
414 while (current < filesize && current < limit)
416 if (!mcview_get_byte (view, current, &c))
417 break;
418 if (c == '\n')
420 current++;
421 break;
423 else if (prev_ch == '\r')
425 break;
427 current++;
428 prev_ch = c;
430 return current;
433 /* --------------------------------------------------------------------------------------------- */
435 char *
436 mcview_get_title (const Dlg_head * h, size_t len)
438 const mcview_t *view = (const mcview_t *) find_widget_type (h, mcview_callback);
439 const char *modified = view->hexedit_mode && (view->change_list != NULL) ? "(*) " : " ";
440 const char *file_label;
441 char *view_filename;
442 char *ret_str;
444 view_filename = view->filename_vpath != NULL ? vfs_path_to_str (view->filename_vpath) : NULL;
446 len -= 4;
448 file_label = view_filename != NULL ? view_filename : view->command != NULL ? view->command : "";
449 file_label = str_term_trim (file_label, len - str_term_width1 (_("View: ")));
451 ret_str = g_strconcat (_("View: "), modified, file_label, (char *) NULL);
452 g_free (view_filename);
453 return ret_str;
456 /* --------------------------------------------------------------------------------------------- */