diff --git a/librz/core/cmd_descs/cmd_descs.c b/librz/core/cmd_descs/cmd_descs.c index 81899c51402..a60191945e2 100644 --- a/librz/core/cmd_descs/cmd_descs.c +++ b/librz/core/cmd_descs/cmd_descs.c @@ -2901,6 +2901,7 @@ static const RzCmdDescDetailEntry slash_z_Examples_detail_entries[] = { { .text = "/z", .arg_str = " (ABC*)D li", .comment = "Search the exact string \"(ABC*)D\" but case insensitive." }, { .text = "/z", .arg_str = " \\\\d\\\\sC*\\\\w ri", .comment = "Search the regular expression \"\\d\\sC*\\w\" but case insensitive." }, { .text = "/z", .arg_str = " \"и.{3}м\" ei", .comment = "Search the extended regular expression \"и.{3}м\" but case insensitive." }, + { .text = "/z", .arg_str = " \"(*LF).+\" r ascii", .comment = "Search any ascii string with line feed is a newline." }, { 0 }, }; static const RzCmdDescDetail slash_z_details[] = { diff --git a/librz/core/cmd_descs/cmd_search.yaml b/librz/core/cmd_descs/cmd_search.yaml index 600025394d0..2539b99e7ee 100644 --- a/librz/core/cmd_descs/cmd_search.yaml +++ b/librz/core/cmd_descs/cmd_search.yaml @@ -1132,6 +1132,9 @@ commands: - text: "/z" arg_str: " \"и.{3}м\" ei" comment: "Search the extended regular expression \"и.{3}м\" but case insensitive." + - text: "/z" + arg_str: " \"(*LF).+\" r ascii" + comment: "Search any ascii string with line feed is a newline." subcommands: - name: "/z" summary: String search. diff --git a/librz/include/rz_util/rz_regex.h b/librz/include/rz_util/rz_regex.h index e87080e557d..cd30bb5bbbf 100644 --- a/librz/include/rz_util/rz_regex.h +++ b/librz/include/rz_util/rz_regex.h @@ -80,6 +80,7 @@ typedef struct { RzRegex32 *re32; }; void *jit_stack; ///< The JIT stack for this pattern. Must be used only by one thread at a time. + RzRegexCompContext *ccontext; } RzRegexMulti; typedef struct { @@ -106,7 +107,7 @@ RZ_API RZ_OWN RzRegex16 *rz_regex_new_16(RZ_NONNULL const char *pattern, RzRegex RZ_API RZ_OWN RzRegex32 *rz_regex_new_32(RZ_NONNULL const char *pattern, RzRegexFlags cflags, RzRegexFlags jflags, RzRegexCompContext *ccontext); RZ_API RZ_OWN RzRegexMulti *rz_regex_new_multi(RZ_NONNULL const char *pattern, RzRegexFlags cflags, RzRegexFlags jflags, - RzRegexCompContext *ccontext, RzRegexType type); + RzRegexType type); RZ_API RZ_OWN RzRegex *rz_regex_new_bytes(RZ_NONNULL const ut8 *pattern, size_t pattern_len, RzRegexFlags cflags, RzRegexFlags jflags, RzRegexCompContext *ccontext); RZ_API void rz_regex_free(RZ_OWN RzRegex *regex); diff --git a/librz/search/string_search.c b/librz/search/string_search.c index 5291dd77c85..fd6d39e3283 100644 --- a/librz/search/string_search.c +++ b/librz/search/string_search.c @@ -422,19 +422,19 @@ static RzDetectedString *setup_str_regex(const char *re_pattern, RzRegexFlags cf return NULL; case RZ_STRING_ENC_UTF8: case RZ_STRING_ENC_8BIT: - re = rz_regex_new_multi(re_pattern, cflags, RZ_REGEX_DEFAULT, NULL, RZ_REGEX_UTF8); + re = rz_regex_new_multi(re_pattern, cflags, RZ_REGEX_DEFAULT, RZ_REGEX_UTF8); break; case RZ_STRING_ENC_UTF16LE: case RZ_STRING_ENC_UTF16BE: - re = rz_regex_new_multi(re_pattern, cflags, RZ_REGEX_DEFAULT, NULL, RZ_REGEX_UTF16); + re = rz_regex_new_multi(re_pattern, cflags, RZ_REGEX_DEFAULT, RZ_REGEX_UTF16); break; case RZ_STRING_ENC_UTF32LE: case RZ_STRING_ENC_UTF32BE: - re = rz_regex_new_multi(re_pattern, cflags, RZ_REGEX_DEFAULT, NULL, RZ_REGEX_UTF32); + re = rz_regex_new_multi(re_pattern, cflags, RZ_REGEX_DEFAULT, RZ_REGEX_UTF32); break; } } else { - re = rz_regex_new_multi(re_pattern, cflags, RZ_REGEX_DEFAULT, NULL, RZ_REGEX_UTF8); + re = rz_regex_new_multi(re_pattern, cflags, RZ_REGEX_DEFAULT, RZ_REGEX_UTF8); } if (!re) { RZ_LOG_ERROR("Failed to compile regex pattern: '%s'\n", re_pattern); diff --git a/librz/util/regex.c b/librz/util/regex.c index 0abc5c4e9c4..f5687c39ceb 100644 --- a/librz/util/regex.c +++ b/librz/util/regex.c @@ -227,6 +227,7 @@ RZ_API RZ_OWN RzRegex32 *rz_regex_new_32(RZ_NONNULL const char *pattern, RzRegex * \brief Compile an Regex pattern of \p type. * * NOTE: The pattern and matching will always be in the host's endianness. + * NOTE: The patterns are compiled with PCRE2_NEWLINE_NUL. * * \param pattern The regex pattern string. It must be an UTF-8 encoded string. * \param cflags The compilation flags or zero for default. @@ -234,13 +235,11 @@ RZ_API RZ_OWN RzRegex32 *rz_regex_new_32(RZ_NONNULL const char *pattern, RzRegex * \param jflags The compilation flags for the JIT compiler. * You can pass RZ_REGEX_JIT_PARTIAL_SOFT or RZ_REGEX_JIT_PARTIAL_HARD if you * intend to use the pattern for partial matching. Otherwise set it to RZ_REGEX_DEFAULT. - * \param ccontext A compile context or NULL. * \param type The string encoding type the pattern should match. * * \return The compiled regex or NULL in case of failure. */ -RZ_API RZ_OWN RzRegexMulti *rz_regex_new_multi(RZ_NONNULL const char *pattern, RzRegexFlags cflags, RzRegexFlags jflags, - RzRegexCompContext *ccontext, RzRegexType type) { +RZ_API RZ_OWN RzRegexMulti *rz_regex_new_multi(RZ_NONNULL const char *pattern, RzRegexFlags cflags, RzRegexFlags jflags, RzRegexType type) { RzRegexMulti *re = RZ_NEW0(RzRegexMulti); if (!re) { return NULL; @@ -255,16 +254,28 @@ RZ_API RZ_OWN RzRegexMulti *rz_regex_new_multi(RZ_NONNULL const char *pattern, R rz_warn_if_reached(); free(re); return NULL; - case RZ_REGEX_UTF8: + case RZ_REGEX_UTF8: { + RzRegexCompContext *ccontext = pcre2_compile_context_create_8(NULL); + pcre2_set_newline_8(ccontext, PCRE2_NEWLINE_NUL); re->re8 = rz_regex_new(pattern, cflags, jflags, ccontext); + re->ccontext = ccontext; break; - case RZ_REGEX_UTF16: + } + case RZ_REGEX_UTF16: { + RzRegexCompContext *ccontext = pcre2_compile_context_create_16(NULL); + pcre2_set_newline_16(ccontext, PCRE2_NEWLINE_NUL); re->re16 = rz_regex_new_16(pattern, cflags, jflags, ccontext); + re->ccontext = ccontext; break; - case RZ_REGEX_UTF32: + } + case RZ_REGEX_UTF32: { + RzRegexCompContext *ccontext = pcre2_compile_context_create_32(NULL); + pcre2_set_newline_32(ccontext, PCRE2_NEWLINE_NUL); re->re32 = rz_regex_new_32(pattern, cflags, jflags, ccontext); + re->ccontext = ccontext; break; } + } if (!re->re8 && !re->re16 && !re->re32) { free(re); return NULL; @@ -457,12 +468,15 @@ RZ_API void rz_regex_free_multi(RZ_NULLABLE RZ_OWN RzRegexMulti *regex_multi) { switch (regex_multi->re_type) { case RZ_REGEX_UTF8: rz_regex_free(regex_multi->re8); + pcre2_compile_context_free_8(regex_multi->ccontext); break; case RZ_REGEX_UTF16: rz_regex_free_16(regex_multi->re16); + pcre2_compile_context_free_16(regex_multi->ccontext); break; case RZ_REGEX_UTF32: rz_regex_free_32(regex_multi->re32); + pcre2_compile_context_free_32(regex_multi->ccontext); break; } #ifdef SUPPORTS_PCRE2_JIT @@ -1458,6 +1472,14 @@ RZ_API RzRegexFlags rz_regex_parse_flag_desc(RZ_NULLABLE const char *re_flags_de flags |= RZ_REGEX_LITERAL; goto return_flags; } + if (strchr(re_flags_desc, 'd')) { + fcount++; + flags |= RZ_REGEX_DOTALL; + } + if (strchr(re_flags_desc, 'm')) { + fcount++; + flags |= RZ_REGEX_MULTILINE; + } if (strchr(re_flags_desc, 'r')) { fcount++; goto return_flags; @@ -1470,14 +1492,6 @@ RZ_API RzRegexFlags rz_regex_parse_flag_desc(RZ_NULLABLE const char *re_flags_de fcount++; flags |= RZ_REGEX_EXTENDED_MORE; } - if (strchr(re_flags_desc, 'm')) { - fcount++; - flags |= RZ_REGEX_MULTILINE; - } - if (strchr(re_flags_desc, 'd')) { - fcount++; - flags |= RZ_REGEX_DOTALL; - } return_flags: if (fcount != strlen(re_flags_desc)) { RZ_LOG_ERROR("Flag combination '%s' is invalid.\n", re_flags_desc); diff --git a/test/db/cmd/cmd_help b/test/db/cmd/cmd_help index 0c15c9b3f69..c41218099a7 100644 --- a/test/db/cmd/cmd_help +++ b/test/db/cmd/cmd_help @@ -299,11 +299,11 @@ e scr.columns=70 /z??~:-6.. EOF EXPECT=<