Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package ugrep for openSUSE:Factory checked 
in at 2022-05-12 22:59:30
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/ugrep (Old)
 and      /work/SRC/openSUSE:Factory/.ugrep.new.1538 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "ugrep"

Thu May 12 22:59:30 2022 rev:26 rq:976256 version:3.7.11

Changes:
--------
--- /work/SRC/openSUSE:Factory/ugrep/ugrep.changes      2022-05-10 
15:12:37.319622348 +0200
+++ /work/SRC/openSUSE:Factory/.ugrep.new.1538/ugrep.changes    2022-05-12 
22:59:59.548767167 +0200
@@ -1,0 +2,7 @@
+Wed May 11 04:22:53 UTC 2022 - Andreas Stieger <andreas.stie...@gmx.de>
+
+- update to 3.7.11:
+  * New -Zbest (--fuzzy=best) option argument best to only output
+    the best matching patterns
+
+-------------------------------------------------------------------

Old:
----
  ugrep-3.7.10.tar.gz

New:
----
  ugrep-3.7.11.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ ugrep.spec ++++++
--- /var/tmp/diff_new_pack.Uf8hNb/_old  2022-05-12 23:00:00.092767897 +0200
+++ /var/tmp/diff_new_pack.Uf8hNb/_new  2022-05-12 23:00:00.096767903 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           ugrep
-Version:        3.7.10
+Version:        3.7.11
 Release:        0
 Summary:        Universal grep: a feature-rich grep implementation with focus 
on speed
 License:        BSD-3-Clause

++++++ ugrep-3.7.10.tar.gz -> ugrep-3.7.11.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ugrep-3.7.10/README.md new/ugrep-3.7.11/README.md
--- old/ugrep-3.7.10/README.md  2022-05-08 19:23:13.000000000 +0200
+++ new/ugrep-3.7.11/README.md  2022-05-10 18:52:02.000000000 +0200
@@ -1617,9 +1617,9 @@
             If the standard input is searched, the string ``(standard input)''
             is written.
     -N PATTERN, --neg-regexp=PATTERN
-            Specify a negative PATTERN used during the search of the input:
-            an input line is selected only if it matches any of the specified
-            patterns unless a subpattern of PATTERN.  Same as -e (?^PATTERN).
+            Specify a negative PATTERN used during the search of the input: an
+            input line is selected only if it matches the specified patterns
+            unless it matches the negative PATTERN.  Same as -e (?^PATTERN).
             Negative pattern matches are essentially removed before any other
             patterns are matched.  Note that longer patterns take precedence
             over shorter patterns.  This option may be repeated.
@@ -2263,16 +2263,19 @@
 
 ### Fuzzy search with -Z
 
-    -Z[+-~][MAX], --fuzzy=[+-~][MAX]
+    -Z[best][+-~][MAX], --fuzzy=[best][+-~][MAX]
             Fuzzy mode: report approximate pattern matches within MAX errors.
             The default is -Z1: one deletion, insertion or substitution is
             allowed.  If `+`, `-' and/or `~' is specified, then `+' allows
             insertions, `-' allows deletions and `~' allows substitutions.  For
             example, -Z+~3 allows up to three insertions or substitutions, but
-            no deletions.  The first character of an approximate match always
+            no deletions.  If `best' is specified, then only the best matching
+            lines are output with the lowest cost per file.  Option -Zbest
+            requires two passes over a file and cannot be used with standard
+            input or Boolean queries.  Option --sort=best orders matching files
+            by best match.  The first character of an approximate match always
             matches the start of a pattern.  Option -U applies fuzzy matching
-            to bytes.  Option --sort=best orders matching files by best match.
-            No whitespace may be given between -Z and its argument.
+            to bytes.  No whitespace may be given between -Z and its argument.
 
 The beginning of a pattern always matches the first character of an approximate
 match as a practical strategy to prevent many false "randomized" matches for
@@ -4301,8 +4304,8 @@
 
            -N PATTERN, --neg-regexp=PATTERN
                   Specify a negative PATTERN used during the search of the  
input:
-                  an  input  line is selected only if it matches any of the 
speci-
-                  fied patterns unless  a  subpattern  of  PATTERN.   Same  as 
 -e
+                  an  input line is selected only if it matches the specified 
pat-
+                  terns unless it  matches  the  negative  PATTERN.   Same  as 
 -e
                   (?^PATTERN).   Negative  pattern matches are essentially 
removed
                   before any other patterns are matched.  Note  that  longer  
pat-
                   terns take precedence over shorter patterns.  This option 
may be
@@ -4437,10 +4440,10 @@
                   Displays  matching files in the order specified by KEY in 
recur-
                   sive searches.  KEY can be `name' to sort by pathname 
(default),
                   `best'  to sort by best match with option -Z (sort by best 
match
-                  requires two passes over the input files),  `size'  to  sort 
 by
-                  file size, `used' to sort by last access time, `changed' to 
sort
-                  by last modification time and  `created'  to  sort  by  
creation
-                  time.   Sorting  is  reversed  with  `rname',  `rbest', 
`rsize',
+                  requires two passes over files, which is expensive),  `size' 
 to
+                  sort by file size, `used' to sort by last access time, 
`changed'
+                  to sort by last modification time and `created' to sort by  
cre-
+                  ation time.  Sorting is reversed with `rname', `rbest', 
`rsize',
                   `rused', `rchanged', or `rcreated'.  Archive  contents  are  
not
                   sorted.   Subdirectories are sorted and displayed after 
matching
                   files.  FILE arguments are searched in the same order as  
speci-
@@ -4554,61 +4557,64 @@
                   Any line is output (passthru).  Non-matching lines are 
output as
                   context with a `-' separator.  See also options -A, -B and 
-C.
 
-           -Z[+-~][MAX], --fuzzy=[+-~][MAX]
+           -Z[best][+-~][MAX], --fuzzy=[best][+-~][MAX]
                   Fuzzy  mode:  report  approximate  pattern  matches  within  
MAX
                   errors.   The default is -Z1: one deletion, insertion or 
substi-
                   tution is allowed.  If `+`, `-' and/or `~'  is  specified,  
then
                   `+'  allows insertions, `-' allows deletions and `~' allows 
sub-
                   stitutions.  For example, -Z+~3 allows up to three 
