Merge lib/utilunix.h into lib/util.h.
[midnight-commander.git] / lib / search / glob.c
blobc2c711672be63e6faba4a0fcef2d077d8e9eb956
1 /*
2 Search text engine.
3 Glob-style pattern matching
5 Copyright (C) 2009-2024
6 Free Software Foundation, Inc.
8 Written by:
9 Slava Zanko <slavazanko@gmail.com>, 2009.
11 This file is part of the Midnight Commander.
13 The Midnight Commander is free software: you can redistribute it
14 and/or modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation, either version 3 of the License,
16 or (at your option) any later version.
18 The Midnight Commander is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 #include <config.h>
29 #include "lib/global.h"
30 #include "lib/strutil.h"
31 #include "lib/search.h"
33 #include "internal.h"
35 /*** global variables ****************************************************************************/
37 /*** file scope macro definitions ****************************************************************/
39 /*** file scope type declarations ****************************************************************/
41 /*** forward declarations (file scope functions) *************************************************/
43 /*** file scope variables ************************************************************************/
45 /* --------------------------------------------------------------------------------------------- */
46 /*** file scope functions ************************************************************************/
47 /* --------------------------------------------------------------------------------------------- */
49 static GString *
50 mc_search__glob_translate_to_regex (const GString * astr)
52 const char *str = astr->str;
53 GString *buff;
54 gsize loop;
55 gboolean inside_group = FALSE;
57 buff = g_string_sized_new (32);
59 for (loop = 0; loop < astr->len; loop++)
61 switch (str[loop])
63 case '*':
64 if (!str_is_char_escaped (str, &(str[loop])))
66 g_string_append (buff, inside_group ? ".*" : "(.*)");
67 continue;
69 break;
70 case '?':
71 if (!str_is_char_escaped (str, &(str[loop])))
73 g_string_append (buff, inside_group ? "." : "(.)");
74 continue;
76 break;
77 case ',':
78 if (!str_is_char_escaped (str, &(str[loop])))
80 g_string_append_c (buff, inside_group ? '|' : ',');
81 continue;
83 break;
84 case '{':
85 if (!str_is_char_escaped (str, &(str[loop])))
87 g_string_append_c (buff, '(');
88 inside_group = TRUE;
89 continue;
91 break;
92 case '}':
93 if (!str_is_char_escaped (str, &(str[loop])))
95 g_string_append_c (buff, ')');
96 inside_group = FALSE;
97 continue;
99 break;
100 case '+':
101 case '.':
102 case '$':
103 case '(':
104 case ')':
105 case '^':
106 g_string_append_c (buff, '\\');
107 break;
108 default:
109 break;
111 g_string_append_c (buff, str[loop]);
113 return buff;
116 /* --------------------------------------------------------------------------------------------- */
118 static GString *
119 mc_search__translate_replace_glob_to_regex (const char *str)
121 GString *buff;
122 char cnt = '0';
123 gboolean escaped_mode = FALSE;
125 buff = g_string_sized_new (32);
127 while (*str != '\0')
129 char c = *str++;
131 switch (c)
133 case '\\':
134 if (!escaped_mode)
136 escaped_mode = TRUE;
137 g_string_append_c (buff, '\\');
138 continue;
140 break;
141 case '*':
142 case '?':
143 if (!escaped_mode)
145 g_string_append_c (buff, '\\');
146 c = ++cnt;
148 break;
149 case '&':
150 if (!escaped_mode)
151 g_string_append_c (buff, '\\');
152 break;
153 default:
154 break;
156 g_string_append_c (buff, c);
157 escaped_mode = FALSE;
159 return buff;
162 /*** public functions ****************************************************************************/
164 void
165 mc_search__cond_struct_new_init_glob (const char *charset, mc_search_t * lc_mc_search,
166 mc_search_cond_t * mc_search_cond)
168 GString *tmp;
170 tmp = mc_search__glob_translate_to_regex (mc_search_cond->str);
171 g_string_free (mc_search_cond->str, TRUE);
173 if (lc_mc_search->is_entire_line)
175 g_string_prepend_c (tmp, '^');
176 g_string_append_c (tmp, '$');
178 mc_search_cond->str = tmp;
180 mc_search__cond_struct_new_init_regex (charset, lc_mc_search, mc_search_cond);
183 /* --------------------------------------------------------------------------------------------- */
185 gboolean
186 mc_search__run_glob (mc_search_t * lc_mc_search, const void *user_data,
187 gsize start_search, gsize end_search, gsize * found_len)
189 return mc_search__run_regex (lc_mc_search, user_data, start_search, end_search, found_len);
192 /* --------------------------------------------------------------------------------------------- */
194 GString *
195 mc_search_glob_prepare_replace_str (mc_search_t * lc_mc_search, GString * replace_str)
197 GString *repl, *res;
199 repl = mc_search__translate_replace_glob_to_regex (replace_str->str);
200 res = mc_search_regex_prepare_replace_str (lc_mc_search, repl);
201 g_string_free (repl, TRUE);
203 return res;
206 /* --------------------------------------------------------------------------------------------- */