(mcview_search_update_steps): fix calculation of update step.
[midnight-commander.git] / src / viewer / search.c
blob8c40b6a6057f3e8bd78db2067981384ba04b5975
1 /*
2 Internal file viewer for the Midnight Commander
3 Function for search data
5 Copyright (C) 1994-2016
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
17 Andrew Borodin <aborodin@vmail.ru>, 2009, 2013
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 "lib/global.h"
39 #include "lib/strutil.h"
40 #include "lib/widget.h"
42 #include "src/setup.h"
44 #include "internal.h"
46 /*** global variables ****************************************************************************/
48 /*** file scope macro definitions ****************************************************************/
50 /*** file scope type declarations ****************************************************************/
52 typedef struct
54 simple_status_msg_t status_msg; /* base class */
56 gboolean first;
57 WView *view;
58 off_t offset;
59 } mcview_search_status_msg_t;
61 /*** file scope variables ************************************************************************/
63 static int search_cb_char_curr_index = -1;
64 static char search_cb_char_buffer[6];
66 /* --------------------------------------------------------------------------------------------- */
67 /*** file scope functions ************************************************************************/
68 /* --------------------------------------------------------------------------------------------- */
70 static int
71 mcview_search_status_update_cb (status_msg_t * sm)
73 simple_status_msg_t *ssm = SIMPLE_STATUS_MSG (sm);
74 mcview_search_status_msg_t *vsm = (mcview_search_status_msg_t *) sm;
75 Widget *wd = WIDGET (sm->dlg);
76 int percent = -1;
78 if (verbose)
79 percent = mcview_calc_percent (vsm->view, vsm->offset);
81 if (percent >= 0)
82 label_set_textv (ssm->label, _("Searching %s: %3d%%"), vsm->view->last_search_string,
83 percent);
84 else
85 label_set_textv (ssm->label, _("Searching %s"), vsm->view->last_search_string);
87 if (vsm->first)
89 int wd_width;
90 Widget *lw = WIDGET (ssm->label);
92 wd_width = MAX (wd->cols, lw->cols + 6);
93 widget_set_size (wd, wd->y, wd->x, wd->lines, wd_width);
94 widget_set_size (lw, lw->y, wd->x + (wd->cols - lw->cols) / 2, lw->lines, lw->cols);
95 vsm->first = FALSE;
98 return status_msg_common_update (sm);
101 /* --------------------------------------------------------------------------------------------- */
103 static void
104 mcview_search_update_steps (WView * view)
106 off_t filesize;
108 filesize = mcview_get_filesize (view);
110 if (filesize != 0)
111 view->update_steps = filesize / 100;
112 else /* viewing a data stream, not a file */
113 view->update_steps = 40000;
115 /* Do not update the percent display but every 20 kb */
116 if (view->update_steps < 20000)
117 view->update_steps = 20000;
120 /* --------------------------------------------------------------------------------------------- */
122 static gboolean
123 mcview_find (mcview_search_status_msg_t * ssm, off_t search_start, off_t search_end, gsize * len)
125 WView *view = ssm->view;
127 view->search_numNeedSkipChar = 0;
128 search_cb_char_curr_index = -1;
130 if (mcview_search_options.backwards)
132 search_end = mcview_get_filesize (view);
133 while (search_start >= 0)
135 view->search_nroff_seq->index = search_start;
136 mcview_nroff_seq_info (view->search_nroff_seq);
138 if (search_end > search_start + (off_t) view->search->original_len
139 && mc_search_is_fixed_search_str (view->search))
140 search_end = search_start + view->search->original_len;
142 if (mc_search_run (view->search, (void *) ssm, search_start, search_end, len)
143 && view->search->normal_offset == search_start)
145 if (view->text_nroff_mode)
146 view->search->normal_offset++;
147 return TRUE;
150 search_start--;
153 mc_search_set_error (view->search, MC_SEARCH_E_NOTFOUND, "%s", _(STR_E_NOTFOUND));
154 return FALSE;
156 view->search_nroff_seq->index = search_start;
157 mcview_nroff_seq_info (view->search_nroff_seq);
159 return mc_search_run (view->search, (void *) ssm, search_start, search_end, len);
162 /* --------------------------------------------------------------------------------------------- */
164 static void
165 mcview_search_show_result (WView * view, size_t match_len)
167 int nroff_len;
169 nroff_len =
170 view->text_nroff_mode
171 ? mcview__get_nroff_real_len (view, view->search->start_buffer,
172 view->search->normal_offset - view->search->start_buffer) : 0;
173 view->search_start = view->search->normal_offset + nroff_len;
175 if (!view->hex_mode)
176 view->search_start++;
178 nroff_len =
179 view->text_nroff_mode ? mcview__get_nroff_real_len (view, view->search_start - 1,
180 match_len) : 0;
181 view->search_end = view->search_start + match_len + nroff_len;
183 mcview_moveto_match (view);
186 /* --------------------------------------------------------------------------------------------- */
187 /*** public functions ****************************************************************************/
188 /* --------------------------------------------------------------------------------------------- */
190 mc_search_cbret_t
191 mcview_search_cmd_callback (const void *user_data, gsize char_offset, int *current_char)
193 WView *view = ((const mcview_search_status_msg_t *) user_data)->view;
195 /* view_read_continue (view, &view->search_onechar_info); *//* AB:FIXME */
196 if (!view->text_nroff_mode)
198 mcview_get_byte (view, char_offset, current_char);
199 return MC_SEARCH_CB_OK;
202 if (view->search_numNeedSkipChar != 0)
204 view->search_numNeedSkipChar--;
205 return MC_SEARCH_CB_SKIP;
208 if (search_cb_char_curr_index == -1
209 || search_cb_char_curr_index >= view->search_nroff_seq->char_length)
211 if (search_cb_char_curr_index != -1)
212 mcview_nroff_seq_next (view->search_nroff_seq);
214 search_cb_char_curr_index = 0;
215 if (view->search_nroff_seq->char_length > 1)
216 g_unichar_to_utf8 (view->search_nroff_seq->current_char, search_cb_char_buffer);
217 else
218 search_cb_char_buffer[0] = (char) view->search_nroff_seq->current_char;
220 if (view->search_nroff_seq->type != NROFF_TYPE_NONE)
222 switch (view->search_nroff_seq->type)
224 case NROFF_TYPE_BOLD:
225 view->search_numNeedSkipChar = 1 + view->search_nroff_seq->char_length; /* real char length and 0x8 */
226 break;
227 case NROFF_TYPE_UNDERLINE:
228 view->search_numNeedSkipChar = 2; /* underline symbol and ox8 */
229 break;
230 default:
231 break;
234 return MC_SEARCH_CB_INVALID;
237 *current_char = search_cb_char_buffer[search_cb_char_curr_index];
238 search_cb_char_curr_index++;
240 return (*current_char != -1) ? MC_SEARCH_CB_OK : MC_SEARCH_CB_INVALID;
243 /* --------------------------------------------------------------------------------------------- */
245 mc_search_cbret_t
246 mcview_search_update_cmd_callback (const void *user_data, gsize char_offset)
248 status_msg_t *sm = STATUS_MSG (user_data);
249 mcview_search_status_msg_t *vsm = (mcview_search_status_msg_t *) user_data;
250 mc_search_cbret_t result = MC_SEARCH_CB_OK;
252 vsm->offset = (off_t) char_offset;
253 if (vsm->offset >= vsm->view->update_activate)
255 vsm->view->update_activate += vsm->view->update_steps;
257 if (sm->update (sm) == B_CANCEL)
258 result = MC_SEARCH_CB_ABORT;
261 /* may be in future return from this callback will change current position in searching block. */
263 return result;
266 /* --------------------------------------------------------------------------------------------- */
268 void
269 mcview_do_search (WView * view, off_t want_search_start)
271 mcview_search_status_msg_t vsm;
273 off_t search_start = 0;
274 off_t orig_search_start = view->search_start;
275 gboolean found = FALSE;
277 size_t match_len;
279 view->search_start = want_search_start;
280 /* for avoid infinite search loop we need to increase or decrease start offset of search */
282 if (view->search_start != 0)
284 if (!view->text_nroff_mode)
285 search_start = view->search_start + (mcview_search_options.backwards ? -2 : 0);
286 else
288 if (mcview_search_options.backwards)
290 mcview_nroff_t *nroff;
292 nroff = mcview_nroff_seq_new_num (view, view->search_start);
293 if (mcview_nroff_seq_prev (nroff) != -1)
294 search_start =
295 -(mcview__get_nroff_real_len (view, nroff->index - 1, 2) +
296 nroff->char_length + 1);
297 else
298 search_start = -2;
300 mcview_nroff_seq_free (&nroff);
302 else
304 search_start = mcview__get_nroff_real_len (view, view->search_start + 1, 2);
306 search_start += view->search_start;
310 if (mcview_search_options.backwards && search_start < 0)
311 search_start = 0;
313 /* Compute the percent steps */
314 mcview_search_update_steps (view);
316 view->update_activate = search_start;
318 vsm.first = TRUE;
319 vsm.view = view;
320 vsm.offset = search_start;
322 status_msg_init (STATUS_MSG (&vsm), _("Search"), 1.0, simple_status_msg_init_cb,
323 mcview_search_status_update_cb, NULL);
327 off_t growbufsize;
329 if (view->growbuf_in_use)
330 growbufsize = mcview_growbuf_filesize (view);
331 else
332 growbufsize = view->search->original_len;
334 if (mcview_find (&vsm, search_start, mcview_get_filesize (view), &match_len))
336 mcview_search_show_result (view, match_len);
337 found = TRUE;
338 break;
341 if (view->search->error_str == NULL)
342 break;
344 search_start = growbufsize - view->search->original_len;
346 while (search_start > 0 && mcview_may_still_grow (view));
348 status_msg_deinit (STATUS_MSG (&vsm));
350 if (orig_search_start != 0 && !found && !mcview_search_options.backwards)
352 view->search_start = orig_search_start;
353 mcview_update (view);
355 if (query_dialog
356 (_("Search done"), _("Continue from beginning?"), D_NORMAL, 2, _("&Yes"),
357 _("&No")) != 0)
358 found = TRUE;
359 else
361 /* continue search from beginning */
362 view->update_activate = 0;
364 vsm.first = TRUE;
365 vsm.view = view;
366 vsm.offset = 0;
368 status_msg_init (STATUS_MSG (&vsm), _("Search"), 1.0, simple_status_msg_init_cb,
369 mcview_search_status_update_cb, NULL);
371 /* search from file begin up to initial search start position */
372 if (mcview_find (&vsm, 0, orig_search_start, &match_len))
374 mcview_search_show_result (view, match_len);
375 found = TRUE;
378 status_msg_deinit (STATUS_MSG (&vsm));
382 if (!found && view->search->error_str != NULL)
384 view->search_start = orig_search_start;
385 mcview_update (view);
386 query_dialog (_("Search"), view->search->error_str, D_NORMAL, 1, _("&Dismiss"));
388 view->dirty++;
391 /* --------------------------------------------------------------------------------------------- */