insertions or
-                  substitutions,  but  no  deletions.   The  first character 
of an
-                  approximate match always matches the start of a pattern.  
Option
-                  -U  applies  fuzzy matching to bytes.  Option --sort=best 
orders
-                  matching files by  best  match.   No  whitespace  may  be  
given
-                  between -Z and its argument.
+                  substitutions,  but  no deletions.  If `best' is specified, 
then
+                  only the best matching lines are output with the lowest cost 
per
+                  file.   Option -Zbest requires two passes over a file and 
cannot
+                  be  used  with  standard  input  or  Boolean  queries.    
Option
+                  --sort=best  orders  matching  files  by  best match.  The 
first
+                  character of an approximate match always matches the start 
of  a
+                  pattern.   Option -U applies fuzzy matching to bytes.  No 
white-
+                  space may be given between -Z and its argument.
 
            -z, --decompress
-                  Decompress  files  to search, when compressed.  Archives 
(.cpio,
-                  .pax, .tar and .zip) and compressed archives (e.g.  .taz,  
.tgz,
-                  .tpz,  .tbz,  .tbz2, .tb2, .tz2, .tlz, .txz, .tzst) are 
searched
-                  and matching pathnames  of  files  in  archives  are  output 
 in
-                  braces.   If  -g,  -O,  -M,  or  -t is specified, searches 
files
-                  stored in archives whose filenames match globs,  match  
filename
-                  extensions,  match  file  signature  magic  bytes, or match 
file
+                  Decompress files to search, when compressed.   Archives  
(.cpio,
+                  .pax,  .tar  and .zip) and compressed archives (e.g. .taz, 
.tgz,
+                  .tpz, .tbz, .tbz2, .tb2, .tz2, .tlz, .txz, .tzst)  are  
searched
+                  and  matching  pathnames  of  files  in  archives  are 
output in
+                  braces.  If -g, -O, -M,  or  -t  is  specified,  searches  
files
+                  stored  in  archives whose filenames match globs, match 
filename
+                  extensions, match file signature  magic  bytes,  or  match  
file
                   types, respectively.  Supported compression formats: gzip 
(.gz),
-                  compress  (.Z),  zip,  bzip2 (requires suffix .bz, .bz2, 
.bzip2,
-                  .tbz, .tbz2, .tb2, .tz2), lzma and xz  (requires  suffix  
.lzma,
-                  .tlz,  .xz,  .txz),  lz4  (requires suffix .lz4), zstd 
(requires
+                  compress (.Z), zip, bzip2 (requires suffix  .bz,  .bz2,  
.bzip2,
+                  .tbz,  .tbz2,  .tb2,  .tz2), lzma and xz (requires suffix 
.lzma,
+                  .tlz, .xz, .txz), lz4 (requires  suffix  .lz4),  zstd  
(requires
                   suffix .zst, .zstd, .tzst).
 
            --zmax=NUM
-                  When used with option -z (--decompress), searches  the  
contents
+                  When  used  with option -z (--decompress), searches the 
contents
                   of compressed files and archives stored within archives by 
up to
-                  NUM recursive expansions.  The  default  --zmax=1  only  
permits
-                  searching  uncompressed  files  stored in cpio, pax, tar and 
zip
-                  archives; compressed files and archives are detected  as  
binary
-                  files  and  are effectively ignored.  Specify --zmax=2 to 
search
-                  compressed files and archives stored in cpio, pax, tar  and  
zip
+                  NUM  recursive  expansions.   The  default --zmax=1 only 
permits
+                  searching uncompressed files stored in cpio, pax,  tar  and  
zip
+                  archives;  compressed  files and archives are detected as 
binary
+                  files and are effectively ignored.  Specify --zmax=2  to  
search
+                  compressed  files  and archives stored in cpio, pax, tar and 
zip
                   archives.  NUM may range from 1 to 99 for up to 99 
decompression
-                  and  de-archiving  steps.   Increasing  NUM   values   
gradually
+                  and   de-archiving   steps.   Increasing  NUM  values  
gradually
                   degrades performance.
 
            -0, --null
-                  Prints  a  zero-byte (NUL) after the file name.  This option 
can
-                  be used with commands such as `find -print0' and `xargs  -0' 
 to
+                  Prints a zero-byte (NUL) after the file name.  This  option  
can
+                  be  used  with commands such as `find -print0' and `xargs 
-0' to
                   process arbitrary file names.
 
-           A  `--' signals the end of options; the rest of the parameters are 
FILE
+           A `--' signals the end of options; the rest of the parameters are  
FILE
            arguments, allowing filenames to begin with a `-' character.
 
            Long options may start with `--no-' to disable, when applicable.
 
-           The regular expression pattern syntax is an extended form of the  
POSIX
+           The  regular expression pattern syntax is an extended form of the 
POSIX
            ERE syntax.  For an overview of the syntax see README.md or visit:
 
                   https://github.com/Genivia/ugrep
 
-           Note  that `.' matches any non-newline character.  Pattern `\n' 
matches
-           a newline character.  Multiple lines may be matched with patterns  
that
+           Note that `.' matches any non-newline character.  Pattern `\n'  
matches
+           a  newline character.  Multiple lines may be matched with patterns 
that
            match one or more newline characters.
 
     EXIT STATUS
@@ -4620,54 +4626,54 @@
 
            >1     An error occurred.
 
-           If  -q  or --quiet or --silent is used and a line is selected, the 
exit
+           If -q or --quiet or --silent is used and a line is selected,  the  
exit
            status is 0 even if an error occurred.
 
     CONFIGURATION
-           The ug command is intended for context-dependent interactive  
searching
-           and  is  equivalent  to  the ugrep --config command to load the 
default
+           The  ug command is intended for context-dependent interactive 
searching
+           and is equivalent to the ugrep --config command  to  load  the  
default
            configuration file `.ugrep' when present in the working directory 
or in
            the home directory.
 
            A configuration file contains `NAME=VALUE' pairs per line, where 
