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/>.
31 #include <sys/types.h>
33 #include "lib/global.h"
34 #include "lib/strutil.h"
35 #include "lib/search.h"
38 #include "lib/charsets.h"
43 /*** global variables ****************************************************************************/
45 /*** file scope macro definitions ****************************************************************/
47 /*** file scope type declarations ****************************************************************/
49 /*** file scope variables ************************************************************************/
51 static const mc_search_type_str_t mc_search__list_types
[] = {
52 {N_("No&rmal"), MC_SEARCH_T_NORMAL
},
53 {N_("Re&gular expression"), MC_SEARCH_T_REGEX
},
54 {N_("He&xadecimal"), MC_SEARCH_T_HEX
},
55 {N_("Wil&dcard search"), MC_SEARCH_T_GLOB
},
56 {NULL
, MC_SEARCH_T_INVALID
}
59 /*** file scope functions ************************************************************************/
61 static mc_search_cond_t
*
62 mc_search__cond_struct_new (mc_search_t
* lc_mc_search
, const char *str
,
63 gsize str_len
, const char *charset
)
65 mc_search_cond_t
*mc_search_cond
;
67 mc_search_cond
= g_malloc0 (sizeof (mc_search_cond_t
));
68 mc_search_cond
->str
= g_string_new_len (str
, str_len
);
69 mc_search_cond
->charset
= g_strdup (charset
);
71 switch (lc_mc_search
->search_type
)
73 case MC_SEARCH_T_GLOB
:
74 mc_search__cond_struct_new_init_glob (charset
, lc_mc_search
, mc_search_cond
);
76 case MC_SEARCH_T_NORMAL
:
77 mc_search__cond_struct_new_init_normal (charset
, lc_mc_search
, mc_search_cond
);
79 case MC_SEARCH_T_REGEX
:
80 mc_search__cond_struct_new_init_regex (charset
, lc_mc_search
, mc_search_cond
);
83 mc_search__cond_struct_new_init_hex (charset
, lc_mc_search
, mc_search_cond
);
88 return mc_search_cond
;
91 /* --------------------------------------------------------------------------------------------- */
94 mc_search__cond_struct_free (mc_search_cond_t
* mc_search_cond
)
96 if (mc_search_cond
->upper
)
97 g_string_free (mc_search_cond
->upper
, TRUE
);
99 if (mc_search_cond
->lower
)
100 g_string_free (mc_search_cond
->lower
, TRUE
);
102 g_string_free (mc_search_cond
->str
, TRUE
);
103 g_free (mc_search_cond
->charset
);
105 #ifdef SEARCH_TYPE_GLIB
106 if (mc_search_cond
->regex_handle
)
107 g_regex_unref (mc_search_cond
->regex_handle
);
108 #else /* SEARCH_TYPE_GLIB */
109 g_free (mc_search_cond
->regex_handle
);
110 #endif /* SEARCH_TYPE_GLIB */
112 g_free (mc_search_cond
);
115 /* --------------------------------------------------------------------------------------------- */
118 mc_search__conditions_free (GPtrArray
* array
)
120 g_ptr_array_foreach (array
, (GFunc
) mc_search__cond_struct_free
, NULL
);
121 g_ptr_array_free (array
, TRUE
);
124 /* --------------------------------------------------------------------------------------------- */
125 /*** public functions ****************************************************************************/
126 /* --------------------------------------------------------------------------------------------- */
127 /* Init search descriptor.
129 * @param original pattern to search
130 * @param original_charset charset of #original. If NULL then cp_display will be used
132 * @return new mc_search_t object. Use #mc_search_free() to free it.
136 mc_search_new (const gchar
* original
, const gchar
* original_charset
)
138 if (original
== NULL
)
141 return mc_search_new_len (original
, strlen (original
), original_charset
);
144 /* --------------------------------------------------------------------------------------------- */
145 /* Init search descriptor.
147 * @param original pattern to search
148 * @param original_len length of #original or -1 if #original is NULL-terminated
149 * @param original_charset charset of #original. If NULL then cp_display will be used
151 * @return new mc_search_t object. Use #mc_search_free() to free it.
155 mc_search_new_len (const gchar
* original
, gsize original_len
, const gchar
* original_charset
)
157 mc_search_t
*lc_mc_search
;
159 if (original
== NULL
|| original_len
== 0)
162 lc_mc_search
= g_new0 (mc_search_t
, 1);
163 lc_mc_search
->original
= g_strndup (original
, original_len
);
164 lc_mc_search
->original_len
= original_len
;
166 lc_mc_search
->original_charset
=
167 g_strdup (original_charset
!= NULL
168 && *original_charset
!= '\0' ? original_charset
: cp_display
);
170 (void) original_charset
;
176 /* --------------------------------------------------------------------------------------------- */
179 mc_search_free (mc_search_t
* lc_mc_search
)
181 if (lc_mc_search
== NULL
)
184 g_free (lc_mc_search
->original
);
186 g_free (lc_mc_search
->original_charset
);
188 g_free (lc_mc_search
->error_str
);
190 if (lc_mc_search
->conditions
!= NULL
)
191 mc_search__conditions_free (lc_mc_search
->conditions
);
193 #ifdef SEARCH_TYPE_GLIB
194 if (lc_mc_search
->regex_match_info
!= NULL
)
195 g_match_info_free (lc_mc_search
->regex_match_info
);
196 #else /* SEARCH_TYPE_GLIB */
197 g_free (lc_mc_search
->regex_match_info
);
198 #endif /* SEARCH_TYPE_GLIB */
200 if (lc_mc_search
->regex_buffer
!= NULL
)
201 g_string_free (lc_mc_search
->regex_buffer
, TRUE
);
203 g_free (lc_mc_search
);
206 /* --------------------------------------------------------------------------------------------- */
209 mc_search_prepare (mc_search_t
* lc_mc_search
)
213 ret
= g_ptr_array_new ();
215 if (lc_mc_search
->is_all_charsets
)
219 for (loop1
= 0; loop1
< codepages
->len
; loop1
++)
222 gsize recoded_str_len
;
225 id
= ((codepage_desc
*) g_ptr_array_index (codepages
, loop1
))->id
;
226 if (g_ascii_strcasecmp (id
, lc_mc_search
->original_charset
) == 0)
228 g_ptr_array_add (ret
,
229 mc_search__cond_struct_new (lc_mc_search
, lc_mc_search
->original
,
230 lc_mc_search
->original_len
,
231 lc_mc_search
->original_charset
));
236 mc_search__recode_str (lc_mc_search
->original
, lc_mc_search
->original_len
,
237 lc_mc_search
->original_charset
, id
, &recoded_str_len
);
239 g_ptr_array_add (ret
,
240 mc_search__cond_struct_new (lc_mc_search
, buffer
,
241 recoded_str_len
, id
));
247 g_ptr_array_add (ret
,
248 mc_search__cond_struct_new (lc_mc_search
, lc_mc_search
->original
,
249 lc_mc_search
->original_len
,
250 lc_mc_search
->original_charset
));
253 g_ptr_array_add (ret
,
254 mc_search__cond_struct_new (lc_mc_search
, lc_mc_search
->original
,
255 lc_mc_search
->original_len
,
256 str_detect_termencoding ()));
258 lc_mc_search
->conditions
= ret
;
260 return (lc_mc_search
->error
== MC_SEARCH_E_OK
);
263 /* --------------------------------------------------------------------------------------------- */
266 mc_search_run (mc_search_t
* lc_mc_search
, const void *user_data
,
267 gsize start_search
, gsize end_search
, gsize
* found_len
)
269 gboolean ret
= FALSE
;
271 if (lc_mc_search
== NULL
|| user_data
== NULL
)
273 if (!mc_search_is_type_avail (lc_mc_search
->search_type
))
275 lc_mc_search
->error
= MC_SEARCH_E_INPUT
;
276 lc_mc_search
->error_str
= g_strdup (_(STR_E_UNKNOWN_TYPE
));
279 #ifdef SEARCH_TYPE_GLIB
280 if (lc_mc_search
->regex_match_info
!= NULL
)
282 g_match_info_free (lc_mc_search
->regex_match_info
);
283 lc_mc_search
->regex_match_info
= NULL
;
285 #endif /* SEARCH_TYPE_GLIB */
287 lc_mc_search
->error
= MC_SEARCH_E_OK
;
288 MC_PTR_FREE (lc_mc_search
->error_str
);
290 if ((lc_mc_search
->conditions
== NULL
) && !mc_search_prepare (lc_mc_search
))
293 switch (lc_mc_search
->search_type
)
295 case MC_SEARCH_T_NORMAL
:
296 ret
= mc_search__run_normal (lc_mc_search
, user_data
, start_search
, end_search
, found_len
);
298 case MC_SEARCH_T_REGEX
:
299 ret
= mc_search__run_regex (lc_mc_search
, user_data
, start_search
, end_search
, found_len
);
301 case MC_SEARCH_T_GLOB
:
302 ret
= mc_search__run_glob (lc_mc_search
, user_data
, start_search
, end_search
, found_len
);
304 case MC_SEARCH_T_HEX
:
305 ret
= mc_search__run_hex (lc_mc_search
, user_data
, start_search
, end_search
, found_len
);
313 /* --------------------------------------------------------------------------------------------- */
316 mc_search_is_type_avail (mc_search_type_t search_type
)
320 case MC_SEARCH_T_GLOB
:
321 case MC_SEARCH_T_NORMAL
:
322 case MC_SEARCH_T_REGEX
:
323 case MC_SEARCH_T_HEX
:
331 /* --------------------------------------------------------------------------------------------- */
333 const mc_search_type_str_t
*
334 mc_search_types_list_get (size_t * num
)
336 /* don't count last NULL item */
338 *num
= G_N_ELEMENTS (mc_search__list_types
) - 1;
340 return mc_search__list_types
;
343 /* --------------------------------------------------------------------------------------------- */
346 mc_search_prepare_replace_str (mc_search_t
* lc_mc_search
, GString
* replace_str
)
350 if (lc_mc_search
== NULL
)
351 return g_string_new_len (replace_str
->str
, replace_str
->len
);
353 if (replace_str
== NULL
|| replace_str
->str
== NULL
|| replace_str
->len
== 0)
354 return g_string_new ("");
356 switch (lc_mc_search
->search_type
)
358 case MC_SEARCH_T_REGEX
:
359 ret
= mc_search_regex_prepare_replace_str (lc_mc_search
, replace_str
);
361 case MC_SEARCH_T_GLOB
:
362 ret
= mc_search_glob_prepare_replace_str (lc_mc_search
, replace_str
);
364 case MC_SEARCH_T_NORMAL
:
365 ret
= mc_search_normal_prepare_replace_str (lc_mc_search
, replace_str
);
367 case MC_SEARCH_T_HEX
:
368 ret
= mc_search_hex_prepare_replace_str (lc_mc_search
, replace_str
);
371 ret
= g_string_new_len (replace_str
->str
, replace_str
->len
);
377 /* --------------------------------------------------------------------------------------------- */
380 mc_search_prepare_replace_str2 (mc_search_t
* lc_mc_search
, const char *replace_str
)
383 GString
*replace_str2
;
385 replace_str2
= g_string_new (replace_str
);
386 ret
= mc_search_prepare_replace_str (lc_mc_search
, replace_str2
);
387 g_string_free (replace_str2
, TRUE
);
388 return (ret
!= NULL
) ? g_string_free (ret
, FALSE
) : NULL
;
391 /* --------------------------------------------------------------------------------------------- */
394 mc_search_is_fixed_search_str (mc_search_t
* lc_mc_search
)
396 if (lc_mc_search
== NULL
)
398 switch (lc_mc_search
->search_type
)
400 case MC_SEARCH_T_REGEX
:
401 case MC_SEARCH_T_GLOB
:
408 /* --------------------------------------------------------------------------------------------- */
409 /* Search specified pattern in specified string.
411 * @param pattern string to search
412 * @param pattern_charset charset of #pattern. If NULL then cp_display will be used
413 * @param str string where search #pattern
414 * @param search type (normal, regex, hex or glob)
416 * @return TRUE if found is successful, FALSE otherwise.
420 mc_search (const gchar
* pattern
, const gchar
* pattern_charset
, const gchar
* str
,
421 mc_search_type_t type
)
429 search
= mc_search_new (pattern
, pattern_charset
);
433 search
->search_type
= type
;
434 search
->is_case_sensitive
= TRUE
;
436 if (type
== MC_SEARCH_T_GLOB
)
437 search
->is_entire_line
= TRUE
;
439 ret
= mc_search_run (search
, str
, 0, strlen (str
), NULL
);
440 mc_search_free (search
);
444 /* --------------------------------------------------------------------------------------------- */
447 mc_search_getstart_result_by_num (mc_search_t
* lc_mc_search
, int lc_index
)
449 if (lc_mc_search
== NULL
)
451 if (lc_mc_search
->search_type
== MC_SEARCH_T_NORMAL
)
453 #ifdef SEARCH_TYPE_GLIB
458 g_match_info_fetch_pos (lc_mc_search
->regex_match_info
, lc_index
, &start_pos
, &end_pos
);
459 return (int) start_pos
;
461 #else /* SEARCH_TYPE_GLIB */
462 return lc_mc_search
->iovector
[lc_index
* 2];
463 #endif /* SEARCH_TYPE_GLIB */
466 /* --------------------------------------------------------------------------------------------- */
469 mc_search_getend_result_by_num (mc_search_t
* lc_mc_search
, int lc_index
)
471 if (lc_mc_search
== NULL
)
473 if (lc_mc_search
->search_type
== MC_SEARCH_T_NORMAL
)
475 #ifdef SEARCH_TYPE_GLIB
480 g_match_info_fetch_pos (lc_mc_search
->regex_match_info
, lc_index
, &start_pos
, &end_pos
);
481 return (int) end_pos
;
483 #else /* SEARCH_TYPE_GLIB */
484 return lc_mc_search
->iovector
[lc_index
* 2 + 1];
485 #endif /* SEARCH_TYPE_GLIB */
488 /* --------------------------------------------------------------------------------------------- */