extfs: tester: fix indentation.
[midnight-commander.git] / src / viewer / lib.c
blobf166184383835602f8d234bf81217ec765b04b49
1 /*
2 Internal file viewer for the Midnight Commander
3 Common finctions (used from some other mcviewer functions)
5 Copyright (C) 1994-2017
6 Free Software Foundation, Inc.
8 Written by:
9 Miguel de Icaza, 1994, 1995, 1998
10 Janne Kukonlehto, 1994, 1995
11 Jakub Jelinek, 1995
12 Joseph M. Hinkle, 1996
13 Norbert Warmuth, 1997
14 Pavel Machek, 1998
15 Roland Illig <roland.illig@gmx.de>, 2004, 2005
16 Slava Zanko <slavazanko@google.com>, 2009, 2013
17 Andrew Borodin <aborodin@vmail.ru>, 2009, 2013, 2014
18 Ilia Maslakov <il.smind@gmail.com>, 2009
20 This file is part of the Midnight Commander.
22 The Midnight Commander is free software: you can redistribute it
23 and/or modify it under the terms of the GNU General Public License as
24 published by the Free Software Foundation, either version 3 of the License,
25 or (at your option) any later version.
27 The Midnight Commander is distributed in the hope that it will be useful,
28 but WITHOUT ANY WARRANTY; without even the implied warranty of
29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 GNU General Public License for more details.
32 You should have received a copy of the GNU General Public License
33 along with this program. If not, see <http://www.gnu.org/licenses/>.
36 #include <config.h>
38 #include <limits.h>
39 #include <sys/types.h>
41 #include "lib/global.h"
42 #include "lib/vfs/vfs.h"
43 #include "lib/strutil.h"
44 #include "lib/util.h" /* save_file_position() */
45 #include "lib/widget.h"
46 #ifdef HAVE_CHARSET
47 #include "lib/charsets.h"
48 #endif
50 #ifdef HAVE_CHARSET
51 #include "src/selcodepage.h"
52 #endif
54 #include "internal.h"
56 /*** global variables ****************************************************************************/
58 #define OFF_T_BITWIDTH (unsigned int) (sizeof (off_t) * CHAR_BIT - 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 (WView * view)
77 char *filename, *command;
78 dir_list *dir;
79 int *dir_idx;
81 mcview_altered_magic_flag = 1;
82 view->magic_mode = !view->magic_mode;
84 /* reinit view */
85 filename = g_strdup (vfs_path_as_str (view->filename_vpath));
86 command = g_strdup (view->command);
87 dir = view->dir;
88 dir_idx = view->dir_idx;
89 view->dir = NULL;
90 view->dir_idx = NULL;
91 mcview_done (view);
92 mcview_init (view);
93 mcview_load (view, command, filename, 0, 0, 0);
94 view->dir = dir;
95 view->dir_idx = dir_idx;
96 g_free (filename);
97 g_free (command);
99 view->dpy_bbar_dirty = TRUE;
100 view->dirty++;
103 /* --------------------------------------------------------------------------------------------- */
105 void
106 mcview_toggle_wrap_mode (WView * view)
108 view->text_wrap_mode = !view->text_wrap_mode;
109 view->dpy_wrap_dirty = TRUE;
110 view->dpy_bbar_dirty = TRUE;
111 view->dirty++;
114 /* --------------------------------------------------------------------------------------------- */
116 void
117 mcview_toggle_nroff_mode (WView * view)
119 view->text_nroff_mode = !view->text_nroff_mode;
120 mcview_altered_nroff_flag = 1;
121 view->dpy_wrap_dirty = TRUE;
122 view->dpy_bbar_dirty = TRUE;
123 view->dirty++;
126 /* --------------------------------------------------------------------------------------------- */
128 void
129 mcview_toggle_hex_mode (WView * view)
131 view->hex_mode = !view->hex_mode;
133 if (view->hex_mode)
135 view->hex_cursor = view->dpy_start;
136 view->dpy_start = mcview_offset_rounddown (view->dpy_start, view->bytes_per_line);
137 widget_want_cursor (WIDGET (view), TRUE);
139 else
141 view->dpy_start = mcview_bol (view, view->hex_cursor, 0);
142 view->hex_cursor = view->dpy_start;
143 widget_want_cursor (WIDGET (view), FALSE);
145 mcview_altered_hex_mode = 1;
146 view->dpy_paragraph_skip_lines = 0;
147 view->dpy_wrap_dirty = TRUE;
148 view->dpy_bbar_dirty = TRUE;
149 view->dirty++;
152 /* --------------------------------------------------------------------------------------------- */
154 void
155 mcview_init (WView * view)
157 size_t i;
159 view->filename_vpath = NULL;
160 view->workdir_vpath = NULL;
161 view->command = NULL;
162 view->search_nroff_seq = NULL;
164 mcview_set_datasource_none (view);
166 view->growbuf_in_use = FALSE;
167 /* leave the other growbuf fields uninitialized */
169 view->hexedit_lownibble = FALSE;
170 view->locked = FALSE;
171 view->coord_cache = NULL;
173 view->dpy_start = 0;
174 view->dpy_paragraph_skip_lines = 0;
175 mcview_state_machine_init (&view->dpy_state_top, 0);
176 view->dpy_wrap_dirty = FALSE;
177 view->force_max = -1;
178 view->dpy_text_column = 0;
179 view->dpy_end = 0;
180 view->hex_cursor = 0;
181 view->cursor_col = 0;
182 view->cursor_row = 0;
183 view->change_list = NULL;
185 /* {status,ruler,data}_area are left uninitialized */
187 view->dirty = 0;
188 view->dpy_bbar_dirty = TRUE;
189 view->bytes_per_line = 1;
191 view->search_start = 0;
192 view->search_end = 0;
194 view->marker = 0;
195 for (i = 0; i < G_N_ELEMENTS (view->marks); i++)
196 view->marks[i] = 0;
198 view->update_steps = 0;
199 view->update_activate = 0;
201 view->saved_bookmarks = NULL;
204 /* --------------------------------------------------------------------------------------------- */
206 void
207 mcview_done (WView * view)
209 /* Save current file position */
210 if (mcview_remember_file_position && view->filename_vpath != NULL)
212 save_file_position (view->filename_vpath, -1, 0,
213 view->hex_mode ? view->hex_cursor : view->dpy_start,
214 view->saved_bookmarks);
215 view->saved_bookmarks = NULL;
218 /* Write back the global viewer mode */
219 mcview_default_hex_mode = view->hex_mode;
220 mcview_default_nroff_flag = view->text_nroff_mode;
221 mcview_default_magic_flag = view->magic_mode;
222 mcview_global_wrap_mode = view->text_wrap_mode;
224 /* Free memory used by the viewer */
226 /* view->widget needs no destructor */
228 vfs_path_free (view->filename_vpath);
229 view->filename_vpath = NULL;
230 vfs_path_free (view->workdir_vpath);
231 view->workdir_vpath = NULL;
232 MC_PTR_FREE (view->command);
234 mcview_close_datasource (view);
235 /* the growing buffer is freed with the datasource */
237 coord_cache_free (view->coord_cache);
238 view->coord_cache = NULL;
240 if (view->converter == INVALID_CONV)
241 view->converter = str_cnv_from_term;
243 if (view->converter != str_cnv_from_term)
245 str_close_conv (view->converter);
246 view->converter = str_cnv_from_term;
249 mc_search_free (view->search);
250 view->search = NULL;
251 MC_PTR_FREE (view->last_search_string);
252 mcview_nroff_seq_free (&view->search_nroff_seq);
253 mcview_hexedit_free_change_list (view);
255 if (mc_global.mc_run_mode == MC_RUN_VIEWER && view->dir != NULL)
257 /* mcviewer is the owner of file list */
258 dir_list_clean (view->dir);
259 g_free (view->dir->list);
260 g_free (view->dir_idx);
261 g_free (view->dir);
264 view->dir = NULL;
267 /* --------------------------------------------------------------------------------------------- */
269 void
270 mcview_set_codeset (WView * view)
272 #ifdef HAVE_CHARSET
273 const char *cp_id = NULL;
275 view->utf8 = TRUE;
276 cp_id =
277 get_codepage_id (mc_global.source_codepage >=
278 0 ? mc_global.source_codepage : mc_global.display_codepage);
279 if (cp_id != NULL)
281 GIConv conv;
282 conv = str_crt_conv_from (cp_id);
283 if (conv != INVALID_CONV)
285 if (view->converter != str_cnv_from_term)
286 str_close_conv (view->converter);
287 view->converter = conv;
289 view->utf8 = (gboolean) str_isutf8 (cp_id);
290 view->dpy_wrap_dirty = TRUE;
292 #else
293 (void) view;
294 #endif
297 /* --------------------------------------------------------------------------------------------- */
299 #ifdef HAVE_CHARSET
300 void
301 mcview_select_encoding (WView * view)
303 if (do_select_codepage ())
304 mcview_set_codeset (view);
306 #endif
308 /* --------------------------------------------------------------------------------------------- */
310 void
311 mcview_show_error (WView * view, const char *msg)
313 if (mcview_is_in_panel (view))
314 mcview_set_datasource_string (view, msg);
315 else
316 message (D_ERROR, MSG_ERROR, "%s", msg);
319 /* --------------------------------------------------------------------------------------------- */
320 /** returns index of the first char in the line
321 * it is constant for all line characters
324 off_t
325 mcview_bol (WView * view, off_t current, off_t limit)
327 int c;
328 off_t filesize;
329 filesize = mcview_get_filesize (view);
330 if (current <= 0)
331 return 0;
332 if (current > filesize)
333 return filesize;
334 if (!mcview_get_byte (view, current, &c))
335 return current;
336 if (c == '\n')
338 if (!mcview_get_byte (view, current - 1, &c))
339 return current;
340 if (c == '\r')
341 current--;
343 while (current > 0 && current > limit)
345 if (!mcview_get_byte (view, current - 1, &c))
346 break;
347 if (c == '\r' || c == '\n')
348 break;
349 current--;
351 return current;
354 /* --------------------------------------------------------------------------------------------- */
355 /** returns index of last char on line + width EOL
356 * mcview_eol of the current line == mcview_bol next line
359 off_t
360 mcview_eol (WView * view, off_t current, off_t limit)
362 int c, prev_ch = 0;
363 off_t filesize;
364 filesize = mcview_get_filesize (view);
365 if (current < 0)
366 return 0;
367 if (current >= filesize)
368 return filesize;
369 while (current < filesize && current < limit)
371 if (!mcview_get_byte (view, current, &c))
372 break;
373 if (c == '\n')
375 current++;
376 break;
378 else if (prev_ch == '\r')
380 break;
382 current++;
383 prev_ch = c;
385 return current;
388 /* --------------------------------------------------------------------------------------------- */
390 char *
391 mcview_get_title (const WDialog * h, size_t len)
393 const WView *view = (const WView *) find_widget_type (h, mcview_callback);
394 const char *modified = view->hexedit_mode && (view->change_list != NULL) ? "(*) " : " ";
395 const char *file_label;
396 const char *view_filename;
397 char *ret_str;
399 view_filename = vfs_path_as_str (view->filename_vpath);
401 len -= 4;
403 file_label = view_filename != NULL ? view_filename : view->command != NULL ? view->command : "";
404 file_label = str_term_trim (file_label, len - str_term_width1 (_("View: ")));
406 ret_str = g_strconcat (_("View: "), modified, file_label, (char *) NULL);
407 return ret_str;
410 /* --------------------------------------------------------------------------------------------- */
413 mcview_calc_percent (WView * view, off_t p)
415 const screen_dimen right = view->status_area.left + view->status_area.width;
416 const screen_dimen height = view->status_area.height;
417 off_t filesize;
418 int percent;
420 if (height < 1 || right < 4)
421 return (-1);
422 if (mcview_may_still_grow (view))
423 return (-1);
425 filesize = mcview_get_filesize (view);
426 if (view->hex_mode && filesize > 0)
428 /* p can't be beyond the last char, only over that. Compensate for this. */
429 filesize--;
432 if (filesize == 0 || p >= filesize)
433 percent = 100;
434 else if (p > (INT_MAX / 100))
435 percent = p / (filesize / 100);
436 else
437 percent = p * 100 / filesize;
439 return percent;
442 /* --------------------------------------------------------------------------------------------- */