`NAME`
-           is the name of a long option (without `--') and `=VALUE'  is  an  
argu-
-           ment,  which  is  optional  and may be omitted depending on the 
option.
+           is  the  name  of a long option (without `--') and `=VALUE' is an 
argu-
+           ment, which is optional and may be omitted  depending  on  the  
option.
            Empty lines and lines starting with a `#' are ignored.
 
-           The --config=FILE option and its  abbreviated  form  ---FILE  load  
the
-           specified  configuration file located in the working directory or, 
when
-           not found, located in the home directory.  An error  is  produced  
when
+           The  --config=FILE  option  and  its  abbreviated form ---FILE load 
the
+           specified configuration file located in the working directory or,  
when
+           not  found,  located  in the home directory.  An error is produced 
when
            FILE is not found or cannot be read.
 
-           Command  line options are parsed in the following order: the 
configura-
-           tion file is loaded first, followed by the remaining options and  
argu-
+           Command line options are parsed in the following order: the  
configura-
+           tion  file is loaded first, followed by the remaining options and 
argu-
            ments on the command line.
 
-           The  --save-config  option  saves  a `.ugrep' configuration file to 
the
-           working directory with a subset of the current  options.   The  
--save-
-           config=FILE  option saves the configuration to FILE.  The 
configuration
+           The --save-config option saves a `.ugrep'  configuration  file  to  
the
+           working  directory  with  a subset of the current options.  The 
--save-
+           config=FILE option saves the configuration to FILE.  The  
configuration
            is written to standard output when FILE is a `-'.
 
     GLOBBING
-           Globbing is used by options -g,  --include,  --include-dir,  
--include-
-           from,  --exclude,  --exclude-dir,  --exclude-from and 
--ignore-files to
-           match pathnames and basenames in recursive  searches.   Glob  
arguments
+           Globbing  is  used  by options -g, --include, --include-dir, 
--include-
+           from, --exclude, --exclude-dir, --exclude-from  and  --ignore-files 
 to
+           match  pathnames  and  basenames in recursive searches.  Glob 
arguments
            for these options should be quoted to prevent shell globbing.
 
-           Globbing  supports  gitignore  syntax  and  the  corresponding 
matching
-           rules, except that a glob normally matches files but  not  
directories.
+           Globbing supports  gitignore  syntax  and  the  corresponding  
matching
+           rules,  except  that a glob normally matches files but not 
directories.
            If a glob ends in a path separator `/', then it matches directories 
but
-           not files, as if --include-dir or --exclude-dir is specified.   
When  a
+           not  files,  as if --include-dir or --exclude-dir is specified.  
When a
            glob contains a path separator `/', the full pathname is matched.  
Oth-
-           erwise the basename of a file or directory is  matched.   For  
example,
-           *.h  matches  foo.h  and  bar/foo.h.  bar/*.h matches bar/foo.h but 
not
-           foo.h and not bar/bar/foo.h.  Use a leading `/' to force /*.h to  
match
+           erwise  the  basename  of a file or directory is matched.  For 
example,
+           *.h matches foo.h and bar/foo.h.  bar/*.h  matches  bar/foo.h  but  
not
+           foo.h  and not bar/bar/foo.h.  Use a leading `/' to force /*.h to 
match
            foo.h but not bar/foo.h.
 
-           When  a  glob  starts  with  a `^' or a `!' as in -g^GLOB, the 
match is
+           When a glob starts with a `^' or a `!' as  in  -g^GLOB,  the  match 
 is
            negated.  Likewise, a `!' (but not a `^') may be used with globs in 
the
-           files  specified  --include-from, --exclude-from, and 
--ignore-files to
-           negate the glob match.  Empty lines or lines starting with  a  `#'  
are
+           files specified --include-from, --exclude-from, and  --ignore-files 
 to
+           negate  the  glob  match.  Empty lines or lines starting with a `#' 
are
            ignored.
 
            Glob Syntax and Conventions
@@ -4685,14 +4691,14 @@
            [!abc-e]
                   Matches one character not a,b,c,d,e,/.
 
-           /      When  used at the start of a glob, matches if pathname has 
no /.
+           /      When used at the start of a glob, matches if pathname has no 
 /.
                   When used at the end of a glob, matches directories only.
 
            **/    Matches zero or more directories.
 
-           /**    When used at the end of a glob, matches everything after the 
 /.
+           /**    When  used at the end of a glob, matches everything after 
the /.
 
-           \?     Matches  a  ?  or  any other character specified after the 
back-
+           \?     Matches a ? or any other character  specified  after  the  
back-
                   slash.
 
            Glob Matching Examples
@@ -4728,46 +4734,46 @@
 
            a\?b   Matches a?b,                 but not a, b, ab, axb, a/b
 
-           Note that exclude glob patterns take priority over  include  glob  
pat-
-           terns   when  specified  with  options  -g,  --exclude,  
--exclude-dir,
+           Note  that  exclude  glob patterns take priority over include glob 
pat-
+           terns  when  specified  with  options  -g,  --exclude,   
--exclude-dir,
            --include and include-dir.
 
-           Glob patterns specified with prefix `!' in any of the files  
associated
-           with  --include-from,  --exclude-from  and --ignore-files will 
negate a
-           previous glob match.  That is, any matching file or directory  
excluded
-           by  a  previous  glob  pattern  specified  in the files associated 
with
-           --exclude-from or --ignore-file will become included again.   
Likewise,
-           any  matching  file  or  directory  included by a previous glob 
pattern
-           specified in the  files  associated  with  --include-from  will  
become
+           Glob  patterns specified with prefix `!' in any of the files 
associated
+           with --include-from, --exclude-from and --ignore-files  will  
negate  a
+           previous  glob match.  That is, any matching file or directory 
excluded
+           by a previous glob pattern  specified  in  the  files  associated  
with
+           --exclude-from  or --ignore-file will become included again.  
Likewise,
+           any matching file or directory included  by  a  previous  glob  
pattern
+           specified  in  the  files  associated  with  --include-from will 
become
            excluded again.
 
     ENVIRONMENT
            GREP_PATH
-                  May  be  used to specify a file path to pattern files.  The 
file
-                  path is used by option -f to open a pattern file, when the  
pat-
+                  May be used to specify a file path to pattern files.   The  
file
+                  path  is used by option -f to open a pattern file, when the 
pat-
                   tern file does not exist.
 
            GREP_COLOR
-                  May  be used to specify ANSI SGR parameters to highlight 
matches
-                  when option --color is used, e.g. 1;35;40 shows pattern  
matches
+                  May be used to specify ANSI SGR parameters to highlight  
matches
+                  when  option --color is used, e.g. 1;35;40 shows pattern 
matches
                   in bold magenta text on a black background.  Deprecated in 
favor
                   of GREP_COLORS, but still supported.
 
            GREP_COLORS
-                  May be used to specify ANSI SGR parameters to highlight  
matches
-                  and  other attributes when option --color is used.  Its 
value is
-                  a colon-separated list of ANSI SGR parameters that  defaults 
 to
+                  May  be used to specify ANSI SGR parameters to highlight 
matches
+                  and other attributes when option --color is used.  Its value 
 is
+                  a  colon-separated  list of ANSI SGR parameters that 
defaults to
                   cx=33:mt=1;31:fn=1;35:ln=1;32:cn=1;32:bn=1;32:se=36.   The  
mt=,
-                  ms=, and mc= capabilities  of  GREP_COLORS  take  priority  
over
+                  ms=,  and  mc=  capabilities  of  GREP_COLORS take priority 
over
                   GREP_COLOR.  Option --colors takes priority over GREP_COLORS.
 
     GREP_COLORS
-           Colors  are  specified as string of colon-separated ANSI SGR 
parameters
-           of the form `what=substring', where `substring'  is  a  
semicolon-sepa-
-           rated  list  of  ANSI SGR codes or `k' (black), `r' (red), `g' 
(green),
-           `y' (yellow), `b' (blue),  `m'  (magenta),  `c'  (cyan),  `w'  
(white).
-           Upper  case  specifies  background  colors.  A `+' qualifies a 
color as
-           bright.  A foreground and a background color may be combined  with  
one
+           Colors are specified as string of colon-separated ANSI  SGR  
parameters
+           of  the  form  `what=substring', where `substring' is a 
semicolon-sepa-
+           rated list of ANSI SGR codes or `k' (black), `r'  (red),  `g'  
(green),
+           `y'  (yellow),  `b'  (blue),  `m'  (magenta),  `c' (cyan), `w' 
(white).
+           Upper case specifies background colors.  A `+'  qualifies  a  color 
 as
+           bright.   A  foreground and a background color may be combined with 
one
            or more font properties `n' (normal), `f' (faint), `h' (highlight), 
`i'
            (invert), `u' (underline).  Substrings may be specified for:
 
@@ -4779,10 +4785,10 @@
 
            mt=    SGR substring for matching text in any matching line.
 
-           ms=    SGR substring for matching text in a selected  line.   The  
sub-
+           ms=    SGR  substring  for  matching text in a selected line.  The 
sub-
                   string mt= by default.
 
-           mc=    SGR  substring  for  matching  text in a context line.  The 
sub-
+           mc=    SGR substring for matching text in a  context  line.   The  
sub-
                   string mt= by default.
 
            fn=    SGR substring for filenames.
@@ -4797,12 +4803,12 @@
 
            rv     a Boolean parameter, switches sl= and cx= with option -v.
 
-           hl     a Boolean parameter, enables filename hyperlinks  
(\33]8;;link).
+           hl     a  Boolean parameter, enables filename hyperlinks 
(\33]8;;link).
 
            ne     a Boolean parameter, disables ``erase in line'' \33[K.
 
     FORMAT
-           Option  --format=FORMAT  specifies  an  output format for file 
matches.
+           Option --format=FORMAT specifies an output  format  for  file  
matches.
            Fields may be used in FORMAT, which expand into the following 
values:
 
            %[ARG]F
@@ -4902,53 +4908,53 @@
 
            %u     select unique lines only, unless option -u is used.
 
-           %1     the first regex group capture of the match,  and  so  on  up 
 to
+           %1     the  first  regex  group  capture  of the match, and so on 
up to
                   group %9, same as %[1]#; requires option -P.
 
            %[NUM]#
                   the regex group capture NUM; requires option -P.
 
            %[NUM]b
-                  the  byte  offset  of the group capture NUM; requires option 
-P.
+                  the byte offset of the group capture NUM;  requires  option  
-P.
                   Use e for the ending byte offset and d for the byte length.
 
            %[NUM1|NUM2|...]#
                   the first group capture NUM that matched; requires option -P.
 
            %[NUM1|NUM2|...]b
-                  the byte offset of the first group  capture  NUM  that  
matched;
-                  requires  option -P.  Use e for the ending byte offset and d 
for
+                  the  byte  offset  of  the first group capture NUM that 
matched;
+                  requires option -P.  Use e for the ending byte offset and d  
for
                   the byte length.
 
            %[NAME]#
-                  the NAMEd group capture; requires option -P and  capturing  
pat-
+                  the  NAMEd  group capture; requires option -P and capturing 
pat-
                   tern `(?<NAME>PATTERN)', see also %G.
 
            %[NAME]b
-                  the  byte  offset of the NAMEd group capture; requires 
option -P
-                  and capturing pattern `(?<NAME>PATTERN)'.  Use e for the  
ending
+                  the byte offset of the NAMEd group capture; requires  option 
 -P
+                  and  capturing pattern `(?<NAME>PATTERN)'.  Use e for the 
ending
                   byte offset and d for the byte length.
 
            %[NAME1|NAME2|...]#
-                  the  first  NAMEd group capture that matched; requires 
option -P
+                  the first NAMEd group capture that matched; requires  option 
 -P
                   and capturing pattern `(?<NAME>PATTERN)', see also %G.
 
            %[NAME1|NAME2|...]b
-                  the byte offset of the first NAMEd group capture  that  
matched;
-                  requires  option  -P  and  capturing pattern 
`(?<NAME>PATTERN)'.
+                  the  byte  offset of the first NAMEd group capture that 
matched;
+                  requires option -P  and  capturing  pattern  
`(?<NAME>PATTERN)'.
                   Use e for the ending byte offset and d for the byte length.
 
-           %G     list of  group  capture  indices/names  that  matched;  
requires
+           %G     list  of  group  capture  indices/names  that  matched; 
requires
                   option -P.
 
            %[TEXT1|TEXT2|...]G
-                  list  of  TEXT  indexed  by  group capture indices that 
matched;
+                  list of TEXT indexed by  group  capture  indices  that  
matched;
                   requires option -P.
 
            %g     the group capture index/name matched or 1; requires option 
-P.
 
            %[TEXT1|TEXT2|...]g
-                  the first TEXT indexed by the first  group  capture  index  
that
+                  the  first  TEXT  indexed  by the first group capture index 
that
                   matched; requires option -P.
 
            %%     the percentage sign.
@@ -4956,22 +4962,22 @@
            Formatted output is written without a terminating newline, unless 
%~ or
            `\n' is explicitly specified in the format string.
 
-           The [ARG] part of a  field  is  optional  and  may  be  omitted.   
When
-           present,  the argument must be placed in [] brackets, for example 
%[,]F
+           The  [ARG]  part  of  a  field  is  optional  and may be omitted.  
When
+           present, the argument must be placed in [] brackets, for example  
%[,]F
            to output a comma, the pathname, and a separator.
 
            %[SEP]$ and %u are switches and do not send anything to the output.
 
-           The separator used by the %F, %H, %N, %K, %B, %S and %G fields  may 
 be
+           The  separator  used by the %F, %H, %N, %K, %B, %S and %G fields 
may be
            changed by preceding the field by %[SEP]$.  When [SEP] is not 
provided,
-           this reverts the separator to the default separator  or  the  
separator
+           this  reverts  the  separator to the default separator or the 
separator
            specified with --separator.
 
            Formatted output is written for each matching pattern, which means 
that
-           a line may be output multiple times when patterns match more than  
once
-           on  the  same  line.   If  field  %u  is specified anywhere in a 
format
+           a  line may be output multiple times when patterns match more than 
once
+           on the same line.  If field  %u  is  specified  anywhere  in  a  
format
            string,  matching  lines  are  output  only  once,  unless  option  
-u,
-           --ungroup  is specified or when more than one line of input matched 
the
+           --ungroup is specified or when more than one line of input matched  
the
            search pattern.
 
            Additional formatting options:
@@ -4988,8 +4994,8 @@
            --format-end=FORMAT
                   the FORMAT when ending the search.
 
-           The context options -A,  -B,  -C,  -y,  and  display  options  
--break,
-           --heading,  --color, -T, and --null have no effect on formatted 
output.
+           The  context  options  -A,  -B,  -C,  -y,  and display options 
--break,
+           --heading, --color, -T, and --null have no effect on formatted  
output.
 
     EXAMPLES
            Display lines containing the word `patricia' in `myfile.txt':
@@ -5050,7 +5056,7 @@
 
                   $ ugrep -n -f c++/comments myfile.cpp
 
-           List  the  lines that need fixing in a C/C++ source file by looking 
for
+           List the lines that need fixing in a C/C++ source file by  looking  
for
            the word `FIXME' while skipping any `FIXME' in quoted strings:
 
                   $ ugrep -e FIXME -N '"(\\.|\\\r?\n|[^\\\n"])*"' myfile.cpp
@@ -5080,7 +5086,7 @@
 
                   $ ugrep -z -tc++ -n FIXME project.tgz
 
-           Recursively find lines with `FIXME' in C/C++ files, but do  not  
search
+           Recursively  find  lines with `FIXME' in C/C++ files, but do not 
search
            any `bak' and `old' directories:
 
                   $ ugrep -n FIXME -tc++ -g^bak/,^old/
@@ -5091,8 +5097,8 @@
                   $ ugrep -z -w --filter='pdf:pdftotext % -' copyright
 
            Match the binary pattern `A3hhhhA3' (hex) in a binary file without 
Uni-
-           code  pattern matching -U (which would otherwise match `\xaf' as a 
Uni-
-           code character U+00A3 with UTF-8 byte sequence C2 A3) and  display  
the
+           code pattern matching -U (which would otherwise match `\xaf' as a  
Uni-
+           code  character  U+00A3 with UTF-8 byte sequence C2 A3) and display 
the
            results in hex with --hexdump with C1 to output one hex line before 
and
            after each match:
 
@@ -5106,12 +5112,12 @@
 
                   $ ugrep -l '' --ignore-files
 
-           List all files containing a RPM signature, located in the `rpm'  
direc-
+           List  all files containing a RPM signature, located in the `rpm' 
direc-
            tory and recursively below up to two levels deeper (3 levels total):
 
                   $ ugrep -3 -l -tRpm '' rpm/
 
-           Monitor  the system log for bug reports and ungroup multiple 
matches on
+           Monitor the system log for bug reports and ungroup multiple matches 
 on
            a line:
 
                   $ tail -f /var/log/system.log | ugrep -u -i -w bug
@@ -5135,8 +5141,8 @@
 
 
     LICENSE
-           ugrep is released under the BSD-3 license.  All parts of  the  
software
-           have  reasonable  copyright terms permitting free redistribution.  
This
+           ugrep  is  released under the BSD-3 license.  All parts of the 
software
+           have reasonable copyright terms permitting free  redistribution.   
This
            includes the ability to reuse all or parts of the ugrep source tree.
 
     SEE ALSO
@@ -5144,7 +5150,7 @@
 
 
 
-    ugrep 3.7.10                     May 08, 2022                         
UGREP(1)
+    ugrep 3.7.11                     May 10, 2022                         
UGREP(1)
 
 ???? [Back to table of contents](#toc)
 
Binary files old/ugrep-3.7.10/bin/win32/ugrep.exe and 
new/ugrep-3.7.11/bin/win32/ugrep.exe differ
Binary files old/ugrep-3.7.10/bin/win64/ugrep.exe and 
new/ugrep-3.7.11/bin/win64/ugrep.exe differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ugrep-3.7.10/include/reflex/fuzzymatcher.h 
new/ugrep-3.7.11/include/reflex/fuzzymatcher.h
--- old/ugrep-3.7.10/include/reflex/fuzzymatcher.h      2022-05-08 
19:23:13.000000000 +0200
+++ new/ugrep-3.7.11/include/reflex/fuzzymatcher.h      2022-05-10 
18:52:02.000000000 +0200
@@ -223,13 +223,13 @@
     // last opcode is a HALT?
     if (jump == Pattern::Const::HALT)
     {
-      if (bin_ || !Pattern::is_opcode_goto(*bpt.pc0) || 
(Pattern::lo_of(*bpt.pc0) & 0x80) != 0x80)
+      if (bin_ || !Pattern::is_opcode_goto(*bpt.pc0) || 
(Pattern::lo_of(*bpt.pc0) & 0xC0) != 0xC0 || (Pattern::hi_of(*bpt.pc0) & 0xC0) 
!= 0xC0)
         return bpt.pc1 = NULL;
       // loop over UTF-8 multibytes, checking linear case only (i.e. one wide 
char or a short range)
       for (int i = 0; i < 3; ++i)
       {
         jump = Pattern::index_of(*bpt.pc0);
-        if (jump == Pattern::Const::HALT)
+        if (jump == Pattern::Const::HALT || pat_->opc_ + jump == bpt.pc0)
           return bpt.pc1 = NULL;
         if (jump == Pattern::Const::LONG)
           jump = Pattern::long_index_of(bpt.pc0[1]);
@@ -266,7 +266,7 @@
     // substitute or insert a pattern char in the text?
     if (bpt.sub)
     {
-      DBGLOG("Substitute, jump to %u at pos %zu char %d (0x%x)", jump, pos_, 
c1, c1);
+      DBGLOG("Substitute: jump to %u at pos %zu char %d (0x%x)", jump, pos_, 
c1, c1);
       int c = get();
       if (!bin_ && c != EOF)
       {
@@ -290,7 +290,7 @@
     }
     else
     {
-      DBGLOG("Insert, jump to %u at pos %zu char %d (0x%x)", jump, pos_, c1, 
c1);
+      DBGLOG("Delete: jump to %u at pos %zu char %d (0x%x)", jump, pos_, c1, 
c1);
       bpt.sub = bpt.alt;
       ++bpt.pc1;
     }
@@ -715,17 +715,14 @@
         if (c1 == '\0' || c1 == '\n' || c1 == EOF)
         {
           // do not try to fuzzy match NUL, LF, or EOF
-          if (err_ < max_)
+          if (err_ < max_ && del_)
           {
             ++err_;
-            if (del_)
+            // set backtrack point to insert pattern char only, not 
substitute, if pc0 os a different point than the last
+            if (stack == 0 || bpt_[stack - 1].pc0 != pc0)
             {
-              // set backtrack point to insert pattern char only, not 
substitute, if pc0 os a different point than the last
-              if (stack == 0 || bpt_[stack - 1].pc0 != pc0)
-              {
-                point(bpt_[stack++], pc0, len0, false, c1 == EOF);
-                DBGLOG("Point[%u] at %zu EOF", stack - 1, pc0 - pat_->opc_);
-              }
+              point(bpt_[stack++], pc0, len0, false, c1 == EOF);
+              DBGLOG("Point[%u] at %zu EOF", stack - 1, pc0 - pat_->opc_);
             }
           }
           else
@@ -777,7 +774,7 @@
                 }
               }
               pc = pc0;
-              DBGLOG("Delete: %d (0x%x) at pos %zu", c1, c1, pos_ - 1);
+              DBGLOG("Insert: %d (0x%x) at pos %zu", c1, c1, pos_ - 1);
             }
           }
           else
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ugrep-3.7.10/man/ugrep.1 new/ugrep-3.7.11/man/ugrep.1
--- old/ugrep-3.7.10/man/ugrep.1        2022-05-08 19:23:13.000000000 +0200
+++ new/ugrep-3.7.11/man/ugrep.1        2022-05-10 18:52:02.000000000 +0200
@@ -1,4 +1,4 @@
-.TH UGREP "1" "May 08, 2022" "ugrep 3.7.10" "User Commands"
+.TH UGREP "1" "May 10, 2022" "ugrep 3.7.11" "User Commands"
 .SH NAME
 \fBugrep\fR, \fBug\fR -- file pattern searcher
 .SH SYNOPSIS
@@ -504,9 +504,9 @@
 specified, use up to MAX mmap memory per thread.
 .TP
 \fB\-N\fR \fIPATTERN\fR, \fB\-\-neg\-regexp\fR=\fIPATTERN\fR
-Specify a negative PATTERN used during the search of the input:
-an input line is selected only if it matches any of the specified
-patterns unless a subpattern of PATTERN.  Same as \fB\-e\fR (?^PATTERN).
+Specify a negative PATTERN used during the search of the input: an
+input line is selected only if it matches the specified patterns
+unless it matches the negative PATTERN.  Same as \fB\-e\fR (?^PATTERN).
 Negative pattern matches are essentially removed before any other
 patterns are matched.  Note that longer patterns take precedence
 over shorter patterns.  This option may be repeated.
@@ -636,8 +636,8 @@
 Displays matching files in the order specified by KEY in recursive
 searches.  KEY can be `name' to sort by pathname (default), `best'
 to sort by best match with option \fB\-Z\fR (sort by best match requires
-two passes over the input files), `size' to sort by file size,
-`used' to sort by last access time, `changed' to sort by last
+two passes over files, which is expensive), `size' to sort by file
+size, `used' to sort by last access time, `changed' to sort by last
 modification time and `created' to sort by creation time.  Sorting
 is reversed with `rname', `rbest', `rsize', `rused', `rchanged', or
 `rcreated'.  Archive contents are not sorted.  Subdirectories are
@@ -750,16 +750,19 @@
 Any line is output (passthru).  Non\-matching lines are output as
 context with a `\-' separator.  See also options \fB\-A\fR, \fB\-B\fR and 
\fB\-C\fR.
 .TP
-\fB\-Z\fR[+\-~][\fIMAX\fR], \fB\-\-fuzzy\fR=[+\-~][\fIMAX\fR]
+\fB\-Z\fR[best][+\-~][\fIMAX\fR], \fB\-\-fuzzy\fR=[best][+\-~][\fIMAX\fR]
 Fuzzy mode: report approximate pattern matches within MAX errors.
 The default is \fB\-Z\fR1: one deletion, insertion or substitution is
 allowed.  If `+`, `\-' and/or `~' is specified, then `+' allows
 insertions, `\-' allows deletions and `~' allows substitutions.  For
 example, \fB\-Z\fR+~3 allows up to three insertions or substitutions, but
-no deletions.  The first character of an approximate match always
+no deletions.  If `best' is specified, then only the best matching
+lines are output with the lowest cost per file.  Option \fB\-Z\fRbest
+requires two passes over a file and cannot be used with standard
+input or Boolean queries.  Option \fB\-\-sort\fR=best orders matching files
+by best match.  The first character of an approximate match always
 matches the start of a pattern.  Option \fB\-U\fR applies fuzzy matching
-to bytes.  Option \fB\-\-sort\fR=best orders matching files by best match.
-No whitespace may be given between \fB\-Z\fR and its argument.
+to bytes.  No whitespace may be given between \fB\-Z\fR and its argument.
 .TP
 \fB\-z\fR, \fB\-\-decompress\fR
 Decompress files to search, when compressed.  Archives (.cpio,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ugrep-3.7.10/src/cnf.cpp new/ugrep-3.7.11/src/cnf.cpp
--- old/ugrep-3.7.10/src/cnf.cpp        2022-05-08 19:23:13.000000000 +0200
+++ new/ugrep-3.7.11/src/cnf.cpp        2022-05-10 18:52:02.000000000 +0200
@@ -34,8 +34,8 @@
 @copyright (c) BSD-3 License - see LICENSE.txt
 */
 
-#include "cnf.hpp"
 #include "ugrep.hpp"
+#include <reflex/fuzzymatcher.h>
 
 // parse a pattern into an operator tree using a recursive descent parser
 void CNF::OpTree::parse(const char *& pattern)
@@ -612,10 +612,25 @@
 
   fprintf(output, flag_files ? "Files " : "Lines ");
 
+
   if (flag_fuzzy > 0)
-    fprintf(output, "fuzzy-matched with max edit distance %zu", flag_fuzzy & 
255);
+  {
+    fprintf(output, "fuzzy-matched ");
+    if (flag_best_match)
+      fprintf(output, "as best matching ");
+    fprintf(output, "with max edit distance ");
+    if ((flag_fuzzy & reflex::FuzzyMatcher::INS))
+      fprintf(output, "+");
+    if ((flag_fuzzy & reflex::FuzzyMatcher::DEL))
+      fprintf(output, "-");
+    if ((flag_fuzzy & reflex::FuzzyMatcher::SUB))
+      fprintf(output, "~");
+    fprintf(output, "%zu", (flag_fuzzy & 0xff));
+  }
   else
+  {
     fprintf(output, "matched");
+  }
   if (flag_ignore_case)
     fprintf(output, " ignoring case");
   fprintf(output, " if:" NEWLINESTR "  ");
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ugrep-3.7.10/src/flag.hpp 
new/ugrep-3.7.11/src/flag.hpp
--- old/ugrep-3.7.10/src/flag.hpp       2022-05-08 19:23:13.000000000 +0200
+++ new/ugrep-3.7.11/src/flag.hpp       2022-05-10 18:52:02.000000000 +0200
@@ -72,6 +72,7 @@
 extern bool flag_all_threads;
 extern bool flag_any_line;
 extern bool flag_basic_regexp;
+extern bool flag_best_match;
 extern bool flag_bool;
 extern bool flag_confirm;
 extern bool flag_count;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ugrep-3.7.10/src/query.cpp 
new/ugrep-3.7.11/src/query.cpp
--- old/ugrep-3.7.10/src/query.cpp      2022-05-08 19:23:13.000000000 +0200
+++ new/ugrep-3.7.11/src/query.cpp      2022-05-10 18:52:02.000000000 +0200
@@ -2929,14 +2929,14 @@
           flags_[30].flag = true;
 
           if ((fuzzy_ & 0xff) > 1)
-            --fuzzy_;
+            fuzzy_ = ((fuzzy_ & 0xff) - 1) | (fuzzy_ & 0xff00);
 
           msg.append(" to ").append(std::to_string(fuzzy_ & 0xff));
         }
         else if (key == ']')
         {
           if (flags_[30].flag && (fuzzy_ & 0xff) < 0xff)
-            ++fuzzy_;
+            fuzzy_ = ((fuzzy_ & 0xff) + 1) | (fuzzy_ & 0xff00);
           else
             flags_[30].flag = true;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ugrep-3.7.10/src/ugrep.cpp 
new/ugrep-3.7.11/src/ugrep.cpp
--- old/ugrep-3.7.10/src/ugrep.cpp      2022-05-08 19:23:13.000000000 +0200
+++ new/ugrep-3.7.11/src/ugrep.cpp      2022-05-10 18:52:02.000000000 +0200
@@ -313,6 +313,7 @@
 bool flag_all_threads              = false;
 bool flag_any_line                 = false;
 bool flag_basic_regexp             = false;
+bool flag_best_match               = false;
 bool flag_bool                     = false;
 bool flag_confirm                  = DEFAULT_CONFIRM;
 bool flag_count                    = false;
@@ -1705,12 +1706,17 @@
 
   // entry data extracted from directory contents, moves pathname to this entry
   struct Entry {
+
+    static const uint16_t MIN_COST       = 0;
+    static const uint16_t UNDEFINED_COST = 65534;
+    static const uint16_t MAX_COST       = 65535;
+
     Entry(std::string& pathname, ino_t inode, uint64_t info)
       :
         pathname(std::move(pathname)),
         inode(inode),
         info(info),
-        cost(0)
+        cost(UNDEFINED_COST)
     { }
 
     std::string pathname;
@@ -1771,6 +1777,36 @@
     }
   };
 
+  // a job in the job queue
+  struct Job {
+
+    // sentinel job NONE
+    static const size_t NONE = UNDEFINED_SIZE;
+
+    Job()
+      :
+        pathname(),
+        cost(Entry::UNDEFINED_COST),
+        slot(NONE)
+    { }
+
+    Job(const char *pathname, uint16_t cost, size_t slot)
+      :
+        pathname(pathname != NULL ? pathname : ""),
+        cost(cost),
+        slot(slot)
+    { }
+
+    bool none()
+    {
+      return slot == NONE;
+    }
+
+    std::string pathname;
+    uint16_t    cost;
+    size_t      slot;
+  };
+
 #ifndef OS_WIN
   // extend the reflex::Input::Handler to handle stdin from a TTY or from a 
slow pipe
   struct StdInHandler : public reflex::Input::Handler {
@@ -2778,11 +2814,11 @@
   // recurse a directory
   virtual void recurse(size_t level, const char *pathname);
 
-  // -Z and --sort=best: perform a presearch to determine edit distance cost, 
return cost of pathname file, 65535 when no match is found
-  uint16_t cost(const char *pathname);
+  // -Z and --sort=best: perform a presearch to determine edit distance cost, 
return cost of pathname file, MAX_COST when no match is found
+  uint16_t compute_cost(const char *pathname);
 
   // search a file
-  virtual void search(const char *pathname);
+  virtual void search(const char *pathname, uint16_t cost);
 
   // check CNF AND/OR/NOT conditions are met for the line(s) spanning bol to 
eol
   bool cnf_matching(const char *bol, const char *eol, bool acquire = false)
@@ -3441,33 +3477,6 @@
 
 };
 
-// a job in the job queue
-struct Job {
-
-  // sentinel job NONE
-  static const size_t NONE = UNDEFINED_SIZE;
-
-  Job()
-    :
-      pathname(),
-      slot(NONE)
-  { }
-
-  Job(const char *pathname, size_t slot)
-    :
-      pathname(pathname != NULL ? pathname : ""),
-      slot(slot)
-  { }
-
-  bool none()
-  {
-    return slot == NONE;
-  }
-
-  std::string pathname;
-  size_t      slot;
-};
-
 struct GrepWorker;
 
 // master submits jobs to workers and implements operations to support 
lock-free job stealing
@@ -3528,9 +3537,9 @@
   }
 
   // search a file by submitting it as a job to a worker
