Ticket 1551: Update GPL version from 2 to 3
[midnight-commander.git] / src / viewer / lib.c
bloba8d204820fe5b8a817acbacfbc831058f85759b7
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 = g_strdup (view->filename);
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.widget.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.widget.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 = NULL;
188 view->workdir = 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 != NULL)
237 char *canon_fname;
238 vfs_path_t *vpath;
239 vpath = vfs_path_from_str (view->filename);
240 canon_fname = vfs_path_to_str (vpath);
241 save_file_position (canon_fname, -1, 0,
242 view->hex_mode ? view->hex_cursor : view->dpy_start,
243 view->saved_bookmarks);
244 view->saved_bookmarks = NULL;
245 g_free (canon_fname);
246 vfs_path_free (vpath);
249 /* Write back the global viewer mode */
250 mcview_default_hex_mode = view->hex_mode;
251 mcview_default_nroff_flag = view->text_nroff_mode;
252 mcview_default_magic_flag = view->magic_mode;
253 mcview_global_wrap_mode = view->text_wrap_mode;
255 /* Free memory used by the viewer */
257 /* view->widget needs no destructor */
259 g_free (view->filename);
260 view->filename = NULL;
261 g_free (view->workdir);
262 view->workdir = NULL;
263 g_free (view->command);
264 view->command = NULL;
266 mcview_close_datasource (view);
267 /* the growing buffer is freed with the datasource */
269 coord_cache_free (view->coord_cache), view->coord_cache = NULL;
271 if (view->converter == INVALID_CONV)
272 view->converter = str_cnv_from_term;
274 if (view->converter != str_cnv_from_term)
276 str_close_conv (view->converter);
277 view->converter = str_cnv_from_term;
280 mc_search_free (view->search);
281 view->search = NULL;
282 g_free (view->last_search_string);
283 view->last_search_string = NULL;
284 mcview_nroff_seq_free (&view->search_nroff_seq);
285 mcview_hexedit_free_change_list (view);
288 /* --------------------------------------------------------------------------------------------- */
290 void
291 mcview_set_codeset (mcview_t * view)
293 #ifdef HAVE_CHARSET
294 const char *cp_id = NULL;
296 view->utf8 = TRUE;
297 cp_id =
298 get_codepage_id (mc_global.source_codepage >=
299 0 ? mc_global.source_codepage : mc_global.display_codepage);
300 if (cp_id != NULL)
302 GIConv conv;
303 conv = str_crt_conv_from (cp_id);
304 if (conv != INVALID_CONV)
306 if (view->converter != str_cnv_from_term)
307 str_close_conv (view->converter);
308 view->converter = conv;
310 view->utf8 = (gboolean) str_isutf8 (cp_id);
312 #else
313 (void) view;
314 #endif
317 /* --------------------------------------------------------------------------------------------- */
319 void
320 mcview_select_encoding (mcview_t * view)
322 #ifdef HAVE_CHARSET
323 if (do_select_codepage ())
324 mcview_set_codeset (view);
325 #else
326 (void) view;
327 #endif
330 /* --------------------------------------------------------------------------------------------- */
332 void
333 mcview_show_error (mcview_t * view, const char *msg)
335 mcview_close_datasource (view);
336 if (mcview_is_in_panel (view))
338 mcview_set_datasource_string (view, msg);
340 else
342 message (D_ERROR, MSG_ERROR, "%s", msg);
346 /* --------------------------------------------------------------------------------------------- */
347 /** returns index of the first char in the line
348 * it is constant for all line characters
351 off_t
352 mcview_bol (mcview_t * view, off_t current, off_t limit)
354 int c;
355 off_t filesize;
356 filesize = mcview_get_filesize (view);
357 if (current <= 0)
358 return 0;
359 if (current > filesize)
360 return filesize;
361 if (!mcview_get_byte (view, current, &c))
362 return current;
363 if (c == '\n')
365 if (!mcview_get_byte (view, current - 1, &c))
366 return current;
367 if (c == '\r')
368 current--;
370 while (current > 0 && current >= limit)
372 if (!mcview_get_byte (view, current - 1, &c))
373 break;
374 if (c == '\r' || c == '\n')
375 break;
376 current--;
378 return current;
381 /* --------------------------------------------------------------------------------------------- */
382 /** returns index of last char on line + width EOL
383 * mcview_eol of the current line == mcview_bol next line
386 off_t
387 mcview_eol (mcview_t * view, off_t current, off_t limit)
389 int c, prev_ch = 0;
390 off_t filesize;
391 filesize = mcview_get_filesize (view);
392 if (current < 0)
393 return 0;
394 if (current >= filesize)
395 return filesize;
396 while (current < filesize && current < limit)
398 if (!mcview_get_byte (view, current, &c))
399 break;
400 if (c == '\n')
402 current++;
403 break;
405 else if (prev_ch == '\r')
407 break;
409 current++;
410 prev_ch = c;
412 return current;
415 /* --------------------------------------------------------------------------------------------- */
417 char *
418 mcview_get_title (const Dlg_head * h, size_t len)
420 const mcview_t *view = (const mcview_t *) find_widget_type (h, mcview_callback);
421 const char *modified = view->hexedit_mode && (view->change_list != NULL) ? "(*) " : " ";
422 const char *file_label;
424 len -= 4;
426 file_label = view->filename != NULL ? view->filename :
427 view->command != NULL ? view->command : "";
428 file_label = str_term_trim (file_label, len - str_term_width1 (_("View: ")));
430 return g_strconcat (_("View: "), modified, file_label, (char *) NULL);
433 /* --------------------------------------------------------------------------------------------- */
435 gboolean
436 mcview_lock_file (mcview_t * view)
438 char *fullpath;
439 gboolean ret;
441 fullpath = mc_build_filename (view->workdir, view->filename, (char *) NULL);
442 ret = lock_file (fullpath);
443 g_free (fullpath);
445 return ret;
448 /* --------------------------------------------------------------------------------------------- */
450 gboolean
451 mcview_unlock_file (mcview_t * view)
453 char *fullpath;
454 gboolean ret;
456 fullpath = mc_build_filename (view->workdir, view->filename, (char *) NULL);
457 ret = unlock_file (fullpath);
458 g_free (fullpath);
460 return ret;
463 /* --------------------------------------------------------------------------------------------- */