Add edit_add_window() function.
[midnight-commander.git] / src / viewer / lib.c
blob3a8db25016aea733bbf097c79e6b60c1610cf085
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 #include "lib/charsets.h"
49 #include "src/main.h"
50 #include "src/selcodepage.h"
52 #include "internal.h"
53 #include "mcviewer.h"
55 /*** global variables ****************************************************************************/
57 #define OFF_T_BITWIDTH (unsigned int) (sizeof (off_t) * CHAR_BIT - 1)
58 const off_t INVALID_OFFSET = (off_t) - 1;
59 const off_t OFFSETTYPE_MAX = ((off_t) 1 << (OFF_T_BITWIDTH - 1)) - 1;
61 /*** file scope macro definitions ****************************************************************/
63 /*** file scope type declarations ****************************************************************/
65 /*** file scope variables ************************************************************************/
67 /*** file scope functions ************************************************************************/
68 /* --------------------------------------------------------------------------------------------- */
70 /* --------------------------------------------------------------------------------------------- */
71 /*** public functions ****************************************************************************/
72 /* --------------------------------------------------------------------------------------------- */
74 void
75 mcview_toggle_magic_mode (mcview_t * view)
77 char *filename, *command;
78 dir_list *dir;
79 int *dir_count, *dir_idx;
81 mcview_altered_magic_flag = 1;
82 view->magic_mode = !view->magic_mode;
84 /* reinit view */
85 filename = vfs_path_to_str (view->filename_vpath);
86 command = g_strdup (view->command);
87 dir = view->dir;
88 dir_count = view->dir_count;
89 dir_idx = view->dir_idx;
90 view->dir = NULL;
91 view->dir_count = NULL;
92 view->dir_idx = NULL;
93 mcview_done (view);
94 mcview_init (view);
95 mcview_load (view, command, filename, 0);
96 view->dir = dir;
97 view->dir_count = dir_count;
98 view->dir_idx = dir_idx;
99 g_free (filename);
100 g_free (command);
102 view->dpy_bbar_dirty = TRUE;
103 view->dirty++;
106 /* --------------------------------------------------------------------------------------------- */
108 void
109 mcview_toggle_wrap_mode (mcview_t * view)
111 if (view->text_wrap_mode)
112 view->dpy_start = mcview_bol (view, view->dpy_start, 0);
113 view->text_wrap_mode = !view->text_wrap_mode;
114 view->dpy_bbar_dirty = TRUE;
115 view->dirty++;
118 /* --------------------------------------------------------------------------------------------- */
120 void
121 mcview_toggle_nroff_mode (mcview_t * view)
123 view->text_nroff_mode = !view->text_nroff_mode;
124 mcview_altered_nroff_flag = 1;
125 view->dpy_bbar_dirty = TRUE;
126 view->dirty++;
129 /* --------------------------------------------------------------------------------------------- */
131 void
132 mcview_toggle_hex_mode (mcview_t * view)
134 view->hex_mode = !view->hex_mode;
136 if (view->hex_mode)
138 view->hex_cursor = view->dpy_start;
139 view->dpy_start = mcview_offset_rounddown (view->dpy_start, view->bytes_per_line);
140 widget_want_cursor (view->widget, 1);
142 else
144 view->dpy_start = mcview_bol (view, view->hex_cursor, 0);
145 view->hex_cursor = view->dpy_start;
146 widget_want_cursor (view->widget, 0);
148 mcview_altered_hex_mode = 1;
149 view->dpy_bbar_dirty = TRUE;
150 view->dirty++;
153 /* --------------------------------------------------------------------------------------------- */
155 gboolean
156 mcview_ok_to_quit (mcview_t * view)
158 int r;
160 if (view->change_list == NULL)
161 return TRUE;
163 if (!mc_global.midnight_shutdown)
165 query_set_sel (2);
166 r = query_dialog (_("Quit"),
167 _("File was modified. Save with exit?"), D_NORMAL, 3,
168 _("&Yes"), _("&No"), _("&Cancel quit"));
170 else
172 r = query_dialog (_("Quit"),
173 _("Midnight Commander is being shut down.\nSave modified file?"),
174 D_NORMAL, 2, _("&Yes"), _("&No"));
175 /* Esc is No */
176 if (r == -1)
177 r = 1;
180 switch (r)
182 case 0: /* Yes */
183 return mcview_hexedit_save_changes (view) || mc_global.midnight_shutdown;
184 case 1: /* No */
185 mcview_hexedit_free_change_list (view);
186 return TRUE;
187 default:
188 return FALSE;
192 /* --------------------------------------------------------------------------------------------- */
194 void
195 mcview_init (mcview_t * view)
197 size_t i;
199 view->filename_vpath = NULL;
200 view->workdir_vpath = NULL;
201 view->command = NULL;
202 view->search_nroff_seq = NULL;
204 mcview_set_datasource_none (view);
206 view->growbuf_in_use = FALSE;
207 /* leave the other growbuf fields uninitialized */
209 view->hexedit_lownibble = FALSE;
210 view->locked = FALSE;
211 view->coord_cache = NULL;
213 view->dpy_start = 0;
214 view->dpy_text_column = 0;
215 view->dpy_end = 0;
216 view->hex_cursor = 0;
217 view->cursor_col = 0;
218 view->cursor_row = 0;
219 view->change_list = NULL;
221 /* {status,ruler,data}_area are left uninitialized */
223 view->dirty = 0;
224 view->dpy_bbar_dirty = TRUE;
225 view->bytes_per_line = 1;
227 view->search_start = 0;
228 view->search_end = 0;
230 view->marker = 0;
231 for (i = 0; i < sizeof (view->marks) / sizeof (view->marks[0]); i++)
232 view->marks[i] = 0;
234 view->update_steps = 0;
235 view->update_activate = 0;
237 view->saved_bookmarks = NULL;
240 /* --------------------------------------------------------------------------------------------- */
242 void
243 mcview_done (mcview_t * view)
245 /* Save current file position */
246 if (mcview_remember_file_position && view->filename_vpath != NULL)
248 save_file_position (view->filename_vpath, -1, 0,
249 view->hex_mode ? view->hex_cursor : view->dpy_start,
250 view->saved_bookmarks);
251 view->saved_bookmarks = NULL;
254 /* Write back the global viewer mode */
255 mcview_default_hex_mode = view->hex_mode;
256 mcview_default_nroff_flag = view->text_nroff_mode;
257 mcview_default_magic_flag = view->magic_mode;
258 mcview_global_wrap_mode = view->text_wrap_mode;
260 /* Free memory used by the viewer */
262 /* view->widget needs no destructor */
264 vfs_path_free (view->filename_vpath);
265 view->filename_vpath = NULL;
266 vfs_path_free (view->workdir_vpath);
267 view->workdir_vpath = NULL;
268 g_free (view->command);
269 view->command = NULL;
271 mcview_close_datasource (view);
272 /* the growing buffer is freed with the datasource */
274 coord_cache_free (view->coord_cache), view->coord_cache = NULL;
276 if (view->converter == INVALID_CONV)
277 view->converter = str_cnv_from_term;
279 if (view->converter != str_cnv_from_term)
281 str_close_conv (view->converter);
282 view->converter = str_cnv_from_term;
285 mc_search_free (view->search);
286 view->search = NULL;
287 g_free (view->last_search_string);
288 view->last_search_string = NULL;
289 mcview_nroff_seq_free (&view->search_nroff_seq);
290 mcview_hexedit_free_change_list (view);
292 if (mc_global.mc_run_mode == MC_RUN_VIEWER && view->dir != NULL)
294 /* mcviewer is the owner of file list */
295 clean_dir (view->dir, *view->dir_count);
296 g_free (view->dir->list);
297 g_free (view->dir_count);
298 g_free (view->dir_idx);
299 g_free (view->dir);
302 view->dir = NULL;
305 /* --------------------------------------------------------------------------------------------- */
307 void
308 mcview_set_codeset (mcview_t * view)
310 #ifdef HAVE_CHARSET
311 const char *cp_id = NULL;
313 view->utf8 = TRUE;
314 cp_id =
315 get_codepage_id (mc_global.source_codepage >=
316 0 ? mc_global.source_codepage : mc_global.display_codepage);
317 if (cp_id != NULL)
319 GIConv conv;
320 conv = str_crt_conv_from (cp_id);
321 if (conv != INVALID_CONV)
323 if (view->converter != str_cnv_from_term)
324 str_close_conv (view->converter);
325 view->converter = conv;
327 view->utf8 = (gboolean) str_isutf8 (cp_id);
329 #else
330 (void) view;
331 #endif
334 /* --------------------------------------------------------------------------------------------- */
336 void
337 mcview_select_encoding (mcview_t * view)
339 #ifdef HAVE_CHARSET
340 if (do_select_codepage ())
341 mcview_set_codeset (view);
342 #else
343 (void) view;
344 #endif
347 /* --------------------------------------------------------------------------------------------- */
349 void
350 mcview_show_error (mcview_t * view, const char *msg)
352 mcview_close_datasource (view);
353 if (mcview_is_in_panel (view))
355 mcview_set_datasource_string (view, msg);
357 else
359 message (D_ERROR, MSG_ERROR, "%s", msg);
363 /* --------------------------------------------------------------------------------------------- */
364 /** returns index of the first char in the line
365 * it is constant for all line characters
368 off_t
369 mcview_bol (mcview_t * view, off_t current, off_t limit)
371 int c;
372 off_t filesize;
373 filesize = mcview_get_filesize (view);
374 if (current <= 0)
375 return 0;
376 if (current > filesize)
377 return filesize;
378 if (!mcview_get_byte (view, current, &c))
379 return current;
380 if (c == '\n')
382 if (!mcview_get_byte (view, current - 1, &c))
383 return current;
384 if (c == '\r')
385 current--;
387 while (current > 0 && current >= limit)
389 if (!mcview_get_byte (view, current - 1, &c))
390 break;
391 if (c == '\r' || c == '\n')
392 break;
393 current--;
395 return current;
398 /* --------------------------------------------------------------------------------------------- */
399 /** returns index of last char on line + width EOL
400 * mcview_eol of the current line == mcview_bol next line
403 off_t
404 mcview_eol (mcview_t * view, off_t current, off_t limit)
406 int c, prev_ch = 0;
407 off_t filesize;
408 filesize = mcview_get_filesize (view);
409 if (current < 0)
410 return 0;
411 if (current >= filesize)
412 return filesize;
413 while (current < filesize && current < limit)
415 if (!mcview_get_byte (view, current, &c))
416 break;
417 if (c == '\n')
419 current++;
420 break;
422 else if (prev_ch == '\r')
424 break;
426 current++;
427 prev_ch = c;
429 return current;
432 /* --------------------------------------------------------------------------------------------- */
434 char *
435 mcview_get_title (const Dlg_head * h, size_t len)
437 const mcview_t *view = (const mcview_t *) find_widget_type (h, mcview_callback);
438 const char *modified = view->hexedit_mode && (view->change_list != NULL) ? "(*) " : " ";
439 const char *file_label;
440 char *view_filename;
441 char *ret_str;
443 view_filename = view->filename_vpath != NULL ? vfs_path_to_str (view->filename_vpath) : NULL;
445 len -= 4;
447 file_label = view_filename != NULL ? view_filename : view->command != NULL ? view->command : "";
448 file_label = str_term_trim (file_label, len - str_term_width1 (_("View: ")));
450 ret_str = g_strconcat (_("View: "), modified, file_label, (char *) NULL);
451 g_free (view_filename);
452 return ret_str;
455 /* --------------------------------------------------------------------------------------------- */