Ticket #2327: Can't put ? into a new name.
[midnight-commander.git] / lib / search / glob.c
blobad0c42506cb938f85f1f1d2a707129b90a05d183
1 /*
2 Search text engine.
3 Glob-style pattern matching
5 Copyright (C) 2009 The Free Software Foundation, Inc.
7 Written by:
8 Slava Zanko <slavazanko@gmail.com>, 2009.
10 This file is part of the Midnight Commander.
12 The Midnight Commander is free software; you can redistribute it
13 and/or modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation; either version 2 of the
15 License, or (at your option) any later version.
17 The Midnight Commander is distributed in the hope that it will be
18 useful, but WITHOUT ANY WARRANTY; without even the implied warranty
19 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
25 MA 02110-1301, USA.
28 #include <config.h>
31 #include "lib/global.h"
32 #include "lib/strutil.h"
33 #include "lib/search.h"
34 #include "lib/strescape.h"
36 #include "src/charsets.h"
38 #include "internal.h"
40 /*** global variables ****************************************************************************/
42 /*** file scope macro definitions ****************************************************************/
44 /*** file scope type declarations ****************************************************************/
46 /*** file scope variables ************************************************************************/
48 /*** file scope functions ************************************************************************/
50 static GString *
51 mc_search__glob_translate_to_regex (gchar * str, gsize * len)
53 GString *buff = g_string_new ("");
54 gsize orig_len = *len;
55 gsize loop = 0;
56 gboolean inside_group = FALSE;
57 while (loop < orig_len)
59 switch (str[loop])
61 case '*':
62 if (!strutils_is_char_escaped (str, &(str[loop])))
64 g_string_append (buff, (inside_group) ? ".*" : "(.*)");
65 loop++;
66 continue;
68 break;
69 case '?':
70 if (!strutils_is_char_escaped (str, &(str[loop])))
72 g_string_append (buff, (inside_group) ? "." : "(.)");
73 loop++;
74 continue;
76 break;
77 case ',':
78 if (!strutils_is_char_escaped (str, &(str[loop])))
80 g_string_append (buff, "|");
81 loop++;
82 continue;
84 break;
85 case '{':
86 if (!strutils_is_char_escaped (str, &(str[loop])))
88 g_string_append (buff, "(");
89 inside_group = TRUE;
90 loop++;
91 continue;
93 break;
94 case '}':
95 if (!strutils_is_char_escaped (str, &(str[loop])))
97 g_string_append (buff, ")");
98 inside_group = FALSE;
99 loop++;
100 continue;
102 break;
103 case '+':
104 case '.':
105 case '$':
106 case '(':
107 case ')':
108 case '^':
109 g_string_append_c (buff, '\\');
110 g_string_append_c (buff, str[loop]);
111 loop++;
112 continue;
114 g_string_append_c (buff, str[loop]);
115 loop++;
117 *len = buff->len;
118 return buff;
121 /* --------------------------------------------------------------------------------------------- */
123 static GString *
124 mc_search__translate_replace_glob_to_regex (gchar * str)
126 GString *buff = g_string_sized_new (32);
127 int cnt = '0';
128 gboolean escaped_mode = FALSE;
129 while (*str)
131 char c = *str++;
132 switch (c)
134 case '\\':
135 if (!escaped_mode)
137 escaped_mode = TRUE;
139 g_string_append_c (buff, c);
140 continue;
141 case '*':
142 case '?':
143 if (!escaped_mode)
145 g_string_append_c (buff, '\\');
146 c = ++cnt;
148 break;
149 case '&':
150 g_string_append_c (buff, '\\');
151 break;
153 g_string_append_c (buff, c);
154 escaped_mode = FALSE;
156 return buff;
159 /*** public functions ****************************************************************************/
161 void
162 mc_search__cond_struct_new_init_glob (const char *charset, mc_search_t * lc_mc_search,
163 mc_search_cond_t * mc_search_cond)
165 GString *tmp =
166 mc_search__glob_translate_to_regex (mc_search_cond->str->str, &mc_search_cond->len);
168 g_string_free (mc_search_cond->str, TRUE);
170 if (lc_mc_search->is_entire_line)
172 g_string_prepend_c (tmp, '^');
173 g_string_append_c (tmp, '$');
175 mc_search_cond->str = tmp;
177 mc_search__cond_struct_new_init_regex (charset, lc_mc_search, mc_search_cond);
181 /* --------------------------------------------------------------------------------------------- */
183 gboolean
184 mc_search__run_glob (mc_search_t * lc_mc_search, const void *user_data,
185 gsize start_search, gsize end_search, gsize * found_len)
187 return mc_search__run_regex (lc_mc_search, user_data, start_search, end_search, found_len);
190 /* --------------------------------------------------------------------------------------------- */
192 GString *
193 mc_search_glob_prepare_replace_str (mc_search_t * lc_mc_search, GString * replace_str)
195 GString *repl = mc_search__translate_replace_glob_to_regex (replace_str->str);
196 GString *res = mc_search_regex_prepare_replace_str (lc_mc_search, repl);
197 g_string_free (repl, TRUE);
198 return res;
201 /* --------------------------------------------------------------------------------------------- */