Internal menu structures are opaque now.
[midnight-commander.git] / src / viewer / lib.c
blobc98671236ddbec4477c39ca65ec2f874caa1d870
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 #ifdef HAVE_CHARSET
48 #include "lib/charsets.h"
49 #endif
51 #ifdef HAVE_CHARSET
52 #include "src/selcodepage.h"
53 #endif
55 #include "internal.h"
56 #include "mcviewer.h"
58 /*** global variables ****************************************************************************/
60 #define OFF_T_BITWIDTH (unsigned int) (sizeof (off_t) * CHAR_BIT - 1)
61 const off_t INVALID_OFFSET = (off_t) - 1;
62 const off_t OFFSETTYPE_MAX = ((off_t) 1 << (OFF_T_BITWIDTH - 1)) - 1;
64 /*** file scope macro definitions ****************************************************************/
66 /*** file scope type declarations ****************************************************************/
68 /*** file scope variables ************************************************************************/
70 /*** file scope functions ************************************************************************/
71 /* --------------------------------------------------------------------------------------------- */
73 /* --------------------------------------------------------------------------------------------- */
74 /*** public functions ****************************************************************************/
75 /* --------------------------------------------------------------------------------------------- */
77 void
78 mcview_toggle_magic_mode (mcview_t * view)
80 char *filename, *command;
81 dir_list *dir;
82 int *dir_count, *dir_idx;
84 mcview_altered_magic_flag = 1;
85 view->magic_mode = !view->magic_mode;
87 /* reinit view */
88 filename = vfs_path_to_str (view->filename_vpath);
89 command = g_strdup (view->command);
90 dir = view->dir;
91 dir_count = view->dir_count;
92 dir_idx = view->dir_idx;
93 view->dir = NULL;
94 view->dir_count = NULL;
95 view->dir_idx = NULL;
96 mcview_done (view);
97 mcview_init (view);
98 mcview_load (view, command, filename, 0);
99 view->dir = dir;
100 view->dir_count = dir_count;
101 view->dir_idx = dir_idx;
102 g_free (filename);
103 g_free (command);
105 view->dpy_bbar_dirty = TRUE;
106 view->dirty++;
109 /* --------------------------------------------------------------------------------------------- */
111 void
112 mcview_toggle_wrap_mode (mcview_t * view)
114 if (view->text_wrap_mode)
115 view->dpy_start = mcview_bol (view, view->dpy_start, 0);
116 view->text_wrap_mode = !view->text_wrap_mode;
117 view->dpy_bbar_dirty = TRUE;
118 view->dirty++;
121 /* --------------------------------------------------------------------------------------------- */
123 void
124 mcview_toggle_nroff_mode (mcview_t * view)
126 view->text_nroff_mode = !view->text_nroff_mode;
127 mcview_altered_nroff_flag = 1;
128 view->dpy_bbar_dirty = TRUE;
129 view->dirty++;
132 /* --------------------------------------------------------------------------------------------- */
134 void
135 mcview_toggle_hex_mode (mcview_t * view)
137 view->hex_mode = !view->hex_mode;
139 if (view->hex_mode)
141 view->hex_cursor = view->dpy_start;
142 view->dpy_start = mcview_offset_rounddown (view->dpy_start, view->bytes_per_line);
143 widget_want_cursor (WIDGET (view), TRUE);
145 else
147 view->dpy_start = mcview_bol (view, view->hex_cursor, 0);
148 view->hex_cursor = view->dpy_start;
149 widget_want_cursor (WIDGET (view), FALSE);
151 mcview_altered_hex_mode = 1;
152 view->dpy_bbar_dirty = TRUE;
153 view->dirty++;
156 /* --------------------------------------------------------------------------------------------- */
158 gboolean
159 mcview_ok_to_quit (mcview_t * view)
161 int r;
163 if (view->change_list == NULL)
164 return TRUE;
166 if (!mc_global.midnight_shutdown)
168 query_set_sel (2);
169 r = query_dialog (_("Quit"),
170 _("File was modified. Save with exit?"), D_NORMAL, 3,
171 _("&Yes"), _("&No"), _("&Cancel quit"));
173 else
175 r = query_dialog (_("Quit"),
176 _("Midnight Commander is being shut down.\nSave modified file?"),
177 D_NORMAL, 2, _("&Yes"), _("&No"));
178 /* Esc is No */
179 if (r == -1)
180 r = 1;
183 switch (r)
185 case 0: /* Yes */
186 return mcview_hexedit_save_changes (view) || mc_global.midnight_shutdown;
187 case 1: /* No */
188 mcview_hexedit_free_change_list (view);
189 return TRUE;
190 default:
191 return FALSE;
195 /* --------------------------------------------------------------------------------------------- */
197 void
198 mcview_init (mcview_t * view)
200 size_t i;
202 view->filename_vpath = NULL;
203 view->workdir_vpath = NULL;
204 view->command = NULL;
205 view->search_nroff_seq = NULL;
207 mcview_set_datasource_none (view);
209 view->growbuf_in_use = FALSE;
210 /* leave the other growbuf fields uninitialized */
212 view->hexedit_lownibble = FALSE;
213 view->locked = FALSE;
214 view->coord_cache = NULL;
216 view->dpy_start = 0;
217 view->dpy_text_column = 0;
218 view->dpy_end = 0;
219 view->hex_cursor = 0;
220 view->cursor_col = 0;
221 view->cursor_row = 0;
222 view->change_list = NULL;
224 /* {status,ruler,data}_area are left uninitialized */
226 view->dirty = 0;
227 view->dpy_bbar_dirty = TRUE;
228 view->bytes_per_line = 1;
230 view->search_start = 0;
231 view->search_end = 0;
233 view->marker = 0;
234 for (i = 0; i < sizeof (view->marks) / sizeof (view->marks[0]); i++)
235 view->marks[i] = 0;
237 view->update_steps = 0;
238 view->update_activate = 0;
240 view->saved_bookmarks = NULL;
243 /* --------------------------------------------------------------------------------------------- */
245 void
246 mcview_done (mcview_t * view)
248 /* Save current file position */
249 if (mcview_remember_file_position && view->filename_vpath != NULL)
251 save_file_position (view->filename_vpath, -1, 0,
252 view->hex_mode ? view->hex_cursor : view->dpy_start,
253 view->saved_bookmarks);
254 view->saved_bookmarks = NULL;
257 /* Write back the global viewer mode */
258 mcview_default_hex_mode = view->hex_mode;
259 mcview_default_nroff_flag = view->text_nroff_mode;
260 mcview_default_magic_flag = view->magic_mode;
261 mcview_global_wrap_mode = view->text_wrap_mode;
263 /* Free memory used by the viewer */
265 /* view->widget needs no destructor */
267 vfs_path_free (view->filename_vpath);
268 view->filename_vpath = NULL;
269 vfs_path_free (view->workdir_vpath);
270 view->workdir_vpath = NULL;
271 g_free (view->command);
272 view->command = NULL;
274 mcview_close_datasource (view);
275 /* the growing buffer is freed with the datasource */
277 coord_cache_free (view->coord_cache), view->coord_cache = NULL;
279 if (view->converter == INVALID_CONV)
280 view->converter = str_cnv_from_term;
282 if (view->converter != str_cnv_from_term)
284 str_close_conv (view->converter);
285 view->converter = str_cnv_from_term;
288 mc_search_free (view->search);
289 view->search = NULL;
290 g_free (view->last_search_string);
291 view->last_search_string = NULL;
292 mcview_nroff_seq_free (&view->search_nroff_seq);
293 mcview_hexedit_free_change_list (view);
295 if (mc_global.mc_run_mode == MC_RUN_VIEWER && view->dir != NULL)
297 /* mcviewer is the owner of file list */
298 clean_dir (view->dir, *view->dir_count);
299 g_free (view->dir->list);
300 g_free (view->dir_count);
301 g_free (view->dir_idx);
302 g_free (view->dir);
305 view->dir = NULL;
308 /* --------------------------------------------------------------------------------------------- */
310 void
311 mcview_set_codeset (mcview_t * view)
313 #ifdef HAVE_CHARSET
314 const char *cp_id = NULL;
316 view->utf8 = TRUE;
317 cp_id =
318 get_codepage_id (mc_global.source_codepage >=
319 0 ? mc_global.source_codepage : mc_global.display_codepage);
320 if (cp_id != NULL)
322 GIConv conv;
323 conv = str_crt_conv_from (cp_id);
324 if (conv != INVALID_CONV)
326 if (view->converter != str_cnv_from_term)
327 str_close_conv (view->converter);
328 view->converter = conv;
330 view->utf8 = (gboolean) str_isutf8 (cp_id);
332 #else
333 (void) view;
334 #endif
337 /* --------------------------------------------------------------------------------------------- */
339 #ifdef HAVE_CHARSET
340 void
341 mcview_select_encoding (mcview_t * view)
343 if (do_select_codepage ())
344 mcview_set_codeset (view);
346 #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 WDialog * 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 /* --------------------------------------------------------------------------------------------- */