-  void search(const char *pathname) override
+  void search(const char *pathname, uint16_t cost) override
   {
-    submit(pathname);
+    submit(pathname, cost);
   }
 
   // start worker threads
@@ -3540,7 +3549,7 @@
   void stop_workers();
 
   // submit a job with a pathname to a worker, workers are visited round-robin
-  void submit(const char *pathname);
+  void submit(const char *pathname, uint16_t cost);
 
   // lock-free job stealing on behalf of a worker from a co-worker with at 
least --min-steal jobs still to do
   bool steal(GrepWorker *worker);
@@ -3595,14 +3604,14 @@
   }
 
   // submit a job to this worker
-  void submit_job(const char *pathname, size_t slot)
+  void submit_job(const char *pathname, uint16_t cost, size_t slot)
   {
     while (todo >= MAX_JOB_QUEUE_SIZE && !out.eof && !out.cancelled())
       std::this_thread::sleep_for(std::chrono::milliseconds(100)); // give the 
worker threads some slack
 
     std::unique_lock<std::mutex> lock(queue_mutex);
 
-    jobs.emplace_back(pathname, slot);
+    jobs.emplace_back(pathname, cost, slot);
     ++todo;
 
     queue_work.notify_one();
@@ -3730,9 +3739,9 @@
 }
 
 // submit a job with a pathname to a worker, workers are visited round-robin
