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;
119 /* Make interrupt more responsive */
120 if (view
->update_steps
> 40000)
121 view
->update_steps
= 40000;
124 /* --------------------------------------------------------------------------------------------- */
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)
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
++;
157 if (!ok
&& view
->search
->error
== MC_SEARCH_E_ABORT
)
163 mc_search_set_error (view
->search
, MC_SEARCH_E_NOTFOUND
, "%s", _(STR_E_NOTFOUND
));
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 /* --------------------------------------------------------------------------------------------- */
175 mcview_search_show_result (WView
* view
, size_t match_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
;
186 view
->search_start
++;
189 view
->text_nroff_mode
? mcview__get_nroff_real_len (view
, view
->search_start
- 1,
191 view
->search_end
= view
->search_start
+ match_len
+ nroff_len
;
193 mcview_moveto_match (view
);
196 /* --------------------------------------------------------------------------------------------- */
197 /*** public functions ****************************************************************************/
198 /* --------------------------------------------------------------------------------------------- */
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
);
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 */
237 case NROFF_TYPE_UNDERLINE
:
238 view
->search_numNeedSkipChar
= 2; /* underline symbol and ox8 */
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 /* --------------------------------------------------------------------------------------------- */
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
;
277 if (vsm
->offset
>= view
->update_activate
)
279 view
->update_activate
+= view
->update_steps
;
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. */
293 /* --------------------------------------------------------------------------------------------- */
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
;
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);
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)
322 -(mcview__get_nroff_real_len (view
, nroff
->index
- 1, 2) +
323 nroff
->char_length
+ 1);
327 mcview_nroff_seq_free (&nroff
);
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)
340 /* Compute the percent steps */
341 mcview_search_update_steps (view
);
343 view
->update_activate
= search_start
;
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
);
356 if (view
->growbuf_in_use
)
357 growbufsize
= mcview_growbuf_filesize (view
);
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
);
368 if (view
->search
->error
== MC_SEARCH_E_ABORT
|| view
->search
->error
== MC_SEARCH_E_NOTFOUND
)
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
);
383 (_("Search done"), _("Continue from beginning?"), D_NORMAL
, 2, _("&Yes"),
388 /* continue search from beginning */
389 view
->update_activate
= 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
);
405 status_msg_deinit (STATUS_MSG (&vsm
));
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"));
424 /* --------------------------------------------------------------------------------------------- */