Updated doc/NEWS file
[midnight-commander.git] / src / viewer / lib.c
blob23a090391fdb7e7b467947ebceb85f4430451e62
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 #include "src/main.h"
52 #ifdef HAVE_CHARSET
53 #include "src/selcodepage.h"
54 #endif
56 #include "internal.h"
57 #include "mcviewer.h"
59 /*** global variables ****************************************************************************/
61 #define OFF_T_BITWIDTH (unsigned int) (sizeof (off_t) * CHAR_BIT - 1)
62 const off_t INVALID_OFFSET = (off_t) (-1);
63 const off_t OFFSETTYPE_MAX = ((off_t) 1 << (OFF_T_BITWIDTH - 1)) - 1;
65 /*** file scope macro definitions ****************************************************************/
67 /*** file scope type declarations ****************************************************************/
69 /*** file scope variables ************************************************************************/
71 /*** file scope functions ************************************************************************/
72 /* --------------------------------------------------------------------------------------------- */
74 /* --------------------------------------------------------------------------------------------- */
75 /*** public functions ****************************************************************************/
76 /* --------------------------------------------------------------------------------------------- */
78 void
79 mcview_toggle_magic_mode (mcview_t * view)
81 char *filename, *command;
83 mcview_altered_magic_flag = 1;
84 view->magic_mode = !view->magic_mode;
85 filename = vfs_path_to_str (view->filename_vpath);
86 command = g_strdup (view->command);
88 mcview_done (view);
89 mcview_init (view);
90 mcview_load (view, command, filename, 0);
91 g_free (filename);
92 g_free (command);
93 view->dpy_bbar_dirty = TRUE;
94 view->dirty++;
97 /* --------------------------------------------------------------------------------------------- */
99 void
100 mcview_toggle_wrap_mode (mcview_t * view)
102 if (view->text_wrap_mode)
103 view->dpy_start = mcview_bol (view, view->dpy_start, 0);
104 view->text_wrap_mode = !view->text_wrap_mode;
105 view->dpy_bbar_dirty = TRUE;
106 view->dirty++;
109 /* --------------------------------------------------------------------------------------------- */
111 void
112 mcview_toggle_nroff_mode (mcview_t * view)
114 view->text_nroff_mode = !view->text_nroff_mode;
115 mcview_altered_nroff_flag = 1;
116 view->dpy_bbar_dirty = TRUE;
117 view->dirty++;
120 /* --------------------------------------------------------------------------------------------- */
122 void
123 mcview_toggle_hex_mode (mcview_t * view)
125 view->hex_mode = !view->hex_mode;
127 if (view->hex_mode)
129 view->hex_cursor = view->dpy_start;
130 view->dpy_start = mcview_offset_rounddown (view->dpy_start, view->bytes_per_line);
131 widget_want_cursor (view->widget, 1);
133 else
135 view->dpy_start = mcview_bol (view, view->hex_cursor, 0);
136 view->hex_cursor = view->dpy_start;
137 widget_want_cursor (view->widget, 0);
139 mcview_altered_hex_mode = 1;
140 view->dpy_bbar_dirty = TRUE;
141 view->dirty++;
144 /* --------------------------------------------------------------------------------------------- */
146 gboolean
147 mcview_ok_to_quit (mcview_t * view)
149 int r;
151 if (view->change_list == NULL)
152 return TRUE;
154 if (!mc_global.midnight_shutdown)
156 query_set_sel (2);
157 r = query_dialog (_("Quit"),
158 _("File was modified. Save with exit?"), D_NORMAL, 3,
159 _("&Yes"), _("&No"), _("&Cancel quit"));
161 else
163 r = query_dialog (_("Quit"),
164 _("Midnight Commander is being shut down.\nSave modified file?"),
165 D_NORMAL, 2, _("&Yes"), _("&No"));
166 /* Esc is No */
167 if (r == -1)
168 r = 1;
171 switch (r)
173 case 0: /* Yes */
174 return mcview_hexedit_save_changes (view) || mc_global.midnight_shutdown;
175 case 1: /* No */
176 mcview_hexedit_free_change_list (view);
177 return TRUE;
178 default:
179 return FALSE;
183 /* --------------------------------------------------------------------------------------------- */
185 void
186 mcview_init (mcview_t * view)
188 size_t i;
190 view->filename_vpath = NULL;
191 view->workdir_vpath = NULL;
192 view->command = NULL;
193 view->search_nroff_seq = NULL;
195 mcview_set_datasource_none (view);
197 view->growbuf_in_use = FALSE;
198 /* leave the other growbuf fields uninitialized */
200 view->hexedit_lownibble = FALSE;
201 view->locked = FALSE;
202 view->coord_cache = NULL;
204 view->dpy_start = 0;
205 view->dpy_text_column = 0;
206 view->dpy_end = 0;
207 view->hex_cursor = 0;
208 view->cursor_col = 0;
209 view->cursor_row = 0;
210 view->change_list = NULL;
212 /* {status,ruler,data}_area are left uninitialized */
214 view->dirty = 0;
215 view->dpy_bbar_dirty = TRUE;
216 view->bytes_per_line = 1;
218 view->search_start = 0;
219 view->search_end = 0;
221 view->marker = 0;
222 for (i = 0; i < sizeof (view->marks) / sizeof (view->marks[0]); i++)
223 view->marks[i] = 0;
225 view->move_dir = 0;
226 view->update_steps = 0;
227 view->update_activate = 0;
229 view->saved_bookmarks = NULL;
232 /* --------------------------------------------------------------------------------------------- */
234 void
235 mcview_done (mcview_t * view)
237 /* Save current file position */
238 if (mcview_remember_file_position && view->filename_vpath != NULL)
240 save_file_position (view->filename_vpath, -1, 0,
241 view->hex_mode ? view->hex_cursor : view->dpy_start,
242 view->saved_bookmarks);
243 view->saved_bookmarks = NULL;
246 /* Write back the global viewer mode */
247 mcview_default_hex_mode = view->hex_mode;
248 mcview_default_nroff_flag = view->text_nroff_mode;
249 mcview_default_magic_flag = view->magic_mode;
250 mcview_global_wrap_mode = view->text_wrap_mode;
252 /* Free memory used by the viewer */
254 /* view->widget needs no destructor */
256 vfs_path_free (view->filename_vpath);
257 view->filename_vpath = NULL;
258 vfs_path_free (view->workdir_vpath);
259 view->workdir_vpath = NULL;
260 g_free (view->command);
261 view->command = NULL;
263 mcview_close_datasource (view);
264 /* the growing buffer is freed with the datasource */
266 coord_cache_free (view->coord_cache), view->coord_cache = NULL;
268 if (view->converter == INVALID_CONV)
269 view->converter = str_cnv_from_term;
271 if (view->converter != str_cnv_from_term)
273 str_close_conv (view->converter);
274 view->converter = str_cnv_from_term;
277 mc_search_free (view->search);
278 view->search = NULL;
279 g_free (view->last_search_string);
280 view->last_search_string = NULL;
281 mcview_nroff_seq_free (&view->search_nroff_seq);
282 mcview_hexedit_free_change_list (view);
285 /* --------------------------------------------------------------------------------------------- */
287 void
288 mcview_set_codeset (mcview_t * view)
290 #ifdef HAVE_CHARSET
291 const char *cp_id = NULL;
293 view->utf8 = TRUE;
294 cp_id =
295 get_codepage_id (mc_global.source_codepage >=
296 0 ? mc_global.source_codepage : mc_global.display_codepage);
297 if (cp_id != NULL)
299 GIConv conv;
300 conv = str_crt_conv_from (cp_id);
301 if (conv != INVALID_CONV)
303 if (view->converter != str_cnv_from_term)
304 str_close_conv (view->converter);
305 view->converter = conv;
307 view->utf8 = (gboolean) str_isutf8 (cp_id);
309 #else
310 (void) view;
311 #endif
314 /* --------------------------------------------------------------------------------------------- */
316 void
317 mcview_select_encoding (mcview_t * view)
319 #ifdef HAVE_CHARSET
320 if (do_select_codepage ())
321 mcview_set_codeset (view);
322 #else
323 (void) view;
324 #endif
327 /* --------------------------------------------------------------------------------------------- */
329 void
330 mcview_show_error (mcview_t * view, const char *msg)
332 mcview_close_datasource (view);
333 if (mcview_is_in_panel (view))
335 mcview_set_datasource_string (view, msg);
337 else
339 message (D_ERROR, MSG_ERROR, "%s", msg);
343 /* --------------------------------------------------------------------------------------------- */
344 /** returns index of the first char in the line
345 * it is constant for all line characters
348 off_t
349 mcview_bol (mcview_t * view, off_t current, off_t limit)
351 int c;
352 off_t filesize;
353 filesize = mcview_get_filesize (view);
354 if (current <= 0)
355 return 0;
356 if (current > filesize)
357 return filesize;
358 if (!mcview_get_byte (view, current, &c))
359 return current;
360 if (c == '\n')
362 if (!mcview_get_byte (view, current - 1, &c))
363 return current;
364 if (c == '\r')
365 current--;
367 while (current > 0 && current >= limit)
369 if (!mcview_get_byte (view, current - 1, &c))
370 break;
371 if (c == '\r' || c == '\n')
372 break;
373 current--;
375 return current;
378 /* --------------------------------------------------------------------------------------------- */
379 /** returns index of last char on line + width EOL
380 * mcview_eol of the current line == mcview_bol next line
383 off_t
384 mcview_eol (mcview_t * view, off_t current, off_t limit)
386 int c, prev_ch = 0;
387 off_t filesize;
388 filesize = mcview_get_filesize (view);
389 if (current < 0)
390 return 0;
391 if (current >= filesize)
392 return filesize;
393 while (current < filesize && current < limit)
395 if (!mcview_get_byte (view, current, &c))
396 break;
397 if (c == '\n')
399 current++;
400 break;
402 else if (prev_ch == '\r')
404 break;
406 current++;
407 prev_ch = c;
409 return current;
412 /* --------------------------------------------------------------------------------------------- */
414 char *
415 mcview_get_title (const Dlg_head * h, size_t len)
417 const mcview_t *view = (const mcview_t *) find_widget_type (h, mcview_callback);
418 const char *modified = view->hexedit_mode && (view->change_list != NULL) ? "(*) " : " ";
419 const char *file_label;
420 char *view_filename;
421 char *ret_str;
423 view_filename = view->filename_vpath != NULL ? vfs_path_to_str (view->filename_vpath) : NULL;
425 len -= 4;
427 file_label = view_filename != NULL ? view_filename : view->command != NULL ? view->command : "";
428 file_label = str_term_trim (file_label, len - str_term_width1 (_("View: ")));
430 ret_str = g_strconcat (_("View: "), modified, file_label, (char *) NULL);
431 g_free (view_filename);
432 return ret_str;
435 /* --------------------------------------------------------------------------------------------- */