@ 260915.5

240709.1 · 148290c57acccc914dfe9ab1b42760961a09c918

released 6.2.0

fix #407 fix #408 update #409

reading declarations

README.md

@@ -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) 

bin/README.md

@@ -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

deleted file mode 100644@@ -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

deleted file mode 100755Binary file changed

bin/linux_amd64/ugrep-indexer

deleted file mode 100755Binary file changed

bin/linux_arm64/README.md

deleted file mode 100644@@ -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

deleted file mode 100755Binary file changed

bin/linux_arm64/ugrep-indexer

deleted file mode 100755Binary file changed

bin/win32/ug.exe

Binary file changed

bin/win32/ugrep-indexer.exe

Binary file changed

bin/win32/ugrep.exe

Binary file changed

bin/win64/ug.exe

Binary file changed

bin/win64/ugrep-indexer.exe

Binary file changed

bin/win64/ugrep.exe

Binary file changed

completions/zsh/_ug

@@ -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]'

completions/zsh/_ug+

@@ -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]'

completions/zsh/_ugrep

@@ -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]'

completions/zsh/_ugrep+

@@ -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]'

completions/zsh/compgen.sh

@@ -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)/" \

configure

@@ -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\\" 

configure.ac

@@ -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.])

include/reflex/pattern.h

@@ -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)

include/reflex/pcre2matcher.h

@@ -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()

include/reflex/simd.h

@@ -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 

lib/error.cpp

@@ -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;

lib/input.cpp

@@ -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

lib/matcher.cpp

@@ -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;

lib/matcher_avx2.cpp

@@ -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;

lib/matcher_avx512bw.cpp

@@ -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;

lib/pattern.cpp

@@ -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)     {

lib/simd_avx2.cpp

@@ -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;

lib/simd_avx512bw.cpp

@@ -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;

man.sh

@@ -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

man/ug.1

@@ -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

man/ugrep-indexer.1

@@ -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

man/ugrep.1

@@ -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

src/cnf.cpp

@@ -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())

src/cnf.hpp

@@ -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;  };

src/flag.hpp

@@ -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;

src/mmap.hpp

@@ -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;

src/query.cpp

@@ -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();

src/ugrep-indexer.cpp

@@ -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

src/ugrep.cpp

@@ -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\

src/ugrep.hpp

@@ -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