Ticket #2894: add support of Gnumeric's spreadsheets.
[midnight-commander.git] / src / viewer / lib.c
blob8a029e7ca1b2b8f01173168b40115168fc9d5ea4
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;
82 dir_list *dir;
83 int *dir_count, *dir_idx;
85 mcview_altered_magic_flag = 1;
86 view->magic_mode = !view->magic_mode;
88 /* reinit view */
89 filename = vfs_path_to_str (view->filename_vpath);
90 command = g_strdup (view->command);
91 dir = view->dir;
92 dir_count = view->dir_count;
93 dir_idx = view->dir_idx;
94 view->dir = NULL;
95 view->dir_count = NULL;
96 view->dir_idx = NULL;
97 mcview_done (view);
98 mcview_init (view);
99 mcview_load (view, command, filename, 0);
100 view->dir = dir;
101 view->dir_count = dir_count;
102 view->dir_idx = dir_idx;
103 g_free (filename);
104 g_free (command);
106 view->dpy_bbar_dirty = TRUE;
107 view->dirty++;
110 /* --------------------------------------------------------------------------------------------- */
112 void
113 mcview_toggle_wrap_mode (mcview_t * view)
115 if (view->text_wrap_mode)
116 view->dpy_start = mcview_bol (view, view->dpy_start, 0);
117 view->text_wrap_mode = !view->text_wrap_mode;
118 view->dpy_bbar_dirty = TRUE;
119 view->dirty++;
122 /* --------------------------------------------------------------------------------------------- */
124 void
125 mcview_toggle_nroff_mode (mcview_t * view)
127 view->text_nroff_mode = !view->text_nroff_mode;
128 mcview_altered_nroff_flag = 1;
129 view->dpy_bbar_dirty = TRUE;
130 view->dirty++;
133 /* --------------------------------------------------------------------------------------------- */
135 void
136 mcview_toggle_hex_mode (mcview_t * view)
138 view->hex_mode = !view->hex_mode;
140 if (view->hex_mode)
142 view->hex_cursor = view->dpy_start;
143 view->dpy_start = mcview_offset_rounddown (view->dpy_start, view->bytes_per_line);
144 widget_want_cursor (view->widget, 1);
146 else
148 view->dpy_start = mcview_bol (view, view->hex_cursor, 0);
149 view->hex_cursor = view->dpy_start;
150 widget_want_cursor (view->widget, 0);
152 mcview_altered_hex_mode = 1;
153 view->dpy_bbar_dirty = TRUE;
154 view->dirty++;
157 /* --------------------------------------------------------------------------------------------- */
159 gboolean
160 mcview_ok_to_quit (mcview_t * view)
162 int r;
164 if (view->change_list == NULL)
165 return TRUE;
167 if (!mc_global.midnight_shutdown)
169 query_set_sel (2);
170 r = query_dialog (_("Quit"),
171 _("File was modified. Save with exit?"), D_NORMAL, 3,
172 _("&Yes"), _("&No"), _("&Cancel quit"));
174 else
176 r = query_dialog (_("Quit"),
177 _("Midnight Commander is being shut down.\nSave modified file?"),
178 D_NORMAL, 2, _("&Yes"), _("&No"));
179 /* Esc is No */
180 if (r == -1)
181 r = 1;
184 switch (r)
186 case 0: /* Yes */
187 return mcview_hexedit_save_changes (view) || mc_global.midnight_shutdown;
188 case 1: /* No */
189 mcview_hexedit_free_change_list (view);
190 return TRUE;
191 default:
192 return FALSE;
196 /* --------------------------------------------------------------------------------------------- */
198 void
199 mcview_init (mcview_t * view)
201 size_t i;
203 view->filename_vpath = NULL;
204 view->workdir_vpath = NULL;
205 view->command = NULL;
206 view->search_nroff_seq = NULL;
208 mcview_set_datasource_none (view);
210 view->growbuf_in_use = FALSE;
211 /* leave the other growbuf fields uninitialized */
213 view->hexedit_lownibble = FALSE;
214 view->locked = FALSE;
215 view->coord_cache = NULL;
217 view->dpy_start = 0;
218 view->dpy_text_column = 0;
219 view->dpy_end = 0;
220 view->hex_cursor = 0;
221 view->cursor_col = 0;
222 view->cursor_row = 0;
223 view->change_list = NULL;
225 /* {status,ruler,data}_area are left uninitialized */
227 view->dirty = 0;
228 view->dpy_bbar_dirty = TRUE;
229 view->bytes_per_line = 1;
231 view->search_start = 0;
232 view->search_end = 0;
234 view->marker = 0;
235 for (i = 0; i < sizeof (view->marks) / sizeof (view->marks[0]); i++)
236 view->marks[i] = 0;
238 view->update_steps = 0;
239 view->update_activate = 0;
241 view->saved_bookmarks = NULL;
244 /* --------------------------------------------------------------------------------------------- */
246 void
247 mcview_done (mcview_t * view)
249 /* Save current file position */
250 if (mcview_remember_file_position && view->filename_vpath != NULL)
252 save_file_position (view->filename_vpath, -1, 0,
253 view->hex_mode ? view->hex_cursor : view->dpy_start,
254 view->saved_bookmarks);
255 view->saved_bookmarks = NULL;
258 /* Write back the global viewer mode */
259 mcview_default_hex_mode = view->hex_mode;
260 mcview_default_nroff_flag = view->text_nroff_mode;
261 mcview_default_magic_flag = view->magic_mode;
262 mcview_global_wrap_mode = view->text_wrap_mode;
264 /* Free memory used by the viewer */
266 /* view->widget needs no destructor */
268 vfs_path_free (view->filename_vpath);
269 view->filename_vpath = NULL;
270 vfs_path_free (view->workdir_vpath);
271 view->workdir_vpath = NULL;
272 g_free (view->command);
273 view->command = NULL;
275 mcview_close_datasource (view);
276 /* the growing buffer is freed with the datasource */
278 coord_cache_free (view->coord_cache), view->coord_cache = NULL;
280 if (view->converter == INVALID_CONV)
281 view->converter = str_cnv_from_term;
283 if (view->converter != str_cnv_from_term)
285 str_close_conv (view->converter);
286 view->converter = str_cnv_from_term;
289 mc_search_free (view->search);
290 view->search = NULL;
291 g_free (view->last_search_string);
292 view->last_search_string = NULL;
293 mcview_nroff_seq_free (&view->search_nroff_seq);
294 mcview_hexedit_free_change_list (view);
296 if (mc_global.mc_run_mode == MC_RUN_VIEWER && view->dir != NULL)
298 /* mcviewer is the owner of file list */
299 clean_dir (view->dir, *view->dir_count);
300 g_free (view->dir->list);
301 g_free (view->dir_count);
302 g_free (view->dir_idx);
303 g_free (view->dir);
306 view->dir = NULL;
309 /* --------------------------------------------------------------------------------------------- */
311 void
312 mcview_set_codeset (mcview_t * view)
314 #ifdef HAVE_CHARSET
315 const char *cp_id = NULL;
317 view->utf8 = TRUE;
318 cp_id =
319 get_codepage_id (mc_global.source_codepage >=
320 0 ? mc_global.source_codepage : mc_global.display_codepage);
321 if (cp_id != NULL)
323 GIConv conv;
324 conv = str_crt_conv_from (cp_id);
325 if (conv != INVALID_CONV)
327 if (view->converter != str_cnv_from_term)
328 str_close_conv (view->converter);
329 view->converter = conv;
331 view->utf8 = (gboolean) str_isutf8 (cp_id);
333 #else
334 (void) view;
335 #endif
338 /* --------------------------------------------------------------------------------------------- */
340 #ifdef HAVE_CHARSET
341 void
342 mcview_select_encoding (mcview_t * view)
344 if (do_select_codepage ())
345 mcview_set_codeset (view);
347 #endif
349 /* --------------------------------------------------------------------------------------------- */
351 void
352 mcview_show_error (mcview_t * view, const char *msg)
354 mcview_close_datasource (view);
355 if (mcview_is_in_panel (view))
357 mcview_set_datasource_string (view, msg);
359 else
361 message (D_ERROR, MSG_ERROR, "%s", msg);
365 /* --------------------------------------------------------------------------------------------- */
366 /** returns index of the first char in the line
367 * it is constant for all line characters
370 off_t
371 mcview_bol (mcview_t * view, off_t current, off_t limit)
373 int c;
374 off_t filesize;
375 filesize = mcview_get_filesize (view);
376 if (current <= 0)
377 return 0;
378 if (current > filesize)
379 return filesize;
380 if (!mcview_get_byte (view, current, &c))
381 return current;
382 if (c == '\n')
384 if (!mcview_get_byte (view, current - 1, &c))
385 return current;
386 if (c == '\r')
387 current--;
389 while (current > 0 && current >= limit)
391 if (!mcview_get_byte (view, current - 1, &c))
392 break;
393 if (c == '\r' || c == '\n')
394 break;
395 current--;
397 return current;
400 /* --------------------------------------------------------------------------------------------- */
401 /** returns index of last char on line + width EOL
402 * mcview_eol of the current line == mcview_bol next line
405 off_t
406 mcview_eol (mcview_t * view, off_t current, off_t limit)
408 int c, prev_ch = 0;
409 off_t filesize;
410 filesize = mcview_get_filesize (view);
411 if (current < 0)
412 return 0;
413 if (current >= filesize)
414 return filesize;
415 while (current < filesize && current < limit)
417 if (!mcview_get_byte (view, current, &c))
418 break;
419 if (c == '\n')
421 current++;
422 break;
424 else if (prev_ch == '\r')
426 break;
428 current++;
429 prev_ch = c;
431 return current;
434 /* --------------------------------------------------------------------------------------------- */
436 char *
437 mcview_get_title (const Dlg_head * h, size_t len)
439 const mcview_t *view = (const mcview_t *) find_widget_type (h, mcview_callback);
440 const char *modified = view->hexedit_mode && (view->change_list != NULL) ? "(*) " : " ";
441 const char *file_label;
442 char *view_filename;
443 char *ret_str;
445 view_filename = view->filename_vpath != NULL ? vfs_path_to_str (view->filename_vpath) : NULL;
447 len -= 4;
449 file_label = view_filename != NULL ? view_filename : view->command != NULL ? view->command : "";
450 file_label = str_term_trim (file_label, len - str_term_width1 (_("View: ")));
452 ret_str = g_strconcat (_("View: "), modified, file_label, (char *) NULL);
453 g_free (view_filename);
454 return ret_str;
457 /* --------------------------------------------------------------------------------------------- */