mcview: refactoring of mcview_get_utf().
[midnight-commander.git] / src / viewer / search.c
blob10af1f3fa4e0dee0d8a007d4feaead1aed237d75
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 = mcview_get_filesize (view);
107 if (filesize != 0)
108 view->update_steps = 40000;
109 else /* viewing a data stream, not a file */
110 view->update_steps = filesize / 100;
112 /* Do not update the percent display but every 20 ks */
113 if (view->update_steps < 20000)
114 view->update_steps = 20000;
117 /* --------------------------------------------------------------------------------------------- */
119 static gboolean
120 mcview_find (mcview_search_status_msg_t * ssm, off_t search_start, off_t search_end, gsize * len)
122 WView *view = ssm->view;
124 view->search_numNeedSkipChar = 0;
125 search_cb_char_curr_index = -1;
127 if (mcview_search_options.backwards)
129 search_end = mcview_get_filesize (view);
130 while (search_start >= 0)
132 view->search_nroff_seq->index = search_start;
133 mcview_nroff_seq_info (view->search_nroff_seq);
135 if (search_end > search_start + (off_t) view->search->original_len
136 && mc_search_is_fixed_search_str (view->search))
137 search_end = search_start + view->search->original_len;
139 if (mc_search_run (view->search, (void *) ssm, search_start, search_end, len)
140 && view->search->normal_offset == search_start)
142 if (view->text_nroff_mode)
143 view->search->normal_offset++;
144 return TRUE;
147 search_start--;
149 view->search->error_str = g_strdup (_(STR_E_NOTFOUND));
150 return FALSE;
152 view->search_nroff_seq->index = search_start;
153 mcview_nroff_seq_info (view->search_nroff_seq);
155 return mc_search_run (view->search, (void *) ssm, search_start, search_end, len);
158 /* --------------------------------------------------------------------------------------------- */
160 static void
161 mcview_search_show_result (WView * view, size_t match_len)
163 int nroff_len;
165 nroff_len =
166 view->text_nroff_mode
167 ? mcview__get_nroff_real_len (view, view->search->start_buffer,
168 view->search->normal_offset - view->search->start_buffer) : 0;
169 view->search_start = view->search->normal_offset + nroff_len;
171 if (!view->hex_mode)
172 view->search_start++;
174 nroff_len =
175 view->text_nroff_mode ? mcview__get_nroff_real_len (view, view->search_start - 1,
176 match_len) : 0;
177 view->search_end = view->search_start + match_len + nroff_len;
179 mcview_moveto_match (view);
182 /* --------------------------------------------------------------------------------------------- */
183 /*** public functions ****************************************************************************/
184 /* --------------------------------------------------------------------------------------------- */
186 mc_search_cbret_t
187 mcview_search_cmd_callback (const void *user_data, gsize char_offset, int *current_char)
189 WView *view = ((const mcview_search_status_msg_t *) user_data)->view;
191 /* view_read_continue (view, &view->search_onechar_info); *//* AB:FIXME */
192 if (!view->text_nroff_mode)
194 mcview_get_byte (view, char_offset, current_char);
195 return MC_SEARCH_CB_OK;
198 if (view->search_numNeedSkipChar != 0)
200 view->search_numNeedSkipChar--;
201 return MC_SEARCH_CB_SKIP;
204 if (search_cb_char_curr_index == -1
205 || search_cb_char_curr_index >= view->search_nroff_seq->char_length)
207 if (search_cb_char_curr_index != -1)
208 mcview_nroff_seq_next (view->search_nroff_seq);
210 search_cb_char_curr_index = 0;
211 if (view->search_nroff_seq->char_length > 1)
212 g_unichar_to_utf8 (view->search_nroff_seq->current_char, search_cb_char_buffer);
213 else
214 search_cb_char_buffer[0] = (char) view->search_nroff_seq->current_char;
216 if (view->search_nroff_seq->type != NROFF_TYPE_NONE)
218 switch (view->search_nroff_seq->type)
220 case NROFF_TYPE_BOLD:
221 view->search_numNeedSkipChar = 1 + view->search_nroff_seq->char_length; /* real char length and 0x8 */
222 break;
223 case NROFF_TYPE_UNDERLINE:
224 view->search_numNeedSkipChar = 2; /* underline symbol and ox8 */
225 break;
226 default:
227 break;
230 return MC_SEARCH_CB_INVALID;
233 *current_char = search_cb_char_buffer[search_cb_char_curr_index];
234 search_cb_char_curr_index++;
236 return (*current_char != -1) ? MC_SEARCH_CB_OK : MC_SEARCH_CB_INVALID;
239 /* --------------------------------------------------------------------------------------------- */
241 mc_search_cbret_t
242 mcview_search_update_cmd_callback (const void *user_data, gsize char_offset)
244 status_msg_t *sm = STATUS_MSG (user_data);
245 mcview_search_status_msg_t *vsm = (mcview_search_status_msg_t *) user_data;
246 mc_search_cbret_t result = MC_SEARCH_CB_OK;
248 vsm->offset = (off_t) char_offset;
249 if (vsm->offset >= vsm->view->update_activate)
251 vsm->view->update_activate += vsm->view->update_steps;
253 if (sm->update (sm) == B_CANCEL)
254 result = MC_SEARCH_CB_ABORT;
257 /* may be in future return from this callback will change current position in searching block. */
259 return result;
262 /* --------------------------------------------------------------------------------------------- */
264 void
265 mcview_do_search (WView * view, off_t want_search_start)
267 mcview_search_status_msg_t vsm;
269 off_t search_start = 0;
270 off_t orig_search_start = view->search_start;
271 gboolean found = FALSE;
273 size_t match_len;
275 view->search_start = want_search_start;
276 /* for avoid infinite search loop we need to increase or decrease start offset of search */
278 if (view->search_start != 0)
280 if (!view->text_nroff_mode)
281 search_start = view->search_start + (mcview_search_options.backwards ? -2 : 0);
282 else
284 if (mcview_search_options.backwards)
286 mcview_nroff_t *nroff;
288 nroff = mcview_nroff_seq_new_num (view, view->search_start);
289 if (mcview_nroff_seq_prev (nroff) != -1)
290 search_start =
291 -(mcview__get_nroff_real_len (view, nroff->index - 1, 2) +
292 nroff->char_length + 1);
293 else
294 search_start = -2;
296 mcview_nroff_seq_free (&nroff);
298 else
300 search_start = mcview__get_nroff_real_len (view, view->search_start + 1, 2);
302 search_start += view->search_start;
306 if (mcview_search_options.backwards && search_start < 0)
307 search_start = 0;
309 /* Compute the percent steps */
310 mcview_search_update_steps (view);
312 view->update_activate = search_start;
314 vsm.first = TRUE;
315 vsm.view = view;
316 vsm.offset = search_start;
318 status_msg_init (STATUS_MSG (&vsm), _("Search"), 1.0, simple_status_msg_init_cb,
319 mcview_search_status_update_cb, NULL);
323 off_t growbufsize;
325 if (view->growbuf_in_use)
326 growbufsize = mcview_growbuf_filesize (view);
327 else
328 growbufsize = view->search->original_len;
330 if (mcview_find (&vsm, search_start, mcview_get_filesize (view), &match_len))
332 mcview_search_show_result (view, match_len);
333 found = TRUE;
334 break;
337 if (view->search->error_str == NULL)
338 break;
340 search_start = growbufsize - view->search->original_len;
342 while (search_start > 0 && mcview_may_still_grow (view));
344 status_msg_deinit (STATUS_MSG (&vsm));
346 if (orig_search_start != 0 && !found && !mcview_search_options.backwards)
348 view->search_start = orig_search_start;
349 mcview_update (view);
351 if (query_dialog
352 (_("Search done"), _("Continue from beginning?"), D_NORMAL, 2, _("&Yes"),
353 _("&No")) != 0)
354 found = TRUE;
355 else
357 /* continue search from beginning */
358 view->update_activate = 0;
360 vsm.first = TRUE;
361 vsm.view = view;
362 vsm.offset = 0;
364 status_msg_init (STATUS_MSG (&vsm), _("Search"), 1.0, simple_status_msg_init_cb,
365 mcview_search_status_update_cb, NULL);
367 /* search from file begin up to initial search start position */
368 if (mcview_find (&vsm, 0, orig_search_start, &match_len))
370 mcview_search_show_result (view, match_len);
371 found = TRUE;
374 status_msg_deinit (STATUS_MSG (&vsm));
378 if (!found && view->search->error_str != NULL)
380 view->search_start = orig_search_start;
381 mcview_update (view);
382 query_dialog (_("Search"), view->search->error_str, D_NORMAL, 1, _("&Dismiss"));
384 view->dirty++;
387 /* --------------------------------------------------------------------------------------------- */