5 Copyright (C) 2009-2016
6 Free Software Foundation, Inc.
9 Slava Zanko <slavazanko@gmail.com>, 2009
10 Andrew Borodin <aborodin@vmail.ru>, 2013
12 This file is part of the Midnight Commander.
14 The Midnight Commander is free software: you can redistribute it
15 and/or modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation, either version 3 of the License,
17 or (at your option) any later version.
19 The Midnight Commander is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
24 You should have received a copy of the GNU General Public License
25 along with this program. If not, see <http://www.gnu.org/licenses/>.
32 #include <sys/types.h>
34 #include "lib/global.h"
35 #include "lib/strutil.h"
36 #include "lib/search.h"
39 #include "lib/charsets.h"
44 /*** global variables ****************************************************************************/
46 /*** file scope macro definitions ****************************************************************/
48 /*** file scope type declarations ****************************************************************/
50 /*** file scope variables ************************************************************************/
52 static const mc_search_type_str_t mc_search__list_types
[] = {
53 {N_("No&rmal"), MC_SEARCH_T_NORMAL
},
54 {N_("Re&gular expression"), MC_SEARCH_T_REGEX
},
55 {N_("He&xadecimal"), MC_SEARCH_T_HEX
},
56 {N_("Wil&dcard search"), MC_SEARCH_T_GLOB
},
57 {NULL
, MC_SEARCH_T_INVALID
}
60 /*** file scope functions ************************************************************************/
62 static mc_search_cond_t
*
63 mc_search__cond_struct_new (mc_search_t
* lc_mc_search
, const char *str
,
64 gsize str_len
, const char *charset
)
66 mc_search_cond_t
*mc_search_cond
;
68 mc_search_cond
= g_malloc0 (sizeof (mc_search_cond_t
));
69 mc_search_cond
->str
= g_string_new_len (str
, str_len
);
70 mc_search_cond
->charset
= g_strdup (charset
);
72 switch (lc_mc_search
->search_type
)
74 case MC_SEARCH_T_GLOB
:
75 mc_search__cond_struct_new_init_glob (charset
, lc_mc_search
, mc_search_cond
);
77 case MC_SEARCH_T_NORMAL
:
78 mc_search__cond_struct_new_init_normal (charset
, lc_mc_search
, mc_search_cond
);
80 case MC_SEARCH_T_REGEX
:
81 mc_search__cond_struct_new_init_regex (charset
, lc_mc_search
, mc_search_cond
);
84 mc_search__cond_struct_new_init_hex (charset
, lc_mc_search
, mc_search_cond
);
89 return mc_search_cond
;
92 /* --------------------------------------------------------------------------------------------- */
95 mc_search__cond_struct_free (mc_search_cond_t
* mc_search_cond
)
97 if (mc_search_cond
->upper
)
98 g_string_free (mc_search_cond
->upper
, TRUE
);
100 if (mc_search_cond
->lower
)
101 g_string_free (mc_search_cond
->lower
, TRUE
);
103 g_string_free (mc_search_cond
->str
, TRUE
);
104 g_free (mc_search_cond
->charset
);
106 #ifdef SEARCH_TYPE_GLIB
107 if (mc_search_cond
->regex_handle
)
108 g_regex_unref (mc_search_cond
->regex_handle
);
109 #else /* SEARCH_TYPE_GLIB */
110 g_free (mc_search_cond
->regex_handle
);
111 #endif /* SEARCH_TYPE_GLIB */
113 g_free (mc_search_cond
);
116 /* --------------------------------------------------------------------------------------------- */
119 mc_search__conditions_free (GPtrArray
* array
)
121 g_ptr_array_foreach (array
, (GFunc
) mc_search__cond_struct_free
, NULL
);
122 g_ptr_array_free (array
, TRUE
);
125 /* --------------------------------------------------------------------------------------------- */
126 /*** public functions ****************************************************************************/
127 /* --------------------------------------------------------------------------------------------- */
128 /* Init search descriptor.
130 * @param original pattern to search
131 * @param original_charset charset of #original. If NULL then cp_display will be used
133 * @return new mc_search_t object. Use #mc_search_free() to free it.
137 mc_search_new (const gchar
* original
, const gchar
* original_charset
)
139 if (original
== NULL
)
142 return mc_search_new_len (original
, strlen (original
), original_charset
);
145 /* --------------------------------------------------------------------------------------------- */
146 /* Init search descriptor.
148 * @param original pattern to search
149 * @param original_len length of #original or -1 if #original is NULL-terminated
150 * @param original_charset charset of #original. If NULL then cp_display will be used
152 * @return new mc_search_t object. Use #mc_search_free() to free it.
156 mc_search_new_len (const gchar
* original
, gsize original_len
, const gchar
* original_charset
)
158 mc_search_t
*lc_mc_search
;
160 if (original
== NULL
|| original_len
== 0)
163 lc_mc_search
= g_new0 (mc_search_t
, 1);
164 lc_mc_search
->original
= g_strndup (original
, original_len
);
165 lc_mc_search
->original_len
= original_len
;
167 lc_mc_search
->original_charset
=
168 g_strdup (original_charset
!= NULL
169 && *original_charset
!= '\0' ? original_charset
: cp_display
);
171 (void) original_charset
;
177 /* --------------------------------------------------------------------------------------------- */
180 mc_search_free (mc_search_t
* lc_mc_search
)
182 if (lc_mc_search
== NULL
)
185 g_free (lc_mc_search
->original
);
187 g_free (lc_mc_search
->original_charset
);
189 g_free (lc_mc_search
->error_str
);
191 if (lc_mc_search
->conditions
!= NULL
)
192 mc_search__conditions_free (lc_mc_search
->conditions
);
194 #ifdef SEARCH_TYPE_GLIB
195 if (lc_mc_search
->regex_match_info
!= NULL
)
196 g_match_info_free (lc_mc_search
->regex_match_info
);
197 #else /* SEARCH_TYPE_GLIB */
198 g_free (lc_mc_search
->regex_match_info
);
199 #endif /* SEARCH_TYPE_GLIB */
201 if (lc_mc_search
->regex_buffer
!= NULL
)
202 g_string_free (lc_mc_search
->regex_buffer
, TRUE
);
204 g_free (lc_mc_search
);
207 /* --------------------------------------------------------------------------------------------- */
210 mc_search_prepare (mc_search_t
* lc_mc_search
)
214 ret
= g_ptr_array_new ();
216 if (lc_mc_search
->is_all_charsets
)
220 for (loop1
= 0; loop1
< codepages
->len
; loop1
++)
223 gsize recoded_str_len
;
226 id
= ((codepage_desc
*) g_ptr_array_index (codepages
, loop1
))->id
;
227 if (g_ascii_strcasecmp (id
, lc_mc_search
->original_charset
) == 0)
229 g_ptr_array_add (ret
,
230 mc_search__cond_struct_new (lc_mc_search
, lc_mc_search
->original
,
231 lc_mc_search
->original_len
,
232 lc_mc_search
->original_charset
));
237 mc_search__recode_str (lc_mc_search
->original
, lc_mc_search
->original_len
,
238 lc_mc_search
->original_charset
, id
, &recoded_str_len
);
240 g_ptr_array_add (ret
,
241 mc_search__cond_struct_new (lc_mc_search
, buffer
,
242 recoded_str_len
, id
));
248 g_ptr_array_add (ret
,
249 mc_search__cond_struct_new (lc_mc_search
, lc_mc_search
->original
,
250 lc_mc_search
->original_len
,
251 lc_mc_search
->original_charset
));
254 g_ptr_array_add (ret
,
255 mc_search__cond_struct_new (lc_mc_search
, lc_mc_search
->original
,
256 lc_mc_search
->original_len
,
257 str_detect_termencoding ()));
259 lc_mc_search
->conditions
= ret
;
261 return (lc_mc_search
->error
== MC_SEARCH_E_OK
);
264 /* --------------------------------------------------------------------------------------------- */
267 * Carries out the search.
269 * Returns TRUE if found.
271 * Returns FALSE if not found. In this case, lc_mc_search->error reveals
274 * - MC_SEARCH_E_NOTFOUND: the pattern isn't in the subject string.
275 * - MC_SEARCH_E_ABORT: the user aborted the search.
276 * - For any other reason (but not for the above two!): the description
277 * is in lc_mc_search->error_str.
280 mc_search_run (mc_search_t
* lc_mc_search
, const void *user_data
,
281 gsize start_search
, gsize end_search
, gsize
* found_len
)
283 gboolean ret
= FALSE
;
285 if (lc_mc_search
== NULL
|| user_data
== NULL
)
287 if (!mc_search_is_type_avail (lc_mc_search
->search_type
))
289 mc_search_set_error (lc_mc_search
, MC_SEARCH_E_INPUT
, "%s", _(STR_E_UNKNOWN_TYPE
));
292 #ifdef SEARCH_TYPE_GLIB
293 if (lc_mc_search
->regex_match_info
!= NULL
)
295 g_match_info_free (lc_mc_search
->regex_match_info
);
296 lc_mc_search
->regex_match_info
= NULL
;
298 #endif /* SEARCH_TYPE_GLIB */
300 mc_search_set_error (lc_mc_search
, MC_SEARCH_E_OK
, NULL
);
302 if ((lc_mc_search
->conditions
== NULL
) && !mc_search_prepare (lc_mc_search
))
305 switch (lc_mc_search
->search_type
)
307 case MC_SEARCH_T_NORMAL
:
308 ret
= mc_search__run_normal (lc_mc_search
, user_data
, start_search
, end_search
, found_len
);
310 case MC_SEARCH_T_REGEX
:
311 ret
= mc_search__run_regex (lc_mc_search
, user_data
, start_search
, end_search
, found_len
);
313 case MC_SEARCH_T_GLOB
:
314 ret
= mc_search__run_glob (lc_mc_search
, user_data
, start_search
, end_search
, found_len
);
316 case MC_SEARCH_T_HEX
:
317 ret
= mc_search__run_hex (lc_mc_search
, user_data
, start_search
, end_search
, found_len
);
325 /* --------------------------------------------------------------------------------------------- */
328 mc_search_is_type_avail (mc_search_type_t search_type
)
332 case MC_SEARCH_T_GLOB
:
333 case MC_SEARCH_T_NORMAL
:
334 case MC_SEARCH_T_REGEX
:
335 case MC_SEARCH_T_HEX
:
343 /* --------------------------------------------------------------------------------------------- */
345 const mc_search_type_str_t
*
346 mc_search_types_list_get (size_t * num
)
348 /* don't count last NULL item */
350 *num
= G_N_ELEMENTS (mc_search__list_types
) - 1;
352 return mc_search__list_types
;
355 /* --------------------------------------------------------------------------------------------- */
358 mc_search_prepare_replace_str (mc_search_t
* lc_mc_search
, GString
* replace_str
)
362 if (replace_str
== NULL
|| replace_str
->len
== 0)
363 return g_string_new ("");
365 if (lc_mc_search
== NULL
)
366 return g_string_new_len (replace_str
->str
, replace_str
->len
);
368 switch (lc_mc_search
->search_type
)
370 case MC_SEARCH_T_REGEX
:
371 ret
= mc_search_regex_prepare_replace_str (lc_mc_search
, replace_str
);
373 case MC_SEARCH_T_GLOB
:
374 ret
= mc_search_glob_prepare_replace_str (lc_mc_search
, replace_str
);
376 case MC_SEARCH_T_NORMAL
:
377 ret
= mc_search_normal_prepare_replace_str (lc_mc_search
, replace_str
);
379 case MC_SEARCH_T_HEX
:
380 ret
= mc_search_hex_prepare_replace_str (lc_mc_search
, replace_str
);
383 ret
= g_string_new_len (replace_str
->str
, replace_str
->len
);
389 /* --------------------------------------------------------------------------------------------- */
392 mc_search_prepare_replace_str2 (mc_search_t
* lc_mc_search
, const char *replace_str
)
395 GString
*replace_str2
;
397 replace_str2
= g_string_new (replace_str
);
398 ret
= mc_search_prepare_replace_str (lc_mc_search
, replace_str2
);
399 g_string_free (replace_str2
, TRUE
);
400 return (ret
!= NULL
) ? g_string_free (ret
, FALSE
) : NULL
;
403 /* --------------------------------------------------------------------------------------------- */
406 mc_search_is_fixed_search_str (mc_search_t
* lc_mc_search
)
408 if (lc_mc_search
== NULL
)
410 switch (lc_mc_search
->search_type
)
412 case MC_SEARCH_T_REGEX
:
413 case MC_SEARCH_T_GLOB
:
420 /* --------------------------------------------------------------------------------------------- */
421 /* Search specified pattern in specified string.
423 * @param pattern string to search
424 * @param pattern_charset charset of #pattern. If NULL then cp_display will be used
425 * @param str string where search #pattern
426 * @param search type (normal, regex, hex or glob)
428 * @return TRUE if found is successful, FALSE otherwise.
432 mc_search (const gchar
* pattern
, const gchar
* pattern_charset
, const gchar
* str
,
433 mc_search_type_t type
)
441 search
= mc_search_new (pattern
, pattern_charset
);
445 search
->search_type
= type
;
446 search
->is_case_sensitive
= TRUE
;
448 if (type
== MC_SEARCH_T_GLOB
)
449 search
->is_entire_line
= TRUE
;
451 ret
= mc_search_run (search
, str
, 0, strlen (str
), NULL
);
452 mc_search_free (search
);
456 /* --------------------------------------------------------------------------------------------- */
459 mc_search_getstart_result_by_num (mc_search_t
* lc_mc_search
, int lc_index
)
461 if (lc_mc_search
== NULL
)
463 if (lc_mc_search
->search_type
== MC_SEARCH_T_NORMAL
)
465 #ifdef SEARCH_TYPE_GLIB
470 g_match_info_fetch_pos (lc_mc_search
->regex_match_info
, lc_index
, &start_pos
, &end_pos
);
471 return (int) start_pos
;
473 #else /* SEARCH_TYPE_GLIB */
474 return lc_mc_search
->iovector
[lc_index
* 2];
475 #endif /* SEARCH_TYPE_GLIB */
478 /* --------------------------------------------------------------------------------------------- */
481 mc_search_getend_result_by_num (mc_search_t
* lc_mc_search
, int lc_index
)
483 if (lc_mc_search
== NULL
)
485 if (lc_mc_search
->search_type
== MC_SEARCH_T_NORMAL
)
487 #ifdef SEARCH_TYPE_GLIB
492 g_match_info_fetch_pos (lc_mc_search
->regex_match_info
, lc_index
, &start_pos
, &end_pos
);
493 return (int) end_pos
;
495 #else /* SEARCH_TYPE_GLIB */
496 return lc_mc_search
->iovector
[lc_index
* 2 + 1];
497 #endif /* SEARCH_TYPE_GLIB */
500 /* --------------------------------------------------------------------------------------------- */
502 * Replace an old error code and message of an mc_search_t object.
504 * @param mc_search mc_search_t object
505 * @param code error code, one of mc_search_error_t values
506 * @param format format of error message. If NULL, the old error string is free'd and become NULL
510 mc_search_set_error (mc_search_t
* lc_mc_search
, mc_search_error_t code
, const gchar
* format
, ...)
512 lc_mc_search
->error
= code
;
514 MC_PTR_FREE (lc_mc_search
->error_str
);
520 va_start (args
, format
);
521 lc_mc_search
->error_str
= g_strdup_vprintf (format
, args
);
526 /* --------------------------------------------------------------------------------------------- */