-void GrepMaster::submit(const char *pathname)
+void GrepMaster::submit(const char *pathname, uint16_t cost)
 {
-  iworker->submit_job(pathname, sync.next++);
+  iworker->submit_job(pathname, cost, sync.next++);
 
   // around we go
   ++iworker;
@@ -3800,7 +3809,7 @@
     out.begin(job.slot);
 
     // search the file for this job
-    search(job.pathname.c_str());
+    search(job.pathname.c_str(), job.cost);
 
     // end output in ORDERED mode (--sort) for this job slot
     out.end();
@@ -4354,6 +4363,8 @@
                   flag_basic_regexp = true;
                 else if (strncmp(arg, "before-context=", 15) == 0)
                   flag_before_context = strtonum(arg + 15, "invalid argument 
--before-context=");
+                else if (strcmp(arg, "best-match") == 0)
+                  flag_best_match = true;
                 else if (strcmp(arg, "binary") == 0)
                   flag_binary = true;
                 else if (strncmp(arg, "binary-files=", 13) == 0)
@@ -5162,7 +5173,7 @@
 
           case 'Z':
             ++arg;
-            if (*arg == '=' || isdigit(*arg) || strchr("+-~", *arg) != NULL)
+            if (*arg == '=' || strncmp(arg, "best", 4) == 0 || isdigit(*arg) 
|| strchr("+-~", *arg) != NULL)
             {
               flag_fuzzy = strtofuzzy(&arg[*arg == '='], "invalid argument 
-Z=");
               is_grouped = false;
@@ -7443,7 +7454,7 @@
     Stats::score_file();
 
     // search standard input
-    search(LABEL_STANDARD_INPUT);
+    search(LABEL_STANDARD_INPUT, static_cast<uint16_t>(flag_fuzzy));
   }
 
   if (arg_files.empty())
@@ -7498,7 +7509,7 @@
           break;
 
         case Type::OTHER:
-          search(pathname);
+          search(pathname, Entry::UNDEFINED_COST);
           break;
 
         case Type::SKIP:
@@ -8050,7 +8061,7 @@
 
         case Type::OTHER:
           if (flag_sort_key == Sort::NA)
-            search(dirpathname.c_str());
+            search(dirpathname.c_str(), Entry::UNDEFINED_COST);
           else
             file_entries.emplace_back(dirpathname, 0, info);
           break;
@@ -8114,7 +8125,7 @@
 
         case Type::OTHER:
           if (flag_sort_key == Sort::NA)
-            search(dirpathname.c_str());
+            search(dirpathname.c_str(), Entry::UNDEFINED_COST);
           else
             file_entries.emplace_back(dirpathname, inode, info);
           break;
@@ -8143,10 +8154,10 @@
     auto entry = file_entries.begin();
     while (entry != file_entries.end())
     {
-      entry->cost = cost(entry->pathname.c_str());
+      entry->cost = compute_cost(entry->pathname.c_str());
 
-      // if a file has no match or cannot be opened, remove it
-      if (entry->cost == 65535)
+      // if a file cannot be opened, then remove it
+      if (entry->cost == Entry::UNDEFINED_COST)
         entry = file_entries.erase(entry);
       else
         ++entry;
@@ -8181,7 +8192,7 @@
     // search the select sorted non-directory entries
     for (const auto& entry : file_entries)
     {
-      search(entry.pathname.c_str());
+      search(entry.pathname.c_str(), entry.cost);
 
       // stop after finding max-files matching files
       if (flag_max_files > 0 && Stats::found_parts() >= flag_max_files)
@@ -8253,11 +8264,11 @@
   }
 }
 
-// -Z and --sort=best: perform a presearch to determine edit distance cost, 
returns 65535 when no match is found
-uint16_t Grep::cost(const char *pathname)
+// -Z and --sort=best: perform a presearch to determine edit distance cost, 
returns MAX_COST when no match is found
+uint16_t Grep::compute_cost(const char *pathname)
 {
-  // default cost is max, which erases pathname from the sorted list
-  uint16_t cost = 65535;
+  // default cost is undefined, which erases pathname from the sorted list
+  uint16_t cost = Entry::UNDEFINED_COST;
 
   // stop when output is blocked
   if (out.eof)
@@ -8278,8 +8289,11 @@
     return cost;
   }
 
+  cost = Entry::MAX_COST;
+
   // -Z: matcher is a FuzzyMatcher for sure
   reflex::FuzzyMatcher *fuzzy_matcher = 
dynamic_cast<reflex::FuzzyMatcher*>(matcher);
+  fuzzy_matcher->distance(static_cast<uint16_t>(flag_fuzzy));
 
   // search file to compute minimum cost
   do
@@ -8320,8 +8334,43 @@
 }
 
 // search input and display pattern matches
-void Grep::search(const char *pathname)
+void Grep::search(const char *pathname, uint16_t cost)
 {
+  // -Zbest (or pseudo --best-match): compute cost if not yet computed by 
--sort=best
+  if (flag_best_match && flag_fuzzy > 0 && !flag_quiet && 
!flag_files_with_matches && matchers == NULL)
+  {
+    // -Z: matcher is a FuzzyMatcher for sure
+    reflex::FuzzyMatcher *fuzzy_matcher = 
dynamic_cast<reflex::FuzzyMatcher*>(matcher);
+    fuzzy_matcher->distance(static_cast<uint16_t>(flag_fuzzy));
+
+    if (pathname != LABEL_STANDARD_INPUT)
+    {
+      // compute distance cost if not yet computed by --sort=best
+      if (cost == Entry::UNDEFINED_COST)
+      {
+        cost = compute_cost(pathname);
+
+        // if no match, then stop searching this file
+        if (cost == Entry::UNDEFINED_COST)
+          return;
+      }
+
+      // no match found?
+      if (cost == Entry::MAX_COST)
+      {
+        if (!flag_invert_match)
+          return;
+
+        // -v: invert match when no match was found, zero cost since we don't 
expect any matches
+        cost = 0;
+      }
+
+      // combine max distance cost (lower byte) with INS, DEL, SUB and BIN 
fuzzy flags (upper byte)
+      cost = (cost & 0xff) | (flag_fuzzy & 0xff00);
+      fuzzy_matcher->distance(cost);
+    }
+  }
+
   // stop when output is blocked
   if (out.eof)
     return;
@@ -11466,6 +11515,12 @@
   {
     switch (*string)
     {
+      case 'b':
+        if (strncmp(string, "best", 4) != 0)
+          usage(message, string);
+        flag_best_match = true;
+        string += 4;
+        break;
       case '+':
         flags |= reflex::FuzzyMatcher::INS;
         ++string;
@@ -11480,7 +11535,7 @@
         break;
       default:
         max = static_cast<size_t>(strtoull(string, &rest, 10));
-        if (max == 0 || max > 255 || rest == NULL || *rest != '\0')
+        if (max == 0 || max > 0xff || rest == NULL || *rest != '\0')
           usage(message, string);
         string = rest;
     }
@@ -11956,9 +12011,9 @@
             under certain conditions to improve performance.  When MAX is\n\
             specified, use up to MAX mmap memory per thread.\n\
     -N PATTERN, --neg-regexp=PATTERN\n\
-            Specify a negative PATTERN used during the search of the input:\n\
-            an input line is selected only if it matches any of the 
specified\n\
-            patterns unless a subpattern of PATTERN.  Same as -e 
(?^PATTERN).\n\
+            Specify a negative PATTERN used during the search of the input: 
an\n\
+            input line is selected only if it matches the specified patterns\n\
+            unless it matches the negative PATTERN.  Same as -e (?^PATTERN).\n\
             Negative pattern matches are essentially removed before any 
other\n\
             patterns are matched.  Note that longer patterns take precedence\n\
             over shorter patterns.  This option may be repeated.\n\
@@ -12076,8 +12131,8 @@
             Displays matching files in the order specified by KEY in 
recursive\n\
             searches.  KEY can be `name' to sort by pathname (default), 
`best'\n\
             to sort by best match with option -Z (sort by best match 
requires\n\
-            two passes over the input files), `size' to sort by file size,\n\
-            `used' to sort by last access time, `changed' to sort by last\n\
+            two passes over files, which is expensive), `size' to sort by 
file\n\
+            size, `used' to sort by last access time, `changed' to sort by 
last\n\
             modification time and `created' to sort by creation time.  
Sorting\n\
             is reversed with `rname', `rbest', `rsize', `rused', `rchanged', 
or\n\
             `rcreated'.  Archive contents are not sorted.  Subdirectories 
are\n\
@@ -12160,16 +12215,19 @@
     -y, --any-line, --passthru\n\
             Any line is output (passthru).  Non-matching lines are output as\n\
             context with a `-' separator.  See also options -A, -B and -C.\n\
-    -Z[+-~][MAX], --fuzzy=[+-~][MAX]\n\
+    -Z[best][+-~][MAX], --fuzzy=[best][+-~][MAX]\n\
             Fuzzy mode: report approximate pattern matches within MAX 
errors.\n\
             The default is -Z1: one deletion, insertion or substitution is\n\
             allowed.  If `+`, `-' and/or `~' is specified, then `+' allows\n\
             insertions, `-' allows deletions and `~' allows substitutions.  
For\n\
             example, -Z+~3 allows up to three insertions or substitutions, 
but\n\
-            no deletions.  The first character of an approximate match 
always\n\
+            no deletions.  If `best' is specified, then only the best 
matching\n\
+            lines are output with the lowest cost per file.  Option -Zbest\n\
+            requires two passes over a file and cannot be used with standard\n\
+            input or Boolean queries.  Option --sort=best orders matching 
files\n\
+            by best match.  The first character of an approximate match 
always\n\
             matches the start of a pattern.  Option -U applies fuzzy 
matching\n\
-            to bytes.  Option --sort=best orders matching files by best 
match.\n\
-            No whitespace may be given between -Z and its argument.\n\
+            to bytes.  No whitespace may be given between -Z and its 
argument.\n\
     -z, --decompress\n\
             Decompress files to search, when compressed.  Archives (.cpio,\n\
             .pax, .tar and .zip) and compressed archives (e.g. .taz, .tgz,\n\
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ugrep-3.7.10/src/ugrep.hpp 
new/ugrep-3.7.11/src/ugrep.hpp
--- old/ugrep-3.7.10/src/ugrep.hpp      2022-05-08 19:23:13.000000000 +0200
+++ new/ugrep-3.7.11/src/ugrep.hpp      2022-05-10 18:52:02.000000000 +0200
@@ -38,7 +38,7 @@
 #define UGREP_HPP
 
 // ugrep version
-#define UGREP_VERSION "3.7.10"
+#define UGREP_VERSION "3.7.11"
 
 // disable mmap because mmap is almost always slower than the file reading 
speed improvements since 3.0.0
 #define WITH_NO_MMAP

Reply via email to