Fixed search for first symbol in string.
[midnight-commander.git] / src / viewer / search.c
blobbf60b3fb05c711040c970c86dd1dd46d45181aa5
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)
120 view->search_start = view->search->normal_offset +
121 mcview__get_nroff_real_len (view,
122 view->search->start_buffer,
123 view->search->normal_offset - view->search->start_buffer);
125 if (!view->hex_mode)
126 view->search_start++;
128 view->search_end = view->search_start + match_len +
129 mcview__get_nroff_real_len (view, view->search_start - 1, match_len);
131 if (view->hex_mode)
133 view->hex_cursor = view->search_start;
134 view->hexedit_lownibble = FALSE;
135 view->dpy_start = view->search_start - view->search_start % view->bytes_per_line;
136 view->dpy_end = view->search_end - view->search_end % view->bytes_per_line;
139 if (verbose)
141 dlg_run_done (*d);
142 destroy_dlg (*d);
143 *d = create_message (D_NORMAL, _("Search"), _("Seeking to search result"));
144 tty_refresh ();
146 mcview_moveto_match (view);
150 /* --------------------------------------------------------------------------------------------- */
151 /*** public functions ****************************************************************************/
152 /* --------------------------------------------------------------------------------------------- */
155 mcview_search_cmd_callback (const void *user_data, gsize char_offset)
157 int lc_byte;
158 mcview_t *view = (mcview_t *) user_data;
160 /* view_read_continue (view, &view->search_onechar_info); *//* AB:FIXME */
161 if (!view->text_nroff_mode)
163 if (!mcview_get_byte (view, char_offset, &lc_byte))
164 return MC_SEARCH_CB_INVALID;
166 return lc_byte;
169 if (view->search_numNeedSkipChar)
171 view->search_numNeedSkipChar--;
172 return MC_SEARCH_CB_SKIP;
175 if (search_cb_char_curr_index == -1)
177 search_cb_char_curr_index = 0;
178 if (view->search_nroff_seq->char_width > 1)
179 g_unichar_to_utf8 (view->search_nroff_seq->current_char, search_cb_char_buffer);
180 else
181 search_cb_char_buffer[0] = (char) view->search_nroff_seq->current_char;
184 if (search_cb_char_curr_index < view->search_nroff_seq->char_width)
186 lc_byte = search_cb_char_buffer[search_cb_char_curr_index];
187 search_cb_char_curr_index++;
189 return (lc_byte != -1) ? lc_byte : MC_SEARCH_CB_INVALID;
192 mcview_nroff_seq_next (view->search_nroff_seq);
193 search_cb_char_curr_index = 0;
194 if (view->search_nroff_seq->char_width > 1)
195 g_unichar_to_utf8 (view->search_nroff_seq->current_char, search_cb_char_buffer);
196 else
197 search_cb_char_buffer[0] = (char) view->search_nroff_seq->current_char;
199 if (view->search_nroff_seq->type != NROFF_TYPE_NONE)
200 view->search_numNeedSkipChar = 1 + view->search_nroff_seq->char_width;
202 return MC_SEARCH_CB_SKIP;
205 /* --------------------------------------------------------------------------------------------- */
208 mcview_search_update_cmd_callback (const void *user_data, gsize char_offset)
210 mcview_t *view = (mcview_t *) user_data;
212 if (char_offset >= (gsize) view->update_activate)
214 view->update_activate += view->update_steps;
215 if (verbose)
217 mcview_percent (view, char_offset);
218 tty_refresh ();
220 if (tty_got_interrupt ())
221 return MC_SEARCH_CB_ABORT;
223 /* may be in future return from this callback will change current position
224 * in searching block. Now this just constant return value.
226 return MC_SEARCH_CB_OK;
229 /* --------------------------------------------------------------------------------------------- */
231 void
232 mcview_do_search (mcview_t * view)
234 off_t search_start = 0;
235 gboolean isFound = FALSE;
236 gboolean need_search_again = TRUE;
238 Dlg_head *d = NULL;
240 size_t match_len;
242 if (verbose)
244 d = create_message (D_NORMAL, _("Search"), _("Searching %s"), view->last_search_string);
245 tty_refresh ();
248 /*for avoid infinite search loop we need to increase or decrease start offset of search */
250 if (view->search_start != 0)
252 int nroff_real_len = mcview__get_nroff_real_len (view, view->search_start + 1, 2);
253 search_start = mcview_search_options.backwards ? -2 : nroff_real_len != 0 ? 2 : 0;
254 search_start += view->search_start + nroff_real_len * search_start;
257 if (mcview_search_options.backwards && (int) search_start < 0)
258 search_start = 0;
260 /* Compute the percent steps */
261 mcview_search_update_steps (view);
262 view->update_activate = 0;
264 tty_enable_interrupt_key ();
268 off_t growbufsize;
270 if (view->growbuf_in_use)
271 growbufsize = mcview_growbuf_filesize (view);
272 else
273 growbufsize = view->search->original_len;
275 if (mcview_find (view, search_start, &match_len))
277 mcview_search_show_result (view, &d, match_len);
278 need_search_again = FALSE;
279 isFound = TRUE;
280 break;
283 if (view->search->error_str == NULL)
284 break;
286 search_start = growbufsize - view->search->original_len;
287 if (search_start <= 0)
289 search_start = 0;
290 break;
293 while (mcview_may_still_grow (view));
295 if (view->search_start != 0 && !isFound && need_search_again
296 && !mcview_search_options.backwards)
298 int result;
300 mcview_update (view);
302 result =
303 query_dialog (_("Search done"), _("Continue from beginning?"), D_NORMAL, 2, _("&Yes"),
304 _("&No"));
306 if (result != 0)
307 isFound = TRUE;
308 else
309 search_start = 0;
312 if (!isFound && view->search->error_str != NULL && mcview_find (view, search_start, &match_len))
314 mcview_search_show_result (view, &d, match_len);
315 isFound = TRUE;
318 if (!isFound && view->search->error_str != NULL)
319 message (D_NORMAL, _("Search"), "%s", view->search->error_str);
321 view->dirty++;
322 mcview_update (view);
324 tty_disable_interrupt_key ();
325 if (verbose)
327 dlg_run_done (d);
328 destroy_dlg (d);
332 /* --------------------------------------------------------------------------------------------- */