Fixed broken search results highlighting
[midnight-commander.git] / src / viewer / search.c
blob04960a408a47b5fb569e222cfb83e8fb0e93bf37
1 /*
2 Internal file viewer for the Midnight Commander
3 Function for search data
5 Copyright (C) 1994, 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003,
6 2004, 2005, 2006, 2007, 2009 Free Software Foundation, Inc.
8 Written by: 1994, 1995, 1998 Miguel de Icaza
9 1994, 1995 Janne Kukonlehto
10 1995 Jakub Jelinek
11 1996 Joseph M. Hinkle
12 1997 Norbert Warmuth
13 1998 Pavel Machek
14 2004 Roland Illig <roland.illig@gmx.de>
15 2005 Roland Illig <roland.illig@gmx.de>
16 2009 Slava Zanko <slavazanko@google.com>
17 2009 Andrew Borodin <aborodin@vmail.ru>
18 2009 Ilia Maslakov <il.smind@gmail.com>
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 2 of the
25 License, or (at your option) any later version.
27 The Midnight Commander is distributed in the hope that it will be
28 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
29 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
30 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, write to the Free Software
34 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
35 MA 02110-1301, USA.
38 #include <config.h>
40 #include "lib/global.h"
41 #include "lib/tty/tty.h"
42 #include "lib/widget.h"
44 #include "src/setup.h"
46 #include "internal.h"
48 /*** global variables ****************************************************************************/
50 /*** file scope macro definitions ****************************************************************/
52 /*** file scope type declarations ****************************************************************/
54 /*** file scope variables ************************************************************************/
56 static int search_cb_char_curr_index = -1;
57 static char search_cb_char_buffer[6];
59 /*** file scope functions ************************************************************************/
60 /* --------------------------------------------------------------------------------------------- */
62 static void
63 mcview_search_update_steps (mcview_t * view)
65 off_t filesize = mcview_get_filesize (view);
66 if (filesize != 0)
67 view->update_steps = 40000;
68 else /* viewing a data stream, not a file */
69 view->update_steps = filesize / 100;
71 /* Do not update the percent display but every 20 ks */
72 if (view->update_steps < 20000)
73 view->update_steps = 20000;
76 /* --------------------------------------------------------------------------------------------- */
78 static gboolean
79 mcview_find (mcview_t * view, gsize search_start, gsize * len)
81 gsize search_end;
83 view->search_numNeedSkipChar = 0;
84 search_cb_char_curr_index = -1;
86 if (mcview_search_options.backwards)
88 search_end = mcview_get_filesize (view);
89 while ((int) search_start >= 0)
91 view->search_nroff_seq->index = search_start;
92 mcview_nroff_seq_info (view->search_nroff_seq);
94 if (search_end > search_start + view->search->original_len
95 && mc_search_is_fixed_search_str (view->search))
96 search_end = search_start + view->search->original_len;
98 if (mc_search_run (view->search, (void *) view, search_start, search_end, len)
99 && view->search->normal_offset == (off_t) search_start)
100 return TRUE;
102 search_start--;
104 view->search->error_str = g_strdup (_("Search string not found"));
105 return FALSE;
107 view->search_nroff_seq->index = search_start;
108 mcview_nroff_seq_info (view->search_nroff_seq);
110 return mc_search_run (view->search, (void *) view, search_start, mcview_get_filesize (view),
111 len);
114 /* --------------------------------------------------------------------------------------------- */
116 static void
117 mcview_search_show_result (mcview_t * view, Dlg_head ** d, size_t match_len)
119 int nroff_len;
121 nroff_len =
122 view->text_nroff_mode
123 ? mcview__get_nroff_real_len (view, view->search->start_buffer,
124 view->search->normal_offset - view->search->start_buffer) : 0;
125 view->search_start = view->search->normal_offset + nroff_len;
127 if (!view->hex_mode)
128 view->search_start++;
130 nroff_len =
131 view->text_nroff_mode ? mcview__get_nroff_real_len (view, view->search_start - 1,
132 match_len) : 0;
133 view->search_end = view->search_start + match_len + nroff_len;
135 if (view->hex_mode)
137 view->hex_cursor = view->search_start;
138 view->hexedit_lownibble = FALSE;
139 view->dpy_start = view->search_start - view->search_start % view->bytes_per_line;
140 view->dpy_end = view->search_end - view->search_end % view->bytes_per_line;
143 if (verbose)
145 dlg_run_done (*d);
146 destroy_dlg (*d);
147 *d = create_message (D_NORMAL, _("Search"), _("Seeking to search result"));
148 tty_refresh ();
150 mcview_moveto_match (view);
154 /* --------------------------------------------------------------------------------------------- */
155 /*** public functions ****************************************************************************/
156 /* --------------------------------------------------------------------------------------------- */
159 mcview_search_cmd_callback (const void *user_data, gsize char_offset)
161 int lc_byte;
162 mcview_t *view = (mcview_t *) user_data;
164 /* view_read_continue (view, &view->search_onechar_info); *//* AB:FIXME */
165 if (!view->text_nroff_mode)
167 if (!mcview_get_byte (view, char_offset, &lc_byte))
168 return MC_SEARCH_CB_OK;
170 return lc_byte;
173 if (view->search_numNeedSkipChar != 0)
175 view->search_numNeedSkipChar--;
176 return MC_SEARCH_CB_SKIP;
179 if (search_cb_char_curr_index == -1
180 || search_cb_char_curr_index >= view->search_nroff_seq->char_width)
182 if (search_cb_char_curr_index != -1)
183 mcview_nroff_seq_next (view->search_nroff_seq);
185 search_cb_char_curr_index = 0;
186 if (view->search_nroff_seq->char_width > 1)
187 g_unichar_to_utf8 (view->search_nroff_seq->current_char, search_cb_char_buffer);
188 else
189 search_cb_char_buffer[0] = (char) view->search_nroff_seq->current_char;
191 if (view->search_nroff_seq->type != NROFF_TYPE_NONE)
193 switch (view->search_nroff_seq->type)
195 case NROFF_TYPE_BOLD:
196 view->search_numNeedSkipChar = 1 + view->search_nroff_seq->char_width; /* real char width and 0x8 */
197 break;
198 case NROFF_TYPE_UNDERLINE:
199 view->search_numNeedSkipChar = 2; /* underline symbol and ox8 */
200 break;
201 default:
202 break;
205 return MC_SEARCH_CB_INVALID;
208 lc_byte = search_cb_char_buffer[search_cb_char_curr_index];
209 search_cb_char_curr_index++;
210 return (lc_byte != -1) ? (unsigned char) lc_byte : MC_SEARCH_CB_INVALID;
214 /* --------------------------------------------------------------------------------------------- */
217 mcview_search_update_cmd_callback (const void *user_data, gsize char_offset)
219 mcview_t *view = (mcview_t *) user_data;
221 if (char_offset >= (gsize) view->update_activate)
223 view->update_activate += view->update_steps;
224 if (verbose)
226 mcview_percent (view, char_offset);
227 tty_refresh ();
229 if (tty_got_interrupt ())
230 return MC_SEARCH_CB_ABORT;
232 /* may be in future return from this callback will change current position
233 * in searching block. Now this just constant return value.
235 return MC_SEARCH_CB_OK;
238 /* --------------------------------------------------------------------------------------------- */
240 void
241 mcview_do_search (mcview_t * view)
243 off_t search_start = 0;
244 gboolean isFound = FALSE;
245 gboolean need_search_again = TRUE;
247 Dlg_head *d = NULL;
249 size_t match_len;
251 if (verbose)
253 d = create_message (D_NORMAL, _("Search"), _("Searching %s"), view->last_search_string);
254 tty_refresh ();
257 /*for avoid infinite search loop we need to increase or decrease start offset of search */
259 if (view->search_start != 0)
261 if (!view->text_nroff_mode)
262 search_start = view->search_start + (mcview_search_options.backwards ? -2 : 0);
263 else
265 int nroff_real_len = mcview__get_nroff_real_len (view, view->search_start + 1, 2);
266 search_start = mcview_search_options.backwards ? -2 : nroff_real_len != 0 ? 1 : 0;
267 search_start += view->search_start + nroff_real_len * search_start;
271 if (mcview_search_options.backwards && (int) search_start < 0)
272 search_start = 0;
274 /* Compute the percent steps */
275 mcview_search_update_steps (view);
276 view->update_activate = 0;
278 tty_enable_interrupt_key ();
282 off_t growbufsize;
284 if (view->growbuf_in_use)
285 growbufsize = mcview_growbuf_filesize (view);
286 else
287 growbufsize = view->search->original_len;
289 if (mcview_find (view, search_start, &match_len))
291 mcview_search_show_result (view, &d, match_len);
292 need_search_again = FALSE;
293 isFound = TRUE;
294 break;
297 if (view->search->error_str == NULL)
298 break;
300 search_start = growbufsize - view->search->original_len;
301 if (search_start <= 0)
303 search_start = 0;
304 break;
307 while (mcview_may_still_grow (view));
309 if (view->search_start != 0 && !isFound && need_search_again
310 && !mcview_search_options.backwards)
312 int result;
314 mcview_update (view);
316 result =
317 query_dialog (_("Search done"), _("Continue from beginning?"), D_NORMAL, 2, _("&Yes"),
318 _("&No"));
320 if (result != 0)
321 isFound = TRUE;
322 else
323 search_start = 0;
326 if (!isFound && view->search->error_str != NULL && mcview_find (view, search_start, &match_len))
328 mcview_search_show_result (view, &d, match_len);
329 isFound = TRUE;
332 if (!isFound && view->search->error_str != NULL)
333 message (D_NORMAL, _("Search"), "%s", view->search->error_str);
335 view->dirty++;
336 mcview_update (view);
338 tty_disable_interrupt_key ();
339 if (verbose)
341 dlg_run_done (d);
342 destroy_dlg (d);
346 /* --------------------------------------------------------------------------------------------- */