Changed internal viewer to use vfs_path_t objects.
[midnight-commander.git] / src / viewer / lib.c
blob035f9b43978682abac3966556b461dcc0562b28f
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/lock.h" /* unlock_file() */
47 #include "lib/widget.h"
48 #include "lib/charsets.h"
50 #include "src/main.h"
51 #include "src/selcodepage.h"
53 #include "internal.h"
54 #include "mcviewer.h"
56 /*** global variables ****************************************************************************/
58 #define OFF_T_BITWIDTH (unsigned int) (sizeof (off_t) * CHAR_BIT - 1)
59 const off_t INVALID_OFFSET = (off_t) - 1;
60 const off_t OFFSETTYPE_MAX = ((off_t) 1 << (OFF_T_BITWIDTH - 1)) - 1;
62 /*** file scope macro definitions ****************************************************************/
64 /*** file scope type declarations ****************************************************************/
66 /*** file scope variables ************************************************************************/
68 /*** file scope functions ************************************************************************/
69 /* --------------------------------------------------------------------------------------------- */
71 /* --------------------------------------------------------------------------------------------- */
72 /*** public functions ****************************************************************************/
73 /* --------------------------------------------------------------------------------------------- */
75 void
76 mcview_toggle_magic_mode (mcview_t * view)
78 char *filename, *command;
80 mcview_altered_magic_flag = 1;
81 view->magic_mode = !view->magic_mode;
82 filename = vfs_path_to_str (view->filename_vpath);
83 command = g_strdup (view->command);
85 mcview_done (view);
86 mcview_init (view);
87 mcview_load (view, command, filename, 0);
88 g_free (filename);
89 g_free (command);
90 view->dpy_bbar_dirty = TRUE;
91 view->dirty++;
94 /* --------------------------------------------------------------------------------------------- */
96 void
97 mcview_toggle_wrap_mode (mcview_t * view)
99 if (view->text_wrap_mode)
100 view->dpy_start = mcview_bol (view, view->dpy_start, 0);
101 view->text_wrap_mode = !view->text_wrap_mode;
102 view->dpy_bbar_dirty = TRUE;
103 view->dirty++;
106 /* --------------------------------------------------------------------------------------------- */
108 void
109 mcview_toggle_nroff_mode (mcview_t * view)
111 view->text_nroff_mode = !view->text_nroff_mode;
112 mcview_altered_nroff_flag = 1;
113 view->dpy_bbar_dirty = TRUE;
114 view->dirty++;
117 /* --------------------------------------------------------------------------------------------- */
119 void
120 mcview_toggle_hex_mode (mcview_t * view)
122 view->hex_mode = !view->hex_mode;
124 if (view->hex_mode)
126 view->hex_cursor = view->dpy_start;
127 view->dpy_start = mcview_offset_rounddown (view->dpy_start, view->bytes_per_line);
128 widget_want_cursor (view->widget, 1);
130 else
132 view->dpy_start = mcview_bol (view, view->hex_cursor, 0);
133 view->hex_cursor = view->dpy_start;
134 widget_want_cursor (view->widget, 0);
136 mcview_altered_hex_mode = 1;
137 view->dpy_bbar_dirty = TRUE;
138 view->dirty++;
141 /* --------------------------------------------------------------------------------------------- */
143 gboolean
144 mcview_ok_to_quit (mcview_t * view)
146 int r;
148 if (view->change_list == NULL)
149 return TRUE;
151 if (!mc_global.midnight_shutdown)
153 query_set_sel (2);
154 r = query_dialog (_("Quit"),
155 _("File was modified. Save with exit?"), D_NORMAL, 3,
156 _("&Yes"), _("&No"), _("&Cancel quit"));
158 else
160 r = query_dialog (_("Quit"),
161 _("Midnight Commander is being shut down.\nSave modified file?"),
162 D_NORMAL, 2, _("&Yes"), _("&No"));
163 /* Esc is No */
164 if (r == -1)
165 r = 1;
168 switch (r)
170 case 0: /* Yes */
171 return mcview_hexedit_save_changes (view) || mc_global.midnight_shutdown;
172 case 1: /* No */
173 mcview_hexedit_free_change_list (view);
174 return TRUE;
175 default:
176 return FALSE;
180 /* --------------------------------------------------------------------------------------------- */
182 void
183 mcview_init (mcview_t * view)
185 size_t i;
187 view->filename_vpath = NULL;
188 view->workdir_vpath = NULL;
189 view->command = NULL;
190 view->search_nroff_seq = NULL;
192 mcview_set_datasource_none (view);
194 view->growbuf_in_use = FALSE;
195 /* leave the other growbuf fields uninitialized */
197 view->hexedit_lownibble = FALSE;
198 view->locked = FALSE;
199 view->coord_cache = NULL;
201 view->dpy_start = 0;
202 view->dpy_text_column = 0;
203 view->dpy_end = 0;
204 view->hex_cursor = 0;
205 view->cursor_col = 0;
206 view->cursor_row = 0;
207 view->change_list = NULL;
209 /* {status,ruler,data}_area are left uninitialized */
211 view->dirty = 0;
212 view->dpy_bbar_dirty = TRUE;
213 view->bytes_per_line = 1;
215 view->search_start = 0;
216 view->search_end = 0;
218 view->marker = 0;
219 for (i = 0; i < sizeof (view->marks) / sizeof (view->marks[0]); i++)
220 view->marks[i] = 0;
222 view->move_dir = 0;
223 view->update_steps = 0;
224 view->update_activate = 0;
226 view->saved_bookmarks = NULL;
229 /* --------------------------------------------------------------------------------------------- */
231 void
232 mcview_done (mcview_t * view)
234 /* Save current file position */
235 if (mcview_remember_file_position && view->filename_vpath != NULL)
237 save_file_position (view->filename_vpath, -1, 0,
238 view->hex_mode ? view->hex_cursor : view->dpy_start,
239 view->saved_bookmarks);
240 view->saved_bookmarks = NULL;
243 /* Write back the global viewer mode */
244 mcview_default_hex_mode = view->hex_mode;
245 mcview_default_nroff_flag = view->text_nroff_mode;
246 mcview_default_magic_flag = view->magic_mode;
247 mcview_global_wrap_mode = view->text_wrap_mode;
249 /* Free memory used by the viewer */
251 /* view->widget needs no destructor */
253 vfs_path_free (view->filename_vpath);
254 view->filename_vpath = NULL;
255 vfs_path_free (view->workdir_vpath);
256 view->workdir_vpath = NULL;
257 g_free (view->command);
258 view->command = NULL;
260 mcview_close_datasource (view);
261 /* the growing buffer is freed with the datasource */
263 coord_cache_free (view->coord_cache), view->coord_cache = NULL;
265 if (view->converter == INVALID_CONV)
266 view->converter = str_cnv_from_term;
268 if (view->converter != str_cnv_from_term)
270 str_close_conv (view->converter);
271 view->converter = str_cnv_from_term;
274 mc_search_free (view->search);
275 view->search = NULL;
276 g_free (view->last_search_string);
277 view->last_search_string = NULL;
278 mcview_nroff_seq_free (&view->search_nroff_seq);
279 mcview_hexedit_free_change_list (view);
282 /* --------------------------------------------------------------------------------------------- */
284 void
285 mcview_set_codeset (mcview_t * view)
287 #ifdef HAVE_CHARSET
288 const char *cp_id = NULL;
290 view->utf8 = TRUE;
291 cp_id =
292 get_codepage_id (mc_global.source_codepage >=
293 0 ? mc_global.source_codepage : mc_global.display_codepage);
294 if (cp_id != NULL)
296 GIConv conv;
297 conv = str_crt_conv_from (cp_id);
298 if (conv != INVALID_CONV)
300 if (view->converter != str_cnv_from_term)
301 str_close_conv (view->converter);
302 view->converter = conv;
304 view->utf8 = (gboolean) str_isutf8 (cp_id);
306 #else
307 (void) view;
308 #endif
311 /* --------------------------------------------------------------------------------------------- */
313 void
314 mcview_select_encoding (mcview_t * view)
316 #ifdef HAVE_CHARSET
317 if (do_select_codepage ())
318 mcview_set_codeset (view);
319 #else
320 (void) view;
321 #endif
324 /* --------------------------------------------------------------------------------------------- */
326 void
327 mcview_show_error (mcview_t * view, const char *msg)
329 mcview_close_datasource (view);
330 if (mcview_is_in_panel (view))
332 mcview_set_datasource_string (view, msg);
334 else
336 message (D_ERROR, MSG_ERROR, "%s", msg);
340 /* --------------------------------------------------------------------------------------------- */
341 /** returns index of the first char in the line
342 * it is constant for all line characters
345 off_t
346 mcview_bol (mcview_t * view, off_t current, off_t limit)
348 int c;
349 off_t filesize;
350 filesize = mcview_get_filesize (view);
351 if (current <= 0)
352 return 0;
353 if (current > filesize)
354 return filesize;
355 if (!mcview_get_byte (view, current, &c))
356 return current;
357 if (c == '\n')
359 if (!mcview_get_byte (view, current - 1, &c))
360 return current;
361 if (c == '\r')
362 current--;
364 while (current > 0 && current >= limit)
366 if (!mcview_get_byte (view, current - 1, &c))
367 break;
368 if (c == '\r' || c == '\n')
369 break;
370 current--;
372 return current;
375 /* --------------------------------------------------------------------------------------------- */
376 /** returns index of last char on line + width EOL
377 * mcview_eol of the current line == mcview_bol next line
380 off_t
381 mcview_eol (mcview_t * view, off_t current, off_t limit)
383 int c, prev_ch = 0;
384 off_t filesize;
385 filesize = mcview_get_filesize (view);
386 if (current < 0)
387 return 0;
388 if (current >= filesize)
389 return filesize;
390 while (current < filesize && current < limit)
392 if (!mcview_get_byte (view, current, &c))
393 break;
394 if (c == '\n')
396 current++;
397 break;
399 else if (prev_ch == '\r')
401 break;
403 current++;
404 prev_ch = c;
406 return current;
409 /* --------------------------------------------------------------------------------------------- */
411 char *
412 mcview_get_title (const Dlg_head * h, size_t len)
414 const mcview_t *view = (const mcview_t *) find_widget_type (h, mcview_callback);
415 const char *modified = view->hexedit_mode && (view->change_list != NULL) ? "(*) " : " ";
416 const char *file_label;
417 char *view_filename;
418 char *ret_str;
420 view_filename =
421 view->filename_vpath != NULL ? vfs_path_to_str (view->filename_vpath) : NULL;
423 len -= 4;
425 file_label = view_filename != NULL ? view_filename : view->command != NULL ? view->command : "";
426 file_label = str_term_trim (file_label, len - str_term_width1 (_("View: ")));
428 ret_str = g_strconcat (_("View: "), modified, file_label, (char *) NULL);
429 g_free (view_filename);
430 return ret_str;
433 /* --------------------------------------------------------------------------------------------- */
435 gboolean
436 mcview_lock_file (mcview_t * view)
438 vfs_path_t *fullpath;
439 gboolean ret;
441 fullpath = vfs_path_append_vpath_new (view->workdir_vpath, view->filename_vpath, (char *) NULL);
442 ret = lock_file (fullpath);
443 vfs_path_free (fullpath);
445 return ret;
448 /* --------------------------------------------------------------------------------------------- */
450 gboolean
451 mcview_unlock_file (mcview_t * view)
453 vfs_path_t *fullpath;
454 gboolean ret;
456 fullpath = vfs_path_append_vpath_new (view->workdir_vpath, view->filename_vpath, (char *) NULL);
457 ret = unlock_file (fullpath);
458 vfs_path_free (fullpath);
460 return ret;
463 /* --------------------------------------------------------------------------------------------- */