Set WOP_TOP_SELECT options for panel widgets: WPanel, WView and WTree.
[midnight-commander.git] / src / viewer / search.c
blobfc7efab1dfceac892074bd9423287be468042082
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;
119 /* Make interrupt more responsive */
120 if (view->update_steps > 40000)
121 view->update_steps = 40000;
124 /* --------------------------------------------------------------------------------------------- */
126 static gboolean
127 mcview_find (mcview_search_status_msg_t * ssm, off_t search_start, off_t search_end, gsize * len)
129 WView *view = ssm->view;
131 view->search_numNeedSkipChar = 0;
132 search_cb_char_curr_index = -1;
134 if (mcview_search_options.backwards)
136 search_end = mcview_get_filesize (view);
137 while (search_start >= 0)
139 gboolean ok;
141 view->search_nroff_seq->index = search_start;
142 mcview_nroff_seq_info (view->search_nroff_seq);
144 if (search_end > search_start + (off_t) view->search->original_len
145 && mc_search_is_fixed_search_str (view->search))
146 search_end = search_start + view->search->original_len;
148 ok = mc_search_run (view->search, (void *) ssm, search_start, search_end, len);
149 if (ok && view->search->normal_offset == search_start)
151 if (view->text_nroff_mode)
152 view->search->normal_offset++;
153 return TRUE;
156 /* Abort search. */
157 if (!ok && view->search->error == MC_SEARCH_E_ABORT)
158 return FALSE;
160 search_start--;
163 mc_search_set_error (view->search, MC_SEARCH_E_NOTFOUND, "%s", _(STR_E_NOTFOUND));
164 return FALSE;
166 view->search_nroff_seq->index = search_start;
167 mcview_nroff_seq_info (view->search_nroff_seq);
169 return mc_search_run (view->search, (void *) ssm, search_start, search_end, len);
172 /* --------------------------------------------------------------------------------------------- */
174 static void
175 mcview_search_show_result (WView * view, size_t match_len)
177 int nroff_len;
179 nroff_len =
180 view->text_nroff_mode
181 ? mcview__get_nroff_real_len (view, view->search->start_buffer,
182 view->search->normal_offset - view->search->start_buffer) : 0;
183 view->search_start = view->search->normal_offset + nroff_len;
185 if (!view->hex_mode)
186 view->search_start++;
188 nroff_len =
189 view->text_nroff_mode ? mcview__get_nroff_real_len (view, view->search_start - 1,
190 match_len) : 0;
191 view->search_end = view->search_start + match_len + nroff_len;
193 mcview_moveto_match (view);
196 /* --------------------------------------------------------------------------------------------- */
197 /*** public functions ****************************************************************************/
198 /* --------------------------------------------------------------------------------------------- */
200 mc_search_cbret_t
201 mcview_search_cmd_callback (const void *user_data, gsize char_offset, int *current_char)
203 WView *view = ((const mcview_search_status_msg_t *) user_data)->view;
205 /* view_read_continue (view, &view->search_onechar_info); *//* AB:FIXME */
206 if (!view->text_nroff_mode)
208 mcview_get_byte (view, char_offset, current_char);
209 return MC_SEARCH_CB_OK;
212 if (view->search_numNeedSkipChar != 0)
214 view->search_numNeedSkipChar--;
215 return MC_SEARCH_CB_SKIP;
218 if (search_cb_char_curr_index == -1
219 || search_cb_char_curr_index >= view->search_nroff_seq->char_length)
221 if (search_cb_char_curr_index != -1)
222 mcview_nroff_seq_next (view->search_nroff_seq);
224 search_cb_char_curr_index = 0;
225 if (view->search_nroff_seq->char_length > 1)
226 g_unichar_to_utf8 (view->search_nroff_seq->current_char, search_cb_char_buffer);
227 else
228 search_cb_char_buffer[0] = (char) view->search_nroff_seq->current_char;
230 if (view->search_nroff_seq->type != NROFF_TYPE_NONE)
232 switch (view->search_nroff_seq->type)
234 case NROFF_TYPE_BOLD:
235 view->search_numNeedSkipChar = 1 + view->search_nroff_seq->char_length; /* real char length and 0x8 */
236 break;
237 case NROFF_TYPE_UNDERLINE:
238 view->search_numNeedSkipChar = 2; /* underline symbol and ox8 */
239 break;
240 default:
241 break;
244 return MC_SEARCH_CB_INVALID;
247 *current_char = search_cb_char_buffer[search_cb_char_curr_index];
248 search_cb_char_curr_index++;
250 return (*current_char != -1) ? MC_SEARCH_CB_OK : MC_SEARCH_CB_INVALID;
253 /* --------------------------------------------------------------------------------------------- */
255 mc_search_cbret_t
256 mcview_search_update_cmd_callback (const void *user_data, gsize char_offset)
258 status_msg_t *sm = STATUS_MSG (user_data);
259 mcview_search_status_msg_t *vsm = (mcview_search_status_msg_t *) user_data;
260 WView *view = vsm->view;
261 gboolean do_update = FALSE;
262 mc_search_cbret_t result = MC_SEARCH_CB_OK;
264 vsm->offset = (off_t) char_offset;
266 if (mcview_search_options.backwards)
268 if (vsm->offset <= view->update_activate)
270 view->update_activate -= view->update_steps;
272 do_update = TRUE;
275 else
277 if (vsm->offset >= view->update_activate)
279 view->update_activate += view->update_steps;
281 do_update = TRUE;
285 if (do_update && sm->update (sm) == B_CANCEL)
286 result = MC_SEARCH_CB_ABORT;
288 /* may be in future return from this callback will change current position in searching block. */
290 return result;
293 /* --------------------------------------------------------------------------------------------- */
295 void
296 mcview_do_search (WView * view, off_t want_search_start)
298 mcview_search_status_msg_t vsm;
300 off_t search_start = 0;
301 off_t orig_search_start = view->search_start;
302 gboolean found = FALSE;
304 size_t match_len;
306 view->search_start = want_search_start;
307 /* for avoid infinite search loop we need to increase or decrease start offset of search */
309 if (view->search_start != 0)
311 if (!view->text_nroff_mode)
312 search_start = view->search_start + (mcview_search_options.backwards ? -2 : 0);
313 else
315 if (mcview_search_options.backwards)
317 mcview_nroff_t *nroff;
319 nroff = mcview_nroff_seq_new_num (view, view->search_start);
320 if (mcview_nroff_seq_prev (nroff) != -1)
321 search_start =
322 -(mcview__get_nroff_real_len (view, nroff->index - 1, 2) +
323 nroff->char_length + 1);
324 else
325 search_start = -2;
327 mcview_nroff_seq_free (&nroff);
329 else
331 search_start = mcview__get_nroff_real_len (view, view->search_start + 1, 2);
333 search_start += view->search_start;
337 if (mcview_search_options.backwards && search_start < 0)
338 search_start = 0;
340 /* Compute the percent steps */
341 mcview_search_update_steps (view);
343 view->update_activate = search_start;
345 vsm.first = TRUE;
346 vsm.view = view;
347 vsm.offset = search_start;
349 status_msg_init (STATUS_MSG (&vsm), _("Search"), 1.0, simple_status_msg_init_cb,
350 mcview_search_status_update_cb, NULL);
354 off_t growbufsize;
356 if (view->growbuf_in_use)
357 growbufsize = mcview_growbuf_filesize (view);
358 else
359 growbufsize = view->search->original_len;
361 if (mcview_find (&vsm, search_start, mcview_get_filesize (view), &match_len))
363 mcview_search_show_result (view, match_len);
364 found = TRUE;
365 break;
368 if (view->search->error == MC_SEARCH_E_ABORT || view->search->error == MC_SEARCH_E_NOTFOUND)
369 break;
371 search_start = growbufsize - view->search->original_len;
373 while (search_start > 0 && mcview_may_still_grow (view));
375 status_msg_deinit (STATUS_MSG (&vsm));
377 if (orig_search_start != 0 && !found && !mcview_search_options.backwards)
379 view->search_start = orig_search_start;
380 mcview_update (view);
382 if (query_dialog
383 (_("Search done"), _("Continue from beginning?"), D_NORMAL, 2, _("&Yes"),
384 _("&No")) != 0)
385 found = TRUE;
386 else
388 /* continue search from beginning */
389 view->update_activate = 0;
391 vsm.first = TRUE;
392 vsm.view = view;
393 vsm.offset = 0;
395 status_msg_init (STATUS_MSG (&vsm), _("Search"), 1.0, simple_status_msg_init_cb,
396 mcview_search_status_update_cb, NULL);
398 /* search from file begin up to initial search start position */
399 if (mcview_find (&vsm, 0, orig_search_start, &match_len))
401 mcview_search_show_result (view, match_len);
402 found = TRUE;
405 status_msg_deinit (STATUS_MSG (&vsm));
409 if (!found
410 && (view->search->error == MC_SEARCH_E_ABORT
411 || view->search->error == MC_SEARCH_E_NOTFOUND))
413 view->search_start = orig_search_start;
414 mcview_update (view);
416 if (view->search->error == MC_SEARCH_E_NOTFOUND)
417 query_dialog (_("Search"), _(STR_E_NOTFOUND), D_NORMAL, 1, _("&Dismiss"));
418 else if (view->search->error_str != NULL)
419 query_dialog (_("Search"), view->search->error_str, D_NORMAL, 1, _("&Dismiss"));
421 view->dirty++;
424 /* --------------------------------------------------------------------------------------------- */