2 Internal file viewer for the Midnight Commander
3 Function for search data
5 Copyright (C) 1994-2016
6 Free Software Foundation, Inc.
9 Miguel de Icaza, 1994, 1995, 1998
10 Janne Kukonlehto, 1994, 1995
12 Joseph M. Hinkle, 1996
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/>.
38 #include "lib/global.h"
39 #include "lib/strutil.h"
40 #include "lib/widget.h"
42 #include "src/setup.h"
46 /*** global variables ****************************************************************************/
48 /*** file scope macro definitions ****************************************************************/
50 /*** file scope type declarations ****************************************************************/
54 simple_status_msg_t status_msg
; /* base class */
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 /* --------------------------------------------------------------------------------------------- */
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
);
79 percent
= mcview_calc_percent (vsm
->view
, vsm
->offset
);
82 label_set_textv (ssm
->label
, _("Searching %s: %3d%%"), vsm
->view
->last_search_string
,
85 label_set_textv (ssm
->label
, _("Searching %s"), vsm
->view
->last_search_string
);
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
);
98 return status_msg_common_update (sm
);
101 /* --------------------------------------------------------------------------------------------- */
104 mcview_search_update_steps (WView
* view
)
108 filesize
= mcview_get_filesize (view
);
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 /* --------------------------------------------------------------------------------------------- */
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
++;
153 mc_search_set_error (view
->search
, MC_SEARCH_E_NOTFOUND
, "%s", _(STR_E_NOTFOUND
));
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 /* --------------------------------------------------------------------------------------------- */
165 mcview_search_show_result (WView
* view
, size_t match_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
;
176 view
->search_start
++;
179 view
->text_nroff_mode
? mcview__get_nroff_real_len (view
, view
->search_start
- 1,
181 view
->search_end
= view
->search_start
+ match_len
+ nroff_len
;
183 mcview_moveto_match (view
);
186 /* --------------------------------------------------------------------------------------------- */
187 /*** public functions ****************************************************************************/
188 /* --------------------------------------------------------------------------------------------- */
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
);
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 */
227 case NROFF_TYPE_UNDERLINE
:
228 view
->search_numNeedSkipChar
= 2; /* underline symbol and ox8 */
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 /* --------------------------------------------------------------------------------------------- */
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. */
266 /* --------------------------------------------------------------------------------------------- */
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
;
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);
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)
295 -(mcview__get_nroff_real_len (view
, nroff
->index
- 1, 2) +
296 nroff
->char_length
+ 1);
300 mcview_nroff_seq_free (&nroff
);
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)
313 /* Compute the percent steps */
314 mcview_search_update_steps (view
);
316 view
->update_activate
= search_start
;
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
);
329 if (view
->growbuf_in_use
)
330 growbufsize
= mcview_growbuf_filesize (view
);
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
);
341 if (view
->search
->error_str
== NULL
)
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
);
356 (_("Search done"), _("Continue from beginning?"), D_NORMAL
, 2, _("&Yes"),
361 /* continue search from beginning */
362 view
->update_activate
= 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
);
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"));
391 /* --------------------------------------------------------------------------------------------- */