240709.1 · 148290c57acccc914dfe9ab1b42760961a09c918
released 6.2.0
fix #407 fix #408 update #409
reading declarations
@@ -1616,12 +1616,11 @@ same line, like XOR: ### Search this but not that with -v, -e, -N, -f, -L, -w, -x -e PATTERN, --regexp=PATTERN- Specify a PATTERN used during the search of the input: an input- line is selected if it matches any of the specified patterns.- Note that longer patterns take precedence over shorter patterns.- This option is most useful when multiple -e options are used to- specify multiple patterns, when a pattern begins with a dash (`-'),- to specify a pattern after option -f or after the FILE arguments.+ Specify a PATTERN to search the input. An input line is selected+ if it matches any of the specified patterns. This option is useful+ when multiple -e options are used to specify multiple patterns, or+ when a pattern begins with a dash (`-'), or to specify a pattern+ after option -f or after the FILE arguments. -f FILE, --file=FILE Read newline-separated patterns from FILE. White space in patterns is significant. Empty lines in FILE are ignored. If FILE does not@@ -4189,11 +4188,10 @@ in markdown: -e PATTERN, --regexp=PATTERN Specify a PATTERN to search the input. An input line is selected- if it matches any of the specified patterns. Note that longer- patterns take precedence over shorter patterns. This option is- most useful when multiple -e options are used to specify multiple- patterns, when a pattern begins with a dash (`-'), to specify a- pattern after option -f or after the FILE arguments.+ if it matches any of the specified patterns. This option is+ useful when multiple -e options are used to specify multiple+ patterns, or when a pattern begins with a dash (`-'), or to+ specify a pattern after option -f or after the FILE arguments. --encoding=ENCODING The encoding format of the input. The default ENCODING is binary@@ -5297,7 +5295,7 @@ in markdown: $ ugrep -e FIXME -f cpp/zap_strings myfile.cpp - Find lines with `FIXME' or `TODO', showing line numberes:+ Find lines with `FIXME' or `TODO', showing line numbers: $ ugrep -n -e FIXME -e TODO myfile.cpp @@ -5380,7 +5378,7 @@ in markdown: $ ugrep --help fuzzy COPYRIGHT- Copyright (c) 2021-2024 Robert A. van Engelen <engelen@acm.org>+ Copyright (c) 2021,2024 Robert A. van Engelen <engelen@acm.org> ugrep is released under the BSD-3 license. All parts of the software have reasonable copyright terms permitting free redistribution. This@@ -5394,7 +5392,7 @@ in markdown: - ugrep 6.1.0 June 3, 2024 UGREP(1)+ ugrep 6.2.0 July 9, 2024 UGREP(1) 🔝 [Back to table of contents](#toc)
@@ -1,6 +1,5 @@-Binaries for Windows 32-bit and 64-bit ugrep.exe are included in the-repository: building ugrep on Windows takes some serious effort to install and+Binaries for Windows 32-bit and 64-bit ugrep.exe and ugrep-indexer.exe are+included: building ugrep on Windows takes some serious effort to install and compile PCRE2 and all of the compression libraries together with ugrep with the-proper configuration settings of C++ dev tools.--Visual Studio ugrep.exe build instructions can be found in vs/ugrep/README.txt+proper configuration settings of C++ dev tools. Visual Studio ugrep.exe build+instructions can be found in vs/ugrep/README.txt
bin/linux_amd64/README.md
@@ -1,6 +0,0 @@-Linux x64 static executables-============================--The executables are statically build on Ubuntu for Linux x64.--The executables detect AVX2 automatically for optimized searching.
bin/linux_amd64/ugrep
bin/linux_amd64/ugrep-indexer
bin/linux_arm64/README.md
@@ -1,6 +0,0 @@-Linux AArch64 static executables-================================--The executables are statically build on Ubuntu for Linux AArch64.--The executables will not run on ARM supporting NEON only.
bin/linux_arm64/ugrep
bin/linux_arm64/ugrep-indexer
@@ -7,17 +7,17 @@ local matchers='(--extended-regexp --fixed-strings --basic-regexp --perl-regexp local arguments=( '(-e --regexp -f --file)1: :_guard "^-*" pattern' '*: :_files'-{-A,--after-context=-}'[Output NUM lines of trailing context after matching lines]'+{-A,--after-context=-}'[Output NUM lines of trailing context after matching lines]:NUM:( )' {-a,--text}'[Process a binary file as if it were text]' {--all,-@}'[Search all files except hidden: cancel previous file and directory search restrictions and cancel --ignore-binary and --ignore-files when specified]' '(1)*'--and'[Specify additional PATTERN that must match]' '(1)*'--andnot'[Combines --and --not]'-{-B,--before-context=-}'[Output NUM lines of leading context before matching lines]'+{-B,--before-context=-}'[Output NUM lines of leading context before matching lines]:NUM:( )' {-b,--byte-offset}'[The offset in bytes of a pattern match is displayed in front of the respective matched line]' --binary-files=-'[Controls searching and reporting pattern matches in binary files]' {--bool,-%,-%%}'[Specifies Boolean query patterns]' --break'[Adds a line break between results from different files]'-{-C,--context=-}'[Output NUM lines of leading and trailing context surrounding each matching line]'+{-C,--context=-}'[Output NUM lines of leading and trailing context surrounding each matching line]:NUM:( )' {-c,--count}'[Only a count of selected lines is written to standard output]' {--color,--colour}'[Mark up the matching text with the colors specified with option --colors or the GREP_COLOR or GREP_COLORS environment variable]' {--colors=-,--colours=-}'[Use COLORS to mark up text]'
@@ -7,17 +7,17 @@ local matchers='(--extended-regexp --fixed-strings --basic-regexp --perl-regexp local arguments=( '(-e --regexp -f --file)1: :_guard "^-*" pattern' '*: :_files'-{-A,--after-context=-}'[Output NUM lines of trailing context after matching lines]'+{-A,--after-context=-}'[Output NUM lines of trailing context after matching lines]:NUM:( )' {-a,--text}'[Process a binary file as if it were text]' {--all,-@}'[Search all files except hidden: cancel previous file and directory search restrictions and cancel --ignore-binary and --ignore-files when specified]' '(1)*'--and'[Specify additional PATTERN that must match]' '(1)*'--andnot'[Combines --and --not]'-{-B,--before-context=-}'[Output NUM lines of leading context before matching lines]'+{-B,--before-context=-}'[Output NUM lines of leading context before matching lines]:NUM:( )' {-b,--byte-offset}'[The offset in bytes of a pattern match is displayed in front of the respective matched line]' --binary-files=-'[Controls searching and reporting pattern matches in binary files]' {--bool,-%,-%%}'[Specifies Boolean query patterns]' --break'[Adds a line break between results from different files]'-{-C,--context=-}'[Output NUM lines of leading and trailing context surrounding each matching line]'+{-C,--context=-}'[Output NUM lines of leading and trailing context surrounding each matching line]:NUM:( )' {-c,--count}'[Only a count of selected lines is written to standard output]' {--color,--colour}'[Mark up the matching text with the colors specified with option --colors or the GREP_COLOR or GREP_COLORS environment variable]' {--colors=-,--colours=-}'[Use COLORS to mark up text]'
@@ -7,17 +7,17 @@ local matchers='(--extended-regexp --fixed-strings --basic-regexp --perl-regexp local arguments=( '(-e --regexp -f --file)1: :_guard "^-*" pattern' '*: :_files'-{-A,--after-context=-}'[Output NUM lines of trailing context after matching lines]'+{-A,--after-context=-}'[Output NUM lines of trailing context after matching lines]:NUM:( )' {-a,--text}'[Process a binary file as if it were text]' {--all,-@}'[Search all files except hidden: cancel previous file and directory search restrictions and cancel --ignore-binary and --ignore-files when specified]' '(1)*'--and'[Specify additional PATTERN that must match]' '(1)*'--andnot'[Combines --and --not]'-{-B,--before-context=-}'[Output NUM lines of leading context before matching lines]'+{-B,--before-context=-}'[Output NUM lines of leading context before matching lines]:NUM:( )' {-b,--byte-offset}'[The offset in bytes of a pattern match is displayed in front of the respective matched line]' --binary-files=-'[Controls searching and reporting pattern matches in binary files]' {--bool,-%,-%%}'[Specifies Boolean query patterns]' --break'[Adds a line break between results from different files]'-{-C,--context=-}'[Output NUM lines of leading and trailing context surrounding each matching line]'+{-C,--context=-}'[Output NUM lines of leading and trailing context surrounding each matching line]:NUM:( )' {-c,--count}'[Only a count of selected lines is written to standard output]' {--color,--colour}'[Mark up the matching text with the colors specified with option --colors or the GREP_COLOR or GREP_COLORS environment variable]' {--colors=-,--colours=-}'[Use COLORS to mark up text]'
@@ -7,17 +7,17 @@ local matchers='(--extended-regexp --fixed-strings --basic-regexp --perl-regexp local arguments=( '(-e --regexp -f --file)1: :_guard "^-*" pattern' '*: :_files'-{-A,--after-context=-}'[Output NUM lines of trailing context after matching lines]'+{-A,--after-context=-}'[Output NUM lines of trailing context after matching lines]:NUM:( )' {-a,--text}'[Process a binary file as if it were text]' {--all,-@}'[Search all files except hidden: cancel previous file and directory search restrictions and cancel --ignore-binary and --ignore-files when specified]' '(1)*'--and'[Specify additional PATTERN that must match]' '(1)*'--andnot'[Combines --and --not]'-{-B,--before-context=-}'[Output NUM lines of leading context before matching lines]'+{-B,--before-context=-}'[Output NUM lines of leading context before matching lines]:NUM:( )' {-b,--byte-offset}'[The offset in bytes of a pattern match is displayed in front of the respective matched line]' --binary-files=-'[Controls searching and reporting pattern matches in binary files]' {--bool,-%,-%%}'[Specifies Boolean query patterns]' --break'[Adds a line break between results from different files]'-{-C,--context=-}'[Output NUM lines of leading and trailing context surrounding each matching line]'+{-C,--context=-}'[Output NUM lines of leading and trailing context surrounding each matching line]:NUM:( )' {-c,--count}'[Only a count of selected lines is written to standard output]' {--color,--colour}'[Mark up the matching text with the colors specified with option --colors or the GREP_COLOR or GREP_COLORS environment variable]' {--colors=-,--colours=-}'[Use COLORS to mark up text]'
@@ -49,7 +49,7 @@ $UGREP --help 2>&1 \ | sed -E -e "s/ /'[/" -e "s/\.?$/\]/" \ | sed -E -e "s/--hexdump/--hexdump=-/" -e "s/--sort'/--sort=-'/" -e "s/-Z,--fuzzy/-Z-,--fuzzy=-/" \ | sed -E -e "/\{-D/s/$/:ACTION:(read skip)/" -e "/\{-d/s/$/:ACTION:(read recurse skip)/" \- | sed -E -e "/\{-g/s/$/:GLOB:( )/" -e "/\{-[eMN]/s/$/:PATTERN:( )/" -e "/\{-f/s/$/:FILE:_files/" -e "/\{-J/s/$/:NUM:( )/" -e "/\{-[Km]/s/$/:MIN,MAX:( )/" -e "/\{-O/s/$/:EXT:( )/" \+ | sed -E -e "/\{-g/s/$/:GLOB:( )/" -e "/\{-[eMN]/s/$/:PATTERN:( )/" -e "/\{-f/s/$/:FILE:_files/" -e "/\{-[ABCJ]/s/$/:NUM:( )/" -e "/\{-[Km]/s/$/:MIN,MAX:( )/" -e "/\{-O/s/$/:EXT:( )/" \ | sed -E -e "/\{-t/s/$/:TYPES:($TYPES)/" -e "/--encoding/s/$/:ENCODING:($ENCODING)/" \ | sed -E -e "/--hexdump/s/$/:NUM:(1a 2a 4ah 6ah 8ah 1aC1 2aC1 4ahC1 6ahC1 8ahC1)/" \ | sed -E -e "/\{-m/s/$/::(1 1, 1,10)/" \
@@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles.-# Generated by GNU Autoconf 2.72 for ugrep 6.1.0.+# Generated by GNU Autoconf 2.72 for ugrep 6.2.0. # # Report bugs to <https://github.com/Genivia/ugrep/issues>. #@@ -606,8 +606,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='ugrep' PACKAGE_TARNAME='ugrep'-PACKAGE_VERSION='6.1.0'-PACKAGE_STRING='ugrep 6.1.0'+PACKAGE_VERSION='6.2.0'+PACKAGE_STRING='ugrep 6.2.0' PACKAGE_BUGREPORT='https://github.com/Genivia/ugrep/issues' PACKAGE_URL='https://ugrep.com' @@ -1382,7 +1382,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF-'configure' configures ugrep 6.1.0 to adapt to many kinds of systems.+'configure' configures ugrep 6.2.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1453,7 +1453,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in- short | recursive ) echo "Configuration of ugrep 6.1.0:";;+ short | recursive ) echo "Configuration of ugrep 6.2.0:";; esac cat <<\_ACEOF @@ -1630,7 +1630,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF-ugrep configure 6.1.0+ugrep configure 6.2.0 generated by GNU Autoconf 2.72 Copyright (C) 2023 Free Software Foundation, Inc.@@ -2184,7 +2184,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by ugrep $as_me 6.1.0, which was+It was created by ugrep $as_me 6.2.0, which was generated by GNU Autoconf 2.72. Invocation command line was $ $0$ac_configure_args_raw@@ -3694,7 +3694,7 @@ fi # Define the identity of the package. PACKAGE='ugrep'- VERSION='6.1.0'+ VERSION='6.2.0' printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h@@ -11790,7 +11790,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log="-This file was extended by ugrep $as_me 6.1.0, which was+This file was extended by ugrep $as_me 6.2.0, which was generated by GNU Autoconf 2.72. Invocation command line was CONFIG_FILES = $CONFIG_FILES@@ -11863,7 +11863,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config='$ac_cs_config_escaped' ac_cs_version="\\-ugrep config.status 6.1.0+ugrep config.status 6.2.0 configured by $0, generated by GNU Autoconf 2.72, with options \\"\$ac_cs_config\\"
@@ -1,4 +1,4 @@-AC_INIT([ugrep],[6.1.0],[https://github.com/Genivia/ugrep/issues],[ugrep],[https://ugrep.com])+AC_INIT([ugrep],[6.2.0],[https://github.com/Genivia/ugrep/issues],[ugrep],[https://ugrep.com]) AM_INIT_AUTOMAKE([foreign subdir-objects dist-xz no-dist-gzip]) AC_CONFIG_HEADERS([config.h]) AC_COPYRIGHT([Copyright (C) 2019-2024 Robert van Engelen, Genivia Inc.])
@@ -355,28 +355,28 @@ class Pattern { return ams_; } /// Returns true when match is predicted, based on s[0..3..e-1] (e >= s + 4).- static inline bool predict_match(const Pred pmh[], const char *s, size_t n)+ inline bool predict_match(const char *s, size_t n) const { Hash h = static_cast<uint8_t>(*s);- Pred f = pmh[h] & 1;+ Pred f = pmh_[h] & 1; h = hash(h, static_cast<uint8_t>(*++s));- f |= pmh[h] & 2;+ f |= pmh_[h] & 2; h = hash(h, static_cast<uint8_t>(*++s));- f |= pmh[h] & 4;+ f |= pmh_[h] & 4; h = hash(h, static_cast<uint8_t>(*++s));- f |= pmh[h] & 8;+ f |= pmh_[h] & 8; const char *e = s + n - 3; Pred m = 16; while (f == 0 && ++s < e) { h = hash(h, static_cast<uint8_t>(*s));- f = pmh[h] & m;+ f = pmh_[h] & m; m <<= 1; } return f == 0; }- /// Returns zero when match is predicted (removed shift distance return, now just returns 0 or 1).- static inline size_t predict_match(const Pred pma[], const char *s)+ /// Returns true when match is predicted using my PM4 logic.+ inline bool predict_match(const char *s) const { uint8_t b0 = s[0]; uint8_t b1 = s[1];@@ -385,13 +385,9 @@ class Pattern { Hash h1 = hash(b0, b1); Hash h2 = hash(h1, b2); Hash h3 = hash(h2, b3);- Pred a0 = pma[b0];- Pred a1 = pma[h1];- Pred a2 = pma[h2];- Pred a3 = pma[h3];- Pred p = (a0 & 0xc0) | (a1 & 0x30) | (a2 & 0x0c) | (a3 & 0x03);+ Pred p = (pma_[b0] & 0xc0) | (pma_[h1] & 0x30) | (pma_[h2] & 0x0c) | (pma_[h3] & 0x03); Pred m = ((((((p >> 2) | p) >> 2) | p) >> 1) | p);- return m == 0xff;+ return m != 0xff; } /// Relative frequency of English letters with upper/lower-case ratio = 0.0563, punctuation and UTF-8 bytes. static uint8_t frequency(uint8_t c)
@@ -50,7 +50,7 @@ class PCRE2Matcher : public PatternMatcher<std::string> { template<typename T> static std::string convert(T regex, convert_flag_type flags = convert_flag::none, bool *multiline = NULL) {- return reflex::convert(regex, "imPRsx!#<>=&|'(0123456789*:abcdefghnrstvwxzABCDGHKNQRSVWXZ0123456789?+", flags, multiline);+ return reflex::convert(regex, "iJmnPRsUx!#<>=&|'(0123456789*:abcdefghnrstvwxzABCDGHKNQRSVWXZ0123456789?+", flags, multiline); } /// Default constructor. PCRE2Matcher()@@ -465,7 +465,7 @@ class PCRE2UTFMatcher : public PCRE2Matcher { template<typename T> static std::string convert(T regex, convert_flag_type flags = convert_flag::none, bool *multiline = NULL) {- return reflex::convert(regex, "imPRsx!#<>=&|'(0123456789*:abcdefghknprstvwxzABCDGHKNPQRSVWXZ0123456789?+", flags, multiline);+ return reflex::convert(regex, "iJmnPRsUx!#<>=&|'(0123456789*:abcdefghknprstvwxzABCDGHKNPQRSVWXZ0123456789?+", flags, multiline); } /// Default constructor. PCRE2UTFMatcher() : PCRE2Matcher()
@@ -60,7 +60,9 @@ #ifdef _MSC_VER # define cpuidex __cpuidex #else-# include <cpuid.h>+# ifndef __cpuid_count+# include <cpuid.h>+# endif # define cpuidex(CPUInfo, id, subid) __cpuid_count(id, subid, CPUInfo[0], CPUInfo[1], CPUInfo[2], CPUInfo[3]) #endif
@@ -69,13 +69,16 @@ std::string regex_error::regex_error_message_code(regex_error_type code, const c std::string regex_error::regex_error_message(const char *message, const char *pattern, size_t pos) {+ const char *p = strrchr(pattern, '\n');+ if (p != NULL)+ pattern = p + 1; size_t l = strlen(pattern); if (pos > l) pos = l; l = strlen(message); size_t n = pos / 40; size_t k = pos % 40 + (n == 0 ? 0 : 20);- const char *p = n == 0 ? pattern : pattern + 40 * n - 20;+ p = n == 0 ? pattern : pattern + 40 * n - 20; while (p > pattern && (*p & 0xc0) == 0x80) { --p;
@@ -28,7 +28,7 @@ /** @file input.cpp-@brief RE/flex input character sequence class and simd.h CPUID check+@brief RE/flex input character sequence class @author Robert van Engelen - engelen@genivia.com @copyright (c) 2016-2020, Robert van Engelen, Genivia Inc. All rights reserved. @copyright (c) BSD-3 License - see LICENSE.txt
@@ -886,7 +886,6 @@ bool Matcher::advance_none(size_t) /// My "needle search" method when pin=1 bool Matcher::advance_pattern_pin1_pma(size_t loc) {- const Pattern::Pred *pma = pat_->pma_; const char *chr = pat_->chr_; size_t min = pat_->min_; uint16_t lcp = pat_->lcp_;@@ -909,7 +908,7 @@ bool Matcher::advance_pattern_pin1_pma(size_t loc) { uint32_t offset = ctz(mask); loc = s - lcp + offset - buf_;- if (loc + 4 > end_ || Pattern::predict_match(pma, &buf_[loc]) == 0)+ if (loc + 4 > end_ || pat_->predict_match(&buf_[loc])) { set_current(loc); return true;@@ -949,7 +948,7 @@ bool Matcher::advance_pattern_pin1_pma(size_t loc) if ((mask & 0xff)) { loc = s - lcp + i - buf_;- if (loc + 4 > end_ || Pattern::predict_match(pma, &buf_[loc]) == 0)+ if (loc + 4 > end_ || pat_->predict_match(&buf_[loc])) { set_current(loc); return true;@@ -966,7 +965,7 @@ bool Matcher::advance_pattern_pin1_pma(size_t loc) if ((mask & 0xff)) { loc = s - lcp + i - buf_;- if (loc + 4 > end_ || Pattern::predict_match(pma, &buf_[loc]) == 0)+ if (loc + 4 > end_ || pat_->predict_match(&buf_[loc])) { set_current(loc); return true;@@ -997,7 +996,7 @@ bool Matcher::advance_pattern_pin1_pma(size_t loc) { s -= lcp; loc = s - buf_;- if (s > e - 4 || (s[lcs] == chr1 && Pattern::predict_match(pma, s) == 0))+ if (s > e - 4 || (s[lcs] == chr1 && pat_->predict_match(s))) { set_current(loc); return true;@@ -1018,7 +1017,6 @@ bool Matcher::advance_pattern_pin1_pma(size_t loc) /// My "needle search" method when pin=1 bool Matcher::advance_pattern_pin1_pmh(size_t loc) {- const Pattern::Pred *pmh = pat_->pmh_; const char *chr = pat_->chr_; size_t min = pat_->min_; uint16_t lcp = pat_->lcp_;@@ -1041,7 +1039,7 @@ bool Matcher::advance_pattern_pin1_pmh(size_t loc) { uint32_t offset = ctz(mask); loc = s - lcp + offset - buf_;- if (Pattern::predict_match(pmh, &buf_[loc], min))+ if (pat_->predict_match(&buf_[loc], min)) { set_current(loc); return true;@@ -1081,7 +1079,7 @@ bool Matcher::advance_pattern_pin1_pmh(size_t loc) if ((mask & 0xff)) { loc = s - lcp + i - buf_;- if (Pattern::predict_match(pmh, &buf_[loc], min))+ if (pat_->predict_match(&buf_[loc], min)) { set_current(loc); return true;@@ -1098,7 +1096,7 @@ bool Matcher::advance_pattern_pin1_pmh(size_t loc) if ((mask & 0xff)) { loc = s - lcp + i - buf_;- if (Pattern::predict_match(pmh, &buf_[loc], min))+ if (pat_->predict_match(&buf_[loc], min)) { set_current(loc); return true;@@ -1129,7 +1127,7 @@ bool Matcher::advance_pattern_pin1_pmh(size_t loc) { s -= lcp; loc = s - buf_;- if (s + min > e || (s[lcs] == chr1 && Pattern::predict_match(pmh, s, min)))+ if (s + min > e || (s[lcs] == chr1 && pat_->predict_match(s, min))) { set_current(loc); return true;@@ -1153,7 +1151,6 @@ bool Matcher::advance_pattern_pin1_pmh(size_t loc) #define ADV_PAT_PIN_ONE(N, INIT, COMP) \ bool Matcher::advance_pattern_pin##N##_one(size_t loc) \ { \- const Pattern::Pred *pma = pat_->pma_; \ const char *chr = pat_->chr_; \ INIT \ while (true) \@@ -1170,7 +1167,7 @@ bool Matcher::advance_pattern_pin##N##_one(size_t loc) \ { \ uint32_t offset = ctz(mask); \ loc = s + offset - buf_; \- if (loc + 4 > end_ || Pattern::predict_match(pma, &buf_[loc]) == 0) \+ if (loc + 4 > end_ || pat_->predict_match(&buf_[loc])) \ { \ set_current(loc); \ return true; \@@ -1285,7 +1282,6 @@ ADV_PAT_PIN_ONE(8, \ #define ADV_PAT_PIN(N, INIT, COMP) \ bool Matcher::advance_pattern_pin##N##_pma(size_t loc) \ { \- const Pattern::Pred *pma = pat_->pma_; \ const char *chr = pat_->chr_; \ size_t min = pat_->min_; \ uint16_t lcp = pat_->lcp_; \@@ -1307,7 +1303,7 @@ bool Matcher::advance_pattern_pin##N##_pma(size_t loc) \ { \ uint32_t offset = ctz(mask); \ loc = s - lcp + offset - buf_; \- if (loc + 4 > end_ || Pattern::predict_match(pma, &buf_[loc]) == 0) \+ if (loc + 4 > end_ || pat_->predict_match(&buf_[loc])) \ { \ set_current(loc); \ return true; \@@ -1330,7 +1326,6 @@ bool Matcher::advance_pattern_pin##N##_pma(size_t loc) \ \ bool Matcher::advance_pattern_pin##N##_pmh(size_t loc) \ { \- const Pattern::Pred *pmh = pat_->pmh_; \ const char *chr = pat_->chr_; \ size_t min = pat_->min_; \ uint16_t lcp = pat_->lcp_; \@@ -1352,7 +1347,7 @@ bool Matcher::advance_pattern_pin##N##_pmh(size_t loc) \ { \ uint32_t offset = ctz(mask); \ loc = s - lcp + offset - buf_; \- if (Pattern::predict_match(pmh, &buf_[loc], min)) \+ if (pat_->predict_match(&buf_[loc], min)) \ { \ set_current(loc); \ return true; \@@ -1533,7 +1528,6 @@ ADV_PAT_PIN(8, \ #define ADV_PAT_PIN_ONE(N, INIT, COMP) \ bool Matcher::advance_pattern_pin##N##_one(size_t loc) \ { \- const Pattern::Pred *pma = pat_->pma_; \ const char *chr = pat_->chr_; \ INIT \ while (true) \@@ -1553,7 +1547,7 @@ bool Matcher::advance_pattern_pin##N##_one(size_t loc) \ if ((mask & 0xff)) \ { \ loc = s + i - buf_; \- if (loc + 4 > end_ || Pattern::predict_match(pma, &buf_[loc]) == 0) \+ if (loc + 4 > end_ || pat_->predict_match(&buf_[loc])) \ { \ set_current(loc); \ return true; \@@ -1570,7 +1564,7 @@ bool Matcher::advance_pattern_pin##N##_one(size_t loc) \ if ((mask & 0xff)) \ { \ loc = s + i - buf_; \- if (loc + 4 > end_ || Pattern::predict_match(pma, &buf_[loc]) == 0) \+ if (loc + 4 > end_ || pat_->predict_match(&buf_[loc])) \ { \ set_current(loc); \ return true; \@@ -1726,7 +1720,6 @@ ADV_PAT_PIN_ONE(8, \ #define ADV_PAT_PIN(N, INIT, COMP) \ bool Matcher::advance_pattern_pin##N##_pma(size_t loc) \ { \- const Pattern::Pred *pma = pat_->pma_; \ const char *chr = pat_->chr_; \ size_t min = pat_->min_; \ uint16_t lcp = pat_->lcp_; \@@ -1750,7 +1743,7 @@ bool Matcher::advance_pattern_pin##N##_pma(size_t loc) \ if ((mask & 0xff)) \ { \ loc = s - lcp + i - buf_; \- if (loc + 4 > end_ || Pattern::predict_match(pma, &buf_[loc]) == 0) \+ if (loc + 4 > end_ || pat_->predict_match(&buf_[loc])) \ { \ set_current(loc); \ return true; \@@ -1767,7 +1760,7 @@ bool Matcher::advance_pattern_pin##N##_pma(size_t loc) \ if ((mask & 0xff)) \ { \ loc = s - lcp + i - buf_; \- if (loc + 4 > end_ || Pattern::predict_match(pma, &buf_[loc]) == 0) \+ if (loc + 4 > end_ || pat_->predict_match(&buf_[loc])) \ { \ set_current(loc); \ return true; \@@ -1792,7 +1785,6 @@ bool Matcher::advance_pattern_pin##N##_pma(size_t loc) \ \ bool Matcher::advance_pattern_pin##N##_pmh(size_t loc) \ { \- const Pattern::Pred *pmh = pat_->pmh_; \ const char *chr = pat_->chr_; \ size_t min = pat_->min_; \ uint16_t lcp = pat_->lcp_; \@@ -1816,7 +1808,7 @@ bool Matcher::advance_pattern_pin##N##_pmh(size_t loc) \ if ((mask & 0xff)) \ { \ loc = s - lcp + i - buf_; \- if (Pattern::predict_match(pmh, &buf_[loc], min)) \+ if (pat_->predict_match(&buf_[loc], min)) \ { \ set_current(loc); \ return true; \@@ -1833,7 +1825,7 @@ bool Matcher::advance_pattern_pin##N##_pmh(size_t loc) \ if ((mask & 0xff)) \ { \ loc = s - lcp + i - buf_; \- if (Pattern::predict_match(pmh, &buf_[loc], min)) \+ if (pat_->predict_match(&buf_[loc], min)) \ { \ set_current(loc); \ return true; \@@ -2090,10 +2082,9 @@ ADV_PAT_PIN(8, \ #endif -/// Minimal 1 char pattern using bitap and PM4+/// Minimal 1 char pattern usign the bitap first bit and PM4 bool Matcher::advance_pattern_min1(size_t loc) {- const Pattern::Pred *pma = pat_->pma_; const Pattern::Pred *bit = pat_->bit_; while (true) {@@ -2101,17 +2092,24 @@ bool Matcher::advance_pattern_min1(size_t loc) const char *e = buf_ + end_ - 3; bool f = true; while (s < e &&- (f = ((bit[static_cast<uint8_t>(*s)] & 1) &&- (bit[static_cast<uint8_t>(*++s)] & 1) &&- (bit[static_cast<uint8_t>(*++s)] & 1) &&- (bit[static_cast<uint8_t>(*++s)] & 1))))+ (f = (bit[static_cast<uint8_t>(s[0])] &+ bit[static_cast<uint8_t>(s[1])] &+ bit[static_cast<uint8_t>(s[2])] &+ bit[static_cast<uint8_t>(s[3])] & 1))) {- ++s;+ s += 4; } loc = s - buf_; if (!f) {- if (s < e && Pattern::predict_match(pma, s) != 0)+ if ((bit[static_cast<uint8_t>(*s)] & 1))+ {+ if ((bit[static_cast<uint8_t>(*++s)] & 1))+ if ((bit[static_cast<uint8_t>(*++s)] & 1))+ ++s;+ loc = s - buf_;+ }+ if (s < e && !pat_->predict_match(s)) { ++loc; continue;@@ -2129,12 +2127,11 @@ bool Matcher::advance_pattern_min1(size_t loc) } } -/// Minimal 2 char pattern using bitam and PM4+/// Minimal 2 char pattern using bitap and PM4 bool Matcher::advance_pattern_min2(size_t loc) { const Pattern::Pred *bit = pat_->bit_;- const Pattern::Pred *pma = pat_->pma_;- Pattern::Pred state = ~0;+ uint32_t state = ~0; while (true) { const char *s = buf_ + loc;@@ -2142,38 +2139,27 @@ bool Matcher::advance_pattern_min2(size_t loc) while (s < e) { state = (state << 1) | bit[static_cast<uint8_t>(*s)];- if ((state & 2) == 0)- break; ++s;- }- if (s < e)- {- s -= 1;- loc = s - buf_;- if (s > e - 4 || Pattern::predict_match(pma, s) == 0)+ if ((state & 2) == 0 && (s > e - 2 || pat_->predict_match(s - 2))) {+ loc = s - buf_ - 2; set_current(loc); return true; }- loc += 2;- }- else- {- loc = s - buf_;- set_current_and_peek_more(loc - 1);- loc = cur_ + 1;- if (loc + 2 > end_)- return false; }+ loc = s - buf_;+ set_current_and_peek_more(loc - 1);+ loc = cur_ + 1;+ if (loc + 2 > end_)+ return false; } } -/// Minimal 3 char pattern using bitam and PM4+/// Minimal 3 char pattern using bitap and PM4 bool Matcher::advance_pattern_min3(size_t loc) { const Pattern::Pred *bit = pat_->bit_;- const Pattern::Pred *pma = pat_->pma_;- Pattern::Pred state = ~0;+ uint32_t state = ~0; while (true) { const char *s = buf_ + loc;@@ -2181,103 +2167,75 @@ bool Matcher::advance_pattern_min3(size_t loc) while (s < e) { state = (state << 1) | bit[static_cast<uint8_t>(*s)];- if ((state & 4) == 0)- break; ++s;- }- if (s < e)- {- s -= 2;- loc = s - buf_;- if (s > e - 4 || Pattern::predict_match(pma, s) == 0)+ if ((state & 4) == 0 && (s > e - 1 || pat_->predict_match(s - 3))) {+ loc = s - buf_ - 3; set_current(loc); return true; }- loc += 3;- }- else- {- loc = s - buf_;- set_current_and_peek_more(loc - 1);- loc = cur_ + 1;- if (loc + 3 > end_)- return false; }+ loc = s - buf_;+ set_current_and_peek_more(loc - 1);+ loc = cur_ + 1;+ if (loc + 3 > end_)+ return false; } } -/// Minimal 4 char pattern using bitam and PM hashing+/// Minimal 4 char pattern using bitap and PM hashing bool Matcher::advance_pattern_min4(size_t loc) { const Pattern::Pred *bit = pat_->bit_;- const Pattern::Pred *pmh = pat_->pmh_; size_t min = pat_->min_;- Pattern::Pred state1 = ~0;- Pattern::Pred state2 = ~0;- Pattern::Pred mask = (1 << (min - 1));+ uint32_t state1 = ~0;+ uint32_t state2 = ~0;+ uint32_t mask = 1 << (min - 1); while (true) { const char *s = buf_ + loc;- const char *e = buf_ + end_;- while (s < e - 1)+ const char *e = buf_ + end_ - 1;+ while (s < e) {- state2 = (state1 << 1) | bit[static_cast<uint8_t>(*s)];- ++s;- state1 = (state2 << 1) | bit[static_cast<uint8_t>(*s)];+ state2 = (state1 << 1) | bit[static_cast<uint8_t>(s[0])];+ state1 = (state2 << 1) | bit[static_cast<uint8_t>(s[1])];+ s += 2; if ((state1 & state2 & mask) == 0)- break;- ++s;- }- if ((state2 & mask) == 0)- {- state1 = state2;- state2 = ~0;- --s;- }- else if ((state1 & mask) != 0 && s == e - 1)- {- state1 = (state1 << 1) | bit[static_cast<uint8_t>(*s)];- if ((state1 & mask) != 0)- ++s;- }- if (s < e)- {- s -= min - 1;- loc = s - buf_;- if (Pattern::predict_match(pmh, s, min)) {- set_current(loc);- return true;+ if ((state2 & mask) == 0)+ {+ state1 = state2;+ --s;+ }+ if (pat_->predict_match(s - min, min))+ {+ loc = s - buf_ - min;+ set_current(loc);+ return true;+ } }- loc += min;- }- else- {- loc = s - buf_;- set_current_and_peek_more(loc - 1);- loc = cur_ + 1;- if (loc + min > end_)- return false; }+ loc = s - buf_;+ set_current_and_peek_more(loc - 1);+ loc = cur_ + 1;+ if (loc + min > end_)+ return false; } } /// Minimal 1 char pattern using PM4 bool Matcher::advance_pattern(size_t loc) {- const Pattern::Pred *pma = pat_->pma_;- size_t min = pat_->min_; while (true) { const char *s = buf_ + loc; const char *e = buf_ + end_ - 6; bool f = true; while (s < e &&- (f = (Pattern::predict_match(pma, s) != 0 &&- Pattern::predict_match(pma, ++s) != 0 &&- Pattern::predict_match(pma, ++s) != 0 &&- Pattern::predict_match(pma, ++s) != 0)))+ (f = (!pat_->predict_match(s) &&+ !pat_->predict_match(++s) &&+ !pat_->predict_match(++s) &&+ !pat_->predict_match(++s)))) { ++s; }@@ -2292,7 +2250,7 @@ bool Matcher::advance_pattern(size_t loc) if (loc + 6 >= end_) { set_current(loc);- return loc + min <= end_;+ return loc + pat_->min_ <= end_; } } }@@ -2323,7 +2281,6 @@ bool Matcher::advance_char(size_t loc) /// One char followed by 1 to 3 minimal char pattern bool Matcher::advance_char_pma(size_t loc) {- const Pattern::Pred *pma = pat_->pma_; char chr0 = pat_->chr_[0]; while (true) {@@ -2334,7 +2291,7 @@ bool Matcher::advance_char_pma(size_t loc) { loc = s - buf_; set_current(loc);- if (s > e - 5 || Pattern::predict_match(pma, s + 1) == 0)+ if (s > e - 5 || pat_->predict_match(s + 1)) return true; ++loc; }@@ -2352,7 +2309,6 @@ bool Matcher::advance_char_pma(size_t loc) /// One char followed by 4 minimal char pattern bool Matcher::advance_char_pmh(size_t loc) {- const Pattern::Pred *pmh = pat_->pmh_; char chr0 = pat_->chr_[0]; size_t min = pat_->min_; while (true)@@ -2363,7 +2319,7 @@ bool Matcher::advance_char_pmh(size_t loc) if (s != NULL) { loc = s - buf_;- if (s + 1 + min > e || Pattern::predict_match(pmh, s + 1, min))+ if (s + 1 + min > e || pat_->predict_match(s + 1, min)) { set_current(loc); return true;@@ -2521,7 +2477,6 @@ bool Matcher::advance_chars_pma(size_t loc) { static const uint16_t lcp = 0; static const uint16_t lcs = LEN - 1;- const Pattern::Pred *pma = pat_->pma_; const char *chr = pat_->chr_; size_t min = pat_->min_; #if defined(HAVE_AVX512BW) || defined(HAVE_AVX2) || defined(HAVE_SSE2)@@ -2545,7 +2500,7 @@ bool Matcher::advance_chars_pma(size_t loc) (LEN == 3 ? s[offset + 1 - lcp] == chr[1] : std::memcmp(s + 1 - lcp + offset, chr + 1, LEN - 2) == 0)) { loc = s - lcp + offset - buf_;- if (loc + LEN + 4 > end_ || Pattern::predict_match(pma, &buf_[loc + LEN]) == 0)+ if (loc + LEN + 4 > end_ || pat_->predict_match(&buf_[loc + LEN])) { set_current(loc); return true;@@ -2589,7 +2544,7 @@ bool Matcher::advance_chars_pma(size_t loc) (LEN == 3 ? s[i + 1 - lcp] == chr[1] : std::memcmp(s + 1 - lcp + i, chr + 1, LEN - 2) == 0))) { loc = s - lcp + i - buf_;- if (loc + LEN + 4 > end_ || Pattern::predict_match(pat_->pma_, &buf_[loc + LEN]) == 0)+ if (loc + LEN + 4 > end_ || pat_->predict_match(&buf_[loc + LEN])) { set_current(loc); return true;@@ -2608,7 +2563,7 @@ bool Matcher::advance_chars_pma(size_t loc) (LEN == 3 ? s[i + 1 - lcp] == chr[1] : std::memcmp(s + 1 - lcp + i, chr + 1, LEN - 2) == 0))) { loc = s - lcp + i - buf_;- if (loc + LEN + 4 > end_ || Pattern::predict_match(pat_->pma_, &buf_[loc + LEN]) == 0)+ if (loc + LEN + 4 > end_ || pat_->predict_match(&buf_[loc + LEN])) { set_current(loc); return true;@@ -2647,7 +2602,7 @@ bool Matcher::advance_chars_pma(size_t loc) (LEN == 3 ? s[1 - lcp] == chr[1] : std::memcmp(s + 1 - lcp, chr + 1, LEN - 2) == 0)) { loc = s - lcp - buf_;- if (loc + LEN + 4 > end_ || Pattern::predict_match(pma, &buf_[loc + LEN]) == 0)+ if (loc + LEN + 4 > end_ || pat_->predict_match(&buf_[loc + LEN])) { set_current(loc); return true;@@ -2669,7 +2624,6 @@ bool Matcher::advance_chars_pmh(size_t loc) { static const uint16_t lcp = 0; static const uint16_t lcs = LEN - 1;- const Pattern::Pred *pmh = pat_->pmh_; const char *chr = pat_->chr_; size_t min = pat_->min_; #if defined(HAVE_AVX512BW) || defined(HAVE_AVX2) || defined(HAVE_SSE2)@@ -2693,7 +2647,7 @@ bool Matcher::advance_chars_pmh(size_t loc) (LEN == 3 ? s[offset + 1 - lcp] == chr[1] : std::memcmp(s + 1 - lcp + offset, chr + 1, LEN - 2) == 0)) { loc = s - lcp + offset - buf_;- if (loc + LEN + min > end_ || Pattern::predict_match(pmh, &buf_[loc + LEN], min))+ if (loc + LEN + min > end_ || pat_->predict_match(&buf_[loc + LEN], min)) { set_current(loc); return true;@@ -2737,7 +2691,7 @@ bool Matcher::advance_chars_pmh(size_t loc) (LEN == 3 ? s[i + 1 - lcp] == chr[1] : std::memcmp(s + 1 - lcp + i, chr + 1, LEN - 2) == 0))) { size_t loc = s - lcp + i - buf_;- if (loc + LEN + min > end_ || Pattern::predict_match(pat_->pmh_, &buf_[loc + LEN], min))+ if (loc + LEN + min > end_ || pat_->predict_match(&buf_[loc + LEN], min)) { set_current(loc); return true;@@ -2756,7 +2710,7 @@ bool Matcher::advance_chars_pmh(size_t loc) (LEN == 3 ? s[i + 1 - lcp] == chr[1] : std::memcmp(s + 1 - lcp + i, chr + 1, LEN - 2) == 0))) { size_t loc = s - lcp + i - buf_;- if (loc + LEN + min > end_ || Pattern::predict_match(pat_->pmh_, &buf_[loc + LEN], min))+ if (loc + LEN + min > end_ || pat_->predict_match(&buf_[loc + LEN], min)) { set_current(loc); return true;@@ -2795,7 +2749,7 @@ bool Matcher::advance_chars_pmh(size_t loc) (LEN == 3 ? s[1 - lcp] == chr[1] : std::memcmp(s + 1 - lcp, chr + 1, LEN - 2) == 0)) { loc = s - lcp - buf_;- if (loc + LEN + min > end_ || Pattern::predict_match(pmh, &buf_[loc + LEN], min))+ if (loc + LEN + min > end_ || pat_->predict_match(&buf_[loc + LEN], min)) { set_current(loc); return true;@@ -2907,7 +2861,6 @@ bool Matcher::advance_string(size_t loc) /// String followed by 1 to 3 minimal char pattern bool Matcher::advance_string_pma(size_t loc) {- const Pattern::Pred *pma = pat_->pma_; const char *chr = pat_->chr_; size_t len = pat_->len_; size_t min = pat_->min_;@@ -2934,7 +2887,7 @@ bool Matcher::advance_string_pma(size_t loc) if (std::memcmp(s - lcp + offset, chr, len) == 0) { loc = s - lcp + offset - buf_;- if (loc + len + 4 > end_ || Pattern::predict_match(pma, &buf_[loc + len]) == 0)+ if (loc + len + 4 > end_ || pat_->predict_match(&buf_[loc + len])) { set_current(loc); return true;@@ -2987,7 +2940,7 @@ bool Matcher::advance_string_pma(size_t loc) if (std::memcmp(s - lcp, chr, len) == 0) { loc = s - lcp - buf_;- if (loc + len + 4 > end_ || Pattern::predict_match(pma, &buf_[loc + len]) == 0)+ if (loc + len + 4 > end_ || pat_->predict_match(&buf_[loc + len])) { set_current(loc); return true;@@ -3006,7 +2959,6 @@ bool Matcher::advance_string_pma(size_t loc) /// String followed by 4 minimal char pattern bool Matcher::advance_string_pmh(size_t loc) {- const Pattern::Pred *pmh = pat_->pmh_; const char *chr = pat_->chr_; size_t len = pat_->len_; size_t min = pat_->min_;@@ -3033,7 +2985,7 @@ bool Matcher::advance_string_pmh(size_t loc) if (std::memcmp(s - lcp + offset, chr, len) == 0) { loc = s - lcp + offset - buf_;- if (loc + len + min > end_ || Pattern::predict_match(pmh, &buf_[loc + len], min))+ if (loc + len + min > end_ || pat_->predict_match(&buf_[loc + len], min)) { set_current(loc); return true;@@ -3086,7 +3038,7 @@ bool Matcher::advance_string_pmh(size_t loc) if (std::memcmp(s - lcp, chr, len) == 0) { loc = s - lcp - buf_;- if (loc + len + min > end_ || Pattern::predict_match(pmh, &buf_[loc + len], min))+ if (loc + len + min > end_ || pat_->predict_match(&buf_[loc + len], min)) { set_current(loc); return true;@@ -3183,7 +3135,7 @@ bool Matcher::simd_advance_string_pma_neon(const char *&s, const char *e) if ((mask & 0xff) && std::memcmp(s - lcp + i, chr, len) == 0) { size_t loc = s - lcp + i - buf_;- if (loc + len + 4 > end_ || Pattern::predict_match(pat_->pma_, &buf_[loc + len]) == 0)+ if (loc + len + 4 > end_ || pat_->predict_match(&buf_[loc + len])) { set_current(loc); return true;@@ -3200,7 +3152,7 @@ bool Matcher::simd_advance_string_pma_neon(const char *&s, const char *e) if ((mask & 0xff) && std::memcmp(s - lcp + i, chr, len) == 0) { size_t loc = s - lcp + i - buf_;- if (loc + len + 4 > end_ || Pattern::predict_match(pat_->pma_, &buf_[loc + len]) == 0)+ if (loc + len + 4 > end_ || pat_->predict_match(&buf_[loc + len])) { set_current(loc); return true;@@ -3240,7 +3192,7 @@ bool Matcher::simd_advance_string_pmh_neon(const char *&s, const char *e) if ((mask & 0xff) && std::memcmp(s - lcp + i, chr, len) == 0) { size_t loc = s - lcp + i - buf_;- if (loc + len + min > end_ || Pattern::predict_match(pat_->pmh_, &buf_[loc + len], min))+ if (loc + len + min > end_ || pat_->predict_match(&buf_[loc + len], min)) { set_current(loc); return true;@@ -3257,7 +3209,7 @@ bool Matcher::simd_advance_string_pmh_neon(const char *&s, const char *e) if ((mask & 0xff) && std::memcmp(s - lcp + i, chr, len) == 0) { size_t loc = s - lcp + i - buf_;- if (loc + len + min > end_ || Pattern::predict_match(pat_->pmh_, &buf_[loc + len], min))+ if (loc + len + min > end_ || pat_->predict_match(&buf_[loc + len], min)) { set_current(loc); return true;@@ -3337,7 +3289,6 @@ bool Matcher::advance_string_bm(size_t loc) bool Matcher::advance_string_bm_pma(size_t loc) { const char *chr = pat_->chr_;- const Pattern::Pred *pma = pat_->pma_; const uint8_t *bms = pat_->bms_; size_t len = pat_->len_; size_t bmd = pat_->bmd_;@@ -3365,7 +3316,7 @@ bool Matcher::advance_string_bm_pma(size_t loc) if (p < chr) { loc = q - buf_ + 1;- if (loc + len + 4 > end_ || Pattern::predict_match(pma, &buf_[loc + len]) == 0)+ if (loc + len + 4 > end_ || pat_->predict_match(&buf_[loc + len])) { set_current(loc); return true;@@ -3393,11 +3344,10 @@ bool Matcher::advance_string_bm_pma(size_t loc) } } -/// My improved Boyer-Moore string search followed by a 4 minimal char pattern, using PM4+/// My improved Boyer-Moore string search followed by a 4 minimal char pattern, using PM bool Matcher::advance_string_bm_pmh(size_t loc) { const char *chr = pat_->chr_;- const Pattern::Pred *pmh = pat_->pmh_; const uint8_t *bms = pat_->bms_; size_t bmd = pat_->bmd_; size_t len = pat_->len_;@@ -3426,7 +3376,7 @@ bool Matcher::advance_string_bm_pmh(size_t loc) if (p < chr) { loc = q - buf_ + 1;- if (loc + len + min > end_ || Pattern::predict_match(pmh, &buf_[loc + len], min))+ if (loc + len + min > end_ || pat_->predict_match(&buf_[loc + len], min)) { set_current(loc); return true;
@@ -163,7 +163,6 @@ void Matcher::simd_init_advance_avx2() // My "needle search" method when pin=1 bool Matcher::simd_advance_pattern_pin1_pma_avx2(size_t loc) {- const Pattern::Pred *pma = pat_->pma_; const char *chr = pat_->chr_; size_t min = pat_->min_; uint16_t lcp = pat_->lcp_;@@ -186,7 +185,7 @@ bool Matcher::simd_advance_pattern_pin1_pma_avx2(size_t loc) uint32_t offset = ctz(mask); loc = s - lcp + offset - buf_; set_current(loc);- if (loc + 4 > end_ || Pattern::predict_match(pma, &buf_[loc]) == 0)+ if (loc + 4 > end_ || pat_->predict_match(&buf_[loc])) return true; mask &= mask - 1; }@@ -207,7 +206,6 @@ bool Matcher::simd_advance_pattern_pin1_pma_avx2(size_t loc) // My "needle search" method when pin=1 bool Matcher::simd_advance_pattern_pin1_pmh_avx2(size_t loc) {- const Pattern::Pred *pmh = pat_->pmh_; const char *chr = pat_->chr_; size_t min = pat_->min_; uint16_t lcp = pat_->lcp_;@@ -230,7 +228,7 @@ bool Matcher::simd_advance_pattern_pin1_pmh_avx2(size_t loc) uint32_t offset = ctz(mask); loc = s - lcp + offset - buf_; set_current(loc);- if (Pattern::predict_match(pmh, &buf_[loc], min))+ if (pat_->predict_match(&buf_[loc], min)) return true; mask &= mask - 1; }@@ -252,7 +250,6 @@ bool Matcher::simd_advance_pattern_pin1_pmh_avx2(size_t loc) #define ADV_PAT_PIN_ONE(N, INIT, COMP) \ bool Matcher::simd_advance_pattern_pin##N##_one_avx2(size_t loc) \ { \- const Pattern::Pred *pma = pat_->pma_; \ const char *chr = pat_->chr_; \ INIT \ while (true) \@@ -269,7 +266,7 @@ bool Matcher::simd_advance_pattern_pin##N##_one_avx2(size_t loc) \ { \ uint32_t offset = ctz(mask); \ loc = s + offset - buf_; \- if (loc + 4 > end_ || Pattern::predict_match(pma, &buf_[loc]) == 0) \+ if (loc + 4 > end_ || pat_->predict_match(&buf_[loc])) \ { \ set_current(loc); \ return true; \@@ -419,7 +416,6 @@ ADV_PAT_PIN_ONE(16, \ #define ADV_PAT_PIN(N, INIT, COMP) \ bool Matcher::simd_advance_pattern_pin##N##_pma_avx2(size_t loc) \ { \- const Pattern::Pred *pma = pat_->pma_; \ const char *chr = pat_->chr_; \ size_t min = pat_->min_; \ uint16_t lcp = pat_->lcp_; \@@ -441,7 +437,7 @@ bool Matcher::simd_advance_pattern_pin##N##_pma_avx2(size_t loc) \ { \ uint32_t offset = ctz(mask); \ loc = s - lcp + offset - buf_; \- if (loc + 4 > end_ || Pattern::predict_match(pma, &buf_[loc]) == 0) \+ if (loc + 4 > end_ || pat_->predict_match(&buf_[loc])) \ { \ set_current(loc); \ return true; \@@ -464,7 +460,6 @@ bool Matcher::simd_advance_pattern_pin##N##_pma_avx2(size_t loc) \ \ bool Matcher::simd_advance_pattern_pin##N##_pmh_avx2(size_t loc) \ { \- const Pattern::Pred *pmh = pat_->pmh_; \ const char *chr = pat_->chr_; \ size_t min = pat_->min_; \ uint16_t lcp = pat_->lcp_; \@@ -486,7 +481,7 @@ bool Matcher::simd_advance_pattern_pin##N##_pmh_avx2(size_t loc) \ { \ uint32_t offset = ctz(mask); \ loc = s - lcp + offset - buf_; \- if (Pattern::predict_match(pmh, &buf_[loc], min)) \+ if (pat_->predict_match(&buf_[loc], min)) \ { \ set_current(loc); \ return true; \@@ -779,7 +774,6 @@ bool Matcher::simd_advance_chars_pma_avx2(size_t loc) { static const uint16_t lcp = 0; static const uint16_t lcs = LEN - 1;- const Pattern::Pred *pma = pat_->pma_; const char *chr = pat_->chr_; size_t min = pat_->min_; while (true)@@ -802,7 +796,7 @@ bool Matcher::simd_advance_chars_pma_avx2(size_t loc) (LEN == 3 ? s[offset + 1 - lcp] : std::memcmp(s + 1 - lcp + offset, chr + 1, LEN - 2) == 0)) { loc = s - lcp + offset - buf_;- if (loc + LEN + 4 > end_ || Pattern::predict_match(pma, &buf_[loc + LEN]) == 0)+ if (loc + LEN + 4 > end_ || pat_->predict_match(&buf_[loc + LEN])) { set_current(loc); return true;@@ -830,7 +824,6 @@ bool Matcher::simd_advance_chars_pmh_avx2(size_t loc) { static const uint16_t lcp = 0; static const uint16_t lcs = LEN - 1;- const Pattern::Pred *pmh = pat_->pmh_; const char *chr = pat_->chr_; size_t min = pat_->min_; while (true)@@ -854,7 +847,7 @@ bool Matcher::simd_advance_chars_pmh_avx2(size_t loc) { loc = s - lcp + offset - buf_; set_current(loc);- if (loc + LEN + min > end_ || Pattern::predict_match(pmh, &buf_[loc + LEN], min))+ if (loc + LEN + min > end_ || pat_->predict_match(&buf_[loc + LEN], min)) return true; } mask &= mask - 1;@@ -923,7 +916,6 @@ bool Matcher::simd_advance_string_avx2(size_t loc) /// Implements AVX2 string search scheme based on http://0x80.pl/articles/simd-friendly-karp-rabin.html bool Matcher::simd_advance_string_pma_avx2(size_t loc) {- const Pattern::Pred *pma = pat_->pma_; const char *chr = pat_->chr_; size_t len = pat_->len_; size_t min = pat_->min_;@@ -948,7 +940,7 @@ bool Matcher::simd_advance_string_pma_avx2(size_t loc) if (std::memcmp(s - lcp + offset, chr, len) == 0) { loc = s - lcp + offset - buf_;- if (loc + len + 4 > end_ || Pattern::predict_match(pma, &buf_[loc + len]) == 0)+ if (loc + len + 4 > end_ || pat_->predict_match(&buf_[loc + len])) { set_current(loc); return true;@@ -973,7 +965,6 @@ bool Matcher::simd_advance_string_pma_avx2(size_t loc) /// Implements AVX2 string search scheme based on http://0x80.pl/articles/simd-friendly-karp-rabin.html bool Matcher::simd_advance_string_pmh_avx2(size_t loc) {- const Pattern::Pred *pmh = pat_->pmh_; const char *chr = pat_->chr_; size_t len = pat_->len_; size_t min = pat_->min_;@@ -999,7 +990,7 @@ bool Matcher::simd_advance_string_pmh_avx2(size_t loc) { loc = s - lcp + offset - buf_; set_current(loc);- if (loc + len + min > end_ || Pattern::predict_match(pmh, &buf_[loc + len], min))+ if (loc + len + min > end_ || pat_->predict_match(&buf_[loc + len], min)) return true; } mask &= mask - 1;
@@ -138,7 +138,6 @@ bool Matcher::simd_advance_chars_pma_avx512bw(size_t loc) { static const uint16_t lcp = 0; static const uint16_t lcs = LEN - 1;- const Pattern::Pred *pma = pat_->pma_; const char *chr = pat_->chr_; size_t min = pat_->min_; while (true)@@ -159,7 +158,7 @@ bool Matcher::simd_advance_chars_pma_avx512bw(size_t loc) (LEN == 3 ? s[offset + 1 - lcp] == chr[1] : std::memcmp(s + 1 - lcp + offset, chr + 1, LEN - 2) == 0)) { loc = s - lcp + offset - buf_;- if (loc + LEN + 4 > end_ || Pattern::predict_match(pma, &buf_[loc + LEN]) == 0)+ if (loc + LEN + 4 > end_ || pat_->predict_match(&buf_[loc + LEN])) { set_current(loc); return true;@@ -187,7 +186,6 @@ bool Matcher::simd_advance_chars_pmh_avx512bw(size_t loc) { static const uint16_t lcp = 0; static const uint16_t lcs = LEN - 1;- const Pattern::Pred *pmh = pat_->pmh_; const char *chr = pat_->chr_; size_t min = pat_->min_; while (true)@@ -208,7 +206,7 @@ bool Matcher::simd_advance_chars_pmh_avx512bw(size_t loc) (LEN == 3 ? s[offset + 1 - lcp] == chr[1] : std::memcmp(s + 1 - lcp + offset, chr + 1, LEN - 2) == 0)) { loc = s - lcp + offset - buf_;- if (loc + LEN + min > end_ || Pattern::predict_match(pmh, &buf_[loc + LEN], min))+ if (loc + LEN + min > end_ || pat_->predict_match(&buf_[loc + LEN], min)) { set_current(loc); return true;@@ -278,7 +276,6 @@ bool Matcher::simd_advance_string_avx512bw(size_t loc) /// Implements AVX512BW string search scheme based on http://0x80.pl/articles/simd-friendly-karp-rabin.html bool Matcher::simd_advance_string_pma_avx512bw(size_t loc) {- const Pattern::Pred *pma = pat_->pma_; const char *chr = pat_->chr_; size_t len = pat_->len_; size_t min = pat_->min_;@@ -301,7 +298,7 @@ bool Matcher::simd_advance_string_pma_avx512bw(size_t loc) if (std::memcmp(s - lcp + offset, chr, len) == 0) { loc = s - lcp + offset - buf_;- if (loc + len + 4 > end_ || Pattern::predict_match(pma, &buf_[loc + len]) == 0)+ if (loc + len + 4 > end_ || pat_->predict_match(&buf_[loc + len])) { set_current(loc); return true;@@ -326,7 +323,6 @@ bool Matcher::simd_advance_string_pma_avx512bw(size_t loc) /// Implements AVX512BW string search scheme based on http://0x80.pl/articles/simd-friendly-karp-rabin.html bool Matcher::simd_advance_string_pmh_avx512bw(size_t loc) {- const Pattern::Pred *pmh = pat_->pmh_; const char *chr = pat_->chr_; size_t len = pat_->len_; size_t min = pat_->min_;@@ -349,7 +345,7 @@ bool Matcher::simd_advance_string_pmh_avx512bw(size_t loc) if (std::memcmp(s - lcp + offset, chr, len) == 0) { loc = s - lcp + offset - buf_;- if (loc + len + min > end_ || Pattern::predict_match(pmh, &buf_[loc + len], min))+ if (loc + len + min > end_ || pat_->predict_match(&buf_[loc + len], min)) { set_current(loc); return true;
@@ -388,7 +388,7 @@ void Pattern::init(const char *options, const uint8_t *pred) } // number of needles required uint16_t n = nlcp > nlcs ? nlcp : nlcs;- DBGLOG("min=%zu lcp=%hu(%hu) pin=%hu nlcp=%hu(%hu) freq=%hu(%hu) freqsum=%hu npy=%zu", min, lcp_, lcs_, n, nlcp, nlcs, freqlcp, freqlcs, freqsum, npy_);+ DBGLOG("min=%zu lcp=%hu(%hu) pin=%hu nlcp=%hu(%hu) freq=%hu(%hu) npy=%zu", min, lcp_, lcs_, n, nlcp, nlcs, freqlcp, freqlcs, npy_); // determine if a needle-based search is worthwhile, below or meeting the thresholds if (n <= pinmax && freqlcp <= freqmax) {
@@ -45,7 +45,7 @@ namespace reflex { // Partially count newlines in string b up to e, updates b close to e with uncounted part-size_t simd_nlcount_avx2(const char*& b, const char *e)+size_t simd_nlcount_avx2(const char *& b, const char *e) { #if defined(HAVE_AVX2) || defined(HAVE_AVX512BW) const char *s = b;
@@ -45,7 +45,7 @@ namespace reflex { // Partially count newlines in string b up to e, updates b close to e with uncounted part-size_t simd_nlcount_avx512bw(const char*& b, const char *e)+size_t simd_nlcount_avx512bw(const char *& b, const char *e) { #if defined(HAVE_AVX512BW) && (!defined(_MSC_VER) || defined(_WIN64)) const char *s = b;
@@ -598,7 +598,7 @@ The same, but using predefined pattern cpp/zap_strings: .IP $ ugrep -e FIXME -f cpp/zap_strings myfile.cpp .PP-Find lines with `FIXME' or `TODO', showing line numberes:+Find lines with `FIXME' or `TODO', showing line numbers: .IP $ ugrep -n -e FIXME -e TODO myfile.cpp .PP@@ -679,7 +679,7 @@ Display options related to "fuzzy" searching: $ ugrep --help fuzzy .PP .SH COPYRIGHT-Copyright (c) 2021-2024 Robert A. van Engelen <engelen@acm.org>+Copyright (c) 2021,2024 Robert A. van Engelen <engelen@acm.org> .PP \fBugrep\fR is released under the BSD\-3 license. All parts of the software have reasonable copyright terms permitting free redistribution. This includes
@@ -1,4 +1,4 @@-.TH UGREP "1" "June 03, 2024" "ugrep 6.1.0" "User Commands"+.TH UGREP "1" "July 09, 2024" "ugrep 6.2.0" "User Commands" .SH NAME \fBugrep\fR, \fBug\fR -- file pattern searcher .SH SYNOPSIS@@ -307,11 +307,10 @@ the default. .TP \fB\-e\fR \fIPATTERN\fR, \fB\-\-regexp\fR=\fIPATTERN\fR Specify a PATTERN to search the input. An input line is selected-if it matches any of the specified patterns. Note that longer-patterns take precedence over shorter patterns. This option is-most useful when multiple \fB\-e\fR options are used to specify multiple-patterns, when a pattern begins with a dash (`\-'), to specify a-pattern after option \fB\-f\fR or after the FILE arguments.+if it matches any of the specified patterns. This option is useful+when multiple \fB\-e\fR options are used to specify multiple patterns, or+when a pattern begins with a dash (`\-'), or to specify a pattern+after option \fB\-f\fR or after the FILE arguments. .TP \fB\-\-encoding\fR=\fIENCODING\fR The encoding format of the input. The default ENCODING is binary@@ -1365,7 +1364,7 @@ The same, but using predefined pattern cpp/zap_strings: .IP $ ugrep -e FIXME -f cpp/zap_strings myfile.cpp .PP-Find lines with `FIXME' or `TODO', showing line numberes:+Find lines with `FIXME' or `TODO', showing line numbers: .IP $ ugrep -n -e FIXME -e TODO myfile.cpp .PP@@ -1446,7 +1445,7 @@ Display options related to "fuzzy" searching: $ ugrep --help fuzzy .PP .SH COPYRIGHT-Copyright (c) 2021-2024 Robert A. van Engelen <engelen@acm.org>+Copyright (c) 2021,2024 Robert A. van Engelen <engelen@acm.org> .PP \fBugrep\fR is released under the BSD\-3 license. All parts of the software have reasonable copyright terms permitting free redistribution. This includes
@@ -1,4 +1,4 @@-.TH UGREP-INDEXER "1" "June 03, 2024" "ugrep-indexer 6.1.0" "User Commands"+.TH UGREP-INDEXER "1" "July 09, 2024" "ugrep-indexer 6.2.0" "User Commands" .SH NAME \fBugrep-indexer\fR -- file indexer to accelerate recursive searching .SH SYNOPSIS
@@ -1,4 +1,4 @@-.TH UGREP "1" "June 03, 2024" "ugrep 6.1.0" "User Commands"+.TH UGREP "1" "July 09, 2024" "ugrep 6.2.0" "User Commands" .SH NAME \fBugrep\fR, \fBug\fR -- file pattern searcher .SH SYNOPSIS@@ -307,11 +307,10 @@ the default. .TP \fB\-e\fR \fIPATTERN\fR, \fB\-\-regexp\fR=\fIPATTERN\fR Specify a PATTERN to search the input. An input line is selected-if it matches any of the specified patterns. Note that longer-patterns take precedence over shorter patterns. This option is-most useful when multiple \fB\-e\fR options are used to specify multiple-patterns, when a pattern begins with a dash (`\-'), to specify a-pattern after option \fB\-f\fR or after the FILE arguments.+if it matches any of the specified patterns. This option is useful+when multiple \fB\-e\fR options are used to specify multiple patterns, or+when a pattern begins with a dash (`\-'), or to specify a pattern+after option \fB\-f\fR or after the FILE arguments. .TP \fB\-\-encoding\fR=\fIENCODING\fR The encoding format of the input. The default ENCODING is binary@@ -1365,7 +1364,7 @@ The same, but using predefined pattern cpp/zap_strings: .IP $ ugrep -e FIXME -f cpp/zap_strings myfile.cpp .PP-Find lines with `FIXME' or `TODO', showing line numberes:+Find lines with `FIXME' or `TODO', showing line numbers: .IP $ ugrep -n -e FIXME -e TODO myfile.cpp .PP@@ -1446,7 +1445,7 @@ Display options related to "fuzzy" searching: $ ugrep --help fuzzy .PP .SH COPYRIGHT-Copyright (c) 2021-2024 Robert A. van Engelen <engelen@acm.org>+Copyright (c) 2021,2024 Robert A. van Engelen <engelen@acm.org> .PP \fBugrep\fR is released under the BSD\-3 license. All parts of the software have reasonable copyright terms permitting free redistribution. This includes
@@ -151,10 +151,14 @@ void CNF::OpTree::parse3(const char *& pattern) if (parens) {+ // skip ( and spacing ++pattern;+ skip_space(pattern); + // new AND term, only parse when pattern isn't an empty () list.emplace_back(AND);- list.back().parse1(pattern);+ if (*pattern != ')')+ list.back().parse1(pattern); if (*pattern == ')') ++pattern;@@ -240,7 +244,10 @@ void CNF::OpTree::parse3(const char *& pattern) ++lookahead; } - if (level == 0 && (*lookahead == ')' || *lookahead == '|' || isspace(static_cast<unsigned char>(*lookahead))))+ if (level == 0 &&+ (*lookahead == ')' ||+ *lookahead == '|' ||+ isspace(static_cast<unsigned char>(*lookahead)))) break; } @@ -373,7 +380,7 @@ void CNF::OpTree::normalize(bool invert) } } -// convert CNF-normalized operator tree to terms, a CNF AND-list of OR-term lists+// convert CNF-normalized operator tree to terms, a CNF AND-list of ALT-term lists void CNF::OpTree::convert(Terms& terms) { if (op == OpTree::AND)@@ -466,26 +473,16 @@ void CNF::OpTree::add_to(Terms& terms) const } } -// add an OR pattern or OR-NOT pattern, optionally negated (option -N)+// add an ALT pattern or ALT-NOT pattern, optionally negated (option -N) void CNF::new_pattern(PATTERN mask, const char *pattern) { if (terms.empty()) terms.emplace_back(); - if (flag_bool && !(mask & PATTERN::NEG))+ if (flag_bool) {- // --bool --not- if ((mask & PATTERN::NOT))- {- std::string not_pattern;- not_pattern.assign("-(").append(pattern).append(")");- compile(not_pattern.c_str());- }- else- {- // --bool- compile(pattern);- }+ // --bool: compile to CNF+ compile(pattern); } else {@@ -541,7 +538,7 @@ void CNF::new_pattern(PATTERN mask, const char *pattern) } } -// prune empty OR terms and OR terms with empty patterns that match anything+// prune empty ALT terms and ALT terms with empty patterns that match anything void CNF::prune() { // -x: empty patterns match empty lines@@ -554,7 +551,7 @@ void CNF::prune() while (i != e) {- // erase empty term and erase NULL term without OR NOT terms, unless the first term and -f FILE is specified+ // erase empty term and erase NULL term without ALT-NOT terms, unless the first term and -f FILE is specified if ((i->empty() || (i->size() == 1 && (!i->front() || i->front()->empty()))) && (i != s || flag_file.empty())) terms.erase(i++); else@@ -565,7 +562,7 @@ void CNF::prune() // split the patterns at \n and \r newlines, when present void CNF::split() {- // --bool: spacing means AND+ // --bool: newlines not present (already converted) if (flag_bool) return; @@ -730,7 +727,7 @@ void CNF::report(FILE *output) const fprintf(output, NEWLINESTR); } -// return all OR terms of the CNF joined together+// return all ALT terms of the CNF joined together std::string CNF::adjoin() const { std::string adjoined;@@ -738,7 +735,7 @@ std::string CNF::adjoin() const if (flag_files) {- // --files: join all OR and OR NOT terms+ // --files: join all ALT and ALT-NOT terms for (const auto& i : terms) for (const auto& j : i) if (j && !j->empty())@@ -757,7 +754,7 @@ std::string CNF::adjoin() const } } - // --lines: join all OR terms unless all of them are paired with OR NOT terms+ // --lines: join all ALT terms unless all of them are paired with ALT-NOT terms if (!allnot) for (const auto& i : terms) if (i.front() && !i.front()->empty())@@ -775,7 +772,7 @@ std::string CNF::adjoin() const return adjoined; } -// return the first OR terms of the CNF+// return the first ALT terms of the CNF std::string CNF::first() const { if (!terms.empty() && terms.front().front())
@@ -55,19 +55,19 @@ class CNF { // a pattern in the CNF is a string or undefined (a NULL smart pointer) typedef std::unique_ptr<std::string> Pattern; - // a term in the CNF is a string/NULL, where the first is an OR pattern (with alternations) or NULL and the rest are OR-NOT alternate patterns+ // a term in the CNF is a string/NULL, where the first is an OR pattern (with alternations) or NULL and the rest are ALT-NOT alternate patterns typedef std::list<Pattern> Term; - // a CNF is a collection of terms, an AND-list of OR-term lists of (NOT-)patterns+ // a CNF is a collection of terms, an AND-list of ALT-term lists of (NOT-)patterns typedef std::list<Term> Terms; // pattern mask values to indicate the type of regex pattern argument to populate CNF struct PATTERN { enum {- NA = 0, // -e PATTERN- NEG = 1, // -N PATTERN- NOT = 2, // --not [-e] PATTERN- TERM = 4, // to create a new AND-term with empty OR-list in the CNF+ ALT = 0, // -e PATTERN+ NEG = 1, // -N PATTERN+ NOT = 2, // --not [-e] PATTERN+ AND = 4, // to create a new AND-term with empty ALT-list in the CNF }; PATTERN(int mask) : mask(mask) { } operator int() const { return mask; }@@ -92,19 +92,19 @@ class CNF { return terms.empty() || (terms.size() == 1 && terms.front().empty()); } - // return true if CNF is undefined or a singleton with just one pattern w/o OR-NOT patterns, after prune()+ // return true if CNF is undefined or a singleton with just one pattern w/o ALT-NOT patterns, after prune() bool singleton_or_undefined() const { return terms.empty() || (terms.size() == 1 && terms.front().size() == 1 && terms.front().front()); } - // return true if the first OR-list term is an empty pattern+ // return true if the first ALT-list term is an empty pattern bool first_empty() const { return !terms.empty() && !terms.front().empty() && terms.front().front() && terms.front().front()->empty(); } - // add a new OR-list term to CNF AND-list+ // add a new ALT-list term to CNF AND-list void new_term() { if (terms.empty())@@ -113,22 +113,22 @@ class CNF { terms.emplace_back(); } - // add an OR pattern or OR-NOT pattern, optionally negated (option -N)+ // add an ALT pattern or ALT-NOT pattern, optionally negated (option -N) void new_pattern(PATTERN mask, const char *pattern); - // compile --bool search query into operator tree, normalize to CNF, and populate CNF AND-list of OR-term lists+ // compile --bool search query into operator tree, normalize to CNF, and populate CNF AND-list of ALT-term lists void compile(const char *pattern) { OpTree(pattern, terms); } - // return the CNF AND-list of OR-term lists+ // return the CNF AND-list of ALT-term lists const Terms& lists() const { return terms; } - // prune empty OR-terms and OR-terms with empty patterns that match anything+ // prune empty ALT-terms and ALT-terms with empty patterns that match anything void prune(); // split the patterns at newlines, when present@@ -137,10 +137,10 @@ class CNF { // report the CNF in readable form void report(FILE *output) const; - // return all OR-terms of the CNF adjoined+ // return all ALT-terms of the CNF adjoined std::string adjoin() const; - // return the first OR-terms of the CNF+ // return the first ALT-terms of the CNF std::string first() const; protected:@@ -152,7 +152,7 @@ class CNF { OpTree(Op op) : op(op) { } - // parse a pattern, normalize to CNF, and convert to a CNF AND-list of OR-term lists+ // parse a pattern, normalize to CNF, and convert to a CNF AND-list of ALT-term lists OpTree(const char *pattern, Terms& terms) { op = AND;@@ -177,7 +177,7 @@ class CNF { // normalize operator tree to CNF void normalize(bool invert = false); - // convert CNF-normalized operator tree to terms, a CNF AND-list of OR-term lists+ // convert CNF-normalized operator tree to terms, a CNF AND-list of ALT-term lists void convert(Terms& terms); // add a [NOT] term of the operator tree to terms@@ -186,7 +186,7 @@ class CNF { // skip space static void skip_space(const char *& pattern) {- while (isspace(static_cast<unsigned char>(*pattern)))+ while (*pattern != '\n' && isspace(static_cast<unsigned char>(*pattern))) ++pattern; } @@ -220,18 +220,20 @@ class CNF { return false; } - // return true if look ahead for a | or OR then return true when found and skip over it, otherwise return false+ // return true if at a |, \n or OR then return true when found and skip over it, otherwise return false static bool is_alternation(const char *& pattern) { const char *lookahead = pattern; skip_space(lookahead); - if (*lookahead != '|' && !is_oper(OR, lookahead))- return false;-- while (*lookahead == '|')+ if (*lookahead == '\n') ++lookahead;+ else if (*lookahead == '|')+ while (*++lookahead == '|')+ continue;+ else if (!is_oper(OR, lookahead))+ return false; skip_space(lookahead); @@ -302,7 +304,7 @@ class CNF { } } - // CNF terms, an AND-list of OR-term lists of string/NULL patterns+ // CNF terms, an AND-list of ALT-term lists of string/NULL patterns Terms terms; };
@@ -199,9 +199,9 @@ extern const char *flag_view; extern std::string flag_filter; extern std::string flag_hyperlink_prefix; // internal flag extern std::string flag_hyperlink_path; // internal flag+extern std::string flag_regexp; // internal flag extern std::set<std::string> flag_config_files; // internal flag extern std::set<std::string> flag_ignore_files;-extern std::vector<std::string> flag_regexp; extern std::vector<std::string> flag_file; extern std::vector<std::string> flag_file_type; extern std::vector<std::string> flag_file_extension;
@@ -77,7 +77,7 @@ class MMap { } // attempt to mmap the given file-based input, return true if successful with base and size- bool file(reflex::Input& input, const char*& base, size_t& size)+ bool file(reflex::Input& input, const char *& base, size_t& size) { base = NULL; size = 0;
@@ -888,39 +888,18 @@ void Query::query_ui() // if -e PATTERN specified, collect patterns on the line to edit if (!flag_regexp.empty()) {- std::string pattern;-- if (flag_regexp.size() == 1)- {- pattern = flag_regexp.front();- }- else- {- int sep = flag_fixed_strings && !flag_bool ? '\n' : '|';-- for (auto& regex : flag_regexp)- {- if (!regex.empty())- {- if (!pattern.empty())- pattern.push_back(sep);- pattern.append(regex);- }- }- }-- flag_regexp.clear();-- size_t num = pattern.size();+ size_t num = flag_regexp.size(); if (num >= sizeof(Line)) num = sizeof(Line) - 1; - pattern.copy(line_, num);+ flag_regexp.copy(line_, num); line_[num] = '\0'; len_ = line_len(); move(len_);++ flag_regexp.clear(); } set_prompt();
@@ -35,7 +35,7 @@ */ // DO NOT ALTER THIS LINE: updated by makemake.sh and we need it physically here for MSVC++ build from source-#define UGREP_VERSION "6.1.0"+#define UGREP_VERSION "6.2.0" // use a task-parallel thread to decompress the stream into a pipe to search, also handles nested archives #define WITH_DECOMPRESSION_THREAD
@@ -432,9 +432,9 @@ const char *flag_view = ""; std::string flag_filter; std::string flag_hyperlink_prefix; std::string flag_hyperlink_path;+std::string flag_regexp; std::set<std::string> flag_config_files; std::set<std::string> flag_ignore_files;-std::vector<std::string> flag_regexp; std::vector<std::string> flag_file; std::vector<std::string> flag_file_type; std::vector<std::string> flag_file_extension;@@ -691,7 +691,7 @@ inline bool getline(reflex::BufferedInput& input, std::string& line) } // read a line from mmap memory, returns true when eof-inline bool getline(const char*& here, size_t& left)+inline bool getline(const char *& here, size_t& left) { // read line from mmap memory if (left == 0)@@ -710,7 +710,7 @@ inline bool getline(const char*& here, size_t& left) } // read a line from mmap memory or from buffered input or from unbuffered input, returns true when eof-inline bool getline(const char*& here, size_t& left, reflex::BufferedInput& buffered_input, reflex::Input& input, std::string& line)+inline bool getline(const char *& here, size_t& left, reflex::BufferedInput& buffered_input, reflex::Input& input, std::string& line) { if (here != NULL) {@@ -2381,7 +2381,7 @@ struct Grep { // extend the reflex::AbstractMatcher::Handler with a grep object reference and references to some of the grep::search locals struct GrepHandler : public reflex::AbstractMatcher::Handler { - GrepHandler(Grep& grep, const char*& pathname, size_t& lineno, bool& heading, bool& binfile, bool& hex, bool& binary, size_t& matches, bool& stop)+ GrepHandler(Grep& grep, const char *& pathname, size_t& lineno, bool& heading, bool& binfile, bool& hex, bool& binary, size_t& matches, bool& stop) : grep(grep), pathname(pathname),@@ -2394,15 +2394,15 @@ struct Grep { stop(stop) { } - Grep& grep; // grep object- const char*& pathname; // grep::search argument pathname- size_t& lineno; // grep::search lineno local variable- bool& heading; // grep::search heading local variable- bool& binfile; // grep::search binfile local variable- bool& hex; // grep::search hex local variable- bool& binary; // grep::search binary local variable- size_t& matches; // grep::search matches local variable- bool& stop; // grep::search stop local variable+ Grep& grep; // grep object+ const char *& pathname; // grep::search argument pathname+ size_t& lineno; // grep::search lineno local variable+ bool& heading; // grep::search heading local variable+ bool& binfile; // grep::search binfile local variable+ bool& hex; // grep::search hex local variable+ bool& binary; // grep::search binary local variable+ size_t& matches; // grep::search matches local variable+ bool& stop; // grep::search stop local variable // define a reflex::AbstractMatcher functor to handle buffer shifts by moving restline string from the buffer to a temporary string buffer virtual void operator()(reflex::AbstractMatcher&, const char*, size_t, size_t) override@@ -2416,7 +2416,7 @@ struct Grep { } // get the start of the after/before context, if present- void begin_before(reflex::AbstractMatcher& matcher, const char *buf, size_t len, size_t num, const char*& ptr, size_t& size, size_t& offset)+ void begin_before(reflex::AbstractMatcher& matcher, const char *buf, size_t len, size_t num, const char *& ptr, size_t& size, size_t& offset) { ptr = NULL; size = 0;@@ -2456,7 +2456,7 @@ struct Grep { } // advance to the next before context, if present- void next_before(const char *buf, size_t len, size_t num, const char*& ptr, size_t& size, size_t& offset)+ void next_before(const char *buf, size_t len, size_t num, const char *& ptr, size_t& size, size_t& offset) { if (ptr == NULL) return;@@ -2489,7 +2489,7 @@ struct Grep { // extend event GrepHandler to output invert match lines for -v struct InvertMatchGrepHandler : public GrepHandler { - InvertMatchGrepHandler(Grep& grep, const char*& pathname, size_t& lineno, bool& heading, bool& binfile, bool& hex, bool& binary, size_t& matches, bool& stop)+ InvertMatchGrepHandler(Grep& grep, const char *& pathname, size_t& lineno, bool& heading, bool& binfile, bool& hex, bool& binary, size_t& matches, bool& stop) : GrepHandler(grep, pathname, lineno, heading, binfile, hex, binary, matches, stop) { }@@ -2571,7 +2571,7 @@ struct Grep { // extend event GrepHandler to output formatted invert match lines for --format -v struct FormatInvertMatchGrepHandler : public GrepHandler { - FormatInvertMatchGrepHandler(Grep& grep, const char*& pathname, size_t& lineno, bool& heading, bool& binfile, bool& hex, bool& binary, size_t& matches, bool& stop)+ FormatInvertMatchGrepHandler(Grep& grep, const char *& pathname, size_t& lineno, bool& heading, bool& binfile, bool& hex, bool& binary, size_t& matches, bool& stop) : GrepHandler(grep, pathname, lineno, heading, binfile, hex, binary, matches, stop) { }@@ -2630,7 +2630,7 @@ struct Grep { // extend event GrepHandler to output any context lines for -y struct AnyLineGrepHandler : public GrepHandler { - AnyLineGrepHandler(Grep& grep, const char*& pathname, size_t& lineno, bool& heading, bool& binfile, bool& hex, bool& binary, size_t& matches, bool& stop)+ AnyLineGrepHandler(Grep& grep, const char *& pathname, size_t& lineno, bool& heading, bool& binfile, bool& hex, bool& binary, size_t& matches, bool& stop) : GrepHandler(grep, pathname, lineno, heading, binfile, hex, binary, matches, stop) { }@@ -2800,7 +2800,7 @@ struct Grep { }; - ContextGrepHandler(Grep& grep, const char*& pathname, size_t& lineno, bool& heading, bool& binfile, bool& hex, bool& binary, size_t& matches, bool& stop)+ ContextGrepHandler(Grep& grep, const char *& pathname, size_t& lineno, bool& heading, bool& binfile, bool& hex, bool& binary, size_t& matches, bool& stop) : AnyLineGrepHandler(grep, pathname, lineno, heading, binfile, hex, binary, matches, stop) { }@@ -3090,7 +3090,7 @@ struct Grep { }; - InvertContextGrepHandler(Grep& grep, const char*& pathname, size_t& lineno, bool& heading, bool& binfile, bool& hex, bool& binary, size_t& matches, bool& stop)+ InvertContextGrepHandler(Grep& grep, const char *& pathname, size_t& lineno, bool& heading, bool& binfile, bool& hex, bool& binary, size_t& matches, bool& stop) : AnyLineGrepHandler(grep, pathname, lineno, heading, binfile, hex, binary, matches, stop) { }@@ -4726,7 +4726,7 @@ int main(int argc, const char **argv) } // set -1,...,-9,-10,... recursion depth flags-static void set_depth(const char*& arg)+static void set_depth(const char *& arg) { const char *range = arg; char *rest = NULL;@@ -6112,24 +6112,7 @@ void options(std::list<std::pair<CNF::PATTERN,const char*>>& pattern_args, int a // parse -e PATTERN and -N PATTERN void option_regexp(std::list<std::pair<CNF::PATTERN,const char*>>& pattern_args, const char *arg, bool is_neg) {- if (flag_query)- {- // -Q: pass -e PATTERN and -N PATTERN patterns to the query engine- if (is_neg)- {- std::string neg_arg(arg);- neg_arg.insert(0, "(?^").append(")");- flag_regexp.emplace_back(neg_arg);- }- else- {- flag_regexp.emplace_back(arg);- }- }- else- {- pattern_args.emplace_back((flag_not ? CNF::PATTERN::NOT : CNF::PATTERN::NA) | (is_neg ? CNF::PATTERN::NEG : CNF::PATTERN::NA), arg);- }+ pattern_args.emplace_back((flag_not ? CNF::PATTERN::NOT : CNF::PATTERN::ALT) | (is_neg ? CNF::PATTERN::NEG : CNF::PATTERN::ALT), arg); } // parse --and [PATTERN]@@ -6138,13 +6121,10 @@ void option_and(std::list<std::pair<CNF::PATTERN,const char*>>& pattern_args, in if (flag_not) usage("missing PATTERN for --not"); - if (flag_query)- usage("option -Q does not support --and");-- pattern_args.emplace_back(CNF::PATTERN::TERM, "");+ pattern_args.emplace_back(CNF::PATTERN::AND, ""); if (i + 1 < argc && *argv[i + 1] != '-')- pattern_args.emplace_back((flag_not ? CNF::PATTERN::NOT : CNF::PATTERN::NA), argv[++i]);+ pattern_args.emplace_back((flag_not ? CNF::PATTERN::NOT : CNF::PATTERN::ALT), argv[++i]); } // parse --and=PATTERN@@ -6153,11 +6133,8 @@ void option_and(std::list<std::pair<CNF::PATTERN,const char*>>& pattern_args, co if (flag_not) usage("missing PATTERN for --not"); - if (flag_query)- usage("option -Q does not support --and");-- pattern_args.emplace_back(CNF::PATTERN::TERM, "");- pattern_args.emplace_back((flag_not ? CNF::PATTERN::NOT : CNF::PATTERN::NA), arg);+ pattern_args.emplace_back(CNF::PATTERN::AND, "");+ pattern_args.emplace_back((flag_not ? CNF::PATTERN::NOT : CNF::PATTERN::ALT), arg); } // parse --andnot [PATTERN]@@ -6166,10 +6143,7 @@ void option_andnot(std::list<std::pair<CNF::PATTERN,const char*>>& pattern_args, if (flag_not) usage("missing PATTERN for --not"); - if (flag_query)- usage("option -Q does not support --andnot");-- pattern_args.emplace_back(CNF::PATTERN::TERM, "");+ pattern_args.emplace_back(CNF::PATTERN::AND, ""); flag_not = true; @@ -6186,24 +6160,18 @@ void option_andnot(std::list<std::pair<CNF::PATTERN,const char*>>& pattern_args, if (flag_not) usage("missing PATTERN for --not"); - if (flag_query)- usage("option -Q does not support --andnot");-- pattern_args.emplace_back(CNF::PATTERN::TERM, "");+ pattern_args.emplace_back(CNF::PATTERN::AND, ""); pattern_args.emplace_back(CNF::PATTERN::NOT, arg); } // parse --not [PATTERN] void option_not(std::list<std::pair<CNF::PATTERN,const char*>>& pattern_args, int& i, int argc, const char **argv) {- if (flag_query)- usage("option -Q does not support --not");- flag_not = !flag_not; if (i + 1 < argc && *argv[i + 1] != '-') {- pattern_args.emplace_back((flag_not ? CNF::PATTERN::NOT : CNF::PATTERN::NA), argv[++i]);+ pattern_args.emplace_back((flag_not ? CNF::PATTERN::NOT : CNF::PATTERN::ALT), argv[++i]); flag_not = false; } }@@ -6211,12 +6179,9 @@ void option_not(std::list<std::pair<CNF::PATTERN,const char*>>& pattern_args, in // parse --not=PATTERN void option_not(std::list<std::pair<CNF::PATTERN,const char*>>& pattern_args, const char *arg) {- if (flag_query)- usage("option -Q does not support --not");- flag_not = !flag_not; - pattern_args.emplace_back((flag_not ? CNF::PATTERN::NOT : CNF::PATTERN::NA), arg);+ pattern_args.emplace_back((flag_not ? CNF::PATTERN::NOT : CNF::PATTERN::ALT), arg); flag_not = false; } @@ -6411,7 +6376,7 @@ void init(int argc, const char **argv) flag_basic_regexp = false; if (flag_fuzzy > 0) usage("options -P and -Z are not compatible");- for (const auto &arg : pattern_args)+ for (const auto& arg : pattern_args) if ((arg.first & CNF::PATTERN::NEG) != 0) usage("options -P and -N are not compatible"); #else@@ -6431,22 +6396,60 @@ void init(int argc, const char **argv) if (flag_fixed_strings) flag_basic_regexp = false; - // populate the CNF with the collected regex pattern args, each arg points to a persistent command line argv[]- for (const auto &arg : pattern_args)+ // -e, -N, --and, --andnot, --not+ if (!pattern_args.empty()) {- if (arg.first == CNF::PATTERN::TERM)- Static::bcnf.new_term();+ if (flag_bool || flag_query)+ {+ // -Q: if --and, --andnot or --not specified then switch to bool mode, -F can't work with -N+ for (const auto& arg : pattern_args)+ {+ if (arg.first == CNF::PATTERN::AND || arg.first == CNF::PATTERN::NOT)+ flag_bool = true;+ else if (arg.first == CNF::PATTERN::NEG && flag_fixed_strings)+ usage("option -F with -% or -Q does not support -N PATTERN");+ }++ // -%: collect -e, --and, --andnot, --not patterns+ const char *lparen = flag_bool ? "(" : "";+ const char *rparen = flag_bool ? ")" : "";+ bool sep = false;++ for (const auto& arg : pattern_args)+ {+ if (sep)+ flag_regexp.append(arg.first == CNF::PATTERN::AND ? " " : "\n");+ sep = true;+ if (arg.first == CNF::PATTERN::ALT)+ flag_regexp.append(lparen).append(arg.second).append(rparen);+ else if (arg.first == CNF::PATTERN::NEG && *arg.second != '\0')+ flag_regexp.append("(?^").append(arg.second).append(")");+ else if (arg.first == CNF::PATTERN::NOT && *arg.second != '\0')+ flag_regexp.append("-(").append(arg.second).append(")");+ else+ sep = false;+ }++ if (!flag_query)+ Static::bcnf.new_pattern(CNF::PATTERN::ALT, flag_regexp.c_str());+ } else- Static::bcnf.new_pattern(arg.first, arg.second); // relies on options --bool, -F, -G, -w, -x and -f+ {+ // populate the CNF with the collected pattern args, each arg points to a persistent command line argv[]+ for (const auto& arg : pattern_args)+ {+ if (arg.first == CNF::PATTERN::AND)+ Static::bcnf.new_term();+ else+ Static::bcnf.new_pattern(arg.first, arg.second);+ }+ } } // --query: override --pager if (flag_query) flag_pager = NULL; - if (flag_query && !pattern_args.empty())- usage("-e PATTERN and -N PATTERN should be specified after option -Q");- // --tree: require sort to produce directory tree if (flag_tree && flag_sort == NULL) flag_sort = "name";@@ -7490,50 +7493,72 @@ void terminal() char *env_grep_colors = NULL; dupenv_s(&env_grep_colors, "GREP_COLORS"); const char *grep_colors = env_grep_colors;+ std::string deprecated_grep_colors; - // if GREP_COLOR is defined but not GREP_COLORS, use it to set mt= default value (overridden by GREP_COLORS mt=, ms=, mc=)+ // if GREP_COLOR is defined but not GREP_COLORS, use it if (env_grep_colors == NULL && env_grep_color != NULL)- set_color(std::string("mt=").append(env_grep_color).c_str(), "mt=", color_mt);+ grep_colors = env_grep_color; else if (grep_colors == NULL) grep_colors = DEFAULT_GREP_COLORS; + // parse deprecated GREP_COLOR format with ANSI SGR codes for matched text only+ if (grep_colors != NULL && strchr(grep_colors, '=') == NULL)+ {+ // use default colors then override matched text color with the specified color+ deprecated_grep_colors.assign(grep_colors);+ grep_colors = DEFAULT_GREP_COLORS;+ }+ // parse GREP_COLORS- set_color(grep_colors, "sl=", color_sl); // selected line- set_color(grep_colors, "cx=", color_cx); // context line- set_color(grep_colors, "mt=", color_mt); // matched text in any line- set_color(grep_colors, "ms=", color_ms); // matched text in selected line- set_color(grep_colors, "mc=", color_mc); // matched text in a context line- set_color(grep_colors, "fn=", color_fn); // file name- set_color(grep_colors, "ln=", color_ln); // line number- set_color(grep_colors, "cn=", color_cn); // column number- set_color(grep_colors, "bn=", color_bn); // byte offset- set_color(grep_colors, "se=", color_se); // separator-- set_color(grep_colors, "qp=", color_qp); // TUI prompt- set_color(grep_colors, "qe=", color_qe); // TUI errors- set_color(grep_colors, "qr=", color_qr); // TUI regex highlight- set_color(grep_colors, "qm=", color_qm); // TUI regex meta characters highlight- set_color(grep_colors, "ql=", color_ql); // TUI regex lists and literals highlight- set_color(grep_colors, "qb=", color_qb); // TUI regex braces highlight+ if (grep_colors != NULL)+ {+ set_color(grep_colors, "sl=", color_sl); // selected line+ set_color(grep_colors, "cx=", color_cx); // context line+ set_color(grep_colors, "mt=", color_mt); // matched text in any line+ set_color(grep_colors, "ms=", color_ms); // matched text in selected line+ set_color(grep_colors, "mc=", color_mc); // matched text in a context line+ set_color(grep_colors, "fn=", color_fn); // file name+ set_color(grep_colors, "ln=", color_ln); // line number+ set_color(grep_colors, "cn=", color_cn); // column number+ set_color(grep_colors, "bn=", color_bn); // byte offset+ set_color(grep_colors, "se=", color_se); // separator+ set_color(grep_colors, "qp=", color_qp); // TUI prompt+ set_color(grep_colors, "qe=", color_qe); // TUI errors+ set_color(grep_colors, "qr=", color_qr); // TUI regex highlight+ set_color(grep_colors, "qm=", color_qm); // TUI regex meta characters highlight+ set_color(grep_colors, "ql=", color_ql); // TUI regex lists and literals highlight+ set_color(grep_colors, "qb=", color_qb); // TUI regex braces highlight+ }++ // deprecated GREP_COLOR format with ANSI SGR codes for matched text only+ if (!deprecated_grep_colors.empty())+ set_color(deprecated_grep_colors.c_str(), "", color_ms); // parse --colors to override GREP_COLORS- set_color(flag_colors, "sl=", color_sl); // selected line- set_color(flag_colors, "cx=", color_cx); // context line- set_color(flag_colors, "mt=", color_mt); // matched text in any line- set_color(flag_colors, "ms=", color_ms); // matched text in selected line- set_color(flag_colors, "mc=", color_mc); // matched text in a context line- set_color(flag_colors, "fn=", color_fn); // file name- set_color(flag_colors, "ln=", color_ln); // line number- set_color(flag_colors, "cn=", color_cn); // column number- set_color(flag_colors, "bn=", color_bn); // byte offset- set_color(flag_colors, "se=", color_se); // separator-- set_color(flag_colors, "qp=", color_qp); // TUI prompt- set_color(flag_colors, "qe=", color_qe); // TUI errors- set_color(flag_colors, "qr=", color_qr); // TUI regex highlight- set_color(flag_colors, "qm=", color_qm); // TUI regex meta characters highlight- set_color(flag_colors, "ql=", color_ql); // TUI regex lists and literals highlight- set_color(flag_colors, "qb=", color_qb); // TUI regex braces highlight+ if (flag_colors != NULL && strchr(flag_colors, '=') == NULL)+ {+ // deprecated format with ANSI SGR codes only+ set_color(flag_colors, "", color_mt); // matched text in any line+ }+ else if (flag_colors != NULL)+ {+ set_color(flag_colors, "sl=", color_sl); // selected line+ set_color(flag_colors, "cx=", color_cx); // context line+ set_color(flag_colors, "mt=", color_mt); // matched text in any line+ set_color(flag_colors, "ms=", color_ms); // matched text in selected line+ set_color(flag_colors, "mc=", color_mc); // matched text in a context line+ set_color(flag_colors, "fn=", color_fn); // file name+ set_color(flag_colors, "ln=", color_ln); // line number+ set_color(flag_colors, "cn=", color_cn); // column number+ set_color(flag_colors, "bn=", color_bn); // byte offset+ set_color(flag_colors, "se=", color_se); // separator+ set_color(flag_colors, "qp=", color_qp); // TUI prompt+ set_color(flag_colors, "qe=", color_qe); // TUI errors+ set_color(flag_colors, "qr=", color_qr); // TUI regex highlight+ set_color(flag_colors, "qm=", color_qm); // TUI regex meta characters highlight+ set_color(flag_colors, "ql=", color_ql); // TUI regex lists and literals highlight+ set_color(flag_colors, "qb=", color_qb); // TUI regex braces highlight+ } // -v: if rv in GREP_COLORS then swap the sl and cx colors (note that rv does not match color letters) if (flag_invert_match &&@@ -7940,7 +7965,7 @@ void ugrep() // add PATTERN to the CNF if (Static::arg_pattern != NULL)- Static::bcnf.new_pattern(CNF::PATTERN::NA, Static::arg_pattern);+ Static::bcnf.new_pattern(CNF::PATTERN::ALT, Static::arg_pattern); // the regex compiled from PATTERN, -e PATTERN, -N PATTERN, and -f FILE std::string regex;@@ -8456,8 +8481,10 @@ void ugrep() { // -P: Perl matching with PCRE2 or Boost.Regex #if defined(HAVE_PCRE2)- // construct the PCRE2 JIT-optimized NFA-based Perl pattern matcher+ // construct the PCRE2 JIT-optimized Perl pattern matcher uint32_t options = flag_binary ? (PCRE2_NEVER_UTF | PCRE2_NEVER_UCP) : (PCRE2_UTF | PCRE2_UCP);+ if (!Static::bcnf.singleton_or_undefined())+ options |= PCRE2_DUPNAMES; Static::string_pattern.assign(flag_binary ? reflex::PCRE2Matcher::convert(regex, convert_flags, &flag_multiline) : reflex::PCRE2UTFMatcher::convert(regex, convert_flags, &flag_multiline)); Static::matcher = std::unique_ptr<reflex::AbstractMatcher>(new reflex::PCRE2Matcher(Static::string_pattern, reflex::Input(), matcher_options.c_str(), options)); Static::matchers.clear();@@ -8505,7 +8532,7 @@ void ugrep() #elif defined(HAVE_BOOST_REGEX) try {- // construct the Boost.Regex NFA-based Perl pattern matcher+ // construct the Boost.Regex Perl pattern matcher Static::string_pattern.assign(reflex::BoostPerlMatcher::convert(regex, convert_flags, &flag_multiline)); Static::matcher = std::unique_ptr<reflex::AbstractMatcher>(new reflex::BoostPerlMatcher(Static::string_pattern, reflex::Input(), matcher_options.c_str())); Static::matchers.clear();@@ -13425,160 +13452,157 @@ void trim_pathname_arg(const char *arg) // convert GREP_COLORS and set the color substring to the ANSI SGR codes void set_color(const char *colors, const char *parameter, char color[COLORLEN]) {- if (colors != NULL)- {- const char *s = strstr(colors, parameter);+ const char *s = strstr(colors, parameter); - // check if substring parameter is present in colors- if (s != NULL)- {- s += 3;- char *t = color + 2;+ // check if substring parameter is present in colors+ if (s != NULL)+ {+ s += strlen(parameter);+ char *t = color + 2; #ifdef WITH_EASY_GREP_COLORS - // foreground colors: k=black, r=red, g=green, y=yellow b=blue, m=magenta, c=cyan, w=white- // background colors: K=black, R=red, G=green, Y=yellow B=blue, M=magenta, C=cyan, W=white- // bright colors: +k, +r, +g, +y, +b, +m, +c, +w, +K, +R, +G, +Y, +B, +M, +C, +W- // modifiers: h=highlight, u=underline, i=invert, f=faint, n=normal, H=highlight off, U=underline off, I=invert off- // semicolons are not required and abbreviations can be mixed with numeric ANSI SGR codes+ // foreground colors: k=black, r=red, g=green, y=yellow b=blue, m=magenta, c=cyan, w=white+ // background colors: K=black, R=red, G=green, Y=yellow B=blue, M=magenta, C=cyan, W=white+ // bright colors: +k, +r, +g, +y, +b, +m, +c, +w, +K, +R, +G, +Y, +B, +M, +C, +W+ // modifiers: h=highlight, u=underline, i=invert, f=faint, n=normal, H=highlight off, U=underline off, I=invert off+ // semicolons are not required and abbreviations can be mixed with numeric ANSI SGR codes - uint8_t offset = 30;- bool sep = false;+ uint8_t offset = 30;+ bool sep = false; - while (*s != '\0' && *s != ':' && t - color < COLORLEN - 6)+ while (*s != '\0' && *s != ':' && t - color < COLORLEN - 6)+ {+ if (isdigit(static_cast<unsigned char>(*s))) {- if (isdigit(static_cast<unsigned char>(*s)))+ if (sep)+ *t++ = ';';+ if (offset == 90) {- if (sep)- *t++ = ';';- if (offset == 90)- {- *t++ = '1';- *t++ = ';';- offset = 30;- }- *t++ = *s++;- while (isdigit(static_cast<unsigned char>(*s)) && t - color < COLORLEN - 2)- *t++ = *s++;- sep = true;- continue;- }-- if (*s == '+')- {- offset = 90;- }- else if (*s == 'n')- {- if (sep)- *t++ = ';';- *t++ = '0';- sep = true;- }- else if (*s == 'h')- {- if (sep)- *t++ = ';';- *t++ = '1';- sep = true;- }- else if (*s == 'H')- {- if (sep)- *t++ = ';';- *t++ = '2'; *t++ = '1';+ *t++ = ';'; offset = 30;- sep = true; }- else if (*s == 'f')- {- if (sep)- *t++ = ';';- *t++ = '2';- sep = true;- }- else if (*s == 'u')- {- if (sep)- *t++ = ';';- *t++ = '4';- sep = true;- }- else if (*s == 'U')- {- if (sep)- *t++ = ';';- *t++ = '2';- *t++ = '4';- sep = true;- }- else if (*s == 'i')- {- if (sep)- *t++ = ';';- *t++ = '7';- sep = true;- }- else if (*s == 'I')- {- if (sep)- *t++ = ';';- *t++ = '2';- *t++ = '7';- sep = true;- }- else if (*s == ',' || *s == ';' || isspace(static_cast<unsigned char>(*s)))+ *t++ = *s++;+ while (isdigit(static_cast<unsigned char>(*s)) && t - color < COLORLEN - 2)+ *t++ = *s++;+ sep = true;+ continue;+ }++ if (*s == '+')+ {+ offset = 90;+ }+ else if (*s == 'n')+ {+ if (sep)+ *t++ = ';';+ *t++ = '0';+ sep = true;+ }+ else if (*s == 'h')+ {+ if (sep)+ *t++ = ';';+ *t++ = '1';+ sep = true;+ }+ else if (*s == 'H')+ {+ if (sep)+ *t++ = ';';+ *t++ = '2';+ *t++ = '1';+ offset = 30;+ sep = true;+ }+ else if (*s == 'f')+ {+ if (sep)+ *t++ = ';';+ *t++ = '2';+ sep = true;+ }+ else if (*s == 'u')+ {+ if (sep)+ *t++ = ';';+ *t++ = '4';+ sep = true;+ }+ else if (*s == 'U')+ {+ if (sep)+ *t++ = ';';+ *t++ = '2';+ *t++ = '4';+ sep = true;+ }+ else if (*s == 'i')+ {+ if (sep)+ *t++ = ';';+ *t++ = '7';+ sep = true;+ }+ else if (*s == 'I')+ {+ if (sep)+ *t++ = ';';+ *t++ = '2';+ *t++ = '7';+ sep = true;+ }+ else if (*s == ',' || *s == ';' || isspace(static_cast<unsigned char>(*s)))+ {+ if (sep)+ *t++ = ';';+ sep = false;+ }+ else+ {+ const char *c = "krgybmcw KRGYBMCW";+ const char *k = strchr(c, *s);++ if (k != NULL) { if (sep) *t++ = ';';- sep = false;- }- else- {- const char *c = "krgybmcw KRGYBMCW";- const char *k = strchr(c, *s);-- if (k != NULL)+ uint8_t n = offset + static_cast<uint8_t>(k - c);+ if (n >= 100) {- if (sep)- *t++ = ';';- uint8_t n = offset + static_cast<uint8_t>(k - c);- if (n >= 100)- {- *t++ = '1';- n -= 100;- }- *t++ = '0' + n / 10;- *t++ = '0' + n % 10;- offset = 30;- sep = true;+ *t++ = '1';+ n -= 100; }+ *t++ = '0' + n / 10;+ *t++ = '0' + n % 10;+ offset = 30;+ sep = true; }-- ++s; } + ++s;+ }+ #else - // traditional grep SGR parameters- while ((*s == ';' || isdigit(static_cast<unsigned char>(*s))) && t - color < COLORLEN - 2)- *t++ = *s++;+ // traditional grep SGR parameters+ while ((*s == ';' || isdigit(static_cast<unsigned char>(*s))) && t - color < COLORLEN - 2)+ *t++ = *s++; #endif - if (t > color + 2)- {- color[0] = '\033';- color[1] = '[';- *t++ = 'm';- *t++ = '\0';- }- else- {- color[0] = '\0';- }+ if (t > color + 2)+ {+ color[0] = '\033';+ color[1] = '[';+ *t++ = 'm';+ *t++ = '\0';+ }+ else+ {+ color[0] = '\0'; } } }@@ -13900,11 +13924,10 @@ void help(std::ostream& out) the default.\n\ -e PATTERN, --regexp=PATTERN\n\ Specify a PATTERN to search the input. An input line is selected\n\- if it matches any of the specified patterns. Note that longer\n\- patterns take precedence over shorter patterns. This option is\n\- most useful when multiple -e options are used to specify multiple\n\- patterns, when a pattern begins with a dash (`-'), to specify a\n\- pattern after option -f or after the FILE arguments.\n\+ if it matches any of the specified patterns. This option is useful\n\+ when multiple -e options are used to specify multiple patterns, or\n\+ when a pattern begins with a dash (`-'), or to specify a pattern\n\+ after option -f or after the FILE arguments.\n\ --encoding=ENCODING\n\ The encoding format of the input. The default ENCODING is binary\n\ and UTF-8 which are the same. Note that option -U specifies binary\n\
@@ -38,7 +38,7 @@ #define UGREP_HPP // DO NOT ALTER THIS LINE: updated by makemake.sh and we need it physically here for MSVC++ build from source-#define UGREP_VERSION "6.1.0"+#define UGREP_VERSION "6.2.0" // disable mmap because mmap is almost always slower than the file reading speed improvements since 3.0.0 #define WITH_NO_MMAP