2009-04-25 12:09:47 +04:00
|
|
|
/*
|
|
|
|
Search text engine.
|
|
|
|
Regex search
|
|
|
|
|
2024-01-01 09:46:17 +03:00
|
|
|
Copyright (C) 2009-2024
|
2014-02-12 10:33:10 +04:00
|
|
|
Free Software Foundation, Inc.
|
2009-04-25 12:09:47 +04:00
|
|
|
|
|
|
|
Written by:
|
2013-10-15 10:34:04 +04:00
|
|
|
Slava Zanko <slavazanko@gmail.com>, 2009, 2010, 2011, 2013
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
Vitaliy Filippov <vitalif@yourcmc.ru>, 2011
|
2015-01-07 09:52:24 +03:00
|
|
|
Andrew Borodin <aborodin@vmail.ru>, 2013-2015
|
2009-04-25 12:09:47 +04:00
|
|
|
|
|
|
|
This file is part of the Midnight Commander.
|
|
|
|
|
2011-10-15 14:56:47 +04:00
|
|
|
The Midnight Commander is free software: you can redistribute it
|
2009-04-25 12:09:47 +04:00
|
|
|
and/or modify it under the terms of the GNU General Public License as
|
2011-10-15 14:56:47 +04:00
|
|
|
published by the Free Software Foundation, either version 3 of the License,
|
|
|
|
or (at your option) any later version.
|
2009-04-25 12:09:47 +04:00
|
|
|
|
2011-10-15 14:56:47 +04:00
|
|
|
The Midnight Commander is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
2009-04-25 12:09:47 +04:00
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
2011-10-15 14:56:47 +04:00
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2009-04-25 12:09:47 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
2009-06-19 14:36:36 +04:00
|
|
|
#include <stdlib.h>
|
2009-04-25 12:09:47 +04:00
|
|
|
|
2010-01-20 18:11:52 +03:00
|
|
|
#include "lib/global.h"
|
2010-01-21 15:17:26 +03:00
|
|
|
#include "lib/strutil.h"
|
2010-01-21 16:06:15 +03:00
|
|
|
#include "lib/search.h"
|
2016-05-02 16:04:37 +03:00
|
|
|
#include "lib/util.h" /* MC_PTR_FREE */
|
2010-01-21 15:17:26 +03:00
|
|
|
|
|
|
|
#include "internal.h"
|
|
|
|
|
2009-04-25 12:09:47 +04:00
|
|
|
/*** global variables ****************************************************************************/
|
|
|
|
|
|
|
|
/*** file scope macro definitions ****************************************************************/
|
|
|
|
|
2011-06-01 11:26:22 +04:00
|
|
|
#define REPLACE_PREPARE_T_NOTHING_SPECIAL -1
|
|
|
|
#define REPLACE_PREPARE_T_REPLACE_FLAG -2
|
|
|
|
#define REPLACE_PREPARE_T_ESCAPE_SEQ -3
|
|
|
|
|
2009-04-25 12:09:47 +04:00
|
|
|
/*** file scope type declarations ****************************************************************/
|
|
|
|
|
2010-03-30 12:10:25 +04:00
|
|
|
typedef enum
|
|
|
|
{
|
2009-06-08 14:54:35 +04:00
|
|
|
REPLACE_T_NO_TRANSFORM = 0,
|
|
|
|
REPLACE_T_UPP_TRANSFORM_CHAR = 1,
|
|
|
|
REPLACE_T_LOW_TRANSFORM_CHAR = 2,
|
|
|
|
REPLACE_T_UPP_TRANSFORM = 4,
|
|
|
|
REPLACE_T_LOW_TRANSFORM = 8
|
|
|
|
} replace_transform_type_t;
|
|
|
|
|
Update template for .c files.
Add section for forward declarations of local functions. This section is
located before file scope variables because functions can be used in
strucutres (see find.c for example):
/*** forward declarations (file scope functions) *************************************************/
/* button callbacks */
static int start_stop (WButton * button, int action);
static int find_do_view_file (WButton * button, int action);
static int find_do_edit_file (WButton * button, int action);
/*** file scope variables ************************************************************************/
static struct
{
...
bcback_fn callback;
} fbuts[] =
{
...
{ B_STOP, NORMAL_BUTTON, N_("S&uspend"), 0, 0, NULL, start_stop },
...
{ B_VIEW, NORMAL_BUTTON, N_("&View - F3"), 0, 0, NULL, find_do_view_file },
{ B_VIEW, NORMAL_BUTTON, N_("&Edit - F4"), 0, 0, NULL, find_do_edit_file }
};
Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
2023-02-24 09:27:11 +03:00
|
|
|
/*** forward declarations (file scope functions) *************************************************/
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
|
2009-04-25 12:09:47 +04:00
|
|
|
/*** file scope variables ************************************************************************/
|
|
|
|
|
Update template for .c files.
Add section for forward declarations of local functions. This section is
located before file scope variables because functions can be used in
strucutres (see find.c for example):
/*** forward declarations (file scope functions) *************************************************/
/* button callbacks */
static int start_stop (WButton * button, int action);
static int find_do_view_file (WButton * button, int action);
static int find_do_edit_file (WButton * button, int action);
/*** file scope variables ************************************************************************/
static struct
{
...
bcback_fn callback;
} fbuts[] =
{
...
{ B_STOP, NORMAL_BUTTON, N_("S&uspend"), 0, 0, NULL, start_stop },
...
{ B_VIEW, NORMAL_BUTTON, N_("&View - F3"), 0, 0, NULL, find_do_view_file },
{ B_VIEW, NORMAL_BUTTON, N_("&Edit - F4"), 0, 0, NULL, find_do_edit_file }
};
Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
2023-02-24 09:27:11 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
2009-04-25 12:09:47 +04:00
|
|
|
/*** file scope functions ************************************************************************/
|
Update template for .c files.
Add section for forward declarations of local functions. This section is
located before file scope variables because functions can be used in
strucutres (see find.c for example):
/*** forward declarations (file scope functions) *************************************************/
/* button callbacks */
static int start_stop (WButton * button, int action);
static int find_do_view_file (WButton * button, int action);
static int find_do_edit_file (WButton * button, int action);
/*** file scope variables ************************************************************************/
static struct
{
...
bcback_fn callback;
} fbuts[] =
{
...
{ B_STOP, NORMAL_BUTTON, N_("S&uspend"), 0, 0, NULL, start_stop },
...
{ B_VIEW, NORMAL_BUTTON, N_("&View - F3"), 0, 0, NULL, find_do_view_file },
{ B_VIEW, NORMAL_BUTTON, N_("&Edit - F4"), 0, 0, NULL, find_do_edit_file }
};
Signed-off-by: Andrew Borodin <aborodin@vmail.ru>
2023-02-24 09:27:11 +03:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
2009-04-25 12:09:47 +04:00
|
|
|
|
|
|
|
static gboolean
|
2024-06-01 21:12:14 +03:00
|
|
|
mc_search__regex_str_append_if_special (GString *copy_to, const GString *regex_str, gsize *offset)
|
2009-04-25 12:09:47 +04:00
|
|
|
{
|
2009-07-15 22:53:13 +04:00
|
|
|
const char *special_chars[] = {
|
2009-04-25 12:09:47 +04:00
|
|
|
"\\s", "\\S",
|
|
|
|
"\\d", "\\D",
|
2009-08-22 15:06:01 +04:00
|
|
|
"\\b", "\\B",
|
2009-04-25 12:09:47 +04:00
|
|
|
"\\w", "\\W",
|
|
|
|
"\\t", "\\n",
|
|
|
|
"\\r", "\\f",
|
|
|
|
"\\a", "\\e",
|
|
|
|
"\\x", "\\X",
|
2009-04-25 17:51:37 +04:00
|
|
|
"\\c", "\\C",
|
2009-04-25 12:09:47 +04:00
|
|
|
"\\l", "\\L",
|
|
|
|
"\\u", "\\U",
|
|
|
|
"\\E", "\\Q",
|
|
|
|
NULL
|
|
|
|
};
|
2014-12-30 13:23:51 +03:00
|
|
|
|
|
|
|
char *tmp_regex_str;
|
|
|
|
const char **spec_chr;
|
2009-04-25 12:09:47 +04:00
|
|
|
|
|
|
|
tmp_regex_str = &(regex_str->str[*offset]);
|
|
|
|
|
2014-12-30 13:23:51 +03:00
|
|
|
for (spec_chr = special_chars; *spec_chr != NULL; spec_chr++)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2014-12-30 13:23:51 +03:00
|
|
|
gsize spec_chr_len;
|
|
|
|
|
2009-04-25 12:09:47 +04:00
|
|
|
spec_chr_len = strlen (*spec_chr);
|
2014-12-30 13:23:51 +03:00
|
|
|
|
|
|
|
if (strncmp (tmp_regex_str, *spec_chr, spec_chr_len) == 0
|
2024-03-09 14:41:08 +03:00
|
|
|
&& !str_is_char_escaped (regex_str->str, tmp_regex_str))
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2014-12-30 13:23:51 +03:00
|
|
|
if (strncmp ("\\x", *spec_chr, spec_chr_len) == 0)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2014-12-30 13:23:51 +03:00
|
|
|
if (tmp_regex_str[spec_chr_len] != '{')
|
|
|
|
spec_chr_len += 2;
|
|
|
|
else
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2014-12-30 13:23:51 +03:00
|
|
|
while ((spec_chr_len < regex_str->len - *offset)
|
|
|
|
&& tmp_regex_str[spec_chr_len] != '}')
|
|
|
|
spec_chr_len++;
|
|
|
|
if (tmp_regex_str[spec_chr_len] == '}')
|
|
|
|
spec_chr_len++;
|
2009-05-05 23:50:19 +04:00
|
|
|
}
|
2009-04-25 12:09:47 +04:00
|
|
|
}
|
2014-12-30 13:23:51 +03:00
|
|
|
g_string_append_len (copy_to, tmp_regex_str, spec_chr_len);
|
|
|
|
*offset += spec_chr_len;
|
|
|
|
return TRUE;
|
2009-04-25 12:09:47 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-30 13:23:51 +03:00
|
|
|
return FALSE;
|
2009-04-25 12:09:47 +04:00
|
|
|
}
|
|
|
|
|
2009-04-25 17:51:37 +04:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
2013-08-09 11:15:21 +04:00
|
|
|
|
2009-04-25 17:51:37 +04:00
|
|
|
static void
|
2024-06-01 21:12:14 +03:00
|
|
|
mc_search__cond_struct_new_regex_hex_add (const char *charset, GString *str_to,
|
|
|
|
const GString *one_char)
|
2009-04-25 17:51:37 +04:00
|
|
|
{
|
|
|
|
GString *upp, *low;
|
|
|
|
gsize loop;
|
|
|
|
|
2022-09-24 09:26:03 +03:00
|
|
|
upp = mc_search__toupper_case_str (charset, one_char);
|
|
|
|
low = mc_search__tolower_case_str (charset, one_char);
|
2009-04-25 17:51:37 +04:00
|
|
|
|
2010-03-30 12:10:25 +04:00
|
|
|
for (loop = 0; loop < upp->len; loop++)
|
|
|
|
{
|
2013-08-09 11:15:21 +04:00
|
|
|
gchar tmp_str[10 + 1]; /* longest content is "[\\x%02X\\x%02X]" */
|
|
|
|
gint tmp_len;
|
2009-04-25 17:51:37 +04:00
|
|
|
|
2013-08-09 11:15:21 +04:00
|
|
|
if (loop >= low->len || upp->str[loop] == low->str[loop])
|
|
|
|
tmp_len =
|
|
|
|
g_snprintf (tmp_str, sizeof (tmp_str), "\\x%02X", (unsigned char) upp->str[loop]);
|
2010-03-30 12:10:25 +04:00
|
|
|
else
|
2013-08-09 11:15:21 +04:00
|
|
|
tmp_len =
|
|
|
|
g_snprintf (tmp_str, sizeof (tmp_str), "[\\x%02X\\x%02X]",
|
|
|
|
(unsigned char) upp->str[loop], (unsigned char) low->str[loop]);
|
|
|
|
|
|
|
|
g_string_append_len (str_to, tmp_str, tmp_len);
|
2009-04-25 17:51:37 +04:00
|
|
|
}
|
2013-08-09 11:15:21 +04:00
|
|
|
|
2009-04-25 17:51:37 +04:00
|
|
|
g_string_free (upp, TRUE);
|
|
|
|
g_string_free (low, TRUE);
|
|
|
|
}
|
|
|
|
|
2009-04-25 12:09:47 +04:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
static void
|
2024-06-01 21:12:14 +03:00
|
|
|
mc_search__cond_struct_new_regex_accum_append (const char *charset, GString *str_to,
|
|
|
|
GString *str_from)
|
2009-04-25 12:09:47 +04:00
|
|
|
{
|
2009-04-25 17:51:37 +04:00
|
|
|
GString *recoded_part;
|
2010-03-06 13:28:07 +03:00
|
|
|
gsize loop = 0;
|
2009-04-25 12:09:47 +04:00
|
|
|
|
2010-03-06 13:28:07 +03:00
|
|
|
recoded_part = g_string_sized_new (32);
|
2009-04-25 12:09:47 +04:00
|
|
|
|
2010-03-30 12:10:25 +04:00
|
|
|
while (loop < str_from->len)
|
|
|
|
{
|
2022-09-18 17:04:53 +03:00
|
|
|
GString *one_char;
|
2010-03-06 13:28:07 +03:00
|
|
|
gboolean just_letters;
|
|
|
|
|
2009-04-25 12:09:47 +04:00
|
|
|
one_char =
|
2022-09-18 17:04:53 +03:00
|
|
|
mc_search__get_one_symbol (charset, str_from->str + loop,
|
2016-04-07 10:52:04 +03:00
|
|
|
MIN (str_from->len - loop, 6), &just_letters);
|
2010-03-06 13:28:07 +03:00
|
|
|
|
2022-09-18 17:04:53 +03:00
|
|
|
if (one_char->len == 0)
|
2009-04-25 12:09:47 +04:00
|
|
|
loop++;
|
2010-03-30 12:10:25 +04:00
|
|
|
else
|
|
|
|
{
|
2022-09-18 17:04:53 +03:00
|
|
|
loop += one_char->len;
|
2010-03-06 13:28:07 +03:00
|
|
|
|
|
|
|
if (just_letters)
|
2022-09-18 17:08:04 +03:00
|
|
|
mc_search__cond_struct_new_regex_hex_add (charset, recoded_part, one_char);
|
2010-03-06 13:28:07 +03:00
|
|
|
else
|
2022-09-18 17:04:53 +03:00
|
|
|
g_string_append_len (recoded_part, one_char->str, one_char->len);
|
2009-04-25 12:09:47 +04:00
|
|
|
}
|
2010-03-06 13:28:07 +03:00
|
|
|
|
2022-09-18 17:04:53 +03:00
|
|
|
g_string_free (one_char, TRUE);
|
2009-04-25 12:09:47 +04:00
|
|
|
}
|
|
|
|
|
2013-08-09 11:42:06 +04:00
|
|
|
g_string_append_len (str_to, recoded_part->str, recoded_part->len);
|
2009-04-25 12:09:47 +04:00
|
|
|
g_string_free (recoded_part, TRUE);
|
|
|
|
g_string_set_size (str_from, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2016-12-01 17:14:27 +03:00
|
|
|
/**
|
|
|
|
* Creates a case-insensitive version of a regex pattern.
|
|
|
|
*
|
|
|
|
* For example (assuming ASCII charset): given "\\bHello!\\xAB", returns
|
|
|
|
* "\\b[Hh][Ee][Ll][Ll][Oo]!\\xAB" (this example is for easier reading; in
|
|
|
|
* reality hex codes are used instead of letters).
|
|
|
|
*
|
|
|
|
* This function knows not to ruin special regex symbols.
|
|
|
|
*
|
|
|
|
* This function is used when working with non-UTF-8 charsets: GLib's
|
|
|
|
* regex engine doesn't understand such charsets and therefore can't do
|
|
|
|
* this job itself.
|
|
|
|
*/
|
2009-04-25 12:09:47 +04:00
|
|
|
static GString *
|
2024-06-01 21:12:14 +03:00
|
|
|
mc_search__cond_struct_new_regex_ci_str (const char *charset, const GString *astr)
|
2009-04-25 12:09:47 +04:00
|
|
|
{
|
|
|
|
GString *accumulator, *spec_char, *ret_str;
|
|
|
|
gsize loop;
|
|
|
|
|
2010-10-21 17:18:18 +04:00
|
|
|
ret_str = g_string_sized_new (64);
|
|
|
|
accumulator = g_string_sized_new (64);
|
|
|
|
spec_char = g_string_sized_new (64);
|
2009-04-25 12:09:47 +04:00
|
|
|
loop = 0;
|
|
|
|
|
2022-10-01 13:07:48 +03:00
|
|
|
while (loop < astr->len)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2010-10-21 17:09:07 +04:00
|
|
|
if (mc_search__regex_str_append_if_special (spec_char, astr, &loop))
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2009-04-25 12:09:47 +04:00
|
|
|
mc_search__cond_struct_new_regex_accum_append (charset, ret_str, accumulator);
|
|
|
|
g_string_append_len (ret_str, spec_char->str, spec_char->len);
|
|
|
|
g_string_set_size (spec_char, 0);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-03-09 14:41:08 +03:00
|
|
|
if (astr->str[loop] == '[' && !str_is_char_escaped (astr->str, &(astr->str[loop])))
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2009-04-25 12:09:47 +04:00
|
|
|
mc_search__cond_struct_new_regex_accum_append (charset, ret_str, accumulator);
|
|
|
|
|
2010-10-21 17:09:07 +04:00
|
|
|
while (loop < astr->len && !(astr->str[loop] == ']'
|
2024-03-09 14:41:08 +03:00
|
|
|
&& !str_is_char_escaped (astr->str, &(astr->str[loop]))))
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2010-10-21 17:09:07 +04:00
|
|
|
g_string_append_c (ret_str, astr->str[loop]);
|
2009-04-25 12:09:47 +04:00
|
|
|
loop++;
|
|
|
|
}
|
2010-10-21 17:07:06 +04:00
|
|
|
|
2010-10-21 17:09:07 +04:00
|
|
|
g_string_append_c (ret_str, astr->str[loop]);
|
2009-04-25 12:09:47 +04:00
|
|
|
loop++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
TODO: handle [ and ]
|
|
|
|
*/
|
2010-10-21 17:09:07 +04:00
|
|
|
g_string_append_c (accumulator, astr->str[loop]);
|
2009-04-25 12:09:47 +04:00
|
|
|
loop++;
|
|
|
|
}
|
|
|
|
mc_search__cond_struct_new_regex_accum_append (charset, ret_str, accumulator);
|
|
|
|
|
|
|
|
g_string_free (accumulator, TRUE);
|
|
|
|
g_string_free (spec_char, TRUE);
|
2010-10-21 17:09:07 +04:00
|
|
|
|
2009-04-25 12:09:47 +04:00
|
|
|
return ret_str;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2015-10-18 20:26:42 +03:00
|
|
|
#ifdef SEARCH_TYPE_GLIB
|
|
|
|
/* A thin wrapper above g_regex_match_full that makes sure the string passed
|
|
|
|
* to it is valid UTF-8 (unless G_REGEX_RAW compile flag was set), as it is a
|
|
|
|
* requirement by glib and it might crash otherwise. See: mc ticket 3449.
|
|
|
|
* Be careful: there might be embedded NULs in the strings. */
|
|
|
|
static gboolean
|
2024-06-01 21:12:14 +03:00
|
|
|
mc_search__g_regex_match_full_safe (const GRegex *regex,
|
|
|
|
const gchar *string,
|
2015-10-18 20:26:42 +03:00
|
|
|
gssize string_len,
|
|
|
|
gint start_position,
|
|
|
|
GRegexMatchFlags match_options,
|
2024-06-01 21:12:14 +03:00
|
|
|
GMatchInfo **match_info, GError **error)
|
2015-10-18 20:26:42 +03:00
|
|
|
{
|
|
|
|
char *string_safe, *p, *end;
|
|
|
|
gboolean ret;
|
|
|
|
|
2016-12-06 15:07:15 +03:00
|
|
|
if (string_len < 0)
|
|
|
|
string_len = strlen (string);
|
|
|
|
|
2015-10-18 20:26:42 +03:00
|
|
|
if ((g_regex_get_compile_flags (regex) & G_REGEX_RAW)
|
|
|
|
|| g_utf8_validate (string, string_len, NULL))
|
|
|
|
{
|
|
|
|
return g_regex_match_full (regex, string, string_len, start_position, match_options,
|
|
|
|
match_info, error);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Correctly handle embedded NULs while copying */
|
2021-03-16 14:04:23 +03:00
|
|
|
p = string_safe = g_malloc (string_len + 1);
|
2015-10-18 20:26:42 +03:00
|
|
|
memcpy (string_safe, string, string_len);
|
2021-03-16 14:04:23 +03:00
|
|
|
string_safe[string_len] = '\0';
|
2015-10-18 20:26:42 +03:00
|
|
|
end = p + string_len;
|
|
|
|
|
|
|
|
while (p < end)
|
|
|
|
{
|
|
|
|
gunichar c = g_utf8_get_char_validated (p, -1);
|
|
|
|
if (c != (gunichar) (-1) && c != (gunichar) (-2))
|
|
|
|
{
|
|
|
|
p = g_utf8_next_char (p);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* U+FFFD would be the proper choice, but then we'd have to
|
|
|
|
maintain mapping between old and new offsets.
|
|
|
|
So rather do a byte by byte replacement. */
|
|
|
|
*p++ = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret =
|
|
|
|
g_regex_match_full (regex, string_safe, string_len, start_position, match_options,
|
|
|
|
match_info, error);
|
|
|
|
g_free (string_safe);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
#endif /* SEARCH_TYPE_GLIB */
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-04-25 12:09:47 +04:00
|
|
|
static mc_search__found_cond_t
|
2024-06-01 21:12:14 +03:00
|
|
|
mc_search__regex_found_cond_one (mc_search_t *lc_mc_search, mc_search_regex_t *regex,
|
|
|
|
GString *search_str)
|
2009-04-25 12:09:47 +04:00
|
|
|
{
|
2009-07-07 12:11:29 +04:00
|
|
|
#ifdef SEARCH_TYPE_GLIB
|
2014-07-15 16:53:06 +04:00
|
|
|
GError *mcerror = NULL;
|
2009-04-25 12:09:47 +04:00
|
|
|
|
2015-10-18 20:26:42 +03:00
|
|
|
if (!mc_search__g_regex_match_full_safe
|
|
|
|
(regex, search_str->str, search_str->len, 0, G_REGEX_MATCH_NEWLINE_ANY,
|
|
|
|
&lc_mc_search->regex_match_info, &mcerror))
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2009-10-30 04:12:04 +03:00
|
|
|
g_match_info_free (lc_mc_search->regex_match_info);
|
|
|
|
lc_mc_search->regex_match_info = NULL;
|
2014-07-15 16:53:06 +04:00
|
|
|
if (mcerror != NULL)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2009-10-30 04:12:04 +03:00
|
|
|
lc_mc_search->error = MC_SEARCH_E_REGEX;
|
2016-04-27 10:26:38 +03:00
|
|
|
g_free (lc_mc_search->error_str);
|
2010-03-30 12:10:25 +04:00
|
|
|
lc_mc_search->error_str =
|
2014-07-15 16:53:06 +04:00
|
|
|
str_conv_gerror_message (mcerror, _("Regular expression error"));
|
|
|
|
g_error_free (mcerror);
|
2009-04-25 12:09:47 +04:00
|
|
|
return COND__FOUND_ERROR;
|
|
|
|
}
|
|
|
|
return COND__NOT_FOUND;
|
|
|
|
}
|
2010-03-31 11:48:53 +04:00
|
|
|
lc_mc_search->num_results = g_match_info_get_match_count (lc_mc_search->regex_match_info);
|
2009-07-07 12:11:29 +04:00
|
|
|
#else /* SEARCH_TYPE_GLIB */
|
2023-03-22 21:50:11 +03:00
|
|
|
|
|
|
|
lc_mc_search->num_results =
|
|
|
|
#ifdef HAVE_PCRE2
|
|
|
|
pcre2_match (regex, (unsigned char *) search_str->str, search_str->len, 0, 0,
|
|
|
|
lc_mc_search->regex_match_info, NULL);
|
|
|
|
#else
|
|
|
|
pcre_exec (regex, lc_mc_search->regex_match_info, search_str->str, search_str->len, 0, 0,
|
|
|
|
lc_mc_search->iovector, MC_SEARCH__NUM_REPLACE_ARGS);
|
|
|
|
#endif
|
2010-03-31 11:48:53 +04:00
|
|
|
if (lc_mc_search->num_results < 0)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2009-05-05 17:19:32 +04:00
|
|
|
return COND__NOT_FOUND;
|
|
|
|
}
|
2009-07-07 12:11:29 +04:00
|
|
|
#endif /* SEARCH_TYPE_GLIB */
|
2009-04-25 12:09:47 +04:00
|
|
|
return COND__FOUND_OK;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
static mc_search__found_cond_t
|
2024-06-01 21:12:14 +03:00
|
|
|
mc_search__regex_found_cond (mc_search_t *lc_mc_search, GString *search_str)
|
2009-04-25 12:09:47 +04:00
|
|
|
{
|
|
|
|
gsize loop1;
|
|
|
|
|
2022-04-02 19:22:31 +03:00
|
|
|
for (loop1 = 0; loop1 < lc_mc_search->prepared.conditions->len; loop1++)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2013-10-15 10:34:04 +04:00
|
|
|
mc_search_cond_t *mc_search_cond;
|
|
|
|
mc_search__found_cond_t ret;
|
|
|
|
|
2022-04-02 19:32:52 +03:00
|
|
|
mc_search_cond =
|
2022-04-02 19:22:31 +03:00
|
|
|
(mc_search_cond_t *) g_ptr_array_index (lc_mc_search->prepared.conditions, loop1);
|
2009-04-25 12:09:47 +04:00
|
|
|
|
2009-05-05 17:19:32 +04:00
|
|
|
if (!mc_search_cond->regex_handle)
|
2009-04-25 12:09:47 +04:00
|
|
|
continue;
|
|
|
|
|
2010-03-30 12:10:25 +04:00
|
|
|
ret =
|
|
|
|
mc_search__regex_found_cond_one (lc_mc_search, mc_search_cond->regex_handle,
|
|
|
|
search_str);
|
2009-04-25 12:09:47 +04:00
|
|
|
if (ret != COND__NOT_FOUND)
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
return COND__NOT_ALL_FOUND;
|
|
|
|
}
|
|
|
|
|
2009-05-05 17:19:32 +04:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
static int
|
2024-06-01 21:12:14 +03:00
|
|
|
mc_search_regex__get_max_num_of_replace_tokens (const gchar *str, gsize len)
|
2009-05-05 17:19:32 +04:00
|
|
|
{
|
2009-06-08 18:41:20 +04:00
|
|
|
int max_token = 0;
|
2009-05-05 17:19:32 +04:00
|
|
|
gsize loop;
|
2023-12-19 21:38:24 +03:00
|
|
|
|
2010-03-30 12:10:25 +04:00
|
|
|
for (loop = 0; loop < len - 1; loop++)
|
2010-11-08 13:21:45 +03:00
|
|
|
if (str[loop] == '\\' && g_ascii_isdigit (str[loop + 1]))
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2024-03-09 14:41:08 +03:00
|
|
|
if (str_is_char_escaped (str, &str[loop]))
|
2009-06-08 14:54:35 +04:00
|
|
|
continue;
|
2009-06-08 18:41:20 +04:00
|
|
|
if (max_token < str[loop + 1] - '0')
|
|
|
|
max_token = str[loop + 1] - '0';
|
2009-06-02 13:09:16 +04:00
|
|
|
}
|
2023-12-19 21:38:24 +03:00
|
|
|
else if (str[loop] == '$' && str[loop + 1] == '{')
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2009-06-02 13:09:16 +04:00
|
|
|
gsize tmp_len;
|
2013-10-15 10:34:04 +04:00
|
|
|
|
2024-03-09 14:41:08 +03:00
|
|
|
if (str_is_char_escaped (str, &str[loop]))
|
2009-06-02 13:09:16 +04:00
|
|
|
continue;
|
|
|
|
|
2009-06-05 12:51:12 +04:00
|
|
|
for (tmp_len = 0;
|
|
|
|
loop + tmp_len + 2 < len && (str[loop + 2 + tmp_len] & (char) 0xf0) == 0x30;
|
|
|
|
tmp_len++);
|
2013-10-15 10:34:04 +04:00
|
|
|
|
2010-03-30 12:10:25 +04:00
|
|
|
if (str[loop + 2 + tmp_len] == '}')
|
|
|
|
{
|
2013-10-15 10:34:04 +04:00
|
|
|
int tmp_token;
|
|
|
|
char *tmp_str;
|
|
|
|
|
2009-06-09 11:59:45 +04:00
|
|
|
tmp_str = g_strndup (&str[loop + 2], tmp_len);
|
2009-06-08 18:41:20 +04:00
|
|
|
tmp_token = atoi (tmp_str);
|
|
|
|
if (max_token < tmp_token)
|
|
|
|
max_token = tmp_token;
|
|
|
|
g_free (tmp_str);
|
|
|
|
}
|
2009-05-05 17:19:32 +04:00
|
|
|
}
|
2023-12-19 21:38:24 +03:00
|
|
|
|
2009-06-08 18:41:20 +04:00
|
|
|
return max_token;
|
2009-05-05 17:19:32 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-06-08 14:54:35 +04:00
|
|
|
static char *
|
2024-06-01 21:12:14 +03:00
|
|
|
mc_search_regex__get_token_by_num (const mc_search_t *lc_mc_search, gsize lc_index)
|
2009-05-05 17:19:32 +04:00
|
|
|
{
|
2009-06-17 11:56:21 +04:00
|
|
|
int fnd_start = 0, fnd_end = 0;
|
2009-06-02 13:09:16 +04:00
|
|
|
|
2009-07-07 12:11:29 +04:00
|
|
|
#ifdef SEARCH_TYPE_GLIB
|
2009-10-30 04:12:04 +03:00
|
|
|
g_match_info_fetch_pos (lc_mc_search->regex_match_info, lc_index, &fnd_start, &fnd_end);
|
2009-07-07 12:11:29 +04:00
|
|
|
#else /* SEARCH_TYPE_GLIB */
|
2009-10-30 04:12:04 +03:00
|
|
|
fnd_start = lc_mc_search->iovector[lc_index * 2 + 0];
|
|
|
|
fnd_end = lc_mc_search->iovector[lc_index * 2 + 1];
|
2009-07-07 12:11:29 +04:00
|
|
|
#endif /* SEARCH_TYPE_GLIB */
|
2009-05-05 17:19:32 +04:00
|
|
|
|
2014-12-30 16:21:55 +03:00
|
|
|
if (fnd_end == fnd_start)
|
|
|
|
return g_strdup ("");
|
2009-06-08 14:54:35 +04:00
|
|
|
|
2009-10-30 04:12:04 +03:00
|
|
|
return g_strndup (lc_mc_search->regex_buffer->str + fnd_start, fnd_end - fnd_start);
|
2009-05-05 17:19:32 +04:00
|
|
|
|
2009-06-08 14:54:35 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
2010-11-08 21:50:15 +03:00
|
|
|
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
static gboolean
|
2024-06-01 21:12:14 +03:00
|
|
|
mc_search_regex__replace_handle_esc_seq (const GString *replace_str, const gsize current_pos,
|
|
|
|
gsize *skip_len, int *ret)
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
{
|
|
|
|
char *curr_str = &(replace_str->str[current_pos]);
|
2014-12-31 19:59:20 +03:00
|
|
|
char c = curr_str[1];
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
|
|
|
|
if (replace_str->len > current_pos + 2)
|
|
|
|
{
|
2011-05-30 20:16:14 +04:00
|
|
|
if (c == '{')
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
{
|
|
|
|
for (*skip_len = 2; /* \{ */
|
2014-12-31 19:59:20 +03:00
|
|
|
current_pos + *skip_len < replace_str->len && curr_str[*skip_len] >= '0'
|
|
|
|
&& curr_str[*skip_len] <= '7'; (*skip_len)++)
|
|
|
|
;
|
|
|
|
|
|
|
|
if (current_pos + *skip_len < replace_str->len && curr_str[*skip_len] == '}')
|
2011-05-30 20:16:14 +04:00
|
|
|
{
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
(*skip_len)++;
|
2011-05-30 20:16:14 +04:00
|
|
|
*ret = REPLACE_PREPARE_T_ESCAPE_SEQ;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*ret = REPLACE_PREPARE_T_NOTHING_SPECIAL;
|
|
|
|
return TRUE;
|
|
|
|
}
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
}
|
|
|
|
|
2011-05-30 20:16:14 +04:00
|
|
|
if (c == 'x')
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
{
|
|
|
|
*skip_len = 2; /* \x */
|
2014-12-31 19:59:20 +03:00
|
|
|
c = curr_str[2];
|
2011-05-30 20:16:14 +04:00
|
|
|
if (c == '{')
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
{
|
|
|
|
for (*skip_len = 3; /* \x{ */
|
|
|
|
current_pos + *skip_len < replace_str->len
|
2014-12-31 19:59:20 +03:00
|
|
|
&& g_ascii_isxdigit ((guchar) curr_str[*skip_len]); (*skip_len)++)
|
|
|
|
;
|
|
|
|
|
|
|
|
if (current_pos + *skip_len < replace_str->len && curr_str[*skip_len] == '}')
|
2011-05-30 20:16:14 +04:00
|
|
|
{
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
(*skip_len)++;
|
2011-05-30 20:16:14 +04:00
|
|
|
*ret = REPLACE_PREPARE_T_ESCAPE_SEQ;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*ret = REPLACE_PREPARE_T_NOTHING_SPECIAL;
|
|
|
|
return TRUE;
|
|
|
|
}
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
}
|
2011-05-30 20:16:14 +04:00
|
|
|
else if (!g_ascii_isxdigit ((guchar) c))
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
{
|
|
|
|
*skip_len = 2; /* \x without number behind */
|
|
|
|
*ret = REPLACE_PREPARE_T_NOTHING_SPECIAL;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-12-31 19:59:20 +03:00
|
|
|
c = curr_str[3];
|
2011-05-30 20:16:14 +04:00
|
|
|
if (!g_ascii_isxdigit ((guchar) c))
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
*skip_len = 3; /* \xH */
|
|
|
|
else
|
|
|
|
*skip_len = 4; /* \xHH */
|
|
|
|
*ret = REPLACE_PREPARE_T_ESCAPE_SEQ;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-30 20:16:14 +04:00
|
|
|
if (strchr ("ntvbrfa", c) != NULL)
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
{
|
|
|
|
*skip_len = 2;
|
|
|
|
*ret = REPLACE_PREPARE_T_ESCAPE_SEQ;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-06-08 14:54:35 +04:00
|
|
|
static int
|
2024-06-01 21:12:14 +03:00
|
|
|
mc_search_regex__process_replace_str (const GString *replace_str, const gsize current_pos,
|
|
|
|
gsize *skip_len, replace_transform_type_t *replace_flags)
|
2009-06-08 14:54:35 +04:00
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
const char *curr_str = &(replace_str->str[current_pos]);
|
|
|
|
|
|
|
|
if (current_pos > replace_str->len)
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
return REPLACE_PREPARE_T_NOTHING_SPECIAL;
|
2009-05-05 17:19:32 +04:00
|
|
|
|
2009-06-08 14:54:35 +04:00
|
|
|
*skip_len = 0;
|
2009-05-05 17:19:32 +04:00
|
|
|
|
2014-12-31 19:59:20 +03:00
|
|
|
if (replace_str->len > current_pos + 2 && curr_str[0] == '$' && curr_str[1] == '{'
|
|
|
|
&& (curr_str[2] & (char) 0xf0) == 0x30)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2013-10-15 10:34:04 +04:00
|
|
|
char *tmp_str;
|
|
|
|
|
2024-03-09 14:41:08 +03:00
|
|
|
if (str_is_char_escaped (replace_str->str, curr_str))
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2009-06-10 16:30:09 +04:00
|
|
|
*skip_len = 1;
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
return REPLACE_PREPARE_T_NOTHING_SPECIAL;
|
2009-06-10 16:30:09 +04:00
|
|
|
}
|
2009-06-08 14:54:35 +04:00
|
|
|
|
|
|
|
for (*skip_len = 0;
|
|
|
|
current_pos + *skip_len + 2 < replace_str->len
|
2014-12-31 19:59:20 +03:00
|
|
|
&& (curr_str[2 + *skip_len] & (char) 0xf0) == 0x30; (*skip_len)++)
|
|
|
|
;
|
2009-06-08 14:54:35 +04:00
|
|
|
|
2014-12-31 19:59:20 +03:00
|
|
|
if (curr_str[2 + *skip_len] != '}')
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
return REPLACE_PREPARE_T_NOTHING_SPECIAL;
|
2009-06-08 14:54:35 +04:00
|
|
|
|
|
|
|
tmp_str = g_strndup (curr_str + 2, *skip_len);
|
|
|
|
if (tmp_str == NULL)
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
return REPLACE_PREPARE_T_NOTHING_SPECIAL;
|
2009-06-08 14:54:35 +04:00
|
|
|
|
|
|
|
ret = atoi (tmp_str);
|
|
|
|
g_free (tmp_str);
|
|
|
|
|
|
|
|
*skip_len += 3; /* ${} */
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
return ret; /* capture buffer index >= 0 */
|
2009-06-08 14:54:35 +04:00
|
|
|
}
|
|
|
|
|
2014-12-31 19:59:20 +03:00
|
|
|
if (curr_str[0] == '\\' && replace_str->len > current_pos + 1)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2024-03-09 14:41:08 +03:00
|
|
|
if (str_is_char_escaped (replace_str->str, curr_str))
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2009-06-10 16:30:09 +04:00
|
|
|
*skip_len = 1;
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
return REPLACE_PREPARE_T_NOTHING_SPECIAL;
|
2009-06-10 16:30:09 +04:00
|
|
|
}
|
2009-06-08 14:54:35 +04:00
|
|
|
|
2014-12-31 19:59:20 +03:00
|
|
|
if (g_ascii_isdigit (curr_str[1]))
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2014-12-31 19:59:20 +03:00
|
|
|
ret = g_ascii_digit_value (curr_str[1]); /* capture buffer index >= 0 */
|
2009-06-08 14:54:35 +04:00
|
|
|
*skip_len = 2; /* \\ and one digit */
|
|
|
|
return ret;
|
|
|
|
}
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
|
2011-05-30 20:16:14 +04:00
|
|
|
if (!mc_search_regex__replace_handle_esc_seq (replace_str, current_pos, skip_len, &ret))
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
return ret;
|
|
|
|
|
|
|
|
ret = REPLACE_PREPARE_T_REPLACE_FLAG;
|
2009-06-08 14:54:35 +04:00
|
|
|
*skip_len += 2;
|
2014-12-31 19:59:20 +03:00
|
|
|
|
|
|
|
switch (curr_str[1])
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2009-06-08 14:54:35 +04:00
|
|
|
case 'U':
|
|
|
|
*replace_flags |= REPLACE_T_UPP_TRANSFORM;
|
|
|
|
*replace_flags &= ~REPLACE_T_LOW_TRANSFORM;
|
|
|
|
break;
|
|
|
|
case 'u':
|
|
|
|
*replace_flags |= REPLACE_T_UPP_TRANSFORM_CHAR;
|
|
|
|
break;
|
|
|
|
case 'L':
|
|
|
|
*replace_flags |= REPLACE_T_LOW_TRANSFORM;
|
|
|
|
*replace_flags &= ~REPLACE_T_UPP_TRANSFORM;
|
|
|
|
break;
|
|
|
|
case 'l':
|
|
|
|
*replace_flags |= REPLACE_T_LOW_TRANSFORM_CHAR;
|
|
|
|
break;
|
|
|
|
case 'E':
|
|
|
|
*replace_flags = REPLACE_T_NO_TRANSFORM;
|
|
|
|
break;
|
|
|
|
default:
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
ret = REPLACE_PREPARE_T_NOTHING_SPECIAL;
|
2009-06-08 14:54:35 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
2009-05-05 17:19:32 +04:00
|
|
|
}
|
2010-11-08 13:21:45 +03:00
|
|
|
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
2009-06-08 14:54:35 +04:00
|
|
|
static void
|
2024-06-01 21:12:14 +03:00
|
|
|
mc_search_regex__process_append_str (GString *dest_str, const char *from, gsize len,
|
|
|
|
replace_transform_type_t *replace_flags)
|
2009-06-08 14:54:35 +04:00
|
|
|
{
|
2013-08-09 11:50:19 +04:00
|
|
|
gsize loop;
|
2009-06-08 14:54:35 +04:00
|
|
|
gsize char_len;
|
|
|
|
|
2012-11-25 11:44:15 +04:00
|
|
|
if (len == (gsize) (-1))
|
2009-06-08 14:54:35 +04:00
|
|
|
len = strlen (from);
|
|
|
|
|
2014-12-30 13:14:32 +03:00
|
|
|
if (*replace_flags == REPLACE_T_NO_TRANSFORM)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2009-06-08 14:54:35 +04:00
|
|
|
g_string_append_len (dest_str, from, len);
|
|
|
|
return;
|
|
|
|
}
|
2013-08-09 11:50:19 +04:00
|
|
|
|
|
|
|
for (loop = 0; loop < len; loop += char_len)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2013-08-09 11:50:19 +04:00
|
|
|
GString *tmp_string = NULL;
|
2022-09-18 17:04:53 +03:00
|
|
|
GString *s;
|
2013-08-09 11:50:19 +04:00
|
|
|
|
2022-09-18 17:04:53 +03:00
|
|
|
s = mc_search__get_one_symbol (NULL, from + loop, len - loop, NULL);
|
|
|
|
char_len = s->len;
|
2013-08-09 11:50:19 +04:00
|
|
|
|
|
|
|
if ((*replace_flags & REPLACE_T_UPP_TRANSFORM_CHAR) != 0)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2010-10-21 13:22:10 +04:00
|
|
|
*replace_flags &= ~REPLACE_T_UPP_TRANSFORM_CHAR;
|
2022-09-24 09:26:03 +03:00
|
|
|
tmp_string = mc_search__toupper_case_str (NULL, s);
|
2013-08-09 11:50:19 +04:00
|
|
|
g_string_append_len (dest_str, tmp_string->str, tmp_string->len);
|
2010-03-30 12:10:25 +04:00
|
|
|
}
|
2013-08-09 11:50:19 +04:00
|
|
|
else if ((*replace_flags & REPLACE_T_LOW_TRANSFORM_CHAR) != 0)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2010-10-21 13:22:10 +04:00
|
|
|
*replace_flags &= ~REPLACE_T_LOW_TRANSFORM_CHAR;
|
2022-09-24 09:26:03 +03:00
|
|
|
tmp_string = mc_search__tolower_case_str (NULL, s);
|
2013-08-09 11:50:19 +04:00
|
|
|
g_string_append_len (dest_str, tmp_string->str, tmp_string->len);
|
2010-03-30 12:10:25 +04:00
|
|
|
}
|
2013-08-09 11:50:19 +04:00
|
|
|
else if ((*replace_flags & REPLACE_T_UPP_TRANSFORM) != 0)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2022-09-24 09:26:03 +03:00
|
|
|
tmp_string = mc_search__toupper_case_str (NULL, s);
|
2013-08-09 11:50:19 +04:00
|
|
|
g_string_append_len (dest_str, tmp_string->str, tmp_string->len);
|
2010-03-30 12:10:25 +04:00
|
|
|
}
|
2013-08-09 11:50:19 +04:00
|
|
|
else if ((*replace_flags & REPLACE_T_LOW_TRANSFORM) != 0)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2022-09-24 09:26:03 +03:00
|
|
|
tmp_string = mc_search__tolower_case_str (NULL, s);
|
2013-08-09 11:50:19 +04:00
|
|
|
g_string_append_len (dest_str, tmp_string->str, tmp_string->len);
|
2010-03-30 12:10:25 +04:00
|
|
|
}
|
2013-08-09 11:50:19 +04:00
|
|
|
|
2022-09-18 17:04:53 +03:00
|
|
|
g_string_free (s, TRUE);
|
2022-09-24 16:50:37 +03:00
|
|
|
if (tmp_string != NULL)
|
|
|
|
g_string_free (tmp_string, TRUE);
|
2009-06-08 14:54:35 +04:00
|
|
|
}
|
|
|
|
}
|
2009-05-05 17:19:32 +04:00
|
|
|
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
static void
|
2024-06-01 21:12:14 +03:00
|
|
|
mc_search_regex__process_escape_sequence (GString *dest_str, const char *from, gsize len,
|
|
|
|
replace_transform_type_t *replace_flags, gboolean is_utf8)
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
{
|
|
|
|
gsize i = 0;
|
2011-05-30 20:16:14 +04:00
|
|
|
unsigned int c = 0;
|
|
|
|
char b;
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
|
|
|
|
if (len == (gsize) (-1))
|
|
|
|
len = strlen (from);
|
|
|
|
if (len == 0)
|
|
|
|
return;
|
2014-12-31 19:59:20 +03:00
|
|
|
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
if (from[i] == '{')
|
|
|
|
i++;
|
|
|
|
if (i >= len)
|
|
|
|
return;
|
2011-05-30 20:16:14 +04:00
|
|
|
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
if (from[i] == 'x')
|
|
|
|
{
|
|
|
|
i++;
|
|
|
|
if (i < len && from[i] == '{')
|
|
|
|
i++;
|
|
|
|
for (; i < len; i++)
|
|
|
|
{
|
|
|
|
if (from[i] >= '0' && from[i] <= '9')
|
|
|
|
c = c * 16 + from[i] - '0';
|
|
|
|
else if (from[i] >= 'a' && from[i] <= 'f')
|
|
|
|
c = c * 16 + 10 + from[i] - 'a';
|
|
|
|
else if (from[i] >= 'A' && from[i] <= 'F')
|
|
|
|
c = c * 16 + 10 + from[i] - 'A';
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-05-30 20:16:14 +04:00
|
|
|
else if (from[i] >= '0' && from[i] <= '7')
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
for (; i < len && from[i] >= '0' && from[i] <= '7'; i++)
|
|
|
|
c = c * 8 + from[i] - '0';
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (from[i])
|
|
|
|
{
|
|
|
|
case 'n':
|
|
|
|
c = '\n';
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
c = '\t';
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
c = '\v';
|
|
|
|
break;
|
|
|
|
case 'b':
|
|
|
|
c = '\b';
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
c = '\r';
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
c = '\f';
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
c = '\a';
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
mc_search_regex__process_append_str (dest_str, from, len, replace_flags);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2011-05-30 20:16:14 +04:00
|
|
|
|
|
|
|
if (c < 0x80 || !is_utf8)
|
|
|
|
g_string_append_c (dest_str, (char) c);
|
|
|
|
else if (c < 0x800)
|
|
|
|
{
|
|
|
|
b = 0xC0 | (c >> 6);
|
|
|
|
g_string_append_c (dest_str, b);
|
|
|
|
b = 0x80 | (c & 0x3F);
|
|
|
|
g_string_append_c (dest_str, b);
|
|
|
|
}
|
|
|
|
else if (c < 0x10000)
|
|
|
|
{
|
|
|
|
b = 0xE0 | (c >> 12);
|
|
|
|
g_string_append_c (dest_str, b);
|
|
|
|
b = 0x80 | ((c >> 6) & 0x3F);
|
|
|
|
g_string_append_c (dest_str, b);
|
|
|
|
b = 0x80 | (c & 0x3F);
|
|
|
|
g_string_append_c (dest_str, b);
|
|
|
|
}
|
|
|
|
else if (c < 0x10FFFF)
|
|
|
|
{
|
|
|
|
b = 0xF0 | (c >> 16);
|
|
|
|
g_string_append_c (dest_str, b);
|
|
|
|
b = 0x80 | ((c >> 12) & 0x3F);
|
|
|
|
g_string_append_c (dest_str, b);
|
|
|
|
b = 0x80 | ((c >> 6) & 0x3F);
|
|
|
|
g_string_append_c (dest_str, b);
|
|
|
|
b = 0x80 | (c & 0x3F);
|
|
|
|
g_string_append_c (dest_str, b);
|
|
|
|
}
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
2009-04-25 12:09:47 +04:00
|
|
|
/*** public functions ****************************************************************************/
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
2009-04-25 12:09:47 +04:00
|
|
|
|
|
|
|
void
|
2024-06-01 21:12:14 +03:00
|
|
|
mc_search__cond_struct_new_init_regex (const char *charset, mc_search_t *lc_mc_search,
|
|
|
|
mc_search_cond_t *mc_search_cond)
|
2009-04-25 12:09:47 +04:00
|
|
|
{
|
2015-09-19 20:26:31 +03:00
|
|
|
if (lc_mc_search->whole_words && !lc_mc_search->is_entire_line)
|
|
|
|
{
|
|
|
|
/* NOTE: \b as word boundary doesn't allow search
|
|
|
|
* whole words with non-ASCII symbols.
|
|
|
|
* Update: Is it still true nowadays? Probably not. #2396, #3524 */
|
|
|
|
g_string_prepend (mc_search_cond->str, "(?<![\\p{L}\\p{N}_])");
|
|
|
|
g_string_append (mc_search_cond->str, "(?![\\p{L}\\p{N}_])");
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2009-07-07 12:11:29 +04:00
|
|
|
#ifdef SEARCH_TYPE_GLIB
|
2015-09-19 20:26:31 +03:00
|
|
|
GError *mcerror = NULL;
|
2016-01-05 11:45:54 +03:00
|
|
|
GRegexCompileFlags g_regex_options = G_REGEX_OPTIMIZE | G_REGEX_DOTALL;
|
|
|
|
|
|
|
|
if (str_isutf8 (charset) && mc_global.utf8_display)
|
|
|
|
{
|
|
|
|
if (!lc_mc_search->is_case_sensitive)
|
|
|
|
g_regex_options |= G_REGEX_CASELESS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
g_regex_options |= G_REGEX_RAW;
|
|
|
|
|
|
|
|
if (!lc_mc_search->is_case_sensitive)
|
|
|
|
{
|
|
|
|
GString *tmp;
|
|
|
|
|
|
|
|
tmp = mc_search_cond->str;
|
|
|
|
mc_search_cond->str = mc_search__cond_struct_new_regex_ci_str (charset, tmp);
|
|
|
|
g_string_free (tmp, TRUE);
|
|
|
|
}
|
|
|
|
}
|
2009-04-25 17:51:37 +04:00
|
|
|
|
2015-09-19 20:26:31 +03:00
|
|
|
mc_search_cond->regex_handle =
|
2016-01-05 11:45:54 +03:00
|
|
|
g_regex_new (mc_search_cond->str->str, g_regex_options, 0, &mcerror);
|
2009-04-25 17:51:37 +04:00
|
|
|
|
2015-09-19 20:26:31 +03:00
|
|
|
if (mcerror != NULL)
|
|
|
|
{
|
|
|
|
lc_mc_search->error = MC_SEARCH_E_REGEX_COMPILE;
|
2016-04-27 10:26:38 +03:00
|
|
|
g_free (lc_mc_search->error_str);
|
2015-09-19 20:26:31 +03:00
|
|
|
lc_mc_search->error_str =
|
|
|
|
str_conv_gerror_message (mcerror, _("Regular expression error"));
|
|
|
|
g_error_free (mcerror);
|
|
|
|
return;
|
|
|
|
}
|
2009-07-07 12:11:29 +04:00
|
|
|
#else /* SEARCH_TYPE_GLIB */
|
2023-03-22 21:50:11 +03:00
|
|
|
|
|
|
|
#ifdef HAVE_PCRE2
|
|
|
|
int errcode;
|
|
|
|
char error[BUF_SMALL];
|
|
|
|
size_t erroffset;
|
|
|
|
int pcre_options = PCRE2_MULTILINE;
|
|
|
|
#else
|
2015-09-19 20:26:31 +03:00
|
|
|
const char *error;
|
|
|
|
int erroffset;
|
|
|
|
int pcre_options = PCRE_EXTRA | PCRE_MULTILINE;
|
2023-03-22 21:50:11 +03:00
|
|
|
#endif
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
|
2015-09-19 20:26:31 +03:00
|
|
|
if (str_isutf8 (charset) && mc_global.utf8_display)
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
{
|
2023-03-22 21:50:11 +03:00
|
|
|
#ifdef HAVE_PCRE2
|
|
|
|
pcre_options |= PCRE2_UTF;
|
|
|
|
if (!lc_mc_search->is_case_sensitive)
|
|
|
|
pcre_options |= PCRE2_CASELESS;
|
|
|
|
#else
|
2015-09-19 20:26:31 +03:00
|
|
|
pcre_options |= PCRE_UTF8;
|
|
|
|
if (!lc_mc_search->is_case_sensitive)
|
|
|
|
pcre_options |= PCRE_CASELESS;
|
2023-03-22 21:50:11 +03:00
|
|
|
#endif
|
2015-09-19 20:26:31 +03:00
|
|
|
}
|
2022-02-23 18:29:55 +03:00
|
|
|
else if (!lc_mc_search->is_case_sensitive)
|
2015-09-19 20:26:31 +03:00
|
|
|
{
|
2022-02-23 18:29:55 +03:00
|
|
|
GString *tmp;
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
|
2022-02-23 18:29:55 +03:00
|
|
|
tmp = mc_search_cond->str;
|
|
|
|
mc_search_cond->str = mc_search__cond_struct_new_regex_ci_str (charset, tmp);
|
|
|
|
g_string_free (tmp, TRUE);
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
}
|
|
|
|
|
2015-09-19 20:26:31 +03:00
|
|
|
mc_search_cond->regex_handle =
|
2023-03-22 21:50:11 +03:00
|
|
|
#ifdef HAVE_PCRE2
|
|
|
|
pcre2_compile ((unsigned char *) mc_search_cond->str->str, PCRE2_ZERO_TERMINATED,
|
|
|
|
pcre_options, &errcode, &erroffset, NULL);
|
|
|
|
#else
|
2015-09-19 20:26:31 +03:00
|
|
|
pcre_compile (mc_search_cond->str->str, pcre_options, &error, &erroffset, NULL);
|
2023-03-22 21:50:11 +03:00
|
|
|
#endif
|
2015-09-19 20:26:31 +03:00
|
|
|
if (mc_search_cond->regex_handle == NULL)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2023-03-22 21:50:11 +03:00
|
|
|
#ifdef HAVE_PCRE2
|
|
|
|
pcre2_get_error_message (errcode, (unsigned char *) error, sizeof (error));
|
|
|
|
#endif
|
2016-04-27 10:26:38 +03:00
|
|
|
mc_search_set_error (lc_mc_search, MC_SEARCH_E_REGEX_COMPILE, "%s", error);
|
2009-05-05 17:19:32 +04:00
|
|
|
return;
|
|
|
|
}
|
2023-03-22 21:50:11 +03:00
|
|
|
#ifdef HAVE_PCRE2
|
|
|
|
if (pcre2_jit_compile (mc_search_cond->regex_handle, PCRE2_JIT_COMPLETE) && *error != '\0')
|
|
|
|
#else
|
2015-09-19 20:26:31 +03:00
|
|
|
lc_mc_search->regex_match_info = pcre_study (mc_search_cond->regex_handle, 0, &error);
|
2016-04-27 10:26:38 +03:00
|
|
|
if (lc_mc_search->regex_match_info == NULL && error != NULL)
|
2023-03-22 21:50:11 +03:00
|
|
|
#endif
|
2015-09-19 20:26:31 +03:00
|
|
|
{
|
2016-04-27 10:26:38 +03:00
|
|
|
mc_search_set_error (lc_mc_search, MC_SEARCH_E_REGEX_COMPILE, "%s", error);
|
|
|
|
MC_PTR_FREE (mc_search_cond->regex_handle);
|
|
|
|
return;
|
2015-09-19 20:26:31 +03:00
|
|
|
}
|
2009-07-07 12:11:29 +04:00
|
|
|
#endif /* SEARCH_TYPE_GLIB */
|
2015-09-19 20:26:31 +03:00
|
|
|
}
|
|
|
|
|
2011-05-30 20:16:14 +04:00
|
|
|
lc_mc_search->is_utf8 = str_isutf8 (charset);
|
2009-04-25 12:09:47 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
gboolean
|
2024-06-01 21:12:14 +03:00
|
|
|
mc_search__run_regex (mc_search_t *lc_mc_search, const void *user_data,
|
|
|
|
gsize start_search, gsize end_search, gsize *found_len)
|
2009-04-25 12:09:47 +04:00
|
|
|
{
|
2016-04-29 14:52:33 +03:00
|
|
|
mc_search_cbret_t ret = MC_SEARCH_CB_NOTFOUND;
|
2009-06-25 13:53:34 +04:00
|
|
|
gsize current_pos, virtual_pos;
|
2009-04-25 12:09:47 +04:00
|
|
|
gint start_pos;
|
|
|
|
gint end_pos;
|
|
|
|
|
2009-10-30 04:12:04 +03:00
|
|
|
if (lc_mc_search->regex_buffer != NULL)
|
2016-05-01 08:56:03 +03:00
|
|
|
g_string_set_size (lc_mc_search->regex_buffer, 0);
|
|
|
|
else
|
|
|
|
lc_mc_search->regex_buffer = g_string_sized_new (64);
|
2009-04-25 12:09:47 +04:00
|
|
|
|
2009-06-25 13:53:34 +04:00
|
|
|
virtual_pos = current_pos = start_search;
|
2010-03-30 12:10:25 +04:00
|
|
|
while (virtual_pos <= end_search)
|
|
|
|
{
|
2009-10-30 04:12:04 +03:00
|
|
|
g_string_set_size (lc_mc_search->regex_buffer, 0);
|
|
|
|
lc_mc_search->start_buffer = current_pos;
|
2009-04-25 12:09:47 +04:00
|
|
|
|
2013-08-09 09:22:24 +04:00
|
|
|
if (lc_mc_search->search_fn != NULL)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2013-11-13 10:43:26 +04:00
|
|
|
while (TRUE)
|
2013-08-09 09:22:24 +04:00
|
|
|
{
|
2023-01-15 16:08:08 +03:00
|
|
|
int current_chr = '\n'; /* stop search symbol */
|
2009-04-25 12:09:47 +04:00
|
|
|
|
2013-08-09 09:22:24 +04:00
|
|
|
ret = lc_mc_search->search_fn (user_data, current_pos, ¤t_chr);
|
2011-07-16 01:32:27 +04:00
|
|
|
|
2013-08-09 09:22:24 +04:00
|
|
|
if (ret == MC_SEARCH_CB_ABORT)
|
|
|
|
break;
|
2009-06-25 13:53:34 +04:00
|
|
|
|
2013-08-09 09:22:24 +04:00
|
|
|
if (ret == MC_SEARCH_CB_INVALID)
|
|
|
|
continue;
|
2009-06-25 13:53:34 +04:00
|
|
|
|
2013-08-09 09:22:24 +04:00
|
|
|
current_pos++;
|
2009-06-25 13:53:34 +04:00
|
|
|
|
2013-08-09 09:22:24 +04:00
|
|
|
if (ret == MC_SEARCH_CB_SKIP)
|
|
|
|
continue;
|
2009-04-25 12:09:47 +04:00
|
|
|
|
2013-08-09 09:22:24 +04:00
|
|
|
virtual_pos++;
|
|
|
|
|
|
|
|
g_string_append_c (lc_mc_search->regex_buffer, (char) current_chr);
|
2013-11-13 10:43:26 +04:00
|
|
|
|
2023-01-15 16:08:08 +03:00
|
|
|
if ((char) current_chr == '\n' || virtual_pos > end_search)
|
2013-11-13 10:43:26 +04:00
|
|
|
break;
|
2013-08-09 09:22:24 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* optimization for standard case (for search from file manager)
|
|
|
|
* where there is no MC_SEARCH_CB_INVALID or MC_SEARCH_CB_SKIP
|
|
|
|
* return codes, so we can copy line at regex buffer all at once
|
|
|
|
*/
|
2013-11-13 10:43:26 +04:00
|
|
|
while (TRUE)
|
2013-08-09 09:22:24 +04:00
|
|
|
{
|
2016-02-20 12:02:59 +03:00
|
|
|
const char current_chr = ((const char *) user_data)[current_pos];
|
2013-11-13 10:43:26 +04:00
|
|
|
|
2013-08-09 09:22:24 +04:00
|
|
|
if (current_chr == '\0')
|
|
|
|
break;
|
|
|
|
|
|
|
|
current_pos++;
|
2013-11-13 10:43:26 +04:00
|
|
|
|
2023-01-15 16:08:08 +03:00
|
|
|
if (current_chr == '\n' || current_pos > end_search)
|
2013-11-13 10:43:26 +04:00
|
|
|
break;
|
2013-08-09 09:22:24 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* use virtual_pos as index of start of current chunk */
|
2016-02-20 12:02:59 +03:00
|
|
|
g_string_append_len (lc_mc_search->regex_buffer, (const char *) user_data + virtual_pos,
|
2013-08-09 09:22:24 +04:00
|
|
|
current_pos - virtual_pos);
|
|
|
|
virtual_pos = current_pos;
|
2009-04-25 12:09:47 +04:00
|
|
|
}
|
2012-04-29 16:13:21 +04:00
|
|
|
|
2010-03-30 12:10:25 +04:00
|
|
|
switch (mc_search__regex_found_cond (lc_mc_search, lc_mc_search->regex_buffer))
|
|
|
|
{
|
2009-04-25 12:09:47 +04:00
|
|
|
case COND__FOUND_OK:
|
2009-07-07 12:11:29 +04:00
|
|
|
#ifdef SEARCH_TYPE_GLIB
|
2015-09-19 18:24:07 +03:00
|
|
|
g_match_info_fetch_pos (lc_mc_search->regex_match_info, 0, &start_pos, &end_pos);
|
2009-07-07 12:11:29 +04:00
|
|
|
#else /* SEARCH_TYPE_GLIB */
|
2015-09-19 18:24:07 +03:00
|
|
|
start_pos = lc_mc_search->iovector[0];
|
|
|
|
end_pos = lc_mc_search->iovector[1];
|
2009-07-07 12:11:29 +04:00
|
|
|
#endif /* SEARCH_TYPE_GLIB */
|
2012-04-29 16:13:21 +04:00
|
|
|
if (found_len != NULL)
|
2009-05-06 17:32:13 +04:00
|
|
|
*found_len = end_pos - start_pos;
|
2009-10-30 04:12:04 +03:00
|
|
|
lc_mc_search->normal_offset = lc_mc_search->start_buffer + start_pos;
|
2009-04-25 12:09:47 +04:00
|
|
|
return TRUE;
|
|
|
|
case COND__NOT_ALL_FOUND:
|
|
|
|
break;
|
|
|
|
default:
|
2009-10-30 04:12:04 +03:00
|
|
|
g_string_free (lc_mc_search->regex_buffer, TRUE);
|
|
|
|
lc_mc_search->regex_buffer = NULL;
|
2009-04-25 12:09:47 +04:00
|
|
|
return FALSE;
|
|
|
|
}
|
2012-04-29 16:13:21 +04:00
|
|
|
|
2010-03-30 12:10:25 +04:00
|
|
|
if ((lc_mc_search->update_fn != NULL) &&
|
|
|
|
((lc_mc_search->update_fn) (user_data, current_pos) == MC_SEARCH_CB_ABORT))
|
2012-04-29 16:13:21 +04:00
|
|
|
ret = MC_SEARCH_CB_ABORT;
|
2009-12-14 12:01:28 +03:00
|
|
|
|
2016-04-29 14:52:33 +03:00
|
|
|
if (ret == MC_SEARCH_CB_ABORT || ret == MC_SEARCH_CB_NOTFOUND)
|
2009-06-25 13:53:34 +04:00
|
|
|
break;
|
2009-04-25 12:09:47 +04:00
|
|
|
}
|
2012-04-29 16:13:21 +04:00
|
|
|
|
2009-10-30 04:12:04 +03:00
|
|
|
g_string_free (lc_mc_search->regex_buffer, TRUE);
|
|
|
|
lc_mc_search->regex_buffer = NULL;
|
2009-12-14 12:01:28 +03:00
|
|
|
|
2016-05-02 16:04:37 +03:00
|
|
|
MC_PTR_FREE (lc_mc_search->error_str);
|
|
|
|
lc_mc_search->error = ret == MC_SEARCH_CB_ABORT ? MC_SEARCH_E_ABORT : MC_SEARCH_E_NOTFOUND;
|
2009-12-14 12:01:28 +03:00
|
|
|
|
2009-04-25 12:09:47 +04:00
|
|
|
return FALSE;
|
|
|
|
}
|
2009-04-29 19:45:21 +04:00
|
|
|
|
|
|
|
/* --------------------------------------------------------------------------------------------- */
|
2010-11-08 21:50:15 +03:00
|
|
|
|
2009-04-29 19:45:21 +04:00
|
|
|
GString *
|
2024-06-01 21:12:14 +03:00
|
|
|
mc_search_regex_prepare_replace_str (mc_search_t *lc_mc_search, GString *replace_str)
|
2009-04-29 19:45:21 +04:00
|
|
|
{
|
|
|
|
GString *ret;
|
|
|
|
|
2013-10-15 10:34:04 +04:00
|
|
|
int num_replace_tokens;
|
2009-05-05 17:19:32 +04:00
|
|
|
gsize loop;
|
2015-01-07 09:52:24 +03:00
|
|
|
gsize prev = 0;
|
2009-06-08 14:54:35 +04:00
|
|
|
replace_transform_type_t replace_flags = REPLACE_T_NO_TRANSFORM;
|
2009-05-05 17:19:32 +04:00
|
|
|
|
|
|
|
num_replace_tokens =
|
2009-06-08 18:41:20 +04:00
|
|
|
mc_search_regex__get_max_num_of_replace_tokens (replace_str->str, replace_str->len);
|
2009-05-05 17:19:32 +04:00
|
|
|
|
2010-03-31 11:48:53 +04:00
|
|
|
if (lc_mc_search->num_results < 0)
|
2021-02-28 18:31:30 +03:00
|
|
|
return mc_g_string_dup (replace_str);
|
2009-05-05 17:19:32 +04:00
|
|
|
|
2010-03-31 11:48:53 +04:00
|
|
|
if (num_replace_tokens > lc_mc_search->num_results - 1
|
2010-03-30 12:10:25 +04:00
|
|
|
|| num_replace_tokens > MC_SEARCH__NUM_REPLACE_ARGS)
|
|
|
|
{
|
2016-04-27 10:26:38 +03:00
|
|
|
mc_search_set_error (lc_mc_search, MC_SEARCH_E_REGEX_REPLACE, "%s",
|
|
|
|
_(STR_E_RPL_NOT_EQ_TO_FOUND));
|
2009-05-05 17:19:32 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-10-21 17:18:18 +04:00
|
|
|
ret = g_string_sized_new (64);
|
|
|
|
|
2010-03-30 12:10:25 +04:00
|
|
|
for (loop = 0; loop < replace_str->len - 1; loop++)
|
|
|
|
{
|
2013-10-15 10:34:04 +04:00
|
|
|
int lc_index;
|
2014-12-30 16:21:55 +03:00
|
|
|
gchar *tmp_str;
|
2015-01-07 09:52:24 +03:00
|
|
|
gsize len = 0;
|
2013-10-15 10:34:04 +04:00
|
|
|
|
2009-10-30 04:12:04 +03:00
|
|
|
lc_index = mc_search_regex__process_replace_str (replace_str, loop, &len, &replace_flags);
|
2009-06-02 13:09:16 +04:00
|
|
|
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
if (lc_index == REPLACE_PREPARE_T_NOTHING_SPECIAL)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
|
|
|
if (len != 0)
|
|
|
|
{
|
2015-01-07 09:52:24 +03:00
|
|
|
mc_search_regex__process_append_str (ret, replace_str->str + prev, loop - prev,
|
2009-06-12 18:10:38 +04:00
|
|
|
&replace_flags);
|
|
|
|
mc_search_regex__process_append_str (ret, replace_str->str + loop + 1, len - 1,
|
|
|
|
&replace_flags);
|
2015-01-07 09:52:24 +03:00
|
|
|
prev = loop + len;
|
|
|
|
loop = prev - 1; /* prepare to loop++ */
|
2009-06-10 16:30:09 +04:00
|
|
|
}
|
2015-01-07 09:52:24 +03:00
|
|
|
|
2009-06-02 13:09:16 +04:00
|
|
|
continue;
|
2009-06-10 16:30:09 +04:00
|
|
|
}
|
2009-06-02 13:09:16 +04:00
|
|
|
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
if (lc_index == REPLACE_PREPARE_T_REPLACE_FLAG)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2015-01-07 09:52:24 +03:00
|
|
|
if (loop != 0)
|
|
|
|
mc_search_regex__process_append_str (ret, replace_str->str + prev, loop - prev,
|
2009-06-08 14:54:35 +04:00
|
|
|
&replace_flags);
|
2015-01-07 09:52:24 +03:00
|
|
|
prev = loop + len;
|
|
|
|
loop = prev - 1; /* prepare to loop++ */
|
2009-06-08 14:54:35 +04:00
|
|
|
continue;
|
|
|
|
}
|
2009-06-02 13:09:16 +04:00
|
|
|
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
/* escape sequence */
|
|
|
|
if (lc_index == REPLACE_PREPARE_T_ESCAPE_SEQ)
|
|
|
|
{
|
2015-01-07 09:52:24 +03:00
|
|
|
mc_search_regex__process_append_str (ret, replace_str->str + prev, loop - prev,
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
&replace_flags);
|
|
|
|
/* call process_escape_sequence without starting '\\' */
|
|
|
|
mc_search_regex__process_escape_sequence (ret, replace_str->str + loop + 1, len - 1,
|
2011-05-30 20:16:14 +04:00
|
|
|
&replace_flags, lc_mc_search->is_utf8);
|
2015-01-07 09:52:24 +03:00
|
|
|
prev = loop + len;
|
|
|
|
loop = prev - 1; /* prepare to loop++ */
|
Ticket #1882: PCRE search: escape sequence support in replacements, UTF8 support (just a flag for libPCRE)
Enables use of escape sequences inside regex replace strings,
Enables UTF-8 caseless search in PCRE.
Supported escape sequences: \DEC, \xHEX, \0OCT, \n, \t, \v,
\b, \r, \f, \a. Any of them could be enclosed into \{}.
Signed-off-by: Slava Zanko <slavazanko@gmail.com>
2011-04-05 13:15:39 +04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* invalid capture buffer number */
|
2010-03-31 11:48:53 +04:00
|
|
|
if (lc_index > lc_mc_search->num_results)
|
2010-03-30 12:10:25 +04:00
|
|
|
{
|
2009-06-05 12:51:12 +04:00
|
|
|
g_string_free (ret, TRUE);
|
2016-04-27 10:26:38 +03:00
|
|
|
mc_search_set_error (lc_mc_search, MC_SEARCH_E_REGEX_REPLACE,
|
|
|
|
_(STR_E_RPL_INVALID_TOKEN), lc_index);
|
2009-06-05 12:51:12 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
2009-05-05 17:19:32 +04:00
|
|
|
|
2009-10-30 04:12:04 +03:00
|
|
|
tmp_str = mc_search_regex__get_token_by_num (lc_mc_search, lc_index);
|
2009-06-08 14:54:35 +04:00
|
|
|
|
2015-01-07 09:52:24 +03:00
|
|
|
if (loop != 0)
|
|
|
|
mc_search_regex__process_append_str (ret, replace_str->str + prev, loop - prev,
|
2009-06-08 14:54:35 +04:00
|
|
|
&replace_flags);
|
|
|
|
|
|
|
|
mc_search_regex__process_append_str (ret, tmp_str, -1, &replace_flags);
|
|
|
|
g_free (tmp_str);
|
2015-01-07 09:52:24 +03:00
|
|
|
|
|
|
|
prev = loop + len;
|
|
|
|
loop = prev - 1; /* prepare to loop++ */
|
2009-05-05 17:19:32 +04:00
|
|
|
}
|
2015-01-07 09:52:24 +03:00
|
|
|
|
|
|
|
mc_search_regex__process_append_str (ret, replace_str->str + prev, replace_str->len - prev,
|
2009-06-08 14:54:35 +04:00
|
|
|
&replace_flags);
|
2009-05-05 17:19:32 +04:00
|
|
|
|
|
|
|
return ret;
|
2009-04-29 19:45:21 +04:00
|
|
|
}
|